C++ - Skipping code after first run-through? - c++

I have a do-while loop, shown below
do
{
dimensions = NULL;
printf("=======================================\nDo you want to multiply in 2 dimensions, or 3?\n\n");
scanf("%c", &dimensions);
... //do stuff
printf("\nEnter r to repeat, return to terminate\n");
scanf("%c", &key);
scanf("%c", &key);
}
while(key == 'r');
On the first run, it executes fine. The problem however is when it runs through the code again after the user enters 'r' and hits return. It'll take you to the first printf("==== etc., but won't allow the user to do anything, it'll go straight back to the second printf("\nEnter...
I stepped through the code to see what was going on, and on a second run through the program just skips the scanf( and all following code for absolutely no reason. Initially I thought it was because 'dimensions' wasn't being set to a value that doesn't run the following methods - but I have, and even if that were the case, the program would run the methods instead of skipping them without user input.
Am I missing something? Is scanf( not enough to stop the program once it's already been used?

Your problem is that when your program gets input from the console with scanf, it reads the data from the keyboard into the input buffer, then values are taken out of the buffer and placed into the locations you provide to scanf. The issue is that when scanf reads a character, it also reads the \n into the buffer, then upon being called again, it reads the second character that was placed into the buffer (without asking you for more input - because why would it? It already HAS things in the buffer).
So there are two solutions: one - use fflush on stdin like so: fflush(stdin). Second - write a while loop that clears out characters one by one from the input buffer: while (getchar() != '\n' );
EDIT: For more reading, see How to clear input buffer in C?

Think it through: "the user enters 'r' and hits return", then the program reads the 'r' and repeats. What's left in the input buffer? There were two keys pressed, and the code only read the first one.
That's also the reason that the code needs two calls to scanf. The first clears the extra character out of the input buffer and the second reads the new character.

What is happening now
To make the buffer flush you need to enter
r<enter>
Hitting <enter> flushes the buffer. So the input buffer now contains two characters.
r\n
So the first scanf will read r
The second scanf will read \n
So by the time you reach the while key has a value of \n. The test fails and the loop is not repeated. So you should remove the second scanf() reading into key.
So you remove the second scanf. Now what happens?
User types
r<enter>
This leaves the input buffer with:
r\n
The scanf() read r into key. The loop repeats correctly. But when we get back to the scanf(). The input buffer still has \n character in the buffer. So the scanf() immediately reads this value and the loop exists as it should have.
how you should fix it.
Ask for Y/N answer and validate that the input is correct.
std::string line;
std::getline(std::cin, line);
while (line != "Y" && line != "N")
{
std::cout << "Hey cluts enter a correct value. Y/N\n";
std::getline(std::cin, line);
}

Related

Difference between while(!file.eof()) and while(file >> variable)

First things first - I've got a text file in which there are binary numbers, one number for each row. I'm trying to read them and sum them up in a C++ program. I've written a function which transforms them to decimal and adds them after that and I know for sure that function's ok. And here's my problem - for these two different ways of reading a text file, I get different results (and only one of these results is right) [my function is decimal()]:
ifstream file;
file.open("sample.txt");
int sum = 0;
string BinaryNumber;
while (!file.eof()){
file >> BinaryNumber;
sum+=decimal(BinaryNumber);
}
and that way my sum is too large, but by a small quantity.
ifstream file;
file.open("sample.txt");
int sum = 0;
string BinaryNumber;
while (file >> BinaryNumber){
sum+=decimal(BinaryNumber);
}
and this way gives me the the right sum. After some testing I came to a conclusion that the while loop with eof() is making one more iteration than the other while loop. So my question is - what is the difference between those two ways of reading from a text file? Why the first while loop gives me the wrong result and what may be this extra iteration that it's doing?
The difference is that >> reads the data first, and then tells you whether it has been a success or not, while file.eof() does the check prior to the reading. That is why you get an extra read with the file.eof() approach, and that read is invalid.
You can modify the file.eof() code to make it work by moving the check to a place after the read, like this:
// This code has a problem, too!
while (true) { // We do not know if it's EOF until we try to read
file >> BinaryNumber; // Try reading first
if (file.eof()) { // Now it's OK to check for EOF
break; // We're at the end of file - exit the loop
}
sum+=decimal(BinaryNumber);
}
However, this code would break if there is no delimiter following the last data entry. So your second approach (i.e. checking the result of >>) is the correct one.
EDIT: This post was edited in response to this comment.
When using file.eof() to test the input, the last input probably fails and the value stays unchanged and is, thus, processed twice: when reading a string, the stream first skips leading whitespace and then reads characters until it finds a space. Assuming the last value is followed by a newline, the stream hasn't touched EOF, yet, i.e., file.eof() isn't true but reading a string fails because there are no non-whitespace characters.
When using file >> value the operation is executed and checked for success: always use this approach! The use of eof() is only to determine whether the failure to read was due to EOF being hit or something else.

How does getline work with cin?

I feel like there are a lot of similar questions, so I'm really sorry if this is a duplicate. I couldn't find the answer to this specific question, though.
I am confused as to how getline works when cin is passed to it, because my understanding is that it should be calling cin each time it is called. When working with code that was in a book I'm reading though, getline is called several times yet only one input is sent. The cin object is not called from anywhere except for within these getline calls.
What's going on here? When getline is reached does the program simply stop in its tracks and wait for the input stream to pass a value including the desired delimiter? If this is the case, do the subsequent getline calls just not have to wait because the input stream already has data including their respective delimiters? I ran a couple tests that would suggest this could be the case.
Here is the code:
string firstName;
getline(cin,firstName,',');
string lastName;
getline(cin,lastName,',');
string job;
getline(cin,job,'\n');
cout<<firstName<<" "<<lastName<<" is a "<<job<<endl;;
Sorry again if this is a stupid question, but I looked around and genuinely could not find the answer. Thanks in advance for any help that can be provided!
Clarification:
This code outputs "First Last is a Job" for the console input "First,Last,Job\n"
A call to a function using cin is not actually a request for user input (at least not directly). It is a request for characters from the standard input. In normal program operation (where standard input is not being directed from a file or other source) standard input is stored in a buffer. If the standard input buffer is empty, and cin is requesting more characters, then your system will request input from the user via the terminal. (i.e. the keyboard). This input which the terminal requests is generally line oriented. That is, it waits for you to press the Enter key, then sends all the data to be stored in the standard input buffer. If cin gets all the characters it needs before the input buffer is empty, those characters remain until the next request.
So, for example, when you make this call:
getline(cin,firstName,',');
and the input buffer is empty, Let's say the user inputs this:
Benjamin, Lindley, Software DeveloperEnter
First, the following string is stored in the input buffer:
"Benjamin, Lindley, Software Developer\n"
Then getline causes "Benjamin," to be read from the input buffer (but discards the comma).
" Lindley, Software Developer\n"
remains in the buffer for any future operations with cin.
getline does not "call" cin at all. cin is an object. Objects contain data. The data in cin is the information needed by input functions to read the standard input stream. If you wanted to read from a file, for instance, you'd open the file and pass the file object to getline instead.
When getline is called, the program reads whatever is in the input buffer. If the input buffer already contains the delimiter then getline will return right away. Otherwise it will wait.

why does cin works wheras cin.getline doesn't?

My code is
char buffer[10]={0};
cin>>buffer; //here i enter the contents as "12345678912345"
//Now i tried to enter 14 characters into a buffer of 10
cin>>buffer; //This works as it waits for input on the console
cout<<buffer;
wheras
char buffer[10]={0};
cin>>buffer;//same input as above "12345678912345"
cin.getline(buffer,10);//This doesn't wait for input on console and returns
cout<<buffer;
why does this happen?
THANKS:
thanks everyone for your answers they were helpful
Neither of your code-snippets "work" in the sense that both overflow the buffer in the first input line. This is not a good thing at all.
The second case doesn't wait for input because of technical differences between operator>> and getline - they react differently to the newline character that you have entered. When reading the first cin >> buffer, the newline at the end of the input is left in the input stream (cin). In your first case, the second cin >> buffer will skip over the newline that is in the input buffer, and then wait for more input.
In the second case, because of the workings of getline, it accepts the remaining newline as input, and buffer is not filled in with anything.
This is a common problem when mixing getline and operator>> for input. The best solution to solve that particular problem is to either use only operator >> or only getline - there are various other solutions, but they are generally quite tricky to get just right.
First off you have a buffer overrun: Reading to a char* stops when the stream goes bad, a space is found, or the width() is exhausted if it were bigger than 0. You want to use
std::cin >> std::setw(10) >> buffer;
Assuming this undefined behavior is abouded, the difference between using formatted and unformatted input for the second read is that formatted input starts with skipping leading whitespace whike unformatted input does not. Your first input stopped right before the newline character resulting from the enter key. That newline is good enough for getline() but it is skipped when using >>.
When switching between formatted and unformatted I/O you normally want to skip leading whitespace using, e.g., the std::ws manipulator:
(std::cin >> std::ws). getline(buffer, 10);
You should also consider using std::string together with std::getline().
When you input the value for buffer in console, the return is still stored in the input stream.
Hence the termination character '\n' is already read by getline() from the previous read operation. This is why this function does not wait further for user input.
Try reading the getline() before the cin >> operation.
Also, as noted by Mike, you should be careful not to cause buffer overflow.
The >> operator does not consume any whitespace including the newline. The getline function returns when it sees a newline. Your problem is the newline that >> statement leaves at the buffer. You can solve this by consuming all characters, including the newline until you see a newline in the buffer. See the ignore function:
char buffer[10]={0};
cin>>buffer;
cin.ignore('\n', 256);
cin.getline(buffer,9);
cout<<buffer;
return 0;

Possible to discard return character when using std::cin >>?

When using the >> operator in c++ to capture user input, is it possible to prevent the console from printing the newline that is generated when the user presses the return key?
You cannot prevent newline character, because when you use cin, you are communicating with system core, which is not under control by users. console will return, when you enter \n or EOF or other exception situation.
So the better way is to use getchar() to capture the '\n', and do not leave it in buffer.
It is possible to prevent this newline behavior by inputting two EOFs instead of Carriage Return from the keyboard. After entering your string at the console prompt, hit
CTRL-D, CTRL-D
Note, this is a platform specific answer. This works on my Mac, but on Windows OS the EOF sequence may be CTRL-Z, RETURN. I would appreciate an answer edit <-- HERE.
Alternately, you can ditch the >> operator and use something like std::getline and specify an exact string termination delimiter. For example:
std::string myString;
std::getline(std::cin, myString, ';');
std::cout << myString;
This will read from standard input to myString, and put the string terminating NULL character where it finds the first semicolon ';'. Then you'll only have to hit CTRL-D (input EOF) once.
You can enter the values or input by pressing space every time. But at the end you must press enter key.
Let's say: you want to enter "5,4,3,2,1"
You can do: 5 [enter] 4 [enter] 3[enter] 2[enter] 1[enter]
Also: 5[space]4[space]3[space]2[space]1[enter]
But if you want to print the output near input, you can simply print the input first and than you can print the what you want.
Example:
Input: 3 Output: input+1
So you will do:
cout<<input;
cout<<" "<<input+1<<endl;
Good luck :)

Copying from istream never stops

This bit of code runs infinitely:
copy(istream_iterator<char>(cin), istream_iterator<char>(), back_inserter(buff));
The behavior I was expecting is that it will stop when I press enter.
However it doesn't.
buff is a vector of chars.
I assume you are typing stuff in at the keyboard.
The enter key doesn't signify the end of the stream. It's just another character from cin's perspective. You need to submit EOF to achieve this (Ctrl+Z, Enter on Windows and Ctrl+D on Unix/Mac).
Incidentally, this isn't the usual way to read characters from the console. It is very inefficient (istream_iterator calls operator>> for each character) and will misbehave with whitespace. To read a line of data entry, use getline instead.