user3552519
user3552519

Reputation: 411

How do commas in the initialization and increment parts of a for-loop work?

I came across a for-loop in code that looks like this:

for ( argc--, argv++; argc > 0; argc--, argv++ )

How does it work? Normally a for loop looks like this:

for (initialization; condition; increment) {/*body of the loop*/}

But this doesn't contain any commas - what do the commas mean and do?

Upvotes: 15

Views: 4033

Answers (9)

haccks
haccks

Reputation: 106092

In this for loop comma operator is used in first and last expressions. So the for statement is like

for(
    (argc--, argv++);  // Expression 1
    argc > 0;          // Expression 2
    (argc--, argv++)   // Expression 3
  )  

There are only three expressions (argc--, argv++), argc > 0 and (argc--, argv++).
Expression 1 should not necessarily be a declaration statement, it can be any valid expression or even it can be omitted

for(;expression2; expression3)

or all expressions can be omitted

for(;;)  

In the given for loop (argc--, argv++) is used as first expression to update variables argc and argv (argc will be decremented by 1 and pointer argv will be incremented by 1). Once the side-effect on these variables is done the program will enter the loop body after checking argc > 0 for true. This is what happen when you do

for( i = 1; i < 10; i++)

i = 1 update i to 1 and then condition is checked. This updation of i is done only once and then for the rest it is updated by the expression i++.

Upvotes: 3

Vlad from Moscow
Vlad from Moscow

Reputation: 311068

In the C Standard (6.8.5.3 The for statement) the for statement is presented in the following form

for ( clause-1 ; expression-2 ; expression-3 ) statement

and according to the clause-1 there is written

If clause-1 is an expression, it is evaluated as a void expression before the first evaluation of the controlling expression

In this for statement

for ( argc--, argv++; argc > 0; argc--, argv++ )  

clause-1 is the expression argc--, argv++ based on the comma operator. From the C Standard (6.5.17 Comma operator)

2 The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its evaluation and that of the right operand. Then the right operand is evaluated; the result has its type and value.

The only peculiarity is that the result of the operator is not used in the for statement. The expression is used for its side effects.

Usually the first parameter passed to a running program is its name. The expression in the clause-1 skips this first parameter.

Compare the output of these two programs. Let's assume that the user specified command line parameters

first second third

The program output of this program

#include <stdio.h>

int main( int argc, char * argv[] )
{
    for ( argc--, argv++; argc > 0; argc--, argv++ )
    {
        puts( *argv );
    }        

    return 0;
}

is

first 
second 
third

and the program output of this program when the clause-1 is empty (neither expression nor declaration)

#include <stdio.h>

int main( int argc, char * argv[] )
{
    for ( /*argc--, argv++*/; argc > 0; argc--, argv++ )
    {
        puts( *argv );
    }        

    return 0;
}

is

./prog.exe
first 
second 
third

To make the comma operator clear consider a program as the first demonstrative program where instead of the for loop there is used a while loop.

#include <stdio.h>

int main( int argc, char * argv[] )
{
    while ( argv++, --argc > 0 )
    {
        puts( *argv );
    }        

    return 0;
}

The output will be the same as in the first demonstrative program

first 
second 
third

Here is in the while statement there is also used the comma operator. The difference is that in this case the value of the comma operator is used as the value of the condition.

Pay attention to that the expression-3 also represents by itself an expression with the comma operator.

Also as the question is marked with the C++ tag then you should know that in C++ the second clause of the for statement (in C++ it is named as condition) can also be either an expression or declaration.

Upvotes: 28

user2371524
user2371524

Reputation:

As already stated in many answers, this is the comma operator, so

argc--, argv++

is only one expression.

The comma operator evaluates both sides, first left, then right. The result is that of the right side. So you could write some strange things like

int a = (x += 5, x + 2);

this would add 5 to x before assigning the result of x + 2 to a. Such code is confusing and should be avoided. But it demonstrates an important property of the comma operator:

It acts as a sequence point: With the code above, you have the guarantee that 5 has already been added to x (the value of x indeed changed), before x + 2 is evaluated.

The main sensible usage of the comma operator is the one shown in your question. It comes handy in more complex for loops to have e.g. multiple side effects and a guaranteed sequencing.

To clarify why sequencing might be important (it isn't in your example because the side effects don't depend on each other), look at this (artificial) example:

int i, j;
for (i = j = 0; i < 10; ++i, j+=i)
{
    printf("%d\n", j);
}

If the comma operator didn't introduce a sequence point here, you wouldn't know whether j+=i would add the incremented i or the not incremented one.

Upvotes: 9

proton
proton

Reputation: 431

for ( argc--, argv++; argc > 0; argc--, argv++ ) means the loop starts with the values of argc,argv set to minus 1 and plus 1 of their initial values correspondingly. Every iteration will decrease and increase their values, and it will stop once argc reaches 0 (meaning all input arguments were read).

Upvotes: 0

alk
alk

Reputation: 70971

for ( argc--, argv++; argc > 0; argc--, argv++ )  
{ ... }

Does the following:

  1. Execute "Initialisation" part: Decrement argc and increment argv
  2. Check if argv > 0, if this is not the case then exit the loop
  3. Execute { ... }
  4. Execute "Updation" part: Decrement argc and increment argv
  5. Goto step 2. above

As "Initialisation" and "Updation" are the same this could also be written as

while (argc--, argv++, argc > 0)
{ ... }

This expression

(argc--, argv++, argc > 0)

consists of three sub-expressions separated by the comma-operator.

Those sub-expressions are executed from left to right.

The whole expression evaluates to the result of the right most sub-expression.

Upvotes: 1

amol13
amol13

Reputation: 362

The initialization parameter in for loop does not means only initializing a variable with particular value.

It can also have one or more regular expressions separated by comma.

Hope it will help !!

Upvotes: 0

Praveen Kumar
Praveen Kumar

Reputation: 483

For multiple initialization and multiple updation/incremental, we use comma operator(,). We separate each instances with a comma(,).
In this case, when the for loop is entered, both argc-- and argv++ expressions in the initialization part are executed. From then onward, every time the loop is iterated, both argc-- and argv++ expressions in the incremental part is executed.

Upvotes: 4

Thomas.L
Thomas.L

Reputation: 331

for ( argc--, argv++; argc > 0; argc--, argv++ )

can be read as

for ( (argc--), argv++; argc > 0; (argc--), argv++ )

as the comma operator has the lowest possible precedence, the left-hand operator will be always evaluated first

Upvotes: 0

Antoine Morrier
Antoine Morrier

Reputation: 4078

argv owns command line arguments. However, the very first one is the name of the program.

So, the loop begins at argv[1] and treat every arguments given by the command line without treating the name of the program

Upvotes: 0

Related Questions