7

タイトルはそれをすべて言います。

本質的に同じ古い質問を見つけましたが、もう少し詳しく説明する必要がありました。

この質問では、受け入れられた答えは次のように述べています。

char* text = "Hello, world"; 

ここでは、自動変数(ポインタ)がスタック上に作成され、定数メモリ内の値を指すように設定されます。これは、次のことを意味します。

  • ""の文字列リテラルは、プログラムの実行全体を通じて存在します。
  • あなたはそれを「割り当てる」または「解放する」責任はありません
  • 変更することはできません。変更したい場合は、「非定数メモリ」を割り当ててそこにコピーする必要があります。

これは、ポインターが削除されるが、ポインターが指しているデータは削除されないということですか?関数内の文字への1,000,000のポインターを作成した場合、それらがスコープ外になると、すべてのメモリーが解放されますか?または、ポインタを作成するために必要なメモリだけで、実際の文字自体を残してすべてのメモリを占有しますか?

4

4 に答える 4

10

文字の配列は静的な保存期間があるため、プログラムの実行全体でぶらぶらします。これは、それらを削除する必要があるという意味ではありません。プログラムの全期間中、それらは残ります実際、それを呼び出すと、delete未定義の動作が発生します。deleteで割り当てられたものだけができますnew

ポインタ自体には自動保存期間があり、スコープ外になると破棄されます。const char*文字列リテラルはの配列を提供するため、ポインタはである必要があることに注意してくださいconst char。検討:

void func()
{
  const char* str = "Hello";
}

を含む文字の配列はHello\0、プログラムの期間中存在します。ポインタstrは、その関数の期間中のみ存在します。ここにある必要はありませんdeleted

あなたがそれについて考えるならば、これは非常に理にかなっています。ソースコードに書き込むこれらの文字列はすべて、実行可能ファイルのどこかに存在する必要があります。コンパイラは通常、これらの文字列を実行可能ファイルのデータセグメントに書き込みます。プログラムを実行すると、実行可能ファイルが文字列を含むデータセグメントとともにメモリにロードされます。

プログラムに同じまたは重複するテキストを持つ2つの文字列リテラルがある場合、コンパイラがそれらの1つだけを格納するように最適化できない理由はありません。検討:

void func()
{
  const char* str1 = "Hello";
  const char* str2 = "Hello";
  const char* str3 = "lo";
}

コンパイラは、Hello\0ここで1回だけ実行可能ファイルに文字を書き込む必要があります。最初の2つのポインターはを指しH、3番目のポインターは2番目を指しlます。コンパイラはこのような最適化を行うことができます。もちろん、この例では、コンパイラーは文字列をすべてまとめて削除するだけでさらに最適化できます。これらの文字列は、プログラムの観察可能な動作に寄与するような方法では使用されません。

そうです、プログラムの観察可能な動作に何らかの形で寄与する100万の異なる文字列リテラルがある場合、もちろん、それらは実行可能ファイルの一部として存在する必要があります。

于 2013-02-13T15:49:29.113 に答える
2

SOがそれを答えと見なすのに十分であれば、私は「何も」(タイトルに答える)と言います。

文字への100万個のポインターについては、ポインターがポップされますが(100万個のポインターを保持するにはかなりのスタックが必要ですが)、それらが指すデータは記憶に残ります。

于 2013-02-13T15:43:21.737 に答える
2

残念ながら、あなたの例は全体像に対処するには不十分です。

まず、いくつかの簡単なアドホックな語彙と説明:メモリセルは、指定されたサイズの(C ++で入力された)メモリゾーンであり、が含まれています。いくつかのメモリーセルには同じ値が含まれている場合がありますが、それは問題ではありません。

考慮すべきメモリーセルには次の3種類があります。

  • "Hello, World!":このメモリセルには静的な保存期間があり、プログラムの期間中ずっと存在します
  • void foo(int a);およびvoid foo() { int a = 5; }:メモリセルaは、どちらの場合も自動保存期間があり、関数が戻ると自動的に消えます。foo
  • void foo() { int* a = new 5; }:値を格納するために匿名メモリセルが「どこかに」作成され、匿名メモリセルのアドレスを格納するために自動保存期間のメモリセルが作成され5ますa

では、ポインタがスコープから外れる(消える)とどうなりますか?

まあ、それだけです。ポインタが消えます。具体的には、ポイントしていたメモリセルに特別なことは何も起こりません。

void foo(int a) {
    int* pointer = &a;
} // pointer disappears, `a` still exists briefly

void foo() {
    int* pointer = 0;
    {
        int a;
        pointer = &a;
    } // a disappears, pointer's value does not change...
} // pointer disappears

実際、CおよびC ++では:

  • 存在しなくなったオブジェクトのアドレスを保持できます=>ぶら下がり参照
  • 既存のオブジェクトへのすべてのアドレスを失う可能性があります=>メモリリーク

では、textinchar const* text = "Hello, world";がスコープ外になるとどうなりますか?

何もない。

于 2013-02-13T16:26:26.237 に答える
1

ポインタ自体が「自動ストレージ」(通常はスタック)のスペースを占有します。関数が戻ると削除されます[またはスコープが終了しますが、技術的には、ほとんどすべてのコンパイラは、関数が戻るまで「待機」してからスペースが解放されます]。

同じ関数をループ内で100万回呼び出すと、常に1つのポインターしか存在しません。100万個の関数[および大量のメモリ]がある場合、現在呼び出されている関数ごとに1つのポインターがあります。例えば

char *foo()
{
    char *text1 = "Hello";
    return text1;
}

void bar()
{
    char *text2 = "World!";
    printf("%s %s!\n", foo(), text2);
}


void baz()
{
    char *text3 = "Meh";
    bar();
}

int main()
{
    char *text4 = "Main";

    baz();
}

mainに入るtext4と、スタック上に作成されます。これは、メモリの他のビットに保持されている文字列「Main」に初期化されます。次に、を呼び出すとbaz()text3作成されて「Meh」に初期化されます。これは、テキスト「World」をbar()作成して指す呼び出しと、を作成して初期化する呼び出しです。戻り値として、内部のアドレスが戻り値として与えられ、ポインター自体が消えます。が終了すると、に戻り、ポインタが消えます。text2footext1Hellofootext1printf()bar

文字列「Main」、「Meh」、「Hello」、および「World」は、プログラムが実行されている限り、そのまま残ります。

于 2013-02-13T15:52:44.723 に答える