例題 2例題 1 で説明した関数 printVector を次の条件に従って書き換えなさい:
コーディング例1 /* 2 * プログラミング演習 第 8 回 3 * [例題 2] 4 * (C) 2006 Hirohisa AMAN <aman@cs.ehime-u.ac.jp, aman@computer.org> 5 */ 6 #include <stdio.h> 7 8 /* 構造体 vector の宣言 */ 9 struct vector { 10 int x; 11 int y; 12 }; 13 14 /* ベクトル表示のための関数 : ポインタ版 */ 15 void printVector( struct vector* v ){ 16 17 printf("( %d, %d )\n", v->x, v->y ); 18 19 } 20 21 int main(void){ 22 struct vector data; 23 24 scanf("%d %d", &data.x, &data.y); 25 26 printVector(&data); /* 呼び出し方法に注意 */ 27 28 return 0; 29 }
※左端の数字は行番号であり,ソースコードには含まれない点に注意!
コンパイル & 実行例$ gcc example8_2.c [Enter] $ ./a.out [Enter] 3 12 [Enter] ( 3, 12 ) 解説ポインタ変数は, ある変数のメモリ上での番地 を格納するための変数である. データ(変数の値)ではなく, データのありか を指し示すために使われるという点が重要である.※少し詳しい説明: 後期の「データ構造とアルゴリズム」で使用予定の説明スライド
一般に,ポインタ変数の宣言は,参照先データの型に依存する.
int* p;
この例題の場合,struct vector 型変数の番地を格納することになるので,
struct vector* v;
という宣言になる(15行目参照).
ポインタ変数の前に * (アスタリスク)を付けると,
参照先データの実体にアクセスできる.
v->x
という書き方も許されている.
こちらの方が直感的(図で描いたイメージに近い)ということもあり,
一般的に使われている(17行目参照).
v->y 関数 printVector を呼び出す側(main 関数側)では, 構造体の 番地 を指定することになる. 変数の番地は, 変数の前に &(アンパサンド)を付けることで調べることができる. したがって,この場合は &data となっている(26 行目参照). 関数の引数をポインタにするメリット既に知っている通り, 関数を呼び出す際に引数が指定されていると その内容がコピー される. この「コピー」という点が重要である.一般に構造体では複数個の変数がひとかたまりになっている. つまり,コピーにはそれだけコスト (その分だけメモリ,時間,手間が) かかる. 一方,引数をポインタにしておくと, コピーは(メモリ上での)番地のみ で済む. 番地であるがゆえに, 構造体の内部構成がどれだけ複雑であっても, どれだけ多くのメモリを必要としようとも関係なく一定量である. |