Yes/No User Choice

Hello,
I am attempting to allow the user to enter a choice of y (yes) or n (no) for a specific question in a program. However, upon compilation the program fails to exit the while loop even when a correct answer of y,Y,n, or N is entered. Depending on the number of characters entered by user also determines the number of times "Please enter Y (Yes) or N (No)" is printed to the screen. I'm a little confused as to what my error maybe? Is there some conversion of the character that I am unaware of? Thanks in advance.

//Ask user for information regarding grain boundary threshold and window/bandwidth value along grain boundary
char choice;
float bandwidth, gbthreshold;
printf ("\nWould you like to select threshold for grain boundary (min. disorientation angle value)? (Y/N)\n");
choice=getchar();

//if user fails to input correct selection\, continue loop until correct selection is entered
while (choice != 'n' || choice != 'N' || choice != 'y' || choice != 'Y')
{printf ("\nPlease enter Y (Yes) or N (No)\n");
choice=getchar();}
Last edited on
You want to use && not || since using a logical OR means the while loop will be infinite.
Zhuge,
Thanks for the help, that resolved the issue. I'm curious, if I were to use an if statement, would the OR statement be applicable. Nonetheless, what is would be causing the multiple print of the line "Please enter Y (Yes) or N (No)" that I am getting based on the number of characters input by user?
No, you would still need to use &&.

The reason that is happening is because getchar() only gets one character from the buffer, so if someone types in: "asdfq\n", then once you get in the while loop the input buffer will contain "sdfg\n", which the next getchar() will get...etc.
in order to avoid this, would you advise using maybe using gets instead?
No, don't EVER use gets(). It is incredibly unsafe. Instead, use std::getline().
firedraco,
Much thanks for the help. Nonetheless, I am having an additional issue with my secondary question. Upon asking the user "Would you like to select window/bandwidth along grain boundary? (Y/N)", it skips the command for user input of a question and goes straight to the while loop asking "Please enter Y (Yes) or N (No)." Any idea why this may be occurring? Is my choice variable already designated as the value entered by the user in the prior question?


string choice;
float bandwidth, gbthreshold;
printf ("\nWould you like to select threshold for grain boundary (min. disorientation angle value)? (Y/N)\n");
getline(cin, choice);
//if user fails to input correct selection\, continue loop until correct selection is entered
while (choice != "n" && choice != "N" && choice != "y" && choice != "Y")
{printf ("\nPlease enter Y (Yes) or N (No)\n");
getline(cin, choice);}

if (choice == "Y" || choice == "y")
{
//if user answers yes, ask him to enter threshold for grain boundary
printf ("\nPlease enter desired grain boundary threshold (in degrees): \n");
cin >> gbthreshold;

//ask secondary question regarding window/bandwidth along grain boundary
printf ("\nWould you like to select window/bandwidth along grain boundary? (Y/N)\n");
getline(cin, choice);
while (choice != "n" && choice != "N" && choice != "y" && choice != "Y")
{printf ("\nPlease enter Y (Yes) or N (No)\n");
getline(cin, choice);}
if (choice == "Y" || choice == "y")
{
//if user answers yes, ask him to enter window/bandwidth along grain boundary
printf ("\nPlease enter desired window/bandwidth along grain boundary (ex. if +/- 10 micrometers enter 10): \n");
cin>>bandwidth;
}
else bandwidth=0;
}
else gbthreshold=0;
When you use a - "cin >> x", it leaves a newline in the input stream.
So when you have:

cin >> gbthreshold

It adds a newline to the input so when your program asks the question, the getline(); takes in the newline.

Just add a cin.get(); before the program asks for the getline(); that you need.
A few things going on here that I see...

1. Why are you using printf? cout is typesafe and generally better overall, and you're using C++, not C, for a reason I presume. printf() kind of defeats that reason if so. Otherwise, if you are not using C++ for it's improvements, you should be using C for whatever reasons you are using C functions in C++, such as speed or file size (the main reasons I ever use C over C++).

2. I think simply using the >> operator with cin is sufficient, if not the solution to the problem, instead of functions like getline(). 'Why complicate it if you don't need to?' is how I see it. Or KISS principal...

