При выполнении последнего упражнения в главе 7, столкнулся с проблемой считывания строки ввода, если в ней встречается перевод строки. Везде это объясняется несколько заумно, попробую на пальцах:
Проблема в том, что когда вы вводите с клавиатуры в scanf
любой ввод — помимо символов (букв, цифр и проч) — вы также _всегда_ отправляете во входящий поток символ /n
— то бишь перевод строки.
К примеру, в программе стоит оператор scanf ("%c", &n);
Вы нажимаете на клавиатуре клавишу q
, а затем клавишу Enter
, чтобы отправить значение в программу…
Что при этом оказывается в программе? Логично предположить, что там теперь будет только q
. Действительно, q
становится значением переменной n
. Но на самом деле кое-что еще — вы отправили в поток ввода (он еще зовётся stdin
) и клавишу Enter
, которую можно интерпретировать как \n
.. Возьмем еще один пример:
#include <stdio.h> int main (void) { int z, x; scanf ("%c", &z); printf("%c", z); scanf ("%c", &x); printf("%c", x); return 0; }
Теперь запустим программу и…
- Нажмем клавишу
a
, затем нажмем клавишуEnter
- На экран будет выведен символ
a
- Теперь нажмем клавишу
b
, затем нажмем клавишуEnter
- На экран не будет выведена
b
, будет лишь пустая строка
А вот таже самая ситуация глазами программы:
- Запрашиваю значение переменной
z
- Пользователь вводит
a
и\n
- Присваиваю переменной
z
значениеa
- Вывожу на экран
a
- Запрашиваю значение переменной
x
- Пользователь вводит
b
и\n
- Вижу, что в входном потоке находится
\n
b
\n
- Беру следующий символ из потока ввода:
\n
и присваиваю его переменнойx
- Вывожу на экран символ новой строки (
\n
) - При этом в потоке все также остаются
b
\n
…которые так и будут вечно лежать в этом буфере (так называют входной поток, который уже сохранен в памяти программы).
Что делать, чтобы таких ошибок не возникало?
- помнить, что
scanf
(и само собойgetchar
) не пропускает служебные символы (в том числе\n
) при вводе символов%c
, а также%[…]
и%n
. В остальных случаях можно не париться, к примеру,scanf ("%d", x)
— не обращает на\n
внимания (поэтому ни в коем случае не используйте что-то вродеscanf ("%d\n", x)
). - чистить буфер. Как говорится: чистота — залог здоровья (пойти принять душ что ли?). Для этого есть много способов, начинающим рекомендую делать так:
while (getchar() != '\n') continue;
Что при этом происходит — цикл вынимает по одному символы из входного потока и сравнивает — не перенос ли это строки. Если нет — то он переходит к
continue;
, которая возвращает программу в начало цикла и снова достает еще один символ и снова сравнивает. И так до тех пор, пока не встретит\n
; при этом, когда он таки встретит\n
— цикл уже его из буфера достанет (т.е. буфер очистит, он станет пустым), и цикл прекратится → ваша программа продолжит выполнение.Есть и другие способы чистки буфера, например, функция
fflush(stdin)
, однако перед тем, как ее использовать обязательно ознакомьтесь с документацией.
Буду рад вашим комментариям!
Символьный пробел перед спецификатором в ф-ции scanf() позволяется обойтись от цикла while.
#include
int main (void)
{
char z, x;
// Запрос первого символа
printf(«Enter the first letter: «);
scanf (» %c», &z); printf(«%c\n», z);
// Запрос второго символа
printf(«Enter the second letter: «);
scanf (» %c», &x); printf(«%c», x);
printf(«\nThe program is completed.\n»);
return 0;
}