Проверить scanf на ошибку

You seem to want to validate a string as input. It depends on whether you want to validate that your string contains a double or a int. The following checks for a double (leading and trailing whitespace is allowed).

bool is_double(char const* s) {
    int n;
    double d;
    return sscanf(s, "%lf %n", &d, &n) == 1 && !s[n];
}

sscanf will return the items converted (without ‘%n’). n will be set to the amount of the processed input characters. If all input was processed, s[n] will return the terminating 0 character. The space between the two format specifiers accounts for optional trailing whitespace.

The following checks for an int, same techniques used:

bool is_int(char const* s) {
    int n;
    int i;
    return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}

There was a question on that here, which include also more C++’ish ways for doing this, like using string streams and functions from boost, like lexical_cast and so on. They should generally be preferred over functions like scanf, since it’s very easy to forget to pass some ‘%’ to scanf, or some address. scanf won’t recognize that, but instead will do arbitrary things, while lexical_cast, for instance, will throw an exception if anything isn’t right .

This is homework, so you might be required to work under certain (arbitrary) restrictions. However, the phrase «scanf error handling» is something of an oxymoron in the C programming language.

The best way to do this is to read in a line/other suitable chunk and parse it with C string functions. You can do it in one line of scanf but there are many drawbacks:

  1. You can guard against buffer overflows, but if a buffer isn’t large enough you can’t recover.
  2. You can specify specific character ranges for your strings, but it starts to look a little regexy, and the behavior of the "%[" format of scanf isn’t mandated in the standard.
  3. You can check for a third name, but the code looks unintuitive — it doesn’t look like you only want two names, it looks like you want three. scanf also gives you very little control over how you handle whitespace.

EDIT: I initially thought from your question that the names were contained in brackets (a la "[Bruce] [Wayne]") but it now appears that was merely your convention for denoting a placeholder.

Anyway, despite my intense dislike of scanf, it has its uses. The biggest killer (for me) is the inability to distinguish between line endings and simple space separation. To fix that, you can call fgets to read the data into a buffer, then call sscanf on the buffer. This gives you both a) safer reading (scanf messes with the ability of other more straightforward functions to read from a buffer) and b) the benefits of scanf formats.

If you have to use scanf, your format basically be this:

" %s %s %s"

With the third being undesirable. As @Constantinius’s answer shows, you’d need to read data into three buffers, and check whether or not the third passed. However, if you’re reading multiple consecutive lines of this data, then the first entry of the next line would satisfy the third slot, falsely giving you an error. I highly recommend using fgets and sscanf or ditching the sscanf for more precise manual parsing in this case.

Here’s a link to the fgets man page if you missed the one I snuck in earlier. If you decide to ditch sscanf, here are some other functions to look into: strchr (or strspn, or strcspn) to find how long the name is, strcpy or memcpy (but please not strncpy, it’s not what you think it is) to copy data into the buffers.

SopranoX

2 / 2 / 0

Регистрация: 04.11.2016

Сообщений: 34

1

13.03.2017, 13:08. Показов 22807. Ответов 8

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Как я понимаю: использовать scanf + массив для проверки на корректность ввода — неудачная идея. Она не чистит буфер, который предоставляет stdio ( ни совсем понимаю чего там происходит )).

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
 
int main(void){
 
    int n;
 
// Вариант с выходом из программы - все работает
    printf("Введите значение: ");
    if ( (scanf("%d",&n) ) != 1 ){
        printf("Неверное введенное значение");
        return 1;
    }
 
// проверка с использованием цикла - зацикливает
 
    printf("Введите значение: ");
    while ( (scanf("%d",&n) ) != 1 ) 
        printf("Неверное введенное значение, попробуйте еще: ");
    printf("Успех!");
}

Неужели единственный способ корректной проверки, это использовать функции read или getс, посимвольно считывать в массив, и потом уже проверять ??



1



6044 / 2159 / 753

Регистрация: 10.12.2010

Сообщений: 6,005

Записей в блоге: 3

13.03.2017, 14:17

2

Цитата
Сообщение от SopranoX
Посмотреть сообщение

Неужели единственный способ корректной проверки, это использовать функции read или getс, посимвольно считывать в массив, и потом уже проверять ??

На самом деле нет. Лучше считывать целую строку, а уже ее проверять.



1



Нарушитель

1165 / 852 / 250

Регистрация: 30.06.2015

Сообщений: 4,439

Записей в блоге: 50

13.03.2017, 14:22

3

Цитата
Сообщение от SopranoX
Посмотреть сообщение

Как я понимаю: использовать scanf + массив для проверки на корректность ввода — неудачная идея. Она не чистит буфер,

Просто буфер нужно чистить самостоятельно.
Да, и кстати, scanf возвращает число фактически присвоенных значений переменной. Поэтому он в данном случае всегда возвращает единицу.



1



SopranoX

2 / 2 / 0

Регистрация: 04.11.2016

Сообщений: 34

13.03.2017, 15:11

 [ТС]

4

Цитата
Сообщение от CoderHuligan
Посмотреть сообщение

Просто буфер нужно чистить самостоятельно.

Ок, буфер stdio, как я понял, использует функция — setbuf(), а размер буфера указа в константе BUFSIZ. Как его более правильно почистить?

C
1
2
3
4
5
    printf("Введите значение: ");
        while (  scanf("%d",&n) == 0 ) {
            printf("Неверное полученное значение, попробуйте еще: ");
            // Чистим буфер -- ??  setbuf() --???
        }

Цитата
Сообщение от HighPredator
Посмотреть сообщение

На самом деле нет. Лучше считывать целую строку, а уже ее проверять.

То-есть использовать fgets ? Если не сложно можно увидеть реализацию ?



0



6044 / 2159 / 753

Регистрация: 10.12.2010

Сообщений: 6,005

Записей в блоге: 3

13.03.2017, 15:15

5

Лучший ответ Сообщение было отмечено SopranoX как решение

Решение



1



CoderHuligan

Нарушитель

1165 / 852 / 250

Регистрация: 30.06.2015

Сообщений: 4,439

Записей в блоге: 50

13.03.2017, 15:27

6

Лучший ответ Сообщение было отмечено SopranoX как решение

Решение

Цитата
Сообщение от SopranoX
Посмотреть сообщение

Как его более правильно почистить?

вот так:

C
1
2
3
4
5
printf("Введите значение: ");
        while (  scanf("%d",&n) == 0 ) {
            printf("Неверное полученное значение, попробуйте еще: ");
                while(getchar()!='n'); // Чистим буфер
        }



1



LFC

737 / 542 / 416

Регистрация: 17.09.2015

Сообщений: 1,601

13.03.2017, 15:32

7

Лучший ответ Сообщение было отмечено SopranoX как решение

Решение

SopranoX, обычно в таких случаях в буфере остается n,я делаю так

C
1
2
3
4
5
 while ( (scanf("%d",&n) ) != 1 ) {
        printf("Неверное введенное значение, попробуйте еще: ");
        while(getchar() != 'n')
              ;
}



2



CoderHuligan

Нарушитель

1165 / 852 / 250

Регистрация: 30.06.2015

Сообщений: 4,439

Записей в блоге: 50

13.03.2017, 16:24

8

Кстати, вот так ещё безопаснее:

C
1
for(int c=getchar(); c!='n' && c!=EOF; c=getchar());



0



2 / 2 / 0

Регистрация: 04.11.2016

Сообщений: 34

13.03.2017, 16:36

 [ТС]

9

Всем спасибо, сильно помогли!



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

13.03.2017, 16:36

9

SopranoX

2 / 2 / 0

Регистрация: 04.11.2016

Сообщений: 34

1

13.03.2017, 13:08. Показов 21021. Ответов 8

