Каков наилучший способ сделать обратный цикл " for " с беззнаковым индексом?
моя первая попытка обратный цикл что делает что-то n раз было что-то вроде:
for ( unsigned int i = n-1; i >= 0; i-- ) {
...
}
этой не потому что арифметика без знакаi
гарантированно всегда больше или равно нулю, поэтому условие цикла всегда будет истинным. К счастью, компилятор gcc предупредил меня о "бессмысленном сравнении", прежде чем мне пришлось задаться вопросом, почему цикл выполняется бесконечно.
Я ищу элегантный способ решения этой проблемы, имея в виду, что:
- это должен быть обратный цикл.
- индекс цикла должен быть без знака.
- N-константа без знака.
- он не должен основываться на "неясной" кольцевой арифметике беззнаковых целых чисел.
какие идеи? Спасибо :)
20 ответов:
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; ... }
for ( unsigned int i = n; i != 0; i-- ) { // do something with i - 1 ... }
обратите внимание, что если вы используете C++, а также C, используя != это хорошая привычка, чтобы попасть в, когда вы переключиться на использование итераторов, где
Я бы использовал
for ( unsigned int i = n; i > 0; ) { --i; ... }
это почти то же самое, что и ответ skizz (он пропускает окончательное ненужное уменьшение, но компилятор должен оптимизировать это), и фактически пройдет проверку кода. Каждый стандарт кодирования, с которым мне приходилось работать, не имел мутации в условном правиле.
почему не просто:
unsigned int i = n; while(i--) { // use i }
Это соответствует всем требованиям, перечисленным в теле вопроса. Он не использует ничего, что может привести к сбою проверки кода или нарушению стандарта кодирования. Единственное возражение, которое я мог бы увидеть, - это если ОП действительно настаивал на
for
цикл и не простой способ генерации i = (n-1) .. 0.
может, так? ИМХО его ясно и читабельно. Вы можете опустить 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 );
или вы можете положиться на поведение обертывания
unsigned int
Если вам нужна индексация от N-1 до 0for(unsigned int i = n-1; i < n; i--) { ... }
for ( unsigned int i = n; i > 0; i-- ) { unsigned int x = i - 1; // do whatever you want with x }
конечно не элегантно, но это работает.
единственная причина, по которой я упоминаю этот параметр, заключается в том, что я не видел его в списке.
for ( unsigned int i = n-1; i < n; i-- ) { ... }
категорически против интуиции, но это работает. причина это работает, потому что вычитая 1 из 0 дает наибольшее число, которое может быть представлено целым числом без знака.
вообще я не думаю, что это хорошая идея, чтобы работать с целыми числами без знака и артметики, особенно при вычитании.
легко, просто остановитесь на -1:
for( unsigned int i = n; i != -1; --i ) { /* do stuff with i */ }
edit: не уверен, почему это становится downvoted. это работает, и это проще и очевиднее, чем любой из вышеперечисленных.
for ( unsigned int i = n; i > 0; i-- ) { ... }
должно работать нормально. Если вам нужно использовать
i
переменная как индекс в массиве сделать это так:array[i-1];
тю. Вот ваши варианты:
- использовать
i=0
поскольку ваше условие разрыва - цикл не будет выполняться, когда я достигну 0, поэтому выполните 1 итерацию содержимого цикла дляi=0
после того, как был произведен выход из цикла.for ( unsigned int i = n-1; i > 0; i-- ) { doStuff(i); } doStuff(0);
- в цикле, тест на
i=0
иbreak
выход. Не рекомендуется, потому что теперь вы проверяете значение i дважды в цикле. Также использование разрыва в цикле обычно считается плохим практиковать.for ( unsigned int i = n-1; i >= 0; i-- ) { doStuff(i); if (i=0) break; }
unsigned index; for (unsigned i=0; i<n; i++) { index = n-1 - i; // {i == 0..n-1} => {index == n-1..0} }
Это непроверенно, но не могли бы вы сделать следующее:
for (unsigned int i, j = 0; j < n; i = (n - ++j)) { /* do stuff with i */ }
используйте две переменные, одну для подсчета до, а другой для индекса массива:
unsigned int Index = MAX - 1; unsigned int Counter; for(Counter = 0; Counter < MAX; Counter++) { // Use Index Index--; }
поскольку это не стандарт для цикла, я бы, вероятно, использовал цикл while вместо этого, например:
unsigned int i = n - 1; while (1) { /* do stuff with i */ if (i == 0) { break; } i--; }