c++: What does 'while (cin >> variable, variable)' exactly do?

143 views Asked by At

So here's that piece of code, very basic but i just can't find any similar questions that have two variables in the while loop with cin in it.

void Perm(int start, int end, int a[]) {
  //some recursion code
}
int main() {
   int i, n, a[10];
   while (cin >> n, n) {
      for (i = 0; i < n; i++)
      {
         a[i] = i + 1;
      }
      Perm(0, n, a);
   }
   return 0;
}

Can't figure out what does while (cin >> n, n) part do, and when will it stops. It looks like when I run the code, the input is just required once..

3

There are 3 answers

1
Vlad from Moscow On

In the condition of the while statement

while (cin >> n, n) {

there us used the comma operator.

That is the expression consists from two subexpressions, cin >> n and n, that are executed sequentially. The result of the condition is the value of the second subexpression that is implicitly converted to the type bool.

From the C++ 17 Standard (8.19 Comma operator)

  1. ... A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression (Clause 8). Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. The type and value of the result are the type and value of the right operand;...

The while loop can be equivalently rewritten like

while (cin >> n, n != 0 ) {

It would be more safer to write the condition of the while statement like

while (cin >> n, n != 0 && n <= 10 ) {

Instead of the comma operator it would be better to use the logical AND operator like for example

while (cin >> n && n != 0 && n <= 10 ) {
10
user4581301 On

The comma operator performs the expression to the left of the comma and discards the result then performs the expression on the right and offers up the result for testing. So, in English

while (cin >> n, n) 

says, read from Standard In into integer n and discard whether or not the read was successful, then test the value of n. If n is not zero, enter the loop.

With a modern compiler the point is sort of moot, but I believe it would read better as

while (cin >> n && n)

or in English, if we successfully read from standard in into integer n and n is not zero, enter the loop. It conveys the intent better, but it's moot because if the read fails, as of C++11 n will be set to zero and still exit the loop. Before C++11 you probably got an infinite loop testing the last good, non-zero value of n over and over forever.

As explored in the comments below the point seems to be not so moot. It appears that under some conditions, no data given in this case, the value is not being zeroed. More Standard-reading required here, but it looks as though

while (cin >> n && n)

or similar is required to catch all of the cases.

0
Lucas Alves On

That is a really nice and tricky question!

First, as pointed out in other answers, it performs a comma operator evaluation. Thus, the left operand (before the ,) is evaluated and its side effects are committed, then it is discarded and the right operand (after the ,) is evaluated and returned.

Note that, as pointed out in the comments, it is not the equivalent of while (std::cin >> n && n) because, in that one, it checks if it could do the input successfully. How is it done? When a error occurs (like if you pass a string instead of a integer, or you are reading from a file and an End-Of-File occurs), the std::cin returns a error that is converted to a bool and evaluated as false by any conditional statement.

You didn't initialize the variable n; this can cause UB (undefined behavior) because the C++ doesn't initialize variables automatically as some other languages do! What the program does is reserve a memory address for that variable and, if you don't explicitly initialize it, it will use any (garbage) value that is inside that memory address!

Let's simulate what could happen!

Let's read input from a empty file, initialize our variable, n, to any non-zero value then usie the comma operator in our while loop:

#include <iostream>

int main()
{
    freopen("test.txt", "r", stdin);
    int n=2502; 
    while (std::cin >> n, n)
    {
        std::cout << n << '\n';
    }
    return 0;
}

In the above example, std::cin will return EOF and the variable n will not be changed at all! Because the comma operator just returns the right operand, just the n will be checked in the while loop, and any non-zero int value is evaluated as true, so this will cause a infinite loop and will always print 2502 in the console.

If you change it to use &&, the while will check the std::cin as well, and EOF will be evaluated as false and the loop will never be executed.

P.S.: Note the uninitialized variables are UB, so it COULD work as expected on your machine and doesn't work in another machine, or it could work as expected in your own machine sometimes, and sometimes, suddenly, stop working as expected, making it HARD to debug.