【问题标题】:How do I put two increment statements in a C++ 'for' loop?如何在 C++ 'for' 循环中放置两个增量语句?
【发布时间】:2010-11-16 23:01:45
【问题描述】:

我想在for-loop 条件中增加两个变量而不是一个。

比如:

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

这是什么语法?

【问题讨论】:

    标签: c++ for-loop comma-operator


    【解决方案1】:

    试试这个

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

    【讨论】:

    • +1 你也可以在第一部分声明 j。 for(int i = 0, j = 0; i != 5; ++i, ++j) { ... }
    • +1 作为旁注,同样的语法也适用于 C#(我从谷歌搜索“C# for loop incrament 2 counters”得到这里,所以我想我会提到这一点)。
    • @CodingWithSpike:嗯,在 C# 中,逗号 特殊的,逗号运算符表达式出现在那里实际上是不合法的。在 C++ 中合法使用逗号运算符但被 C# 拒绝的示例:for( ; ; ((++i), (++j)) )
    • @BenVoigt 与逗号无关。这也不是合法的 C#:for(int i = 0; i != 5; (++i)) { 额外的括号使编译器认为它不再是“增量”操作。
    • @CodingWithSpike:确实如此,但括号改变了C#如何看待逗号并阻止了for操作中的特殊含义。
    【解决方案2】:
    for (int i = 0; i != 5; ++i, ++j) 
        do_something(i, j);
    

    【讨论】:

    • 我很惊讶人们不知道这一点
    【解决方案3】:
    int main(){
        int i=0;
        int a=0;
        for(i;i<5;i++,a++){
            printf("%d %d\n",a,i);
        } 
    }
    

    【讨论】:

    • 不将ia 设置为本地循环有什么意义?
    • 无,只是展示了如何在for中做两个增量,它只是一个sytnax的例子
    【解决方案4】:

    一个常见的习惯用法是使用comma operator,它计算两个操作数,并返回第二个操作数。因此:

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

    但它真的是逗号吗?

    写完之后,一位评论者建议它实际上是 for 语句中的一些特殊语法糖,而不是逗号运算符。我在 GCC 中进行了如下检查:

    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);
    }
    

    我希望 x 能够获取 a 的原始值,所以它应该显示 5,6,7.. 的 x。我得到的是这个

    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
    

    但是,如果我将表达式括起来以强制解析器真正看到逗号运算符,我会得到这个

    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
    

    最初我认为这表明它根本不像逗号运算符,但事实证明,这只是一个优先级问题 - 逗号运算符具有lowest possible precedence,因此表达式 x=i++, a++ 被有效地解析为 (x=i++),a++

    感谢所有 cmets,这是一次有趣的学习经历,而且我已经使用 C 多年了!

    【讨论】:

    • 我多次读到 for 循环的第一或第三部分中的逗号 不是 逗号运算符,而只是一个逗号分隔符。 (但是,我找不到官方来源,因为我在解析 C++ 语言标准方面特别差。)
    • 我一开始以为你错了,但我写了一些测试代码,你是对的——它不像逗号运算符。将修改我的答案!
    • 在那个上下文中的一个逗号操作符。您没有得到您期望的原因是命令运算符的优先级低于赋值运算符,因此如果没有括号,它会解析为 (x = i++), j++。
    • 它是一个逗号运算符。赋值比逗号运算符更紧密,所以 x=i++,a++ 被解析 (x=i++),a++ 而不是 x=(i++, a++)。该特性被某些库滥用,因此 v = 1,2,3;做直观的事情,但只是因为 v = 1 返回一个代理对象,重载的逗号运算符对其进行追加。
    • 好的。从open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2857.pdf 第 6.5.3 节开始,最后一部分是“表达式”。 (虽然 1.6 #2 将“表达式列表”定义为“用逗号分隔的表达式列表”,但该结构并未出现在 6.5.3 中。)。这意味着当我们写“++i,++j”时,它必须是 an 中的表达式,因此“,”必须是逗号运算符(5.18)。 (这不是“初始化器列表”或“函数参数列表”,它们是“逗号被赋予特殊含义”的示例,如 5.18 #2 所述。)。不过我觉得有点混乱。
    【解决方案5】:

    尽量不要这样做!

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

    AV 规则 199
    for 循环中的增量表达式除了更改单个 循环参数到循环的下一个值。

    理由:可读性。

    【讨论】:

    • 没错,但公平地说,我很确定规则标准是为战斗机中的嵌入式软件编写的,而不是花园品种 C(++) 程序。话虽如此,这可能是一个很好的可读性习惯,谁知道呢,也许你会设计 F-35 软件,而要改掉的习惯会少一个。
    【解决方案6】:

    我同意 squelart。增加两个变量很容易出错,尤其是如果您只测试其中一个。

    这是执行此操作的可读方式:

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

    For 循环适用于循环在一个递增/递减变量上运行的情况。对于任何其他变量,在循环中更改它。

    如果您需要将j 绑定到i,为什么不保留原来的变量并添加i

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

    如果您的逻辑更复杂(例如,您需要实际监控多个变量),我会使用while 循环。

    【讨论】:

    • 在第一个例子中,j 比 i 增加了一次!对于前 x 步需要执行一些操作的迭代器呢? (并且集合总是足够长)您可以在每次迭代时提升迭代器,但恕我直言要干净得多。
    【解决方案7】:

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

    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);
    

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

    【讨论】:

      【解决方案8】:

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2014-10-30
        • 2021-07-19
        • 1970-01-01
        • 2015-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-03
        • 2019-08-31
        相关资源
        最近更新 更多