do/while loop with output error message problem

Hello, I am having difficulty with part of the code. I've only been learning C++ for a week or two, so bear with me. :)

Basically, this is the start of a program that does the quadratic formula, and this part of the code covers the input for "a".

I want the code to do this: If I type "0" or something non-valid such as "j" into the "a" input prompt, I want it to read-out the ERROR message and then bring me back to inputting another value for "a".

I used to have a "goto" pair of lines, but I feel like that will just get messy as I account for more Errors, so I tried to do a do/while loop that I recently read about in my C++ book.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <cmath>
#include <complex> 
#include <iomanip>
using namespace std;
int main()
{
    double a;
    
    do
    {
    cout << "Enter a value for a: ";
    cin >> a;

    if (a == 0 || cin.fail())
	{
        cout << "ERROR: \"a\" must be a number and non-zero." << endl << endl;
	}
    }
    while (a == 0 || !cin.fail());
    ...


With this code, when I type in "0" at the "a" input, it does what I want: It outputs the ERROR message and then brings me back to input another value for "a".

However, if I did a non-number character, such as "j", I get this message:
http://i1093.photobucket.com/albums/i434/GanadoFO/do_loop_cin01.png

Which repeats forever. My question is why doesn't it let me go to the " cin >> " part after outputting the text once, allowing me type what "a" is again? Note that this happens whether or not I have the ! in front of cin.fail, so I think the problem is with my while clause, but I'm not sure.

Thanks for reading, I hope you can help. (Also, if there is a way to simplify or a better way to get same result, please do tell.)
try this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <cmath>
#include <complex>
#include <iomanip>
using namespace std;
int main()
{
    double a;

    do
    {
        cout << "Enter a value for a: ";
        cin >> a;

        if (a == 0 || cin.fail())
        {
            cout << "ERROR: \"a\" must be a number and non-zero." << endl << endl;
            cin.clear();
            cin.ignore();
        }
    } while (a == 0 || cin.fail());
    return 0;
}


After user tryes to enter an invalid type (a char into a double variable), the object cin still has the invalid variable inputed in it, and tryies to "put" it ( >> ) again and again into your duoble a

To further understand:
http://www.cplusplus.com/reference/istream/istream/ignore/
http://www.cplusplus.com/reference/ios/ios/clear/
That works just like how I wanted it, thanks a lot! Didn't know that was possible.

Of course, I guess I should delete the return 0; since I have more code below, and I'm going to now fix the problem with my "b" (linear) and "c" (constant) variables, too. I'll read the links too, thanks.
Great.
Yes, the return 0 is there just to finish the main function, which off course doesn't make any sense.
You shold mark the post as solved (the green tic mark).
Good luck.
-------------------------------------------------------------
EDIT: Okay, I'm still having some problems.

Here's my new code, sorry if it is long but I think it is needed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
int main ()
{

    double a;
    
    do
    {
        cout << "Enter a value for a: ";
        cin >> a;

        if (a == 0 || cin.fail())
        {
            cout << "ERROR: \"a\" must be a valid number and non-zero." << endl << endl;
            cin.clear();
            cin.ignore();
        }
    }
    while (a == 0 || cin.fail());

    double b;
    
    do
    {
        cout << "Enter a value for b: ";
        cin >> b;
        
        if (cin.fail())
        {
            cout << "ERROR: \"b\" must be a valid number." << endl << endl;
            cin.clear();
            cin.ignore();
        }
    }
    while (cin.fail());

    double c;
    
    do
    {
        cout << "Enter a value for c: ";
        cin >> c;
        
        if (cin.fail())
        {
            cout << "ERROR: \"c\" must be a valid number." << endl << endl;
            cin.clear();
            cin.ignore();
        }
    }
    while (cin.fail());

    ...


Here's a picture of my first new problem:
http://i1093.photobucket.com/albums/i434/GanadoFO/do_loop_cin02.png
If I do a valid input for "a", but then do an invalid "b" input, it goes to "c" without allowing me to re-do "b".

Here's a picture of my second new problem:
http://i1093.photobucket.com/albums/i434/GanadoFO/do_loop_cin03.png
If I do a multi-character invalid input for "a", it skips the input option and wants me to input c.
Edit: I think I know what the problem is for the second option - It thinks that the "q" and the "34" are two separate inputs, so it then makes a = 34 (see: http://i1093.photobucket.com/albums/i434/GanadoFO/do_loop_cin04.png ). How do I prevent it from thinking this?
Last edited on
cin.ignore() used with no arguments becomes cin.ignore(1, EOF), as it has default values for its two paremters:

istream& ignore (streamsize n = 1, int delim = EOF);
(http://www.cplusplus.com/reference/istream/istream/ignore/)

so it's only removing 1 char from cin. To remove all caracters (what you need if user enters something like 'q34', to use your example) you should specify that. I've seen people use cin.ignore(256, '\n') which means "discard up to 256 characters, or until you find a new line character, whatever comes first".

When user inputs q34 , cin.ignore() gets rid of 'q', but still has 34 to insert to the variable, which works!.

EDIT
________________________
Right now, I can't make it work either, so someone else should give you a better answer. Sorry.
Last edited on
Your loops (after the first) will only ever execute once since they loop on a failure state that is reset inside the loop. The program would be better written like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <limits>   // for numeric_limits

using namespace std ;

int main ()
{

    double a;
 
    while ( (std::cout << "Enter a value for a: "), !(cin >> a) && a == 0 )
    {
        if ( !std::cin )
        {
            std::cout << "ERROR: invalid number entered.\n\n" ;
            std::cin.clear() ;
            // The canonical way to igore a full line of input:
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') ;
        }
        else
            std::cout << "ERROR: number must be non-zero.\n\n" ;
    }

    double b;

    while ( (std::cout << "Enter a value for b: "), !(cin >> b) )
    {
        std::cout << "ERROR: invalid number entered.\n\n" ;
        std::cin.clear() ;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') ;
    }

    // ...
}


That is indeed shorter, although not sure if I totally understand the while statement.

But, I tried your code and it doesn't give me an ERROR message if I input 0 for "a". Other than that it works fine (except for the problem that Marcos was trying to fix also)

Well thanks for all the help, I learned some stuff even if it didn't fix it. I guess most simple programs like this don't account for errors like typing "q34" in input.
But, I tried your code and it doesn't give me an ERROR message if I input 0 for "a". Other than that it works fine (except for the problem that Marcos was trying to fix also)


There is a typo on line 11. The && should be replaced with ||.



That is indeed shorter, although not sure if I totally understand the while statement.


In C++, the comma operator takes two arguments. The first is evaluated and discarded. Then the second is evaluated.

So in

while ( (std::cout << "Enter a value for a: "), !(cin >> a) || a == 0 )

the (std::cout << "Enter a value for a: ") is evaluated, causing "Enter a value for a: " to be output and the return value of that expression is discarded. Then the other expression (!(cin>>a) || a == 0)is evaluated and used to control the execution of the while loop.

!(cin >> a) evaluates to true when a double is not extracted from the input stream cin. If it evaluates to true, then the || operator short circuits execution and the body of the while is entered. If it evaluates to false, then the truth of the condition (and whether or not the loop's body is entered) is dependent on a == 0.
Okay thanks for the explanation, that is convenient. I changed the 'and' to 'or', and that works now, thanks.

Edit: Oh and that also fixed the "q34" input thing. Although, typing something like "34+" still makes a = 34 and b = + (which then gives my error message for b), but that isn't really a big issue at this point, thanks again.
Last edited on
Topic archived. No new replies allowed.