2013-01-17 9 views
13

以下は3つの関数です。 main()は期待どおりに出力します。 mycharstack()の文字列はスタックに格納されているので、 "ch"が範囲外になると文字列を返すことはできません。どのように正しく動作しますか? mychar()に格納されている文字列もスタックにあると思います。それは正しく動作するはずですか? コードやメモリリークに他のエラーがあると思いますが、もしあれば教えてください。私はこれらのクリーナー& std :: stringで簡単に行うことができます。しかし、私はchar *で何が起こっているのか理解したい。戻り値char * from function

#include <iostream> 
using namespace std; 

char* mychar() 
{ 
    return "Hello"; 
} 

char* mycharstack() 
{ 
    char* ch = "Hello Stack"; 
    return ch; 
} 

char* mycharheap() 
{ 
    char* ch = new char; 
    ch = "Hello Heap"; 
    return ch; 
} 

int main() 
{ 
    cout << "mychar() = " << mychar() << endl; 
    cout << "mycharstack() = " << mycharstack() << endl; 
    cout << "mycharheap() = " << mycharheap() << endl; 

    system("PAUSE"); 
    return 0; 
} 

答えて

15

C++では、文字列の処理が、たとえばパスカルとは異なります。

char* mycharheap() 
{ 
    char* ch = new char; 
    ch = "Hello Heap"; 
    return ch; 
} 

これは、次のん:

  1. char* ch = new char;は1文字分のメモリを作成し、バイト"Hello Heap\0"が含まれているメモリを読み取り専用にする変数chポインタに代入する変数ch
  2. ch = "Hello Heap";に割り当てます。また、変数chの元の内容が失われ、メモリリークが発生します。
  3. return ch;は、変数chに格納されたポインタを返します。あなたはおそらく望ん

char* mycharheap() 
{ 
    char* ch = new char[11] /* 11 = len of Hello Heap + 1 char for \0*/; 
    strcpy(ch, "Hello Heap"); 
    return ch; 
} 

注あるstrcpy - >あなたは11文字のためのスペースを持っているchのメモリを持っている、とあなたは読み取り専用部分から文字列でそれを埋めていますメモリの。

この場合、リークが発生します。あなたは次のように、書き込み後のメモリを消去する必要があります。

char* tempFromHeap = mycharheap(); 
cout << "mycharheap() = " << tempFromHeap << endl; 
delete[] tempFromHeap; 

しかし、私は非常にこの(呼び出し先で割り当てたメモリを、呼び出し側で削除)やってお勧めしません。このような状況では、たとえばSTL std::stringがあります。もう1つの一般的でより合理的なアプローチは、呼び出し元に割り当て、呼び出し先に渡すことです。結果をメモリに '充填'し、呼び出し元で再度割り当てを解除します。未定義の動作になりますどのような

は以下の通りです:

char* mycharstack() 
{ 
    char[] ch = "Hello Heap"; /* this is a shortcut for char[11] ch; ch[0] = 'H', ch[1] = 'e', ...... */ 
    return ch; 
} 

これはバイト"Hello Heap\0"でスタック上の配列を作成し、その後(その配列の最初のバイトへのポインタを返すように試みることができ、関数を呼び出すことで、何かを指す)

+0

If私はちょうど私のコードで言及したものとmycharheap()を置き換えました、まだリーク...右でしょうか? main()では、割り当てられたメモリを解放するものはありません。 – ontherocks

+0

はい。私の更新された答えを見てください。 – nothrow

+0

mycharheap()のような関数では、char *を入力パラメーターとする他の関数のパラメーターとして直接使用することはお勧めしません。例えば、print(char * char_in);という関数があるとします。 'print(mycharheap());'のようなことはしないでください。それはメモリリークを引き起こすでしょう。私は正しい?正確には – ontherocks

0

機能mycharheap()が漏れている:あなたは、ヒープ上に割り当てられた1 charの長さのメモリ領域へのポインタのポイントを作る、そしてあなたが読み取りに格納された文字列リテラルを指すようにそのポインタを変更メモリのみ。割り当てられたメモリは解放されません。

+0

割り当てられたメモリを解放するにはどうすればよいですか?つまり、上記のコードではどこでdeleteを呼び出しますか? – ontherocks

+0

@ontherocks:この質問は間違っています;-)最初にポインタを再割り当てするべきではありません。ヒープに "hello world"という文字列を割り当てたい場合は、十分な長さのバッファ( 'new char [size]')を割り当てて、そのバッファに文字列をコピーします。一度ポインタを呼び出し元に戻すと、呼び出し側はそれを削除する責任があります(結果を 'char *'ポインタに代入して、そのポインタ上で 'delete'を –

+0

の後に呼び出すことによって)。したがって、上記のコードでは解放する方法はありません割り当てられたメモリ? – ontherocks

