为什么这行得通?使用 cin 读取小于给定输入的字符数组

2022-01-12 00:00:00 arrays char c++ cin

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

I'm reading C++ Primer Plus (6th Edition) and I've come across some sample code in chapter 4 which I have a question about:

清单 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?
";
    cin >> name1;
    cout << "Well, " << name1 << ", your name has ";
    cout << strlen(name1) << " letters and is stored
";
    cout << "in an array of " << sizeof(name1) << " bytes.
";
    cout << "Your initial is " << name1[0] << ".
";
    name2[3] = ''; // set to null character
    cout << "Here are the first 3 characters of my name: ";
    cout << name2 << endl;
    return 0;
}

代码本身不会引起任何混乱,但我一直在运行它,并且对某个场景感到困惑.

The code itself doesn't cause any confusion, but I've been running it through and I'm confused by a certain scenario.

name1 被初始化为长度为 15 个元素的字符数组 - 我是否认为这应该包含一个长度为 14 个字符的字符串?结束字符应该保留给字符串终止符吧?

name1 is initialised as an array of chars 15 elements in length - am I right in thinking this should hold a string 14 characters in length? The end char should be reserved for the string terminator, right?

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

If I enter my name as HowCanIPossiblyFitThisEntireStringIn?, I get the following output:

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

Howdy! I'm C++owboy! What's your name?

HowCanIPossiblyFitThisEntireStringIn?

HowCanIPossiblyFitThisEntireStringIn?

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

Well, HowCanIPossiblyFitThisEntireStringIn?, your name has 37 letters and is stored

在一个 15 字节的数组中.

in an array of 15 bytes.

您的姓名首字母是 H.

Your initial is H.

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

Here are the first 3 characters of my name: C++

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

How is the entire name I enter being stored? If I step through the code, after cin reads into name1, Visual Studio tells me it contains elements 0 - 14, with the last one being the char 'y' ("HowCanIPossibly...). I would assume from this that any extra data entered had been truncated and lost, but this is obviously not the case as the following cout successfully writes the entire name out to the console.

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

For curiosity's sake, could anyone enlighten me as to what's happening here? For the record, I'm using Visual Studio 2012 Express.

推荐答案

你正在写超出数组的边界.C++ 标准并没有说这应该是一个错误.它说这是未定义的行为.这意味着任何事情都可能发生,包括看似正常工作.简而言之,您的代码没有明确定义的行为,因此您不应该相信它可以正常工作.

You are writing past the bounds of the array. The C++ standard doesn't say this should be an error; it says it is undefined behaviour. This means anything can happen, including seemingly working correctly. Simply put, your code does not have well-defined behaviour and so you shouldn't trust it to work.

我们可以想象为什么它可能会起作用.前 15 个字符非常适合数组:

We can imagine why it's probably working though. The first 15 characters will fit nicely into the array:

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

The rest of the characters are being written to the following memory locations. Now, remember that the null character, which is used to terminate C-style strings, is defined to have a representation that is all 0 bits. Now if the location following the location that contains the ? has all 0 bits in it, the string will appear to be null-terminated.

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

But the fact is, this is undefined. It just happens to work. Unfortunately, this is the scariest type of bug because it can seemingly work for a long time until one day you start getting calls from your very, very angry client.

相关文章