mallocとfree

実行してみるまで人数が分からない

入門で書いた成績管理は int scores[100]; のような固定長の配列でした。この書き方は、要素数をコンパイルの時点で決めなければなりません。10人しか来なくても100人分の場所を取り、101人来たら破綻します。

人数を実行時に読み取ってから、その人数ぶんだけ場所を借りたい。そのための道具が malloc です。前回まで見てきた3つの領域のうち、ヒープを使います。

malloc が返すもの

malloc<stdlib.h> にあり、必要なバイト数を渡すと、その大きさの領域の先頭アドレスを返します。

int n = 3; int *scores = malloc(sizeof(int) * n);

渡すのは要素数ではなくバイト数です。int が3個なら sizeof(int) * 3 で12バイトになります。sizeof(int) * n と書いておけば型を変えても壊れないので、数字の 12 を直接書かないでください。

返ってくるのは void * という「型の決まっていないポインタ」で、代入する変数の型に合わせて自動で変換されます。C言語では (int *) のキャストは不要です。

NULL を確かめる

借りられなかったときは NULL が返ります。この確認を飛ばして使うと、失敗した瞬間ではなく少し先で落ち、原因が分からなくなります。

if (scores == NULL) { printf("確保に失敗しました\n"); return 1; }

確保した領域は普通の配列のように使える

scores はポインタですが、第1章でやったとおり scores[i] と書けます。*(scores + i) と同じ意味です。違うのは大きさが実行時に決まることと、後始末が自分の仕事になることだけです。

free は「消す」ではなく「返す」

使い終わったら free(scores); で返します。ここで起きるのは「借りていた領域を、また誰かに貸してよい状態に戻す」ことです。中の値が0で塗り潰されるわけではなく、scores に入っていたアドレスが消えるわけでもありません。

だから free のあとの scores は、もう自分のものではない場所を指したままになっています。これが前回出てきたダングリングポインタです。読めてしまうことがあるので、たちが悪いのも同じです。

そこで、返した直後に NULL を入れておきます。

free(scores); scores = NULL;

こうしておけば、うっかり触ったときに「たまたま動く」ではなく確実に落ちるので、間違いがその場で分かります。free(NULL) は何もしない安全な動作と決まっているので、二重に free してしまう事故も防げます。

今回は人数を読み取ってから、その人数ぶんの点数を動的に確保して集計します。

要件

  1. malloc で n 人分の int を確保する。バイト数は sizeof(int) * n で求める
  2. 戻り値が NULL のときは「確保に失敗しました」と出して return 1 する
  3. 平均は %.1f で小数第1位まで出す
  4. free したあと変数に NULL を入れ、最後の行を表示する

入出力例

main("3 80 90 79") → "人数 3 確保 12 バイト 合計 249平均 83.0解放後 scores は NULL です" main("5 60 71 80 90 95") → "人数 5 確保 20 バイト 合計 396平均 79.2解放後 scores は NULL です"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.c
学習モード

メモ

mallocとfree

⌘S で保存