即使输入是另一种数据类型,C ++ cin.fail()也会执行并移至下一行 [英] C++ cin.fail() executes and moves to next line even though input is of another data type

查看:56
本文介绍了即使输入是另一种数据类型,C ++ cin.fail()也会执行并移至下一行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用get.fail()来检查输入中是否有任何字符,如果有,我想给用户一个重新输入的机会.但是,无论情况如何,只要输入前面有一个整数,该程序似乎仍会接受用户输入.说 w1 1w ,该程序将告诉用户,它仅接受整数,而后者接受输入并移至下一行,这将导致另一个问题

I am using get.fail() to check if there's any char in the input, and if there is I would like to give the user a chance to re-enter. However, the program seems to still accept the user input whenever there's an integer in front of the input no matter the case. Say w1 and 1w, the program will tell the user that the it only accepts integers while the latter one accepts the input and moves over to the next line which then causes another problem.

    void userChoice(int input){

        switch(input)
        {
            case 1:
                insert();
                break;
            case 2:
                display();  
                break;
            case 3:
                update_data();
                break;
            case 4:
                delete_position();
                break;
            case 5:
                cout<<"Thank you for using the program\n";
                exit(0);
                break;
            case 6:
                tellSize();
                break;
            default:
                cout<<"Not an option\n";
                cin>>input;

                while(cin.fail())
                {
                    cin.clear();
                    cin.ignore(INT_MAX, '\n'); 
                    cin>>input;
                    break; 
                }
                userChoice(input);
        }

    }

参考上面的代码,假设我输入了 1w .该程序仍将执行情况1,就好像没有什么问题一样,然后以某种方式将 w 传递给了 insert()函数,这不是我想要的.我希望该程序允许用户重新输入,无论它是 1w 还是 w1 ,总之,我不希望该程序移至下一个如果在整数输入中有一个char,则行.

Referring to the code above, say I give the input 1w. The program will still execute case 1 as if there's nothing wrong, and then w is somehow passed into the insert() function which is not what I want. I would like the program to let the user re-enter the input no matter if it's 1w or w1, in short I do not want the program to move over to the next line if there's a char in an integer input.

tl; dr:为什么当cin为 1w 时,下面的代码仍然执行,为什么不打印仅输入数字",因为里面有一个字符?

tl;dr: Why does the code below still execute when the cin is 1w, shouldn't it print "Enter number only" since there's a character in there?

这是我制作的一个快速程序,要重现我所面临的错误,我首先输入 1h ,这是我所遇到的第一个错误,为什么当出现错误时该程序仍在执行输入中的char h 吗?然后在第二个输入中,我输入 2w ,并且程序将打印出 2 ,由于存在char w 在输入中?

Here's a quick program I made, to reproduce the error I am facing, I first enter 1h and here's the first bug I'm facing, why is the program still executing when there's a char h in the input? Afterwards in the second input, I enter 2w and the program prints out 2, shouldn't the program loop the while loop since there's a char w in the input?

#include<iostream>
#include<iomanip>
#include<limits>
using namespace std;

void option_1()
{
    int amount_input;

    cout<<"Enter the amount of cake"<<endl;
    cin>>amount_input;
    while(cin.fail())
    {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
        cout<<"Enter number only\n";
        cin>>amount_input;
    }
        cout<<amount_input;
}

void options(int input)
{
    bool fail;

    switch(input)
    {
        case 1:
            option_1();
            break;


        default:
            cout<<"Not an option"<<endl;
            cin>>input;
            while(cin.fail())
            {
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
                cin>>input;
                break; 
            }
            options(input);

    }
}

void menu(){
    int user_input;

    cout<<"Enter 1 to print something\n";
    cin>>user_input;
    options(user_input);
}

int main(){
    menu();
}

推荐答案

