4
int main()
{
   char myString = NULL;
   realloc(&myString, 5);
   strncpy((char *)&myString, "test", 5);
}

正常に動作しているように見えますが、スタックとヒープについてはまだ少し混乱しています。これは許可されていますか?許可されている場合、myString手動で解放する必要がありますか、それともスコープ外になったときに解放されますか?


編集:回答ありがとうございますので、これも同様に違法だと思います

//I want the code to change myString to "tests"
char myString[5] = "test";
realloc(&myString, strlen(myString)+2);
myString[4] = 's';
myString[5] = '\0';
4

9 に答える 9

19

いいえ、これは完全に間違っています。reallocは、mallocによって割り当てられたメモリを再割り当てするためにのみ使用する必要があります。実行していることは偶然にのみ機能し、最終的にはひどくクラッシュします。

char *myString = malloc(x);
myString = realloc(myString,y);
free(myString)

ただし、newとdeleteを使用する方が適切であり、std::stringを使用する方がさらに適切です。

于 2009-03-16T14:44:17.077 に答える
8

投稿したコードに関するいくつかの問題:

  • はい、malloc、realloc、およびその他の関連するCスタイルのメモリ割り当て関数で割り当てるすべてのものを解放する必要があります。
  • charではなくchar*myStringを使用するつもりだったと思います。スタック上の何か(あなたのchar)のアドレスを渡すことは完全に間違っています。
  • reallocで使用する前に、myStringcharポインタをNULLに初期化する必要があります。
  • より大きな文字列がある場合は、メモリを上書きするため、5ではなく4をstrncpyに渡す必要があります。
  • 例で作成したバッファを解放する必要があります
  • realloc呼び出しの戻り値を確認する必要があります。realloc()

[reallocの戻り値について:] 0以外のサイズで正常に完了すると、realloc()は(移動された可能性のある)割り当てられたスペースへのポインターを返します。サイズが0の場合、nullポインターまたはfree()に正常に渡すことができる一意のポインターが返されます。使用可能なメモリが十分にない場合、realloc()はnullポインタを返し、errnoを[ENOMEM]に設定します。

  • NULLを渡すと、re-allocはmallocのように機能します。

ptrがnullポインターの場合、realloc()は、指定されたサイズに対してmalloc()のように動作します。

それを行うためのより多くのC++の方法:

ただし、これをC ++としてタグ付けしたので、C++の新しい演算子を使用する方がタイプセーフです。new演算子は再割り当てを許可しませんが、割り当ておよび既存のバッファーの再利用(新規配置)には機能します。

char *myString = new char[5];
strncpy(myString, "test", 4); 
//...
delete[] myString;

あるいは:

#include <string>

//...

std::string str = "test";

トップ2の引用の出典

于 2009-03-16T14:43:48.950 に答える
4

これは機能しないはずです。そもそもマロケートされていないものを再割り当てしています。いいえ、スコープ外になっても解放されません。mallocまたはreallocを使用する場合は、すべてあなた次第です。

更新:編集によって何も変更されません。そもそもmallocされていないものを再割り当てしようとしています。また、reallocからの戻り値を無視することはできません。reallocがメモリを別の場所に移動する必要がある場合は、戻り値でそれを見つけることができます。言い換えると:

char* ptr = malloc(4);
ptr = realloc(ptr, 5);

reallocの後、ptrはメモリ内のまったく異なる場所を指している可能性があり、ptrの元の値を引き続き使用すると、解放されて思ったほど大きくないメモリを使用したままになる可能性があります。

于 2009-03-16T14:43:03.977 に答える
2

これは危険です!これにより、スタックが破損します。関数のスタック上で何かを再割り当てしてからmain()に戻すと、実際にはスタックフレームを上書きして、main()以外の場所に戻ることになります。これは潜在的なセキュリティホールです。

次のコマンドを実行してみてください。reallocでクラッシュした場合は、幸運に恵まれます。memcpy(&myString)のようなもので深刻なダメージを与えることができます。

int dostuff();

int main()
{
        dostuff();
        return 0;
}

int dostuff()
{
        char myString = NULL;
        realloc(&myString, 5);
        strncpy((char *)&myString, "test", 5);
        return 0;
}
于 2009-03-16T14:46:52.453 に答える
2

これはあなたが決してしてはいけないことです。スタック変数をfree()またはrealloc()しようとすると、スタックの破損(制御の予期しないフローにつながる)、ヒープサービス構造の破損、ユーザーメモリの破損など、未定義の動作が発生する可能性があります。プログラムがAVでクラッシュするだけなら、あなたは幸運です。場合によっては機能することもありますが、絶対にそうしようとしないでください。

