コース一覧
    C言語中級 連結リスト・応用
    動的な二次元配列

    C言語中級 連結リスト・応用

    C言語の連結リストと応用的なデータ操作を学び、実装でデータを扱うコースです。

    1
    連結リスト
    01. 配列の限界15分
    02. ノードを定義する15分
    03. 先頭に追加する15分
    04. リストを歩く15分
    05. 任意位置の挿入と削除15分
    06. リストを全解放する15分
    07. つくる リスト版成績管理15分
    08. 第5章クイズ10分
    2
    応用
    01. 動的な二次元配列15分
    02. コマンドライン引数15分
    03. バイナリ保存15分
    04. エラーの調べ方15分
    05. つくる 引数とバイナリ保存15分
    06. 第6章クイズ10分
    3
    総合制作
    01. リスト版を完成させる20分
    02. メモリバグ演習20分
    03. 自由拡張20分
    04. 完成と次のステップ10分

    動的な二次元配列

    表の形のデータをどう置くか

    第4章で Student の動的配列を作りました。あれは1人につき1つの点数を持つ、細長い一列のデータでした。ここからは学生ごとに国語・数学・英語の3科目を持つ、表の形のデータを扱います。

    人数が実行時に決まる以上、int table[10][3]; のような固定の二次元配列では足りません。行のほうを、動く形で用意する必要があります。

    int は「行へのポインタを並べた配列」

    C で動的な表を作るときの定番は、次の2段構えです。

    c

    int **table = malloc(sizeof(int *) * n);   /* 行へのポインタを n 本 */
    for (int i = 0; i < n; i++) {
        table[i] = malloc(sizeof(int) * 3);    /* 各行の実体を 3 個ずつ */
    }

    1回目の malloc が確保しているのは点数ではなく ポインタ** です。だから要素1個の大きさは sizeof(int *) になります。ここを sizeof(int) と書き間違えると、64 ビット環境では必要な量の半分しか取れず、後ろのほうの行を書いた瞬間に他人の領域を壊します。しかも壊れるのは書いた場所ではなく、あとから読んだ別の場所なので、原因を追うのがとても難しくなります。

    2回目以降の malloc が、実際に点数が入る場所です。table[i] は int * なので、table[i][j] と書けば i 番目の学生の j 科目目になります。これは *(*(table + i) + j) の短い書き方で、第1章でやった a[i] と *(a + i) の同値が、そのまま2段に重なっただけです。

    確保と解放は逆の順にする

    解放するときは、確保したのと逆の順に戻します。

    c

    for (int i = 0; i < n; i++) {
        free(table[i]);
    }
    free(table);

    先に free(table) を書いてしまうと、そのあとの table[i] は解放済みの領域を読むことになります。第2章で扱ったダングリングポインタそのもので、行の置き場所を書いた紙を先に捨ててから、中身を捨てに行こうとしている状態です。

    行ごとに長さを変えられる

    この形は行を別々に確保しているので、行ごとに長さを変えられます。学生によって受けた科目数が違う表も素直に書けます。

    もう1つ、malloc(sizeof(int) * n * m) で1枚の大きな領域を取り、data[i * m + j] と自分で添字を計算する方法もあります。こちらは確保も解放も1回で済み、領域が飛び飛びにならないぶん速く読めます。行の長さがそろっているならこちらが有利です。

    では、人数を読み込んで点数表を動的に確保し、学生ごとと科目ごとの合計を出してみましょう。

    要件

    1. 行へのポインタの配列と、各行の実体を malloc で確保する
    2. 学生ごとの合計を 学生1の合計は240点です の形で人数ぶん出す
    3. 続けて科目ごとの合計を 科目1の合計は140点です の形で3行出す
    4. 最後に各行と表本体を解放する

    ヒント

    1回目の malloc は点数ではなくポインタを並べるので、要素の大きさは sizeof(int *) です

    解放は行を先に、表本体をあとにします。順番を逆にすると解放済みの領域を読むことになります

    生田 陸人
    監修生田 陸人
    ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
    編集 ゆめさく編集部·公開 2026/08/07

    関連レッスン

    • コマンドライン引数

      起動時に渡された値を受け取れるようになります。

    • バイナリ保存

      構造体をそのままの形で保存して読み戻せるようになります。

    • エラーの調べ方

      失敗の理由を具体的に表示できるようになります。

    • つくる 引数とバイナリ保存

      起動と保存を実用的な形にできるようになります。

    main.c
    エディタを読み込んでいます

    メモ

    動的な二次元配列

    ⌘S で保存