24

以下は3つの機能です。main()は期待どおりに出力されます。さて、mycharstack()では、文字列はスタックに格納されていると思います。そのため、「ch」がスコープ外になると、文字列を返すことができなくなります。どのように正しく機能しますか?mychar()に格納されている文字列もスタックにあると思います。正しく動作するはずですか?コードに他のエラーやメモリリークがあると思います。もしあれば教えてください。std :: stringを使用すると、これらをよりクリーンで簡単に実行できます。しかし、char*で何が起こっているのかを理解したいと思います。

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

7 に答える 7

24

C ++では、文字列の処理は、たとえば、pascalとは異なります。

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

これは次のことを行います。

  1. char* ch = new char;1文字のメモリを作成し、それを変数に割り当てますch
  2. ch = "Hello Heap";chバイトを含む読み取り専用メモリへの変数ポインタに割り当てます"Hello Heap\0"。また、変数の元の内容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->メモリがchあり、11文字のスペースがあり、メモリの読み取り専用部分から文字列で埋めていることに注意してください。

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

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

ただし、これを行うことは強くお勧めしません(呼び出し先にメモリを割り当て、呼び出し元で削除します)。この状況では、たとえば、STLがありますstd::string。別の一般的でより合理的なアプローチは、呼び出し元に割り当て、呼び出し先に渡し、結果でメモリを「埋め」、呼び出し元で再度割り当てを解除することです。

未定義の動作が発生する原因は次のとおりです。

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"、その配列の最初のバイトへのポインターが返されようとします(これは、関数の呼び出し時に、任意のものを指すことができます)

于 2013-01-17T12:45:52.677 に答える
4

mycharstack()では、文字列はスタックに格納されていると思います。そのため、「ch」がスコープ外になると、文字列を返すことができなくなります。どのように正しく機能しますか?

文字列リテラルは、静的メモリに存在する配列を指します。自動メモリ(別名スタック)、フリーストア(別名ヒープ)、静的メモリの3つのメモリ領域を知っていることを願っています。スタック上のものは単なるポインタ変数であり、ポインタの値(格納されているアドレス)を値で返します。const char*したがって、文字列リテラルが参照する配列を変更することは許可されていないため、ポインタ型として使用する必要があるという事実を除いて、すべて問題ありません。

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

文字列(文字配列)は静的メモリに保存されます。char*は、アドレスを渡すために使用できる単なるポインタタイプです。constまた行方不明です。

コードに他のエラーやメモリリークがあると思います。もしあれば教えてください。

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

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

于 2013-01-17T12:54:55.363 に答える
1

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

今あなたの質問に。char*はへのポインタchar(またはsの配列char)です。文字列リテラル(引用符で囲まれたもの)は、配列型の読み取り専用オブジェクトでありchar、ある種の読み取り専用メモリ(スタックでもヒープでもない)に格納されます。

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

mycharheap()単に漏れます。charを使用してヒープに1つ割り当てnew char、そのアドレスを忘れて、代わりに文字列リテラルへのポインタを返します。私はあなたがこれを意味したと思います:

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

それでも、繰り返しになりchar*ますが、C++の文字列には使用しないでください。を使用しstd::stringます。

于 2013-01-17T12:47:03.950 に答える
0

関数mycharheap()がリークしています。ヒープに割り当てられた長さのメモリ領域を指すようにポインタを作成charしてから、読み取り専用メモリに格納されている文字列リテラルを指すようにポインタを変更します。割り当てられたメモリは解放されません。

于 2013-01-17T12:42:57.750 に答える
0

リークされただけでコードにエラーはありません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は私よりも速かった。

于 2013-01-17T12:43:28.343 に答える
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;
}
于 2016-10-12T09:08:02.070 に答える
0
const char* mychar_readonly() {
    // each time it returns the same pointer to char array in Read-Only memory
    return "Hello Read-Only";
}

int main() {
    const char* s1 = mychar_readonly();
    const char* s2 = mychar_readonly();
    // it will print the same addresses
    // e.g s1: 0x100000f87, s2: 0x100000f87
    printf("s1: %p, s2: %p\n", s1, s2);
    return 0;
}
于 2020-12-22T20:43:56.897 に答える