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

Форматная строка — это шаблон

printf и scanf работают по форматной строке — шаблону, где обычный текст перемешан со спецификаторами %.

Аналогия. Форматная строка — бланк заказа в кафе: «Кофе: ___, размер: ___». Пустые поля (%) заполняются значениями, а слова и запятые остаются как есть.

printf("Студент №%d получил %d баллов\n", 12, 5);
/*                ^ поле-число       ^ поле-число */

Порядок важен: первый % берёт первое значение, второй — второе.

Полный вид спецификатора вывода

%[флаги][ширина][.точность][длина]спецификатор

Все части, кроме последней, необязательны. Разберём %08.3f:

ЧастьЗначениеВ примере
флагидополнительное оформление0 — дополнить нулями
ширинаминимальное число символов8 — всего 8 позиций
точностьзнаков после точки.3 — три знака
спецификатортип значенияf — дробное число

Для числа 3.14159 результат — 0003.142.

Флаги

ФлагЧто делаетПримерРезультат
-выравнивание по левому краю%-6d, 4242
+показывать знак +%+d, 42+42
0дополнить нулями%05d, 4200042
#показывать основание%#x, 2550xff
пробелпробел вместо +% d, 4242

Ширина и точность

printf("|%d|\n", 42);          /* |42|      */
printf("|%5d|\n", 42);         /* |   42|   */
printf("|%-5d|\n", 42);        /* |42   |   */
printf("|%05d|\n", 42);        /* |00042|   */
printf("%.2f\n", 3.14159);     /* 3.14      */
printf("%8.2f\n", 3.14159);    /*     3.14  */
printf("%.0f\n", 2.6);         /* 3 — округление до целого */
  • ширина — сколько минимум позиций займёт значение (если число короче, добавляются пробелы);
  • точность для дробных — сколько знаков после точки (последний знак округляется).

Выравнивание «таблицей» без циклов

Даже без циклов можно напечатать ровные колонки: укажите ширину поля в каждой строке.

#include <stdio.h>

int main(void)
{
    double a = 199.9, b = 45.0, c = 1234.5;

    printf("№        Цена\n");              /* обычный текст без спецификаторов */
    printf("%-8d%10.2f\n", 1, a);
    printf("%-8d%10.2f\n", 2, b);
    printf("%-8d%10.2f\n", 3, c);
    return 0;
}
№        Цена
1           199.90
2            45.00
3          1234.50

%-8d — целое в поле шириной 8 по левому краю, %10.2f — число в поле шириной 10 с двумя знаками после точки. Текст заголовка печатается как обычные символы.

Спецификаторы длины: не перепутать тип

Длина указывается перед спецификатором и должна совпадать с типом переменной:

ТипВвод (scanf)Вывод (printf)
int%d%d
long long%lld%lld
float%f%f
double%lf%f

Запомните разницу: в scanf для double нужен %lf, а в printf — %f (там l не требуется, потому что float уже повышен до double).

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

scanf пропускает пробельные символы (пробелы, табы, переводы строк) перед числами, поэтому данные можно вводить как угодно:

int a, b;
double x;
scanf("%d %d %lf", &a, &b, &x);

Ширину поля можно ограничить — удобно, чтобы не «съесть» лишние символы:

int day, month;
scanf("%2d%2d", &day, &month);   /* ввод 1209 → 12 и 9 */

Спецификатор %c — исключение: он читает любой символ, включая пробел и перевод строки. Поэтому перед %c ставят пробел:

int n;
char c;
scanf("%d", &n);
scanf(" %c", &c);      /* пробел пропустит Enter, оставшийся после числа */

Частые ошибки

ОшибкаКак правильно
printf("%d", 3.14)для дробного — %f
scanf("%f", &d) для doublescanf("%lf", &d)
printf("%lf", d)в выводе достаточно %f
ширина меньше нужнойзначение не обрежется, но колонки «разъедутся»
%c сразу после числапоставить пробел: " %c"
точность у целых (%.2d)у целых точность означает минимум цифр, обычно не нужна

Мини-шпаргалка

printf("%-10d|%5d|%8.2f|\n", 7, 42, 3.5);
printf("%+d %05d %#x\n", 7, 42, 255);      /* +7 00042 0xff */
printf("%.3f %.1f %.0f\n", 1.2345, 1.2345, 2.6);

int x;
double d;
scanf("%d %lf", &x, &d);                    /* несколько значений за раз */
scanf(" %c", &ch);                          /* символ после числа — с пробелом */

Что запомнить: ширина задаёт место под значение, точность — количество знаков после точки; спецификатор ввода обязан совпадать с типом (%lf для double).

Подтверждение

—