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;
}

実際のプログラムでは、メモリの割り当てと解放を別々の関数で行うことが多い。ポインターの所有権を明確にし、各領域をいつ解放するかを決めておく必要がある。