cout: different behavior due to context?

I was experimenting to see what I need to do to verify that a supported operator (+, -, *, /) was input. As cin strips the sign from the input, the operators '-' and '+' can't be read, so I checked out cin.get(c), intending to verify only a single character. However I entered more characters and found what I think is odd behavior, cout appears to be change its behavior depending on whether the commented lines are commented out or not, see the program below.

1. Run it as shown below and type anything and then press enter. This will be output as if cout is in a loop, each character typed in will be output on its own line followed by the cnt value until everything that you entered is output with "end of line!" at the end, after what must be '/n'. For example:

125/?
1
cnt =: 0
2
cnt =: 1
5
cnt =: 2
/
cnt =: 3
?
cnt =: 4

cnt =: 5
end of line!


2. Then, delete the comment symbols and run it again. This time, only the first character input is on its own line, followed by cnt = 0, followed by the rest of the input (all on one line), followed by cnt = 1, followed by "end of line!". (Note: you don't need to enter the second set to see what I'm talking about. for example:

125/?
1
cnt =: 0
25/?


cnt =: 1
end of line!


My question is why would cout output one way, as if it was in a loop, line by line, and then another, only two lines, depending on whether other lines are commented out or not?

Also, is there any reference that might explain this type of behavior so I have a better understanding of what to expect?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#define TRUE 1
#define FALSE 0

using namespace std;

int main()
{
    char c;
    //char m[15];
    int END = FALSE;
    int i = 0;

    while(!END){
        cin.get(c);
        cout << c << endl;
        cout << "cnt =: " << i++ << endl;
        if(c == '\n'){
            cout<<"end of line!"<<endl;
            END = TRUE;
        }


        //cin.get(m, 15);
        //cout<< m << endl;
    }
    return 0;
}
The basic difficulty you are having is understanding the nature of an input stream.

The input (and I think you know this) is nothing more than a stream of characters. For example:

    1 + 2 * 3

This can be represented as a string or array or any ordered collection of characters:

    { '1', ' ', '+', ' ', '2', ' ', '*', ' ', '3' }

    "1 + 2 * 3"

    etc

The trick is that cin knows how to do formated extraction: it knows how to read the string "72" as the integer 72, etc.

In order to properly parse the stream, you must consider which operation to apply to extract the next character(s).

To help with this task, google around "recursive descent parser" and you'll find examples of basic arithmetic expression parser. The idea is to have an idea of what kind of characters to expect next.


As to your question about the blanks, it is because your loop is mal-formed. Don't worry -- it is a common mistake -- but you must always check for EOF immediately after an attempt to read, before your code does anything with the (possibly failed-to-read) data.

1
2
3
4
5
6
7
8
9
10
11
12
  while (true)
  {
    // attempt to get data
    cin.get( c );

    // if failure (such as EOF) then quit the loop
    if (!cin) break;

    // (data read successfully)

    // do something with data
  }

The C++ iostreams provide a convenient shortcut for that when inputting homogeneous data. For example, if you know your input is a space-separated list of integers, you can easily use a pretty loop like this:

1
2
3
4
5
6
  int sum = 0;
  int x;
  while (cin >> x)
  {
    sum += x;
  }
...which is exactly equivalent to:

  while ((cin >> x).good())  // attempt to read x; continue only if no failure
  {
    sum += x;
  }

Likewise, you can read entire lines with the getline() function, because getline() returns the istream:

1
2
3
4
5
6
  string s;
  while (getline( cin, s ))
  {
    // s was successfully obtained
    ...
  }

But, when you are reading heterogeneous data, such as parsing an algebraic expression, you really can't use the simple loop -- you'll need to use the more complex variety.

Hope this helps.
Adding to Duoas's post,

I think I have an answer for your question of
jeffbliss1 wrote:
My question is why would cout output one way, as if it was in a loop, line by line, and then another, only two lines, depending on whether other lines are commented out or not?


So I see that while you are in the loop you print out any characters that the user types, right?
But, what you want is the std::cout function to not print out the newline (\n) character.

I think what you want is the following pseudo code:
1
2
3
4
5
6
7
8
 while there isn't a newline character in the array of characters:
   //newlines between all the print-outs  
   print-out the character 
   print-out the character position
end while;
print-out position
print-out string "end of line!\n"
end program. 


As for your other question which is;
jeffbliss1 wrote:
Also, is there any reference that might explain this type of behavior so I have a better understanding of what to expect?


The only tutorial that I can tell you that might help is the following:
http://www.cplusplus.com/doc/tutorial/control/

I hope this helps,

-Hirokachi
@Duoas: it looks like i posted right after you...lol
Last edited on
Duoas and Hirokachi,

Thanks for the explanations. I knew that I didn't understand cin at all when it retrieved a "string" of characters, as Duoas discusses about it understanding formatted input.

I figure that I need to output the assembler from the source to see precisely what the compiler determines my code "wants".

For anyone wanting to check out what happens to the C++ cide at the assembly level, see:

http://forums.codeblocks.org/index.php?topic=13025.0

While this is for Code::Blocks, the process can be applied to other IDEs and there are reources for using the command line like this:

http://stackoverflow.com/questions/137038/how-do-you-get-assembler-output-from-c-c-source-in-gcc

Now that I've generated it, I need to understand it! It's amazing how a few lines of code can result in such a large assembly file.
Last edited on
Topic archived. No new replies allowed.