1. ホーム
  2. c

[解決済み] C言語の文字列リテラルの "ライフタイム"

2023-03-03 02:57:49

質問

以下の関数が返すポインタはアクセスできないのでしょうか?

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型を持ち、ワイド文字列で初期化されます...。

これらの配列が、その要素が適切な値を持っている場合、区別されるかどうかは特定されていません。 プログラムがこのような配列を変更しようとした場合、その動作は未定義です。 .