102

I would like to increment two variables in a for-loop condition instead of one.

So something like:

for (int i = 0; i != 5; ++i and ++j) 
    do_something(i, j);

What is the syntax for this?

4

8 回答 8

174

A common idiom is to use the comma operator which evaluates both operands, and returns the second operand. Thus:

for(int i = 0; i != 5; ++i,++j) 
    do_something(i,j);

But is it really a comma operator?

Now having wrote that, a commenter suggested it was actually some special syntactic sugar in the for statement, and not a comma operator at all. I checked that in GCC as follows:

int i=0;
int a=5;
int x=0;

for(i; i<5; x=i++,a++){
    printf("i=%d a=%d x=%d\n",i,a,x);
}

I was expecting x to pick up the original value of a, so it should have displayed 5,6,7.. for x. What I got was this

i=0 a=5 x=0
i=1 a=6 x=0
i=2 a=7 x=1
i=3 a=8 x=2
i=4 a=9 x=3

However, if I bracketed the expression to force the parser into really seeing a comma operator, I get this

int main(){
    int i=0;
    int a=5;
    int x=0;

    for(i=0; i<5; x=(i++,a++)){
        printf("i=%d a=%d x=%d\n",i,a,x);
    }
}

i=0 a=5 x=0
i=1 a=6 x=5
i=2 a=7 x=6
i=3 a=8 x=7
i=4 a=9 x=8

Initially I thought that this showed it wasn't behaving as a comma operator at all, but as it turns out, this is simply a precedence issue - the comma operator has the lowest possible precedence, so the expression x=i++,a++ is effectively parsed as (x=i++),a++

Thanks for all the comments, it was an interesting learning experience, and I've been using C for many years!

于 2009-08-05T09:44:20.003 回答
57

Try this

for(int i = 0; i != 5; ++i, ++j)
    do_something(i,j);
于 2009-08-05T09:42:21.830 回答
6

尽量不要这样做!

来自http://www.research.att.com/~bs/JSF-AV-rules.pdf

AV 规则 199
for 循环中的增量表达式除了将单个循环参数更改为循环的下一个值外,不会执行任何操作。

理由:可读性。

于 2009-08-05T09:53:20.483 回答
4
for (int i = 0; i != 5; ++i, ++j) 
    do_something(i, j);
于 2009-08-05T09:42:44.060 回答
2

我来这里是为了提醒自己如何将第二个索引编码到 FOR 循环的增量子句中,我知道这可以主要通过在我合并到另一个项目中的示例中观察它来完成,该示例是用 C++ 编写的。

今天,我在 C# 中工作,但我确信它在这方面会遵守相同的规则,因为 FOR 语句是所有编程中最古老的控制结构之一。值得庆幸的是,我最近花了几天时间在我的一个较旧的 C 程序中精确记录 FOR 循环的行为,我很快意识到这些研究提供了适用于当今 C# 问题的经验,特别是第二个索引变量的行为.

对于粗心的人,以下是我的观察总结。通过仔细观察 Locals 窗口中的变量,我今天看到的一切都证实了我的预期,即 C# FOR 语句的行为与 C 或 C++ FOR 语句完全相同。

  1. 第一次执行 FOR 循环时,将跳过 increment 子句(三个子句中的第三个)。在 Visual C 和 C++ 中,增量是在实现循环的块中间生成为三个机器指令,因此初始通道只运行一次初始化代码,然后跳过增量块执行终止测试。这实现了 FOR 循环执行零次或多次的功能,具体取决于其索引和限制变量的状态。
  2. 如果循环体执行,它的最后一条语句是跳转到第一次迭代跳过的三个增量指令中的第一个。在这些执行之后,控制自然落入实现中间子句的限制测试代码中。该测试的结果决定了 FOR 循环的主体是否执行,或者控制是否转移到通过其范围底部的跳转的下一条指令。
  3. 由于控制从 FOR 循环块的底部转移到增量块,因此索引变量在执行测试之前递增。这种行为不仅解释了为什么您必须按照所学的方式编写限制子句,而且它会影响您通过逗号运算符添加的任何辅助增量,因为它成为第三个子句的一部分。因此,它在第一次迭代中没有改变,但在最后一次迭代中,它永远不会执行主体。

如果循环结束时您的任一索引变量仍在范围内,则它们的值将比停止循环的阈值高一个,在真正的索引变量的情况下。同样,例如,如果第二个变量在进入循环之前被初始化为零,那么它最后的值将是迭代计数,假设它是递增 (++),而不是递减,并且在循环体改变了它的值。

于 2016-06-10T05:01:42.523 回答
1

I agree with squelart. Incrementing two variables is bug prone, especially if you only test for one of them.

This is the readable way to do this:

int j = 0;
for(int i = 0; i < 5; ++i) {
    do_something(i, j);
    ++j;
}

For loops are meant for cases where your loop runs on one increasing/decreasing variable. For any other variable, change it in the loop.

If you need j to be tied to i, why not leave the original variable as is and add i?

for(int i = 0; i < 5; ++i) {
    do_something(i,a+i);
}

If your logic is more complex (for example, you need to actually monitor more than one variable), I'd use a while loop.

于 2009-08-05T10:38:25.557 回答
0
int main(){
    int i=0;
    int a=0;
    for(i;i<5;i++,a++){
        printf("%d %d\n",a,i);
    } 
}
于 2009-08-05T09:43:01.550 回答
0

使用数学。如果这两个操作在数学上依赖于循环迭代,为什么不做数学呢?

int i, j;//That have some meaningful values in them?
for( int counter = 0; counter < count_max; ++counter )
    do_something (counter+i, counter+j);

或者,更具体地说,是指 OP 的示例:

for(int i = 0; i != 5; ++i)
    do_something(i, j+i);

特别是如果您按值传递给函数,那么您应该得到完全符合您想要的东西。

于 2015-06-11T13:17:17.670 回答