1

あなたのコードにはエラーがありません。ただ漏れたcharです。しかしそれはかなり奇妙です。

char* mycharheap() 
{ 
    char* ch = new char; //creates a pointer that points to a new char in the heap 
    ch = "Hello Heap"; //overwrites the pointer with const char - but this cast is legal. 
         //note: pointer to the previous char is lost 
    return ch;   //return the pointer to the constant area where "Hello heap" is stored. 
         //no, "Hello heap" is not on the heap. 
} 

「必要なもの:」の部分については、Yossarianは私よりも速いです。

+0

同じコードでもエラーがなくても動作するこのコードは、同じでなければ同じです。 'char * mycharheap() { char * ch = new char []; ch =" Hello Heap "; return ch; }' – ontherocks

+0

はい。ほとんどのインデントがあり、同じ問題があります。 '' Hello Heap ''はヒープにはありません。@ Yossarianの答えを見て、あなたが望むものを実装する方法を見てください。 – Csq

1

まず、C++を使用している場合は、std::stringを使用して文字列を表します。

今すぐご質問ください。 char*char(またはcharの配列)へのポインタです。文字列リテラル(引用符で囲まれたもの)は、何らかの種類の読み取り専用メモリ(スタックまたはヒープ上に保存されていない)に格納されたcharというタイプの配列の読み取り専用オブジェクトです。

char*はポインタで、ポインタを代入するとポインタが変更されます。したがって、mychar()mycharstack()は両方とも、読み取り専用メモリに格納された文字列リテラルへのポインタを返します。

mycharheap()は単にリークします。 new charを使用してヒープ上にcharを割り当て、そのアドレスを忘れて、代わりに文字列リテラルへのポインタを返します。 C++での文字列にchar*を使用していない、再反復するために、それにも関わらず

char* mycharheap() { 
    char* ch = new char[strlen("Hello Heap") + 1]; 
    strcpy(ch, "Hello Heap"); 
    return ch; 
} 

:私はあなたがこれを意味推測します。 std::stringを使用してください。

+0

次の場合はどうなりますか?SET_ERROR_MESSAGE(false、(returnErrorCppString()。c_str()));ここで、大文字はvarargsをとるマクロを表します。 – Zingam

+0

@ジンガムええと、何?それはどのように質問または私の答えに関連していますか?あなたは精緻化できますか? – Angew

+0

まあ、SET_ERROR_MESSAGEはconst char *を受け入れますが、あなたのアドバイスによれば、std :: stringを返す関数を使用すると、const char *に変換して使用できるようにする必要があります。 SET_ERROR_MESSAGEは第三者のライブラリによって定義されています。 – Zingam

2

mycharstack()内の文字列はスタックに格納されていると思います。「ch」が範囲外になると、文字列を返すことができません。どのように正しく動作しますか?

文字列リテラルは、スタティックメモリに存在する配列を指します。自動メモリ(別名スタック)、フリーストア(別名ヒープ)、スタティックメモリの3つのメモリ領域を認識していただければ幸いです。そのスタック上のものはポインタ変数に過ぎず、ポインタの値(格納するアドレス)を値で返します。文字列リテラルが参照する配列を変更することは許可されていないので、ポインタ型としてconst char*を使用していたはずです。

mychar()に格納されている文字列もスタックにあると思います。

文字列(文字配列)はスタティックメモリに格納されます。 char*は、アドレスを渡すために使用できるポインタ型です。 constもありません。

コードやメモリリークには他にも誤りがあると思いますが、もしあればお知らせください。

3番目の機能に漏れがあります。ヒープ上の1文字だけのメモリを割り当て、そのアドレスをchという変数に格納します。次の割り当てでは、このアドレスを文字列リテラルのアドレスで上書きします。だから、あなたは記憶を漏らしている。

文字列変数の型としてchar*を考えているようです。そうではありません。これは、文字または文字シーケンスへのポインタの型です。ポインタとそれが指す文字列は、2つの別個のものです。おそらく、ここで使用しているはずのものはstd :: stringです。

0

以下の例は、関数呼び出しから情報を出し入れしようとしていたときに発生した問題です。

#include <iostream> 
#include <cstring> 
using namespace std; 

char* Xout(char* message); 

int main() 
{ 
const int LEN = 64; 
char message[LEN], *x; 

cin>>message; 

x=Xout(message); 
cout<<x; 
return 0; 
} 

char* Xout(char* message) 
{ 
int length=strlen(message); 
for(int i = 0; i < length; i++) 
{ 
    message[i] = 'X'; 
} 
return message; 
}