Подтвердить что ты не робот

Какой лучший способ сделать обратный цикл "for" с индексом без знака?

Моя первая попытка reverse для цикла, которая делает что-то n раз, была чем-то вроде:

for ( unsigned int i = n-1; i >= 0; i-- ) {
    ...     
}

Этот терпит неудачу, потому что в беззнаковой арифметике i гарантировано всегда больше или равно нулю, поэтому условие цикла всегда будет истинным. К счастью, gcc-компилятор предупредил меня о "бессмысленном сравнении", прежде чем мне пришлось задаться вопросом, почему цикл выполнялся бесконечно.


Я ищу элегантный способ решения этой проблемы, имея в виду, что:

  • Он должен быть обратным циклом.
  • Индекс цикла должен быть без знака.
  • n - неизменная константа.
  • Он не должен основываться на "неясной" кольцевой арифметике целых чисел без знака.

Любые идеи? Спасибо:)

4b9b3361

Ответ 1

Как насчет:

for (unsigned i = n ; i-- > 0 ; )
{
  // do stuff with i
}

Ответ 2

for ( unsigned int loopIndex = n; loopIndex > 0; --loopIndex ) {
    unsigned int i = loopIndex - 1;
    ...
} 

или

for ( unsigned int loopIndex = 0; loopIndex < n; ++loopIndex ) {
    unsigned int i = n - loopIndex - 1;
    ...
} 

Ответ 3

for ( unsigned int i = n; i != 0; i-- ) {
    // do something with i - 1
    ...     
}

Обратите внимание, что если вы используете С++, а также C, использование!= является хорошей привычкой, когда вы переключаетесь на использование итераторов, где <= и т.д. могут быть недоступны.

Ответ 4

for ( unsigned int i = n; i > 0; i-- ) {
    ...  
    i-1 //wherever you've been using i   
}

Ответ 5

Я бы использовал

 for ( unsigned int i = n; i > 0; )  {
    --i;
    ...     
 }

он почти такой же, как ответ skizz ', (он пропускает окончательный ненужный декремент, но компилятор должен его оптимизировать), и на самом деле пройдет обзор кода. Каждый стандарт кодирования, с которым мне приходилось работать, не имел мутации в условном правиле.

Ответ 6

Почему бы просто:

unsigned int i = n;
while(i--)
{ 
    // use i
}

Это отвечает всем требованиям, перечисленным в теле вопроса. Он не использует ничего, что может привести к сбою проверки кода или нарушению стандарта кодирования. Единственное возражение, которое я мог видеть, это то, что OP действительно настаивал на цикле for, а не на простом способе генерации я = (n-1).. 0.

Ответ 7

Может, так? ИМХО его понятно и понятно. Вы можете опустить if (n >= 1), если он неявно известен как-то.

if(n>=1) {
    // Start the loop at last index
    unsigned int i = n-1;
    do {
       // a plus: you can use i, not i-1 here
    } while( i-- != 0 );
}

Другая версия:

if(n>=1) {
    unsigned int i = n;
    do {
       i--;

    } while( i != 0 );
}

Первый код без оператора if будет выглядеть следующим образом:

unsigned int i = n-1;
do {

} while( i-- != 0 );

Ответ 8

Или вы можете положиться на поведение оболочки unsigned int, если вам нужно индексировать от n-1 до 0

for(unsigned int i = n-1; i < n; i--) {
    ...
}

Ответ 9

for ( unsigned int i = n; i > 0; i-- ) {
    unsigned int x = i - 1;
    // do whatever you want with x    
}

Конечно, не элегантный, но он работает.

Ответ 10

for (unsigned int i = n-1; i<(unsigned int)-1; i--)

ОК, его "нечеткая кольцевая арифметика".

Ответ 11

Единственная причина, по которой я упоминаю этот вариант, состоит в том, что я не видел его в списке.

for ( unsigned int i = n-1; i < n; i-- ) {
... 
}

Полностью против интуиции, но он работает. причина, по которой она работает, состоит в том, что вычитание 1 из 0 дает наибольшее число, которое может быть представлено целым числом без знака.

В общем, я не думаю, что это хорошая идея для работы с целыми целыми числами без подзарядки, а также при вычитании.

Ответ 12

Просто, просто остановитесь на -1:

for( unsigned int i = n; i != -1; --i )
{
 /* do stuff with i */
}

edit: не знаю, почему это происходит. он работает, и это проще и очевиднее любого из вышеперечисленных.

Ответ 13

for ( unsigned int i = n; i > 0; i-- ) {
    ...     
}

Должно работать нормально. Если вам нужно использовать переменную i в качестве индекса в массиве, сделайте следующее:

array[i-1];

Ответ 14

Hm. Вот ваши варианты:

  • Используйте i=0 как условие прерывания. Петля не будет выполняться, когда я достигнет 0, поэтому выполните 1-ю итерацию содержимого цикла для i=0 после выхода цикла.
for ( unsigned int i = n-1; i > 0; i-- ) {
    doStuff(i);
}
doStuff(0);
  1. В цикле проверьте i=0 и break. Не рекомендуется, потому что теперь вы проверяете значение я дважды в цикле. Также использование перерыва в цикле обычно рассматривается как плохая практика.
for ( unsigned int i = n-1; i >= 0; i-- ) {
    doStuff(i);
    if (i=0) break;
}

Ответ 15

unsigned index;
for (unsigned i=0; i<n; i++)
{
    index = n-1 - i; // {i == 0..n-1} => {index == n-1..0}
}

Ответ 16

Так как это не стандарт для цикла, я, скорее всего, использовал бы цикл while, например:

unsigned int i = n - 1;
while (1)
{
    /* do stuff  with i */

     if (i == 0)
    {
        break;
    }
    i--;
}

Ответ 17

Это не проверено, но вы можете сделать следующее:

for (unsigned int i, j = 0; j < n; i = (n - ++j)) {
    /* do stuff with i */
}

Ответ 18

Используйте две переменные: одну для подсчета, а другую для индекса массива:

unsigned int Index = MAX - 1;
unsigned int Counter;
for(Counter = 0; Counter < MAX; Counter++)
{
    // Use Index
    Index--;
}

Ответ 19

for ( unsigned int i = n-1; (n-i) >= 0; i-- ) {
    // n-i will be negative when the loop should stop.
    ...     
}

Ответ 20

e.z:

#define unsigned signed

for ( unsigned int i = n-1; i >= 0; i-- ) { ... 
}