C++ 为什么这样做?使用cin读取小于给定输入的char数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15642820/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:34:50  来源:igfitidea点击:

Why does this work? Using cin to read to a char array smaller than given input

c++arrayscharcin

提问by Rich

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:

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

Listing 4.2 strings.cpp

清单 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] = '
|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
'; // 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 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?

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

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

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

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

HowCanIPossiblyFitThisEntireStringIn?

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

in an array of 15 bytes.

Your initial is H.

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

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

HowCanIPossablyFitThisEntireStringIn?

好吧,HowCanIPossivelyFitThisEntireStringIn?,你的名字有 37 个字母并被存储

在 15 个字节的数组中。

你的首字母是 H。

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

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.

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

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

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

回答by Joseph Mansfield

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.

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

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

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

cin.get(name1, Size);

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.

其余字符将写入以下内存位置。现在,请记住,用于终止 C 样式字符串的空字符被定义为具有全 0 位的表示形式。现在,如果包含 的位置后面的位置?全为 0 位,则该字符串将显示为空终止。

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.

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

回答by Peter Wood

You could use istream::getwith the buffer and the size of the buffer:

您可以使用istream::get缓冲区和缓冲区的大小:

std::string name1;
cin >> name;

As others have noted, it's far easier to use std::string:

正如其他人所指出的,使用起来要容易得多std::string

##代码##