Как поместить два оператора приращения в цикл C ++ для for?

StackOverflow https://stackoverflow.com/questions/1232176

  •  22-07-2019
  •  | 
  •  

Вопрос

Я хотел бы увеличить две переменные в условии for -loop вместо одной.

Так что-то вроде:

for (int i = 0; i != 5; ++i and ++j) 
    do_something(i, j);

Какой синтаксис для этого?

Это было полезно?

Решение

Распространенная идиома - использование оператора запятой , который оценивает оба операнда и возвращает второй операнд. Таким образом:

for(int i = 0; i != 5; ++i,++j) 
    do_something(i,j);

Но действительно ли это оператор запятой?

Теперь, написав это, комментатор предположил, что это действительно какой-то особый синтаксический сахар в операторе for, а не оператор запятой вообще. Я проверил это в GCC следующим образом:

int i=0;
int a=5;
int x=0;

for(i; i<5; x=i++,a++){
    printf("i=%d a=%d x=%d\n",i,a,x);
}

Я ожидал, что x выберет исходное значение a, поэтому он должен был отображать 5,6,7 .. для x. Я получил это

i=0 a=5 x=0
i=1 a=6 x=0
i=2 a=7 x=1
i=3 a=8 x=2
i=4 a=9 x=3

Однако, если я заключил в скобки выражение, чтобы заставить парсер действительно увидеть оператор запятой, я получу это

int main(){
    int i=0;
    int a=5;
    int x=0;

    for(i=0; i<5; x=(i++,a++)){
        printf("i=%d a=%d x=%d\n",i,a,x);
    }
}

i=0 a=5 x=0
i=1 a=6 x=5
i=2 a=7 x=6
i=3 a=8 x=7
i=4 a=9 x=8

Сначала я думал, что это показывает, что он вообще не работает как оператор запятой, но, как оказалось, это просто проблема приоритета - у оператора запятой есть минимально возможный приоритет , поэтому выражение x = i ++, a ++ эффективно анализируется как (x = i ++), a ++

Спасибо за все комментарии, это был интересный опыт обучения, и я использую C уже много лет!

Другие советы

Попробуйте это

for(int i = 0; i != 5; ++i, ++j)
    do_something(i,j);

Постарайся не делать этого!

От http://www.research.att.com/~bs/JSF-AV-rules.pdf :

  

AV Rule 199
  Выражение приращения в цикле for не будет выполнять никаких действий, кроме изменения одного   параметр цикла до следующего значения для цикла.      

Обоснование: удобочитаемость.

for (int i = 0; i != 5; ++i, ++j) 
    do_something(i, j);

Я пришел сюда, чтобы напомнить себе, как кодировать второй индекс в предложении приращения цикла FOR, что, как я знал, можно сделать главным образом из наблюдения за ним в образце, который я включил в другой проект, написанный на C ++.

Сегодня я работаю в C #, но я был уверен, что он будет подчиняться тем же правилам в этом отношении, поскольку оператор FOR является одной из самых старых управляющих структур во всем программировании. К счастью, недавно я потратил несколько дней на точное документирование поведения цикла FOR в одной из моих старых программ на C, и я быстро понял, что в этих исследованиях были извлечены уроки, относящиеся к сегодняшней проблеме C #, в частности к поведению второй индексной переменной. .

Для неосторожных ниже приводится краткое изложение моих наблюдений. Все, что я видел сегодня, внимательно наблюдая за переменными в окне Locals, подтвердило мои ожидания, что оператор C # FOR ведет себя точно так же, как оператор C или C ++ FOR.

<Ол>
  • При первом выполнении цикла FOR предложение приращения (третье из трех) пропускается. В Visual C и C ++ приращение генерируется в виде трех машинных инструкций в середине блока, который реализует цикл, так что начальный этап запускает код инициализации только один раз, а затем перепрыгивает через блок приращения, чтобы выполнить тест завершения. Это реализует функцию, что цикл FOR выполняется ноль или более раз, в зависимости от состояния его индекса и предельных переменных.
  • Если тело цикла выполняется, его последний оператор является переходом к первой из трех инструкций приращения, которые были пропущены при первой итерации. После их выполнения управление естественным образом попадает в код проверки предела, который реализует предложение middle. Результат этого теста определяет, выполняется ли тело цикла FOR или управление переходит к следующей инструкции после перехода в нижней части его области.
  • Поскольку управление переходит из нижней части блока цикла FOR в блок приращения, индексная переменная увеличивается до выполнения теста. Это поведение не только объясняет, почему вы должны кодировать предельные предложения, как вы узнали, но и влияет на любое добавляемое вами дополнительное приращение через оператор запятой, поскольку оно становится частью третьего предложения. Следовательно, он не изменяется на первой итерации, но на последней итерации, которая никогда не выполняет тело.
  • Если одна из ваших индексных переменных останется в области видимости после окончания цикла, их значение будет на единицу выше порогового значения, которое останавливает цикл, в случае истинной индексной переменной. Аналогично, если, например, вторая переменная инициализируется в ноль до ввода цикла, ее значением в конце будет счетчик итераций, при условии, что это приращение (++), а не уменьшение, и что ничего в тело цикла меняет свое значение.

    Я согласен с squelart. Увеличение двух переменных подвержено ошибкам, особенно если вы тестируете только одну из них.

    Это читабельный способ сделать это:

    for(int i = 0; i < 5; ++i) {
        ++j;
        do_something(i, j);
    }
    
    Циклы

    For предназначены для случаев, когда ваш цикл выполняется на одной возрастающей / убывающей переменной. Для любой другой переменной измените ее в цикле.

    Если вам нужно привязать j к i , почему бы не оставить исходную переменную как есть и добавить i ?

    for(int i = 0; i < 5; ++i) {
        do_something(i,a+i);
    }
    

    Если ваша логика более сложная (например, вам нужно фактически отслеживать более одной переменной), я бы использовал цикл while .

    int main(){
        int i=0;
        int a=0;
        for(i;i<5;i++,a++){
            printf("%d %d\n",a,i);
        } 
    }
    

    Используйте математику. Если две операции математически зависят от итерации цикла, почему бы не выполнить математические вычисления?

    int i, j;//That have some meaningful values in them?
    for( int counter = 0; counter < count_max; ++counter )
        do_something (counter+i, counter+j);
    

    Или, более конкретно, ссылаясь на пример OP:

    for(int i = 0; i != 5; ++i)
        do_something(i, j+i);
    

    Особенно, если вы переходите в функцию по значению, тогда вы должны получить что-то, что делает именно то, что вы хотите.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top