Посимвольный ввод и вывод. Понятие буфера
В заголовочном файле 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; // первое Hello printf("%s\n", str); // второе Hello for (i = 0; str[i] != '\0'; i++) 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
Поэтому выбор в пользу той или иной функции зависит от ситуации и ваших предпочтений.
В отличие от функции putchar() функция getchar() не имеет параметром. Когда 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 введем несколько символов (больше двух). После Enter вы увидите три первых символа введенной вами строки, и программа завершиться. Хотя куда логичней было бы ожидать, что будет прочитан только первый символ, потом выведен на экран и потом запрошен следующий символ.
Такое странное на первый взгляд поведение программы связано не с языком C, а с особенностью работы операционных систем, в которых реализован буферный ввод-вывод. При операциях ввода-вывода выделяется область временной памяти (буфер), куда и помещаются поступающие символы. Как только поступает специальный сигнал (например, переход на новую строку при нажатии Enter), данные из буфера передаются по месту своего назначения (на экран, в переменную и др.).
Теперь, зная это, давайте посмотрим, что происходило в нашей программе, и сначала разберем второй случай с «некорректным пользователем», т.к. для понимания этот случай проще. Когда пользователь ввел первый символ, он попал в переменную a, далее сработала функция putchar(a) и символ попал в буфер. Т.к. Enter’а не было, то содержимое буфера на экране не было отображено. Пользователь ввел второй символ, переменная b получила свое значение, а putchar(b) отправила это значение в буфер. Аналогично с третьим символом. Как только пользователь нажал Enter, содержимое буфера было выведено на экран. Но символы, которые были выведены на экран, были выведены не программой, а операционной системой. Программа же выводила символы еще до того, как мы нажали Enter.
Почему же в первом случае при выполнении программы мы смогли ввести и увидеть на экране только два символа? Когда был введен первый символ, то он был присвоен переменной a и далее выведен в буфер. Затем был нажат Enter. Это сигнал для выброса данных их буфера, но это еще и символ перехода на новую строку. Этот символ ‘\n’, наверное, и был благополучно записан в переменную b. Тогда в буфере должен оказаться переход на новую строку, после этого введенный символ (уже помещенный в переменную c). После нажатия Enter мы должны были бы увидеть переход на новую строку от символа ‘\n’ и букву. Однако печатается только буква. Причина этого вероятно в том, что переход на новую строку не хранится в буфере.
Во многих учебниках по языку C приводится пример считывания символов, вводимых пользователем, и их вывод на экран:
int a; a = getchar(); while (a != '\n') { putchar(a); a = getchar(); } putchar('\n');
В переменной a всегда хранится последний введенный символ, но перед тем как присвоить a новое значение с помощью функции putchar() старое значение сбрасывается в буфер. Как только поступает символ новой строки, работа программы прекращается, а также, поскольку была нажата клавиша Enter, происходит вывод содержимого буфер на экран. Если в условии цикла while будет не символ ‘\n’, а какой-нибудь другой, то программа будет продолжать обрабатывать символы, даже после нажатия Enter. В результате чего мы можем вводить и выводить множество строк текста.
Напишите программу посимвольного ввода-вывода, используя в качестве признака окончания ввода любой символ, кроме ‘\n’. Протестируйте ее.
При совместном использовании функций putchar() и getchar() обычно пользуются более коротким способом записи. Например:
while ((a = getchar()) != '~') putchar(a);
- Объясните, почему сокращенный вариант записи посимвольного ввода-вывода работает правильно. Для этого опишите последовательность операций в условии цикла while .
- Перепишите вашу программу на более короткий вариант.
EOF
Как быть, если требуется «прочитать» с клавиатуры или файла неизвестный текст, в котором может быть абсолютно любой символ? Как сообщить программе, что ввод окончен, и при этом не использовать ни один из возможных символов?
В операционных системах и языках программирования вводят специальное значение, которое служит признаком окончания потока ввода или признаком конца файла. Называется это значение EOF (end of file), а его конкретное значение может быть разным, но чаще всего это число -1. EOF представляет собой константу, в программном коде обычно используется именно имя (идентификатор) константы, а не число -1. EOF определена в файле stdio.h.
В операционных системах GNU/Linux можно передать функции getchar() значение EOF, если нажать комбинацию клавиш Ctrl + D, в Windows – Ctrl + Z.
Исправьте вашу программу таким образом, чтобы считывание потока символов прерывалось признаком EOF.
Решение задач
Не смотря на свою кажущуюся примитивность, функции getchar() и putchar() часто используются, т.к. посимвольный анализ данных при вводе-выводе не такая уж редкая задача. Используя только функцию getchar() , можно получить массив символов (строку) и при этом отсеять ненужные символы. Вот пример помещения в строку только цифр из потока ввода, в котором может быть набран абсолютно любой символ:
#include #define N 100 int 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); }
- Напишите программу, которая считает количество введенных пользователем символов и строк.
- Напишите программу, которая подсчитывает количество слов в строке.
Курс с решением части задач:
pdf-версия
Урок 1. Часть 2: Инструкции языка Си printf, puts, putchar — вывод текста и других данных
![]()
Функция puts в Си осуществляет вывод информации на экран. Параметром функции (параметр заключен в круглые скобки, именно он выводится на экран) могут быть данные одного из следующих типов:
-
Вывод строкового литерала
1 2 3 4 5
main() { puts("Hello world!"); system ("pause"); }
Показать аналог в Pascal
begin writeln('Hello world!'); end.
begin writeln(‘Hello world!’); end.
main() { char slovo[]="Hello world!"; puts(slovo); system ("pause"); }
Показать аналог в Pascal
var slovo: string; begin slovo:='Hello world!'; writeln(slovo); end.
var slovo: string; begin slovo:=’Hello world!’; writeln(slovo); end.
#define SLOVO "Hello world!" main() { puts(SLOVO); system ("pause"); }
#define SLOVO «Hello world!» main()
Показать аналог в Pascal
const SLOVO='Hello world!'; begin writeln(SLOVO); end.
const SLOVO=’Hello world!’; begin writeln(SLOVO); end.
Функция putchar в Си
Функция putchar в Си необходима для вывода единичного символа на экран. Параметром функции могут быть данные следующих типов:
-
Вывод символьного литерала
main() { putchar('H'); system ("pause"); }
main() { char c; c='H'; putchar(c); }
#define C 'H' main() { putchar(C); system ("pause"); }
#define C ‘H’ main()
В некоторых компиляторах при использовании функции putchar в Си необходимо подключить в код файл заголовков STDIO.H с помощью директивы #include. В подобных компиляторах функция putchar() является производной другой функции — putc(), которая осуществляет вывод на специальные устройства, такие как диск или принтер.
Пример подключения файла заголовка:
#include main() { char c; c='H'; putchar(c); }
Escape символы в Си или управление перемещением курсора
В Си есть возможность управлять перемещением курсора на экране, т.е. переходить на другую строку, двигаться на n позиций в строны и т.п. Для этого используются специальные коды — escape-последовательности или escape-символы. Последовательность начинается с символа \ , который указывает на то, что символы, расположенные за ним, являются escape-символами. Компилятор, встречая обратную косую черту, не отображает следующие за ней символы, а выполняет действие, на которое они указывают.
Escape-символы в Си должны помещаться в кавычки
\n – переход на новую строку :
puts("Ура!\n");
После слова Ура! произойдет переход на начало следующей строки.
puts("0\t1\t2\t3");
Отображает строку с цифрой 0 в крайней левой позиции экрана и цифры от 1 до 5 через табуляцию
\r – возврат каретки к началу той же строки :
puts ("1\r2"); // произойдет затирание
puts («1\r2»); // произойдет затирание
\b – сдвиг курсора на одну позицию влево
\’ — отображает одинарную кавычку
\» — отображает двойную кавычку
\\ — отображает обратную косую черту
Язык Си printf — функция вывода информации
Языки Си и Си++ имеют более сложную и комплексную функцию для вывода информации, называемую printf(). Она позволяет выводить на экран данные любого типа и работать с несколькими аргументами.
Кроме того, функция Си printf() позволяет осуществлять так называемый форматированный вывод данных.
Самый обычный случай, когда функция printf() просто заменяет функцию puts() для вывода строки:
#define NOTE "Привет!" main() { printf(NOTE ); }
#define NOTE «Привет!» main()

