6

私はCの初心者です。次のようなプログラムがあります。

int main()
{
    char* func();
    char *c;
    c = func();
    printf("%s", c);
}

char* func()
{
    char *ptr = "OK";
    return ptr;
}

ご存知のように、ptrは のローカル変数でfunc()あり、 はポインターです。スコープはローカルです。しかし、ptrが呼び出し元に返されるとmain、それはまだ有効であり、cが出力されると "OK" が出力されます。

これはどのように可能ですか?どのメモリ セグメントにptr格納されているか。スタック、またはヒープ?

4

8 に答える 8

8

これは、ポインターを使用するときに内部で行われていることです (ポインターは名前が示すとおりであり、何かを指している指のようなものであることに注意してください)。

コードを分解して、少しずつ理解しましょう。メイン関数で、文字ポインター *c を宣言しました

char *c;

次に、これを行いました:

c = func();

これは、この func() が指しているものを指すように c ポインターに指示します。

あなたの機能を見てみましょう

char* func()
{
    char *ptr = "OK";
    return ptr;
}

最初の行でも、文字ポインター ptr を宣言し、そのアドレスに "OK" を割り当てます (注: ポインターはメモリ アドレスを指しているだけです)。そのため、そのアドレスには文字列 "OK" (より正確には char の配列) が含まれています。

次に、「OK」がある場所のアドレスである ptr を返します。ptr は func() で宣言されているため、ローカル変数であることに注意してください。したがって、一度戻ると、スタックから削除されます(うんざり! なくなってしまいました)。

ただし、あなたの main() では:

c = func(); 

変数 c は、「OK」が格納されているアドレスを指しています。したがって、変数 ptr が存在しなくなっても、変数 c はそれがどこにあるかを認識しており、引き続き "OK" にアクセスできます。

あなたの質問に答えるには:

  • ptr はスタックに格納されます
  • func() を終了すると、ptr がスタックからポップオフされます。
于 2015-06-10T10:06:37.207 に答える
4

スタック/ヒープのことはしばらく忘れましょう。Cの話をしましょう。

ローカル変数ptrは外部には存在しないfuncため、呼び出し元はそれを参照できませんし、参照すべきではありません。

しかし、 C は参照渡しを行いません。すべて値渡しです。に格納されているを呼び出し元にfunc返します。anまたはその他の型のを返すのと同じように。ptrint

したがって、あなたの例では、ptrの値は、という文字列リテラルのアドレスです"OK"。また、文字列リテラルは、プログラムのスコープ全体で有効です。Sofuncは、文字列リテラルのアドレスを返します。これは、プログラム内のどこでも逆参照できます。

より明確にするために、func次と同等です。

const char * func (void)
{
  return "OK";
}

これがすべてがうまくいく理由です。

また、以下は問題ありませんが、知っておくと便利です。

const char * func (void)
{
  char *ptr = "OK";
  return ptr;
}

これではありません:

const char * func (void)
{
  char ptr[] = "OK";
  return ptr;
}

にローカルな配列へのポインターを返すようになったため、問題ありません。func

もう1つの小さなポイント。は変更が許可されていないconst char * func ()ため、次のようにする必要があります。"OK"

于 2012-07-14T07:22:19.670 に答える
3

関数を呼び出すと、そのすべてのローカル変数とリターンアドレスがスタックにプッシュされます。したがって、ptrはスタックにありますが、「OK」-定数データセクションの文字列です。から戻るとfunc、の値は変数にptr割り当てられ、存在しなくなります(実際には存在します)が、その値はに格納されます。cptrc

于 2012-07-14T05:10:30.540 に答える
2

テキストは、実行可能ファイルの定数データ"OK"セクションに格納されます (プロセスの開始時にメモリに読み込まれます)。はローカル変数ですが、コンパイラは、別の場所に格納されているを指すように初期化します。呼び出し元に戻っても、ポインタは同じ を指しています。ptr"OK"ptr"OK"

于 2012-07-14T04:43:59.367 に答える
0

ptr"OK"定数データセクション のデータのアドレスを保持します。それが返されるアドレスです。ptrSoのアドレスじゃなくてptr無くなっても"OK"残り続ける

于 2012-07-14T05:58:18.737 に答える
0

スタック上のptr自体は一時的ですが、それが指す場所はそうではありません。1 つの状況は func() のようなもので、文字列リテラルは「定数データ領域」に格納されます。もう 1 つの状況はデータがヒープに割り当てられていることです。つまり、malloc() を介して、したがってグローバルであり、スタックがの機能がなくなりました。

char* func()
{
        char* ptr;
        ptr = (char*)malloc(100);
        strcpy(ptr, "OK");
        return ptr;
}
于 2012-07-15T10:31:05.597 に答える
0

char *ptr = "OK";- このステートメントは、変数に 4 バイト (32 ビット マシンの場合) を割り当てptr、文字列リテラルのアドレスを保持しますOK。現在ptr、文字列の開始アドレス (4 バイト) を持っていますOK(実際には を含めて 3 バイト\0です)。この 3 バイトの文字列OKは、読み取り専用データであるテキスト セグメントになります。また、変更することはできません。たとえばptr[0] = 'T'、この場合は不可能です。テキスト セグメント内の文字列リテラル (3 バイト) は、プロセスの有効期間を通じて存在します。しかし、制御が function から出ると、文字列リテラルのアドレスを保持するfuncために変数に割り当てられた 4 バイトptrが解放されます。func以下のように関数を書くこともできます

char* func()
{
    return "OK";
}

以下のように関数を変更します

char* func()
{
    char ptr[] = "OK";
    return ptr;
}

今回はptr、文字列をローカルに格納するために変数に 3 バイトが割り当てられます。この範囲は関数内のみです。

于 2012-07-14T09:50:33.817 に答える