我有以下代码片段:
int main(int argc, char *argv[])
{
char line[MAXLINE];
long lineno = 0;
int c, except = 0, number = 0, found = 0;
while(--argc > 0 && (*++argv)[0] == '-') //These two lines
while(c = *++argv[0]) //These two lines
switch(c) {
case 'x':
except = 1;
break;
case 'n':
number = 1;
break;
default:
printf("find: illegal option %c\n", c);
argc = 0;
found = -1;
break;
}
...
}
包含以下表达式:
while(--argc > 0 && (*++argv)[0] == '-')
括号(*++argv)[0]
中的此表达式是否与while(c = *++argv[0])
的括号不同?
如果是这样,怎么样? (*++argv)
是指向下一个参数的指针,*++argv[0]
是否指向指向当前char数组中下一个字符的指针?
答案 0 :(得分:40)
首先,K& R在这个特定的片段上有一个勘误表:
117(§5.10):在 find 示例中,程序递增
argv[0]
。这不是特别禁止的,但也没有特别允许。
现在进行解释。
假设您的程序名为prog
,您可以使用:prog -ab -c Hello World
执行该程序。您希望能够解析参数以指出已指定选项a
,b
和c
,并且Hello
和World
是非选项参数。
argv
的类型为char **
- 请记住,函数中的数组参数与指针相同。在程序调用时,事情看起来像这样:
+---+ +---+---+---+---+---+
argv ---------->| 0 |-------->| p | r | o | g | 0 |
+---+ +---+---+---+---+---+
| 1 |-------->| - | a | b | 0 |
+---+ +---+---+---+---+
| 2 |-------->| - | c | 0 |
+---+ +---+---+---+---+---+---+
| 3 |-------->| H | e | l | l | o | 0 |
+---+ +---+---+---+---+---+---+
| 4 |-------->| W | o | r | l | d | 0 |
+---+ +---+---+---+---+---+---+
| 5 |-------->NULL
+---+
此处argc
为5,argv[argc]
为NULL
。最初,argv[0]
是char *
,其中包含字符串"prog"
。
在(*++argv)[0]
中,由于括号,argv
首先递增,然后取消引用。增量的作用是将argv ---------->
箭头“向下移动一个块”,指向1
。解除引用的效果是获取指向第一个命令行参数-ab
的指针。最后,我们获取此字符串中的第一个字符([0]
中的(*++argv)[0]
),并测试它是否为'-'
,因为它表示选项的开头。
对于第二个构造,我们实际上想要沿着当前argv[0]
指针所指向的字符串向下走。所以,我们需要将argv[0]
视为指针,忽略它的第一个字符(就像我们刚刚测试的那样'-'
),并查看其他字符:
++(argv[0])
将递增argv[0]
,以获取指向第一个非-
字符的指针,并且取消引用它将为我们提供该字符的值。所以我们得到*++(argv[0])
。但是因为在C中,[]
比++
绑定得更紧,我们实际上可以摆脱括号并将表达式设为*++argv[0]
。我们希望继续处理此字符,直到它为0
(上图中每行中的最后一个字符框)。
表达式
c = *++argv[0]
为c
分配当前选项的值,的值为c
。 while(c)
是while(c != 0)
的简写,因此while(c = *++argv[0])
行基本上将当前选项的值分配给c
并对其进行测试以查看我们是否已达到当前的命令行参数。
在此循环结束时,argv将指向第一个非选项参数:
+---+ +---+---+---+---+---+
| 0 |-------->| p | r | o | g | 0 |
+---+ +---+---+---+---+---+
| 1 |-------->| - | a | b | 0 |
+---+ +---+---+---+---+
| 2 |-------->| - | c | 0 |
+---+ +---+---+---+---+---+---+
argv ---------->| 3 |-------->| H | e | l | l | o | 0 |
+---+ +---+---+---+---+---+---+
| 4 |-------->| W | o | r | l | d | 0 |
+---+ +---+---+---+---+---+---+
| 5 |-------->NULL
+---+
这有帮助吗?
答案 1 :(得分:5)
while(--argc > 0 && (*++argv)[0] == '-')
逐个扫描命令行参数的数组(长度为argc),查找以-
选项前缀开头的数组。对于每一个:
while(c = *++argv[0])
正在浏览当前参数中的第一个-
后面的一组切换字符(即t
中的n
和-tn
,直到它到达字符串null终结符\0
,它终止while循环,因为它的计算结果为false。
这种设计允许两者
myApp -t -n
和
myApp -tn
同时工作并被理解为具有选项t
和n
。
答案 2 :(得分:5)
增加argv是一个非常糟糕的主意,因为一旦你这样做,很难恢复原始值。使用整数索引更简单,更清晰,更好 - 毕竟argv是一个数组!
要回答你的问题,++ argv会增加指针。然后将其应用于间接以获取第一个字符。
答案 3 :(得分:4)
括号会更改表达式的计算顺序。
没有括号*++argv[0]
:
argv[0]
获取指向argv
当前指向的字符数据的指针。++
将该指针递增到字符数组中的下一个字符。*
获得角色。括号(*++argv)[0]
:
++argv
将argv指针递增为指向下一个参数。*
表示它获取指向字符数据的指针。[0]
获取字符数组中的第一个字符。答案 4 :(得分:2)
是的,这两个表达式有所不同(尽管只是略有不同)。 IMO,这段代码有点过于聪明。你最好用这样的东西:
for (int i=1; i<argc; i++)
if (argv[i][0] == '-') {
size_t len = strlen(argv[i]);
for (int j=0; j<len; ++j)
switch(argv[i][j]) {
case 'x':
// ...
这几乎与上面的代码相同,但是我怀疑任何人(根本不知道C)会弄清楚它究竟是做什么的。