Хочу отдельным постом поделиться с весьма нетривиальной с точки зрения новичка в 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;
}
Буду рад вашим комментариям!
