11日目 13日目

12日目

目標


課題12

メモリの動的確保/解放

現在までのプログラムでは、変数はすでにプログラムの段階で大きさが決定されていた。 しかしながら、様々な場面で用いられるプログラムの場合、扱うデータの量はあらかじめ予想できない。 (たとえば、課題11で取り上げた学生の成績をつけるプログラムを例にとると、 受講生の数は開講初日にふたを開けてみないと判らない。)

学生の成績をつけるプログラムの場合には、最大数の予測をつけることもできるが、 一般の場合には予測が困難な場合も考えられるし、最大の場合に備えた巨大な配列を 用意することは資源(メモリ)の無駄遣いでもある。 あるいは配列が大きすぎて実行できなくなる場合も考えられる。 このような場合の最適な解決方法の一つは、必要な量のメモリを必要となった場合に用意するという戦略である。

メモリの確保

必要なときに必要なだけのメモリを確保する方法として、C では、malloc()関数を用いることができる。 (malloc()関数は stdlib.hで定義されているので、#include <stdlib.h>が必要である。) malloc 関数は確保したメモリの先頭アドレスを返すので、ポインタ変数を用いてそのメモリ領域を管理する。

  #include <stdlib.h>
  ...

  char *s;
  s = malloc(512);

上の例では 512バイトの領域を確保し、その先頭アドレスをポインタ変数 s に代入している。

  #include <stdlib.h>
  ...

  int *s;
  s = malloc(sizeof(int)*50);

上の例では、int 型の変数50個分の領域を確保し、その先頭アドレスをポインタ変数 s に代入している。

メモリが確保できなかった場合、malloc は、NULLを返すので、正しくメモリが確保できたかどうかを 確認することができる。当然ながら確保できなかった場合は、プログラムは期待通りの動きはしないのでエラーチェックを入れる必要がある。

メモリの解放

malloc関数で確保されたメモリは不要になっても、そのままでは解放されないため システムで利用可能なメモリが少なくなっていく。 (自動的に確保された変数はスコープを抜けると解放されていたのであった。) このため、malloc で確保した領域が不要になった場合、システムへ返却する必要がある。 システムの返却には free関数を用いる。free 関数はポインタを 引数に取り、そのポインタが指すメモリ空間を解放する。ただし、このポインタは 以前に呼び出された malloc関数(および、その仲間)が返した値でなければ ならないことに注意する。 (従って、途中で確保したメモリを解放したい場合には malloc 関数が返した値を保持する 変数と、その領域を操作するための変数の2つを利用することになる。)


fgets関数

ストリームから読み込む関数として、これまでに取り上げたものに加えて良く使うものとして fgets関数がある。 fgets関数の書式は次のようなものである。

    char *fgets(char *, int, FILE *);

使用例

     char buf[80];
     FILE *fp;
...
     fgets(buf, sizeof(buf), fp);

上の例では、fgets関数は、fpで指定されるストリームから 最大sizeof(buf)(80 である)よりも 1だけ少ないデータを読み込み、 buf に格納する。ただし、EOF(ファイルの終端)もしくは、改行文字を 読み込んだ時点で終了する。読み込んだ文字の後ろには '\0' 文字が付け加えられ、 buf は文字列として正しいことが保証される。

従って、fgetsは、行単位の処理を行いたい場合等に良く用いられる関数である。 行全体が読み込まれたかどうかは、終端文字の1つ前が改行かどうかで判断することが可能である。 あるいは、strchr関数を用いて、buf中に '\n' が含まれているかどうかで 判断しても良い。ただし、その場合には、最終行に改行文字が含まれていなかった場合の処理を考慮する必要がある。

問題 12-1

与えられたファイルに含まれる各行を検査し、もっとも長い行に関する情報を 表示するプログラムを作成せよ。 表示する情報としては、行番号、長さおよび、その行そのものの3つとする。 ただし、一行の長さに関する制限はないものとする。

問題12-2

課題11ででてきた、構造体 student_infoの定義を次のように変更して、 できるだけ、メモリに無駄のないようなプログラムに変更せよ。 ヒント: すでに取り上げた関数 strlenstrcpy を使っても良いし、 strdup関数を使っても良い。

 struct student_info {
      char gakuseki_bango[10];
      char *family_name;
      char *given_name;
      int shusseki;
      int mark;
};

さらにに、受講生の数が何人であっても対応できるようにプログラムを改良せよ。


11日目 表紙 13日目

tacha@tack.fukui-med.ac.jp
$Id$