Метки нет (Все метки)


Как я понимаю: использовать scanf + массив для проверки на корректность ввода — неудачная идея. Она не чистит буфер, который предоставляет stdio ( ни совсем понимаю чего там происходит )).

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
 
int main(void){
 
    int n;
 
// Вариант с выходом из программы - все работает
    printf("Введите значение: ");
    if ( (scanf("%d",&n) ) != 1 ){
        printf("Неверное введенное значение");
        return 1;
    }
 
// проверка с использованием цикла - зацикливает
 
    printf("Введите значение: ");
    while ( (scanf("%d",&n) ) != 1 ) 
        printf("Неверное введенное значение, попробуйте еще: ");
    printf("Успех!");
}

Неужели единственный способ корректной проверки, это использовать функции read или getс, посимвольно считывать в массив, и потом уже проверять ??

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь

1

6044 / 2159 / 753

Регистрация: 10.12.2010

Сообщений: 6,007

Записей в блоге: 3

13.03.2017, 14:17

2

Цитата
Сообщение от SopranoX
Посмотреть сообщение

Неужели единственный способ корректной проверки, это использовать функции read или getс, посимвольно считывать в массив, и потом уже проверять ??

На самом деле нет. Лучше считывать целую строку, а уже ее проверять.

1

1122 / 803 / 248

Регистрация: 30.06.2015

Сообщений: 4,210

Записей в блоге: 44

13.03.2017, 14:22

3

Цитата
Сообщение от SopranoX
Посмотреть сообщение

Как я понимаю: использовать scanf + массив для проверки на корректность ввода — неудачная идея. Она не чистит буфер,

Просто буфер нужно чистить самостоятельно.
Да, и кстати, scanf возвращает число фактически присвоенных значений переменной. Поэтому он в данном случае всегда возвращает единицу.

1

SopranoX

2 / 2 / 0

Регистрация: 04.11.2016

Сообщений: 34

13.03.2017, 15:11

 [ТС]

4

Цитата
Сообщение от CoderHuligan
Посмотреть сообщение

Просто буфер нужно чистить самостоятельно.

Ок, буфер stdio, как я понял, использует функция — setbuf(), а размер буфера указа в константе BUFSIZ. Как его более правильно почистить?

C
1
2
3
4
5
    printf("Введите значение: ");
        while (  scanf("%d",&n) == 0 ) {
            printf("Неверное полученное значение, попробуйте еще: ");
            // Чистим буфер -- ??  setbuf() --???
        }

Цитата
Сообщение от HighPredator
Посмотреть сообщение

На самом деле нет. Лучше считывать целую строку, а уже ее проверять.

То-есть использовать fgets ? Если не сложно можно увидеть реализацию ?

0

6044 / 2159 / 753

Регистрация: 10.12.2010

Сообщений: 6,007

Записей в блоге: 3

13.03.2017, 15:15

5

Лучший ответ Сообщение было отмечено SopranoX как решение

Решение

1

CoderHuligan

1122 / 803 / 248

Регистрация: 30.06.2015

Сообщений: 4,210

Записей в блоге: 44

13.03.2017, 15:27

6

Лучший ответ Сообщение было отмечено SopranoX как решение

Решение

Цитата
Сообщение от SopranoX
Посмотреть сообщение

Как его более правильно почистить?

вот так:

C
1
2
3
4
5
printf("Введите значение: ");
        while (  scanf("%d",&n) == 0 ) {
            printf("Неверное полученное значение, попробуйте еще: ");
                while(getchar()!='n'); // Чистим буфер
        }

1

LFC

737 / 542 / 416

Регистрация: 17.09.2015

Сообщений: 1,601

13.03.2017, 15:32

7

Лучший ответ Сообщение было отмечено SopranoX как решение

Решение

SopranoX, обычно в таких случаях в буфере остается n,я делаю так

C
1
2
3
4
5
 while ( (scanf("%d",&n) ) != 1 ) {
        printf("Неверное введенное значение, попробуйте еще: ");
        while(getchar() != 'n')
              ;
}

2

CoderHuligan

1122 / 803 / 248

Регистрация: 30.06.2015

Сообщений: 4,210

Записей в блоге: 44

13.03.2017, 16:24

8

Кстати, вот так ещё безопаснее:

C
1
for(int c=getchar(); c!='n' && c!=EOF; c=getchar());

0

2 / 2 / 0

Регистрация: 04.11.2016

Сообщений: 34

13.03.2017, 16:36

 [ТС]

9

Всем спасибо, сильно помогли!

0

IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

13.03.2017, 16:36

9

This is homework, so you might be required to work under certain (arbitrary) restrictions. However, the phrase «scanf error handling» is something of an oxymoron in the C programming language.

The best way to do this is to read in a line/other suitable chunk and parse it with C string functions. You can do it in one line of scanf but there are many drawbacks:

  1. You can guard against buffer overflows, but if a buffer isn’t large enough you can’t recover.
  2. You can specify specific character ranges for your strings, but it starts to look a little regexy, and the behavior of the "%[" format of scanf isn’t mandated in the standard.
  3. You can check for a third name, but the code looks unintuitive — it doesn’t look like you only want two names, it looks like you want three. scanf also gives you very little control over how you handle whitespace.

EDIT: I initially thought from your question that the names were contained in brackets (a la "[Bruce] [Wayne]") but it now appears that was merely your convention for denoting a placeholder.

Anyway, despite my intense dislike of scanf, it has its uses. The biggest killer (for me) is the inability to distinguish between line endings and simple space separation. To fix that, you can call fgets to read the data into a buffer, then call sscanf on the buffer. This gives you both a) safer reading (scanf messes with the ability of other more straightforward functions to read from a buffer) and b) the benefits of scanf formats.

If you have to use scanf, your format basically be this:

" %s %s %s"

With the third being undesirable. As @Constantinius’s answer shows, you’d need to read data into three buffers, and check whether or not the third passed. However, if you’re reading multiple consecutive lines of this data, then the first entry of the next line would satisfy the third slot, falsely giving you an error. I highly recommend using fgets and sscanf or ditching the sscanf for more precise manual parsing in this case.

Here’s a link to the fgets man page if you missed the one I snuck in earlier. If you decide to ditch sscanf, here are some other functions to look into: strchr (or strspn, or strcspn) to find how long the name is, strcpy or memcpy (but please not strncpy, it’s not what you think it is) to copy data into the buffers.

Other Alias

fscanf, sscanf, vscanf, vsscanf, vfscanf

ОБЗОР

#include <stdio.h>
int scanf(const char *format, …);
int fscanf(FILE *stream, const char *format, …);
int sscanf(const char *str, const char *format, …);


#include <stdarg.h>
int vscanf(const char *format, va_list ap);
int vsscanf(const char *str, const char *format, va_list ap);
int vfscanf(FILE *stream, const char *format, va_list ap);

Требования макроса тестирования свойств для glibc
(см. feature_test_macros(7)):

vscanf(), vsscanf(), vfscanf():

_XOPEN_SOURCE >= 600 || _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L;

или cc -std=c99

ОПИСАНИЕ

Группа функций scanf() считывает вводимую информацию в соответствии с
форматом format так, как описано ниже. В формате могут указываться
определители преобразования (conversion specifications); результаты
каждого преобразования, если они производились, сохраняются по адресам
параметров указателей, передаваемых после format. Каждый параметр
указатель должен быть того же типа, что и значение, получаемое в
результате преобразования данных в соответствии с форматом.

Если количество определителей преобразования в format превышает
количество параметров указателей, то результат не определён. Если
количество параметров указателей превышает количество определителей
преобразования, то лишние параметры указатели вычисляются, но
игнорируются.

