2

これは、C 言語での 3 番目のプログラムです。このプログラムは、文字列の概念を示すためのものです。

調査から、文字列の末尾にヌル文字 '\0' があり、文字列を終了することがわかっています。

私はそのコードを書きました:

main()
{
      char  name[8];

      strcpy(name, "Mahmoud");
      printf("The contents of name are %s\n", name);
      getchar();
}

このコードでは、文字列を保存するために char 型の配列を宣言しています。私の名前 "Mahmoud" は 7 文字で、サイズ 8 ("Mahmoud" の場合は 7、'\0' の場合は 1) で名前を宣言すると、正しく機能します。

しかし、次のコードでは:

main()
{
      char  name[8];

      strcpy(name, "MahmoudEmam");
      printf("The contents of name are %s\n", name);
      getchar();
}

名前を表示すると、出力は「MahmoudEmam」になりますが、名前のサイズは 8 です。

それはどのようにしますか?

4

5 に答える 5

5

Cは配列の境界チェックを実行しません(おそらくC11で...)。配列の末尾を超えて書き込みを行っています。これは未定義の動作です (何かが起こる可能性があります)。

于 2012-07-23T13:44:12.310 に答える
4

フルネームが表示されるという事実は、未定義の動作です。基本的に、7 文字以上と終端 0 (合計 8​​ 文字) を、7 文字と終端 0 用に予約されたストレージにコピーしています。

たまたま機能するだけで、プログラムがクラッシュする可能性があります。

これが、C が低レベルのプログラミング言語、または何年も前に使われていたフレーズのように、高レベルのアセンブリ プログラミング言語と見なされる理由です。

プログラマーは、 のような構造を使用してコピー操作のターゲットの長さをチェックし、コピーするsizeof(name)ものがそのスペースを上書きしないことを確認する必要があります。また、文字列の終端、終端の '\0' を考慮して十分なスペース + 1 を考慮する必要があります。

malloc で割り当てられた文字列で sizeof を使用すると、32 ビット ポインターの値 4、またはハードウェアのポインター長が返されることを忘れないでください。その場合、 strlen に依存してバッファの長さを取得するか、文字列の malloc に使用されたサイズを保存する必要があります。

最後に、文字列ポインターを関数に渡す場合、バッファー長を持つように関数を記述すると非常に役立ちます。真のバッファー長を取得することはできません。strlen は文字列の長さのみを返し、ポインターが実際に指しているバッファーのサイズは返しません。

于 2012-07-23T13:48:54.377 に答える
2

この場合、あなたは幸運です。何が起こっているかというと、スタックに 7 文字の文字列 (+ の場合は 1 つ'\0') に十分なメモリを割り当てましたが、それを超えて書き込みを行っているということです。

C は、配列境界からの読み取り/書き込みを検出しません。

何が起こっているのかというと、配列の残りの部分を上書きして、他にあるものをすべて破壊しています。大規模なプログラムでは、クラッシュが発生する可能性が高くなります。

これは、なぜ の使い方を学ぶべきかの良い例ですが、バッファがいっぱいの場合は終了を追加しないのでstrncpy、自分で行う必要があることに注意してください。このようなコードは次のようになります。strncpy'\0'

strncpy(name, "the text of your string, whatever it is", sizeof(name));
name[sizeof(name) - 1] = '\0';
于 2012-07-23T13:45:03.390 に答える
1

未定義の動作を呼び出しています。それが機能するので、あなたはそれに頼ることはできません。

于 2012-07-23T13:44:27.000 に答える
1

質問はすでに回答されていますが、もしよろしければ、少し絞り込みたいと思います。

気づいたらstrcpy()、パラメータとしてバッファ長を取りません。これは、宛先バッファがオーバーフローしないようにユーザーが注意を払うことを信頼しているためです。

C では、メモリ内のどの場所にどのデータを配置できるかについての制約はありません。それは強力なツールであると同時に、使い方を誤ると危険なツールでもあります。

を呼び出すとprintf()、最初の 0 を見つけてすべてを出力するまで、指定したバッファーを通過します。ランダムなバッファを提供すると、意味不明な出力がされます。あなたが書いたプログラムの場合、そこにコピーした文字列を含むバッファーを提供しました。バッファを破ったとしても、メモリが破損していることさえ認識していないため、プログラムはその方法を見つけて出力することができました。

バッファ オーバーフローは、最も見つけにくいバグの 1 つです。多くの場合、モジュール自体に関連しないプログラムの部分に影響を与え、破損自体を引き起こし、効果が現れるまでに時間がかかることがよくあります。そのため、このようなバグが発生しないように細心の注意を払う必要があります。

于 2012-07-23T20:07:16.257 に答える