Разница между (*++argv) [0] и while (c = *++argv[0])
у меня есть следующий фрагмент кода:
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 %cn", c);
argc = 0;
found = -1;
break;
}
...
}
, содержащие следующие выражения:
while(--argc > 0 && (*++argv)[0] == '-')
делает ли это выражение в скобках (*++argv)[0]
отличается от while(c = *++argv[0])
без скобок?
если да, то как? Делает (*++argv)
означает указатель на следующий аргумент, а не *++argv[0]
средний указатель на следующий символ в текущем массиве символов, на который указывается?
5 ответов
во-первых, у K&R есть ошибки на этом конкретном фрагменте:
117(§5.10): в найти пример, программа увеличивает
argv[0]
. Это не запрещено, но и не разрешено.
теперь для объяснения.
Допустим, ваша программа называется prog
, и вы выполняете его с:prog -ab -c Hello World
. Вы хотите иметь возможность анализировать аргументы, чтобы сказать, что options a
, b
и c
были указаны и Hello
и World
являются аргументами non-option.
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]
is NULL
. В начале, argv[0]
- это char *
содержит строку "prog"
.
на (*++argv)[0]
из-за скобки, argv
сначала увеличивается, и затем разыграли. Эффект приращения состоит в том, чтобы переместить это argv ---------->
стрелка "один блок вниз", чтобы указать на 1
. Эффект разыменования заключается в том, чтобы получить указатель на первый аргумент командной строки,-ab
. Наконец, возьмем первый символ ([0]
на (*++argv)[0]
) этой строки и проверьте ее, чтобы узнать, является ли она '-'
, потому что это означает начало вариант.
для второй конструкции мы действительно хотим спуститься по строке, на которую указывает текущий
Incrementing argv-очень плохая идея, так как после этого вам трудно вернуть исходное значение. Проще, понятнее и лучше использовать целочисленный индекс - ведь argv-это массив!
чтобы ответить на ваш вопрос ++argv увеличивает указатель. Затем к нему применяется косвенность, чтобы получить первый символ.
да, вы правы.
while(--argc > 0 && (*++argv)[0] == '-')
сканирует массив (длины argc) аргументов командной строки один за другим, ища те, которые начинаются с -
префикс вариант. Для каждого из них:
while(c = *++argv[0])
просматривает набор символов переключателя, которые следуют за первым -
в текущем аргументе (т. е. t
и n
на -tn
, пока он не попадет в строку null terminator , который завершает цикл while, так как он оценивает как ложный.
эта конструкция позволяет как
myApp -t -n
и
myApp -tn
как работать, так и пониматься как имеющие параметры t
и n
.
скобки изменяют порядок вычисления выражений.
без скобок *++argv[0]
:
-
argv[0]
получает указатель на символьные данные, на которые в настоящее время указываетargv
. -
++
увеличивает указатель на следующий символ в массиве символов. -
*
возвращает символ.
в скобки (*++argv)[0]
:
-
++argv
увеличивает argv указатель на следующий аргумент. -
*
переносит его, чтобы получить указатель на символьные данные. -
[0]
получает первый символ в символьном массиве.
да, два выражения различаются (хотя и незначительно). ИМО, этот код немного на чрезмерно умной стороне. Тебе бы лучше сделать что-нибудь вроде этого:--2-->
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) будет иметь какие-либо трудности с выяснением того, что он действительно делает.