53

私は最近、Java と Python から来て、C でプログラミングを始めました。さて、私の本で、「Hello World」プログラムを作成するための構文は次のようなものであることに気付きました。

char message[10]
strcpy(message, "Hello, world!")
printf("%s\n", message);

さて、この例では char 配列を使用していますが、文字列はどうなったのでしょうか? それらのいずれかを単純に使用できないのはなぜですか?多分これを行う別の方法がありますか?

4

7 に答える 7

87

C には、ネイティブの文字列型がありません。慣例により、言語はcharnull char で終了する の配列、つまり with を使用します'\0'言語の標準ライブラリの関数とマクロは、null で終わる文字配列のサポートを提供しcharます。'\0''\0'

C でのヌル終了文字列の使用は、C がアセンブリ言語よりも少しだけ高レベルになることを意図していたという事実を反映しています。PDP-10 および PDP-11 のアセンブリ言語では、その時点ですでにゼロ終了文字列が直接サポートされていました。

C 文字列のこの特性は、重大なセキュリティ上の欠陥を含む、かなりの数の厄介なバッファ オーバーラン バグを引き起こすことに注意してください。たとえば、ソース引数として に渡された文字列を null で終了するのを忘れた場合strcpy、関数は、ソース文字列の末尾を過ぎてメモリ内にあるものから順次バイトをコピーし続け0ます。メモリ内の宛先文字列の場所に続く貴重な情報。

あなたのコード例では、文字列リテラル "Hello, world!" の 14 バイト長の配列にコンパイルされますchar。最初の 13 バイトには、文字、コンマ、スペース、感嘆符が含まれ、最後のバイトには'\0'、コンパイラによって自動的に追加されるヌル終了文字が含まれます。配列の最後の要素にアクセスすると、 と等しいことがわかります0。例えば:

const char foo[] = "Hello, world!";
assert(foo[12] == '!');
assert(foo[13] == '\0');

ただし、あなたの例では、message長さはわずか 10 バイトです。strcpyはヌル ターミネータを含む 14 バイトすべてを のアドレスから始まるメモリに書き込みますmessage。最初の 10 バイトはスタックに割り当てられたメモリに書き込まれmessage、残りの 4 バイトは単にスタックの最後に書き込まれます。この場合、これらの 4 バイトをスタックに書き込んだ結果を予測するのは困難ですが (この単純な例では、問題は発生しない可能性があります)、実際のコードでは通常、データの破損やメモリ アクセス違反のエラーが発生します。

于 2013-02-05T14:20:46.797 に答える
15

stringに型はありませんC。char 配列を使用する必要があります。

ちなみに、配列のサイズは、配列全体に加えて 1 つのゼロ終端文字を追加できるようにする必要があるため、コードは機能しません。

于 2013-02-05T14:06:36.170 に答える
14

あなたが言及した言語でそれをメモするには:

ジャワ:

String str = new String("Hello");

パイソン:

str = "Hello"

Java と Python の両方に「文字列」の概念がありますが、C には「文字列」の概念がありません。Cには、「読み取り専用」または操作可能な文字配列があります。

子:

char * str = "Hello";  // the string "Hello\0" is pointed to by the character pointer
                       // str. This "string" can not be modified (read only)

また

char str[] = "Hello";  // the characters: 'H''e''l''l''o''\0' have been copied to the 
                       // array str. You can change them via: str[x] = 't'

文字配列は、最後に一意のセンチネル文字 (通常は NULL ターミネータ'\0') を持つ連続した文字のシーケンスです。上記の場合、センチネル文字が自動的に追加されることに注意してください。

于 2013-02-05T14:27:18.200 に答える
8

C では、文字列は単なる文字の配列であり、最後にヌル バイトが付きます。char*そのため、 C コードを読んでいる場合、aは「文字列」と発音されることがよくあります。

于 2013-02-05T14:06:49.760 に答える
5

C は、ファースト クラスの文字列型をサポートしていません。

C++ には std::string があります

于 2013-02-05T14:06:04.530 に答える
1

C には、Java のような独自の String データ型はありません。

文字配列または文字ポインターを使用して C で String データ型を宣言できるのは、私たちだけです。たとえば、次のようになります。

 char message[10]; 
 or 
 char *message;

ただし、少なくとも宣言する必要があります。

    char message[14]; 

「こんにちは、世界!」をコピーします。メッセージ変数に。

  • 13 : 「Hello, world!」の長さ
  • 1 : 文字列の末尾を識別する '\0' ヌル文字
于 2013-02-05T14:10:49.640 に答える
1

まず、すべてを行う必要はありません。特に、strcpyは冗長です。文字列をコピーする必要はありませんprintf。その文字列を使用して定義messageできます。

次に、「Hello, World!」を表示するための十分なスペースがありません。文字列 ( messagenull ターミネータ用の余分な文字を許可して、少なくとも 14 文字である必要があります)。

その理由については、しかし、それは歴史です。アセンブラには、文字列はなく、バイト、単語などしかありません。Pascal には文字列がありましたが、そのために静的型付けに問題がありましstring[20]string[40]。初期の段階でもこの問題を回避する言語がありましたが、そのためにインダイレクションと動的割り当てのオーバーヘッドが発生し、当時ははるかに効率の問題がありました。

C は単純に、オーバーヘッドを回避し、非常に低いレベルに留まることを選択しました。文字列は文字配列です。配列は、最初の項目を指すポインターと非常に密接に関連しています。配列型がポインター型に「崩壊」すると、静的型からバッファー サイズ情報が失われるため、古い Pascal 文字列の問題は発生しません。

C++ にはstd::string、これらの問題の多くを回避するクラスがあり、動的割り当てのオーバーヘッドがありますが、最近では通常は気にしません。いずれにせよ、std::stringライブラリ クラスです。その下には、C スタイルの文字配列処理があります。

于 2013-02-05T14:17:44.760 に答える