クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

C言語のポインタとは何か

このレッスンのあとで: ポインタを使ったコードを読み、書ける。

55分のレッスンコマンド4件コンパイラとアーキテクチャのラボ:gcc、flex、bison、RISC-V を1台の VM で

ポインタは番地を持つ変数

ポインタは、別の変数の番地を入れておく変数です。C言語では、関数に変数そのものを渡して、書き換えさせたいときに使います。

番地を扱えると、配列の途中や、あとで確保したメモリを読み書きできます。同時に、間違えるとプログラムが止まる、いちばん危ない部分でもあります。

このレッスンのゴール

メモ

ポインタを使ったコードを読み、書ける。

重要な言葉

ことばいみれい
ポインタ番地を入れる変数int *p
アドレス演算子変数の番地を取る記号&x
間接参照ポインタが指す先の値を、読み書きすること*p
NULLどこも指さないポインタの値。中身は0
ポインタ演算ポインタに足すと、型の大きさだけ進むこと
値渡し関数に、値のコピーを渡すこと

学生が入力するセルは、このプレビューでは空白です。

&は番地を取り、*は先を読み書きする

&x は、変数 x の番地です。int *p = &x; と書くと、p に x の番地が入ります。

*p と書くと、p が指す先の値を読み書きできます。*p = 7; は、x を7に変えます。どこも指さないときは NULL を入れ、その先は読みません。

変数 x とポインタ p

書き方意味型
x値そのもの。たとえば42int
&xx の番地int *
px の番地を持つ変数int *
*pp が指す先。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つ確かめましょう。

このラボとソースについて: コンパイラとアーキテクチャのラボ:gcc、flex、bison、RISC-V を1台の VM で

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。