Форматированный ввод и вывод

Теги: Форматированный ввод, форматированный вывод, printf, scanf, fgets, getch, строка формата, спецификатор формата, флаги, управляющие символы.



Форматированный вывод

Сегодня мы рассмотрим две важные функции форматированного ввода и вывода. Устройство и работу этих функций полностью можно понять только после изучения работы с указателями и функций с переменным числом параметров. Но пользоваться этими функциями необходимо уже сейчас, так что некоторые моменты придётся пропустить.

Функция форматированного вывода printf получает в качестве аргументов строку формат и аргументы, которые необходимо вывести в соответствии с форматом, и возвращает число выведенных символов. В случае ошибки возвращает отрицательное значение и устанавливает значение ferror. Если произошло несколько ошибок, errno равно EILSEQ.
int printf (const char * format, ...);

#include <stdio.h>
#include <conio.h>

void main() {
	//функция не получает никаких аргументов, кроме строки
	printf("Hello world");
	getch();
}

Функция проходит по строке и заменяет первое вхождение %<спецификатор формата> на первый аргумент, второе вхождение %<спецификатор формата> на второй аргумент и т.д. Далее мы будем просто рассматривать список флагов и примеры использования.

Общий синтаксис спецификатора формата
%[флаги][ширина][.точность][длина]спецификатор
Спецификатор – это самый важный компонент. Он определяет тип переменной и способ её вывода.

Таб. 1 Спецификатор типа.
Спецификатор Что хотим вывести Пример
d или i Целое со знаком в в десятичном виде 392
u Целое без знака в десятичном виде 7235
o Беззнаковое в восьмеричном виде 657
x Беззнаковое целое в шестнадцатеричном виде 7fa
X Беззнаковое целое в шестнадцатеричном виде, верхний регистр 7FA
f или F Число с плавающей точкой 3.4563745
e Экспоненциальная форма для числа с плавающей точкой 3.1234e+3
E Экспоненциальная форма для числа с плавающей точкой, верхний регистр 3.1234E+3
g Кратчайшее из представлений форматов f и e 3.12
G Кратчайшее из представлений форматов F и E 3.12
a Шестнадцатеричное представление числа с плавающей точкой -0xc.90fep-2
A Шестнадцатеричное представление числа с плавающей точкой, верхний регистр -0xc.90FEP-2
c Буква a
s Строка (нуль-терминированный массив букв) Hello World
p Адрес указателя b8000000
n Ничего не печатает. Аргументом должен быть указатель на signed int. По этому адресу будет сохранено количество букв, которое было выведено до встречи %n
% Два идущих друг за другом процента выводят знак процента %

Примеры

#include <stdio.h>
#include <conio.h>

void main() {
	int a = 0x77, b = -20;
	char c = 'F';
	float f = 12.2341524;
	double d = 2e8;
	char* string = "Hello, World!";

	printf("%s\n", string);
	printf("a = %d, b = %d\n", a, b);
	printf("a = %u, b = %u\n", a, b);
	printf("a = %x, b = %X\n", a, b);
	printf("dec a = %d, oct a = %o, hex a = %x\n", a, a, a);
	printf("floating point f = %f, exp f = %e\n", f, f);
	printf("double d = %f or %E\n", d, d);
	printf("not all compiler support %a\n", f);
	printf("character c = %c, as number c = %d", c, c);
	printf("address of string is %p", string);
	getch();
}

Строка формата также может включать в себя следующие необязательные суб-спецификаторы: флаг, ширина, .точность и модификатор (именно в таком порядке).

