C応用2 ポインタ
C応用2 ポインタ
C言語の最大難関と言われるポインタについて勉強します。
ポインタは、何かが入っている場所を示すもので、家の住所の様なものです。コンピュータの中にあるメモリには、様々なデータが記録されています。このデータが記録されているメモリの番地(アドレス)がポインタになります。
メモリに記録されているデータは、固定2進数表現で記録されているものもあれば、浮動小数点表現で記録されているものもあります。また、1バイトで記録されているものもあれば、4バイトで記録されているものもあります。どの様な表現で何バイトのデータなのかは、データ型で区別するようにしています。このため、プログラムでポインタを扱う場合、どの様なデータ型のデータが記録されているメモリの番地なのかを意識しなければなりません。ポインタを扱う文法と合わせて、データが記録されているメモリイメージとデータ型をアニメーションで説明します。
また、ポインタを使ったプログラミング練習については、以下のステップで行うことで、ポインタに慣れるようにします。
配列をインデックス方式からポインタ方式に修正
文字列をポインタ方式で扱う
構造体配列を構造体ポインタで扱う
ポインタの文法と、イメージ図の書き方を説明します。ポインタを習得するには、ポインタの指す先が、何型のデータなのかを意識することが重要です。イメージ図を書く時は、データ型を一緒に書く様にします。
・ポインタ変数宣言は*を使う
変数宣言の時、変数名の前に*を付けると、ポインタ変数宣言になります。
・変数のアドレスは&演算子で求める
ポインタ変数にはアドレスをセットします。アドレスは&(アドレス)演算子で求めることができます。
・ポインタの指す先は*演算子を使う
アドレス演算子で求めたアドレスに入っているデータは、*(ポインタ)演算子で求めることができます。
・&が付くと*が増え*が付くと*が減る
=演算子の左辺と右辺のデータ型は同じになる様にします。
「&演算子のついた式のデータ型は*が増え、*演算子のついた式のデータ型は*が減る」と覚えましょう。
int型、char型、double型の変数を宣言、適当なデータを代入します。また、これらのデータ型に対応したポインタ変数を宣言し、ポインタ変数を使って、ポインタの指す先を表示するプログラムを作成しましょう(ポインタ変数に入っているアドレスも表示)。
int型の変数名はx、代入する値は10、int型のポインタ変数名はpにします。
char型の変数名はy、代入する値は'a'、char型のポインタ変数名はqにします。
double型の変数名はz、代入する値は1.23、double型のポインタ変数名はrにします。
また、上記に加え、ポインタ変数の指す先に1を足したり、ポインタに1を足したポインタの指す先を表示したりして、どうしてその様な結果になるか考えてみましょう。
練習問題06の実行結果を考察します。
ポインタの指す先のイメージをアニメーションを使って説明します。
配列処理を復習します。
配列名は配列の先頭要素のポインタです。このポインタを加算することで、配列要素を順番にポイントすることが出来ます。配列要素を指すポインタを使って、配列処理する書き方を説明します。
・配列名は先頭要素へのポインタ
配列名はポインタで、配列名に整数を足すと、その数をインエデックスとした要素へのポインタになる。
・配列処理するfor文をポインタで書く
インデックスをループカウンタとするfor文は、ポインタをループカウンタにした書き方に修正できます。
この修正は、ポインタを使ったプログラミングの訓練になります。
配列の要素を初期化して宣言し、その合計を求めるプログラムをポインタ方式で書いてみましょう。
配列だけを宣言し、その配列にキー入力でデータをセットしてから、そのデータを表示するプログラムを、ポインタ方式で書いてみましょう。
練習問題の動画の中で説明していますが、ポインタ変数pに対して、「&*p」という式を書く事ができます。この式は、ポインタの指す先のアドレスという意味で、ポインタ変数に入っているアドレスそのものになります。このため、「&*p」は「p」と書く事ができます。「&*p」という書き方は無駄に難しくする書き方なので、「&*p」は「p」と書く様にしましょう。
[ ] は、配列演算子と言います。[ ] を使って配列の要素を扱うプログラムを書いていましたが、[ ] 演算子と*演算子は同じ意味を持つ演算子です。
配列を処理するfor文のプログラムは、[ ]演算子と*演算子を使い、 様々な書き方にすることができます。
・[ ] と*は同じ意味を持つ演算子
どちらの演算子もポインタと整数を組み合わせた、2つの項からなる二項演算子です。
・配列処理のfor文を様々な方法で書く
インデックスカウンタ方式とポインタ方式が代表的な書き方ですが、お勧めはしませんが、他にも、色々な書き方があります。
・[ ]と*を使った頭の体操問題
意味のあるプログラムでは使いませんが、[ ]演算子と*演算子を使うと、様々な頭の体操問題が出来ます。
メモリイメージを書いて、解いてみましょう。
strcpy関数がしていること(文字列複写)を、インデックスカウンタを使った方法で書いて説明しています。復習として、ヌル文字が抜けてしまうと、どうなるかも説明しています。
インデックスカウンタを使った書き方を、ポインタを使った書き方にすると、非常にスッキリとした書き方になります。プログラムの実行の流れを説明しながら、少しずつプログラムを書き替えていきます。
・文字列複写プログラムはポインタの練習になる
ポインタを使うと、文字列複写は1行で書く事ができますが、これは練習プログラムです。実際のプログラミングでは、文字列複写はstrcpy関数を使ってください。
・「c = *p++」は便利な書き方
文字列中の文字を1文字ずつ調べるプログラムで、よく使う書き方です。使う機会があったら、積極的に使うことで慣れると良いでしょう。
from配列に英小文字の入った文字列を初期化してセットし、to配列には、英小文字を英大文字に変換して複写するプログラムを作成しましょう。
なお、文字列複写後、from配列とto配列の文字列を表示して、英小文字が英大文字になっていることを確認してください。
from配列に文字列を初期化してセットし、to配列には、from配列の文字列を逆順にセットするプログラムを作成しましょう。
なお、文字列を逆順に複写後、from配列とto配列の文字列を表示して、逆順になっていることを確認してください。
文字列は、char型配列(文字配列)と、char型ポインタ(文字ポインタ)で扱うことが出来ます。
文字配列と文字ポインタで同じ書き方ができる場合と、同じ書き方が出来ない場合があります。メモリイメージを比較しながら、その相違点を説明します。
ポインタが理解できたかの頭の体操問題が用意されています。YouTubeの動画説明の所に、頭の体操問題のタイムスタンプを記載していますので、それを参照してください。
・%sで文字列表示する方法は同じ
文字列は%sで表示できます。文字ポインタも文字配列も、%sで表示する書き方は同じです。
・%cで文字表示する方法は同じ
文字列の文字は%cで表示できます。文字ポインタも文字配列も、文字列中の文字を%cで表示する書き方は同じです。
文字列中の文字は、[ ]演算子で指定する書き方と、*演算子で指定する書き方がありますが、文字配列も文字ポインタも同じ書き方ができます。
・const char *型の文字列中の文字は変更できない
文字を変更する場合は、文字配列を用意しなければなりません。
・文字配列への文字列セットはstrcpy関数を使う
文字配列の場合は、strcpy関数で文字列をセットしますが、const char *型の文字列は、文字列定数の代入をすることができます。
・参照の書き方は同じで、更新の書き方が違う
文字列を、文字配列で用意した場合と文字ポインタで用意した場合では、表示等の参照系は同じ書き方ができますが、代入等の更新系は、書き方が異なります。更新系は、どこのメモリを変更するのかを意識すると、その理由が分かります。
・更新系は二次元配列による複数文字列が便利
文字列中の文字を変更する場合は、変更する文字をセットするためのメモリが確保されている二次元配列を用意する方が、プログラミングが楽です。
・参照系は文字ポインタ配列による複数文字列が便利
文字列を表示するだけの様な、参照系の文字列は、文字列中の文字数を意識する必要のない文字ポインタ配列の方が、プログラミングが楽です。
以下は、意味のあるプログラムではありませんが、文字の入った配列なのか、ポインタの入った配列なのか、を見分ける力を付けるための頭の体操問題です。ポインタが理解できたかを確認するのに役立つでしょう。メモリイメージを書いて、解いてみましょう。解説と答えは、上記の動画の中で説明しています。YouTubeの動画説明の所に、頭の体操問題のタイムスタンプを記載していますので、それを参照してください。
最初に構造体の復習をします。
この後、構造体を指すポインタである構造体ポインタについて説明します。構造体ポインタは、基本型のデータを指すポインタと同様に*演算子を使う事もできますが、より便利なアロー(->)演算子を使う事ができます。
・構造体ポイントはアロー演算子が使える
「(*p).メンバ」のような面倒な書き方をしなくとも「p->メンバ名」と書く事ができます。
・ループカウンタをポインタにする
構造体配列を処理するfor文のインデックスカウンタをポインタにした場合、配列の要素である構造体のメンバは、アロー演算子を使って書きます。
・構造体ポインタ配列は構造体ポインタの配列
構造体ポインタの配列を作る事もできます。構造体ポインタ配列の要素を指すポインタは、ポインタを指すポインタになるため、*が2つ付いたポインタ型になります。
複雑なポインタを扱うことで、ポインタが理解できたかを確認してみましょう。
練習問題04のプログラムを修正し、要素数5の構造体配列に3つの要素だけ初期化し、残り2個要素には、キー入力でデータをセットするプログラムに修正してみましょう。なお、ループカウンタは構造体ポインタを使う様にしましょう。
練習問題05のバトルルールで3人のエネミーとバトルするプログラムを作成しましょう。3人のエネミーのデータは構造体配列で初期化します。プレイヤーデータはキー入力します。3人とのバトルが終わったならば、何勝何敗だったかを表示しましょう。
上記で説明した練習問題と同じ問題です。
下記のYoutubeの動画の説明の所にはダウンロードのURLが記載されいます。
main.cppというソースファイルを含むVisual Studio 2022のプロジェクトファイル一式がダウンロードできます。ソースファイルは未完成の状態です。ソリューションファイルからVisual Studioを立ち上げ、プログラムを完成させてください。
《練習問題06》ポインタの実験
《練習問題07》配列処理にポインタを使う
《練習問題08》ポインタを使って入力する
《練習問題09》文字列を大文字変換して複写
《練習問題10》文字列を逆順に複写する
《練習問題11》構造体ポインタで構造体配列を扱う
《練習問題12》バトルゲーム
テスト実施フォーム ← テストチャレンジできます
上記テストの解説と解答