2016-09-18 6 views
0

Вот небольшая функция лямбды я использую в качестве вспомогательной функции в коде для моего лексического анализатора:Странных вещи происходят после того, как с помощью зОго :: strtod

auto buildnumber = [&line, &i]() -> Token* { 
    Token* new_number = new Token(nullptr, number, line); 

    char** after_number = nullptr; 
    double* value = new double(std::strtod(i, after_number)); 

    printf("Value got: %f\n", *value); 
    printf("Comparing it to 0\n"); 
    if (*value == 0.0) { 
     printf("value was 0, comparing position to after number\n"); 
     if (i == *after_number) { 
      printf("No number detected\n"); 
      delete value; 
      delete new_number; 
      return nullptr; 
     } 
    } 

    printf("Value was different from 0, storing it in Token\n"); 
    new_number->value = (void*) value; 
    printf("Advancing position\n"); 
    i = *after_number; 
    printf("Returning\n"); 

    return new_number; 
}; 

Вот небольшой фон: Token класса с атрибутом value типа void, атрибут line типа int и атрибут type пользовательского перечисления token_type. В первой строке я инициализирую новую, передающую ее конструктору нулевой указатель для значения (поскольку нам все еще нужно его создать), значение enum token_type (number, потому что этот токен относится к этому типу), а текущая строка мы захватили в лямбда.

i является указателем типа const char*, который указывает на текущий мошенник, который мы рассматриваем. Когда мы называем эту лямбда-функцию, гарантируется, что она укажет на печатный символ.

printf s предназначено для целей отладки;

Так что я пытаюсь сделать так: создать новый Token внутреннего типа number; спросите strtod, если мы можем построить номер из текущей позиции; затем проверьте, не возвращает ли strtod ненулевое значение, и в этом случае мы сохраняем это значение в новом Token, продвигаем позицию символа, на который мы указываем символ, после номера, и возвращаем Token.

Если strtod вместо этого возвращено нулевое значение, мы должны удвоить, если нуль является результатом того, что было найдено фактическое значение 0, или если вместо этого не может быть построено число. Поэтому мы проверяем, указывает ли указатель на символ после номера на тот же символ, что и текущие позиции: если это правда, это означает, что strtok не продвигал этот указатель, и это означает, что не было найдено никакого номера (и мы удалим выделенные значения и вернуть нулевой указатель, чтобы сигнализировать об этом). В противном случае это означает, что найдено 0, и поэтому мы сохраняем его, продвигаемся и возвращаемся.

Проблема заключается в том, я получаю ошибку Segfault буквально каждый раз, когда я пытаюсь почтительное after_number: то есть, если я называю buildnumber когда i указывает на строку, как "111", я получаю Segfault после печатает "Advancing position". И если я его назову, когда i указывает на строку, такую ​​как "+0.0" или "abc()", я получаю segfault после того, как он печатает "Value was 0, comparing position to after number".

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

+1

'i == * after_number' вызывает неопределенное поведение - dereferncing null pointer –

+0

Это не мало. –

+0

@nm хорошо, если вы вынимаете строки 'printf', это не слишком долго. И вы также можете сжать два' if 'после 'Сравнение его с 0' в просто один с использованием '&&'. – user6245072

ответ

6

Вы указали after_number как указатель на указатель на символ, а затем использовали напрямую,, когда он на самом деле не указывает на что-либо полезное.

Проблема в том, что вы в основном говорить strtod не на самом деле магазин конца указатель (потому что вы предоставили nullptr в качестве адреса для сохранения его в), то вы идете вперед и попытаться разыменовать него в любом случае - он все равно будет nullptr, и поэтому вы получите неопределенное поведение.

Правильный способ сделать это состоит в следующем:

char *after_number; 
double *value = new double(std::strtod(i, &after_number)); 

Это фактически создает в char * переменную, в которую strtod может поместить конец указателя, и передает адрес его к strtod. После выхода after_number будет содержать указатель на символ конца, который остановил числовую оценку (надеюсь, это будет указатель на конец строки, поставленной, *after_number == '\0'.

+0

Я клянусь, что я делал это так, но это порождало некоторые ошибки, и я переключился неправильно, думая, что это решит его. Теперь он все равно работает. Большое спасибо. – user6245072