2012-01-28 3 views
8

Я провел некоторое исследование Stackoverflow об обратном для циклов на C++, которые используют целое число без знака вместо подписанного. Но я до сих пор НЕ понимаю, почему возникает проблема (см. Unsigned int reverse iteration with for loops). Почему следующий код даст ошибку сегментации?Целые числа без знака в C++ для циклов

#include <vector> 
#include <iostream> 
using namespace std; 

int main(void) 
{ 
    vector<double> x(10); 

    for (unsigned int i = 9; i >= 0; i--) 
    { 
     cout << "i= " << i << endl; 
     x[i] = 1.0; 
    } 

    cout << "x0= " << x[0] << endl; 

    return 0; 
} 

Я понимаю, что проблема в том, что индекс i будет равен нулю, потому что есть что-то вроде переполнения. Но я думаю, что целое число без знака разрешено принимать нулевое значение, не так ли? Теперь, если я заменил его на целое число со знаком, нет абсолютно никакой проблемы.

Может ли кто-нибудь объяснить мне механизм за этим обратным циклом с целым числом без знака?

спасибо!

+3

'i> = 0' всегда верно для unsigned' i', поэтому цикл никогда не заканчивается. – TonyK

+0

Прочтите предупреждения компилятора, они полезны. В этом случае ваш компилятор должен, вероятно, предупредить вас о том, что условие в вашем цикле всегда истинно. – dragonroot

+0

@dragonroot: К сожалению, нет. Я использую флаг -Wall g ++. Знаете ли вы флаг компилятора, который обнаружит эту проблему? Благодарю. – Benjamin

ответ

24

Проблема здесь в том, что целое число без знака никогда не является отрицательным.

Таким образом, цикл испытаний:

i >= 0 

всегда будет истинным. Таким образом, вы получаете бесконечный цикл.

Когда он опускается ниже нуля, он обертывается до наибольшего значения unsigned.
Таким образом, вы также получите доступ к x[i] за пределами.

Это не проблема для целых целых чисел, потому что она просто будет отрицательной и, таким образом, сбой i >= 0.

Таким образом, если вы хотите использовать целые числа без знака, вы можете попробовать один из следующих возможностей:

for (unsigned int i = 9; i-- != 0;) 

и

for (unsigned int i = 9; i != -1; i--) 

Эти два были предложены GManNickG и AndreyT от комментариев.


А вот мои оригинальные 3 версии:

for (unsigned int i = 9; i != (unsigned)0 - 1; i--) 

или

for (unsigned int i = 9; i != ~(unsigned)0; i--) 

или

for (unsigned int i = 9; i != UINT_MAX; i--) 
+0

Или есть 'i' be * еще один *, чем индекс, так что' 0' является правильным условием завершения. Так сложно, как и все остальное. –

+0

Не являются неопределенными поведение целых чисел и переполнения? – josefx

+2

@josefx Только подписанное целое число over/underflow - это неопределенное поведение. – Mysticial

4

Независимо значение unsigned int i всегда верно, что i >= 0 так у наша петля for никогда не заканчивается.

Другими словами, если в какой-то момент i является 0, и вы уменьшить его, он по-прежнему остается неотрицательным, так как он содержит то огромное количество, вероятно, 4294967295 (то есть 2 -1).

6

Проблема заключается в том, что ваша петля позволяет мне быть как можно меньше нуля и только ожидать выхода из цикла, если i меньше 0. Так как i без знака, оно никогда не может быть меньше 0. Оно перевернуто до 2^32-1.Это больше, чем размер вашего вектора и, следовательно, приводит к segfault.

3

Проблемы здесь:

for (unsigned int i = 9; i >= 0; i--) 

Вы начинаете со значением 9 для неподписанных INT и ваше определение выхода есть я> = 0, и это будет всегда верно. (unsigned int никогда не будет отрицательным !!!). Из-за этого ваш цикл начнется (бесконечный цикл, потому что i = 0, тогда -1 идет max uint).

 Смежные вопросы

  • Нет связанных вопросов^_^