infinite loop due to buffer value -1? - c++

I'm writing this program for class. It's supposed to take in a word 10 or less chars in size and change each char individually to uppercase using a toupper() call. The requirements of the assignment are to use toupper() on each individual char in an array that holds the word and the '\n'. Here is my code:
int main(int argc, char *argv[])
{
char again = ' ';
char word[11];
for(int count=0; count<11; count++){
word[count] = ' ';
}
while(true){
for(int clear=0; clear < 11; clear++){
word[clear] = ' ';
}
system("CLS");
cout << "Please provide a lowercase word!" << endl;
cin.getline(word, 11);
for(int letter = 0; letter < 11; letter++){
system("CLS");
if(letter < 10){
word[letter] = toupper(word[letter]);
}
for(int printw = 0; printw < 11; printw++){
cout << word[printw];
}
Sleep(200);
}
cout << endl;
while(true){
cout << "Would you like to Repeat or Quit? (R/Q)" << endl;
cin.get(again);
cin.get();
tolower(again);
if(again == 'r' || again == 'q'){
break;
}
else{
cout << "That was an invalide input!" << endl;
}
}
if(again == 'q'){
break;
}
}
system("PAUSE");
return EXIT_SUCCESS;
}
The program works just fine for 1 - 10 char words, but if the user decides to enter a string larger than 10 chars, the program will uppercase the first 10 and then hit an infinite loop when it asks if the user would like to try again. When that happens it will continue to return "That was an invalid output!" and the next prompt to repeat or quit on the next line. It will not wait for input, and I've tried clearing the buffer with cin.ignore().
I tried checking the values in the buffer with several cout << cin.get() << endl; line and they all come back with the ascii value of -1. I assume this means it is throwing a failbit exception, but I'm not actually sure.

Instead of using a character array of fixed size, you should use a string to store your input. You can use getline to read a line from cin like this:
string input;
...
getline(cin, input);
This will read the entire line, regardless of how long it is or how many characters you actually process.

