Форматированный ввод данных в Си — функция scanf
В то время как функция printf() осуществляет форматированный вывод данных, функция scanf() осуществляет их форматированный ввод. Это значит, что поступающие на ввод данные преобразуются соответственно указанному формату(ам) и записываются по адресу(ам) указанной(ых) переменной(ых):
scanf(строка_формата, адреса_переменных);
Причина, по которой в scanf() передаются адреса, а не значения переменных, очевидна. Функция scanf() должна изменять значения переменных тех функций, из которых вызывается. Единственный способ — это получить адреса областей памяти.
Спецификации, допустимые в строке формата, для scanf() почти идентичны тем, что были описаны для функции printf() .
Ввод чисел, символов и строк
Пример ввода-вывода целого и вещественного чисел, символа и строки:
int a; float b; char ch, str[30]; scanf("%d%f%c%s", &a, &b, &ch, str); printf("%d %.3f %c %s\n", a, b, ch, str);
45 34.3456y hello 45 34.346 y hello
Здесь при выполнении программы все данные были введены в одну строку. Разделителем между числами и строками является пробел, а также любой другой символ пустого пространства (например, ‘\n’). Однако при считывании символа, пробел учитывается как символ; чтобы этого не произошло, в примере букву записали сразу после числа. Данные можно было бы ввести, разделяя их переходом на новую строку (опять же при этом надо иметь ввиду, как считывается символ).
В строке формата функции scanf() между спецификациями вполне допустимо поставить пробелы: %d %f %c %s . Они никакой роли не сыграют. Понятно, что данные можно было получить и так:
scanf("%d", &a); scanf("%f", &b); scanf("%c", &ch); scanf("%s", str);
Обратите внимание, перед переменной str отсутствует знак амперсанда. В последующих уроках вы узнаете, что имя массива уже само по себе является ссылкой на массив (другими словами, str содержит адрес начала массива).
В функции scanf() в спецификации формата вещественных чисел не указывается точность представления числа. Запись типа %.3f или %.10lf приведет к невозможности получить вещественное число. Чтобы получить число типа double используют формат %lf , для long double ‒ %Lf .
Для целых чисел: длинное целое ‒ %ld , короткое целое ‒ %hd . Существуют спецификации для ввода восьмеричных и шестнадцатеричных чисел.
Функция scanf() возвращает количество удачно считанных данных; т.е. значение, возвращаемое функцией, можно проанализировать и таким образом узнать, корректно ли были введены данные. Например:
int a; double b; char ch, str[30]; ch = scanf("%d %lf %s", &a, &b, str); if (ch == 3) printf("%d %.3lf %s\n", a, b, str); else printf("Error input\n");
Обычные символы в строке формата
В строке формата scanf() допустимо использование обычных символов. В этом случае при вводе данных также должны вводиться и эти символы:
int a, b, c; scanf("%d + %d = %d", &a, &b, &c); printf("Your answer is %d\n", c); printf("The correct is %d\n", a+b);
В данном случае, когда программа выполняется, ввод должен выглядеть примерно так: 342+1024 = 1366. Знаки «+» и » lang»>% , но перед буквой формата звездочку * . В таком случае данные считываются, но никакой переменной не присваиваются. Это можно использовать, например, когда нет определенной уверенности в том, что поступит на ввод, с одной стороны, и нужды сохранять эти данные, с другой:
float arr[3]; int i; for(i = 0; i 3; i++) scanf("%*s %f", &arr[i]); printf("Sum: %.2f\n", arr[0]+arr[1]+arr[2]);
Здесь предполагается, что перед каждым числом будет вводиться строка, которую следует проигнорировать, например:
First: 23.356 Second: 17.285 Third: 32.457 Sum: 73.098
Использование «шаблонов»
Для функции scanf() есть пара спецификаций формата, отдаленно напоминающих шаблоны командной оболочки и др. Формат […] позволяет получить строку, содержащую любые символы, указанные в квадратных скобках. Как только на ввод поступает символ, не входящий в указанный набор, считывание данных прекращается. Формат [^…] , наоборот, помещает в строку символы, не входящие в указанный набор, до тех пор пока не встретит любой из указанных.
В примере ниже как только поступает не цифра, считывание ввода завершается. При этом если первый символ — не цифра, то в str вообще ничего не записывается:
char str[30]=""; scanf("%[0-9]", str); printf("%s\n", str);
А в этом случае строке будет присвоена последовательность символов до любого из указанных знаков препинания:
scanf("%[^;. ]", str); printf("%s\n", str);
one two three four five! one two three four five
Обратите внимание, что в примере выше в строку были записаны как символы пробелов, так и символ перехода на новую строку. Таким образом, если надо прочитать одну строку вместе с пробелами, можно использовать такой подход:
scanf("%[^'\n']", str);
Здесь в строку считываются все символы, кроме перехода на новую строку. Как только встречается этот символ ‒ ‘\n’ , запись данных в переменную прекращается.
Некоторые особенности и ограничения функции scanf
Как только поступают некорректные данные, функция scanf() завершает свою работу. В примере:
scanf("%d%f", &a, &b);
если переменной a попытаться присвоить символ или строку, что невозможно, то в переменную b потом уже не получится записать число. Можно предположить, что так будет надежнее:
scanf("%d", &a); scanf("%f", &b);
Вроде бы неудачное считывание a не должно оказывать никакого влияния на b , т.к. это уже иной вызов scanf() . Но не все так просто: при некорректном вводе данные остаются в буфере и пытаются «навязать» себя последующим вызовам scanf() . Поэтому при использовании scanf() надо думать о том, как в случае некорректного ввода очистить буфер. Например, это можно сделать так, как показано ниже, или путем использования специальных функций (здесь не рассматриваются):
// если данные не удалось присвоить, if (scanf("%d", &a) != 1) // то выбросить их в виде строки scanf("%*s"); scanf("%f", &b);
- На прошлом занятии вы написали программу, содержащую функции, вычисляющие факториал числа и заданный элемент ряда Фибоначчи. Измените эту программу таким образом, чтобы она запрашивала у пользователя, что он хочет вычислить: факториал или число Фибоначчи. Затем программа запрашивала бы у пользователя либо число для вычисления факториала, либо номер элемента ряда Фибоначчи.
- Напишите программу, которая запрашивает у пользователя две даты в формате дд.мм.гггг. Дни, месяцы и года следует присвоить целочисленным переменным. Программа должна выводить на экран информацию о том, какая дата более ранняя, а какая более поздняя.
- Используя цикл, напишите код, в котором пользователю предлагается вводить данные до тех пор, пока он не сделает это корректно, т.е. пока все указанные в scanf() переменные не получат свои значения. Протестируйте программу.
Курс с решением задач:
pdf-версия
Как сделать проверку на ввод символов
Если введено символ функция printf зацикливается при том что scanf не считывает значение с клавиатуры. Для компилации кода использую терминал в Linux Ubuntu.
Как сделать чтобы при ошибке можно было нормально ввести значение и продолжить работу программы? Полный пример функции.
int menu(void) < int casenum=0, counter = 0; char answerYes[] = "y", ans[10]; do < printf("+----------------------------------+\n"); printf("|0|Вихід |\n"); printf("|1|Ввести дані |\n"); printf("|2|Видалити запис |\n"); printf("|3|Видалити всі дані про місяць |\n"); printf("|4|Відсортувати за спадінням |\n"); printf("|5|Найменші витрати на харчування |\n"); printf("|6|Найбільші витрати на квартпліту |\n"); printf("|7|Витрати більші ніж зарплата |\n"); printf("+----------------------------------+\n"); scanf("%d", &casenum); while( casenum < 0 && casenum >7 ) < printf("Помилка! Ви ввели символ. Введіть ще раз.\n"); int c; while((c = getchar()) != '\n' && c != EOF); scanf("%d", &casenum); >switch (casenum) < case 0: return 0; break; case 1: add(); counter = 1; break; case 2: deleteAllDataMonth(); counter = 2; break; case 3: sorting(); counter = 3; break; case 4: minFootCosts(); counter = 4; break; case 5: maxCostsForRent(); counter = 5; break; case 6: spendingMoreThanSalary(); counter = 6; break; default: system("cls || clear"); printf("Ви ввели неістуючу команду!\n"); break; >> while (counter == 0); printf("\n\nБажаєте повернутися в меню або вийти з програми? (y/n)\n"); scanf("%s", ans); if (strcmp(ans, answerYes)==0) < system("cls || clear"); menu(); >else return 0; return 0; >
Здесь я исправил код, но проблема осталась. По идеи при вводе символа она должна выводить ошибку, но програма просто закрываеться.
Ввод только цифр при инициализации переменной в C/C++, запрет на ввод букв в консоли.
Наверняка многие сталкивались с крашем программы если произвести ввод букв при инициализации переменной типа int. Для выполнения проверки нам потребуется следующая конструкция:
do < res = scanf("%d", & n); while (getchar() != '\n'); if (res == 1) printf("%s", "Хорошо!\n"); else printf("%s", "Плохо:(\n"); >while (res != 1);
*Не забудьте объявить переменную res (int res;)
Теперь при вводе любых символов кроме цифр в консоли будет выводиться «Плохо:(«, а с помощью цикла будет запрашиваться повторный ввод. При правильном вводе (только цифр) выведется «Хорошо!».
Вот так должно получиться:

Если остались вопросы — задавайте в комментариях.
Подпишись если хочешь
Enter your email

2 команды для очистки места в Ubuntu
Хотите почистить место на вашем VPS или домашнем компьютере с Ubuntu? Начните с кэша apt-get, journalctl! За годы использования он копится гигабайтами. Очистить кэш apt-get Проверить сколько занимает места: sudo du -csh /var/cache/apt Очистить кэш: sudo apt-get clean Очистить кэш journalctl Проверить сколько занимают места логи: sudo journalctl
17 дек. 2023 г. 1 min read

Как проверить износ SSD диска MacBook
Для того чтобы проверить износ диска потребуется выполнить 3 команды в терминале: 1. установить Homebrew 2. установить smartmontools 3. выполнить команду проверки. Делов на 5 минут. Установка Homebrew Если у вас еще не установлен Homebrew – зря. Это удобная утилита для установки пакетов в MacOS. Для установки выполните в терминале: /bin/
4 дек. 2023 г. 1 min read

Arc браузер будущего?
Пару недель назад бороздил просторы интернета и наткнулся на новый браузер под названием Arc. Есть ощущение, что Google Chrome мне больше не нужен. В данный момент Arc доступен на двух платформах: MacOS, iOS. Версии для Windows, Android обещают добавить позже Откуда появился The Browser Company – стартап, который собрал более 17
Как реализовать проверку на вводимые символы?
Есть участок кода, в котором я ожидаю от пользователя подтверждения в виде ‘Y’/’y’ или ‘N’/’n’. Перепробовал кучу вариантов, от getch до scanf() совместно с fflush(stdio) в разных циклах и их комбинациях. И всегда программа частично работает, но с подвохом. В частности: в нижеприведенной реализации я хоть и добился того, что проверка реагирует на ‘Y’/’y’ или ‘N’/’n’, но делать она это может, например, и при вот таком вводе: «polniyBred». (наткнулась на y в 6 позиции). Честное слово, я прекрасно понимаю, что проблема во мне, что я не совсем соображаю уже в 2 часа ночи, что я не знаю и 10% функций стандартной библиотеки. Поэтому прошу сжалиться и показать, как канонично пишутся такого рода проверки и пользовательские диалоги, избегая по возможности костылей и изоленты. Вы же все сталкивались с такими программами, которые не позволяют вам ввести чушь.
void usrSettings(struct usrSettings_str **usrSet) < char consent; printf("Before changing the settings, read the command manual .help\n"); printf("Are you sure? (Y/y(for 'Yes') or N/n(for 'No' - setting by default)\n"); scanf("%c", &consent); while(consent != 'Y' && consent != 'y' && consent != 'N' && consent != 'n')< printf("Enter Y/y or N/n\n"); printf(">"); scanf("%c", &consent); > if (consent == ('Y' || 'y')); < //Edit somethings settings printf("User enter Yes\n"); >if (consent == ('N' || 'n')) < //Return to main menu printf("User enter NO\n"); >>
В общих чертах, я понимаю, что решение должно быть банальным, но чем дольше я копаю, тем сильнее зарываюсь. Вот, например, scanf() отработала в цикле 4 раза (видать, брала символы из буферизированного ввода), до тех пор, пока не повстречала ‘y’. (скриншот 3).
Скриншот 1 (Казалось бы. )

Скриншот 2 (Вот тут начинается)

Скриншот 3 (Полный абзац!)

- Вопрос задан более трёх лет назад
- 1519 просмотров
1 комментарий
Простой 1 комментарий
Как сделать проверку на ввод символов
Если введено символ функция printf зацикливается при том что scanf не считывает значение с клавиатуры. Для компилации кода использую терминал в Linux Ubuntu.
Как сделать чтобы при ошибке можно было нормально ввести значение и продолжить работу программы? Полный пример функции.
int menu(void) < int casenum=0, counter = 0; char answerYes[] = "y", ans[10]; do < printf("+----------------------------------+\n"); printf("|0|Вихід |\n"); printf("|1|Ввести дані |\n"); printf("|2|Видалити запис |\n"); printf("|3|Видалити всі дані про місяць |\n"); printf("|4|Відсортувати за спадінням |\n"); printf("|5|Найменші витрати на харчування |\n"); printf("|6|Найбільші витрати на квартпліту |\n"); printf("|7|Витрати більші ніж зарплата |\n"); printf("+----------------------------------+\n"); scanf("%d", &casenum); while( casenum < 0 && casenum >7 ) < printf("Помилка! Ви ввели символ. Введіть ще раз.\n"); int c; while((c = getchar()) != '\n' && c != EOF); scanf("%d", &casenum); >switch (casenum) < case 0: return 0; break; case 1: add(); counter = 1; break; case 2: deleteAllDataMonth(); counter = 2; break; case 3: sorting(); counter = 3; break; case 4: minFootCosts(); counter = 4; break; case 5: maxCostsForRent(); counter = 5; break; case 6: spendingMoreThanSalary(); counter = 6; break; default: system("cls || clear"); printf("Ви ввели неістуючу команду!\n"); break; >> while (counter == 0); printf("\n\nБажаєте повернутися в меню або вийти з програми? (y/n)\n"); scanf("%s", ans); if (strcmp(ans, answerYes)==0) < system("cls || clear"); menu(); >else return 0; return 0; >
Здесь я исправил код, но проблема осталась. По идеи при вводе символа она должна выводить ошибку, но програма просто закрываеться.
Ввод только цифр при инициализации переменной в C/C++, запрет на ввод букв в консоли.
Наверняка многие сталкивались с крашем программы если произвести ввод букв при инициализации переменной типа int. Для выполнения проверки нам потребуется следующая конструкция:
do < res = scanf("%d", & n); while (getchar() != '\n'); if (res == 1) printf("%s", "Хорошо!\n"); else printf("%s", "Плохо:(\n"); >while (res != 1);
*Не забудьте объявить переменную res (int res;)
Теперь при вводе любых символов кроме цифр в консоли будет выводиться «Плохо:(«, а с помощью цикла будет запрашиваться повторный ввод. При правильном вводе (только цифр) выведется «Хорошо!».
Вот так должно получиться:

Если остались вопросы — задавайте в комментариях.
Подпишись если хочешь
Enter your email

2 команды для очистки места в Ubuntu
Хотите почистить место на вашем VPS или домашнем компьютере с Ubuntu? Начните с кэша apt-get, journalctl! За годы использования он копится гигабайтами. Очистить кэш apt-get Проверить сколько занимает места: sudo du -csh /var/cache/apt Очистить кэш: sudo apt-get clean Очистить кэш journalctl Проверить сколько занимают места логи: sudo journalctl
17 дек. 2023 г. 1 min read

Как проверить износ SSD диска MacBook
Для того чтобы проверить износ диска потребуется выполнить 3 команды в терминале: 1. установить Homebrew 2. установить smartmontools 3. выполнить команду проверки. Делов на 5 минут. Установка Homebrew Если у вас еще не установлен Homebrew – зря. Это удобная утилита для установки пакетов в MacOS. Для установки выполните в терминале: /bin/
4 дек. 2023 г. 1 min read

Arc браузер будущего?
Пару недель назад бороздил просторы интернета и наткнулся на новый браузер под названием Arc. Есть ощущение, что Google Chrome мне больше не нужен. В данный момент Arc доступен на двух платформах: MacOS, iOS. Версии для Windows, Android обещают добавить позже Откуда появился The Browser Company – стартап, который собрал более 17
Форматированный ввод данных в Си — функция scanf
В то время как функция printf() осуществляет форматированный вывод данных, функция scanf() осуществляет их форматированный ввод. Это значит, что поступающие на ввод данные преобразуются соответственно указанному формату(ам) и записываются по адресу(ам) указанной(ых) переменной(ых):
scanf(строка_формата, адреса_переменных);
Причина, по которой в scanf() передаются адреса, а не значения переменных, очевидна. Функция scanf() должна изменять значения переменных тех функций, из которых вызывается. Единственный способ — это получить адреса областей памяти.
Спецификации, допустимые в строке формата, для scanf() почти идентичны тем, что были описаны для функции printf() .
Ввод чисел, символов и строк
Пример ввода-вывода целого и вещественного чисел, символа и строки:
int a; float b; char ch, str[30]; scanf("%d%f%c%s", &a, &b, &ch, str); printf("%d %.3f %c %s\n", a, b, ch, str);
45 34.3456y hello 45 34.346 y hello
Здесь при выполнении программы все данные были введены в одну строку. Разделителем между числами и строками является пробел, а также любой другой символ пустого пространства (например, ‘\n’). Однако при считывании символа, пробел учитывается как символ; чтобы этого не произошло, в примере букву записали сразу после числа. Данные можно было бы ввести, разделяя их переходом на новую строку (опять же при этом надо иметь ввиду, как считывается символ).
В строке формата функции scanf() между спецификациями вполне допустимо поставить пробелы: %d %f %c %s . Они никакой роли не сыграют. Понятно, что данные можно было получить и так:
scanf("%d", &a); scanf("%f", &b); scanf("%c", &ch); scanf("%s", str);
Обратите внимание, перед переменной str отсутствует знак амперсанда. В последующих уроках вы узнаете, что имя массива уже само по себе является ссылкой на массив (другими словами, str содержит адрес начала массива).
В функции scanf() в спецификации формата вещественных чисел не указывается точность представления числа. Запись типа %.3f или %.10lf приведет к невозможности получить вещественное число. Чтобы получить число типа double используют формат %lf , для long double ‒ %Lf .
Для целых чисел: длинное целое ‒ %ld , короткое целое ‒ %hd . Существуют спецификации для ввода восьмеричных и шестнадцатеричных чисел.
Функция scanf() возвращает количество удачно считанных данных; т.е. значение, возвращаемое функцией, можно проанализировать и таким образом узнать, корректно ли были введены данные. Например:
int a; double b; char ch, str[30]; ch = scanf("%d %lf %s", &a, &b, str); if (ch == 3) printf("%d %.3lf %s\n", a, b, str); else printf("Error input\n");
Обычные символы в строке формата
В строке формата scanf() допустимо использование обычных символов. В этом случае при вводе данных также должны вводиться и эти символы:
int a, b, c; scanf("%d + %d = %d", &a, &b, &c); printf("Your answer is %d\n", c); printf("The correct is %d\n", a+b);
В данном случае, когда программа выполняется, ввод должен выглядеть примерно так: 342+1024 = 1366. Знаки «+» и » lang»>% , но перед буквой формата звездочку * . В таком случае данные считываются, но никакой переменной не присваиваются. Это можно использовать, например, когда нет определенной уверенности в том, что поступит на ввод, с одной стороны, и нужды сохранять эти данные, с другой:
float arr[3]; int i; for(i = 0; i 3; i++) scanf("%*s %f", &arr[i]); printf("Sum: %.2f\n", arr[0]+arr[1]+arr[2]);
Здесь предполагается, что перед каждым числом будет вводиться строка, которую следует проигнорировать, например:
First: 23.356 Second: 17.285 Third: 32.457 Sum: 73.098
Использование «шаблонов»
Для функции scanf() есть пара спецификаций формата, отдаленно напоминающих шаблоны командной оболочки и др. Формат […] позволяет получить строку, содержащую любые символы, указанные в квадратных скобках. Как только на ввод поступает символ, не входящий в указанный набор, считывание данных прекращается. Формат [^…] , наоборот, помещает в строку символы, не входящие в указанный набор, до тех пор пока не встретит любой из указанных.
В примере ниже как только поступает не цифра, считывание ввода завершается. При этом если первый символ — не цифра, то в str вообще ничего не записывается:
char str[30]=""; scanf("%[0-9]", str); printf("%s\n", str);
А в этом случае строке будет присвоена последовательность символов до любого из указанных знаков препинания:
scanf("%[^;. ]", str); printf("%s\n", str);
one two three four five! one two three four five
Обратите внимание, что в примере выше в строку были записаны как символы пробелов, так и символ перехода на новую строку. Таким образом, если надо прочитать одну строку вместе с пробелами, можно использовать такой подход:
scanf("%[^'\n']", str);
Здесь в строку считываются все символы, кроме перехода на новую строку. Как только встречается этот символ ‒ ‘\n’ , запись данных в переменную прекращается.
Некоторые особенности и ограничения функции scanf
Как только поступают некорректные данные, функция scanf() завершает свою работу. В примере:
scanf("%d%f", &a, &b);
если переменной a попытаться присвоить символ или строку, что невозможно, то в переменную b потом уже не получится записать число. Можно предположить, что так будет надежнее:
scanf("%d", &a); scanf("%f", &b);
Вроде бы неудачное считывание a не должно оказывать никакого влияния на b , т.к. это уже иной вызов scanf() . Но не все так просто: при некорректном вводе данные остаются в буфере и пытаются «навязать» себя последующим вызовам scanf() . Поэтому при использовании scanf() надо думать о том, как в случае некорректного ввода очистить буфер. Например, это можно сделать так, как показано ниже, или путем использования специальных функций (здесь не рассматриваются):
// если данные не удалось присвоить, if (scanf("%d", &a) != 1) // то выбросить их в виде строки scanf("%*s"); scanf("%f", &b);
- На прошлом занятии вы написали программу, содержащую функции, вычисляющие факториал числа и заданный элемент ряда Фибоначчи. Измените эту программу таким образом, чтобы она запрашивала у пользователя, что он хочет вычислить: факториал или число Фибоначчи. Затем программа запрашивала бы у пользователя либо число для вычисления факториала, либо номер элемента ряда Фибоначчи.
- Напишите программу, которая запрашивает у пользователя две даты в формате дд.мм.гггг. Дни, месяцы и года следует присвоить целочисленным переменным. Программа должна выводить на экран информацию о том, какая дата более ранняя, а какая более поздняя.
- Используя цикл, напишите код, в котором пользователю предлагается вводить данные до тех пор, пока он не сделает это корректно, т.е. пока все указанные в scanf() переменные не получат свои значения. Протестируйте программу.
Курс с решением задач:
pdf-версия
Как сделать проверку на ввод символов в c
Здравствуйте. У меня вопрос. Как можно организовать в языке Си проверку на ввод числа т.е. если мы введем букву или иные символы вместо числа то должно выдать ошибку.
Заранее спасибо.
| Snifer1994 |
| Посмотреть профиль |
| Найти ещё сообщения от Snifer1994 |
Белик Виталий 🙂
Регистрация: 23.07.2007
Сообщений: 57,792
Переведи строку в число. Если функция перевода вернет ошибку значит нужно уведомить пользователя. Функций перевода в число множество — выбирай какая по вкусу из хелпа своего компилятора..
I’m learning to live.
Регистрация: 14.08.2012
Сообщений: 3
Не знаю по поводу перевода строки в число. А нету способа полегче?
Вот нашел на просторах интернета этот способ но не могу понять как он работает?
Сможет кто нибудь объяснить принцип его работы.
void main()
| Snifer1994 |
| Посмотреть профиль |
| Найти ещё сообщения от Snifer1994 |
Белик Виталий 🙂
Регистрация: 23.07.2007
Сообщений: 57,792
Эта функция умеет возвращать в качестве результата код ошибки, если введенное нельзя сравнить с шаблоном формата. Короче если введенное не является числом по формату %d (т.е. не целое) то выдать ошибку.
Можно и так, если scanf-ом не брезгуешь.
I’m learning to live.