Разница между (*++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) будет иметь какие-либо трудности с выяснением того, что он действительно делает.