confused by control flow execution in C++ Primer example - c++

I am going through C++ Primer (5th ed). In section 1.4.4, there is the following example:
#include <iostream>
int main()
{
// currVal is the number we're counting; we'll read new values into val
int currVal = 0, val = 0;
// read first number and ensure that we have data to process
if (std::cin >> currVal) {
int cnt = 1; // store the count for the current value we're processing
while (std::cin >> val) { // read the remaining numbers
if (val == currVal) // if the values are the same
++cnt; // add 1 to cnt
else { // otherwise, print the count for the previous value
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
currVal = val; // remember the new value
cnt = 1; // reset the counter
}
} // while loop ends here
// remember to print the count for the last value in the file
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
} // outermost if statement ends here
return 0;
}
When you run it with the given input
42 42 42 42 42 55 55 62 100 100 100
It prints
42 occurs 5 times
55 occurs 2 times
62 occurs 1 times
However, in order to get the final output line
100 occurs 3 times
you must press CTRL+D. Then that is printed and the program exits.
Why is this? To me, it looks like this last line should be printed and the program exited with the others. It seems I am misunderstanding how the control flow is executed so can someone please clarify?
ps I am aware of this Incorrect output. C++ primer 1.4.4 and C++ Primer fifth edtion book (if statement) is this not correct? However, neither of these explain WHY you must ctrl+d to print the final statement.

That's because of this part:
while (std::cin >> val)
In order to terminate reading the input stream, you have to terminate it with an EOF, which is supplied by Ctrl-D.
Think about it: cin skips over whitespace by default and every time you enter a number you separate it with whitespace (a space, a tab or a newline).
How will the program ever terminate the input? The answer is when it reads an EOF character - which, as stated before, is supplied by Ctrl-D.

You must press CTRL+D because otherwise the program does not know when your stdin stream has finished. It will otherwise just sit there at while (std::cin >> val forever without terminating.

Related

Strange behavior of std::cin as while loop condition

So...here is my code that refer to C++ Primer 1.4.4 section.
#include <iostream>
int main()
{
int currVal = 0, val = 0;
if (std::cin >> currVal) {
int cnt = 1;
while (std::cin >> val) {
if (val == currVal) {
++cnt;
} else {
std::cout << currVal << " occurs "
<< cnt << " times." << std::endl;
currVal = val;
cnt = 1;
}
}
std::cout << currVal << " occurs "
<< cnt << " times." << std::endl;
}
return 0;
}
I have to admit that the simple program basically work normally. But for the further discussion, I'd like refer to a asciinema recording in the first place.
In the recording I run ./a.out three times. In the first time, I typed numbers and press enter the first two recording printed and only after ctrl + D was pressed the third (last) result was printed. From previous sections in the book, I know ctrl + D is used to feed some symbols to stop the while loop. But I really wonder if it (ctrl + D here cause a strange stop) works just like as same as authors' expectation for there is no mention on how keys was pressed exactly about that example in the book.
In the last two runs, my first approach is press ctrl + D (the first result printed) and enter (the second result printed), then following several enters (no respond except more lines). Lastly, I pressed ctrl + D (the third result printed).
My last approach is press ctrl + D for two times. The first result printed on the first press and the last two came out on the second press.
With these two runs comes my confusing that after press ctrl + D (I think) there should be a stopping signal in the end of cin stream. So why did the while loop not stop? I'd appreciate a lot if anyone can explain the process behind it.
My working environment is urxvt on Manjaro Linux with zsh and oh-my-zsh installed.

c++ primer 5th 1.4.4 why can't std::cout type out things immediately

The 《c++ primer 5th》1.4.4 code example is like this
#include <iostream>
int main()
{
// currVal is the number we're counting; we'll read new values into val
int currVal = 0, val = 0;
// read first number and ensure that we have data to process
if (std::cin >> currVal) {
int cnt = 1; // store the count for the current value we're processing
while (std::cin >> val) { // read the remaining numbers
if (val == currVal) // if the values are the same
++cnt; // add 1 to cnt
else { // otherwise, print the count for the previous value
std::cout << currVal << " occurs "
<< cnt << " times" << std::endl;
currVal = val; // remember the new value
cnt = 1; // reset the counter
}
} // while loop ends here
// remember to print the count for the last value in the file
std::cout << currVal << " occurs "
<< cnt << " times" << std::endl;
} // outermost if statement ends here
return 0;
}
if i input :
11
11
13
13
13
14
I think it should execute like this :
when i input
11
11
the console should show "11 occurs 2 times".
Then i can continue to input
13
13
13
then the console should show " 13 occurs 3 times".
But the result is only when i have finished typing all the number , the console output the result once . why ?
Thanks for your help .
Input from terminal is line buffered.
The first std::cin >> currVal blocks until input is available at standard input.
That doesn't happen until you press <Enter>. (Up to that <Enter>, the characters you entered are still residing in the line buffer of your terminal / CMD box. You can backspace, edit etc.; only when you press <Enter> does the terminal / CMD box actually send those characters to the program's standard input.)
For your expected behaviour to happen, try pressing <Enter> after each number.
Both std::cin >> currVal in your sample will block the standard input, std::cin means a value that comes from standard input, in that case your keyboard is your standard input.
To confirm the input from keyboard you need to push Enter key, then values are removed from the buffer of the keyboard and processed by your code.
If you want to get the values for each press of key you need to use something like std::getchar, that function reads the buffer immediately like you expect.