Таб. 2 Флаги.
Флаг Описание
- Выключка влево на заданное шириной значение
+ Явно указывать знак у числа, даже для положительных чисел
(пробел) Если знак не будет выведен, то вставляет пробел перед выводимым числом
# Когда используется вместе с o, x или X, вставляет перед числом 0, 0x или 0X
Когда используется со спецификаторами a, A, e, E, f, F, g или G, вставляет десятичную точку, даже если после неё нет десятичных знаков.
0 Вставляет нули, когда объявлен спецификатор ширины
Таб. 3 Ширина.
Ширина Описание
(число) Минимальное количество знаков, которое необходимо вывести. Если в числе меньше знаков, то вставляет пробелы (или нули)
* Ширина не указана в строке формата, она передаётся отдельно в виде аргумента, который должен предшествовать выводимому числу
Таб. 4 Точность.
.Точность Описание
.число Для спецификаторов целых (d, i, o, u, x, X) точность определяет минимальное количество знаков, которое необходимо вывести. Если значение короче, то выводятся нули перед числом. Значение не обрезается, даже если оно длиннее. Точночть 0 означает, что для значения 0 ничего не выводится.
Для спецификаторов чисел с плавающей точкой (a, A, e, E, f, F) это число знаков, которые необходимо вывести после десятичной точки (по умолчанию 6).
Для g и G - это число значащих разрядов, которые необходимо вывести.
Для s - выводится указанное число символов. По умолчанию выводятся все символы до первого нулевого.
Если число не стоит, то по умолчанию точность равна 0
.* Точность не указана в строке формата, она передаётся отдельно в виде аргумента, который должен предшествовать выводимому числу

Примеры

#include <stdio.h>
#include <conio.h>

void main() {
	int a = 0x77, b = -20;
	char c = 'F';
	float f = 12.2341524;
	double d = 2e2;
	char* string = "Hello, World!";

	printf("%.3f\n", f);
	printf("%.*f\n", 2, f);
	printf("%010.3f\n", d);
	printf("%*d\n", 6, a);
	printf("%+d\n", b);
	printf("%0.6d\n", a);
	printf("%.f\n", d);
	printf("%.4s", string);
	getch();
}

Суб-спецификатор длины изменяет длину типа. В случае, если длина не совпадает с типом, по возможности происходит преобразование до нужного типа.

Таб. 5 Длина.
спецификаторы
Длина d, i u o x X f F e E g G a A c s p n
(none) int unsigned int double int char* void* int*
hh signed char unsigned char signed char*
h short int unsigned short int short int*
l long int unsigned long int wint_t wchar_t* long int*
ll long long int unsigned long long int long long int*
j intmax_t uintmax_t intmax_t*
z size_t size_t size_t*
t ptrdiff_t ptrdiff_t ptrdiff_t*
L long double

Примеры

#include <stdio.h>
#include <conio.h>

void main() {
	long long x = 12300000000579099123;
	short i = 10;
	printf("%llu\n", x);
	printf("%d\n", i);
	printf("%hd\n", i);
	getch();
}

Форматированный ввод

Рассмотрим форматированный ввод функцией scanf.
int scanf(const char*, ...)
Функция принимает строку формата ввода (она похожа на строку формата printf) и адреса, по которым необходимо записать считанные данные. Возвращает количество успешно проинициализированных аргументов.
Формат спецификатора ввода
%[*][ширина][длинна]спецификатор

Таб. 6 Спецификатор типа.
Спецификатор Описание Выбранные символы
i, u Целые Произвольное число цифр (0-9), возможно, начинающихся с + или -. Если число начинается с 0, то считывается в восьмеричном формате, если с 0x, то в шестнадцатеричном.
d Десятичное целое Произвольное число цифр (0-9), возможно, начинающихся с + или -.
o восьмеричное целое Произвольное число цифр (0-7), возможно, начинающихся с + или -.
x Шестнадцатеричное целое Произвольное число цифр (0-F), возможно, начинающихся с + или - и префикса 0x или 0X.
f, e, g Число с плавающей точкой Число, состоящее из набора цифр 0-9, возможно с десятичным разделителем (точкой). Возможно также представление в экспоненциальной форме. C99 позволяет также вводить число в шестнадцатеричном формате.
a
c Символ Если ширина не передана, то считывает один символ. Если ширина передана, то считывает нужное количество символов и размещает их в массиве БЕЗ терминального символа на конце.
s Строка Считывает все не пробельные символы. Если указана ширина, то не более n символов. Ставит на место n+1 символа терминальный.
p Адрес указателя Последовательность символов, трактуемая как адрес указателя. Формат зависит от реализации, но совпадает с тем, как выводит printf с ключом p
[символы] Множество символов Считывает только те символы, которые записаны в квадратных скобках, С99
[^символы] Множество символов Считывает только те символы, которые не указаны в квадратных скобках, С99
n Ничего не считывает Сохраняет число уже считанных символов по указанному адресу