Функция scanf() считывает информацию из стандартного потока ввода
stdin; fscanf() считывает информацию из потока, на который указывает
stream, а sscanf() считывает информацию из символьной строки, на
которую указывает str.

Функция vfscanf() является аналогом vfprintf(3) и читает информацию из
потока, на который указывает указатель stream, используя список
указателей переменной длины (смотрите stdarg(3)). Функция vscanf()
считывает список параметров переменной длины из стандартного ввода, а
функция vsscanf() считывает его из строки. Эти функции являются аналогами
функций vprintf(3) и vsprintf(3), соответственно.

Строка format состоит из последовательности инструкций (directives),
которые описывают порядок обработки входных символов. Если обработка
инструкции завершается с ошибкой, то чтение прекращается и scanf()
завершает работу. «Отказом» может быть: ошибка ввода, то есть
недоступность входных символов или ошибка совпадения, то есть получены
неподходящие данные (смотрите далее).

Инструкцией может быть:

  • Последовательность пробельных символов (пробел, табуляция, символ новой
    строки и т. д.; смотрите isspace(3)). Эта инструкция совпадает с любым
    количеством пустого места, включая отсутствие данных.
  • Обычный символ (т. е., отличный от пробельного или «%»). Такой символ должен
    точно совпадать со следующим символом входных данных.
  • Определитель преобразования, который начинается с символа «%»
    (процент). Последовательность символов ввода преобразуется в соответствии с
    определителем, а результат помещается в соответствующий параметр
    указатель. Если следующий элемент ввода не соответствует определителю
    преобразования, то преобразование завершается с ошибкой — ошибкой
    совпадения
    .

