2

私はそれを述べているいくつかの文書を調べていました

最初のケース

char * p_var="Sack";     

定数文字列リテラルを作成します。

したがって、次のようなコード

  p_var[1]="u";             

そのプロパティのために失敗します。

2 番目のケース

また、これは文字リテラルでのみ可能であり、ポインターを介した他のデータ型では可能ではないことも述べられています。だからコードのように

float *p="3.14"; 

失敗し、コンパイラ エラーが発生します。

しかし、試してみると、コンパイラエラーは発生しませんが、アクセスしても0.000000f(Ubuntuでgccを使用して)得られます。

上記に関して、私は3つの質問があります:

  1. First Caseで文字列リテラルが読み取り専用で作成されるのはなぜですか?

  2. 文字列リテラルのみを作成でき、float through pointers のような他の定数は作成できないのはなぜですか?

3. Second Caseでコンパイラ エラーが発生しないのはなぜですか?

アップデート

3 番目の質問と 2 番目のケースは破棄してください。引用符を追加してテストしました。

ありがとう

4

4 に答える 4

5

前提が間違っています。ポインターは文字列リテラルを作成せず、読み取り専用でも書き込み可能でもありません。

読み取り専用の文字列リテラルを作成するの、リテラルそのものです"foo"。読み取り専用の文字列リテラルです。また、それをポインターに割り当てると、そのポインターは読み取り専用のメモリ位置を指します。

それでは、質問に移りましょう。

First Case で文字列リテラルが読み取り専用で作成されるのはなぜですか?

本当の質問は次のとおりです。ほとんどの場合、後で文字列リテラルの値を変更したくないため、デフォルトの仮定は理にかなっています。さらに、他の方法で C で書き込み可能な文字列を作成できます。

文字列リテラルのみを作成でき、float などの他の定数は作成できないのはなぜですか?

繰り返しますが、間違った仮定です。他の定数を作成できます。

float f = 1.23f;

ここで、1.23fリテラルは読み取り専用です。定数変数に代入することもできます:

const float f = 1.23f; 

Second Case でコンパイラ エラーが発生しないのはなぜですか?

コンパイラは一般に、ポインタが読み取り専用メモリを指しているか書き込み可能メモリを指しているかをチェックできないためです。このことを考慮:

char* p = "Hello";
char str[] = "world"; // `str` is a writeable string!

p = &str[0];

p[1] = 'x';

ここでp[1] = 'x'は、完全に合法pです。事前に割り当てを変更していなければ、違法でした。これをチェックすることは、通常、コンパイル時に行うことはできません。

于 2012-11-18T14:47:40.370 に答える
1

あなたの質問について:

  • First Caseで文字列リテラルが読み取り専用で作成されるのはなぜですか?

char *p_var="Sack";

さて、p_var文字列に割り当てられたメモリの開始アドレスが割り当てられます"Sack"。C コンストラクトのどこにもキーワードp_varを配置していないため、 content は読み取り専用ではありません。ただし、 strcpy や strcat などconstのコンテンツを操作すると、未定義の動作が発生する可能性があります。p_var

引用 C ISO 9899:

この宣言は、プレーンchar 配列オブジェクトを
char s[] = "abc", t[3] = "abc";
定義し、その要素は文字列リテラルで初期化されます。 この宣言は次と同じです: 配列の内容は変更可能です。一方、宣言:はchar へのポインタ型で 定義し、要素が文字列リテラルで初期化された長さ 4の char 型の配列を持つオブジェクトを指すように初期化します。を使用して配列の内容を変更しようとした場合の動作は未定義です。st

char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };

char *p = "abc";
pp

プラットフォームとコンパイラごとに読み取り専用になる理由の説明:

通常、文字列リテラルは「読み取り専用データ」セクションに配置され、プロセス空間に読み取り専用としてマップされます (これが、変更が許可されていないように見える理由です)。

ただし、一部のプラットフォームでは、データ セグメントを書き込み可能にすることができます。

  • 文字列リテラルのみを作成でき、float などの他の定数は作成できないのはなぜですか? そして3つ目の質問。

float 定数を作成するには、次を使用する必要があります。 const float f=1.5f;

さて、あなたがやっているとき: float *p="3.14"; あなたは基本的に文字列リテラルのアドレスをfloatポインタに割り当てています。

でコンパイルしてみてください-Wall -Werror -Wextra。何が起こっているかがわかります。実際には、 aと a の間に違いがないため、機能し ます。char *float *

あなたがこれを書いているかのようです:
float *p=(float*) "3.14";

これは、float と char のメモリ アラインメント要件が異なる場合を除き、明確に定義された動作です。異なる場合は、未定義の動作になります (参照: C99、6.3.2.3 p7)。

于 2012-11-18T15:05:04.813 に答える
0
  1. 効率
  2. 彼らです
  3. 引用符を気にするのは文字列です
于 2012-11-18T14:47:32.593 に答える
0
float *p="3.14"; 

これも文字列リテラルです!

  Why are string literals created in First Case read-only?

いいえ、両方とも"sack"文字"3.14"列リテラルであり、両方とも読み取り専用です。


文字列リテラルのみを作成でき、float などの他の定数は作成できないのはなぜですか?

float const を作成する場合は、次のようにします。

const float p=3.14;

Why is Second Case not giving me compiler errors? 

ポインターpが文字列リテラルを指すようにしています。を逆参照pすると、float 値を読み取ることが期待されます。したがって、コンパイラが確認できる限り、何も問題はありません。

于 2012-11-18T14:49:19.267 に答える