【问题标题】:Most common/idiotproof way to catch invalid input捕获无效输入的最常见/最简单的方法
【发布时间】:2012-10-24 05:23:09
【问题描述】:

我现在正在学习 c++,现在我想知道捕获无效输入的最常见/最佳方法。我很想回答这个广泛开放的问题,但我更具体的问题如下。

我想从用户那里得到一个字符。如果 char 为 'y' 则重复,如果为 'n' 则程序将关闭。如果我输入多个字符,那么它将重复与字符一样多次,例如我输入“你好”,它将显示我的输出 5 次。我假设它读取每个字符并遍历整个循环,然后读取行中的下一个字符。我怎样才能让它只显示一次?

bool valid = 0;
while(valid)
{

...

    bool secValid = 0;
    while(secValid == 0)
    {
        cout << "To enter another taxable income type 'y': \n\n";
        char repeat = NULL;
        cin >> repeat;
        if(repeat == 'y')
        {
            valid = 0;
            secValid = 0;
            system("cls");
        }else if(repeat == 'n')
        {
            return;
        }else
        {
            secValid = 1;
        }
    }
}

【问题讨论】:

  • 哎呀,我把它们从常量改了

标签: c++ char cin


【解决方案1】:

你可以这样组织它:

while(true) {
    cout << "Repeat (y/n)? ";
    string line;
    if(!getline(cin, line))
        break; // stream closed or other read error
    if(line == "y") {
        continue;
    } else if(line == "n") {
        break;
    } else {
        cout << "Invalid input." << endl;
    }
}

示例会话:

Repeat (y/n)? y
Repeat (y/n)? foo
Invalid input.
Repeat (y/n)? n

这里我们使用std::getline 来获取一整行输入,而不是一次获取一个字符。

【讨论】:

  • 您需要在std::getline()之后检查读取是否成功,例如if (std::getline(std::cin, line)) { ... }
【解决方案2】:

std::getline():

std::string line;
std::getline(std::cin, line);
if (line == "y") {
   // handle yes
}
else if (line == "n") {
   // handle no
}
else {
   // handle invalid input
}

【讨论】:

  • 总是需要检查输入是否成功:if (std::getline(std::cin, line)) { ... }
  • 什么输入是不成功的例子?如果用户点击返回?没有输入任何内容
  • std::getline() 如果没有字符则失败,例如,当使用 Ctrl-D (UNIX) 或 Ctrl-Z (Windows) 时。由于输入失败时std::string 不变,因此您将有一个无限循环。对于格式化的输入,例如整数,失败的可能性更大。
【解决方案3】:

使用&lt;string&gt; 标头中的std::getline 的输入读入std::string

【讨论】:

    【解决方案4】:

    此外,在检查字符串中的“y”或“n”时,最好使用大写字符串。例如

    std::string YES = "Y";
    std::string NO = "N";
    ...
    std::string line;
    std::getline(std::cin, line);
    std::transform(line.begin(), line.end(), line.begin(), std::toupper);
    if (line == YES)
    {
        ...
    }
    else if (line == NO)
    {
        ..
    

    。 }

    【讨论】:

    • 我需要导入一些东西才能使用转换吗?
    • 是的,你应该包括 模块。 transform 函数将一元(或二元)函数应用于可迭代对象并将结果写入另一个可迭代对象。
    • 请注意,toupper() 的这种使用可能会导致崩溃:如果 char 已签名,则将其与非 ASCII 值一起使用会导致未定义的行为!你需要使用char my_toupper(unsigned char c) { return std::toupper(c); } 之类的东西。此外,您需要在读取后检查它是否成功。
    猜你喜欢
    • 1970-01-01
    • 2019-04-21
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2015-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多