5

私はC++Primer Plus(6th Edition)を読んでいて、第4章でいくつかのサンプルコードに出くわしました。これについて質問があります。

リスト4.2strings.cpp

// strings.cpp -- storing strings in an array
#include <iostream>
#include <cstring> // for the strlen() function
int main()
{
    using namespace std;
    const int Size = 15;
    char name1[Size]; // empty array
    char name2[Size] = "C++owboy"; // initialized array
    // NOTE: some implementations may require the static keyword
    // to initialize the array name2
    cout << "Howdy! I'm " << name2;
    cout << "! What's your name?\n";
    cin >> name1;
    cout << "Well, " << name1 << ", your name has ";
    cout << strlen(name1) << " letters and is stored\n";
    cout << "in an array of " << sizeof(name1) << " bytes.\n";
    cout << "Your initial is " << name1[0] << ".\n";
    name2[3] = '\0'; // set to null character
    cout << "Here are the first 3 characters of my name: ";
    cout << name2 << endl;
    return 0;
}

コード自体は混乱を引き起こしませんが、私はそれを実行してきました、そして私は特定のシナリオによって混乱しています。

name1は、長さが15要素のcharの配列として初期化されます-これは14文字の長さの文字列を保持する必要があると思いますか?終了文字は文字列ターミネータ用に予約する必要がありますよね?

私の名前をHowCanIPossiblyFitThisEntireStringInと入力した場合はどうなりますか?、次の出力が得られます。

なんてこった!私はC++owboyです!あなたの名前は何ですか?

HowCanIPossiblyFitThisEntireStringIn?

さて、HowCanIPossiblyFitThisEntireStringIn ?、あなたの名前は37文字で、保存されています

15バイトの配列で。

あなたのイニシャルはHです。

これが私の名前の最初の3文字です:C ++

入力した名前全体はどのように保存されますか?コードをステップスルーすると、cinがname1を読み込んだ後、Visual Studioは要素0〜14が含まれていることを通知し、最後の要素はchar'y'( "HowCanIPossibly ...)です。入力されたデータは切り捨てられて失われましたが、次のcoutが名前全体をコンソールに正常に書き出すため、これは明らかに当てはまりません。

好奇心のために、ここで何が起こっているのかについて誰かに教えてもらえますか?記録のために、私はVisual Studio2012Expressを使用しています。

4

2 に答える 2

8

配列の境界を超えて書き込んでいます。C ++標準では、これはエラーであるべきだとは言われていません。それは未定義の振る舞いであると言っています。これは、一見正しく機能していることを含め、何でも起こり得ることを意味します。簡単に言えば、コードには明確に定義された動作がないため、コードが機能することを信頼するべきではありません。

なぜそれがおそらく機能しているのか想像できます。最初の15文字は、配列にうまく収まります。

|H|o|w|C|a|n|I|P|o|s|s|i|b|l|y|F|i|t|T|h|i|s|E|n|t|i|r|e|S|t|r|i|n|g|I|n|?|...
^                             ^
|    These characters fit     |
         in the array

残りの文字は、次のメモリ位置に書き込まれています。ここで、Cスタイルの文字列を終了するために使用されるヌル文字は、すべて0ビットの表現を持つように定義されていることに注意してください。これで、を含む場所に続く場所に?すべて0ビットが含まれている場合、文字列はnullで終了しているように見えます。

しかし、実際には、これは未定義です。それはたまたまうまくいきます。残念ながら、これは最も恐ろしいタイプのバグです。非常に怒っているクライアントから電話がかかってくる日が来るまで、長い間機能しているように見えるからです。

于 2013-03-26T16:52:53.323 に答える
2

istream::getバッファとバッファのサイズで使用できます。

cin.get(name1, Size);

他の人が指摘しているように、それははるかに使いやすいですstd::string

std::string name1;
cin >> name;
于 2013-03-26T17:45:35.473 に答える