ok i have been at this for hours....
//after a character is entered, library routines are used to uppercase the
letters. loops the program until "1" is entered
char letter;
while (letter != '1')
{
cout << "Enter a letter: ";
cin.get(letter);
cout << char(toupper(letter)) << '\n';
}
everything works but it couts "Enter a letter: " twice...
here is a sample output
Enter a letter: h
H
Enter a letter:
Enter a letter: k
K
Enter a letter:
Enter a letter: a
A
i want it to look like this
Enter a letter: h
H
Enter a letter: k
K
Enter a letter: a
A
Can you help and explain why it is doing this....
When you enter your data, you type the letter then press ENTER. This adds your letter as well as the return character (\n) to the stream. Since cin.get() isn't going to wait for your input when there are still characters to extract from the stream, it's picking up the \n every other pass.
You can quickly fix this by adding cin.ignore:
while (letter != '1')
{
cout << "Enter a letter: ";
cin.get(letter);
cin.ignore(256, '\n');
cout << char(toupper(letter)) << '\n';
}
An alterative would be to use the >> operator as cin.get only retrieves one char at a time:
while (letter != '1')
{
cout << "Enter a letter: ";
cin >> letter;
cout << char(toupper(letter)) << '\n';
}
Just change the cin.get(letter) to cin >> letter;, and it will work as expected.
EDIT: Thought I give some more information on this. get() extracts exactly one character from the stream, which will leave the newline character in there as others have pointed out. The next call to get() will extract it and terminate immediately instead of waiting for input, since the stream still had data. The >>-operator on the other hand, is made exactly for what you're trying to do here: Read a value from stdin until the return key is pressed. So it consumes the newline as well, causing the next call to operator<<() to block until new data is entered by the user.
Note: One more thing to keep in mind: >>-extracting into a char will extract at most one character from the stream, but it does not prevent the user from entering more characters before pressing enter. This will produce some output like the following:
niko#lethal-guitar:~$ ./a.out
Enter a letter: a
A
Enter a letter: asas
A
Enter a letter: S
Enter a letter: A
Enter a letter: S
This is because the operator removes one char and the newline, but keeps the remaining chars in the stream. These will terminate the next three operator>>()-calls immediately.
For starters, because you don't check whether cin.get succeeds
or not. You will almost certainly output the last character you
read twice. Your loop should be:
while ( letter != '1' && cin.get( letter ) ) ...
or
while ( cin.get( letter ) && letter != '1' ) ...
Note too that on most systems, cin.get() will not return until
you hit enter (supposing input from the keyboard). So you'll
output "Enter a letter: ", and then wait until the enter key
is pressed. You'll then loop without waiting, reading all of
the characters you've entered, until you've read '\n'. There
are no provisions for character-wise input in the C++ standard,
and the techiques for doing it vary radically from one system
to the next.
Related
I have the following question. I want to read user's input which should be only two char R or B. How do I make a correctly working while loop to control that the user inputs only this two characters and nothing else. If it's wrong asks the user for an input again. Thank you very much.
cout<< "Enter R or B: ";
cin >> letter;
while(cin.fail()) {
cin.clear();
}
You could use do-while:
do {
cin.clear();
cout<< "Enter R or B: ";
cin >> letter;
} while (letter != 'R' && letter != 'B');
That ensures that your program will be run at least once. In the checking, simply check if the letter is not R and also not B, you repeat the loop.
I am reading "C++ primer plus/Stephen Prata"
Here is the code from this book
while (!(cin >> golf[i])) {
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
The code above is easy to understand.
But the context from this book mentions
"...the program uses cin.get() in a while loop to read the remaining input through the end of the line.This gets rid of the bad input, along with anything else on the line.
Another approach is to read to the next whitespace, which gets rid of bad input one word at a time instead of one line at a time.
Finally, the program tells the user to enter a number."
I wonder what the another approach is?
I try to express the code in different way and I know it's not correct.
while (!(cin >> golf[i])) {
cin.clear(); // resset input
char word[20];
while (cin >> word)
continue; // get rid of bad input
cout << "Please enter a number: ";
}
How do I code to read to the next whitespace, which gets rid of bad input one word at a time instead of one line at a time?
thank you for your reading.
Let's start by looking at the existing code:
while (cin.get() != '\n')
continue;
This is what reads up to the new-line. We read a character, compare it to the new-line, and if it's not equal, we read another character. So, it reads characters, and stops reading when it gets to a new-line.
If we want to read to a space character instead, we just change the value we compare to:
while (cin.get() != ' ')
continue;
If we want to stop reading at any white-space, we could use a function to tell us whether a character is white space or not. That function would look something like this:
bool is_white_space(char ch) {
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v';
}
But this is a common enough task that the standard library already has an isspace function, so we don't have to write our own. We just have to use it:
while (!isspace(cin.get())
continue;
Personally, I'd at least consider putting this into a function by itself, and giving it a readable name like skip_to_whitespace, so our outer loop would look something like:
void skip_to_space(std::istream &in) {
in.clear();
while (!isspace(in.get()))
continue;
}
// ...
while (!(cin >> golf[i])) {
skip_to_space(cin);
cout << "Please enter a number: ";
}
At least to me, this seems to make the intent of the code considerably more apparent--we don't have to read through the content of the loop to figure out what it's supposed to do--that's obvious from the name of the function.
There is one last thing I'd change though. A while loop should normally have no effect if its condition is false. This one, however, always reads at least one character from its input, regardless of what that character might be. To make that fact more apparent, I'd prefer to use a do loop, to correctly reflect the intent that the loop always executes at least once:
void skip_to_space(std::istream &in) {
in.clear();
char ch;
do {
ch = in.get();
} while (!isspace(ch));
}
Now it's obvious that the cin.get() always happens at least once, and continues to happen until we reach a white-space character.
To throw out words until you reach a number do this:
string word;
cout << "Please enter a number: ";
while(!(cin >> golf[i])){
cin.clear();
cin >> word;
if(cin.rdbuf()->in_avail() == 1){
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "Please enter a number: ";
}
}
One method of throwing out an entire line would be to use ignore.
while (!(cin >> golf[i])) {
cin.clear(); // resset input
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // get rid of bad input
cout << "Please enter a number: ";
}
So, I was writing this question in c++
cout << "Would you like the answer in Joules or eV?" << endl;
cout << "Type 'j' or 'e' to make the selection" << endl;
invalid = true;
while (invalid) { //This while loop repeats the question until the user enters e or j
invalid = false;
getline(cin, units);
if (units == "e"|| units == "E") {
answer = energy(Z,n1,n2);
cout << "The answer is: " << answer << " eV" << endl;
}
else if (units == "j"|| units == "J" || units == "joules" || units == "joule") {
answer = energy_j(Z,n1,n2);
cout << "The answer is: " << answer << " J" << endl;
}
else {
cout << "Please enter either j or e, and press enter." << endl;
invalid = true;
}
}
and it seemed fine, but for some reason it always prints the "else" bit when I run it. I have the exact same code below and it runs fine. Can anyone help? (I'm compiling with g++ on linux, if that makes a difference)
The code runs fine, but I'd like to know about why this small bug is happening. The output is shown below:
Would you like the answer in Joules or eV?
Type 'j' or 'e' to make the selection
Please enter either j or e, and press enter.
k
Please enter either j or e, and press enter.
e
Edit: So you can see how variables are defined, etc. Link to full code here
The problem:
The last extraction you performed before the call to std::getline() was:
while (!(cin >> n2))
{
cout << "Please enter a number for the final state" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
Which is perfectly fine. The only problem is that, given a valid extraction, the newline character '\n' will be left in the stream. By default, the unformatted input function std::getline() delimits input upon the acquisition of a newline character. If the residual newline is still left in the stream, the input cannot be performed.
Note that technically std::getline() discards the character but ceases extraction once it is found.
The solution:
The solution I suggested in the comments section of your question was to execute the following lines of code above your unformatted extraction:
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
What this does in order is clear the underlying stream state (a bitmask that represents errors during I/O) and ignore the maximum amount of characters until the next newline character is found (it also consumes the newline).
Why did I suggest this?
If the stream state has a bit turned on (either failbit, eofbit, or badbit) the stream won't be able to perform I/O (this also includes ignoring characters). The ignore() call is used to discard any residual input until we reach the end of the line, so we have a fresh new line to restart input.
However, since you updated your post showing me the full code, I now realize that those two calls are not needed as you already took care of invalid input in the first code example I showed you. Moreover, since you made sure the most recent extraction succeeded, there's no need to reset the stream state.
Instead, what I propose is to use the manipulator std::ws which will discard all whitespace characters (newline is also considered whitespace) until a non-whitespace character is found. It is a much more idiomatic approach to discarding newlines:
std::getline(std::cin >> std::ws, units);
// ^^^^^^^^^^^^^^^^^^^
This should be equivalent to the ignore() call because all that's left in the stream is a newline.
Improvements:
Here are a few:
The first is to always check if your input succeeded:
if (std::getline(std::cin >> std::ws, units))
{
//
}
If units will always be one character, then just use a character:
char units;
if (std::cin >> units)
{
if (units == 'e' || ... )
}
Try with std::cin.clear(); before the getline.
Maybe print out units before the if to see what it is holding. I would personally do the following to get input :
string units;
cin >> units;
I am trying to determine if the user enters something other than a character, and specifically, that they only enter m or s. See code below.
Note:
filingStatus is a char
do
{
cout << "Please enter your filing status (s for single, m for married)" << '\n';
cin >> filingStatus;
if (cin.fail())
{
cin.clear();
dataTest = 1;
cout << "Error, please enter a valid input!" << '\n';
double dummyDouble;
cin >> dummyDouble;
if (cin.fail())
{
cin.clear();
cin >> dummyString;
}
}
else
{
if (filingStatus == 'm' || filingStatus == 's')
{
dataTest = 0;
}
else
{
cout << "Error, please enter either m or s!" << '\n';
dataTest = 1;
}
}
} while (dataTest == 1);
Here is the problem, if I enter 1000 for example, the input doesn't fail. It instead stores the 1 in the char, and since 1 is neither m or S, it loops again, then it puts the 0, loops again, puts another 0, etc.
My understanding was it would fail when it sees that a integer is being stored in a char, but obviously it isn't failing.
My question is:
Why isn't the input failing? How can I change it so if someone enters a string, or number that it fails?
The input isn't failing, because '1' is a character. Digits are a subset of characters.
Read into a std::string. Then test whether that string consists of a single character from your desired range.
Note however, that reading into a string using >> stops at the first white space. To prevent this and read the whole line instead, read using std::getline().
I am assuming that fillingStatus is of char type.
Now even if you enter a numeral say '1' or '0', it is read as a char. Hence cin does not fail. It just keeps on looping as per your code.
Also, while reading an invalid char, you should be careful of clearing the input buffer because the return character '\n' stays along with other characters in the input buffer.
I would do it something like the following:
while ( !(cin >> fillingStatus) || (filingStatus != 'm' && filingStatus != 's') ) {
cout << "Error, please enter either m or s!" << '\n'; // error message
cin.clear(); // clear the error flag
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // ignore all invalid previous input
}
One way could be to change the fillingStatus to string and get only the first character of that string and see if it fails or not.
Alternatively, there used to be a method for getting a character input, getche() I think (it has been many years since I worked in C++ so don't exactly recall)...you maybe able to use that too.
Thanks
Since you are only reading the input one character at a time, your are essentially unable to tell that the user has input more and it is being held until you read more from the input stream.
Using a string to read a line of data at a time and having the program react to that string as a whole will solve your problem.
std::string filingStatus ;
while(!(cin >> filingStatus ) || ( filingStatus != "m" && filingStatus != "f") )
{
cin.clear();
std::cout << "Error, please enter either m or s!" << '\n';
};
I'm trying to only accept integers as input and loop through it at the same time as a sort of validation. The problem is, when a user enters something along the lines of "Two" the while loop goes through the input 3 different times before asking the user again. Is there a way to prevent this from happening and just skip the 3 iterations?
cout << "Enter Student ID: ";
while(!(cin >> id))
{
cout << "\nERROR: Please enter a Positive Whole Number" << endl;
cin.clear();
cin.ignore ();
cout << "Enter Student ID: ";
}
You can use this.
cin.ignore (std::numeric_limits<streamsize>::max (), '\n') ;
It would skip all the lines and you wont get extra loop iterations, no matter how many invalid characters you enter.
The reason for your while loop iterating is that the stream is not being extracted completely so by just using this line
cin.ignore (std::numeric_limits<streamsize>::max (), '\n') ;
the loop will iterate only for once because no matter how much big input you give it will be extracted. Cin.ignore() only removes the one character from the stream.
In your case if you enter "two" then after firs iteration only 't' will be extracted and the input would be "wo" for the second iteration. But by adding this line stream would be empty in the second iteration and will take input from user.