プログラミング

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を指すポインタはそのまま読み書きしない

前の回 / 次の回:構造体と列挙型

← 記事一覧へ戻る