0
#include <stdio.h>

main()
{
  char * ptr;

  ptr = "hello";


  printf("%p %s" ,"hello",ptr );

  getchar();

}

こんにちは、配列をポインターに割り当てる方法を明確に理解しようとしています。char の配列を charのポインターに割り当てると、配列がポインターに減衰することに気付きますptr="hello";が、この場合、変数内になく、それらを含む変数ではなく、配列の char を割り当てています。割り当ては、(明らかに何が起こっているのか) のために特別にメモリ アドレスを取得し"Hello"、この配列が格納されているメモリ アドレスに含まれる "Hello" の各要素の値を変更することは可能ですか? 比較として、それは問題ありませんか?たとえばintの配列でポインターを割り当てるには、これと同じくらいあいまいなものint_ptr = 5,3,4,3;値 5,3,4,3 は、"Hello" が行ったようにメモリ アドレスに配置されます。そうでない場合、なぜ文字列でのみ可能ですか? ありがとうございます。

4

4 に答える 4

3

"hello"文字列リテラルです。タイプ の名前のない変更不可能なオブジェクトですchar [6]。これは配列であり、他の配列と同じように動作します。名前がないという事実は、実際には何も変わりません。[]たとえば、 in などの演算子で使用できます"hello"[3]。他の配列と同様に、ほとんどのコンテキストでポインターに減衰する可能性があります。

文字列リテラルは定義上変更できないため、文字列リテラルの内容を変更することはできません。読み取り専用メモリに物理的に格納できます。文字の共通のサブシーケンスが含まれている場合、他の文字列リテラルと重複する可能性があります。

複合リテラル構文により、他の配列型にも同様の機能が存在します

int *p = (int []) { 1, 2, 3, 4, 5 };

この場合、右側は型の名前のないオブジェクトであり、ポインターint [5]に崩壊します。int *ただし、複合リテラルは変更可能です。つまり、実行してでp[3] = 8置き換えることができます。48

char 配列で複合リテラル構文を使用して、次のことを行うこともできます。

char *p = (char []) { "hello" };

この場合、右側はタイプ の変更可能な名前のないオブジェクトですchar [6]

于 2013-01-05T01:33:16.717 に答える
1

最初にすべきことは、comp.lang.cFAQのセクション6を読むことです。

文字列リテラル"hello"はタイプの式ですchar[6](「hello」の場合は5文字、終了の場合は1文字'\0')。これは、静的ストレージ期間を持つ匿名配列オブジェクトを参照し、プログラムの起動時にこれらの6文字の値を含むように初期化されます。

ほとんどのコンテキストでは、配列型の式は、配列の最初の要素へのポインターに暗黙的に変換されます。例外は次のとおりです。

  • それがの引数である場合sizeofsizeof "hello"ポインタのサイズではなく、6を生成します);
  • _Alignof(C11の新機能)の引数の場合。
  • 単項の引数の場合&&arr最初の要素ではなく、配列全体のアドレスを生成します。同じメモリ位置、異なるタイプ)。と
  • 配列オブジェクトを初期化するために使用される初期化子の文字列リテラルの場合(char s[6] = "hello";ポインターだけでなく、配列全体をコピーします)。

これらの例外はいずれもコードには適用されません。

char *ptr;
ptr = "hello";

したがって、式は、前述の匿名配列オブジェクト"hello"の最初の要素()へのポインタに変換されます(「減衰」します) 。'h'

したがって、、およびメモリを*ptr == 'h'進んで他の文字にアクセスできます:、、、、、および。これはあなたがそれにフォーマットを与えるとき何をするかです。ptr'e''l''l''o''\0'printf()"%s"

文字列リテラルに関連付けられているその匿名配列オブジェクトは読み取り専用ですが、ではありませんconst。つまり、その配列またはその要素のいずれかを変更しようとすると、未定義の動作が発生します(標準で明示的に指定されているため)。ただし、コンパイラは必ずしもそれについて警告するわけではありません。(C ++は文字列リテラルを作成しますconst。Cで同じことを行うと、言語に追加される前に記述された既存のコードが壊れてしまいconstます。)したがって、"hello"-の要素を変更することはできません。少なくとも試してはいけません。また、試してみた場合にコンパイラに警告を表示するには、ポインタをconst次のように宣言する必要があります。

const char *ptr; /* pointer to const char, not const pointer to char */
ptr = "hello";

-Wwrite-strings(gccには、文字列リテラルをとして処理するオプションがありますconst。これにより、標準に関する限り有効なCコードについて警告が表示されますが、そのようなコードはおそらく使用するように変更する必要がありますconst。)

于 2013-01-05T05:55:13.810 に答える
-2

何だって?

コードは 6 バイトのメモリを割り当て、値 'h'、'e'、'l'、'l'、'o'、および '\0' で初期化します。

次に、ポインターを割り当て (ポインターのバイト数は実装によって異なります)、ポインターの値を前述の 5 バイトの先頭に設定します。

などの構文を使用して、配列の値を変更できますptr[1] = 'a'

構文的には、文字列は特殊なケースです。C には特定の文字列型がないため、それらを宣言するためのショートカットがいくつか用意されています。intただし、構文が少し異なる必要がある場合でも、を使用して文字列に対して行ったのと同じタイプの構造を簡単に作成できます。

于 2013-01-05T01:31:23.517 に答える