ポインタとメモリ

C・C++の動的メモリ管理

このレッスンでは、実行時に大きさが決まる配列を確保し、そのメモリを安全に解放します。

はじめに

動的メモリは、データの大きさや寿命がコンパイル時に決まらないときに使います。たとえば要素の数がユーザーの入力によって変わる場合です。このメモリはプログラムの実行中に確保され、使い終わったら解放しなければなりません。

大切なポイント

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

CとC++のコード例

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

int main(void) {
    size_t count = 5;
    int *values = calloc(count, sizeof *values);
    if (!values) return 1;
    for (size_t i = 0; i < count; ++i) values[i] = (int)(i * i);
    printf("last=%d\n", values[count - 1]);
    free(values);
    return 0;
}
実行結果
last=16
C++
実行 →
main.cpp
#include <iostream>
#include <vector>

int main() {
    std::vector<int> values(5);
    for (std::size_t i = 0; i < values.size(); ++i) values[i] = static_cast<int>(i * i);
    std::cout << "last=" << values.back() << '\n';
}
実行結果
last=16

CとC++の比較

Cのcallocは5個の整数分のメモリを確保し、0で初期化します。プログラムは確保に失敗していないかを確認し、使い終わったらfreeで解放する必要があります。忘れるとメモリリーク(memory leak)が起こります。C++のstd::vectorは自分でメモリを管理し、例外が起きた場合も含めて、使われなくなると自動で解放します。

C

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

C++

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

発展問題

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

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

チャレンジで練習する

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

すべてのチャレンジ