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.
Related
I am learning C++ using the book C++ Primer.
In Section 1.4.3, the following example code about reading the unknown number of inputs is given.
#include <iostream>
int main()
{
int sum = 0, value = 0;
// read until end-of-file, calculating a running total of all values read
while (std::cin >> value)
sum += value; // equivalent to sum = sum + value
std::cout << "Sum is: " << sum << std::endl;
return 0;
}
According to the book, if we give an input of 3 4 5 6, the output will be Sum is: 18
But when I try this on my computer(Windows 10 with MinGW), The code does not end. It just keeps on asking for input even if I enter a newline. It works only when I enter a non-int input like f.
Is this expected? If yes, is there any code that stops after inputting a newline?
I am quite new to c++ and I have already learned python, so getting stuck so early on is quite frustrating.
Thanks and regards.
You need to terminate your input by an End-Of-File-character (i.e. CTRL-Z on Windows, CTRL-D on Mac/Unix), not just by an End-Of-Line (i.e. Enter).
A simple Enter is interpreted as white space, which will be simply ignored by operator>> when reading into an integral data type.
CTRL-Z / End-Of-File, in contrast, makes any operator>> fail with an error.
See also this SO answer.
Note: Entering f will also terminate your loop, since f is not considered a valid integral number; Hence, std::cin >> value with value being of type int and an input like f will fail as well. To be more accurate: operator>> actually returns a reference to the input stream, but if reading in a value fails, failbit is set on the stream, and then interpreting the stream object in a boolean expression (implicitly calling basic_istream::operator bool()) returns false; So maybe the author of the book did not want to explain these details at the respective section in the book :-)
Is this expected?
Yes, as operator>> ignores leading whitespace by default, which includes line breaks.
If yes, is there any code that stops after inputting a newline?
Use std::cin.getline() or std::getline() instead of operator>>. You can then use operator>> with a std::istringstream to parse values from each line, eg:
#include <iostream>
#include <string>
#include <sstream>
int main()
{
std::string line;
int sum, value;
do
{
std::cout << "Enter a set of numbers, or a blank line to exit: ";
if (!std::getline(std::cin, line) || line.empty())
break;
// read until end-of-line, calculating a running total of all values read
std::istringstream iss(line);
sum = 0;
while (iss >> value)
sum += value; // equivalent to sum = sum + value
std::cout << "Sum is: " << sum << std::endl;
}
while (true);
return 0;
}
Live Demo
Is this expected?
Yes, Thats what while (std::cin >> value) does. See this answer for more explanations: How is "std::cin>>value" evaluated in a while loop?
is there any code that stops after inputting a newline?
No, as >> simply ignore a white space(also #StephanLechner mentioned it)
What you can do instead is:
Just give a condition; if it satisfies just break the loop. you
can also provide a console out to make it more understandable to the
user. For example:
std::cout << "Enter value to sum or press -1 to exit" << std::endl;
while (std::cin >> value && value != -1) // if value == -1, loop stops.
{
sum += value;
}
You can simply terminate by the end of character:
CTRL-Z on Windows
CTRL-D on Mac/Unix
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.
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.
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.
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?