3

似たようなものがすでにここに投稿されていたら申し訳ありませんが、実際には見つけられませんでした。

私は次のコードを持っています。これは正しくないと言いますが、正しい答えを受け取ります。

char *selectStr(int index){
    char *str[] = {
        "hello",
        "hola",
        "epa",
        "alright",
    };
    return str[index];
}

int main() {
    printf("String: %s\n", selectStr(2));
    return 0;
}

これが実際に機能する理由を誰か教えてもらえますか? 私の見方: 文字列の配列はstrselectStr 関数内のローカル変数です。この関数は、この配列に含まれる文字列を返します。しかし、この文字列の配列はstrローカル変数であるため、返された後にメモリから消去する必要があるため (そうですか?)、何らかのメモリ アクセス エラーが発生することを予期していました。

このコードが機能することを幸運だと考えるべきですか (つまり、これは未定義の動作ですか?)、それとも、これは実際に物事を行う良い方法です (この場合はなぜですか)?

私の推測では、配列へのポインターstrは関数が返された後に消去されますが、それが指す実際のコンテンツは消去されず、他の何かが書き込まれるまでメモリに残ります。誰かがそれを確認できるか、実際に何が起こっているのか教えていただければ幸いです.

前もって感謝します!

PS: 私が行う方法は、バッファをパラメータとして渡すことですが、驚くべきことに (少なくとも私にとっては)、これが実際に機能する理由を知りたいと思っています。

4

4 に答える 4

4

これが実際に機能する理由を誰か教えてもらえますか?

これは未定義の動作であり、UB は「コードが明らかにクラッシュまたは失敗する」という意味ではなく、何かが起こる可能性があることを意味します。

この場合、ローカルを格納するために使用されるスタック領域はまだ再利用されておらず、元の値が含まれている可能性があると考えることができます。将来どこかで失敗する可能性がありますが、明らかな失敗を期待することはできません。

ただし、静的に割り当てられた文字列リテラルへのポインターを返しているため、ここでは UB を呼び出していません (読み取り専用メモリに格納される可能性が高いため、実際には を返す必要がありますconst char*)。配列はローカルです。文字列はそうではありません。

PS:私が行う方法は、バッファをパラメータとして渡すことです...

関数内で配列を静的にすることもできます。それが良いアイデアかどうかは、全体的な設計によって異なります。

于 2012-10-01T22:21:30.850 に答える
2

このコードは正しいです。

char *str[] = {
    "hello",
    "hola",
    "epa",
    "alright",
};

これは文字列の配列を作成しません。

文字列へのポインターの配列を作成します。文字列自体には静的な保存期間があります。ポインターの配列には、自動保存期間があります。関数が戻ると、ポインターの配列は制限されなくなりますが、文字列はまだ存在します。

return str[index];

これにより、配列が逆参照されて文字列の 1 つへのポインターが取得され、そのポインターが返されます。 str範囲外になりますが、ポインターはまだ静的ストレージ内の文字列を指しています。

strとしてマークしても害はありませんstatic。オプティマイザはすでにそうしている可能性があります。したがって、次のように書くことができます。

static char *str[] = {
    "hello",
    "hola",
    "epa",
    "alright",
};

そのほうが気が楽になるなら。

于 2012-10-01T23:18:37.147 に答える
2

"anything" などの文字列定数はスタックに格納されません。スタック (selectStr() 内) にはポインターの配列が含まれており、スタック上のポインターのアドレスではなく、ポインターを返しています。この場合、ポインタは常に有効です。

于 2012-10-01T22:22:50.973 に答える
1

このコードが機能することを幸運だと考えるべきですか (つまり、これは未定義の動作ですか?)、それとも、これは実際に物事を行う良い方法です (この場合はなぜですか)?

おそらく=)ただし、あなたが蹴った議論から、それを伝えるのは難しい. すべての意図と目的のために、技術的な理由で機能する可能性がありますが、良い考えではありません.

関数内で配列を静的にしますが、それでもここで人々を動揺させる場合は、スコープを増やしてみませんか?

static const char *str[] = {
    "hello",
    "hola",
    "epa",
    "alright"
};

const char *selectStr(int index){
    return str[index];
}

この関数が同じファイルにある場合、グローバルに関するプログラム設計の考慮事項は実際には関係ありませんmain...これをモジュールに分割すると、その配列をソースファイルに対してプライベートにしてエクスポートしますselectStr関数。心配ない。

私が行う唯一の調整は、配列に よりも明らかにグローバルな名前を付けることですstr

于 2012-10-01T22:45:59.100 に答える