C言語

配列とポインタ

値が置かれた場所を表すアドレスと、安全にポインタを使う基本を学びます。

01

変数のアドレスを確認する

&演算子は変数のアドレスを取得します。表示には%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...

アドレスは実行環境や実行のたびに異なります。

02

ポインタから値を読む

ポインタはアドレスを保存する変数です。*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
03

関数から呼び出し元の値を変更する

二つの値を交換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 10

C言語の引数は値渡しです。アドレスの値を渡すことで、関数は呼び出し元の変数へアクセスできます。

04

配列とポインタの関係

多くの式で配列名は先頭要素へのポインタへ変換されます。関数へ配列を渡すときは要素数も別に渡します。

配列の合計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では元の配列の要素数を求められません。
05

変更しない値を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を返します。

06

無効なポインタを使わない

確認すること
  • 初期化していないポインタを参照しない
  • 何も指さない状態はNULLで表し、参照前に確認する
  • 配列の先頭より前や末尾より後を参照しない
  • 寿命を終えたローカル変数のアドレスを返さない
  • ポインタの型をむやみに変換しない
PRACTICE

ミニ課題:最小値と最大値

配列、要素数、結果を書き込む二つのポインタを受け取り、最小値と最大値を返す関数を作ってください。空の配列を受け付けない設計も考えましょう。