シンプル:メモリリークするからです。そして、メモリリークは悪いです。リーク: 悪い、フリー: 良い。or 、または実際に *alloc 関数
を呼び出すときは、メモリのチャンクを要求しています (そのサイズは、割り当て関数に渡される引数によって定義されます)。malloc
calloc
プログラムが持っているメモリの一部に存在するスタック変数とは異なり、自由に支配され、同じルールがヒープメモリには適用されません。さまざまな理由でヒープ メモリを割り当てる必要がある場合があります。スタックが十分に大きくない、ポインタの配列が必要であるが、コンパイル時にこの配列が必要な大きさを知る方法がない、共有する必要があるメモリの一部 (スレッド化の悪夢)、プログラム内のさまざまな場所 (関数) でメンバーを設定する必要がある構造体...
これらの理由のいくつかは、その性質上、メモリへのポインタが範囲外になるとすぐにメモリを解放できないことを意味します。同じメモリ ブロックを指す別のポインターが、別のスコープ内にまだ存在している可能性があります。
ただし、コメントの 1 つに記載されているように、これにはわずかな欠点があります。ヒープ メモリは、プログラマ側でより多くの認識を必要とするだけでなく、スタックでの作業よりも高価で遅くなります。
したがって、いくつかの経験則は次のとおりです。
- あなたはメモリを要求したので、それを大事に扱います... 遊んだ後は解放されていることを確認してください。
- 正当な理由がない限り、ヒープ メモリを使用しないでください。たとえば、スタック オーバーフローを回避することは正当な理由です。
とにかく、いくつかの例:
スタック オーバーフロー:
#include <stdio.h>
int main()
{
int foo[2000000000];//stack overflow, array is too large!
return 0;
}
ここではスタックを使い果たしたので、ヒープにメモリを割り当てる必要があります。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *foo= malloc(2000000000*sizeof(int));//heap is bigger
if (foo == NULL)
{
fprintf(stderr, "But not big enough\n");
}
free(foo);//free claimed memory
return 0;
}
または、長さがユーザー入力に依存する配列の例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *arr = NULL;//null pointer
int arrLen;
scanf("%d", &arrLen);
arr = malloc(arrLen * sizeof(int));
if (arr == NULL)
{
fprintf(stderr, "Not enough heap-mem for %d ints\n", arrLen);
exit ( EXIT_FAILURE);
}
//do stuff
free(arr);
return 0;
}
リストは続きます... malloc
orcalloc
が役立つ別のケース: 文字列の配列で、すべてのサイズが異なる場合があります。比較:
char str_array[20][100];
この場合str_array
は、それぞれ 100 文字の長さの 20 文字の配列 (または文字列) の配列です。しかし、必要な最大文字数が 100 文字で、平均して 25 文字以下しか使用しないとしたらどうでしょうか。
C で書いているのは、高速であり、プログラムが実際に必要とする以上のリソースを使用しないためですか? それでは、これはあなたが実際にやりたいことではありません。おそらく、次のことが必要です。
char *str_array[20];
for (int i=0;i<20;++i) str_array[i] = malloc((someInt+i)*sizeof(int));
の各要素には、str_array
必要なメモリ量が正確に割り当てられています。その方がずっときれいです。ただし、この場合、呼び出しfree(str_array)
はそれをカットしません。もう 1 つの経験則は次のとおりです。各 alloc 呼び出しには、free
それに一致する呼び出しが必要なので、このメモリの割り当て解除は次のようになります。
for (i=0;i<20;++i) free(str_array[i]);
注:
メモリ リークの原因は、動的に割り当てられたメモリだけではありません。それは言わなければならない。ファイルを読み取る場合、 を使用してファイル ポインタを開きますfopen
が、そのファイル ( ) を閉じるのに失敗するfclose
と、リークも発生します。
int main()
{//LEAK!!
FILE *fp = fopen("some_file.txt", "w");
if (fp == NULL) exit(EXIT_FAILURE);
fwritef(fp, "%s\n", "I was written in a buggy program");
return 0;
}
コンパイルして正常に実行されますが、リークが含まれており、1 行追加するだけで簡単にプラグインできます (プラグインする必要があります)。
int main()
{//OK
FILE *fp = fopen("some_file.txt", "w");
if (fp == NULL) exit(EXIT_FAILURE);
fwritef(fp, "%s\n", "I was written in a bug-free(?) program");
fclose(fp);
return 0;
}
余談ですが、スコープが非常に長い場合は、1 つの関数に詰め込みすぎている可能性があります。そうでない場合でも、要求されたメモリはいつでも解放できます。現在のスコープの最後である必要はありません。
_Bool some_long_f()
{
int *foo = malloc(2000000000*sizeof(int));
if (foo == NULL) exit(EXIT_FAILURE);
//do stuff with foo
free(foo);
//do more stuff
//and some more
//...
//and more
return true;
}