[解決済み] C言語の文字列リテラルの "ライフタイム"
質問
以下の関数が返すポインタはアクセスできないのでしょうか?
char *foo(int rc)
{
switch (rc)
{
case 1:
return("one");
case 2:
return("two");
default:
return("whatever");
}
}
C/C++のローカル変数の寿命は、実質的に関数内だけなんですね。ということは
char* foo(int)
が終了した後、それが返すポインタはもはや何の意味もなさないということですね?
ローカル変数のライフタイムについて、少し混乱しています。何か良い説明はないでしょうか?
どのように解決するのですか?
はい、ローカル変数のライフタイムはスコープ内です(
{
,
}
) の中で作成されます。
ローカル変数は、自動的または局所的に保存されます。 自動 というのは、作成されたスコープが終了すると、自動的に破棄されるからです。
しかし、ここにあるのは文字列リテラルで、実装で定義された読み取り専用メモリに割り当てられています。文字列リテラルはローカル変数とは異なり、プログラムのライフタイムを通じて存続します。文字列リテラルには 静的持続時間 [参考1] の寿命になります。
注意の一言!
しかし、文字列リテラルの内容を変更しようとする試みはすべて
未定義の動作
(UB)となります。ユーザープログラムは、文字列リテラルの内容を変更することはできません。
したがって、常に
const
を使うことが推奨されます。
const char*p = "string";
の代わりに
char*p = "string";
実際,C++では文字列リテラルを宣言する際に
const
しかし、C ではそうではありません。しかし、文字列リテラルを
const
で宣言すると、2番目のケースで文字列リテラルを変更しようとしたときに、コンパイラが通常警告を出すという利点があります。
#include<string.h>
int main()
{
char *str1 = "string Literal";
const char *str2 = "string Literal";
char source[]="Sample string";
strcpy(str1,source); // No warning or error just Uundefined Behavior
strcpy(str2,source); // Compiler issues a warning
return 0;
}
出力します。
cc1: 警告はエラーとして扱われる
prog.c: 関数 'main' で。
prog.c:9: error: 'strcpy' の引数1を渡すと、ポインタ・ターゲット型から修飾子が破棄されます。
コンパイラは2番目のケースで警告を発しますが、最初のケースでは警告を発しないことに注意してください。
ここで何人かのユーザーから質問されていることに答えます。
積分リテラルはどうなっているのでしょうか?
言い換えれば、次のコードは有効ですか?
int *foo()
{
return &(2);
}
答えは、「いいえ、このコードは有効ではありません」です。これは不正な形式であり、コンパイラーエラーが発生します。
のようなものです。
prog.c:3: error: lvalue required as unary ‘&’ operand
文字列リテラルはl値です。すなわち、文字列リテラルのアドレスを取ることはできますが、その内容を変更することはできません。
しかし、他のすべてのリテラル (
int
,
float
,
char
など)はr値(C言語規格では
式の値
であり、そのアドレスはまったく取ることができません。
[参考文献1] C99標準6.4.5/5 "文字列リテラル - セマンティクス"。
翻訳フェーズ7では、文字列リテラルまたはリテラルから生じる各マルチバイト文字シーケンスに、値0のバイトまたはコードが付加されます。 マルチバイト文字シーケンスは、次に、シーケンスを含むのに十分な静的記憶期間と長さを持つ配列を初期化するために使用されます。 . 文字列リテラルでは、配列の要素はchar型を持ち、マルチバイト文字列の各バイトで初期化され、ワイド文字列リテラルでは、配列の要素はwchar_t型を持ち、ワイド文字列で初期化されます...。
これらの配列が、その要素が適切な値を持っている場合、区別されるかどうかは特定されていません。 プログラムがこのような配列を変更しようとした場合、その動作は未定義です。 .
関連
-
#137: 式は変更可能なlvalueでなければならない問題 // 文字列配列の代入問題
-
[解決済み] Code::Blocks アプリケーションをコンパイルできない
-
[解決済み] "static const" vs "#define" vs "enum"
-
[解決済み] C言語のコードで「:-!」とは何ですか?
-
[解決済み] 関数名を文字列として取得するには?
-
[解決済み] longをフォーマットするprintfの引数は何ですか?
-
[解決済み] C++の複数行の文字列リテラル
-
[解決済み] C言語で "unsigned long "をprintfする方法は?
-
[解決済み] C / Objective-Cで文字列リテラルを複数行にまたがるように分割するには?
-
[解決済み] C言語のポインタ(宣言と単項演算子)を初心者にどう説明するか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
解決済み] g++ コンパイルエラー: ')'トークンの前に一次式があることが予想される
-
[C] レポートエラー 代入の左オペランドとしてlvalueが必要
-
警告:代入がキャストなしで整数からポインタを作成する場合の修正方法に関する警告
-
[解決済み] MIPSのネストされたForループと配列の使用
-
[解決済み] ⑭と⑯は何のためにあるのですか?
-
[解決済み] ソケットアクセプト - "開かれているファイルが多すぎる"
-
[解決済み] mallocの結果はキャストするのですか?
-
[解決済み] C言語で配列のサイズを決定するにはどうすればよいですか?
-
[解決済み] longをフォーマットするprintfの引数は何ですか?
-
[解決済み] 関数からC言語の文字列を返す