for循环的初始化和增量部分中的逗号如何工作?
Posted
技术标签:
【中文标题】for循环的初始化和增量部分中的逗号如何工作?【英文标题】:How do commas in the initialization and increment parts of a for-loop work? 【发布时间】:2018-01-25 19:23:05 【问题描述】:我在代码中遇到了一个如下所示的 for 循环:
for ( argc--, argv++; argc > 0; argc--, argv++ )
它是如何工作的?通常for
循环如下所示:
for (initialization; condition; increment) /*body of the loop*/
但这不包含任何逗号 - 逗号是什么意思和作用?
【问题讨论】:
它仍然是一样的,只是使用,
运算符(阅读它)并且它只执行第一次递增和递减一次。可能看起来像是循环的一部分,但不是。还有什么不清楚的吗?
为什么初始化部分看起来不像?这是argc--, argv++
。这是常规的 C/C++ 表达式。
initialization
可以是任何表达式。它实际上不需要初始化任何东西。你可以把printf("Hello!")
放在那里。 condition
和 updation
也是如此。
for(int i=1; i<argc; i++) do_something(argv[i]);
的写法不称职。不幸的是,许多 C 程序员都是装腔作势的人,他们喜欢以最复杂、最模糊的方式编写代码。虽然有能力的程序员会认识到好的代码等于简单易读的代码。
【参考方案1】:
在 C 标准(6.8.5.3 for 语句)中,for 语句以下列形式呈现
for ( clause-1 ; expression-2 ; expression-3 ) statement
根据 clause-1 有这样写的
如果 Clause-1 是一个表达式,它被评估为一个 void 表达式 在控制表达式的第一次评估之前
在这个for语句中
for ( argc--, argv++; argc > 0; argc--, argv++ )
clause-1 是基于逗号运算符的表达式argc--, argv++
。
来自 C 标准(6.5.17 逗号运算符)
2 逗号运算符的左操作数被评估为 void 表达;在它的评估和那个之间有一个序列点 的右操作数。然后对右操作数求值;结果 有它的类型和价值。
唯一的特点是for语句中没有使用运算符的结果。该表达式用于其副作用。
通常传递给正在运行的程序的第一个参数是它的名称。 clause-1 中的表达式跳过了第一个参数。
比较这两个程序的输出。假设用户指定了命令行参数
first second third
本程序的程序输出
#include <stdio.h>
int main( int argc, char * argv[] )
for ( argc--, argv++; argc > 0; argc--, argv++ )
puts( *argv );
return 0;
是
first
second
third
以及当clause-1为空时该程序的程序输出(既不是表达式也不是声明)
#include <stdio.h>
int main( int argc, char * argv[] )
for ( /*argc--, argv++*/; argc > 0; argc--, argv++ )
puts( *argv );
return 0;
是
./prog.exe
first
second
third
为了使逗号操作符更清晰,可以考虑一个程序作为第一个演示程序,其中使用了一个 while 循环而不是 for 循环。
#include <stdio.h>
int main( int argc, char * argv[] )
while ( argv++, --argc > 0 )
puts( *argv );
return 0;
输出将与第一个演示程序中的相同
first
second
third
这里在while 语句中也使用了逗号操作符。不同的是,在这种情况下,逗号运算符的值被用作条件的值。
注意expression-3本身也代表一个带逗号的表达式。
同样问题是用 C++ 标签标记的,那么你应该知道在 C++ 中 for 语句的第二个子句(在 C++ 中被命名为 condition)也可以是表达式或声明。
【讨论】:
"表达式用于其副作用。" for 的clause-1
和expression-3
中很典型,因此我认为 一个好的答案还应该提到引入的序列点,即使在 OPs 代码中无关......
当然,在这种特殊情况下,while
循环更短且可读性更强……【参考方案2】:
正如许多答案中已经说明的那样,这是逗号运算符,所以
argc--, argv++
只是一个表达式。
逗号运算符计算两边,先左后右。结果是右侧的结果。所以你可以写一些奇怪的东西,比如
int a = (x += 5, x + 2);
这会在将x + 2
的结果分配给a
之前将x 加5。这样的代码令人困惑,应该避免。但它展示了 逗号运算符 的一个重要属性:
它作为一个序列点:使用上面的代码,你可以保证 5 已经被添加到 x (x 的值确实改变了),在评估 x + 2
之前。
逗号运算符的主要合理用法是您的问题中显示的那个。它在更复杂的for
循环中派上用场,例如多种副作用和有保证的顺序。
为了阐明为什么排序可能很重要(在你的例子中没有,因为副作用不相互依赖),看看这个(人造的)例子:
int i, j;
for (i = j = 0; i < 10; ++i, j+=i)
printf("%d\n", j);
如果逗号运算符没有在此处引入序列点,您将不知道j+=i
是添加递增的i
还是未递增的。
【讨论】:
【参考方案3】:对于多次初始化和多次更新/增量,我们使用comma operator(,)
。
我们用comma(,)
分隔每个实例。
在这种情况下,当进入for循环时,初始化部分的argc--
和argv++
表达式都会被执行。
从那时起,每次循环迭代时,增量部分中的argc--
和argv++
表达式都会被执行。
【讨论】:
【参考方案4】:在这个for
循环中,comma operator 用于第一个和最后一个表达式。所以for
语句就像
for(
(argc--, argv++); // Expression 1
argc > 0; // Expression 2
(argc--, argv++) // Expression 3
)
只有三个表达式(argc--, argv++)
、argc > 0
和(argc--, argv++)
。
表达式1不一定是声明语句,它可以是任何有效的表达式,甚至可以省略
for(;expression2; expression3)
或者所有表达式都可以省略
for(;;)
在给定的 for 循环中,(argc--, argv++)
用作更新变量 argc
和 argv
的第一个表达式(argc
将减 1,指针 argv
将加 1)。一旦对这些变量的副作用完成后,程序将在检查argc > 0
中的true
后进入循环体。当你这样做时会发生这种情况
for( i = 1; i < 10; i++)
i = 1
将i
更新为1
,然后检查条件。 i
的更新只进行一次,然后通过表达式i++
进行更新。
【讨论】:
【参考方案5】:for ( argc--, argv++; argc > 0; argc--, argv++ ) ...
执行以下操作:
-
执行“初始化”部分:递减
argc
并递增argv
检查是否argv > 0
,如果不是则退出循环
执行 ...
执行“更新”部分:递减argc
并递增argv
转到上面的第 2 步
由于“初始化”和“更新”是一样的,所以也可以写成
while (argc--, argv++, argc > 0)
...
这个表达式
(argc--, argv++, argc > 0)
由三个以the comma-operator分隔的子表达式组成。
这些子表达式从左到右执行。
整个表达式的计算结果是最右边的子表达式的结果。
【讨论】:
【参考方案6】:argv 拥有命令行参数。但是,第一个是程序的名称。
因此,循环从argv[1]
开始,并处理命令行给出的每个参数,而不处理程序的名称
【讨论】:
【参考方案7】:for ( argc--, argv++; argc > 0; argc--, argv++ )
可以读作
for ( (argc--), argv++; argc > 0; (argc--), argv++ )
因为逗号运算符的优先级最低,所以总是先计算左边的运算符
【讨论】:
【参考方案8】:for循环中的初始化参数并不意味着只初始化一个具有特定值的变量。
它也可以有一个或多个用逗号分隔的正则表达式。
希望对你有帮助!!
【讨论】:
【参考方案9】:for ( argc--, argv++; argc > 0; argc--, argv++ )
表示循环以 argc
,argv
的值开始,分别设置为负 1 和相应的初始值加 1。每次迭代都会减少和增加它们的值,并且一旦 argc
达到 0(意味着读取了所有输入参数)就会停止。
【讨论】:
“设置为”具有误导性。 不是,他们正在改变 认为动词to minus
和to plus
在英语中不存在。最好使用to be de/incremented by
或类似的。一些母语为母语的人可能想在这里介入...:
是的,但动词set
确实存在
我警告过阅读“设置为-1”和“设置为+1”的可能性。动词“设置”确实存在。然而,设置这两个值与“设置为高一的值”又称为“增量”和“设置为低一的值”又称为递减不同。在argc--
之后,如果之前为 0,它只会以 -1 结束。我知道你的意思,但是在 *** 上写答案需要尽可能少地被误解。如果发现对您所写内容的误解,则由您决定如何反应。以上是关于for循环的初始化和增量部分中的逗号如何工作?的主要内容,如果未能解决你的问题,请参考以下文章