Как и в printf, ширина, заданная символом * ожидает аргумента, который будт задавать ширину. Флаг длина совпадает с таким флагом функции printf.

Примеры

#include <stdio.h>
#include <conio.h>

void main() {
	int year, month, day;
	char buffer[128];
	int count;
	//Требует форматированного ввода, например 2013:12:12
	printf("Enter data like x:x:x = ");
	scanf("%d:%d:%d", &year, &month, &day);
	printf("year = %d\nmonth = %d, day = %d\n", year, month, day);
	//Считываем строку, не более 127 символов. При считывании в массив писать & не надо,
	//так как массив подменяется указателем
	printf("Enter string = ");
	scanf("%127s", buffer);
	printf("%s", buffer);
	getch();
}

Кроме функций scanf и printf есть ещё ряд функций, которые позволяют получать вводимые данные

int getch() [aka _getch(), getchar()] - возвращает введённый символ, при этом не выводит его на консоль.
#include <stdio.h>
#include <conio.h>

void main() {
	char c = 0;
	do {
		c = getch();
		printf("%c", c);
	} while (c != 'q');
}

char * fgets ( char * str, int num, FILE * stream ) - функция позволяет считывать строку с пробельными символами. Несмотря на то, что она работает с файлом, можно с её помощью считывать и из стандартного потока ввода. Её преимущество относительно gets в том, что она позволяет указать максимальный размер считываемой строки и заканчивает строку терминальным символом.

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

void main() {
	char buffer[128];
	//Считываем из стандартного потока ввода
	fgets(buffer, 127, stdin);
	printf("%s", buffer);
	//Этим можно заменить ожидание ввода символа
	scanf("1");
}

Это не полный набор различных функций символьного ввода и вывода. Таких функций море, но очень многие из них небезопасны, поэтому перед использованием внимательно читайте документацию.

Непечатные символы

В си определён ряд символов, которые не выводятся на печать, но позволяют производить форматирование вывода. Эти символы можно задавать в виде численных значений, либо в виде эскейп-последовательностей: символа, экранированного обратным слешем.

Таб. 7 Управляющие последовательности.
Последовательность Числовое значение Результат
\a 0x07 Звуковой сигнал
\b 0x08 Перевод каретки на одно значение назад
\f 0x0c Новая страница
\n 0x0a Перевод строки, новая строка
\r 0x0d Возврат каретки
\t 0x09 Табуляция
\v 0x0b Вертикальная табуляция
\" 0x22 Двойная кавычка
\\ 0x5с Обратный слеш
#include <stdio.h>
#include <conio.h>

void main() {
	char backspace = 0x08;
	//Выводим с использованием символа переноса строки
	printf("Hello\nWorld\n");
	//Выводим символ переноса строки через его значение
	printf("Hello%cWorld\n", 0x0a);
	//"Выводим" сигнал
	printf("\a");
	//Выводим сигнал, как символ
	printf("%c", '\a');
	//Выводим сигнал через шестнадцатеричное значение
	printf("%c", 0x07);
	printf("This is sparta!!!\b\b%c", backspace);
	printf("   ");
	getch();
}
Q&A

Всё ещё не понятно? – пиши вопросы на ящик email
Оператор присваивания