変数のアドレスを確認する
&演算子は変数のアドレスを取得します。表示には%pを使い、void *へ変換します。
アドレスC
#include <stdio.h>
int main(void) {
int score = 80;
printf("値: %d\n", score);
printf("アドレス: %p\n", (void *)&score);
return 0;
}実行例OUTPUT
値: 80
アドレス: 0x7ffd...アドレスは実行環境や実行のたびに異なります。
ポインタから値を読む
ポインタはアドレスを保存する変数です。*pointerで、そのアドレスにある値を読み書きします。
間接参照C
#include <stdio.h>
int main(void) {
int score = 80;
int *pointer = &score;
printf("%d\n", *pointer);
*pointer = 95;
printf("%d\n", score);
return 0;
}実行結果OUTPUT
80
95関数から呼び出し元の値を変更する
二つの値を交換C
#include <stdio.h>
void swap(int *a, int *b) {
int temporary = *a;
*a = *b;
*b = temporary;
}
int main(void) {
int left = 10, right = 20;
swap(&left, &right);
printf("%d %d\n", left, right);
return 0;
}実行結果OUTPUT
20 10C言語の引数は値渡しです。アドレスの値を渡すことで、関数は呼び出し元の変数へアクセスできます。
配列とポインタの関係
多くの式で配列名は先頭要素へのポインタへ変換されます。関数へ配列を渡すときは要素数も別に渡します。
配列の合計C
#include <stdio.h>
int sum(const int values[], size_t length) {
int total = 0;
for (size_t i = 0; i < length; i++) total += values[i];
return total;
}
int main(void) {
int values[] = {10, 20, 30};
printf("%d\n", sum(values, 3));
return 0;
}実行結果OUTPUT
60要素数は自動で渡らない 関数内の
sizeof valuesでは元の配列の要素数を求められません。変更しない値をconstで示す
const int *valuesは、ポインタ経由で要素を書き換えない約束を表します。読み取り専用の関数には積極的に付けます。
最大値を読むC
int max_value(const int *values, size_t length) {
int max = values[0];
for (size_t i = 1; i < length; i++) {
if (values[i] > max) max = values[i];
}
return max;
}{4, 9, 2}と長さ3を渡すと9を返します。
無効なポインタを使わない
確認すること
- 初期化していないポインタを参照しない
- 何も指さない状態は
NULLで表し、参照前に確認する - 配列の先頭より前や末尾より後を参照しない
- 寿命を終えたローカル変数のアドレスを返さない
- ポインタの型をむやみに変換しない
ミニ課題:最小値と最大値
配列、要素数、結果を書き込む二つのポインタを受け取り、最小値と最大値を返す関数を作ってください。空の配列を受け付けない設計も考えましょう。