Но целесообразней использовать функцию для осуществления форматированного вывода:
main() { printf("Mne ispolnilos %d let", 12); system ("pause"); }
Программа выведет на экран «Mne ispolnilos 12 let».
Указатели формата:
%d целое число
%u беззнаковое целое число
%f вещественное число типа float или double
%e вещественное число в экспоненциальной форме
%c символ
%s строка
Арифметические операции в Си, оператор присваивания
+ сложение
– вычитание
* умножение
/ деление
% получение остатка от деления нацело
Оператор присваивания
= простое присваивание a=b
++ унарный инкремент a++ (или ++a)
— унарный декремент
+= a+=b если a=3, b=4, то a=7
–= a-=b
*= a*=b
/= a/=b
%= a%=b если a=10, b=3 то а=1
Задание C 1_2_1: Напишите программу, содержащую переменные:
сhar item[] = "Винчестер"; float cost = 3000.50; float markup = 0.75;
сhar item[] = «Винчестер»; float cost = 3000.50; float markup = 0.75;
Добавьте в программу функцию printf(), которая выводит на экран следующие сообщения:
Наименование товара: Жесткий диск Цена за 1 упаковку: 3000.50 Наценка: 0.75
Наименование товара: Жесткий диск Цена за 1 упаковку: 3000.50 Наценка: 0.75
Обратите внимание на выравнивание.
Putchar – выводит символ в поток stdout