3. I'd use tolower() (or equivalent C++ type method) to reduce some redundancy with all the upper and lower variants in the conditions..

4. 'choice' doesn't need to be a string if it's only going to be getting single character input, like y/n. This might also be the solution to the problem.

5. You didn't initialize the floats, which causes them to be, by default, some useless number like 1.68729e+038. You probably want to init them as 0.0...

Here is what I would suggest, for implementing the things I addressed above:
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
#include <iostream>
#include <cctype>
using namespace std;

int main() {
    char choice;
    float bandwidth = 0.0, gbthreshold = 0.0;

    cout << "\nWould you like to select threshold for grain boundary\n"
        "(min. disorientation angle value)? (Y/N): ";
    cin >> choice;

    while (tolower(choice) != 'n' && tolower(choice) != 'y') {
        cout << "\nPlease enter Y (Yes) or N (No): ";
        cin >> choice;
    }

    if (tolower(choice) == 'y') {
        cout << "\nPlease enter desired grain boundary threshold "
            "(in degrees): ";
        cin >> gbthreshold;
        cout << "\nWould you like to select window/bandwidth along\n"
            "grain boundary? (Y/N): ";
        cin >> choice;

        while (tolower(choice) != 'n' && tolower(choice) != 'y') {
            cout << "\nPlease enter Y (Yes) or N (No): ";
            cin >> choice;
        }

        if (tolower(choice) == 'y') {
            cout << "\nPlease enter desired window/bandwidth along\n"
                "grain boundary (ex. if +/- 10 micrometers enter 10): ";
            cin >> bandwidth;
        }
    }
    cout << "Bandwidth = " << bandwidth << "\nGbThreshold = " << gbthreshold
            << endl;
    return 0;
}
Last edited on
Thank you all for the replies. RyanCaywood, the edits worked like a dream. I was initially using printf because I eventually was printing my results to an output file using fprintf to keep it consistent. I guess it was unnecessary. However, for future reference, outside of simplicity, what am I gaining by using cout vs. printf?
To the cout vs printf question:
Parashift com FAQ wrote:
[15.1] Why should I use <iostream> instead of the traditional <cstdio>?

Increase type safety, reduce errors, allow extensibility, and provide inheritability.

printf() is arguably not broken, and scanf() is perhaps livable despite being error prone, however both are limited with respect to what C++ I/O can do. C++ I/O (using << and >>) is, relative to C (using printf() and scanf()):

* More type-safe: With <iostream>, the type of object being I/O'd is known statically by the compiler. In contrast, <cstdio> uses "%" fields to figure out the types dynamically.
* Less error prone: With <iostream>, there are no redundant "%" tokens that have to be consistent with the actual objects being I/O'd. Removing redundancy removes a class of errors.
* Extensible: The C++ <iostream> mechanism allows new user-defined types to be I/O'd without breaking existing code. Imagine the chaos if everyone was simultaneously adding new incompatible "%" fields to printf() and scanf()?!
* Inheritable: The C++ <iostream> mechanism is built from real classes such as std::ostream and std::istream. Unlike <cstdio>'s FILE*, these are real classes and hence inheritable. This means you can have other user-defined things that look and act like streams, yet that do whatever strange and wonderful things you want. You automatically get to use the zillions of lines of I/O code written by users you don't even know, and they don't need to know about your "extended stream" class.


For more info, you should google "C++ printf vs cout", or similar. I suggest doing some reading on the new C++ classes, etc, the pro's and con's, etc.

Basically to sum up the main differences, cout is typesafe (meaning you can put any type (int, string, char, etc) into it without any special treatment, so you won't have any errors with types, like you might in C functions like printf, if you specify %d for a char, or use too many or too few parameters with printf, etc. On the con side, cout is slower than printf() (as with most C++ I/O vs C I/O). I think... I've also heard that cout is faster... You'll have to look that one up.

Also, for printing to a file, you should use a stream instead of fprintf()... Lookup streams on this site or google.
Last edited on
Topic archived. No new replies allowed.