Возможности для ввода и вывода данных не являются частью языка Си. Необходимые для ввода и вывода данных функции имеются в стандартной библиотеке и специфицированы в заголовочном файле stdio.h.
Библиотечные функции ввода и вывода точно определяются стандартом ANSI, таким образом, программы, которые при взаимодействии с системным окружением не выходят за рамки возможностей стандартной библиотеки являются кроссплатформенными на уровне компиляции.
Текстовый поток состоит из последовательности строк. Каждая строка заканчивается символом новой строки.
Чтение одного символа из стандартного ввода (по умолчанию с клавиатуры) производится с помощью функции getchar()
.
int getchar();
В качестве результата каждого своего вызова функция getchar()
возвращает следующий символ ввода или, если обнаружен конец файла, константу EOF
(End Of File). Именованная константа EOF определена в stdio.h
и обычно равна -1, однако не следует в программе вместо EOF использовать -1.
Запись одного символа в стандартный вывод (по умолчанию экран) производится с помощью функции putchar(int)
.
int putchar(int);
Вызов функции putchar(symbol)
отправляет символ symbol в стандартный вывод (печатает на экране символ symbol) и возвращает значение symbol или, в случае ошибки, EOF.
Пример программы, получающей на входе последовательность различных символов и выводящей символы с кодом на единицу большую. Для окончания работы программы необходимо ввести пробел и нажать кнопку Enter. Код кнопки пробел - 0x20 (записан в шестнадцатеричной позиционной системе счисления). Вместо 0x20 можно было написать 32, а ещё лучше пробел выделенный апострофами - ‘ ‘.
1
2
3
4
5
6
7
8
9
#include <stdio.h>
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 <stdio.h>
int main() {
int c;
while( ( c = getchar() ), c != 0x20 ) {
if('0' <= c && c <= '9')
putchar(c);
}
return 0;
}
Например, введите a9b2c1 и нажмите Enter, на экране, кроме надписи a9b2c1 должна появится надпись 921 (результат работы вышеуказанной программы).
Дело в том, что во многих библиотеках компиляторов эта функция реализуется таким образом, что она заполняет буфер ввода до тех пор, пока не будет нажата клавиша Enter, то есть реализуется построчно буферизированным способом.
В библиотеках большинства компиляторов в заголовочном файле <conio.h>
имеется описание функций getch()
и getche()
, которые не используют буфер.
Для понимания разницы работы этих функций поочерёдно запустите программы с различными строчками, которые даны чуть ниже.
1
2
3
printf("%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
), чтобы определить, сколько ещё ожидается аргументов и какого они будут типа.
Форматная строка содержит два вида объектов: обычные символы, которые копируются в выходной поток, и спецификации преобразования. Спецификации преобразования начинаются со знака % и заканчивается символом-спецификатором.
Между % и символом-спецификатором могут быть расположены (в указанном ниже порядке) следующие элементы:
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
5
printf("%*.*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 <stdio.h>
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()
нет, они определены в <conio.h>
и предназначены для работы с клавиатурой.
Пример использования freopen()
1
2
3
freopen("first.txt", "rt", stdin);
char ch;
scanf("%c", &ch);
scanf("%c", &ch);
в третьей строке не будет ожидать ввода с клавиатуры, а считает один символ из файла first.txt
, который определён функцией freopen()
в первой строке.