При успешном завершении putchar возвращает выведенный символ c. При ошибке он возвращает EOF.
Переносимость
Функция putchar доступна в системах UNIX и поддерживается стандартом ANSI C. Определена также у Кернигана и Ричи.
Пример
#include /* определение некоторых символов, предназначенных для рисования рамок */ #define LEFT_TOP 0xDA #define RIGHT_TOP 0xBF #define HORIZ 0xC4 #define VERT 0xB3 #define LEFT_BOT 0xC0 #define RIGHT_BOT 0xD9 int main(void) < char i,j; /* нарисовать верхнюю часть рамки */ putch(LEFT_TOP); for(i = 0; i < 10; i++) putch(HORIZ); putch(RIGHT_TOP); /* нарисовать центральную часть */ for(i = 0; i < 4; i++) < putch(VERT); for(j = 0; j < 10; j++) putch(' '); putch(VERT); putch('\n'); >/* нарисовать нижнюю часть рамки */ putch(LEFT_BOT); for(i = 0; i
Putchar c что это
Возможности для ввода и вывода данных не являются частью языка Си. Необходимые для ввода и вывода данных функции имеются в стандартной библиотеке и специфицированы в заголовочном файле stdio.h.
Библиотечные функции ввода и вывода точно определяются стандартом ANSI, таким образом, программы, которые при взаимодействии с системным окружением не выходят за рамки возможностей стандартной библиотеки являются кроссплатформенными на уровне компиляции.
Стандартный ввод и вывод
Текстовый поток состоит из последовательности строк. Каждая строка заканчивается символом новой строки.
Чтение одного символа из стандартного ввода (по умолчанию с клавиатуры) производится с помощью функции getchar() .
В качестве результата каждого своего вызова функция getchar() возвращает следующий символ ввода или, если обнаружен конец файла, константу EOF (End Of File). Именованная константа EOF определена в stdio.h и обычно равна -1, однако не следует в программе вместо EOF использовать -1.
Запись одного символа в стандартный вывод (по умолчанию экран) производится с помощью функции putchar(int) .
Вызов функции putchar(symbol) отправляет символ symbol в стандартный вывод (печатает на экране символ symbol) и возвращает значение symbol или, в случае ошибки, EOF.
Пример программы, получающей на входе последовательность различных символов и выводящей символы с кодом на единицу большую. Для окончания работы программы необходимо ввести пробел и нажать кнопку Enter. Код кнопки пробел — 0x20 (записан в шестнадцатеричной позиционной системе счисления). Вместо 0x20 можно было написать 32, а ещё лучше пробел выделенный апострофами — ‘ ‘.
1 2 3 4 5 6 7 8 9#include int main() int c; while( ( c = getchar() ), c != 0x20 ) if(c > 0x20) putchar(c+1); > return 0; >При нажатии на кнопки клавиатуры на экране отображаются те же символы, которые нажаты на клавиатуре - это не действие вышеописанной программы, нажмите на Enter и только после этого Вы увидите работу программы.
Например, введите abcd123 и нажмите Enter, на экране, кроме надписи abcd123 должна появится надпись bcde234 (результат работы вышеуказанной программы).
Пример программы, которая печатает только цифры.
1 2 3 4 5 6 7 8 9#include int main() int c; while( ( c = getchar() ), c != 0x20 ) if('0' c && c '9') putchar(c); > return 0; >Например, введите a9b2c1 и нажмите Enter, на экране, кроме надписи a9b2c1 должна появится надпись 921 (результат работы вышеуказанной программы).
Дело в том, что во многих библиотеках компиляторов эта функция реализуется таким образом, что она заполняет буфер ввода до тех пор, пока не будет нажата клавиша Enter, то есть реализуется построчно буферизированным способом.
В библиотеках большинства компиляторов в заголовочном файле имеется описание функций getch() и getche() , которые не используют буфер.
Для понимания разницы работы этих функций поочерёдно запустите программы с различными строчками, которые даны чуть ниже.
1 2 3printf("%c", getch()); printf("%c", getche()); printf("%c", getchar());Попробуйте при работе программы ввести надпись hello , с первой строчкой, получится ввести только h , после чего программа завершит свою работу, а на экране будет отображено h , это работа printf() . Со второй строчкой на экране увидим hh , так как getche() сама отображает символ на экране. С третьей же строчкой проблем с набором hello возникнуть не должно, но по нажатию на Enter, будет ещё выведено h , так как в буфере находится всё слово hello и первый символ - это h .
Форматный вывод
Для организации форматного вывода может быть использована функция printf() .
int printf(char *format, . )
Многоточие означает, что число и типы аргументов могут изменяться. Знак многоточие может стоять только в конце списка аргументов. Функция printf() возвращает количество записанных (напечатанных) символов.
Функция printf() использует свой первый аргумент (Си строку format ), чтобы определить, сколько ещё ожидается аргументов и какого они будут типа.
Форматная строка содержит два вида объектов: обычные символы, которые копируются в выходной поток, и спецификации преобразования. Спецификации преобразования начинаются со знака % и заканчивается символом-спецификатором.
Между % и символом-спецификатором могут быть расположены (в указанном ниже порядке) следующие элементы:
- Знак минус, предписывающий выравнивать преобразованный аргумент по левому краю поля
- Число, предписывающее минимальную ширину поля
- Точка, отделяющая ширину поля от величины, устанавливающей точность
- Число (точность), специфицирующее максимальное количество печатаемых символов в строке, или количество цифр после десятичной точки - для чисел с плавающей запятой, или минимальное количество цифр - для целого
- Буква h, если печатаемое целое должно рассматриваться как short, или l, если целое должно рассматриваться как long
- Символ-спецификатор. Обязан быть, иначе поведение функции printf() не определено.
- d или i - Десятичное целое ( int )
- o - Беззнаковое восьмеричное целое (unsigned int)
- x или X - Беззнаковое шестнадцатеричное целое ( unsigned int )
- u - Беззнаковое десятичное целое ( unsigned int )
- c - Одиночный символ ( int )
- s - Си строка. Печать символов до символа \\0 (с кодом 0) и не более количества заданного точностью ( char * )
- f - Вещественное число [-]m.dddddd, где количество чисел после десятичной точки задаётся точностью ( double )
- e или E - Вещественное число [-]m.dddddde+-xx или [-]m.ddddddE+-xx, где количество чисел после десятичной точки задаётся точностью (double)
- g или G - Вещественное число. Если порядок меньше точности, выводит как при спецификаторе f , в противном случае как при спецификаторе e или E ( double )
- p - Указатель, представление зависит от реализации ( void * )
- % - Печатается %
- n - Особый спецификатор, который записывает количество уже напечатанных текущей функцией printf символов в переменную (указатель в следующем аргументе). В Visual Studio C++ из-за проблем с безопасностью по умолчанию отключена возможность использования %n . Для включения следует в начале программы написать _set_printf_count_output(1); . Для других компиляторов (например, GCC) ничего писать не надо.
Ширину и точность можно специфицировать с помощью * , в этом случает величина берётся из следующего аргумента.
Шаблон спецификации преобразования.
[-][минимальная ширина поля][.точность][h | l][Символ-спецификатор]
Далее на каждой новой строке представлен пример, попробуйте определить, что будет выведено и проверьте правы ли Вы, набрав код и запустив программу на компьютере.
1 2 3 4 5printf("%*.*f",8,3,12.123456789); printf("\n%.*s",printf("%*.*f",8,3,12.123456789),"1234567890"); printf("\n%.*s",printf("%-*.*f",8,3,12.123456789),"1234567890"); printf("\n%10.*s",printf("%-*.*f",8,3,12.123456789),"1234567890"); printf("\n%-10.*s",printf("%-*.*f",8,3,12.123456789),"1234567890");Теперь пример с применением %n
1 2 3 4 5 6 7 8#include int main(void) _set_printf_count_output(1); int count = 0; printf("%.2f%n\ncount = %d\n", 3.14, &count, count); printf("count = %d\n", count); return 0; >Для функций: scanf() , getc() , gets() и getchar() , а также функций printf() , putc() и puts() с помощью функции freopen() возможно перенаправление потоков в файл, а для функций: getch() и getche() нет, они определены в и предназначены для работы с клавиатурой.
Пример использования freopen()
1 2 3freopen("first.txt", "rt", stdin); char ch; scanf("%c", &ch);scanf("%c", &ch); в третьей строке не будет ожидать ввода с клавиатуры, а считает один символ из файла first.txt , который определён функцией freopen() в первой строке.
Code More Team - GitHub