2009-03-16 19 views
3
int main() 
{ 
    char myString = NULL; 
    realloc(&myString, 5); 
    strncpy((char *)&myString, "test", 5); 
} 

うまく動作するようですが、私はまだスタック対ヒープについて少し混乱しています、これは許されていますか? myStringは手動で解放する必要がありますか、範囲外になると解放されますか?スタック&realloc質問C++


編集:回答のおかげで、私は、これはこれでうまくいかなければならない

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

はい、第2の亜種は「決してそうしない」部門のものです。 – sharptooth

+0

具体的には、malloc()、calloc()、またはrealloc()によって与えられなかった値を決してrealloc()するべきではありません。 –

答えて

18

いいえ、これは完全に間違っています。 reallocのは、あなただけの事故で作品をやっている、malloc関数によって割り当てられたメモリを再割り当てするために使用する必要があり、最終的にあなたが新しいを使用してオフに優れていると削除、およびSTDを使用してオフにしても良く恐ろしく

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

をクラッシュします::しかし、文字列。

+0

また、 "char * myString = NULL;"ヌルポインタを再割り当てします。 –

3

も同様に違法であると推定。あなたは最初に払われていなかったものを再割り当てしています。そして、それは範囲外になると解放されません。あなたがmallocまたはreallocを使うときは、あなた次第です。

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

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

は、ptrはメモリ内のまったく別の場所を指し、そしてptrが解放されていたメモリを使用して、あなたを残すことができるの元の値を使用し続けることとされる場合がありますように大きくはありませんそれはあなたが思うように。あなたが投稿したコードと

+0

これは問題ありません。 realloc()は非常に汎用性の高い関数であり(私の意見ではあまりにも多用途)、すべてのメモリ管理を行います。 –

+0

@David、それはokではありません - reallocはポインタを再割り当てすることができ、そのようなスタックに変数を再割当てすることはできません。 –

+0

まあ、良くない - 私は&myStringに気付かなかった。間違いなく良い。 –

8

いくつかの問題:

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

【のreallocの戻り値については:]が0に等しくないサイズ と正常に完了すると、のrealloc()は(おそらく移動) 割り当てられた領域に のポインタを返します。 sizeが0の場合は、 nullポインタまたは一意のポインタ のいずれかが正常に渡され、 free()が返されます。 十分なメモリがない場合、realloc() はNULLポインタを返し、errno を[ENOMEM]に設定します。

  • あなたはNULLを渡すときのreallocは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"; 

Source of top 2 quotes

+0

realloc()をNULLで使用するように定義されています。 realloc()ですべてのCメモリ管理を行うことができます。これが良いアイデアかどうかは別の質問です。 –

+0

これまでのところ、メモリを管理するC++の方法でさえないという事実は、あなたが唯一の人物です。あなたは私から+1を得る。 –

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

あなたはそれが(その取得「解放」残しスコープ)スタック上にあるためmyStringを解放する必要はありません。

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

あなたが宣言するすべての変数は、スタック上でもポインタです:

のint * X;

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

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

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

2

これは決して行うべきではありません。スタック変数をfree()またはrealloc()しようとすると、破損したスタック(予期せぬコントロールの流れ)、ヒープサービス構造の破損、ユーザーメモリの破損など、未定義の動作が発生する可能性があります。プログラムがただちにAVでクラッシュするならあなたは幸運です。場合によってはうまくいくかもしれませんが、決して行ってはいけません。

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

0

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

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

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

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

よう

何かが動作しますが、あなたは()のmyStringを解放することになるでしょう。

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

0

2番目のコード例に対する応答:

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

さらに、reallocはポインタへのポインタを最初の引数としてとらない。割り当てられたメモリへのポインタをとり、別の(場合によっては異なる)ポインタを返します。代わりに、このような呼び出しを書く:

myString = realloc(myString, strlen(myString)+2); 
1

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

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

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


これ以外にも、サンプルプログラムにはいくつかの論理エラーがあります。


char myString = NULL; 

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

また、charはNULLと割り当てられています。アドレス0は、通常は無効なポインタに割り当てられます。これは、プリプロセッサがNULLをリテラル0に置き換えたためにコンパイルされます。実際には、ゼロバイトをcharに格納します。これは、通常はCスタイルの文字列の終端文字です。

上記のように、スタックオブジェクトのアドレスをヒープアロケータに渡すため、これは不正です。この問題は、2番目のコード例に残ります。

また、戻り値を破棄します。 realloc()は、新しいメモリが割り当てられたアドレスを返します。以前と同じアドレスではない可能性があります。それはNULLであるかもしれません、それはrealloc()のそれがメモリから去ったことを伝える方法です。


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

これは正しいですが、キャストは冗長です。完全に)(reallocのを避けた方がよい、C++では


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

:ここ


は、あなたのプログラムのより適切なバージョンです。たとえば、次のようなものを使用できます。


#include <string> 

int main() 
{ 
    std::string myString; 

    /* some code using myString */ 

    myString = "test"; 

    return 0; 
}