fprintf в C/C++: разбираемся с примерами

👋 Привет! В этой статье мы поговорим о функции fprintf. В отличие от функции printf, она выводит результат форматирования не на экран, а в нужный нам файл. В начале мы посмотрим на пример использования этой функции, а потом подробно рассмотрим спецификаторы формата, которые можно использовать. В конце статьи вы найдете упражнения для закрепления материала.

Иллюстрация fprintf

Как отформатировать строку используя fprintf

Функция fprintf объявлена в заголовочном файле <stdio.h>. В C++ вы также можете использовать <cstdio>.

fprintf форматирует строку как printf, но записывает результат работы в нужный файл, вместо того, чтобы вывести строку в стандартный вывод.

Прототип этой функции выглядит следующим образом:

int fprintf ( FILE * stream, const char * format, ... );
  • Первым аргументом функция принимает указатель на объект FILE, в который будет записан результат ее работы.
  • Вторым аргументом передается строка форматирования. Модификаторы, которые можно использовать будут рассмотрены ниже.
  • Далее передаются дополнительные аргументы. Их количество зависит от используемых спецификаторов формата в строке форматирования (второй аргумент).
  • Возвращает функция длину отформатированной строки (как и printf).

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

#include <stdio.h>

int main() {
  FILE * f = fopen("output.txt", "w");
  fprintf(f, "число: %d", 1234);
  fclose(f);

  return 0;
}

Содержимое файла output.txt:

число: 1234

В этой программе мы:

  1. Открываем файл output.txt с помощью функции fopen на запись.
  2. Используем функцию fprintf для записи строки в этот файл.
  3. Закрываем открытый файл.

Какой будет результат выполнения следующего кода?

#include <cstdio>

int main() {
  FILE * f = fopen("output.txt", "w");
  int res = fprintf(f, "x = %d", 1234);
  fclose(f);

  return 0;
}
Файл output.txt будет создан, но останется пустым.
Файл output.txt не будет создан.
Файл output.txt будет создан с содержимым “число: 1234”, а res будет равен 8.
Файл output.txt будет создан с содержимым “число: 1234”, но res будет равен 0.

Также, fprintf можно использовать для вывода на экран. Для этого нужно просто передать указатель на стандартный вывод stdout в первый аргумент этой функции:

#include <stdio.h>

int main() {
  fprintf(stdout, "число: %d \n", 1234);

  return 0;
}

Вывод программы на экран:

число: 1234

Спецификаторы формата

Спецификатор формата имеет следующую структуру (в квадратных скобках опциональные модификаторы):

%[флаги][ширина][.точность][размер]тип

Обязательно нужно указать только знак вопроса и тип. Остальное можно опустить если вас устраивает вывод без них.

Тут довольно много различных модификаторов. Некоторые из них мы уже использовали выше, но большинство мы еще не встречали. Давайте пройдемся по каждому из них:

Тип

ТипОписаниеПримерФайл f
d/iВыводит целое число

fprintf(f, "%d", -1234);
fprintf(f, "%i", -1234);

-1234
-1234

uВыводит целое число без знакаfprintf(f, "%u", 1234);1234
oВыводит целое восьмеричное число без знакаfprintf(f, "%o", 1234);2322
xВыводит целое число без знака в шестнадцатеричной системеfprintf(f, "%x", 1234);4d2
XКак x, только большими буквамиfprintf(f, "%X", 1234);4D2
fВыводит дробное числоfprintf(f, "%f", 12.34);12.340000
FКак f, только большими буквамиfprintf(f, "%F \n", 1. / 0);INF
eВыводит дробное число в экспоненциальной записиfprintf(f, "%e", 12.34);1.234000e+01
EКак e, только большими буквамиfprintf(f, "%E", 1234.);1.234000E+03
gВыводит дробное число, используя экспоненциальную запись если она короче

fprintf(f, "%g", 12.34);
fprintf(f, "%g", 12000000.34);

12.34
1.2e+07

GКак g, но большими буквами

fprintf(f, "%G", 12.34);
fprintf(f, "%G", 12000000.34);

12.34
1.2E+07

