Хочу отдельным постом поделиться с весьма нетривиальной с точки зрения новичка в C задачкой. Она приходятся восьмым вопросом для самоконтроля в 6 главе книжки Стивена Прата “C Primer Plus”.
Задание таково:
Что выведут приведенные далее программы в случае ввода Go west, young man!
?
(В кодировке ASCII символ ! следует за символом пробела).
#include <stdio.h> int main(void) { char ch; scanf("%c", &ch); while (ch != 'g') { printf("%c", ch); scanf("%c", &ch); } return 0; }
Казалось бы все просто. Должно вывестись G
— ведь %c
в scanf
является запросом одного символа. Точнее даже так — программа написана неверно, т.к. мы вводим целую фразу при помощи %c
, тогда как ее надо вводить как строку %s
. Ну да ладно. Это обучающий пример и все такое, поэтому предположим.. Итак, ответ G
.
Не тут-то было. Программа выводит:
Go west, youn
Как так? Потыкавшись, я решил потерять девственность на stackoverflow и создал там свой первый топик. Оказалось, дело вот в чем (по мотивам ответа уважаемого Youssef13).
Удобно рассмотреть этот пример, добавив перенос строк:
#include <stdio.h> int main(void) { char ch; scanf("%c", &ch); while (ch != 'g') { printf("PRINTING: %c\n", ch); scanf("%c", &ch); } return 0; }
Смысл в том, что scanf работает таким образом — образуется к «внутреннему» курсору в stdin
(standard input или стандартный поток ввода), который следит за тем, что было прочитано. Когда мы вводим Go west, young man!
, символ G
сохраняется в переменной ch
, а курсор в stdin
перемещается на одну позицию, к символу o
. Затем, в следующий раз, когда мы вызываем scanf
и она уже смотрит что находится на позиции курсора — и там оказывается o
.
Если же мы хотим в последующих scanf
проигнорировать то, что было введено ранее, мы должны это прочитать (или применить fseek
в stdin
, который работает в Windows, но не сработает в Линукс):
#include <stdio.h> int main(void) { char ch; scanf("%c", &ch); while (getchar() != '\n'); // Get to the end of the stdin. // The previous line can be replaced with fseek(stdin, 0, SEEK_END); // but it will work under Windows only. while (ch != 'g') { printf("PRINTING: %c\n", ch); scanf("%c", &ch); } return 0; }
Буду рад вашим комментариям!