Целые числа без знака в C ++ для циклов - PullRequest
10 голосов
/ 28 января 2012

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

#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 будет равен нулю, потому что есть что-то вроде переполнения. Но я думаю, что целое число без знака может принимать нулевое значение, не так ли? Теперь, если я заменю его целым числом со знаком, проблем не будет.

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

Большое спасибо!

Ответы [ 4 ]

25 голосов
/ 28 января 2012

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

Следовательно, петля-тест:

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--)
6 голосов
/ 28 января 2012

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

4 голосов
/ 28 января 2012

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

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

3 голосов
/ 28 января 2012

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

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

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

...