Каждый определитель преобразования в format начинается с символа «%»
или последовательности символов «%n$» (смотрите о разнице далее) за
которым следует:

  • Необязательный символ подавления назначения «*»: scanf() читает данные
    как предписано определителем преобразования, но отбрасывает
    их. Соответствующий параметр указатель необязателен, и этот определитель
    не учитывается в счётчике успешных назначений, возвращаемом scanf().
  • Необязательный символ «m». Используется в строковых преобразованиях (%s,
    %c, %[) и освобождает вызывающего от необходимости выделять
    соответствующий буфер для хранения входных данных: вместо этого scanf()
    выделяет буфер достаточного размера и присваивает адрес этого буфера
    соответствующему параметру указателю, который должен быть указателем на
    переменную char * (эту переменную не нужно инициализировать перед
    вызовом). Вызывающий должен вызвать free(3) для этого буфера, как только
    он станет ненужным.
  • Необязательное целое десятичное число, которое задаёт максимальную ширину
    поля
    . Чтение символов прерывается по достижении этого максимума или при
    нахождении несовпадающего символа, неважно что случится раньше. В
    большинстве преобразований начальные пробельные символы отбрасываются
    (исключения приведены далее), и эти отброшенные символы не учитываются в
    максимальной ширине поля. В преобразованных строках ввода сохраняется
    конечный байт null (») для отметки конца ввода; в максимальной
    ширине поля он также не учитывается.
  • Необязательный символ модификатора типа. Например, модификатор типа l
    используется в преобразованиях целых чисел, например с помощью %d, для
    указания того, что соответствующий параметр указатель ссылается на
    long int, а не на int.
  • Определитель преобразования, который задаёт тип входного преобразования.

Определители преобразования в format бывают двух видов: начинающиеся с
«%» и начинающиеся с «%n$». Эти два вида не должны использоваться
одновременно в строке format, за исключением случая, когда строка,
содержащая определители «%n$», может включать %% и %*. Если в
format содержатся определители «%», то они задаются в порядке появления
параметров указателей, указанных после. В форме «%n$» (есть в
POSIX.1-2001, но отсутствует в C99), n — это десятичное целое, которое
задаёт в какое место должен быть помещён ввод, то есть указывает на
расположение n-го параметра указателя, передаваемого после format.

Преобразования

Следующие символы модификаторов типа (type modifier characters) могут
появляться в определении преобразования:

h
Обозначает, что преобразование будет одним из d, i, o, u, x,
X или n и следующий указатель является указателем на short int или
на unsigned short int (но не int).
hh
Как h, но следующий указатель — указатель на signed char или
unsigned char.
j
Как h, но следующий указатель — указатель на intmax_t или
uintmax_t. Этот модификатор появился в C99.
l
Обозначает, что преобразование будет одним из d, i, o, u, x,
X или n и следующий указатель является указателем на long int или
unsigned long int (но не int), или что преобразование будет одним из
e, f или g и следующий указатель является указателем на double
(но не float). Указание двух символов l эквивалентно L. Если
используется с %c или %s, то соответствующий параметр считается
указателем на широкий символ или строку широких символов, соответственно.
L
Обозначает, что преобразование будет одним из e, f или g и
следующий указатель является указателем на long double или преобразование
будет одним из d, i, o, u или x и следующий указатель
является указателем на long long.
q
Эквивалентен L. Данный определитель отсутствует в ANSI C.
t
Как h, но следующий указатель — указатель на ptrdiff_t. Этот
модификатор появился в C99.
z
Как h, но следующий указатель — указатель на size_t. Этот модификатор
появился в C99.

Доступны следующие определители преобразования:

%
Совпадает с литерой «%». То есть %% в строке формата соответствует
одиночному символу данных «%». Преобразование не выполняется (но начальные
пробельные символы отбрасываются) и назначения не происходит.
d
Совпадает с необязательным знаковым десятичным целым; следующий указатель
должен быть указателем на int.
D
Эквивалентно ld; оставлено только для обратной совместимости (замечание:
есть только в libc4. В libc5 и glibc %D просто игнорируется, что приводит
к непонятным ошибкам в старых программах).
i
Совпадает с необязательным знаковым целым; следующий указатель должен быть
указателем на int. Целое считывается как шестнадцатеричное число, если
начинается с 0x или 0X, как восьмеричное, если начинается с 0 и как
десятичное в остальных случаях. Используются только символы, подходящие для
работы с выбранным основанием системы счисления.
o
Совпадает с необязательным беззнаковым восьмеричным целым; следующий
указатель должен быть указателем на unsigned int.
u
Совпадает с необязательным беззнаковым десятичным целым; следующий указатель
должен быть указателем на unsigned int.
x
Совпадает с необязательным беззнаковым шестнадцатеричным целым; следующий
указатель должен быть указателем на unsigned int.
X
Эквивалентно x.
f
Совпадает с необязательным знаковым числом с плавающей запятой; следующий
указатель должен быть указателем на float.
e
Эквивалентно f.
g
Эквивалентно f.
E
Эквивалентно f.
a
(C99) Эквивалентно f.
s
Совпадает с последовательностью непробельных символов; следующий указатель
должен указывать на первый элемент массива символов достаточной длины для
сохранения входной последовательности и завершающего байта null
(»), который добавляется автоматически. Входная строка обрывается
при появлении пробельного символа или достижении максимальной ширины поля,
неважно что случится раньше.
c
Совпадает с последовательностью символов, чья длина задаётся максимальной
шириной поля
(по умолчанию 1); следующий указатель должен быть указателем
на char, и должно быть достаточно места для всех символов (завершающий
байт null не добавляется). Обычный пропуск начальных пробелов не
выполняется. Чтобы пропустить пробелы, явно укажите их в формате.
[
Совпадает с непустой последовательностью символов из задаваемого набора
допустимых символов; следующий указатель должен быть указателем на char и
должно быть достаточно места для всех символов в строке плюс завершающий
байт null. Обычный пропуск начальных пробелов не выполняется. Строка будет
состоять (или нет) из символов определённого набора; набор задаётся
указанием символов между символом открывающей скобки [ и закрывающей
скобки ]. Набором определяются исключающиеся символы, если первым
символом после открывающей скобки является символ диакритического знака
(^). Чтобы включить закрывающую скобку в набор, укажите её первым
символом после открывающей скобки или диакритического знака; в любой другой
позиции она закрывает набор. Символ переноса также является
специализированным; если он указывается между двумя символами, то в набор
добавляются все лежащие в промежутке символы. Чтобы добавить в набор символ
переноса укажите его последним, перед конечной закрывающей
скобкой. Например, [^]0-9-] означает, что «все символы, кроме закрывающей
скобки, цифр от 0 до 9 и переноса». Строка обрывается при появлении символа
не из набора (или, при указании символа диакритического знака, из) или при
достижении ширины поля.
p
Совпадает со значением указателя (как выводится при %p в printf(3));
следующий указатель должен быть указателем на void.
n
Ничего не ожидается; вместо этого количество символов, использованных к
настоящему времени из ввода, сохраняется по следующему указателю, который
должен быть указателем на int. Это не преобразование и не
увеличивает счётчик, возвращаемый функцией. Назначение может подавляться при
указании символа подавления назначения *, но влияние этого на
возвращаемое значение не определено. Поэтому преобразования %*n лучше не
использовать.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

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

Если конец входных данных был достигнут раньше, чем произошло хотя бы одно
совпадение или при ошибке совпадения возвращается значение EOF. Значение
EOF также возвращается при ошибке чтения; в этом случае для потока
устанавливается индикатор ошибки (смотрите ferror(3)), а в errno
указывается номер ошибки.

ОШИБКИ

EAGAIN
Файловый дескриптор stream помечен как неблокирующий, а чтение вызвало бы
блокировку.
EBADF
Неправильный файловый дескриптор для stream или он не открыт на чтение.
EILSEQ
Из входной байтовой последовательности невозможно создать корректный символ.
EINTR
Операция чтения была прервана сигналом; смотрите signal(7).
EINVAL
Недостаточно параметров или format равен NULL.
ENOMEM
Не хватает памяти.
ERANGE
Результат преобразования целого превысил бы размер, который можно хранить в
соответствующем целочисленном типе.

АТРИБУТЫ

Описание терминов данного раздела смотрите в attributes(7).

Интерфейс Атрибут Значение
scanf(),
fscanf(),

sscanf(),
vscanf(),

vsscanf(),
vfscanf()

безвредность в нитях безвредно (MT-Safe locale)

СООТВЕТСТВИЕ СТАНДАРТАМ

Функции fscanf(), scanf() и sscanf() соответствуют C89, C99 и
POSIX.1-2001. В этих стандартах не определена ошибка ERANGE.

Определитель q в 4.4BSD используется для long long, а определители
ll или L используются в GNU для преобразования целых чисел.

Версия Linux этих функций основана на библиотеке GNU libio. Более
точное описание функций можно найти в документации в формате info на
GNU libc (glibc-1.08).

ЗАМЕЧАНИЯ

Модификатор выделения-назначения «a»

Первоначально, в библиотеке GNU C поддерживалось динамическое выделение
памяти для входных строк при указании символа a (нестандартное
расширение) (это свойство существует до glibc 2.0). То есть можно указать
scanf() выделить буфер под входную строку, передав в указателе только
указатель на буфер *buf:

    char *buf;

    scanf(«%as», &buf);

Использование буквы a для этой цели проблематично, так как a также
используется в стандарте ISO C как синоним f (ввод данных с плавающей
запятой). В POSIX.1-2008 для назначения с выделением определён модификатор
m (смотрите в ОПИСАНИЕ выше).

Заметим, что модификатор a недоступен, если программа скомпилирована
посредством gcc -std=c99 или gcc -D_ISOC99_SOURCE (если не определён
_GNU_SOURCE); в этом случае a рассматривается как определитель чисел с
плавающей запятой (смотрите выше).

Поддержка модификатора m была добавлена в glibc начиная с версии 2.7, и в
новых программах нужно использовать этот модификатор вместо a.

Стандартизированный в POSIX модификатор m имеет дополнительные
преимущества над a:

*
Он может также применяться к определителям преобразования %c (например,
%3mc).
*
Исчезает неоднозначность с определителем преобразования чисел с плавающей
запятой %a (не подвержен влиянию gcc -std=c99).

ДЕФЕКТЫ

Все функции полностью соответствуют C89, но предоставляют дополнительные
определители q и a, а также дополнительные возможности определителей
L и l. Последнее может считаться дефектом, так как это изменяет
поведение определителей, заданное в C89.

Некоторые комбинации модификаторов типов и определителей преобразования,
определённые в ANSI C, не имеют смысла (например, %Ld). Хотя они могут
иметь хорошо описанное поведение в Linux, это не обязательно так на других
архитектурах. Поэтому, обычно, лучше использовать модификаторы, не
определённые в ANSI C, то есть использовать q вместо L в комбинации с
преобразованием d, i, o, u, x и X или ll.

Работа q отличается от работы в 4.4BSD, так как может использоваться при
преобразовании вещественных числе подобно L.

ПРИМЕР

Чтобы использовать определитель динамического выделения при преобразовании,
укажите m в качестве модификатора длины (в виде %ms или
%m[диапазон]). Вызывающий должен вызвать free(3) для
возвращённой строки как в следующем примере:

char *p;
int n;
errno = 0;
n = scanf("%m[a-z]", &p);
if (n == 1) {
    printf("чтение: %sn", p);
    free(p);
} else if (errno != 0) {
    perror("scanf");
} else {
    fprintf(stderr, "Нет совпадающих символовn");
}

Как показано в примере выше, необходимо вызывать free(3) только, если при
вызове scanf() была прочитана строка.

Кажется, вы хотите проверить строку как входную. Это зависит от того, хотите ли вы подтвердить, что ваша строка содержит double или int. Следующие проверки на двойное (разрешены начальные и конечные пробелы).

bool is_double(char const* s) {
    int n;
    double d;
    return sscanf(s, "%lf %n", &d, &n) == 1 && !s[n];
}

sscanf вернет преобразованные элементы (без «% n»). n будет установлено количество обработанных входных символов. Если весь ввод был обработан, s [n] вернет завершающий символ 0. Пространство между двумя спецификаторами формата учитывает необязательные завершающие пробелы.

Следующие проверки на int используются те же методы:

bool is_int(char const* s) {
    int n;
    int i;
    return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}

Был вопрос по этому поводу здесь, которые включают в себя и другие способы C ++ для этого, например, использование строковых потоков и функций из boost, таких как lexical_cast и т. д. Как правило, они должны быть предпочтительнее таких функций, как scanf, так как очень легко забыть передать какой-нибудь «%» в scanf или какой-либо адрес. scanf не распознает это, но вместо этого будет выполнять произвольные действия, в то время как lexical_cast, например, выдаст исключение, если что-то не так.

The catch is that I cannot use atoi or any other function like that (I’m pretty sure we’re supposed to rely on mathematical operations).

 int num; 
 scanf("%d",&num);
 if(/* num is not integer */) {
  printf("enter integer");
  return;
 }

I’ve tried:

(num*2)/2 == num
num%1==0
if(scanf("%d",&num)!=1)

but none of these worked.

Any ideas?

The Archetypal Paul's user avatar

asked Nov 1, 2010 at 19:04

Gal's user avatar

6

num will always contain an integer because it’s an int. The real problem with your code is that you don’t check the scanf return value. scanf returns the number of successfully read items, so in this case it must return 1 for valid values. If not, an invalid integer value was entered and the num variable did probably not get changed (i.e. still has an arbitrary value because you didn’t initialize it).

As of your comment, you only want to allow the user to enter an integer followed by the enter key. Unfortunately, this can’t be simply achieved by scanf("%dn"), but here’s a trick to do it:

int num;
char term;
if(scanf("%d%c", &num, &term) != 2 || term != 'n')
    printf("failuren");
else
    printf("valid integer followed by enter keyn");

answered Nov 1, 2010 at 19:42

AndiDog's user avatar

AndiDogAndiDog

67.6k21 gold badges159 silver badges204 bronze badges

7

You need to read your input as a string first, then parse the string to see if it contains valid numeric characters. If it does then you can convert it to an integer.

char s[MAX_LINE];

valid = FALSE;
fgets(s, sizeof(s), stdin);
len = strlen(s);
while (len > 0 && isspace(s[len - 1]))
    len--;     // strip trailing newline or other white space
if (len > 0)
{
    valid = TRUE;
    for (i = 0; i < len; ++i)
    {
        if (!isdigit(s[i]))
        {
            valid = FALSE;
            break;
        }
    }
}

answered Nov 1, 2010 at 19:08

Paul R's user avatar

Paul RPaul R

206k35 gold badges381 silver badges549 bronze badges

8

There are several problems with using scanf with the %d conversion specifier to do this:

  1. If the input string starts with a valid integer (such as «12abc»), then the «12» will be read from the input stream and converted and assigned to num, and scanf will return 1, so you’ll indicate success when you (probably) shouldn’t;

  2. If the input string doesn’t start with a digit, then scanf will not read any characters from the input stream, num will not be changed, and the return value will be 0;

  3. You don’t specify if you need to handle non-decimal formats, but this won’t work if you have to handle integer values in octal or hexadecimal formats (0x1a). The %i conversion specifier handles decimal, octal, and hexadecimal formats, but you still have the first two problems.

First of all, you’ll need to read the input as a string (preferably using fgets). If you aren’t allowed to use atoi, you probably aren’t allowed to use strtol either. So you’ll need to examine each character in the string. The safe way to check for digit values is to use the isdigit library function (there are also the isodigit and isxdigit functions for checking octal and hexadecimal digits, respectively), such as

while (*input && isdigit(*input))
   input++;    

(if you’re not even allowed to use isdigit, isodigit, or isxdigit, then slap your teacher/professor for making the assignment harder than it really needs to be).

If you need to be able to handle octal or hex formats, then it gets a little more complicated. The C convention is for octal formats to have a leading 0 digit and for hex formats to have a leading 0x. So, if the first non-whitespace character is a 0, you have to check the next character before you can know which non-decimal format to use.

The basic outline is

  1. If the first non-whitespace character is not a ‘-‘, ‘+’, ‘0’, or non-zero decimal digit, then this is not a valid integer string;
  2. If the first non-whitespace character is ‘-‘, then this is a negative value, otherwise we assume a positive value;
  3. If the first character is ‘+’, then this is a positive value;
  4. If the first non-whitespace and non-sign character is a non-zero decimal digit, then the input is in decimal format, and you will use isdigit to check the remaining characters;
  5. If the first non-whitespace and non-sign character is a ‘0’, then the input is in either octal or hexadecimal format;
  6. If the first non-whitespace and non-sign character was a ‘0’ and the next character is a digit from ‘0’ to ‘7’, then the input is in octal format, and you will use isodigit to check the remaining characters;
  7. If the first non-whitespace and non-sign character was a 0 and the second character is x or X, then the input is in hexadecimal format and you will use isxdigit to check the remaining characters;
  8. If any of the remaining characters do not satisfy the check function specified above, then this is not a valid integer string.

answered Nov 1, 2010 at 20:19

John Bode's user avatar

John BodeJohn Bode

117k18 gold badges116 silver badges194 bronze badges

First ask yourself how you would ever expect this code to NOT return an integer:

int num; 
scanf("%d",&num);

You specified the variable as type integer, then you scanf, but only for an integer (%d).

What else could it possibly contain at this point?

answered Nov 1, 2010 at 19:38

abelenky's user avatar

abelenkyabelenky

62.8k22 gold badges108 silver badges158 bronze badges

3

If anyone else comes up with this question, i’ve written a program, that keeps asking to input a number, if user’s input is not integer, and finishes when an integer number is accepted

#include<stdlib.h>
#include<stdio.h>
#include<stdbool.h>

bool digit_check(char key[])
{
    for(int i = 0; i < strlen(key); i++)
    {
        if(isdigit(key[i])==0)
        {
            return false;
        }
    }
    return true;
}

void main()
{
    char stroka[10];
    do{
        printf("Input a number: ");
        scanf("%s",stroka);}
    while (!digit_check(stroka));
    printf("Number is accepted, input finished!n");
    system("pause");
}

answered May 28, 2021 at 17:03

user16062049's user avatar

I looked over everyone’s input above, which was very useful, and made a function which was appropriate for my own application. The function is really only evaluating that the user’s input is not a «0», but it was good enough for my purpose. Hope this helps!

#include<stdio.h>

int iFunctErrorCheck(int iLowerBound, int iUpperBound){

int iUserInput=0;
while (iUserInput==0){
    scanf("%i", &iUserInput);
    if (iUserInput==0){
        printf("Please enter an integer (%i-%i).n", iLowerBound, iUpperBound);
        getchar();
    }
    if ((iUserInput!=0) && (iUserInput<iLowerBound || iUserInput>iUpperBound)){
        printf("Please make a valid selection (%i-%i).n", iLowerBound, iUpperBound);
        iUserInput=0;
    }
}
return iUserInput;
}

answered Nov 2, 2014 at 17:53

Nick's user avatar

1

Try this…

#include <stdio.h>

int main (void)
{
    float a;
    int q;

    printf("nInsert numbert");
    scanf("%f",&a);

    q=(int)a;
    ++q;

    if((q - a) != 1)
        printf("nThe number is not an integernn");
    else
        printf("nThe number is an integernn");

    return 0;
}

Unihedron's user avatar

Unihedron

10.8k13 gold badges61 silver badges70 bronze badges

answered Nov 20, 2014 at 5:58

OscaRoCa's user avatar

1

This is a more user-friendly one I guess :

#include<stdio.h>

/* This program checks if the entered input is an integer
 * or provides an option for the user to re-enter.
 */

int getint()
{
  int x;
  char c;
  printf("nEnter an integer (say -1 or 26 or so ): ");
  while( scanf("%d",&x) != 1 )
  {
    c=getchar();

    printf("You have entered ");
    putchar(c);
    printf(" in the input which is not an integer");

    while ( getchar() != 'n' )
     ; //wasting the buffer till the next new line

    printf("nEnter an integer (say -1 or 26 or so ): ");

  }

return x;
}


int main(void)
{
  int x;
  x=getint();

  printf("Main Function =>n");
  printf("Integer : %dn",x);

 return 0;
}

answered Mar 3, 2016 at 6:39

sjsam's user avatar

sjsamsjsam

21k5 gold badges53 silver badges98 bronze badges

1

I developed this logic using gets and away from scanf hassle:

void readValidateInput() {

    char str[10] = { '' };

    readStdin: fgets(str, 10, stdin);
    //printf("fgets is returning %sn", str);

    int numerical = 1;
    int i = 0;

    for (i = 0; i < 10; i++) {
        //printf("Digit at str[%d] is %cn", i, str[i]);
        //printf("numerical = %dn", numerical);
        if (isdigit(str[i]) == 0) {
            if (str[i] == 'n')break;
            numerical = 0;
            //printf("numerical changed= %dn", numerical);
            break;
        }
    }
    if (!numerical) {
        printf("This is not a valid number of tasks, you need to enter at least 1 taskn");
        goto readStdin;
    }
    else if (str[i] == 'n') {
        str[i] = '';
        numOfTasks = atoi(str);
        //printf("Captured Number of tasks from stdin is %dn", numOfTasks);
    }
}

answered Jul 19, 2016 at 17:48

Shaimaa Yehia's user avatar

1

printf("type a number ");
int converted = scanf("%d", &a);
printf("n");

if( converted == 0) 
{
    printf("enter integer");
    system("PAUSE n");
    return 0;
}

scanf() returns the number of format specifiers that match, so will return zero if the text entered cannot be interpreted as a decimal integer

answered Mar 4, 2017 at 16:28

Eduardo's user avatar

The way I worked around this question was using cs50.h library. So, the header goes:

#include <cs50.h>

There you have get_int function and you simply use it for variable initiation:

    int a = get_int("Your number is: "); 

If a user inputs anything but integer, output repeats the line «Your number is: «; and so on until the integer is being written.

answered Dec 26, 2022 at 16:23

Zed Pi's user avatar

I’ve been searching for a simpler solution using only loops and if statements, and this is what I came up with. The program also works with negative integers and correctly rejects any mixed inputs that may contain both integers and other characters.


#include <stdio.h>
#include <stdlib.h> // Used for atoi() function
#include <string.h> // Used for strlen() function

#define TRUE 1
#define FALSE 0

int main(void)
{
    char n[10]; // Limits characters to the equivalent of the 32 bits integers limit (10 digits)
    int intTest;
    printf("Give me an int: ");

    do
    {        
        scanf(" %s", n);

        intTest = TRUE; // Sets the default for the integer test variable to TRUE

        int i = 0, l = strlen(n);
        if (n[0] == '-') // Tests for the negative sign to correctly handle negative integer values
            i++;
        while (i < l)
        {            
            if (n[i] < '0' || n[i] > '9') // Tests the string characters for non-integer values
            {              
                intTest = FALSE; // Changes intTest variable from TRUE to FALSE and breaks the loop early
                break;
            }
            i++;
        }
        if (intTest == TRUE)
            printf("%in", atoi(n)); // Converts the string to an integer and prints the integer value
        else
            printf("Retry: "); // Prints "Retry:" if tested FALSE
    }
    while (intTest == FALSE); // Continues to ask the user to input a valid integer value
    return 0;
}

answered Oct 4, 2014 at 1:34

de3z1e's user avatar

de3z1ede3z1e

4014 silver badges8 bronze badges

1

Just check is your number has any difference with float version of it, or not.

float num; 
scanf("%f",&num);

if(num != (int)num) {
    printf("it's not an integer");
    return;
}

answered Aug 24, 2020 at 16:27

MohammadReza BeitSaeed's user avatar

This method works for everything (integers and even doubles) except zero (it calls it invalid):

The while loop is just for the repetitive user input. Basically it checks if the integer x/x = 1. If it does (as it would with a number), its an integer/double. If it doesn’t, it obviously it isn’t. Zero fails the test though.

#include <stdio.h> 
#include <math.h>

void main () {
    double x;
    int notDouble;
    int true = 1;
    while(true) {
        printf("Input an integer: n");
        scanf("%lf", &x);
        if (x/x != 1) {
            notDouble = 1;
            fflush(stdin);
        }
        if (notDouble != 1) {
            printf("Input is validn");
        }
        else {
            printf("Input is invalidn");
        }
        notDouble = 0;
    }
}

answered Jan 27, 2016 at 11:18

Danis Terzi's user avatar

1

I was having the same problem, finally figured out what to do:

#include <stdio.h>
#include <conio.h>

int main ()
{
    int x;
    float check;
    reprocess:
    printf ("enter a integer number:");
    scanf ("%f", &check);
    x=check;
    if (x==check)
    printf("nYour number is %d", x);
    else 
    {
         printf("nThis is not an integer number, please insert an integer!nn");
         goto reprocess;
    }
    _getch();
    return 0;
}

answered Nov 9, 2013 at 11:26

vtolentino's user avatar

vtolentinovtolentino

7245 silver badges14 bronze badges

2

I found a way to check whether the input given is an integer or not using atoi() function .

Read the input as a string, and use atoi() function to convert the string in to an integer.

atoi() function returns the integer number if the input string contains integer, else it will return 0. You can check the return value of the atoi() function to know whether the input given is an integer or not.

There are lot more functions to convert a string into long, double etc., Check the standard library «stdlib.h» for more.

Note : It works only for non-zero numbers.

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

int main() {
    char *string;
    int number;

    printf("Enter a number :");
    string = scanf("%s", string);

    number = atoi(string);

    if(number != 0)
        printf("The number is %dn", number);
    else
        printf("Not a number !!!n");
    return 0;
}

answered Nov 8, 2016 at 5:29

Rishi's user avatar

RishiRishi

135 bronze badges

1

The catch is that I cannot use atoi or any other function like that (I’m pretty sure we’re supposed to rely on mathematical operations).

 int num; 
 scanf("%d",&num);
 if(/* num is not integer */) {
  printf("enter integer");
  return;
 }

I’ve tried:

(num*2)/2 == num
num%1==0
if(scanf("%d",&num)!=1)

but none of these worked.

Any ideas?

The Archetypal Paul's user avatar

asked Nov 1, 2010 at 19:04

Gal's user avatar

6

num will always contain an integer because it’s an int. The real problem with your code is that you don’t check the scanf return value. scanf returns the number of successfully read items, so in this case it must return 1 for valid values. If not, an invalid integer value was entered and the num variable did probably not get changed (i.e. still has an arbitrary value because you didn’t initialize it).

As of your comment, you only want to allow the user to enter an integer followed by the enter key. Unfortunately, this can’t be simply achieved by scanf("%dn"), but here’s a trick to do it:

int num;
char term;
if(scanf("%d%c", &num, &term) != 2 || term != 'n')
    printf("failuren");
else
    printf("valid integer followed by enter keyn");

answered Nov 1, 2010 at 19:42

AndiDog's user avatar

AndiDogAndiDog

67.6k21 gold badges159 silver badges204 bronze badges

7

You need to read your input as a string first, then parse the string to see if it contains valid numeric characters. If it does then you can convert it to an integer.

char s[MAX_LINE];

valid = FALSE;
fgets(s, sizeof(s), stdin);
len = strlen(s);
while (len > 0 && isspace(s[len - 1]))
    len--;     // strip trailing newline or other white space
if (len > 0)
{
    valid = TRUE;
    for (i = 0; i < len; ++i)
    {
        if (!isdigit(s[i]))
        {
            valid = FALSE;
            break;
        }
    }
}

answered Nov 1, 2010 at 19:08

Paul R's user avatar

Paul RPaul R

206k35 gold badges381 silver badges549 bronze badges

8

There are several problems with using scanf with the %d conversion specifier to do this:

  1. If the input string starts with a valid integer (such as «12abc»), then the «12» will be read from the input stream and converted and assigned to num, and scanf will return 1, so you’ll indicate success when you (probably) shouldn’t;

  2. If the input string doesn’t start with a digit, then scanf will not read any characters from the input stream, num will not be changed, and the return value will be 0;

  3. You don’t specify if you need to handle non-decimal formats, but this won’t work if you have to handle integer values in octal or hexadecimal formats (0x1a). The %i conversion specifier handles decimal, octal, and hexadecimal formats, but you still have the first two problems.

First of all, you’ll need to read the input as a string (preferably using fgets). If you aren’t allowed to use atoi, you probably aren’t allowed to use strtol either. So you’ll need to examine each character in the string. The safe way to check for digit values is to use the isdigit library function (there are also the isodigit and isxdigit functions for checking octal and hexadecimal digits, respectively), such as

while (*input && isdigit(*input))
   input++;    

(if you’re not even allowed to use isdigit, isodigit, or isxdigit, then slap your teacher/professor for making the assignment harder than it really needs to be).

If you need to be able to handle octal or hex formats, then it gets a little more complicated. The C convention is for octal formats to have a leading 0 digit and for hex formats to have a leading 0x. So, if the first non-whitespace character is a 0, you have to check the next character before you can know which non-decimal format to use.

The basic outline is

  1. If the first non-whitespace character is not a ‘-‘, ‘+’, ‘0’, or non-zero decimal digit, then this is not a valid integer string;
  2. If the first non-whitespace character is ‘-‘, then this is a negative value, otherwise we assume a positive value;
  3. If the first character is ‘+’, then this is a positive value;
  4. If the first non-whitespace and non-sign character is a non-zero decimal digit, then the input is in decimal format, and you will use isdigit to check the remaining characters;
  5. If the first non-whitespace and non-sign character is a ‘0’, then the input is in either octal or hexadecimal format;
  6. If the first non-whitespace and non-sign character was a ‘0’ and the next character is a digit from ‘0’ to ‘7’, then the input is in octal format, and you will use isodigit to check the remaining characters;
  7. If the first non-whitespace and non-sign character was a 0 and the second character is x or X, then the input is in hexadecimal format and you will use isxdigit to check the remaining characters;
  8. If any of the remaining characters do not satisfy the check function specified above, then this is not a valid integer string.

answered Nov 1, 2010 at 20:19

John Bode's user avatar

John BodeJohn Bode

117k18 gold badges116 silver badges194 bronze badges

First ask yourself how you would ever expect this code to NOT return an integer:

int num; 
scanf("%d",&num);

You specified the variable as type integer, then you scanf, but only for an integer (%d).

What else could it possibly contain at this point?

answered Nov 1, 2010 at 19:38

abelenky's user avatar

abelenkyabelenky

62.8k22 gold badges108 silver badges158 bronze badges

3

If anyone else comes up with this question, i’ve written a program, that keeps asking to input a number, if user’s input is not integer, and finishes when an integer number is accepted

#include<stdlib.h>
#include<stdio.h>
#include<stdbool.h>

bool digit_check(char key[])
{
    for(int i = 0; i < strlen(key); i++)
    {
        if(isdigit(key[i])==0)
        {
            return false;
        }
    }
    return true;
}

void main()
{
    char stroka[10];
    do{
        printf("Input a number: ");
        scanf("%s",stroka);}
    while (!digit_check(stroka));
    printf("Number is accepted, input finished!n");
    system("pause");
}

answered May 28, 2021 at 17:03

user16062049's user avatar

I looked over everyone’s input above, which was very useful, and made a function which was appropriate for my own application. The function is really only evaluating that the user’s input is not a «0», but it was good enough for my purpose. Hope this helps!

#include<stdio.h>

int iFunctErrorCheck(int iLowerBound, int iUpperBound){

int iUserInput=0;
while (iUserInput==0){
    scanf("%i", &iUserInput);
    if (iUserInput==0){
        printf("Please enter an integer (%i-%i).n", iLowerBound, iUpperBound);
        getchar();
    }
    if ((iUserInput!=0) && (iUserInput<iLowerBound || iUserInput>iUpperBound)){
        printf("Please make a valid selection (%i-%i).n", iLowerBound, iUpperBound);
        iUserInput=0;
    }
}
return iUserInput;
}

answered Nov 2, 2014 at 17:53

Nick's user avatar

1

Try this…

#include <stdio.h>

int main (void)
{
    float a;
    int q;

    printf("nInsert numbert");
    scanf("%f",&a);

    q=(int)a;
    ++q;

    if((q - a) != 1)
        printf("nThe number is not an integernn");
    else
        printf("nThe number is an integernn");

    return 0;
}

Unihedron's user avatar

Unihedron

10.8k13 gold badges61 silver badges70 bronze badges

answered Nov 20, 2014 at 5:58

OscaRoCa's user avatar

1

This is a more user-friendly one I guess :

#include<stdio.h>

/* This program checks if the entered input is an integer
 * or provides an option for the user to re-enter.
 */

int getint()
{
  int x;
  char c;
  printf("nEnter an integer (say -1 or 26 or so ): ");
  while( scanf("%d",&x) != 1 )
  {
    c=getchar();

    printf("You have entered ");
    putchar(c);
    printf(" in the input which is not an integer");

    while ( getchar() != 'n' )
     ; //wasting the buffer till the next new line

    printf("nEnter an integer (say -1 or 26 or so ): ");

  }

return x;
}


int main(void)
{
  int x;
  x=getint();

  printf("Main Function =>n");
  printf("Integer : %dn",x);

 return 0;
}

answered Mar 3, 2016 at 6:39

sjsam's user avatar

sjsamsjsam

21k5 gold badges53 silver badges98 bronze badges

1

I developed this logic using gets and away from scanf hassle:

void readValidateInput() {

    char str[10] = { '' };

    readStdin: fgets(str, 10, stdin);
    //printf("fgets is returning %sn", str);

    int numerical = 1;
    int i = 0;

    for (i = 0; i < 10; i++) {
        //printf("Digit at str[%d] is %cn", i, str[i]);
        //printf("numerical = %dn", numerical);
        if (isdigit(str[i]) == 0) {
            if (str[i] == 'n')break;
            numerical = 0;
            //printf("numerical changed= %dn", numerical);
            break;
        }
    }
    if (!numerical) {
        printf("This is not a valid number of tasks, you need to enter at least 1 taskn");
        goto readStdin;
    }
    else if (str[i] == 'n') {
        str[i] = '';
        numOfTasks = atoi(str);
        //printf("Captured Number of tasks from stdin is %dn", numOfTasks);
    }
}

answered Jul 19, 2016 at 17:48

Shaimaa Yehia's user avatar

1

printf("type a number ");
int converted = scanf("%d", &a);
printf("n");

if( converted == 0) 
{
    printf("enter integer");
    system("PAUSE n");
    return 0;
}

scanf() returns the number of format specifiers that match, so will return zero if the text entered cannot be interpreted as a decimal integer

answered Mar 4, 2017 at 16:28

Eduardo's user avatar

The way I worked around this question was using cs50.h library. So, the header goes:

#include <cs50.h>

There you have get_int function and you simply use it for variable initiation:

    int a = get_int("Your number is: "); 

If a user inputs anything but integer, output repeats the line «Your number is: «; and so on until the integer is being written.

answered Dec 26, 2022 at 16:23

Zed Pi's user avatar

I’ve been searching for a simpler solution using only loops and if statements, and this is what I came up with. The program also works with negative integers and correctly rejects any mixed inputs that may contain both integers and other characters.


#include <stdio.h>
#include <stdlib.h> // Used for atoi() function
#include <string.h> // Used for strlen() function

#define TRUE 1
#define FALSE 0

int main(void)
{
    char n[10]; // Limits characters to the equivalent of the 32 bits integers limit (10 digits)
    int intTest;
    printf("Give me an int: ");

    do
    {        
        scanf(" %s", n);

        intTest = TRUE; // Sets the default for the integer test variable to TRUE

        int i = 0, l = strlen(n);
        if (n[0] == '-') // Tests for the negative sign to correctly handle negative integer values
            i++;
        while (i < l)
        {            
            if (n[i] < '0' || n[i] > '9') // Tests the string characters for non-integer values
            {              
                intTest = FALSE; // Changes intTest variable from TRUE to FALSE and breaks the loop early
                break;
            }
            i++;
        }
        if (intTest == TRUE)
            printf("%in", atoi(n)); // Converts the string to an integer and prints the integer value
        else
            printf("Retry: "); // Prints "Retry:" if tested FALSE
    }
    while (intTest == FALSE); // Continues to ask the user to input a valid integer value
    return 0;
}

answered Oct 4, 2014 at 1:34

de3z1e's user avatar

de3z1ede3z1e

4014 silver badges8 bronze badges

1

Just check is your number has any difference with float version of it, or not.

float num; 
scanf("%f",&num);

if(num != (int)num) {
    printf("it's not an integer");
    return;
}

answered Aug 24, 2020 at 16:27

MohammadReza BeitSaeed's user avatar

This method works for everything (integers and even doubles) except zero (it calls it invalid):

The while loop is just for the repetitive user input. Basically it checks if the integer x/x = 1. If it does (as it would with a number), its an integer/double. If it doesn’t, it obviously it isn’t. Zero fails the test though.

#include <stdio.h> 
#include <math.h>

void main () {
    double x;
    int notDouble;
    int true = 1;
    while(true) {
        printf("Input an integer: n");
        scanf("%lf", &x);
        if (x/x != 1) {
            notDouble = 1;
            fflush(stdin);
        }
        if (notDouble != 1) {
            printf("Input is validn");
        }
        else {
            printf("Input is invalidn");
        }
        notDouble = 0;
    }
}

answered Jan 27, 2016 at 11:18

Danis Terzi's user avatar

1

I was having the same problem, finally figured out what to do:

#include <stdio.h>
#include <conio.h>

int main ()
{
    int x;
    float check;
    reprocess:
    printf ("enter a integer number:");
    scanf ("%f", &check);
    x=check;
    if (x==check)
    printf("nYour number is %d", x);
    else 
    {
         printf("nThis is not an integer number, please insert an integer!nn");
         goto reprocess;
    }
    _getch();
    return 0;
}

answered Nov 9, 2013 at 11:26

vtolentino's user avatar

vtolentinovtolentino

7245 silver badges14 bronze badges

2

I found a way to check whether the input given is an integer or not using atoi() function .

Read the input as a string, and use atoi() function to convert the string in to an integer.

atoi() function returns the integer number if the input string contains integer, else it will return 0. You can check the return value of the atoi() function to know whether the input given is an integer or not.

There are lot more functions to convert a string into long, double etc., Check the standard library «stdlib.h» for more.

Note : It works only for non-zero numbers.

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

int main() {
    char *string;
    int number;

    printf("Enter a number :");
    string = scanf("%s", string);

    number = atoi(string);

    if(number != 0)
        printf("The number is %dn", number);
    else
        printf("Not a number !!!n");
    return 0;
}

answered Nov 8, 2016 at 5:29

Rishi's user avatar

RishiRishi

135 bronze badges

1

Как я могу проверить ввод пользователя с помощью scanf. Сейчас у меня что-то вроде этого есть, но не работает.

ПРИМЕЧАНИЕ: у меня есть atoi, чтобы убедиться, что проверка scanf работает.

scanf("%[0987654321.-]s",buf);

i = atoi(buf);

if(i)
    index = i;

person
Raúl Roa
  
schedule
19.01.2009
  
source
источник


Ответы (6)

Использование scanf() обычно является плохой идеей для пользовательского ввода, поскольку при сбое указатель FILE остается в неизвестной позиции. Это потому, что scanf означает «сканированное отформатированное», а неформатированных немного больше, чем вводимые пользователем.

Я бы предложил использовать fgets() для ввода строки, а затем sscanf() в строке, чтобы проверить и обработать ее.

Это также позволяет вам проверять строку на предмет тех символов, которые вам нужны (либо с помощью цикла, либо с помощью регулярного выражения), для чего семейство функций scanf не совсем подходит.

Например, использование scanf() с "%d" или "%f" остановится на первом нечисловом символе, поэтому конечные ошибки, такие как "127hello", не будут обнаружены, что даст вам просто 127. А использование его с неограниченным %s просто < em> умолять о переполнении буфера.

Если вам действительно необходимо использовать спецификатор формата []scanf или sscanf), я не думаю, что он должен сопровождаться s.

