C言語超入門⑦ ポインタの基本を理解しよう
メモリアドレス、&と*、ポインタを使う関数、NULLの意味を初心者向けに整理します。
第7回では、C言語でつまずきやすいポインタを扱います。
最初は「変数が置かれている場所を保存する変数」と考えれば十分です。
この回でできるようになること
- メモリアドレスの意味を知る
- ポインタへアドレスを保存する
- ポインタを通して値を読み書きする
- 関数から元の変数を変更する
変数には置き場所がある
プログラムを実行すると、変数はパソコンのメモリへ置かれます。
メモリを番号付きのロッカーにたとえると、変数の値が荷物、ロッカー番号がメモリアドレスです。
変数の前に&を付けると、そのアドレスを取得できます。
int score = 80;
printf("%p\n", (void *)&score);
アドレスは実行するたびに変わることがあります。表示された番号を覚える必要はありません。
ポインタへアドレスを保存する
int score = 80;
int *scorePointer = &score;
| 部分 | 意味 |
|---|---|
| int * | int型の変数を指すポインタ |
| scorePointer | ポインタの名前 |
| &score | scoreのアドレス |
scorePointerは80という値ではなく、scoreが置かれている場所を保存しています。
ポインタから値を読み書きする
ポインタの前に*を付けると、指している場所の値を扱えます。
#include <stdio.h>
int main(void) {
int score = 80;
int *scorePointer = &score;
printf("%d\n", *scorePointer);
*scorePointer = 95;
printf("%d\n", score);
return 0;
}
この*は、ポインタが指す場所の値を取り出す記号です。結果として、scoreそのものが95へ変わります。
関数から元の変数を変更する
通常、関数へ渡したint型の値はコピーされます。ポインタを渡すと、呼び出し元の変数を変更できます。
#include <stdio.h>
void addOne(int *number) {
(*number)++;
}
int main(void) {
int count = 3;
addOne(&count);
printf("%d\n", count);
return 0;
}
第2回のscanf("%d", &age)で&を付けたのも、scanfへageの場所を渡すためです。
NULLを確認する
どこも指していないことを表す特別な値がNULLです。
int *numberPointer = NULL;
if (numberPointer != NULL) {
printf("%d\n", *numberPointer);
}
NULLのポインタから値を読もうとすると、プログラムが異常終了することがあります。使う前に有効な場所を指しているか確認します。
練習してみよう
2つのint型変数のアドレスを受け取り、値を入れ替えるswap関数を作ってみましょう。
模範解答
#include <stdio.h>
void swap(int *a, int *b) {
int temporary = *a;
*a = *b;
*b = temporary;
}
int main(void) {
int first = 10;
int second = 20;
swap(&first, &second);
printf("first = %d, second = %d\n", first, second);
return 0;
}
解説
一方の値をそのまま上書きすると元の値が消えるため、temporaryへ一時保存します。mainからは&firstと&secondを渡し、swapの中では*aと*bを通して元の変数を書き換えています。
この回のまとめ
- ポインタはメモリアドレスを保存する変数
&で変数のアドレスを取得する*でポインタが指す値を読み書きする- ポインタを関数へ渡すと元の変数を変更できる
- NULLを指すポインタはそのまま読み書きしない