C言語 | 高度な機能 | 動的メモリ割り当て - malloc(), free()
必要な記憶容量が実行時までわからない場合、プログラムはメモリを動的に割り当てる必要がある。C言語では、malloc() でメモリを確保し、free() で解放できる。
実行時のメモリ割り当て
通常の配列は宣言時にサイズが固定される。しかし、テキストエディターのようなアプリケーションでは、ユーザーが入力するデータ量をコンパイル時に決められない。
標準ライブラリの malloc() は stdlib.h に宣言されている。
malloc() 関数
void* malloc(size_t size);
size にはバイト数を指定する。確保に成功するとヒープ領域へのポインターを返し、失敗すると NULL を返す。ポインターを使う前に必ず NULL を確認する。
コード1
#include <stdio.h>
#include <stdlib.h>
#define ALPHABET_COUNT 26
int main() {
int iCount;
char *str = (char *)malloc(ALPHABET_COUNT + 1);
if (str == NULL) return 1;
for(iCount = 0 ; iCount < ALPHABET_COUNT ; iCount++)
str[iCount] = 0x41 + iCount;
str[iCount] = 0;
printf("%s\n" , str);
free(str);
return 0;
}
このプログラムは27バイトを確保し、アルファベットを表示する。確保した範囲を超えてアクセスしてはならない。他の型では、sizeof(int) * 4 のように sizeof で必要なバイト数を計算する。
malloc() で確保したメモリは、ローカルスコープを抜けても自動的には解放されない。解放せずに割り当てを繰り返すと、メモリリークが発生する。
コード2
#include <stdio.h>
#include <stdlib.h>
int main() {
while(1) {
int *iPo = (int *)malloc(sizeof(int) * 0x100000);
if (iPo == NULL) {
printf("メモリを割り当てられませんでした。\n");
break;
}
printf("iPo = %p\n" , iPo);
}
return 0;
}
この例ではポインターを失うため、確保した領域を再利用できない。長時間動作するプログラムでは、利用可能なメモリを使い果たす原因になる。
free() 関数
void free(void *memblock);
割り当て関数が返したポインターだけを渡し、同じポインターを2回解放してはならない。
コード3
#include <stdio.h>
#include <stdlib.h>
int main() {
while(1) {
int *iPo = (int *)malloc(sizeof(int) * 0x100000);
if (iPo == NULL) {
printf("メモリを割り当てられませんでした。\n");
break;
}
printf("iPo = %p\n" , iPo);
free(iPo);
}
return 0;
}
実際のプログラムでは、メモリの割り当てと解放を別々の関数で行うことが多い。ポインターの所有権を明確にし、各領域をいつ解放するかを決めておく必要がある。