5

我正在阅读 C++ Primer Plus(第 6 版),并且在第 4 章中遇到了一些示例代码,我对此有疑问:

清单 4.2 strings.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 个元素的字符数组 - 我认为这应该包含一个长度为 14 个字符的字符串吗?结束字符应该保留给字符串终止符,对吧?

如果我输入我的名字为HowCanIPossiblyFitThisEntireStringIn? ,我得到以下输出:

你好!我是 C++owboy!你叫什么名字?

HowCanIPossiblyFitThisEntireStringIn?

嗯,HowCanIPossiblyFitThisEntireStringIn?,你的名字有 37 个字母并且被存储

在 15 个字节的数组中。

您的姓名首字母是 H。

这是我名字的前 3 个字符:C++

我输入的全名是如何存储的?如果我单步执行代码,在 cin 读入 name1 后,Visual Studio 告诉我它包含元素 0 - 14,最后一个是 char 'y'(“HowCanIPossibly...)。我会假设任何额外的输入的数据已被截断并丢失,但显然情况并非如此,因为以下 cout 成功地将整个名称写入控制台。

出于好奇,有人能告诉我这里发生了什么吗?作为记录,我使用的是 Visual Studio 2012 Express。

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,则该字符串将显示为以空值结尾。

但事实是,这是未定义的。它只是碰巧起作用。不幸的是,这是最可怕的错误类型,因为它似乎可以工作很长时间,直到有一天你开始接到你非常非常愤怒的客户的电话。

于 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 回答