What you're seeing here is the expected behaviour of cin.getline(char* s, streamsize n) From C++ ref for istream::getline:
The failbit flag is set if the function extracts no characters, or if
the delimiting character is not found once (n-1) characters have
already been written to s.
If a user types a word longer than 10 chars, then cin writes the first 10 chars to word and sets its internal flag to fail as no delimiter \n (newline) has been seen.
If you want to stick to your current solution, you could overcome this with:
const int SIZE = 11;
...
cin.getline(word, SIZE);
if (cin.fail() && cin.gcount() == SIZE-1) { // failed because user entered a word longer than 10 chars
word[SIZE-1] = '\0'; // make sure to null terminate
cin.clear(); // clear the failure from cin
cin.ignore(256, '\n'); // ignore the leftover input from cin until next newline
}
You need to both clear the failbit and ignore the leftover input. 256 is simply a number large enough, to be super safe you can use cin.ignore(numeric_limits<streamsize>::max(), '\n'); (don't forget to #include <limits>)
PS You might be better off reading a char at a time with cin.get(char& c) though.

Related

why while loop do not need user to input in c++

I'm learning c++ and reading c++ primer plus, but I don't understand why this code need two "cin >> ch". I know the first cin will read character that was user input.but then I delete first "cin >> ch" and run code ,the program have no error.So the fist cin is necessary? why the second cin needn't user to input?
#include <iostream>
int main()
{
using namespace std;
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
cin >> ch; //get a character
while (ch != '#')
{
cout << ch;
++count;
cin >> ch; // get the next character
}
cout << endl << count << " characters read\n";
return 0;
}
You can evaluate your input right inside condition of while loop.
#include <iostream>
int main()
{
char ch;
int count = 0;
std::cout << "Enter characters; enter # to quit:\n";
while (std::cin >> ch && ch != '#')
{
std::cout << "entered: " << ch << std::endl;
++count;
}
std::cout << std::endl << count << " characters read" << std::endl;
return 0;
}
When while condition is entered it will wait for you to enter anything first. Once input is received it will check if the input is not #. If input is not # the loop is entered, input printed out, counter increased, and back to waiting for another input. If # is entered, condition becomes false, and loop is aborted.
If you remove the first cin then count will never be incremented. The user can enter # character before entering the loop and the program can never enter it therefore.
The first cin>>ch is obviously used to take input from user but you
have again accepting data in while loop using the same variable name "ch" ,
So when you run the program it will not give u error but accept only first value that you have accept before the while loop not in while loop.
In while loop you can assign new value to variable "ch" but not accept the new value again.

String to ascii function

I actually wrote a function to convert string into ascii values.
However I managed to confuse my self and don't understand why my own code works.
here it is:
void convertToString()
{
char redo;
int letter;
int length;
do {
cout<< "How long is your word \n";
cin >> length;
cout << "Type in the letter values \n";
for (int x = 0; x < length; x++) {
cin >> letter;
cout << char (letter);
}
cout << "\n To enter another word hit R" << endl;
cin >> redo;
} while (redo == 'R');
}
In the terminal I can type in all the ASCII values I want with out changing line, however I though this would cause a problem, anyways my question is, is hitting the enter button the same as hitting space? if not i dont understand how my code is able to print out the chars since i write it all in one line...Does it assign the interger "letter" a new value everytime there is a space?
Please help/explain
This is to expand a bit on what Igor said in his comment and to give a little example.
As Igor said, istream::operator>>(&int) will read non-whitespace. This means for each call on the operator, it scans along the input stream (what you typed in) for non-whitespace and reads until the next whitespace again. The next call will pick up where you left off. So, entering a space or a newline is exactly the same for this situation where you're taking in an int.
You can verify this with a simple bit of code that scans until EOF:
#include <iostream>
int main()
{
int number;
while (std::cin >> number)
{
std::cout << number << std::endl;
}
return 0;
}
This will wait for user entry to be complete (pressing enter), but print a new line for each integer in your input as separated by whitespace. So "1 2 3 4" will print each of those numbers on separate lines, regardless of if you separate them with spaces, tabs, or newlines.

newline character left in the cin.get() buffer

I am using cin.get(input).ignore(INT_MAX, '\n'); in my code. this statement is being called in a while loop to choose an option in a menu.
Although I am using ignore chained with cin.get() for every input I am reading in, sometimes a newline character remains in the cin buffer and I should press an extra 'Enter' to go to the normal process of the while loop for choosing an option.
what should I do to solve this problem?
int Menu::getChoice(int menuNum) // getChoice() returns users menu choice
{
int i = 0;
char input;
while(0 == i) // As long as users choice not valid
{
cout << "Make your choice: ";
cin.get(input).ignore(INT_MAX, '\n');
if (!cin.good())
{
cin.clear();
cin.ignore(INT_MAX, '\n');
}
i = atoi(&input);
if (menuNum == 1)
{
if (i < 1 || i > 2)
{
cout << "Not a valid choice!" << endl;
i = 0;
}
}
}
return i;
}
If I understand correctly, this issue is that sometimes in order for the code to move past cin, and to get the assignment for input, two new line characters are needed. If this is correct, than if you replace:
cin.get(input).ignore(INT_MAX, '\n');
with this:
cin >> input;
the issue will be resolved.

cin.get() getting too much

I want a user to enter a char. I want to filter what they enter and take only the first char they type.
int main(){
while (true){
char n = readOption();
cout << n << std::endl;
}
return 0;
}
char readOption() {
char input = '\0';
while (input != '\n') {
input = cin.get();
if (isalpha(input)) {
break;
}
}
return toupper(input);
}
If I enter 13# jkjoi, the console prints.
J
K
J
O
I
I only want it to print J. Why is it printing the other letters as well?
It is printing all of the characters because (after you fix your semi-colon error) you loop forever:
while (true)
{
char n = readOption();
cout << n << std::endl;
}
This will call your read function over and over, forever! Your read function loops until he gets an alpha character, so it ignores "13# " and then grabs 1 character for each iteration of the while (true) loop. If you want it to stop after reading the first alpha character, don't loop:
char n = readOption();
cout << n << std::endl;
Updated
With your comment, you can actually re-write your code entirely:
std::locale loc;
char c = '\0';
do
{
// get a character with error checking
while (!(std::cin >> c))
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
} while (!std::isalpha(c, loc));
// ignore the rest of the input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Because you asked it to.
You perform this in a loop, forever.
If you only want to do it once, then simply do it once. Remove your loops.

Failed Input help, Int and Char, C++

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';
};