Reputation: 411
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
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
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
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
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
Reputation: 70971
for ( argc--, argv++; argc > 0; argc--, argv++ ) { ... }
Does the following:
argc
and increment argv
argv > 0
, if this is not the case then exit the loop{ ... }
argc
and increment argv
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
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
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
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
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