И для надежного решения ввода с использованием этого совета см. здесь. Если у вас есть строка ввода в виде строки, вы можете sscanf сколько душе угодно.

person
paxdiablo
  
schedule
19.01.2009

Кажется, вы хотите проверить строку как входную. Это зависит от того, хотите ли вы проверить, что ваша строка содержит значение типа double или int. Следующие проверки на двойное (разрешены начальные и конечные пробелы).

bool is_double(char const* s) {
    int n;
    double d;
    return sscanf(s, "%lf %n", &d, &n) == 1 && !s[n];
}

sscanf вернет преобразованные элементы (без «% n»). n будет установлено на количество обработанных входных символов. Если весь ввод был обработан, s [n] вернет завершающий символ 0. Пространство между двумя спецификаторами формата учитывает необязательные завершающие пробелы.

Следующие проверки на int используются те же методы:

bool is_int(char const* s) {
    int n;
    int i;
    return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}

Был вопрос об этом здесь, который включает также больше способов сделать это в C ++, например, использовать строковые потоки и функции из boost, такие как lexical_cast и так далее. Как правило, они должны быть предпочтительнее таких функций, как scanf, так как очень легко забыть передать какой-нибудь «%» в scanf или какой-либо адрес. scanf не распознает это, но вместо этого будет выполнять произвольные действия, в то время как lexical_cast, например, выдаст исключение, если что-то не так.