経験則:割り当てられたメモリマネージャにのみメモリを返します。この場合、スタック変数をランタイムヒープに戻そうとしないでください。

于 2009-03-16T14:51:24.283 に答える
2

プログラムは構文的には有効な C++ ですが、スタック オブジェクトのアドレスをヒープ アロケーターに渡すため、未定義の動作が発生します。通常、これは実行時にプログラムがクラッシュすることを意味します。

スタックとヒープは、プログラムを実行するプロセスに割り当てられる 2 つの異なるメモリ領域です。スタックは、引数とローカル変数を保持するために関数に入ると大きくなり、関数から戻ると自動的に縮小します。一方、ヒープは、必要に応じてメモリを取得できる別のアドレス領域であり、不要になったときに明示的に解放する必要があります。

ローカル変数のアドレスが realloc() に渡されると、メモリを解放して別の場所に割り当てようとする場合があります。アドレスはヒープからではなく、realloc() はヒープ上で動作するため、これは失敗します。ほとんどの場合、realloc() はアドレスがヒープからのものではないことを検出し、プログラムを中止します。


これとは別に、サンプル プログラムにはいくつかの論理エラーが含まれています。


char myString = NULL;

文字列ではなく文字を保持する変数を宣言します。C スタイルの文字列には type char*、つまり char へのポインタがあります。

NULLまた、従来は無効なポインタに割り当てられていたアドレス 0 にchar が割り当てられます。プリプロセッサがNULLリテラルに置き換えるため、これはコンパイルされ0ます。実際には、char に 0 バイトを格納します。これは、慣例により、C スタイルの文字列のターミネータでもあります。


realloc(&myString, 5);

前述のように、スタック オブジェクトのアドレスをヒープ アロケーターに渡すため、これは違法です。この問題は、2 番目のコード例に残っています。

また、戻り値を破棄します。realloc()新しいメモリが割り当てられたアドレスを返します。以前と同じアドレスではない可能性があります。NULL の場合もあります。これはrealloc()、メモリが不足していることを示す方法です。


strncpy((char *)&myString, "test", 5);

これは正しいですが、キャストは冗長です。


あなたのプログラムのより正しいバージョンは次のとおりです。


#include <stdlib.h>
#include <string.h>

int main()
{
   /* allocate space for, say, one character + terminator */
   char* myString = (char*) malloc(2);

   /* some code using myString omitted */

   /* get more space */
   myString = (char*) realloc(myString, 5);

   /* write to the string */
   strncpy(myString, "test", 5);

   /* free the memory */
   free(myString);

   return 0;
}

C++ では、realloc() を完全に回避することをお勧めします。たとえば、次のようなものを使用できます。


#include <string>

int main()
{
   std::string myString;

   /* some code using myString */

   myString = "test";

   return 0;
}
于 2009-03-25T23:26:31.303 に答える
0

スタック上にあるため、解放する必要はありませんmyString(スコープを離れると「解放」されます)。

reallocここでは違法です。アドレスは、またはNULLへの以前の呼び出しによって返されたアドレスである必要があります。reallocmalloccalloc

宣言するすべての変数は、ポインタも含めてスタック上にあります。

int * x;

変数xはスタックにあります!タイプpointerであり、アドレスを保持します。

x =(int *)malloc(sizeof(int));

によって返されたアドレスmallocを変数x!に割り当てます。の内容xはメモリアドレスです!

于 2009-03-16T14:47:21.967 に答える
0

あなたがしていることの問題は、あなたが変数ではない何かをいじっているということです。myStringをcharとして定義したため、そのアドレスを変更しようとしています。それは良くないね。

関数realloc()は、渡されたものを変更することは想定されていません。ヒープ上のメモリへのポインタ(または、まだ何も割り当てられていない場合はnullポインタ)を受け取り、ヒープ上のメモリへのポインタを返します。

したがって、nullポインター、またはmalloc()、realloc()、またはcalloc()によって割り当てられたものへのポインターを指定し、返されたポインターを保管します。

何かのようなもの

char * myString = NULL;
myString = realloc(myString, 5);

動作しますが、myStringをfree()する必要があります。

ただし、C ++では、std::stringを使用します。

于 2009-03-16T14:51:47.760 に答える
0

2 番目のコード例に応じて:

はい、これも違法です。myString は malloc (または calloc) で割り当てられないため、realloc で再割り当てしたり、free で解放したりすることはできません。

さらに、その realloc は、ポインターへのポインターを最初の引数として取りません。割り当てられたメモリへのポインターを受け取り、別の (おそらく異なる) ポインターを返します。代わりに、次のように呼び出しを記述します。

myString = realloc(myString, strlen(myString)+2);
于 2009-03-16T15:15:23.197 に答える