私は realloc
について読んでいて、そこで言及されている点について混乱しました。以下のコードを検討してください:
#include <stdio.h>
#include <stdlib.h>
int main () {
int* ptr = NULL;
ptr = realloc(ptr, 10*sizeof(int));
return 0;
}
最初にrealloc
値のNULL
を使用してptr
でメモリを割り当てることに危険はありますか?代わりに:
int* ptr = NULL;
私はこれを持っていました:
int* ptr; // no value given to ptr
realloc
を使用してptr
を呼び出すのは問題でしょうか?
最初にNULL値のptrを使用してreallocでメモリを割り当てることには危険がありますか
None
7.22.3.5
PtrがNULLポインターの場合、realloc関数は、指定されたサイズのmalloc関数のように動作します。
2番目の部分:
int* ptr; // no value given to ptr
ptrを使用してreallocを呼び出すのは問題でしょうか?
初期化されていないポインタを使用している場合、その値が何であるかを予測できないため、それは実際に非常に深刻な問題です。関数realloc
は、NULL
またはmalloc
/realloc
から取得した値に対してのみ正しく機能します。
それ以外の場合、ptrがメモリ管理関数によって以前に返されたポインタと一致しない場合[...]動作は未定義です。
特定のコードが示されている場合、最初にnullポインターを使用しても問題はありません。
変数ptr
が初期化されていない場合-0またはNULLに設定されていない場合-を使用してrealloc()
を呼び出すと危険です。動作は未定義であり、運が良ければプログラムはクラッシュしますが、運が悪ければ、しばらくの間動作しているように見え、プログラムの後で問題が発生して問題を特定するのが困難になります。ずっと前に実行されたコードで。
最初の割り当てにはmalloc()
を使用し、その後はrealloc()
を使用する方がよいと主張する人もいます。特に、ptr = realloc(ptr, 0);
を使用してメモリを解放することはできないとしても(たとえmalloc()
や[ free()
は、realloc()
は3つの操作すべてを実行できるため)。しかし、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++コンパイラでのコンパイルを明示的に禁止する場合を除きます。
最初にNULL値のptrを使用してreallocを使用してメモリを割り当てることに危険はありますか?
いいえ、それはmalloc
とまったく同じです。
代わりに:
int* ptr = NULL;
私はこれを持っていました:
int* ptr; // no value given to ptr
ptrを使用してreallocを呼び出すのは問題でしょうか?
はい、問題があります。 realloc
がNULL
を取得しない場合、その場所からメモリを拡張しようとするか、またはmayfree
とmalloc
のメモリの別の部分を試します。 初期化されていない変数は任意の値をとることができるであるため、確率は非常に高く、realloc
のような値ではありません。運が良ければ、プログラムはすぐにクラッシュします。