現在までのプログラムでは、変数はすでにプログラムの段階で大きさが決定されていた。 しかしながら、様々な場面で用いられるプログラムの場合、扱うデータの量はあらかじめ予想できない。 (たとえば、課題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
関数の書式は次のようなものである。
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'
が含まれているかどうかで
判断しても良い。ただし、その場合には、最終行に改行文字が含まれていなかった場合の処理を考慮する必要がある。
与えられたファイルに含まれる各行を検査し、もっとも長い行に関する情報を 表示するプログラムを作成せよ。 表示する情報としては、行番号、長さおよび、その行そのものの3つとする。 ただし、一行の長さに関する制限はないものとする。
課題11ででてきた、構造体 student_info
の定義を次のように変更して、
できるだけ、メモリに無駄のないようなプログラムに変更せよ。
ヒント: すでに取り上げた関数 strlen
、strcpy
を使っても良いし、
strdup
関数を使っても良い。
struct student_info { char gakuseki_bango[10]; char *family_name; char *given_name; int shusseki; int mark; };
さらにに、受講生の数が何人であっても対応できるようにプログラムを改良せよ。
11日目 | 表紙 | 13日目 |