从您的注释中看来,您似乎只想整数输入,并且不想在 1w ,即使 1 会被转换为 int ,而未读 w 会被删除.调用 .clear()后忽略(...).(如上所述,您现在对 .clear() .ignore(...)的使用是正确的.

From your comments, it appears you want integer input exclusively and do not want to allow input of additional character after the integer like 1w, even though 1 would be converted to an int while leaving w unread to be removed by .ignore(...) after your call to .clear(). (as mentioned above, your use of .clear() and .ignore(...) are now correct.

如果这是您的意图,则需要一种方法来检查用户输入的整数后面是否还有其他内容.要在没有障碍物的情况下以非阻塞方式进行操作,您有两种选择.(例如,您可以在下一个字符处使用 .peek()-但您只能得到一个字符,或者可以使用面向 line 的输入法) line面向的方法允许您将整个用户输入行读取为 string ,然后提取整数值并检查输入行中是否还包含其他任何内容.

If this is your intent, you need a way to check if there is anything else following the integer input by the user. To do that in a non-blocking way if nothing actually exists, you have a couple of options. (e.g. you can .peek() at the next character -- but you only get one, or you can use a line-oriented input approach) The line-oriented approach allows you to read the entire line of user input into a string and then extract the integer value and check whether there is anything else contained in the line of input.

最直接的方法是创建 std :: basic_stringstream 从使用 getline()读取的数据行中.这种方法消耗了整个用户输入行,并为您提供了从行中提取任何所需信息所需的所有工具.这样做也不会影响您以后的任何用户输入.

The most straight forward way is to create a std::basic_stringstream from the line of data read with getline(). This approach, consumes the entire line of user input and provides you with all the tools you need to extract whatever information you may want from the line. It also does this in a way that does not effect any of your subsequent user inputs.

虽然我建议您将 void menu() void options(int input)函数结合在一起,所以您只需要一个函数即可处理菜单的输入处理--除了将几行代码重复的可能性外,将它分成两部分没有什么问题.以下仅是有关如何处理 menu()函数以仅允许整数输入的建议.您可以将其改编为其余代码.

While I would recommend you combine your void menu() and void options(int input) functions so you simply have one function to handle input processing for your menu -- there is nothing wrong with breaking it in two other than the possibility of a few lines of code being duplicated. The following is just a suggestion on how to handle your menu() function to only allow integer input. You can adapt it to the remainder of your code.

您将需要几个附加条件:

You will need a couple of additional includes:

#include <sstream>
#include <string>

我还将 #define 第一个和最后一个可接受的菜单项,这样您就可以在代码中的那些常量可用的地方轻松添加菜单,例如,

I would also #define the first and last acceptable menu entries so you have those constants available in your code in a place that can be easily changed as you add to your menu, e.g.

#define MENUFIRST 1     /* first valid entry */
#define MENULAST  1     /* last valid entry */

(注意:,将只允许输入 1 作为有效菜单项)

(note: that will allow only 1 be entered as a valid menu entry)

要使用上述方法限制您的 menu()函数,您可以执行以下操作:

To limit you menu() function using the approach outlined above, you could do:

void menu(){

    int user_input = 0;
    string line, unwanted;

    for (;;) {  /* loop continually until valid input received */
        cout << "\nEnter 1 to print something: ";
        if (!getline (cin, line)) { /* read an entire line at a time */
            cerr << "(user canceled or unrecoverable stream error)\n";
            return;
        }
        stringstream ss (line);         /* create a stringstream from line */
        if (!(ss >> user_input)) {      /* test if valid integer read */
            /* test eof() or bad() */
            if (ss.eof() || ss.bad())   /* if not, did user cancel or err */
                cerr << "(empty-input or unreconverable error)\n";
            else if (ss.fail())         /* if failbit - wasn't an int */
                cerr << "error: invalid integer input.\n";
        }
        else if (ss >> unwanted) {      /* are there unwanted chars? */
            cerr << "error: additional characters following user_input.\n";
            user_input = 0;             /* reset user_input zero */
        }       /* was int outside MENUFIRST-to-MENULAST? */
        else if (user_input < MENUFIRST || MENULAST < user_input)
            cerr << "error: integer not a valid menu selection.\n";
        else    /* valid input!, break read loop */
            break;
    }

    options(user_input);
}

鉴于上述讨论,这些评论应该是不言自明的,但是如果您有任何疑问,请告诉我.将该函数与其余代码一起使用(并注释未使用的//bool fail; ),您可以测试其是否满足您的要求,例如

The comments should be self-explanatory given the discussion above, but let me know if you have questions. Using the function with the rest of your code (and commenting the unused // bool fail;), you can test whether it meets your requirements, e.g.

使用/输出示例

$ ./bin/menu_int

Enter 1 to print something: w1
error: invalid integer input.

Enter 1 to print something: $#%&^#&$ (cat steps on keyboard) !#$%%^%*()
error: invalid integer input.

Enter 1 to print something: 1w
error: additional characters following user_input.

Enter 1 to print something: -1
error: integer not a valid menu selection.

Enter 1 to print something: 24
error: integer not a valid menu selection.

Enter 1 to print something: 1
Enter the amount of cake
3
3

还请注意,您的 menu()功能现在可以正确捕获用户按下 Ctrl + d (或<在Windows上为kbd> Ctrl + z )以取消输入并正常退出.

Also note, your menu() funciton will now properly trap a manual EOF generated by the user pressing Ctrl+d (or Ctrl+z on windows) to cancel input and exit gracefully.

这篇关于即使输入是另一种数据类型,C ++ cin.fail()也会执行并移至下一行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