CPP для циклических символов строки начинается с неожиданного индекса? - PullRequest
1 голос
/ 06 марта 2019
for(unsigned long i=add1.length()-1;i>=0;i--){
        int presum = stoi(to_string(add1.at(i))) + stoi(to_string(add2.at(i))) + curcarry;

У меня есть этот код, циклически перебирающий символы строки (add1), начиная с последнего и заканчивая первым.Затем он получает текущий символ, используя индекс, и превращает его в целое число, добавляя его к текущему символу другой строки с гарантированной равной длиной (add2).

Я получаю строку out_of_range с ошибкой, и послеГлядя на меню отладки, я вижу, что, хотя мои строки обе, как и должно быть, с длинами только 3, значение i каким-то образом заканчивается как 18446744073709551615.

Прикрепленное изображение значенияя, наряду со строками, длина которых, очевидно, не коррелирует.Что происходит?

Значения отладки:

enter image description here

Ответы [ 2 ]

5 голосов
/ 06 марта 2019

Для значения без знака i>=0 всегда верно. Таким образом, ваш индекс обнуляется, а затем возвращается к наибольшему значению unsigned long, которое, в вашем случае, равно 18446744073709551615.

Напишите свой цикл так (например)

for (unsigned long i = add1.length(); i-- > 0; ) {
1 голос
/ 07 марта 2019

Сбор комментариев к john 's answer :

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

Теперь у вас есть несколько вариантов:

  1. Проверить индекс перед уменьшением (юмористический взгляд на это см. здесь ):

    for (unsigned long i = add1.length(); i-- > 0; )
  2. Прибыль от обхода поведения при недостаточном потоке:

    for (unsigned long i = add1.length() - 1; i < add1.length(); --i)
  3. Обратные итераторы - я бы рассмотрел этонаиболее предпочтительный вариант;но нам нужно инициализировать две переменные и полагаться на оператор последовательности (запятая), некоторые могут отклонить ...:

    for(auto i1 = add1.rbegin(), i2 = add2.rbegin(); i1 != add1.rend(); ++i1, ++i2)
    //                                      ++, even if going reverse!   ^     ^
    {
        // use *i1 and *i2 here
    }

Вы можете предпочесть тип size_t вместо unsigned long, он всегда будет иметь соответствующий размер и является типом, который возвращается std::string::length или функцией size любого контейнера STL.

Я не вижу, однако, где вы обрабатываете случайadd2, являющаяся более короткой строкой - любой из приведенного выше приведет к неопределенному поведению!И если add1 является более коротким, вы начинаете где-то в середине add2.Покрывая оба:

decltype(add1.rend()) ir, er;
for(auto i1 = add1.rbegin(), i2 = add2.rbegin(); ; ++i1, ++i2)
                                                ^ leaving out condition!
{
    if(i1 == add1.rend())
    {
        ir = i2;          // handle rest of add2 after loop
        er = add2.rend(); // needed to be able to compare with appropriate end
        break;
    }
    if(i2 == add2.rend())
    {
        ir = i1;          // handle rest of add1 after loop
        er = add1.rend(); // needed to be able to compare with appropriate end
        break;
    }
    // adding the values as you did before
}
for(; ir != er; ++ir)
{
    // special handling: append whatever remained from add1 or add2
}

Наконец: stoi(to_string(addN.at(i))) - я не могу себе представить ничего менее эффективного ...

  1. at делает проверку диапазона, но через ваш цикл выгарантированный диапазон уже (предполагается, что вы исправили его в соответствии с одним из вариантов выше), поэтому оператор индекса (addN[i]), который этого не делает, является лучшим выбором.Допустим, на этот раз, поскольку цикл был некорректным, at не позволил вам неопределенное поведение.Таким образом, вы можете начать с at сначала и заменить оператором индекса, как только вы узнаете, что код работает правильно ...
  2. (Гораздо тяжелее): промежуточные строки (действительно) имеют длинный путь.Поскольку стандарт C ++ гарантирует, что цифры (только !!!) будут иметь последующие кодовые точки, вы можете просто сделать addN[i] - '0' (или *iX - '0', если используете итераторы), чтобы получить значение.Если вы хотите оставаться переносимым, не принимайте это также и для букв, как в if('A' <= c && c <= 'Z') c += 'a' - 'A' (для этого примера уже существует функция , выполняющая то же самое, что вам абсолютно необходимо).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...