person
Johannes Schaub — litb
  
schedule
19.01.2009

Мой подход заключался бы в том, чтобы прочитать вводимые пользователем данные в строку, а затем преобразовать ее в long, используя strtol(). strtol() возвращает указатель на первый символ входной строки, которую он не смог обработать, поэтому, проверив этот символ, вы узнаете, была ли проанализирована вся строка, например:

char *string;
char *endptr;
long result;

scanf("%as", string);
errno = 0;
result = strtol(string, &endptr, 10);
if (ERANGE == errno)
    printf("Input number doesn't fit into longn");
else if (*endptr)
    printf("%s is not a valid long number - it contains invalid char %cn",
        string, *endptr);
else
    printf("Got %ldn", result);

В этом фрагменте scanf() указано автоматически выделять string достаточно большого размера с использованием модификатора формата «a» (это расширение GNU). Если вы не пользуетесь GNU, выделите string вручную и ограничьте максимальный размер в формате scanf().

Такой подход позволяет лучше обрабатывать ошибки.

person
qrdl
  
schedule
19.01.2009

В первом аргументе scanf вы указали спецификаторы преобразования. scanf попытается преобразовать ввод в формат, но иногда вы можете быть удивлены, с чем он будет соответствовать :)

Первая проверка, которую вы должны сделать, — это возвращаемое значение из scanf (оно даст вам количество совпадающих входных данных). Если вы не получили ожидаемое число, значит, вы знаете, что с вводом что-то не так. В вашем случае это должно быть 1.

if( scanf("%[0987654321.-]s", buf) == 1 )
{
      if( sanit_check( buf ) ) 
      {
      /* good input */
      }
      else
      {
      /* invalid input */
      }
}
else 
{
/* invalid input */
}

Кроме того, вам нужно будет самостоятельно проверить работоспособность конверсии, которую вы просили scanf сделать.

person
hhafez
  
schedule
19.01.2009

Если вы пытаетесь прочитать только число, используйте:

int i;
scanf( "%d", &i );

Если вам нужно выполнить более сложную проверку, вам придется сделать это самостоятельно. Scanf не сделает этого за вас.

person
SoapBox
  
schedule
19.01.2009

«buf» должен быть указателем. Похоже, вы переходите по значению.

person
prestomation
  
schedule
19.01.2009

Понравилась статья? Поделить с друзьями:
  • Проверить html код на ошибку
  • Причиной ошибки может быть защита от атак credssp
  • Проверить hdd на ошибки и исправить
  • Проверить esp ошибка
  • Проверить dns на ошибки