it-roy-ru.com

Как работают запятые в частях инициализации и приращения цикла for?

Я наткнулся на цикл for в коде, который выглядит так:

for ( argc--, argv++; argc > 0; argc--, argv++ )

Как это работает? Обычно цикл for выглядит так: 

for (initialization; condition; increment) {/*body of the loop*/}

Но это не содержит запятых - что запятые означают и делают?

12
user3552519

В Стандарте C (6.8.5.3 Формулировка for) Формулировка for представлена ​​в следующей форме

for ( clause-1 ; expression-2 ; expression-3 ) statement

и согласно пункт-1 там написано

Если условие-1 является выражением, оно оценивается как пустое выражение до первой оценки контрольного выражения

В этом для заявления

for ( argc--, argv++; argc > 0; argc--, argv++ )  

условие-1 - это выражение argc--, argv++, основанное на операторе запятой . из стандарта C (6.5.17 оператор запятой)

2 Левый операнд оператора запятой оценивается как void выражение; между его оценкой и этим есть точка последовательности правого операнда. Затем вычисляется правый операнд; результат имеет свой тип и значение.

Единственная особенность в том, что результат оператора не используется в операторе 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;
}

является

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 также используется оператор запятой. Разница в том, что в этом случае значение оператора запятой используется в качестве значения условия.

Обратите внимание на то, что expression-3 также представляет собой выражение с оператором запятой.

Также, поскольку вопрос помечен тегом C++, вы должны знать, что в C++ второе предложение оператора for (в C++ оно называется условие ) также может быть выражением или объявлением.

27
Vlad from Moscow

Как уже говорилось в много ответов, это оператор запятая, поэтому

argc--, argv++

это только один выражение.

Оператор запятой оценивает обе стороны, сначала слева, а затем справа. Результат - с правой стороны. Таким образом, вы могли бы написать несколько странных вещей, таких как

int a = (x += 5, x + 2);

это добавило бы 5 к x перед тем, как присваивать результат x + 2a. Такой код сбивает с толку и его следует избегать. Но он демонстрирует важное свойство оператора comma:

Он действует как точка последовательности : С помощью приведенного выше кода у вас есть гарантия того, что 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 или не увеличенную.

8
user2371524

Для многократной инициализации и множественного обновления/инкремента мы используем comma operator(,). Мы разделяем каждый экземпляр с comma(,).
В этом случае при вводе цикла for выражения argc-- и argv++ в части инициализации выполняются . С этого момента каждый раз, когда цикл повторяется, выражения argc-- и argv++ в инкрементной части имеют вид казнены. 

4
Praveen Kumar

В этом for loop оператор запятой используется в первом и последнем выражениях. Таким образом, оператор 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(;;)  

В заданном цикле for (argc--, argv++) используется в качестве первого выражения для обновления переменных argc и argv (argc будет уменьшен на 1, а указатель argv будет увеличен на 1). Как только побочный эффект этих переменных завершен, программа войдет в тело цикла после проверки argc > 0 для true. Это то, что происходит, когда вы делаете 

for( i = 1; i < 10; i++)

i = 1 обновите i до 1 и затем условие проверяется. Это обновление i выполняется только один раз, а для остальных оно обновляется выражением i++

3
haccks
for ( argc--, argv++; argc > 0; argc--, argv++ )  
{ ... }

Делает следующее:

  1. Выполните часть "Initialisation": Уменьшение argc и увеличение argv
  2. Проверьте, если argv > 0, если это не так, выйдите из цикла
  3. Выполнить { ... }
  4. Выполните часть "Updation": Уменьшение argc и увеличение argv
  5. Перейти к шагу 2. выше

Поскольку "Initialisation" и "Updation" одинаковы, это также можно записать как

while (argc--, argv++, argc > 0)
{ ... }

Это выражение

(argc--, argv++, argc > 0)

состоит из трех подвыражений, разделенных оператором запятой .

Эти подвыражения выполняются слева направо. 

Целое выражение оценивается как результат самого правого подвыражения.

1
alk

for ( argc--, argv++; argc > 0; argc--, argv++ ) означает, что цикл начинается со значений argc, argv, установленных на минус 1 и плюс 1 их начальных значений соответственно. Каждая итерация будет уменьшаться и увеличивать свои значения, и она остановится, когда argc достигнет 0 (что означает, что все входные аргументы были прочитаны).

0
proton

Параметр инициализации в цикле for не означает только инициализацию переменной с определенным значением.

Он также может иметь одно или несколько регулярных выражений, разделенных запятой.

Надеюсь, это поможет!

0
amol13
for ( argc--, argv++; argc > 0; argc--, argv++ )

можно прочитать как 

for ( (argc--), argv++; argc > 0; (argc--), argv++ )

так как оператор запятой имеет наименьший возможный приоритет, левый оператор всегда будет оцениваться первым

0
Thomas.L

argv владеет аргументами командной строки. Однако самое первое - это название программы.

Итак, цикл начинается с argv[1] и обрабатывает все аргументы, заданные командной строкой, без обработки имени программы. 

0
Antoine Morrier