Vasudha Dixit Ответов: 3

*Pointer_variable ! = '\0' не работает для проверки неудачного преобразования в функции strtol()


Программа не работала для ввода данных то есть при вводе, когда первый символ-это число, а оставшийся следующий символ-любой алфавит или отрицательное число. Например, когда я даю ввод как на выходе я получаю факториал 5.

Поэтому я попробовал поставить чек на strtol неудачное преобразование :-

if (p == buf || *p != '\0'){ printf("\nInvalid input: not a number\n");}

но я получаю вывод как недопустимый ввод: не число для всех входных данных.

Я нашел много подобных вопросов в google. Однако они не решают мою проблему. Я не понимаю, что плохого в этой простой проверке? Как я могу успешно обнаружить ошибки из strtol?

Что я уже пробовал:

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <errno.h>

int display();
void fact_fun(int num_fact);

int main()
{
    int num;
    while ((num = display()) >= 0)
        {
        fact_fun(num);
        }
    return 0;
}

int display()
{
    char buf[256];
    char *p;
    long value;


    for (;;)
        {
        printf("Enter number to find factorial or press ENTER KEY to exit: ");

        if (fgets(buf, sizeof buf, stdin) == NULL || *buf == '\n')
            return -1;

        errno = 0;
        value = strtol(buf, &p, 0);

        if (p == buf || *p != '\0')
            {
            printf("Invalid input: not a number\n");
            }
        else
            {
            if (value < 0)
            {
                printf("Invalid input: negative values not allowed\n");
            }
            else if (errno != 0 || value > INT_MAX)
                {
                    printf("Invalid input: value too large for type int\n");
                }
                else
                    {
                        return (int)value;
                    }
            }
        }
}

void fact_fun(int num_fact)
{
    int fact = 1;
    for (int i = 1; i <= num_fact; i++)
        {
        if (fact > INT_MAX / i)
        {
            printf("Invalid input: arithmetic overflow\n");
            return;
        }
        fact = fact * i;
    }
    printf("Factorial of %d is %d\n", num_fact, fact);
}

3 Ответов

Рейтинг:
16

Jochen Arndt

Вы используете fgets() чтобы прочитать входные данные из стандартный ввод Эта функция поместит завершающую строку '\n' в буфер. Так что даже при вводе действительного номера strtol() остановится на этом новом символе строки, а не на конце строки.

Самое простое решение - это изменение условия:

if (p == buf || *p != '\n')


Vasudha Dixit

Боже Мой! Как же я был глуп! Спасибо

Jochen Arndt

Добро пожаловать и благодарю вас за то, что вы приняли мое решение.

Maciej Los

5ed!

Рейтинг:
1

Richard MacCutchan

&низкотемпературный;pre lang="c++">
значение = strtol(buf, &p, 0);

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


Как указал Йохен, ноль является допустимым основанием.


CPallini

Хороший улов. 5.

Jochen Arndt

Основание нуля является специальным и позволяет вводить данные в шестнадцатеричном, восьмеричном и десятичном виде:

С man-страницы strtol:

Если база равна нулю или 16, то строка может содержать префикс "0x", и число будет считываться в базе 16; в противном случае нулевая база принимается как 10 (десятичная), если следующий символ не является "0", и в этом случае он принимается как 8 (восьмеричная).

CPallini

Ух ты, я кое-что узнал.

Richard MacCutchan

Спасибо. Я посмотрел на страницу MSDN, но пропустил эту часть.

Рейтинг:
1

OriginalGriff

Ричард прав, что ваша база ошибочна, но ... .. посмотрите на свой код

if (p == buf || *p != '\0')
    {
    printf("Invalid input: not a number\n");
    }
p является неназначенным, поэтому он никогда не пройдет первую часть теста.
С p не назначается, *p он также не определен и, вероятно, начнет давать вам ошибки доступа, которые приведут к сбою вашего приложения со многими компиляторами.

Даже если вы установите p к пользовательскому входу в систему buf первая часть теста пройдет успешно - так что вы получите сообщение - и даже если этого не произошло, любой непустой ввод пользователя сделает вторую часть проходной.

Так что в значительной степени при любых обстоятельствах этот код либо даст вам сообщение, либо потерпит крах. Вам нужно сделать шаг назад, подумать о том, что вы делаете, и попробовать кодировать это снова - потому что то, что у вас есть в данный момент, выглядит для меня как "панический код", а не "продуманный" код!


Jochen Arndt

p инициализируется функцией strtol ().

Richard MacCutchan

Нет, я ошибся, смотрите комментарий Йохена к моему решению.