Функции putchar() и getchar()
Заголовочный файл stdio.h известен не только функцией printf()
, но и множеством других,
которые связаны с вводом-выводом данных. Среди них выделяются функции для обработки каждого символа:
putchar()
и getchar()
.
Функция putchar()
в основном принимает символ или переменную, содержащую символ, и
выводит на экран соответствующий ему символ. Можно передать этой функции и обычное целое число, однако символ
может не появиться, если в таблице ASCII оно не определено. Например:
char ch = 'c';
putchar('a');
putchar(98);
putchar('\n');
putchar(ch);
Результат:
ab
c
Функции putchar()
и printf()
некоторые задачи могут выполняться
по-разному, но давать один исход. Хотя код исполнения будет разниться:
char str[] = "Hello";
int i;
printf("%s\n", str); // первое Hello
for (i = 0; str[i] != '\0'; i++) // второе Hello
putchar(str[i]);
printf("\n");
При выполнении этого кода вы увидите на экране два слова "Hello", каждое на новой строке. С putchar()
реализация задачи выглядит несколько запутанней. Строка как структура данных заканчивается нулевым по ASCII
символом, который служит признаком её завершения в реализации вывода. Однако, если мы захотим добиться
вывода строки с разделением символов другим символом, таким как тире, то даже с использованием
printf()
это может стать сложной задачей:
char str[] = "Hello";
int i;
for (i = 0; str[i] != '\0'; i++)
printf("%c-",str[i]);
printf("%c%c %c",'\b', '\0', '\n');
for (i = 0; str[i] != '\0'; i++) {
putchar(str[i]);
putchar('-');
}
printf("%c%c %c",'\b', '\0', '\n');
Результат:
H-e-l-l-o
H-e-l-l-o
В выборе функции нужно ориентироваться на конкретную задачу и предпочтения.
Функция getchar()
работает по принципу, отличному от putchar()
, так
как она не принимает аргументов. Когда getchar()
вызывается, она читает из потока ввода
один символ и возвращает его программе. Полученный символ можно присвоить переменной, использовать в
различных выражениях, или вывести на экран через функции вывода.
int a;
a = getchar();
printf("%c ", a);
putchar(a);
putchar('\n');
После ввода символа и нажатия клавиши Enter, этот символ дважды отобразится на экране:
u
u u
Первое отображение происходит из-за функции printf()
, второе — благодаря
putchar()
. Если перед Enter вы введете несколько символов, будет учтен только первый, остальное
игнорируется. Вот пример кода:
char a, b, c;
a = getchar();
putchar(a);
b = getchar();
putchar(b);
c = getchar();
putchar(c);
printf("\n");
Как думаете, как он исполняется? После ввода каждого символа он сразу печатается на экране через функцию
putchar()
, а затем запрашивается следующий, так происходит каждый раз, когда вызывается
getchar()
. Если вы корректно введете первый символ и нажмете Enter, символ появится на
экране. Введите второй и после Enter он также будет отображен. И тут программа завершится, не дав возможности
ввести третий символ.
Проведем эксперимент "некорректного пользователя" и попробуем ввести несколько символов до нажатия Enter. После нажатия вы увидите только первые три символа, и программа завершится. Этот эффект объясняется не языком C, а специфическими особенностями буферизации ввода-вывода в операционных системах. Во время операций ввода-вывода выделяется буферная память, куда сначала помещаются поступающие символы, и только по специальному сигналу (например, при нажатии Enter) они передаются по месту назначения (на экран, переменную и т.д.).
Теперь, зная это, мы можем понять, что происходило в нашей программе. К примеру, второй вариант с "некорректным
пользователем" проще понять. Первый введенный символ заносится в переменную a, срабатывает функция
putchar(a)
, и символ отправляется в буфер. Поскольку Enter еще не был нажат, он
остается в буфере, не отображаясь. По той же логике последовательно обработаны другие символы. Как только
нажат Enter, буфер немедленно выводится на экран системой, а не программой, которая завершает вывод задолго до этого.
В начальном варианте программы видно только два символа, хоть было введено больше. Первый символ помещен в a, выведен в буфер, затем Enter отправил его на экран, и символ \n присвоен b. Однако, переход на новую строку \n, видимо, не сохраняется в буфере.
Во многих учебных текстах на языке C приводится пример, где используя getchar()
,
вводятся символы с клавиатуры и сразу же печатаются на экране:
int a;
a = getchar();
while (a != '\n') {
putchar(a);
a = getchar();
}
putchar('\n');
В переменной a всегда находится последний введенный символ, который, прежде чем стать новым, через
putchar()
отправляется в вывод. Как только программа получает символ новой строки, работа
завершается, но нажатие Enter приводит к демонстрации буфера на экране. Если условие цикла
while
изменить и вместо '\n' использовать другой символ, например, ";", программа
продолжит обработку символов, даже после нажатия Enter. Таким образом можно вводить и выводить множество строк текста.
Напишите программу, которая осуществляет ввод и вывод символов, используя любой символ, кроме '\n', в качестве признака завершения. Протестируйте ее.
При объединении функций putchar()
и getchar()
, часто
используется более лаконичная запись. К примеру:
while ((a = getchar()) != '~')
putchar(a);
-
Объясните, почему сокращенная запись посимвольного ввода-вывода корректно работает. Подробно опишите
последовательность действий в цикле
while
. - Переделайте вашу программу на более краткую форму.
EOF
Возникает вопрос: как завершить считывание текста с клавиатуры или файла, не зная точное количество символов и не предваряя его конкретным символом? Как передать программе сигнал об окончании ввода, не используя конкретное значение?
Для этих целей в операционных системах и языках программирования предусмотрена специальная константа — EOF (end of file) — обозначающая конец потока ввода или файла. Значение EOF варьируется, однако чаще всего это число -1. В коде принято писать именно идентификатор EOF, а не чисто числовое значение. EOF определен в stdio.h.
Для передачи значения EOF функции getchar()
в системе GNU/Linux используют Ctrl + D,
а в Windows - Ctrl + Z.
Измените вашу программу так, чтобы она прекращала считывание символов, когда получает сигнал EOF.
Решение задач
Хотя функции getchar()
и putchar()
могут показаться простыми,
они часто применяются на практике, так как задача посимвольного анализа данных при вводе-выводе не так уж
редка. Используя только getchar()
, можно, например, сформировать массив символов (строку),
отсеяв лишние символы. Пример этого подхода: из ввода выбраны только цифры, хотя могут быть введены любые
символы:
span>#include <stdio.h>
#define N 100
main () {
char ch;
char nums[N];
int i;
i = 0;
while ((ch = getchar()) != EOF && i < N-1)
if (ch >= 48 && ch <= 57) {
nums[i] = ch;
i++;
}
nums[i] = '\0';
printf("%s\n", nums);
}
Здесь ввод может прерваться не только сигналом EOF, но и по достижению предела массива (i < N-1
).
В условии while
предусмотрен контроль, чтобы числовой код символа был в диапазоне [48, 57],
который соответствует цифрам (0-9) в таблице ASCII. Если введен символ является цифрой, он добавляется в массив
по индексу i, после чего i увеличивается на 1. Заканчивается алгоритм добавлением нулевого символа
к массиву символов, так как по условиям строки требуется таковой (именно поэтому четко оставлено место —
N-1
).
- Создайте программу, которая будет считать количество символов и строк, введенных пользователем.
- Разработайте программу, подсчитывающую количество слов в строке.