ポインタは番地を持つ変数
ポインタは、別の変数の番地を入れておく変数です。C言語では、関数に変数そのものを渡して、書き換えさせたいときに使います。
番地を扱えると、配列の途中や、あとで確保したメモリを読み書きできます。同時に、間違えるとプログラムが止まる、いちばん危ない部分でもあります。
このレッスンのゴール
メモ
ポインタを使ったコードを読み、書ける。
重要な言葉
| ことば | いみ | れい |
|---|---|---|
| ポインタ | 番地を入れる変数 | int *p |
| アドレス演算子 | 変数の番地を取る記号 | &x |
| 間接参照 | ポインタが指す先の値を、読み書きすること | *p |
| NULL | どこも指さないポインタの値。中身は0 | |
| ポインタ演算 | ポインタに足すと、型の大きさだけ進むこと | |
| 値渡し | 関数に、値のコピーを渡すこと |
学生が入力するセルは、このプレビューでは空白です。
&は番地を取り、*は先を読み書きする
&x は、変数 x の番地です。int *p = &x; と書くと、p に x の番地が入ります。
*p と書くと、p が指す先の値を読み書きできます。*p = 7; は、x を7に変えます。どこも指さないときは NULL を入れ、その先は読みません。
変数 x とポインタ p
| 書き方 | 意味 | 型 |
|---|---|---|
| x | 値そのもの。たとえば42 | int |
| &x | x の番地 | int * |
| p | x の番地を持つ変数 | int * |
| *p | p が指す先。x と同じ場所 | int |
学生が入力するセルは、このプレビューでは空白です。
ポインタ越しに x を書き換える
printf '%s\n' 'int main(void){int x = 42; int *p = &x; *p = 7; printf("%d %d\n", x, *p); return 0;}' | gcc -include stdio.h -x c - -o /tmp/ptr && /tmp/ptrここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
番地を渡して2つの値を入れ替える
printf '%s\n' 'void swap(int *a, int *b){int t = *a; *a = *b; *b = t;} int main(void){int x = 1, y = 2; swap(&x, &y); printf("%d %d\n", x, y); return 0;}' | gcc -include stdio.h -x c - -o /tmp/swap && /tmp/swapここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
ポインタに1を足すと、1要素ぶん進む
p + 1 は、次の1バイトではなく、次の要素を指します。int * なら4バイト、double * なら8バイト進みます。
配列の名前は、先頭の要素の番地として使えます。p[3] は *(p + 3) と同じ意味です。足し算の結果を使う前に、* と + のどちらが先かに気をつけます。
p + 1 が進むバイト数
| ポインタの型 | 1つ進むバイト数 |
|---|---|
| char * | 1 |
| short * | 2 |
| int * | 4 |
| double * | 8 |
学生が入力するセルは、このプレビューでは空白です。
隣の要素までのバイト数
printf '%s\n' 'int main(void){int a[2]; char b[2]; double d[2]; printf("%d %d %d\n", (int)((char *)&a[1] - (char *)&a[0]), (int)((char *)&b[1] - (char *)&b[0]), (int)((char *)&d[1] - (char *)&d[0])); return 0;}' | gcc -include stdio.h -x c - -o /tmp/step && /tmp/stepここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
3通りの読み方
printf '%s\n' 'int main(void){int a[4] = {10, 20, 30, 40}; int *p = a; printf("%d %d %d\n", *(p + 2), p[3], *p + 2); return 0;}' | gcc -include stdio.h -x c - -o /tmp/arr && /tmp/arrここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
よくある間違い
注意
ポインタに1を足すと、番地が1増える、と思いがちです。int * で4ずつ進むのは、型の大きさを掛けているからです。数えるのはバイトでなく要素なので、char * のときだけ、1バイトずつ進みます。
さらに挑戦: 書き込みを足す
課題が通ったら、write_int(memory, address, size, value) を書きましょう。value を、小さい桁のバイトから順に、memory に書き込みます。
そして、write_int のあとに read_int で読むと、同じ値に戻ることを、自分のテストで3つ確かめましょう。