为什么我的小c ++代码出乎意料?

时间:2013-12-19 22:23:07

标签: c++

// using structures
#include <iostream>
#include <string>
using namespace std;

struct playerinfo
{
    string name;
    int level;
};

int main()
{
    playerinfo arr[5];
    for (int i = 0; i < 5; i++)
    {
        cout << " enter name for player " << i << endl;
        getline(cin, arr[i].name, '\n');
        cout << " and level \n";
        cin >> arr[i].level;
    }
    for (int i = 0; i < 5; i++)
        cout << "the level of player " << arr[i].name << " is " << arr[i].level << endl;
}

我正在读一本关于c ++语法的书,我正在练习。我希望代码的行为使得代码要求用户填写播放器的名称和级别,然后代码将它们全部打印出来。但它的表现并不像这样。当我运行代码并输入播放器的名称说“汤姆猫”然后代码询问级别,我打印一个整数说“100”,然后意外的事情开始发生,其中的原因,我无法理解。你能帮忙吗? 编辑 - 很少有人让我详细说明“意想不到的事情”开始发生的事情。 意想不到的是,当我输入播放器的名称和播放器0的级别时,屏幕上的下一个输出是“输入播放器1和级别的名称”,而我希望它只能输出“和级别”之后我输入了播放器1的名称。

3 个答案:

答案 0 :(得分:6)

当使用operator>>()从格式化输入切换时,例如,在cin >> arr[i].level和未格式化的输入中,例如,使用std::getline(),您需要知道可能在输入中等待的空格:格式化一旦找到空格(例如换行符),整数的输入就会停止。另一方面,std::getline()会在找到换行符后立即停止!所以你得到一个空行。修复是在切换到无格式输入时跳过前导空格,例如:

std::getline(std::cin >> std::ws, arr[i].name);

操纵者std::ws在使用std::istream时会跳过前导空格。

在使用输入之前,您还应始终验证输入是否成功:如果输入失败,则流停止运行并转换为false

if (std::cin >> arr[i].level) {
    // process the data
}
else {
    // report that the input is wrong and bail out
}

答案 1 :(得分:1)

当您在级别中键入并按Enter键时,您实际上是在输入100\nin >> arr[i].level会提取数字100并将其放入arr[i].level,因为它会触及换行符而停止,但它不会提取换行符本身。换行符保留在输入流中!下一次迭代将开始,getline将看到已经有一些可用的输入要读取,它将尝试读取一行到下一个\n字符。我们知道,下一个\n是输入中剩下的第一个字符,因此getline将读取一个空字符串。从现在开始,你的程序处于搞砸状态。

解决此问题的一种快捷方法是在使用ignore读取关卡后直到并包含换行符后,从输入中丢弃字符:

cin >> arr[i].level;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

这将允许用户输入100foobar,它将被解释为100。这可能是你想要的,也可能不是。如果你想接受/拒绝其他一些格式,我会把它留给你。

答案 2 :(得分:1)

包含标题

#include <limits>

在此声明之前

    getline(cin, arr[i].name, '\n');

插入声明

cin.ignore( numeric_limits<streamsize>::max() );

问题是声明之后

cin >> arr[i].level;

输入缓冲区将在用户按Enter后保留新行字符('\ n'),下一个getline函数将在此新行字符前读取空字符串。