我在代码中遇到了一个for循环,看起来像这样:
for ( argc--, argv++; argc > 0; argc--, argv++ )
它是如何工作的?通常,for循环看起来像这样:
for
for (initialization; condition; increment) {/*body of the loop*/}
但是这里没有包含任何逗号--逗号的意思和作用是什么?
ny6fqffe1#
在C标准中(6.8.5.3 for语句)for语句以下列形式表示
for ( clause-1 ; expression-2 ; expression-3 ) statement
并且根据 * 子句-1 *,写有如果子句-1是表达式,则在对控制表达式进行第一次求值之前,将其求值为void表达式在此声明
argc--, argv++
2逗号运算符的左操作数被计算为空表达式;在其求值和右操作数的求值之间存在序列点。则计算右操作数;结果具有其类型和值。唯一的特殊性是在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; }
为
以及当 * 子句-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; }
输出将与第一个演示程序中的输出相同
在while语句中也使用了逗号运算符。不同之处在于,在这种情况下,逗号运算符的值用作条件的值。请注意,expression-3 本身也表示一个带有逗号运算符的表达式。同样,当问题用C标记时,你应该知道在C中for语句的第二个子句(在C++中它被命名为 condition)也可以是表达式或声明。
uhry853o2#
正如在许多答案中已经说明的,这是 * 逗号运算符 *,所以
只有一个表达式。逗号运算符计算两边的值,先左后右。结果就是右边。所以你可以写一些奇怪的东西比如
int a = (x += 5, x + 2);
这将在将x + 2的结果分配给a之前将5加到x。这样的代码容易混淆,应该避免。但它展示了 * 逗号运算符 * 的一个重要属性:
x + 2
a
作为序列点:使用上面的代码,您可以保证在x + 2被计算之前,5已经被添加到x(x的值 * 确实 * 改变了)。
逗号操作符的主要合理用法是在您的问题中显示的。在更复杂的for循环中,它可以方便地使用e。例如多种副作用和有保证的顺序。为了澄清为什么测序 * 可能 * 重要(它不在你的例子中,因为副作用并不依赖于彼此),看看这个(人工的)例子:
int i, j; for (i = j = 0; i < 10; ++i, j+=i) { printf("%d\n", j); }
如果逗号操作符没有在这里引入序列点,您将不知道j+=i是否会添加递增的i或未递增的i。
j+=i
i
31moq8wy3#
对于多次初始化和多次更新/增量,我们使用comma operator(,)。我们用comma(,)分隔每个示例。在这种情况下,当进入for循环时,执行初始化部分中的argc--和argv++表达式。从那时起,每次循环迭代时,增量部分中的argc--和argv++表达式都会执行。
comma operator(,)
comma(,)
argc--
argv++
fykwrbwg4#
在这个for循环中,comma operator用于第一个和最后一个表达式。所以for语句如下
for( (argc--, argv++); // Expression 1 argc > 0; // Expression 2 (argc--, argv++) // Expression 3 )
只有三个表达式(argc--, argv++)、argc > 0和(argc--, argv++)。表达式1不一定是声明语句,它可以是任何有效的表达式,甚至可以省略
(argc--, argv++)
argc > 0
for(;expression2; expression3)
或者可以省略所有表达式
for(;;)
在给定的for循环中,(argc--, argv++)被用作第一个表达式来更新变量argc和argv(argc将递减1,指针argv将递增1)。一旦对这些变量的副作用完成,程序将在检查argc > 0是否为true后进入循环体。你这么做的后果就是这样
argc
argv
true
for( i = 1; i < 10; i++)
i = 1将i更新为1,然后检查条件。对i的更新只进行一次,其余的则通过表达式i++进行更新。
i = 1
1
i++
ryhaxcpt5#
for ( argc--, argv++; argc > 0; argc--, argv++ ) { ... }
执行以下操作:1.执行“* 初始化 ”部分:减少argc并增加argv1.检查argv > 0,如果不是,则退出循环1.执行{ ... }1.执行“Updation”部分:减少argc并增加argv1.后藤步骤2。以上由于“ Initialization *”和“Updation”相同,因此也可以写为
argv > 0
{ ... }
while (argc--, argv++, argc > 0) { ... }
此表达式
(argc--, argv++, argc > 0)
由三个子表达式组成,由逗号操作符分隔。这些子表达式从左到右执行。整个表达式的计算结果为最右侧子表达式的结果。
amrnrhlw6#
argv拥有命令行参数。第一个问题是程序的名称。因此,循环从argv[1]开始,处理命令行给出的每个参数,而不处理程序名
argv[1]
xtfmy6hx7#
可以读作
for ( (argc--), argv++; argc > 0; (argc--), argv++ )
由于逗号运算符的优先级可能最低,所以左手运算符总是先计算
nbnkbykc8#
for循环中的初始化参数并不意味着只初始化具有特定值的变量。它还可以有一个或多个正则表达式,由逗号分隔。希望能有帮助!!
ig9co6j19#
for ( argc--, argv++; argc > 0; argc--, argv++ )表示循环开始时,argc、argv的值分别设置为它们初始值的负1和正1。每次迭代都会减少和增加它们的值,一旦argc达到0(意味着所有输入参数都被读取),迭代就会停止。
9条答案
按热度按时间ny6fqffe1#
在C标准中(6.8.5.3 for语句)for语句以下列形式表示
并且根据 * 子句-1 *,写有
如果子句-1是表达式,则在对控制表达式进行第一次求值之前,将其求值为void表达式
在此声明
argc--, argv++
。从C标准(6.5.17逗号运算符)2逗号运算符的左操作数被计算为空表达式;在其求值和右操作数的求值之间存在序列点。则计算右操作数;结果具有其类型和值。
唯一的特殊性是在for语句中不使用运算符的结果。该表达式用于其副作用。
通常传递给运行程序的第一个参数是程序名。clause-1 中的表达式跳过第一个参数。
比较这两个程序的输出。让我们假设用户指定了命令行参数
此程序的程序输出
为
以及当 * 子句-1 * 为空时此程序的程序输出(既不是表达式也不是声明)
为
为了使逗号操作符清晰,我们可以将一个程序看作第一个演示程序,其中使用了while循环来代替for循环。
输出将与第一个演示程序中的输出相同
在while语句中也使用了逗号运算符。不同之处在于,在这种情况下,逗号运算符的值用作条件的值。
请注意,expression-3 本身也表示一个带有逗号运算符的表达式。
同样,当问题用C标记时,你应该知道在C中for语句的第二个子句(在C++中它被命名为 condition)也可以是表达式或声明。
uhry853o2#
正如在许多答案中已经说明的,这是 * 逗号运算符 *,所以
只有一个表达式。
逗号运算符计算两边的值,先左后右。结果就是右边。所以你可以写一些奇怪的东西比如
这将在将
x + 2
的结果分配给a
之前将5加到x。这样的代码容易混淆,应该避免。但它展示了 * 逗号运算符 * 的一个重要属性:作为序列点:使用上面的代码,您可以保证在
x + 2
被计算之前,5已经被添加到x(x的值 * 确实 * 改变了)。逗号操作符的主要合理用法是在您的问题中显示的。在更复杂的
for
循环中,它可以方便地使用e。例如多种副作用和有保证的顺序。为了澄清为什么测序 * 可能 * 重要(它不在你的例子中,因为副作用并不依赖于彼此),看看这个(人工的)例子:
如果逗号操作符没有在这里引入序列点,您将不知道
j+=i
是否会添加递增的i
或未递增的i
。31moq8wy3#
对于多次初始化和多次更新/增量,我们使用
comma operator(,)
。我们用comma(,)
分隔每个示例。在这种情况下,当进入for循环时,执行初始化部分中的
argc--
和argv++
表达式。从那时起,每次循环迭代时,增量部分中的argc--
和argv++
表达式都会执行。fykwrbwg4#
在这个
for
循环中,comma operator用于第一个和最后一个表达式。所以for
语句如下只有三个表达式
(argc--, argv++)
、argc > 0
和(argc--, argv++)
。表达式1不一定是声明语句,它可以是任何有效的表达式,甚至可以省略
或者可以省略所有表达式
在给定的for循环中,
(argc--, argv++)
被用作第一个表达式来更新变量argc
和argv
(argc
将递减1,指针argv
将递增1)。一旦对这些变量的副作用完成,程序将在检查argc > 0
是否为true
后进入循环体。你这么做的后果就是这样i = 1
将i
更新为1
,然后检查条件。对i
的更新只进行一次,其余的则通过表达式i++
进行更新。ryhaxcpt5#
执行以下操作:
1.执行“* 初始化 ”部分:减少
argc
并增加argv
1.检查
argv > 0
,如果不是,则退出循环1.执行
{ ... }
1.执行“Updation”部分:减少
argc
并增加argv
1.后藤步骤2。以上
由于“ Initialization *”和“Updation”相同,因此也可以写为
此表达式
由三个子表达式组成,由逗号操作符分隔。
这些子表达式从左到右执行。
整个表达式的计算结果为最右侧子表达式的结果。
amrnrhlw6#
argv拥有命令行参数。第一个问题是程序的名称。
因此,循环从
argv[1]
开始,处理命令行给出的每个参数,而不处理程序名xtfmy6hx7#
可以读作
由于逗号运算符的优先级可能最低,所以左手运算符总是先计算
nbnkbykc8#
for循环中的初始化参数并不意味着只初始化具有特定值的变量。
它还可以有一个或多个正则表达式,由逗号分隔。
希望能有帮助!!
ig9co6j19#
for ( argc--, argv++; argc > 0; argc--, argv++ )
表示循环开始时,argc
、argv
的值分别设置为它们初始值的负1和正1。每次迭代都会减少和增加它们的值,一旦argc
达到0(意味着所有输入参数都被读取),迭代就会停止。