проблема локальной переменной в c ++ - PullRequest
1 голос
/ 23 декабря 2011

Я только начал изучать самые основы c ++, у меня есть опыт работы с vb.net и c #

Теперь я подумал, что основы могут быть рассмотрены для некоторых проблем Project euler, что будет хорошим упражнением.Я столкнулся с очень странной проблемой, пытаясь решить Проблема 4 , возможно, из-за недостаточного понимания c ++.

У меня есть 2 сценария, один работает, другой нет (> переменная просто переходит с 999 на 768, когда команда sprintf выполняется, как показано ниже), теперь мой вопрос: почему это происходит в решении 1?Единственное отличие состоит в том, что переменные цикла a и b объявляются перед циклом, поскольку в решении 2 они объявляются с помощью цикла.

Решение 1 (не работает):

int a =999;
int b =999;
int lb = 100;
int c = 0;
char strNumber[6];
int result = 0;
int ra = 0;
int rb = 0;
for (a=999; a>=100; a--){
    for (b = a; b>=lb; b--){
        c = a * b;
        sprintf(strNumber, "%d", c);
        if (isPalindrome(strNumber)){
            if (c > result){
                result = c;
                lb = b;
                rb = b;
                ra = a;
            }
            b = 0;
        }
    }
}

Решение 2(рабочий):

int lb = 100;
int c = 0;
char strNumber[6];
int result = 0;
int ra = 0;
int rb = 0;

for (int a=999; a>=100; a--){
    for (int b = a; b>=lb; b--){
        c = a * b;
        sprintf(strNumber, "%d", c);
        if (isPalindrome(strNumber)){
            if (c > result){
                result = c;
                lb = b;
                rb = b;
                ra = a;
            }
            b = 0;
        }
    }
}

Ответы [ 2 ]

4 голосов
/ 23 декабря 2011

На самом деле оба имеют одну и ту же проблему, а именно неопределенное поведение . Отсюда проблема:

char strNumber[6];

Эта переменная не может вместить значение 999 x 999 в строковом представлении, поскольку в конце также есть нулевой символ '\0'. Поэтому, когда вы вызываете sprintf для преобразования целого числа в его строковое представление, прямо внутри функции она вызывает неопределенное поведение, когда пытается поставить символ '\0' в индекс 6, потому что индексы 0 в 5 уже заняты шестью цифрами 998001, который является произведением 999 x 999.

Вы должны определить его как минимум размером 7:

char strNumber[7]; //one char for null-character.

Что касается того, почему ваш второй код работает, так это потому, что вам повезло (скорее не повезло ). Вот что означает неопределенное поведение: может произойти все, что угодно . Это может бежать, или не может. Ни спецификация языка, ни компилятор не дают никаких гарантий поведения, следовательно, undefined поведение.

Как отметил @James Kanze в комментарии, реальное решение - забыть о sprintf и лучше использовать std::ostringstream и std::string как:

#include <sstream> //for std::ostringstream 
#include <string>  //for std::string 

std::ostringstream ss;
ss << number;
std::string s = ss.str(); //get the string representation of the number
3 голосов
/ 23 декабря 2011

При первом прохождении цикла c будет представлять собой 6-значное число (999²).
Таким образом, sprintf(strNumber, "%d", c); будет записывать 7 символов в strNumber:шесть цифр и знаменитый нулевой терминатор.Поскольку вы зарезервировали только шесть символов для strNumber, эта последняя запись приведет к тому, что что-то сработает.

Похоже, что это не похоже на то, что сработает что-то важное во втором случае, но это просто "удача", поведение вашего кода не определенов обоих случаях.

Зарезервируйте дополнительный символ в strNumber, и, насколько я могу судить, обе версии должны работать одинаково.

...