示されている特定のコードでは、最初にヌル ポインターを使用しても問題はありません。
変数ptr
が初期化されていない場合 (0 または NULL に設定されていない場合)、それをrealloc()
使用する呼び出しは危険です。動作は定義されておらず、運が良ければプログラムはクラッシュしますが、運が悪ければ、プログラムの後半で問題が発生し、問題を特定するのが困難になるまで、しばらくは機能しているように見えます。ずっと前に実行されたコードで。
malloc()
最初の割り当て以降に使用する方が良いと主張する人がいますrealloc()
。特に、メモリを解放することができたとしても、メモリを解放するために使用ptr = realloc(ptr, 0);
しない可能性があるためです (実際には必要ないmalloc()
か、3 つの操作すべてを実行できるfree()
ためrealloc()
)。しかし、C90 標準ではrealloc(0, new_size)
と同等に動作する必要malloc(new_size)
があり、異なる動作をする C ライブラリを私は知りません (ただし、いくつかあるかもしれません。ほとんどが最も広く使用されているものではありますが、いくつかの C ライブラリしか使用していません)。
ただし、次のコードのようなより一般的なケースでは、コードに微妙な問題があります (ただし、最初の null ポインターには関係ありません)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *ptr = NULL;
size_t len = 0;
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin))
{
size_t buflen = strlen(buffer) + 1;
if (buflen > len)
{
if ((ptr = realloc(ptr, buflen)) == 0) // Danger!
// ... handle memory allocation failure ...
len = buflen;
}
strcpy(ptr, buffer);
// ... do something with ptr
}
free(ptr);
return 0;
}
危険は何ですか?危険なのは、2 回目以降のメモリ割り当てが失敗ptr
し、割り当てられたメモリへの唯一のポインタである場合、以前の値を null で上書きすることです。つまり、これ以上使用して割り当てられたメモリを解放することはできませんptr
— メモリ リークが発生しました。(最初の割り当てでは、初期値は 0、上書きされた値は 0 で、何も変更されていません。メモリ リークはありません。そのため、コードにループが追加されています。)
経験則
- 書かないで
ptr = realloc(ptr, newsize);
テストが完了するまで、新しい値を別の変数に保存します。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *ptr = NULL;
size_t len = 0;
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin))
{
size_t buflen = strlen(buffer) + 1;
if (buflen > len)
{
char *new_ptr = realloc(ptr, buflen);
if (new_ptr == 0)
// ... handle memory allocation failure ...
ptr = new_ptr;
len = buflen;
}
strcpy(ptr, buffer);
// ... do something with ptr
}
free(ptr);
return 0;
}
このコードは、割り当ての失敗時にメモリをリークしません。
補助的な推奨事項: という変数を使用しないでくださいnew
。C++ コンパイラでコンパイルするのが難しくなります。今は C++ に変換するつもりがなくても (そして、そうするとメモリ管理を書き直すことになるかもしれませんが)、C++ キーワードnew
を C 変数名として使用するメリットはありません...明示的に変換したい場合を除きます。 C++ コンパイラでのコンパイルを防ぎます。