Как работают запятые в инициализации и приращения частей цикла for-loop?
Я столкнулся с циклом for-loop, который выглядит следующим образом:
for ( argc--, argv++; argc > 0; argc--, argv++ )
Как это работает? Обычно цикл for
выглядит следующим образом:
for (initialization; condition; increment) {/*body of the loop*/}
Но это не содержит никаких запятых - что означают запятые и делают?
Ответы
Ответ 1
В стандарте C (6.8.5.3 Оператор for) оператор for представлен в следующем виде
for ( clause-1 ; expression-2 ; expression-3 ) statement
и в соответствии с пунктом-1 написано
Если предложение-1 является выражением, оно оценивается как выражение void перед первой оценкой управляющего выражения
В этом для оператора
for ( argc--, argv++; argc > 0; argc--, argv++ )
clause-1 - выражение argc--, argv++
на основе оператора запятой.
Из C-стандарта (6.5.17 Comma-оператора)
2 Левый операнд оператора запятой оценивается как пустота выражение; между его оценкой и точкой правого операнда. Затем оценивается правый операнд; результат имеет свой тип и значение.
Единственная особенность заключается в том, что результат оператора не используется в инструкции for. Выражение используется для его побочных эффектов.
Обычно первым параметром, переданным запущенной программе, является его имя. Выражение в разделе-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
и выход программы этой программы, когда предложение-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
Чтобы сделать оператор запятой понятным, рассмотрим программу как первую демонстрационную программу, где вместо цикла for используется цикл while.
#include <stdio.h>
int main( int argc, char * argv[] )
{
while ( argv++, --argc > 0 )
{
puts( *argv );
}
return 0;
}
Результат будет таким же, как в первой демонстрационной программе
first
second
third
Здесь в инструкции while используется также оператор запятой. Разница в том, что в этом случае значение оператора запятой используется как значение условия.
Обратите внимание на то, что выражение-3 также представляет собой выражение с оператором запятой.
Также, когда вопрос помечен тегом С++, вы должны знать, что в С++ второе предложение оператора for (в С++ оно называется условием) также может быть выражением или декларацией.
Ответ 2
Как уже было сказано в ответах many, это оператор запятой, поэтому
argc--, argv++
- это выражение one.
Оператор запятой оценивает обе стороны, сначала левую, затем правую. В результате получается правая сторона. Таким образом, вы могли бы написать некоторые странные вещи, такие как
int a = (x += 5, x + 2);
это добавит 5 к x, прежде чем назначить результат x + 2
на a
. Такой код запутан, и его следует избегать. Но это демонстрирует важное свойство оператора запятой:
Он действует как точка последовательности. С приведенным выше кодом у вас есть гарантия того, что 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
оператор запятой используется в первом и последнем выражениях. Таким образом, оператор 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(;;)
В данном цикле (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++ )
{ ... }
Выполняется ли следующее:
- Выполнить "Инициализация": Decrement
argc
и increment argv
- Проверьте, если
argv > 0
, если это не так, то выйдите из цикла
- Выполнить
{ ... }
- Выполнение части "Обновление": Уменьшение
argc
и приращение argv
- Перейдите к шагу 2. выше
Поскольку "Инициализация" и "Обновление" одинаковы, это также можно записать как
while (argc--, argv++, argc > 0)
{ ... }
Это выражение
(argc--, argv++, argc > 0)
состоит из трех подвыражений, разделенных запятой.
Эти подвыражения выполняются слева направо.
Все выражение оценивается как результат самого субэкпозиции справа.
Ответ 6
argv владеет аргументами командной строки. Однако самое первое - это название программы.
Итак, цикл начинается с argv[1]
и обрабатывает все аргументы, заданные командной строкой, без обработки имени программы
Ответ 7
for ( argc--, argv++; argc > 0; argc--, argv++ )
означает, что цикл начинается со значений argc
, argv
, установленных соответственно минус 1 и плюс 1 их начальных значений. Каждая итерация будет уменьшаться и увеличивать их значения, и она остановится, как только argc
достигнет 0 (что означает, что все входные аргументы были прочитаны).
Ответ 8
for ( argc--, argv++; argc > 0; argc--, argv++ )
можно читать как
for ( (argc--), argv++; argc > 0; (argc--), argv++ )
поскольку оператор с запятой имеет наименьший возможный приоритет, левый оператор всегда будет оцениваться первым
Ответ 9
Параметр инициализации в цикле for не означает только инициализацию переменной с определенным значением.
Он также может иметь одно или несколько регулярных выражений, разделенных запятой.
Надеюсь, это поможет!