aВыводит дробное число в шестнадцатеричной системеfprintf(f, "%a", -12.34);-0x1.8ae147p+3
AКак a, только большими буквамиfprintf(f, "%A", -12.34);-0X1.8AE147P+3
cВыводит символfprintf(f, "%c", 'C');C
sВыводит строкуfprintf(f, "%s", "C++");C++
pВыводит указатель
void* p;
fprintf(f, "%p", p);
0x104ddc000
nНичего не выводит. fprintf сохранит количество символов, которые были записаны в файл до этого момента, в указатель переданный в соответствующем аргументе.
int n;
fprintf(f, "n = %n", &n);
fprintf(f, "%d", n);
n = 4
%Выводит процентfprintf(f, "%%");%

Флаги

ФлагОписаниеПримерФайл f
-Выравнивает по левому краю

fprintf(f, "%3d", 1);
fprintf(f, "%-3d", 1);

1
1

+Выводит + для положительных чисел

fprintf(f, "%+d", 1234);
fprintf(f, "%+d", -1234);

+1234
-1234

Выводит для положительных чисел

fprintf(f, "% d", 1234);
fprintf(f, "% d", -1234);

1234
-1234

#Выводит 0, 0x, 0X перед числами типа %o, %x, %X соответственно (кроме нуля). Для дробных чисел выводит дробную часть независимо от ее наличия.

fprintf(f, "%#o", 1234);
fprintf(f, "%#x", 1234);
fprintf(f, "%#x", 0);
fprintf(f, "%#f", 12.34);
fprintf(f, "%#f", 12.);
fprintf(f, "%#f", 0.);

02322
0x4d2
0
12.340000
12.000000
0.00000

0Выводит нули вместо пробела, когда указана ширина

fprintf(f, "%04d", 1);

0001

Ширина

ШиринаОписаниеПримерФайл f
числоВыводит минимальное число символов

fprintf(f, "%3d", 1);

1

*Как число, только оно передается в соответствующем аргументе

fprintf(f, "%*d", 4, 1);

1

Точность

ТочностьОписаниеПримерФайл f
.число

Для целых чисел (d, i, o, u, x, X) работает как ширина.

Для дробных (a, A, e, E, f, F) указывает, сколько дробных цифр нужно вывести. Если указан ноль, то ничего не будет выведено для 0.

Для g и G указывает, сколько значимых чисел (перед e) нужно вывести.

Для строк (s) указывает максимальное количество символов, которые будут выведены.

Если после точки число не указано, подразумевается ноль.

fprintf(f, "%.4f", 12.34);
fprintf(f, "%.0d", 0);
fprintf(f, "%.1s", "C++");

12.3400
<пусто>
C

*Как число, только оно передается в соответствующем аргументе

fprintf(f, "%.*f", 4, 12.34);

12.3400

Размер

Модификаторы размера нам нужны, потому что в C нет возможности понять размер переданного аргумента в fprintf. Давайте посмотри на простой пример, чтобы продемонстрировать о чем я говорю:

FILE * f = fopen("output.txt", "w");
long long int x = 10000000000; // десять миллиардов
fprintf(f, "%d\n", x); 

Содержание файла:

1410065408

Дело здесь в том, что fprintf ожидает int для спецификатора %d. Значение типа long long int просто не влезает, поэтому мы видим не то, что ожидали.

Чтобы решить эту проблему, нужно явно указать размер целого числа, которое нужно вывести:

FILE * f = fopen("output.txt", "w");
long long int x = 10000000000; // десять миллиардов
fprintf(f, "%lld\n", x);

Содержание файла:

10000000000

Теперь содержание файла соответствует нашим ожиданиям. Вот таблица возможных типов:

РазмерТип
hh

signed char / unsigned char

h

short int / unsigned short int

l

long int / unsigned long int

ll

long long int / unsigned long long int

j

intmax_t / uintmax_t

z

size_t

t

ptrdiff_t

L

long double

Упражнения

  1. Использование fprintf для записи в файл:
    Напишите программу на C++, которая запрашивает у пользователя целое число и строку, а затем записывает их в файл с использованием функции fprintf. После этого, программа должна считывать и выводить содержимое файла.

  2. Форматирование строки с fprintf:
    Измените программу из первого задания так, чтобы пользователь мог вводить несколько чисел (целых и вещественных) и строк. Ваша программа должна форматировать и записывать их в файл с использованием различных спецификаторов формата.

  3. Сравнение fprintf и printf:
    Напишите программу, которая демонстрирует различия (или их отсутствие) между fprintf и printf. Ваша программа должна использовать обе функции для вывода строки с переменными, и результаты их работы должны быть записаны в файл и выведены на экран соответственно.

Обсуждение