【问题标题】:How to limit user input in C++ for strings & characters?如何在 C++ 中限制用户输入字符串和字符?
【发布时间】:2020-06-07 01:28:17
【问题描述】:

我正在尝试创建一个小型餐厅程序,我将在其中练习我目前在 C++ 中学到的所有内容。但是我跳进了一个小问题。在程序开始时,我会提示用户是否要进入程序,或者选择Y或N退出程序。如果输入的不是其他任何内容,程序会告诉用户无效。

问题是假设用户输入了一个无效字符 a。 无效的输出将正常显示,一切看起来都很完美。 但如果用户输入两个或更多字符,则无效输出大小写将与用户输入的字符一样多。示例如下:

Output image

#include <iostream>

int main()
{
    char ContinueAnswer;
    std::string Employee {"Lara"};
    std::cout << "\n\t\t\t---------------------------------------"
              << "\n\t\t\t|                                     |"    
              << "\n\t\t\t|            Welcome to OP            |"
              << "\n\t\t\t|Home to the best fast food in Orlando|"
              << "\n\t\t\t|                                     |"
              << "\n\t\t\t--------------------------------------|" << std::endl;

do
{
    std::cout << "\n\t\t\t    Would you like to enter? (Y/N)"
              << "\n\t\t\t                  "; std::cin >> ContinueAnswer;
    if(ContinueAnswer == 'y' || ContinueAnswer == 'Y')
    {
        system("cls");
        std::cout << "\n\t\t\t              My name is " << Employee << "."
                  << "\n\t\t\tI will assist you as we go through the menu." << std::endl;
    }
    else if(ContinueAnswer == 'n' || ContinueAnswer == 'N')
    {
        std::cout << "\t\t\t\tGoodbye and come again!" << std::endl;
        return 0;
    }
    else
        std::cout << "\n\t\t\t\t  Invalid Response" << std::endl;
}
while(ContinueAnswer != 'y' && ContinueAnswer != 'Y')

感谢您花时间阅读并感谢任何回答的人:)

【问题讨论】:

  • do-while 循环的每次迭代中,单独读取和处理一个字符。如果有两个无效字符,循环将为两者产生相同的输出。尝试使用std::getline() 之类的函数将整行数据读取为std::string(不是char),而不是读取单个字符。另外,认真考虑使用getline()cin 读取所有内容(并根据需要解释字符串以获取数据) - 如果您不这样做,您会得到奇怪的(对用户而言)行为,例如丢弃输入或似乎在阅读两次。

标签: c++ c++11 c++14


【解决方案1】:

您可以简单地让用户输入string

std::string ContinueAnswer;

然后像这样比较:

if(ContinueAnswer == "y" || ContinueAnswer == "Y")

它将处理多字符输入。

如果您还想处理输入中的空格,请更改:

std::cin >> ContinueAnswer;

到:

std::getline(std::cin, ContinueAnswer);

【讨论】:

  • @Searetix 没问题。尽可能考虑accepting 的答案。
【解决方案2】:

在解决您的问题之前,我需要指出您应该始终在对输入进行任何操作之前验证输入是否成功。由于 inout 失败而未设置的处理变量是一个相当常见的错误来源。例如:

if (std::cin >> ContinueAnswer) {
    // do something with successfully read data
}
else {
    // deal with the input failing, e.g., bail out
}

如果读取了 9 个预期字符,我假设您认为同一行中的所有内容都是无效的。您可以将一行读入std::string。但是,这可能会被滥用以提供极长的输入行,最终会使您的程序崩溃。此外,将数据读入std::string 只是为了将其丢弃似乎是不明智的。我建议忽略所有字符,直到并包括可以使用的换行符(对于这种方法,您需要包含 &lt;limits&gt;):

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), ‘\n’);

第一个参数是一个特殊值,表示在换行符之前可以有任意数量的字符。在实践中,您可能可以使用像 1000 这样的值,这很好,但它可以被玩弄。当然,在实际应用程序中,可以使用专用限制来防止对手长时间保持程序繁忙。我倾向于假设我的程序受到攻击,以确保我能够处理不寻常的情况。

【讨论】:

  • 感谢您的提示!您的意思是验证用户是否使用 std::cin >> ContinueAnswer 输入了某些内容?我以前没有使用过 但我一定会检查一下。感谢您指出这一点!我最初想使用一个简单的字符,但我试图在没有任何异常输出的情况下尽可能地使它更好:)
  • char 的输入没有多少失败的机会。唯一的情况是在流结束之前只输入空格。但是,这种情况仍然可以正常工作。
【解决方案3】:

快速重构会产生这样的结果:

#include <iostream>
#include <cstring>
#include <stdio.h>

int main()
{
        char ContinueAnswer[256];
        std::string Employee {"Lara"};
        std::cout << "\n\t\t\t---------------------------------------"
              << "\n\t\t\t|                                     |"
              << "\n\t\t\t|            Welcome to OP            |"
              << "\n\t\t\t|Home to the best fast food in Orlando|"
              << "\n\t\t\t|                                     |"
              << "\n\t\t\t--------------------------------------|" << std::endl;

        do
        {
            std::cout << "\n\t\t\t    Would you like to enter? (Y/N)"
                      << "\n\t\t\t                  "; std::cin.getline(ContinueAnswer,sizeof(ContinueAnswer));
            if(strcmp(ContinueAnswer, "Y") == 0 || strcmp(ContinueAnswer, "y") == 0)
            {
                system("cls");
                std::cout << "\n\t\t\t              My name is " << Employee << "."
                          << "\n\t\t\tI will assist you as we go through the menu." << std::endl;
            }
            else if(strcmp(ContinueAnswer, "N") == 0 || strcmp(ContinueAnswer, "n") == 0)
            {
                std::cout << "\t\t\t\tGoodbye and come again!" << std::endl;
                return 0;
            }
            else
                std::cout << "\n\t\t\t\t  Invalid Response" << std::endl; 
        }       
        while(true);
}

cin.getline 将获取所有字符,直到一个分隔符。然后,您可以使用 strcmp 检查等效性并拒绝除您想要的以外的任何内容。最后,您似乎希望它处于无限循环中,所以不要担心最后检查输入并返回。

【讨论】:

  • 再次检查istream::getline 的文档。有一些重要的警告。在这种情况下,特别重要的是如果程序读取 sizeof(ContinueAnswer)-1 字节而没有找到分隔符会发生什么。
  • 这是一个很好的观点。更好的实现还将检查边缘情况,例如故障位等。感谢您指出这一点。
  • 感谢您抽出宝贵的时间来回答,将检查所有这些信息:)
  • 基于@user4581301 cmets 放置更多上下文,在此处查看源代码:en.cppreference.com/w/cpp/io/basic_istream/ignore
猜你喜欢
  • 2017-09-12
  • 1970-01-01
  • 2019-05-14
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-31
相关资源
最近更新 更多