Считывание одного символа с консоли [закрыт]
Нострадамлю :), что перед этим где-то было считывание в духе scanf(«%d» без сброса после этого буфера ввода, так что в нем остался \n , который и считывается следующим scanf .
Проверьте, сбросили ли вы буфер ( fflush тут ни при чем, если что), и если нет — попробуйте сбросить.
Ну, и второй вариант — неверная кодировка, если вы именно русские символы читаете.
По совету @AndrejLevkovitch: сброс буфера — это считать остаток строки в никуда 🙂 — например,
for(int c = getchar (); c != '\n' && c != EOF; c = getchar ());
Отслеживать
ответ дан 30 дек 2017 в 14:42
219k 15 15 золотых знаков 119 119 серебряных знаков 230 230 бронзовых знаков
Добавлю, что после какого-либо ввода, после которого нужно считать символы, лучше добовлять код: while (getchar () != ‘\n’) continue;
31 дек 2017 в 5:55
@AndrejLevkovitch Так это и есть сброс буфера ввода.
31 дек 2017 в 7:05
Я так думаю, что лучше привести код — если он не знает, что в буфере остаются непрочтенные символы, то межет и не знает как их пропустить.
31 дек 2017 в 8:02
Обычно ввод с клавиатуры приходит в программу построчно. В Си нет стандартного переносимого способа прочитать один символ с консоли, не дожидаясь Enter клавиши. comp.lang.c FAQ: How can I read a single character from the keyboard without waiting for the RETURN key?
Другими словами: getchar() не вернётся пока ‘\n’ не встретится (что может произойти после ввода многих многих символов). Чтобы не дожидаясь новой строки прочитать один символ из Windows консоли, можно _getche() / _getwche() из conio.h использовать.
На Unix, необходимо изменить режим терминала, чтобы посимвольный ввод получать и самостоятельно восстановить предыдущие настройки при выходе из программы. К примеру, используя curses библиотеку, можно cbreak режим использовать:
#include #include int main() < initscr(); cbreak(); // change terminal mode to accept a char at a time // get answer int c; do < mvaddstr(0, 0, "Are you sure? (Y)es/(N)o: "); c = getch(); c = toupper((unsigned char)c); >while (c != 'Y' && c != 'N'); endwin(); // restore terminal settings return c == 'N'; >
$ cc *.c -lcurses && ./a.out && echo yes || echo no
Как считать с консоли c
Для ввода данных в консоли может использоваться функция scanf() . Эта функция определена в заголовочном файле stdio.h (там же, где и функция printf) и имеет следующее формальное определение:
scanf(форматная_строка, аргументы)
И форматная_строка, и аргументы для функции scanf обязательны.
Форматная_строка содержит спецификации преобразования, которые определяют вводимые данные. Общий вид спецификаций преобразования:
% * ширина_поля модификатор спецификатор
Из этих элементов обязательны только два: знак процента % и спецификатор.
Спецификатор определяет тип вводимых данных:
- %c : считывает один символ
- %d : считывает десятичное целое число
- %i : считывает целое число в любой системе (десятичной, шестнадцатеричной, восьмеричной)
- %u : считывает положительное целое число
- %e : считывает число с плавающей точкой в экспоненциальной форме
- %E : считывает число с плавающей точкой в экспоненциальной форме с заглавным символом экспоненты
- %f : считывает число с плавающей точкой
- %F : считывает число с плавающей точкой
- %g : считывает число с плавающей точкой
- %G : считывает число с плавающей точкой
- %o : считывает восьмеричное число
- %x : считывает шестнадцатеричное число
- %X : считывает шестнадцатеричное число
- %s : считывает строку
- %% : считывает символ процента
Символ звездочки * в спецификации преобразования позволяет пропустить при вводе водимые символы для типа, указанного через спецификатор.
Ширина_поля представляет целое положительное число, которое позволяет определить, какое количество байтов будет учитываться при вводе.
Модификаторы позволяют конкретизировать тип данных. В частности, есть следующие модификаторы:
- h : для ввода значений типа short int ( %hd )
- l : для ввода значений типа long int ( %ld ) или double ( %lf , %le )
- L : для ввода значений типа long double ( %Lf , %Le )
В качестве аргументов в функцию scanf() передаются адреса переменной, которая будет получать введенное значение. Для получения адреса переменной перед ее именем ставится знак амперсанда & . Например, если переменная называется age , то ее адрес мы можем получить с помощью выражения &age .
Например, введем с консоли числовое значение:
#include int main(void)
Здесь вводится значение для переменной age, которая представляет тип int , поэтому в форматную строку в функции scanf передается спецификатор %d . Здесь не используется ни символ звездочки, ни ширина поля, ни модификаторы. Вторым параметром идет адрес переменной age — &age .
После ввода значения мы можем его использовать, например, вывести на консоль:
Input your age:44 age = 44
Аналогичен будет ввод данных других типов:
#include int main(void)
После ввода значения мы можем его использовать, например, вывести на консоль:
Enter the product code: 1234 Enter the price: 234.567 Product code: 1234 price: 234.57
Можно сразу вводить несколько значений. В этом случае в качестве разделителя используется пробел:
#include int main(void)
При вводе данных в консоли функция scanf может использовать пробелы в качестве разделителей, чтобы выдернуть из ввода значения для определенных переменных. Консольный ввод-вывод:
Enter product data: 1234 3 234.56 Product code: 1234 count: 3 price: 234.56
Ввод строк
Функция scanf() также позволяет вводить строки. Например:
#include int main(void) < char name[10]; // вводим имя printf("Enter your name: "); scanf("%10s", name); printf("Name: %s \n",name); return 0; >
Здесь для имени выделяется 10 символов. Теоретически мы можем ввести и большее количество символов, но чтобы только 10 из них учитывались, в строку форматирования передается ширина поля, которая представляет 10 символов — %10s . Когда функция считает достаточное количетсво символов, она прекратит считывание.
Обратите внимание, что для ввода строки перед названием переменной не указывается символ адреса.
scanf("%10s", name);
Потому что название массива уже само по себе представляет адрес на первый элемент массива.
Возможный консольный вывод:
Enter your name: Tom Name: Tom
Однако при использовании этой функции мы можем столкнуться с рядом проблем. Прежде всего попробуйте ввести в предыдущем примере составное имя, в которм подстроки разделены пробелами, например, «Tom Smith».
Enter your name: Tom Smith Name: Tom
Для решения этой проблемы можно использовать один хак:
#include int main(void)
Спецификатор %10[^\n] указавает, что мы по прежнему считываем неболее 10 символов. Квадратные скобки [] представляют позволяют определить набор символов, которые будут извлекаться из ввода или, наоборот, игнорироваться. Так, выражение [^\n] говорит, что надо считать ввод до тех пор пока не встретиться символ перевода строки ‘\n’, то есть пока пользователь не нажмет на клавишу Enter.
Как считать с консоли c
При запуске программы на Си автоматически открываются ряд потоков, основными из которых являются следующие:
- Стандартный поток ввода stdin
- Стандартный поток вывода stdout
- Стандартный поток вывода сообщений об ошибках stderr
Стандартный поток ввода stdin по умолчанию соответствует клавиатуре, а потоки stdout и stderr — экрану монитора.
Для управления вводом-выводом с помощью этих потоков используются ряд функций:
- getchar() : ввод с клавиатуры одного символа
- putchar() : вывод на консоль одного символа
- fgets() : ввод одной строки
- puts() / fputs() : вывод одной строки на консоль
- scanf() : ввод с консоли с форматированием данных
- sscanf() : ввод с из строки с форматированием данных
- printf() : вывод с форматированием данных
Функции printf и scanf уже рассматривались ранее, поэтому посмотрим, как применять остальные функции.
Ввод и вывод символов
Для ввода и вывода символа применяются функции getchar() и putchar() . Но следует сказать, что на самом деле они полноценными функциями не являются, а определены как макросы в заголовочном файле stdio.h :
#define getchar() getc(stdin) #define putchar(c) putc((c), stdout)
Вывод символа
Для вывода отдельного символа на консоль предназначена функция putchar() со следующим прототипом:
int putchar(int c);
Выводимый символ в виде числового кода передается в putchar в качестве параметра, он же возвращается функцией.
#include int main(void) < char c = 'A'; putchar(c); // Выводим символ A >
Ввод символа
Для ввода одного символа с клавиатуры применяется функция getchar() , которая имеет следующий прототип:
int getchar(void);
В качестве результата функция возвращает числовой код введенного символа.
При использовании функции getchar следует учитывать, что при печати текста посредством клавиатуры в буфер операционной системы заносятся коды печатаемых символов, а сами символы отображаются на экране. Поучение программой введенного символа из буфера производится с помощью нажатия клавиши Enter.
И если буфер операционной системы не пуст, то при вызове функции getc() она получает очередной символ из буфера. Если же буфер пуст, то происходит чтение байта из потока ввода с помощью системной функции, название которой зависит от операционной системы.
При этом при нажатии клавиши Enter, в буфер также помещается код этой клавиши. То есть если мы введем один символ и нажмем на Enter, в буфере окажутся два числовых кода — введенного символа и клавиши Enter. И это надо учитывать при работе с функцией getchar. В частости, рассмотрим простой, но показательный пример:
#include int main(void) < printf("1"); getchar(); // ожидание ввода символа printf("2"); getchar(); // ожидание ввода символа printf("3"); return 0; >
Сначала на экран выводится цифра 1, после чего функция getchar ожидает ввода символа. Если после ввода символа мы нажмем Enter, то в буфер будет помещены два числовых кода — введеного символа и клавиши Enter. Поэтому при втором вызове getchar эта функция считывает байт из буфера — то есть числовой код клавиши Enter.
Например, введем при первом вызове функции getchar символ «a», а затем Enter:
1a 23
Но если при каждом вызове getchar мы будем только нажимать клавишу Enter, тогда в буфер будет заноситься только код этой клавиши, и соответственно программа будет работать, как и ожидалось:
1 2 3
Применим функции getchar и putchar для ввода и вывода символов с клавиатуры:
#include int main(void) < int c; while((c=getchar())!=EOF) < putchar(c); >return 0; >
Функция getchar() считывает числовой код символа, который потом выводится в функции putchar() . Для вывода из программы необходимо ввести комбинацию клавиш Ctrl+C.
Ввод и вывод строк
Вывод строк и puts
Для вывода одной строки на консоль предназначена функция puts() со следующим прототипом:
int putchar(char *s);
В качестве параметра передается указатель на строку, а возвращаемым результатом функции является последний выведенный символ.
При этом функция puts() будет выводить символы переданной строки, пока не дойдет до нулевого символа ‘\0’. Если же выводимый массив символов не содержит этого символа, то результат программы неопределен. Например:
#include int main(void) < puts("Hello World"); // выводим строковый литерал char* name = "Hello Metanit.com"; puts(name); // выводим значение переменной return 0; >
Hello World Hello Metanit.com
Вывод строк и fputs
Функция fputs() также записывает в поток вывода строку, то есть набор символов, который завершается символом ‘\0’. При записи строки нулевой символ ‘\0’ не записывается. Она имеет следующий прототип:
int fputs(const char *s, FILE *stream);
Первый параметр функции — записываемая строка, а второй — указатель на поток вывода. В качестве результата функция возвращает неотрицательное целое число. При ошибках в процессе записи возвращается значение EOF .
Применим функцию для записи в стандартный поток вывода, то есть на консоль. В этом случае в качестве второго параметра надо передать значение stdout :
#include int main(void)
Ввод строк и fgets
Для ввода строки с клавиатуры применяется функция fgets() , которая имеет следующий прототип:
char *fgets(char *str, int count, FILE *stream);
- char *str : строка, в которую производится считывание.
- int count : сколько символов необходимо считывать.
- FILE *stream : файловый поток, из которого производится считывание. В качестве потока ввода может выступать и консольный ввод.
Функция fgets() прекращает считывание, когда пользователь нажимает клавишу ENTER, то есть когда в поток добавляется символ перевода строки.
Рассмотрим считывание строки с консоли. Для этого в качестве третьего параметра в функцию передается значение stdin :
#include #define MAX 15 int main(void)
Здесь функция fgets считывает не более 15 символов в строку name, а В реальности функция предложит ввести 14 символов, так как последний символ зарезервирован для нулевого символа ‘\0’. Если будет введено больше символов, то fgets все равно считает не более 15 символов. Таким образом функция позволяет проверить количество считываемых символов и поэтому считается безопасной.
Пример работы программы:
Enter name: Tom Smith Your name: Tom Smith
Стоит отметить, что функция fgets() возвращает указатель char * — указатель на буфер, в который считаны данные. В реальности это тот же самый буфер, который передавался в качестве первого параметра, то есть в примере выше — это массив name. Однако этот результат может нам пригодится для проверки успешности выполнения функции — если считывание прошло неудачно, то функция возвращает NULL :
#include #define MAX 15 int main(void) < char name[MAX]; printf("Enter name: "); if(fgets(name, MAX, stdin) != NULL) // if(fgets(name, MAX, stdin)) - можно сократить < printf("Your name: %s\n", name); >else < printf("Critical Error. "); >return 0; >
Для эмуляции ошибки можно передать в функцию вторым параметром число 0.
fgets и scanf
При использовании функции fgets() после функции scanf() мы можем столкнуться с некорректным вводом:
#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >
В данном случае сначала с помощью функции scanf() считываем число в переменную age. После этого считываем имя — строку с помощью функции fgets() в переменную name. Но посмотрим, какой будет результат работы программы:
Input age: 39 Input name: Age: 39Name:
В данном случае мы видим, что ввод имени с помощью fgets вроде как пропускается. По крайней мере мы не можем ввести имя, а программа сразу же выводит результат.
Все дело в том, что функция scanf() считывает именно то, что ей предписано — число в виде переменной типа int. Все остальные символы остаются в буфере, в который предварительно попадают введенные с клавиатуры символы. Так, после ввода возраста мы нажимаем на клавишу Enter, и в буфер попадает символ «\n», то есть перевод строки. И fgets считывает этот символ из буфера, после чего ввод имени завершается. Очевидно, это не то поведение, на которое мы рассчитывали.
Чтобы исправить ситуацию, мы можем использовать различные хаки. Рассмотрим пару из них. Все они сводятся к тому, чтобы вынуть из буфера этот символ перевода строки.
Первый способ — считывание символа с помощью вызова scanf(«%*c») :
#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); scanf("%*c"); // вытаскиваем символ из буфера // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >
Второй способ — мы можем считать символ с помощью getchar() :
#include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); getchar(); // вытаскиваем символ из буфера // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >
Результат работы программы:
Input age: 39 Input name: Tom Age: 39 Name: Tom
Как считать из консоли string и int?
В консоль вводится String и Int через пробел, но на месте Int может ничего не быть как это считать?
- Вопрос задан более трёх лет назад
- 408 просмотров
Комментировать
Решения вопроса 1

Roman @myjcom Куратор тега C++
но на месте Int может ничего не быть как это считать?
std::optional
#include #include #include #include #include using namespace std; auto try_parse(const string& s) -> tuple> < string sval; optionalival; auto is = istringstream(s); is >> sval; if(isdigit(s.back())) < int i = 0; is >> i; ival = i; > return ; > int main() < string line; getline(cin, line); auto [sval, ival] = try_parse(line); cout cin.get(); >
Ответ написан более трёх лет назад