ポインタとメモリ

C・C++のポインタとアドレス

このレッスンでは、変数のアドレスをポインタに保存し、ポインタを通して値にアクセスして元の変数を変更します。

はじめに

ポインタ(pointer)は、別の変数のメモリアドレスを保存する変数です。演算子&は変数のアドレスを取り出し、演算子*(間接参照、dereference)はポインタが指すアドレスにある値にアクセスします。ポインタはCとC++で最も重要な概念の1つです。

大切なポイント

  • ポインタは、まだ存在している正しい型のオブジェクトを指すか、nullにしておきましょう。
  • 確保したメモリ領域は、ちょうど1回だけ解放しましょう。
  • どの関数がメモリの持ち主(ownership)で、どのデータが読み取り専用(const)かをはっきりさせましょう。

CとC++のコード例

C
実行 →
main.c
#include <stdio.h>

int main(void) {
    int score = 70;
    int *score_ptr = &score;
    *score_ptr += 5;
    printf("score=%d same-address=%s\n", score,
           score_ptr == &score ? "yes" : "no");
    return 0;
}
実行結果
score=75 same-address=yes
C++
実行 →
main.cpp
#include <iostream>

int main() {
    int score = 70;
    int* score_ptr = &score;
    *score_ptr += 5;
    std::cout << "score=" << score << " same-address="
              << std::boolalpha << (score_ptr == &score) << '\n';
}
実行結果
score=75 same-address=true

CとC++の比較

ポインタscore_ptrにはscoreのアドレスが入っているので、*score_ptr += 5は実際には変数score自身に5を足し、70から75に増やします。比較score_ptr == &scoreで、2つのアドレスが同じであることを確かめています。C++でも、メモリを管理せずアクセスだけしたい場合は生のポインタ(raw pointer)を使いますが、空になることがない場合は参照を使うのが一般的です。

C

メモリの持ち主と解放は、すべてプログラマーが自分で保証します。

C++

コンテナとRAIIが、オブジェクトの寿命が終わるときにリソースを自動で解放します。

発展問題

両方のバージョンを実行し、コードを書き換えて、それぞれの言語がもたらす安全性の違いを観察しましょう。

  • nullポインタやメモリ確保の失敗で試しましょう。
  • AddressSanitizerとUndefinedBehaviorSanitizerを付けて実行し、メモリのエラーを見つけましょう。
  • どのポインタがメモリの持ち主で、どのポインタが読むだけかをはっきり書き添えましょう。

チャレンジで練習する

このレッスンの内容を使って実際の問題を解きましょう。各チャレンジはブラウザで動き、すぐにテストされ、AI のレビューも受けられます。

すべてのチャレンジ