Unexpected while behavior C++ (perhaps IDE related)

I am writing a very simple program to count and display the number of consecutive integers in an inputted sequence (an exercise to teach myself about while loops and conditionals). The code is as follows:
#include "stdafx.h" //obviously using VS
#include <iostream>
int main()
{
int currVal = 0, val = 0;
if (std::cin >> currVal) {
int cnt = 1; //number of consecutive values
while (std::cin >> val) {
if (val == currVal)
++cnt;
else {
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
currVal = val;
cnt = 1;
}
}
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
}
return 0;
}
In the last cout line, I account for the eof behavior that should exit the while loops without printing the last value. However, in VS 2015 the last line is not being printed and the while loop is apparently not terminating despite cnt no longer incrementing. The console continues running and accepts further inputs, and will actually return that last value if I enter another value or a non-integer. The final console looks like this:
And with another input:
Yet when I run the same code in an online compiler like Ideone, the result is correct and the loop terminates. http://ideone.com/mUZuh7
Is this some unusual behavior of Visual Studio, or is there some obvious beginners mistake in my code that I'm overlooking.
Thanks
You're making a mistake in your code, and as TeamEnternode points out in their answer it's unusual behaviour for Ideone.
Your while loop continue to process while there is a character to read from std::cin; however, after it reads the last 4, it increments cnt and doensn't output anything (as per your if statement). When the while loop next evaluates std::cin, there's nothing in it anymore!
Your code works as you probably expect if you don't end your input with a double (e.g. 1 2 3 4 4 5 ).
Here's what your code is doing (assume input is 1 2 3 4 4):
if (std::cin >> currVal): waits for input from std::cin. You will need to enter something in the console and press enter to get past this.
currVal is equal to 1, and the first letter from your input.
while (std::cin >> val) read another character from std::cin. This will read 2: val is now 2.
if (val == currVal): 1 is not equal to 2, so your code outputs the occurrences of 1, and changes currVal to 2.
while (std::cin >> val) read another character from std::cin. This will read 3: val is now 3.
if (val == currVal): 2 is not equal to 3, so your code outputs the occurrences of 2, and changes currVal to 3.
while (std::cin >> val) read another character from std::cin. This will read 4: val is now 4.
if (val == currVal): 3 is not equal to 4, so your code outputs the occurrences of 3, and changes currVal to 4.
while (std::cin >> val) read another character from std::cin. This will read another 4, and val will remain as 4.
if (val == currVal): 4 is equal to 4, so cnt is incremented
while (std::cin >> val) there is nothing further to read from std::cin.
If you input another different character (e.g. 5), the while loop will continue, evaluate that 5 != 4 and then output 4s occurrences and set currVal to 5. It will then try your while loop again; however, the input is once again empty.
Visual Studio is running the code correctly.
No, it's unusual behavior in the online compiler.
I'm assuming that the online compiler's standard input will only read until the end of the line, while a normal C++ program will read until end-of-file (either invalid output or the end-of-file shortcut is used), Because the while loop's condition at the end of
1 2 3 4 4
is not false. To fix your problem, you would have to read one line at a time (which you are yet to learn how to do I'm assuming), or wait to output anything at all and just save the information to a container and output everything at the end (which you are also yet to learn to do).
I can't really give you a fix in a way that you would understand. Just ignore the bug for now, and once you know more about how Standard I/O works, you can fix the bug then.
Sorry I can't be more helpful.

Incorrect output. C++ primer 1.4.4

the following program is supposed to count the number of times a user inputs a integer. example: user inputs 42 42 10 10. the program is supposed to out put : 42 occurs 2 times, 10 occurs 2 times.
the problem: the code will not output the last result for the number 10 until you input another number. i have pasted the code below. this code comes from c++ primer. 1.4.4
#include <iostream>
int main()
{
// currVal is the number we're counting; we'll read new values into val
int currVal = 0, val = 0;
// read first number and ensure that we have data to process
if (std::cin >> currVal)
{
int cnt = 1; // store the count for the current value we're processing
while (std::cin >> val)
{ // read the remaining numbers
if (val == currVal) // if the values are the same
++cnt; // add 1 to cnt
else
{ // otherwise, print the count for the previous value
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
currVal = val; // remember the new value
cnt = 1; // reset the counter
}
} // while loop ends here
// remember to print the count for the last value in the file
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
} // outermost if statement ends here
return 0;
}
Your program as-written appears correct for a series of numeric inputs separated by whitespace.
You need to give an end-of-file indication to the program so that it will exit the while loop and print the count for the final data. In Windows, you can do that by entering [Ctrl]-[Z] as the first character on a new line. In Linux, UNIX and Mac OS X, [Ctrl]-[D] serves a similar purpose.
Alternately, you can put your set of values into a text file and use redirection to feed your program. Suppose, for example, you put your data in a file named data.txt in the same directory as your executable. In a terminal window, you can run your program as follows:
myprogram < data.txt
As some others have noted, a non-numeric input will also work in place of end of file. For example, you could enter 42 42 10 10 fred, and it'll output what you expect as well. That doesn't appear to be the intent of the program, though. For example, if you input 42 42 10 10 fred 37, the program stops at fred and won't see 37.

Counting consecutive number of times in C++?

I am learning C++ to write a program to count how many consecutive times each distinct value appears in the input.
The code is
#include <iostream>
int main()
{
// currVal is the number we're counting; we'll read new values into val
int currVal = 0, val = 0;
// read first number and ensure that we have data to process
if (std::cin >> currVal)
{
int cnt = 1; // store the count for the current value we're processing
while (std::cin >> val)
{ // read the remaining numbers
if (val == currVal) // if the values are the same
++cnt; // add 1 to cnt
else
{ // otherwise, print the count for the previous value
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
currVal = val; // remember the new value
cnt = 1; // reset the counter
}
} // while loop ends here
// remember to print the count for the last value in the file
std::cout << currVal << " occurs " << cnt << " times" << std::endl;
} // outermost if statement ends here
return 0;
}
But it won't count the last set of numbers. For example: If I have input 5 5 5 3 3 4 4 4 4, the output is:
5 occurs 5 times.
3 occurs 2 times.
The last set result which is "4 occurs 4 times." does not show up.
I wonder what is wrong with the code.
Please help.
Thanks.
hc.
Your program is correct. Your while loop will exit when the condition is false
while (std::cin >> val)
The stream input will return false when you reach end of file (EOF), which from a terminal you can enter with Ctrl-D.
Try placing your input in a file, and your program will work. I've used the cat command to copy from the terminal's standard input and redirected to a file called input. You need to press Ctrd-D to tell cat that you are done. You could also create the input file using your favorite editor.
$ cat > input
5 5 5 3 3 4 4 4 4
<press Ctrl-D here>
Now invoke the program and redirect input from the file
$ ./test < input
Output is
5 occurs 3 times
3 occurs 2 times
4 occurs 4 times
See this related question on SO
the question on while (cin >> )
You seem to generate output only when (val == currVal) is false. What makes you think this will happen after the last 4 is read from input?