Sprintf форматный вывод в буфер


Содержание

printf()

Вот прототип функции printf() :

Функция printf() возвращает число выведенных символов или отрицательное значение в случае ошибки.

Управляющая_строка [1] состоит из элементов двух видов. Первый из них — это символы, которые предстоит вывести на экран; второй — это спецификаторы преобразования [2] , которые определяют способ вывода стоящих за ними аргументов. Каждый такой спецификатор начинается со знака процента, за которым следует код формата. Аргументов должно быть ровно столько, сколько и спецификаторов, причем спецификаторы преобразования и аргументы должны попарно соответствовать друг другу в направлении слева направо. Например, в результате такого вызова printf()

В этом примере первому спецификатору преобразования ( %c ), соответствует символ ‘C’, а второму ( %s ), — строка «и к тому же очень сильно!».

В функции printf() , как видно из табл. 8.2, имеется широкий набор спецификаторов преобразования.

Таблица 8.2. Спецификаторы преобразования для функции printf()
Код Формат
%a Шестнадцатеричное в виде 0xh.hhhhp+d (только С99)
%A Шестнадцатеричное в виде 0Xh.hhhhP+d (только С99)
%c Символ
%d Десятичное целое со знаком
%i Десятичное целое со знаком
%e Экспоненциальное представление (‘е’ на нижнем регистре)
%E Экспоненциальное представление (‘Е’ на верхнем регистре)
%f Десятичное с плавающей точкой
%g В зависимости от того, какой вывод будет короче, используется %е или %f
%G В зависимости от того, какой вывод будет короче, используется %Е или %F
%o Восьмеричное без знака
%s Строка символов
%u Десятичное целое без знака
%x Шестнадцатеричное без знака (буквы на нижнем регистре)
%X Шестнадцатеричное без знака (буквы на верхнем регистре)
%p Выводит указатель
%n Аргумент, соответствующий этому спецификатору, должен быть указателем на целочисленную переменную. Спецификатор позволяет сохранить в этой переменной количество записанных символов (записанных до того места, в котором находится код %n )
%% Выводит знак %

Вывод символов

Для вывода отдельного символа используйте %с . В результате соответствующий аргумент будет выведен на экран без изменения.

Для вывода строки используйте %s .

Вывод чисел

Числа в десятичном формате со знаком отображаются с помощью спецификатора преобразования %d или %i . Эти спецификаторы преобразования эквивалентны; оба поддерживаются в силу сложившихся привычек программистов, например, из-за желания поддерживать те же спецификаторы, которые применяются в функции scanf() .

Для вывода целого значения без знака используйте %u .

Спецификатор преобразования %f дает возможность выводить числа в формате с плавающей точкой. Соответствующий аргумент должен иметь тип double .

Спецификаторы преобразования %e и %E в функции printf() позволяют отображать аргумент типа double в экспоненциальном формате. В общем виде числа в таком формате выглядят следующим образом:

Чтобы отобразить букву E в верхнем регистре, используйте спецификатор преобразования %E ; в противном случае используйте спецификатор преобразования %e .

Спецификатор преобразования %g или %G указывает, что функции printf() необходимо выбрать один из спецификаторов: %f или %e . В результате printf() выберет тот спецификатор преобразования, который позволяет сделать самый короткий вывод. Если нужно, чтобы при выборе экспоненциального формата буква E отображалась на верхнем регистре, используйте спецификатор преобразования %G ; в противном случае используйте спецификатор преобразования %g .

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

В результате выполнения получится следующее:

Целые числа без знака можно выводить в восьмеричном или шестнадцатеричном формате, используя спецификатор преобразования %o или %x . Так как в шестнадцатеричной системе для представления чисел от 10 до 15 используются буквы от А до F, то эти буквы можно выводить на верхнем или на нижнем регистре. Как показано ниже, в первом случае используется спецификатор преобразования %X , а во втором — спецификатор преобразования %x :

Вот что вывела эта программа:

Отображение адреса

Для отображения адреса используйте спецификатор преобразования %p . Этот спецификатор преобразования дает printf() указание отобразить машинный адрес в формате, совместимом с адресацией, которая используется компьютером. Следующая программа отображает адрес переменной sample :

Спецификатор преобразования %n

Спецификатор %n довольно значительно отличается от остальных спецификаторов преобразования. Когда функция printf() встречает его, ничто не выводится. Вместо этого выполняется совсем другое действие: в целую переменную, указанную соответствующим аргументом функции, записывается количество выведенных символов. Другими словами, значение, которое соответствует спецификатору преобразования %n , должно быть указателем на переменную. После завершения вызова printf() в этой переменной будет храниться количество символов, выведенных до того момента, когда встретился спецификатор преобразования %n . Чтобы уяснить смысл этого несколько необычного спецификатора преобразования, разберитесь, как работает следующая программа:

Программа отображает строку Это проверка , после которой появляется число 3 . Спецификатор преобразования %n в основном используется в программе для выполнения динамического форматирования.

Модификаторы формата

Во многих спецификаторах преобразования можно указать модификаторы [3] , которые слегка меняют их значение. Например, можно указывать минимальную ширину поля, количество десятичных разрядов и выравнивание по левому краю. Модификатор формата помещают между знаком процента и кодом формата. Об этих модификаторах сейчас и пойдет речь.

Модификаторы минимальной ширины поля

Целое число, расположенное между знаком % и кодом формата, играет роль модификатора минимальной ширины поля . Если указан модификатор минимальной ширины поля, то чтобы ширина поля вывода была не меньше указанной минимальной длины, при необходимости вывод будет дополнен пробелами. Если же выводятся строки или числа, которые длиннее указанного минимума, то они все равно будут отображаться полностью. По умолчанию для дополнения используются пробелы. А если для этого надо использовать нули, то перед модификатором ширины поля следует поместить 0. Например, %05d означает, что любое число, количество цифр которого меньше пяти, будет дополнено таким количеством нулей, чтобы число состояло из пяти цифр. В следующей программе показано, как применяется модификатор минимальной ширины поля:

Вот что выводится при выполнении этой программы:

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

Модификаторы точности

Модификатор точности следует за модификатором минимальной ширины поля (если таковой имеется). Он состоит из точки и расположенного за ней целого числа. Значение этого модификатора зависит от типа данных, к которым его применяют.

Когда модификатор точности применяется к данным с плавающей точкой, для преобразования которых используются спецификаторы преобразования %f , %e или %E , то он определяет количество выводимых десятичных разрядов. Например, %10.4f означает, что ширина поля вывода будет не менее 10 символов, причем для десятичных разрядов будет отведено четыре позиции.

Если модификатор точности применяется к %g или %G , то он определяет количество значащих цифр.

Примененный к строкам, модификатор точности определяет максимальную длину поля. Например, %5.7s означает, что длина выводимой строки будет составлять минимум пять и максимум семь символов. Если строка окажется длиннее, чем максимальная длина поля, то конечные символы выводиться не будут.

Если модификатор точности применяется к целым типам, то он определяет минимальное количество цифр, которые будут выведены для каждого из чисел. Чтобы получилось требуемое количество цифр, добавляется некоторое количество ведущих нулей.

В следующей программе показано, как можно использовать модификатор точности:

Вот что выводится при выполнении этой программы:

Выравнивание вывода

По умолчанию весь вывод выравнивается по правому краю. То есть если ширина поля больше ширины выводимых данных, то эти данные располагаются по правому краю поля. Вывод по левому краю можно назначить принудительно, поместив знак минус прямо за % . Например, %-l0.2f означает, что число с плавающей точкой и с двумя десятичными разрядами будет выровнено по левому краю 10-символьного поля.

В следующей программе показано, как применяется выравнивание по левому краю:

И вот что получилось:

Обработка данных других типов

Некоторые модификаторы в вызове функции printf() позволяют отображать целые числа типа short и long . Такие модификаторы можно использовать для следующих спецификаторов типа: d , i , o , u и x . Модификатор l (эль) в вызове функции printf() указывает, что за ним следуют данные типа long . Например, %ld означает, что надо выводить данные типа long int . После модификатора h функция printf() выведет целое значение в виде short . Например, %hu означает, что выводимые данные имеют тип short unsigned int .

Модификаторы l и h можно также применить к спецификатору n . Это делается с той целью, чтобы показать — соответствующий аргумент является указателем соответственно на длинное ( long ) или короткое ( short ) целое.

Если компилятор поддерживает обработку символов в расширенном 16-битном алфавите, добавленную Поправкой 1 от 1995 года (1995 Amendment 1), то для указания символа в расширенном 16-битном алфавите вы можете применять модификатор 1 для спецификатора преобразования c . Кроме того, для указания строки из символов в расширенном 16-битном алфавите можно применять модификатор 1 для спецификатора преобразования s .

Модификатор L может находиться перед спецификаторами преобразования с плавающей точкой e , f и g , и указывать этим, что преобразуется значение long double .

В Стандарте С99 вводится два новых модификатора формата: hh и ll . Модификатор hh можно применять для спецификаторов преобразования d , i , o , u , x или n . Он показывает, что соответствующий аргумент является значением signed или unsigned char или, в случае n , указателем на переменную signed char . Модификатор ll также можно применять для спецификаторов преобразования d , i , o , u , x или n . Он показывает, что соответствующий аргумент является значением signed или unsigned long long int или, в случае n , указателем на long long int . В С99 также разрешается применять l для спецификаторов преобразования с плавающей точкой a , е , f и g ; впрочем, это не дает никакого результата.

На заметку В составе С99 имеются некоторые дополнительные модификаторы типа для функции printf() ; о них рассказывается в части II.

Модификатор * и #

Для некоторых из своих спецификаторов преобразования функция printf() поддерживает два дополнительных модификатора: * и # .

Непосредственное расположение # перед спецификаторами преобразования g , G , f , Е или e означает, что при выводе обязательно появится десятичная точка — даже если десятичных цифр нет. Если вы поставите # непосредственно перед x или X , то шестнадцатеричное число будет выведено с префиксом 0x . Если # будет непосредственно предшествовать спецификатору преобразования o , число будет выведено с ведущим нулем. К любым другим спецификаторам преобразования модификатор # применять нельзя. (В С99 модификатор # можно применять по отношению к преобразованию %а ; это значит, что обязательно будет выведена десятичная точка.)

Модификаторы минимальной ширины поля и точности можно передавать функции printf() не как константы, а как аргументы. Для этого в качестве заполнителя используйте звездочку ( * ). При сканировании строки формата функция printf() будет каждой звездочке * из этой строки ставить в соответствие очередной аргумент, причем в том порядке, в каком расположены аргументы. Например, при выполнении оператора, показанного на рис. 8.1, минимальная ширина поля будет равна 10 символам, точность — 4, а отображаться будет число 123.3 .

В следующей программе показано применение обоих модификаторов # и * :

Рис. 8.1. Обратите внимание на то, каким образом звездочке (*) ставится в соответствие определенное значение

[1] Часто называется просто форматной строкой , форматным стрингом или форматом .

[2] Называются также спецификациями формата .

[3] Называются также спецификаторами .

Описание функций языка Си

All | _ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

printf – вывод форматированной строки в стандартный поток вывода.

#include
int printf (const char *format, . );

format – указатель на строку c описанием формата.

При успешном завершении вывода возвращается количество выведенных символов.
При шибке возвращается отрицательное число.

Функция printf выводит в стандартный поток вывода строку отформатированную в соответствии с правилами, указанными в строке, на которую указывает аргумент format.

Правила задаются набором трех типов директив:
1. Обычные символы (кроме ‘%’ и ‘\’), которые выводятся без изменения;
2. Спецификаторы формата;
3. Специальные сиволы.

Каждый спецификатор формата начинается с символа ‘%’ и имеет следующий формат:

Спецификатор формата может иметь 0 или более [флагов], которые могут принемать значенияуказанные в таблице 1.

Таблица 1.

Флаг Назначение флага
— (дефис) Результат преобразования выравнивается по левому краю (по умолчанию — по правому краю)
+ Перед положительными числами выводится знак ‘+’, а перед отрицательыыми — знак ‘-‘ (по умолчанию выводится только знак ‘-‘ перед отрицательыми числами)
‘ ‘ (пробел) Если не указан модификатор ‘+’, то перед положительными числами, на месте знака числа, будет выводиться пробел.
# Использовать альтернативную форму представления выводимого числа. При выводе чисел в шестнадцатеричном формате (преобразователь ‘х’ или ‘Х’) перед числом будет указываться 0х или 0Х соответственно. При выводе чисел в восьмеричном формате (преобразователь ‘о’)перед числом будет указываться 0. При выводе чисел с плавующей точкой (преобразователи e, E, f, g и G) всегда будет содержаться десятичная точка (по умолчанию десятичная точка выводится только при ненулевой дробной части). При использовании преобразователей g и G хвостовые нули не будут удаляться (по умолчанию удаляются).
Если не указан флаг ‘-‘, то слева от выводимого числа будут выведены символы ‘0’ для подгона числа к указанной ширене. Если для преобразователей d, i, o, x или X указана точность, то флаг 0 игнорируется.

Спецификатор [флаги] можно не указывать.

Спецификатор [ширина] задаёт минимальный размер выводимого числа в символах. Если количество символов в выводимом числе меньше указанной минимальной ширины, то недостоющее количество символов заполняется нулями или пробелами слева или справа в зависимости от указанных флагов. Ширина указывается либо целым числом, либо символом * с последующим указанием имени переменной типа int, содержащей значение ширины, перед аргументом к которому он относится. Если аргумент имеет отрицательное значение, то он эквивалентен соответствующему положительному значению с флагом «-«.

Спецификатор [ширина] можно не указывать.

Действия спецификатора [точность] зависит от типа выводимого числа:

— Для типов d, i, o, u, x, X определяет минимальное число выводимых цифр. Если количество выводимых цифр в числе меньше, чем указано в спецификаторе [точность], то выводимое число будет дополнено нулями слева. Например, если при выводе числа 126 указать точность 4, то на экран будет выведено число 0126

— Для типов a, A, e, E, f, F определяет количество выводимых цифр после запятой. Если в выводимом числе количество значимых цифр после запятой меньше указанной точности, то недостающие символы выводятся нулями справа от числа. Если больше, то лишние цифры не выводятся. Например, если при выводе числа 126.345 указать точность 2, будет выведено на экран число 126.34, а если указать точность 5, то на экран будет выведено число 126.34500.

— Для типов g и G определяет максимальное выводимое число цифр. Например, если при выводе числа 126.345 указать точность 4, будет выведено на экран число 126.3. Если при выводе числа 1242679.23 указать точность 3, будет выведено на экран число 1.24е+06.

Точность указывается в виде символа точка, за которым следует десятичное число или символ «*», с последующим указанием имени переменной типа int, содержащей значение точности, перед аргументом к которому он относится.

Спецификатор [точность] можно не указывать.

Спецификатор [модификаторы] определяет размер выводимых данных (char, short, long, longlong). Спецификаторы используются для вывода чисел типа: char, short int, long int, long long int, long double или для явного преобразования выводимых данных. Например, если имеется переменная типа int, а необходимо вывести ее как short int. Доступные модификаторы приведены в таблице 2.

Таблица 2.

Модификатор Назначение модификатора
h Для вывода числа типа short int или unsigned short int. Или для явного преобразования при выводе целочисленного числа к типу short int или unsigned short int. Используется совместно с типами преобразования:d, i, o, u, x и X, n.
hh Для вывода числа типа char или unsigned char. Или для явного преобразования при выводе целочисленного числа к типу char или unsigned char. Используется совместно с типами преобразования:d, i, o, u, x и X, n.
l Для вывода числа типа long int или unsigned long int. Или для явного преобразования при выводе целочисленного числа к типу long int или unsigned long int. Используется совместно с типами преобразования:d, i, o, u, x и X, n.
ll Для вывода числа типа long long int или unsigned long long int. Или для явного преобразования при выводе целочисленного числа к типу long long int или unsigned long long int. Используется совместно с типами преобразования:d, i, o, u, x и X, n.
L Для вывода числа типа long double. Или для явного преобразования при выводе числа c плавающей точкой к типу long double. Используется совместно с типами преобразования:e, E, f, g и G.

Спецификатор [тип преобразования] определяет как надо итерпритировать и выводить число, например как знаковое целочисленное в десятичном виде, или беззнаковое целочисленное в шестнадцатеричном, или как число с плавающей точкой и так далее. Перечень доступных преобразований и их описание указано в таблице 3.

Таблица 3.

Тип преобразования Назначение преобразования
d,i Вывод целого числа со знаком в десятичной систем счисления. По умолчанию выводится число размером sizeof( int ), с правым выравниванием, указанием знака только для отрицательных чисел.
u Вывод целого числа без знака в десятичной систем счисления. По умолчанию выводится число размером sizeof( int ), с правым выравниванием.
o Вывод целого числа без знака в восьмеричной систем счисления. По умолчанию выводится число размером sizeof( int ), с правым выравниванием.
x, X Вывод целого числа без знака в шестнадцетеричной систем счисления. Причем для преобразования x используются символы abcdef, а для X — символы ABCDEF. По умолчанию выводится число размером sizeof( int ), с правым выравниванием.
f, F Вывод числа с плавающей точкой в виде [-]dddd.ddd. По умолчанию выводится число с точностью 6, если число по модулю меньше единицы, то пред десятично точкой выводится ноль, знак указывается только для отрицательных чисел, с правым выравниванием. Размер по умолчанию sizeof( double ).
e, E Вывод числа с плавающей точкой в экспоненциальной форме записи, в виде [-]dddd.ddde±dd, причем для модификатора e используется символ e, а для модификатора E — символ E. По умолчанию выводится число с точностью 6, если число по модулю меньше еденицы, то пред десятично точкой выводится ноль, знак указывается только для отрицательных чисел, с правым выравниванием. После символа «e» (или «E») всегда выводится две цифры (они равны 0, если аргумент равен 0).
g, G Вывод числа с плавающей точкой в форме зависищей от величины цисла. Например число 345.26 будет выведено как 345.26, а число 1344527.434 как 1.34453e+06. По умолчанию выводится 6 значащих цифр числа с округлением, если число по модулю меньше еденицы, то пред десятично точкой выводится ноль, знак указывается только для отрицательных чисел, с правым выравниванием.
a, A Вывод числа с плавающей точкой в шестнадцатеричном фомрате, в экспоненциальной форме записи. Например число 137.434 будет выведено как 0x1.12de353f7ced9p+7. Экспонента обозначается символом p. Для модификатора a используется символ p, а для модификатора A — символ P.По умолчанию знак указывается только для отрицательных чисел, выравнивание — правое.
с Вывод символа, соответстветсвующего числу указанному в аргументе функции. По умолчанию число приводится к типу unsigned char.
s Вывод строки, на которую ссылается указатель в аргументе функции printf. Строка выводится пока не будет встречен символ конец строки (/0). По умолчанию строка должна обозначаться как char*. Если указан модификатор l, то строка интерпитируется как wchar_t*. Для функции wprintf строка по умолчанию обрабатывается как wchar_t*.
S Аналогичен преобразованию s с модификатором l (ls).
p Вывод указателя. Результат ввода зависит от архитектуры и используемого компилятрора. Например, на 16 битной платформе MS-DOS вывод будет иметь вид типа FFAB:1402, а на 32-битной платформе с плоской адресацией — 00FC0120.
n Запись по адресу, указанному в аргументе функции, количества выведенных символов функцией printf до встречи преобразователя %n. При обработке преобразователя %n никакого вывода символов не производится.

Для форматирования вывода в функции printf предусмотрен набор специальных симовлов. Перечень специальных символов приведен в таблице 4.

Sprintf форматный вывод в буфер

Функция printf переводит внутренние значения в текст.

В предыдущих главах мы использовали printf неформально. Здесь мы покажем наиболее типичные случаи применения этой функции; полное ее описание дано в приложении В.

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

Форматная строка содержит два вида объектов: обычные символы, которые напрямую копируются в выходной поток, и спецификации преобразования, каждая из которых вызывает преобразование и печать очередного аргумента printf . Любая спецификация преобразования начинается знаком % и заканчивается символом-спецификатором. Между % и символом-спецификатором могут быть расположены (в указанном ниже порядке) следующие элементы:

  • Знак минус, предписывающий выравнивать преобразованный аргумент по левому краю поля.
  • Число, специфицирующее минимальную ширину поля. Преобразованный аргумент будет занимать поле по крайней мере указанной ширины. при необходимости лишние позиции слева (или справа при левостороннем расположении) будут заполнены пробелами.
  • Точка, отделяющая ширину поля от величины, устанавливающей точность.
  • Число (точность), задающее максимальное количество печатаемых символов в строке, или количество цифр после десятичной точки (для чисел с плавающей запятой), или минимальное количество цифр (для целых чисел).
  • Буква h , если печатаемое целое должно рассматриваться как short , или l (строчная латинская буква L), если целое должно рассматриваться как long .


Символы-спецификаторы перечислены в таблице 7.1. Если за % не помещен символ-спецификатор, поведение функции printf будет не определено.

Таблица 7.1. Основные преобразования printf

Символ Тип аргумента; вид печати
d , i int ; десятичное целое
o int ; беззнаковое восьмеричное (octal) целое (без нуля слева)
x , X unsigned int ; беззнаковое шестнадцатиричное целое (без 0x или 0X слева), для шестнадцатиричных цифр от 10 до 15 используются символы a , b , c , d , e , f или A , B , C , D , E , F
u int ; беззнаковое десятичное целое
c int ; одиночный символ
s char * ; печатает символы, пока не встретится символ \0 , или количество символов, заданное точностью
f double ; [-] m.dddddd, где количество цифр d задается точностью (по умолчанию равно 6)
e , E double ; [-] m.dddddd e + xx или [-] m.dddddd E + xx, где количество цифр d задается точностью (по умолчанию равно 6)
g , G double ; использует %e или %E , если порядок меньше, чем -4, или больше или равен точности; в противном случае использует %f. Завершающие нули и завершающая десятичная точка не печатаются
p void * ; указатель (представление зависит от реализации)
% Аргумент не преобразуется; печатается знак %

Ширину и точность можно задавать с помощью знака * ; значение ширины (или точности) в этом случае берется из следующего аргумента, который должен быть типа int . Например, чтобы напечатать не более max символов из строки s , годится следующая запись:

Большая часть форматных преобразований была продемонстрирована в предыдущих главах. Исключение составляет задание точности для строк. Далее приводится перечень спецификаций и показывается их влияние на печать строки «hello, world», состоящей из 12 символов. Поле специально обрамлено двоеточиями, чтобы была видна его протяженность.

Предостережение: функция printf использует свой первый аргумент, чтобы определить, сколько еще ожидается аргументов и какого они будут типа. Вы не получите правильного результата, если аргуметов будет не хватать или они будут принадлежать не тому типу. Вы должны также понимать разницу в следующих двух обращениях:

Функция sprintf выполняет те же преобразования, что и printf , но вывод запоминается в строке

Эта функция форматирует аргументы arg 1 , arg 2 и т.д. в соответствии с информацией, заданной аргументом format , как мы описывали ранее, но результат помещает не в стандартный вывод, а в string . Заметим, что строка string должна быть достаточно большой, чтобы в ней поместился результат.

Ввод-вывод в Си

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

Ввод и вывод информации осуществляется через функции стандартной библиотеки. Прототипы рассматриваемых функций находятся в файле stdio.h . Эта библиотека содержит функции

  • printf() — для вывода информации
  • scanf() — для ввода информации.

Вывод информации

Функция printf() предназначена для форматированного вывода. Она переводит данные в символьное представление и выводит полученные изображения символов на экран. При этом у программиста имеется возможность форматировать данные, то есть влиять на их представление
на экране.

Общая форма записи функции printf() :

СтрокаФорматов состоит из следующих элементов:

  • управляющих символов;
  • текста, представленного для непосредственного вывода;
  • форматов, предназначенных для вывода значений переменных различных типов.

Объекты могут отсутствовать.

Управляющие символы не выводятся на экран, а управляют расположением выводимых символов. Отличительной чертой управляющего символа является наличие обратного слэша ‘\’ перед ним.

Основные управляющие символы:

  • ‘\n’ — перевод строки;
  • ‘\t’ — горизонтальная табуляция;
  • ‘\v’ — вертикальная табуляция;
  • ‘\b’ — возврат на символ;
  • ‘\r’ — возврат на начало строки;
  • ‘\a’ — звуковой сигнал.

Форматы нужны для того, чтобы указывать вид, в котором информация будет выведена на экран. Отличительной чертой формата является наличие символа процент ‘%’ перед ним:

  • %d — целое число типа int со знаком в десятичной системе счисления;
  • %u — целое число типа unsigned int ;
  • %x — целое число типа int со знаком в шестнадцатеричной системе счисления;
  • %o — целое число типа int со знаком в восьмеричной системе счисления;
  • %hd — целое число типа short со знаком в десятичной системе счисления;
  • %hu — целое число типа unsigned short ;
  • %hx — целое число типа short со знаком в шестнадцатеричной системе счисления;
  • %ld — целое число типа long int со знаком в десятичной системе счисления;
  • %lu — целое число типа unsigned long int ;
  • %lx — целое число типа long int со знаком в шестнадцатеричной системе счисления;
  • %f — вещественный формат (числа с плавающей точкой типа float );
  • %lf — вещественный формат двойной точности (числа с плавающей точкой типа double );
  • %e — вещественный формат в экспоненциальной форме (числа с плавающей точкой типа float в экспоненциальной форме);
  • %c — символьный формат;
  • %s — строковый формат.

Строка форматов содержит форматы для вывода значений. Каждый формат вывода начинается с символа % . После строки форматов через запятую указываются имена переменных, которые необходимо вывести.
Количество символов % в строке формата должно совпадать с количеством переменных для вывода. Тип каждого формата должен совпадать с типом переменной, которая будет выводиться на это место. Замещение форматов вывода значениями переменных происходит в порядке их следования.
Пример на Си

Результат работы программы

Тот же самый код может быть представлен с использованием одного вызова printf :

Sprintf форматный вывод в буфер

Функции производят форматированный вывод в символьную строку (функция библиотеки С и С++).

Синтаксис

Параметры

Указатель на строку, в которую осуществляется вывод.

Максимальное число символов, которое сохраняется в версии Unicode этой функции.

Переменное число параметров (дополнительные параметры).

Возвращаемое значение

В случае ошибки возвращается EOF (WEOF)

Функция возвращает число записанных символов или – (минус)1, если произошла ошибка. Если string или format — пустой указатель, вызывается обработчик недопустимых параметров, как описано в статье Проверка достоверности параметров. Если разрешено исполнение кода, чтобы продолжить, эти функции возвращают значение -(минус)1 и устанавливают errno в EINVAL.

Функция sprintf возвращает число байтов, сохраненное в буфере, не считая символ завершающего нуля. Функция swprintf возвращает число «широких » символов, сохраненных в буфере, не считая «широкого » завершающегося нулевого символа.

Замечания

Функция sprintf форматирует и охраняет ряд символов и значений в буфере. Каждый параметр (если он есть) преобразуется и выводится согласно соответствующей спецификации формата. Формат состоит из обычных символов и имеет ту же самую форму и действие, как и параметры формата для функции printf. Нулевой символ добавлен в конец после последнего письменного символа. Если копирование происходит между строками, которые накладываются друг на друга, поведение функции не определяется.

Функция sprintf форматирует и записывает ряд символов и значений в массиве вывода данных, на который ссылается параметр string. Если параметры следуют за строкой format, то форматирующая (format) строка должна содержать спецификации, которые определяют формат вывода для параметров. Функции sprintf и printf ведут себя тождественно за исключением того, что printf печатает выводимые данные в stdout, а не в массив выводимых данных (строку).

Функция swprintf — широкосимвольная версия sprintf (для Unicode); format — широкосимвольная строка. Функции swprintf и sprintf во всем остальном ведут себя тождественно.

Параметр format состоит из обычных символов, последовательностей escape, и (если параметры следуют за параметром format) спецификаций формата. Обычные символы и последовательности escape копируются в строке в порядке их поступления. Например, строка

Спецификации формата всегда начинаются со знака процента (%) и читается слева направо. Когда функция sprintf встречается с первой спецификацией формата (если она есть), то преобразует значение первого параметра после format и выводит его соответственно. Вторая спецификация формата заставляет второй параметр быть преобразованным и выведенным и так далее. Если имеется больше параметров, чем есть их спецификаций, дополнительные параметры игнорируются. Результаты не определяются, если недостаточно параметров для всех спецификаций формата.

Замечание по обеспечению безопасности! Убедитесь в том, что формат не определяемая пользователем строка.

Демонстрационный пример

Вывод данных

Смотри также

Процедуры поддержки плавающей запятой | Процедуры потоков ввода-вывода (I/O) | Локальные процедуры | Функции fopen | fprintf | scanf | sprintf | vprintf | Процедуры времени исполнения программы и эквиваленты .NET Framework

Требования

Процедуры

Требуется заголовочный файл

Совместимость

sprintf ANSI, Win 98, Win Me, Win NT, Win 2000, Win XP swprintf или ANSI, Win 98, Win Me, Win NT, Win 2000, Win XP

Дополнительную информацию о совместимости см. в статье Совместимость в главе Введение.

Библиотеки

Все версии библиотек времени исполнения программы C.

Функции sprintf_s, _sprintf_s_l, swprintf_s, _swprintf_s_l, swprintf и _swprintf_l

Записывает форматированные данные в строку. Доступны более безопасные версии некоторых из этих функций; см. sprintf_s, _sprintf_s_l, swprintf_s, _swprintf_s_l. У swprintf и _swprintf_l нет более безопасной версии, потому что они получают параметр подсчета.

Синтаксис

Параметры

Место хранения для выводимых данных.

Максимальное число символов, которое хранится в версии Unicode этой функции.

Параметр строки управления форматом. Это дополнительные (необязательные) параметры.

Используемый язык страны (местности).

Для получения дополнительной информации, см. статью Спецификации формата.

Возвращаемое значение

Замечания

Замечание по безопасности: При использовании функции sprintf, нет какого-либо способа ограничить число записываемых символов, что означает, что код, используя sprintf, восприимчив к переполнению буфера. Примите во внимание то, что лучше использовать связанные функции _snprintf, которая определяет максимальное число символов, которые будут записаны в буфер или _scprintf, которая определяет какой величины буфер требуется. Кроме того, обеспечьте, чтобы формат являлся не определяемой пользователем строкой.

Функция swprintf — широкосимвольная версия sprintf; параметры указателя на swprintf — широкосимвольные строки. Обнаружение ошибок кодировки в swprintf может отличаться от того, что заложено в функции sprintf. Функции swprintf и fwprintf ведут себя тождественно за исключением того, что swprintf читает выводимые данные в строке, а не в месте назначения типа FILE , а функция swprintf, требует, чтобы параметр подсчета определил максимальное число символов, которое будет записано. Версии этих функций с суффиксом _l идентичны за исключением того, что они используют параметр языка страны (местности), переданный вместо потока текущего языка страны.

В Visual C++ 2005, функция swprintf приведена в соответствие со Стандартом C Международной Организации по Стандартизации (ISO), который требует второго параметра count, типа size_t. Чтобы заставить действовать старое нестандартное поведение функции, определите флажок _CRT_NON_CONFORMING_SWPRINTFS . В будущей версии может быть удалено старое поведение функции, таким образом код должен меняться для использования нового соответствующего стандарту поведения.

В C ++, у этих функций есть перегрузки шаблона, которые вызывают более новые, безопасные копии этих функций. Для получения дополнительной информации, см. статью Безопасные перегрузки шаблона.

Форматный ввод-вывод: функции fscanf и fprintf

В отличие от функции бинарного ввода fread, которая вводит байты из файла без всякого преобразования непосредственно в память компьютера, функция форматного ввода fscanf предназначена для ввода информации с преобразованием ее из текстового представления в бинарное. Пусть информация записана в текстовом файле в привычном для человека виде (т.е. так, что ее можно прочитать или ввести в файл, используя текстовый редактор). Функция fscanf читает информацию из текстового файла и преобразует ее во внутреннее представление данных в памяти компьютера. Информация о количестве читаемых элементов, их типах и особенностях представления задается с помощью формата. В случае функции ввода формат — это строка, содержащая описания одного или нескольких вводимых элементов. Форматы, используемые функцией fscanf, аналогичны применяемым функцией scanf, они уже неоднократно рассматривались (см. раздел 3.5.4). Каждый элемент формата начинается с символа процента «%». Наиболее часто используемые при вводе форматы приведены в таблице:

целое десятичное число типа int (d — от decimal)

вещ. число типа double (lf — от long float)

один символ типа char

ввод строки. Из входного потока выделяется слово, ограниченое пробелами или символами перевода строки ‘\n’. Слово помещается в массив символов. Конец слова отмечается нулевым байтом.

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

int fscanf(FILE *f, const char *format, . );

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

int n, m; double a; char c; char str[256];

fscanf(f, «%d», &n); // Ввод целого числа

fscanf(f, «%lf», &a); // Ввод вещественного числа

fscanf(f, «%c», &c); // Ввод одного символа

fscanf(f, «%s», str); // Ввод строки (выделяется очередное

// слово из входного потока)


fscanf(f, «%d%d», &n, &m); // Ввод двух целых чисел

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

Функция fprintf используется для форматного вывода в файл. Данные при выводе преобразуются в их текстовое представление в соответствии с форматной строкой. Ее отличие от форматной строки, используемой в функции ввода fscanf, заключается в том, что она может содержать не только форматы для преобразования данных, но и обычные символы, которые записываются без преобразования в файл. Форматы, как и в случае функции fscanf, начинаются с символа процента «%». Они аналогичны форматам, используемым функцией fscanf. Небольшое отличие заключается в том, что форматы функции fprintf позволяют также управлять представлением данных, например, указывать количество позиций, отводимых под запись числа, или количество цифр после десятичной точки при выводе вещественного числа. Некоторые типичные примеры форматов для вывода приведены в следующей таблице:

вывод целого десятичного числа

вывод целого десятичного числа, для записи числа отводится 10 позиций, запись при необходимости дополняется пробелами слева

вывод вещественного число типа double в форме с фиксированной десятичной точкой

вывод вещественного число типа double с печатью трёх знаков после десятичной точки

вывод вещественного число типа double с тремя знаками после десятичной точки, под число отводится 12 позиций

вывод одного символа

конец строки, т.е. массива символов. Конец строки задается нулевым байтом

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

int fprinf(FILE *f, const char *format, . );

Многоточие, как и в случае функции fscanf, означает, что функция имеет переменное число аргументов. Количество и типы аргументов, начиная с третьего, должны соответствовать форматной строке. В отличие от функции fscanf, фактические аргументы, начиная с третьего, представляют собой выводимые значения, а не указатели на переменные. Для примера рассмотрим небольшую программу, выводящую данные в файл «tmp.dat»:

#include // Описания функций ввода вывода

#include // Описания математических функций

#include // Описания функций работы со строками

int n = 4, m = 6; double x = 2.;

char str[256] = «Print test»;

FILE *f = fopen(«tmp.dat», «wt»); // Открыть файл

perror(«Не могу открыть файл для записи»);

return 1; // Завершить программу с кодом ошибки

fprintf(f, «n=%d, m=%d\n», m, n);

fprintf(f, «x=%.4lf, sqrt(x)=%.4lf\n», x, sqrt(x));

f, «Строка \»%s\» содержит %d символов.\n»,

fclose(f); // Закрыть файл

return 0; // Успешное завершение программы

В результате выполнения этой программы в файл «tmp.dat» будет записан следующий текст:

Строка «Print test» содержит 10 символов.

В последнем примере форматная строка содержит внутри себя двойные апострофы. Это специальные символы, выполняющие роль ограничителей строки, поэтому внутри строки их надо экранировать (т.е. защищать от интерпретации как специальных символов) с помощью обратной косой черты \, которая, напомним, в системе Unix и в языке Си выполняет роль защитного символа. Отметим также, что мы воспользовались стандартной функцией sqrt, вычисляющей квадратный корень числа, и стандартной функцией strlen, вычисляющей длину строки.

Sprintf форматный вывод в буфер

Интуитивное определение файла звучит примерно так. Файл — именованная область на жестком диске. На самом деле с точки зрения ОС UNIX это совсем не так. В ОС UNIX файл — очень удобная абстракция. С точки зрения UNIX файлом называется «что-нибудь», из чего можно считывать информацию или во что можно записывать информацию. Файлы это:

  • Файлы в обычном смысле: файлы, которые хранятся на жестком диске (можно считывать из них и запиcывать в них информацию);
  • Экран монитора: файл, в который можно выводить информацию (отобразится на экране монитора);
  • Клавиатура: файл, из которого можно считывать информацию;
  • Принтер: файл, в который можно выводить информацию (печать текста);
  • Модем: файл, из которого можно считывать информацию и в который можно записывать информацию (обмен информации по сети);

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

0.2 Разделение понятий файла и названия

Неправильно думать, что между сущностями «файл» и «название файла» есть взаимно однозначное соответствие.

Можно привести аналогию из жизни: если представить, что файл — это банка с некоторым содержимым, то название файла — это этикетка на этой банке. Логично предположить, что у банки может быть несколько этикеток.

С точки зрения UNIX:

Правильно говорить, что у названия есть файл. И наоборот: неправильно говорить, что у файла есть название. Никакого эффективного способа узнать имя файла не существует (но можно перебрать все файлы файловой системы).

Пусть есть файл file1.txt . Для его удаления используется функция:

int unlink(const char* filename);

Эта функция не всегда удаляет файл (с жесткого диска), а только удаляет «этикетку» этого файла. Если есть другая «этикетка» этого файла, то файл останется на жестком диске; просто у него уже не будет этой «этикетки». Файл знает, сколько у него таких «этикеток» (есть специальный счетчик). И если этот счетчик стал равен нулю, то функция удаляет файл с жесткого диска. В ОС Windows эта функция всегда удаляет файл.

Парная функция к этой функции:

int link(const char* filename1, const char* filename2);

Эта функция создает еще одну «этикетку» для этого файла и прибавляет к значению счетчика «этикеток» единицу.

1 Ввод и вывод, язык C, структура FILE

1.1 Чтение и запись: printf и scanf

Всем хорошо известная функция printf :

printf(«Hello!») — печать текста на экран;
printf(«N = %d», N) — форматированный вывод на экран: вывести число N в десятичной записи;
printf(«N = %x», N) — форматированный вывод на экран: вывести число N в шестнадцатеричной записи;

Аналогично парная функция scanf :

char *ptr = new char[10];
scanf(«%s», ptr); — считывание с клавиатуры строки в массив *ptr

Тут могут возникать различные проблемы.

    Проблема безопасности:

char *ptr = new char[10];
scanf(«%s», ptr);

Тут налицо потенциальная проблема переполнения буфера (в данном примере в буфере всего 10 байт).
Никогда не следует пользоваться scanf ‘ом для чтения строк.

scanf + «%s» — запрещенная комбинация!

  • Форматная строка не компилируется: она будет разбираться в момент исполнения программы. Это обозначает проблему быстродействия. scanf — не предназначен для чтения большого количества информации.
    Аналогично printf — тоже сравнительно медленный (однако существенно быстрее, чем scanf ).
  • Проблема безопасной работы со стеком:
    printf(«%d %d», N);

    Проблема состоит в том, что форматная строка «%d %d» будет проанализирована в момент исполнения. В данном случае произойдет ошибка при работе со стеком: во время исполнения будет взят лишний int .

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

    1.2 Чтение и запись файлов: FILE* , fopen , fprintf , fscanf

    Есть несколько способов работы с файлами c использованием языков C и C++.

    Самый распространенный связан со структурой FILE (это не класс, потому что сущность языка C). Эта структура определена в заголовочном файле стандартной библиотеки . Размер этой структуры и ее поля зависят от ОС и от версии компилятора. Поэтому никто не пользуется структурой FILE . Обычно пользуются указателем на эту структуру: FILE* . Например:

    FILE *f = fopen(«file1.txt», «r»);

    fopen — функция из стандартной библиотеки. Первый параметр — имя файла (в текущем каталоге). Второй параметр задает режим открытия файла; в данном случае «r» означает, что файл будет открыт только для чтения. Эта функция возвращает ненулевой указатель, если открытие прошло успешно; и возвращает NULL , если произошла ошибка. Ошибка может возникать в следующих ситуациях:

    1. не существует файла;
    2. у программы недостаточно прав доступа для работы с файлом;

    Для дальнейшей корректной работы следует писать примерно такой код:

    if (f == NULL) <
    // файл не удалось открыть
    >
    else <
    // Работа с файлом
    >

    Допустим, что нам удалось открыть файл, т.е. f != NULL . Тогда для того, чтобы считывать файл, можно использовать функцию:

    Эта функция работает аналогично функции scanf . Поэтому использовать эту функцию небезопасно! Все проблемы, перечисленные для scanf ‘а, имеют место и при работе с fscanf ‘ом.

    Если мы хотим записать в файл что-то, то мы должны сначала открыть его на запись:

    FILE *f = fopen(«file2.html», «w»);
    Тут «w» означает, что мы открываем файл на запись (от write). Если файл не существовал, то он создастся и откроется на запись, а если он существовал, то он сначала будет уничтожен, а затем создан заново, и потом файл будет открыт на запись.
    Еще один способ открыть файл — это открыть его на дозапись. Это можно сделать с помощью параметра «a» (от append). Если файл не существовал, то он создастся и откроется на запись, а если он существовал, то он откроется на запись, и запись будет производится в конец файла.

    Затем можно использовать функцию fprintf(f, . )

    1.2.1 Зачем нужно закрывать файлы

    • Зададимся вопросом: «Что надо сделать после того, как мы поработали с файлом?»
      Формальный ответ: «Закрыть файл.» Это можно сделать с помощью функции:
      fclose(f);

    Но зачем это делать?

    Ввиду механического устройства жесткого диска, данные в файл попадают не сразу. Сначала данные записываются в так называемый буфер (область оперативной памяти), и когда он переполнится, то данные из буфера будут записаны в файл. Такая схема придумана для ускорения работы с файлами. На самом деле, буфер — это поле структуры FILE : указатель на массив char ‘ов.

    Если мы напишем fprintf(. ) , то запись произведется в буфер. И только тогда, когда буфер будет заполнен до конца, он будет сразу весь записан на жесткий диск. По этой причине, если мы не закроем файл функцией fclose(f) , то последние данные из буфера не запишутся в файл. Отсутствие этой команды может привести к потере данных в файле, который был открыт для записи (дозаписи).
    А зачем закрывать файлы, открытые только на чтение?

    Если не закрывать файлы (которые открыты даже для чтения), то это может привести к ограничению доступа к файлу для других программ. Какие именно ограничения наложатся — это зависит от ОС. Но в ОС Windows если файл открыт на чтение и не закрывается, то из другой программы его нельзя удалить.

  • В любой ОС есть ограничение на количество одновременно открытых файлов. И это еще одна причина для закрытия файлов.
  • 1.2.2 Важность буфера при работе с файлами

    • Рассмотрим следующую ситуацию. Программа пишет протокол своих действий в файл (например, с помощью функции fprintf ). Допустим, что программа сломалась. Понятно, что скорее всего получится так, что в файл последний fprintf (последний протокол действий) не запишется. Причина тому — это буфер.
      Чтобы «протолкнуть» буфер в файл, используется функция

    В коде это выглядит примерно так:

    fprintf(file, «%d», data); //данные записались в буфер
    fflush(file); //данные из буфера «проталкнулись» в файл

    1.3 Стандартные уже открытые файлы: stdin, stdout, stderr

    С точки зрения UNIX клавиатура и экран — это файлы.


    Есть три стандартные константы:
    FILE *stdin
    FILE *stdout
    FILE *stderr

    Это три стандартных заранее открытых файла.

    stdin — это стандартный файл (поток) ввода, а stdout — стандартный файл (поток) вывода. Таким образом:
    scanf(. ) в точности эквивалентно fscanf(stdin, . )
    printf(. ) в точности эквивалентно fprintf(stdout, . )

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

    //FILE *f = fopen(. );
    FILE *f = stdin;

    При этом код программы будет содержать такие функции: fscanf(f, . ) или fprintf(f, . ) . А когда отладка законичится, просто снимаем/ставим соответствующие комментарии в двух строчках программы.

    stderr — это стандартный файл (поток) ошибок. По умолчанию выводит данные на экран.
    Но существует заметное отличие этого «файла» от stdin и stdout : stderr — небуферизованный файл (поток). Поэтому в этот файл (поток) все байты уходят без «задержки», которая могла бы возникнуть при буферизированном подходе. Понятно, что польза от этого подхода заключается в том, что вместо кода:

    1.4 Текстовые и бинарные файлы; что меняет опция t/b

    fopen(f, «file1.txt», «w»);

    Почему второй параметр «w» является строкой, а не символом?
    На самом деле бывает много способов прочитать/записать файл. Например:
    fopen(«file1.txt», «wt») — откроет файл как текстовый файл;
    fopen(«file1.txt», «wb») — откроет файл как бинарный файл.

    Но в чем отличие?

    Разница заключается лишь в том, что символы переноса строк запишутся по разному.
    Рассмотрим пример в UNIX и Windows:

    Исходная строка кода выглядит так: fprintf(«Hello\n»);

      Откроем в Windows файл на запись с параметром «wb» (как бинарный файл). Это означает, что в него запишется в точности то, что мы передали в функции fprintf . Тогда в файл запишутся ровно 6 байт: Hello\10

    А теперь мы откроем в Windows файл на запись с параметром «wt» (как текстовый файл). Тогда в файл запишутся ровно 7 байт: Hello\10\13
    Тут \10\13 означает симлов перевода строки в ОС Windows.

    Откроем в UNIX файл на запись с параметром «wt» или «wb» . Тогда в файл запишутся ровно 6 байт: Hello\10
    Тут \10 означает симлов перевода строки в ОС UNIX.

    В ОС UNIX разницы все-таки нет.

    Различие между «wt» и «wb» объясняется тем, что в разных операционных системах символы перевода строки разные. При чтении файла, т.е. при открытии файла с параметрами «rt» или «rb» , проблема следующая. Если мы поставим параметр «rb» , то при чтении файла символ \10 будет восприниматься как перевод строки. А если поставим параметр «rt» , то при чтении файла пара символов \10\13 будет восприниматься как символ перевода строки.

    1.5 Как же читать/писать на самом деле: fgets , fread и fwrite

    Использование функций ptintf и scanf для записи и для чтения — это очень плохая идея. Тогда все-таки как лучше читать и записывать?

    Хороший способ чтения из файла дает функция fgets() (от «get string»):

    char *fgets(char *buffer, size_t length, FILE *file);

    Тут

    • buffer — это указатель на буфер, в который мы читаем;
    • length — это размер буфера;
    • file — это файл, из которого мы читаем (если читаем с клавиатуры, то разумно использовать stdin ).
    • Функция возвращает строку

    Эта функция делает примерно следующее. Она читает из файла file в буфер buffer не больше length-1 символов. Функция может прочитать не все length-1 символов в том случае, если она встретит конец строки, либо конец файла. Функция читает length-1 символ потому, что последний символ функция добавляет сама — ‘\0’

    Налицо быстрота и безопасность. Главное отличие от scanf ‘а заключается в том, что функция перестанет читать в тот момент, когда закончится буфер. Быстрота обусловлена тем, что функция scanf должна в момент выполнения разобрать форматную строку, в то время как fgets просто читает строку.

    1.5.1 Как доставать числа? Семейство atoi, sscanf

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

    В языке C есть семейство функций

    atoi (a — ASCII , i — integer ):

    Функция принимает единственный параметр строку и пытается ее привести в типу int . Надо заметить, что функция atoi безопасная, но не очень удобная. Безопасная в том смысле, что не сломается: atoi(«25a») == 25 . «Неудобства» заключаются в том, то если мы передаем в качестве параметра строку, в которой есть не только числа, нужно быть очень внимательным и знать, как работает эта функция. Функция atoi никак не проинформирует нас, если преобразование прошло неудачно.

    Например, atoi(«abc») == 0 , что на самом деле не совсем соостветствует действительности. Использовать функцию atoi нужно лишь в том случае, когда вы уверены, что в строке есть число.

    Родственные функции: atol, atoll, atof, strtol .

    Им соответствуют функции для преобразования в типы long , long long и float .

    Рассмотрим подробнее strtol :

    long strtol(char *buffer, char **endPtr, int base);

    Тут

    • buffer — это указатель на буфер, из которого мы читаем;
    • endPtr — это переменная, которая используется для того, чтобы сообщить нам насколько успешно произошло преобразование;
      это указатель на char * , в котором записан первый символ, который не смог проинтерпретироваться с помощью функции strtol ;
      Применение выглядит примерно так:

    char *end;
    char *ptr = «25a»;
    int N = strtol(ptr, &end, 10);

    Теперь end указывает на «a».

    if (ptr == end) <
    // ничего не получилось прочитать
    >

  • base — это основание системы счисления, с которой мы работаем (от 2 до 36);
  • Функция возвращает целое число типа long .
  • Более мощное средство

    Есть более мощное средство, чем нежели fgets + atoi . Речь идет о функции sscanf .
    Вместо использования функции fscanf(f, «%d», &N) можно использовать связку:

    fgets(ptr, 100, f);
    sscanf(ptr, «%d», &N);

    В чем преимущество и мощность такого подхода?

    • Мы знаем длину того, что мы прочитали;
    • Рассмотрим следующую ситуацию: мы хотим прочитать какие-то данные, но не смогли из-за ошибки.

    Используя такой подход, мы можем передать пользователю сообщение об ошибке и ту строчку, которую нам не удалось прочитать: ptr . С использованием fscanf ‘а это невозможно.

    С помощью fscanf’ а мы можем только узнать, сколько переменных было успешно прочитан. А именно: посмотреть на возвращаемое значение.

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

    1.5.2 fread и fwrite

    На самом деле не все файлы выглядят как текст. Файле могут быть записаны числовые данные.

    size_t fread(void *ptr, size_t size, size_t nelts, FILE *f);

    • void *ptr — указатель на ту область памяти, в которую мы читаем;
    • size_t size — размер элемента, который мы читаем;
    • size_t nelts — максимальное количество элементов, которые можно записать;
    • FILE *f — файл, из которого читаем;
    • size_t fread() — сама функция возвращает количество элементов, которые удалось прочитать.

    Есть парная функция:

    size_t fwrite(const void *ptr, size_t size, size_t nelts, FILE *F);

    Аналогично fread эта функция возвращает количество элементов, которые удалось записать.
    Тут параметр nelts просто показывает, сколько элементов надо вывести.

    1.6 Другие полезные опции: fseek и ftell

    Для файлов, которые открыты на чтение есть полезные функции. Одна из них это:

    int fseek(FILE *f, long offset, int flag);

    • FILE *f — файл, в котором передвигаемся;
    • long offset — количество байтов для отступа, отступ производится в соответствии с 3-м параметром;
    • int flag — позиция, от которой будет совершен отступ; в стандартной библиотеке C для этого параметра определены 3 константы:

    SEEK_SET — начало файла;
    SEEK_CUR — текущас позиция;
    SEEK_END — конец файла;

  • int fseek() — сама функция возвращает ноль, если операция прошло успешно, иначе возвращается ненулевое значение.
  • Еще одна полезная функция может определить текущее положение в файле (который открыт для чтения):

    long int ftell(FILE *f);

    2 Другие подходы для работы с файлами

    2.1 File descriptors. Open, close, read, write

    В языке C есть много способов работы с файлами. Помимо структуры FILE можно использовать так называемые дескрипторы файла (file descriptors). Дескриптор файла — целое неотрицательное число. Оно обозначает номер открытого файла в таблице открытых файлов операционной системы. Использование дескрипторов файла — более низкий уровень, чем нежели ипользование струкруты FILE. Структура FILE — сущность языка C и его стандартной библиотеки, тогда как дескриптор файла — сущность операционной системы. Например, при работе со структурой FILE автоматически создается буфер, и программист работает с более высокоуровневой абстракцией. А при работе с дескрипторами файла программист должен позаботится о буферизации вручную.

    Пример работы с дескрипторами файла довольно прост и почти в точности повторяет процесс работы со структурой FILE:

    Сходство работы с дескрипторами файла с работой со структурой FILE заключается в том, что в названии функций отсутствует буква «f» . Иногда параметры функций незначительно отличаются.

    Структуру FILE полезно использовать при работе с настоящими «файлами» (которые находятся на жестком диске). Ипользовать дескрипторы файла полезно в случаях работы со специальными «файлами». В этом подходе есть своя специфика работы, но сейчас просто полезно знать, что такой подход существует.

    Аналогами stdin, stdout и stderr в дескрипторах файла являются числа 0, 1 и 2 соответственно. Стандарт POSIX.1 обозначил числа 0, 1, 2 символическими константами STDIN_FILENO, STDOUT_FILENO и STDERR_FILENO соответственно.

    2.2 Memory mapping. Что делает mmap

    Следующий способ работы с файлами удобен в тех случаях, когда приходится читать файл нелинейно: надо «ходить» вперед и назад. В предыдущих подходах такие ситуации оказывались неудобными с точки зрения программирования: получился бы громоздкий код.

    В языке C был придуман удобный способ работы в таких ситуациях, который называется memory mapping. Соответствующая функция:

    Работает эта функция примерно так. Мы указываем этой функции файл на диске, и она «отображает» этот файл в такую-то область в памяти. В результате работы функции мы получаем указатель на начало файла. И потом мы можем работать с этим файлом как с обычным указателем на какую-то область памяти: можем «ходить» вперед и назад по этому файлу.

    Можно «отобразить» не весь файл целиком, а, например, отдельную часть файла: с 3-его килобайта по 4-ый килобайт.

    2.3 Win32 API: FileCreate, FileRead , etc.

    При работе с файлами в ОС Windows можно использовать все те функции, которые были описаны выше. В ОС Windows есть своя большая стандартная библиотека Win32 API . В этой библиотеке также есть функции для работы с файлами: например, функции FileCreate(. ) или FileOpen(. ) . Они по своей работе похожи на функции из стандартной библиотеки C, но отличия также присутствуют. Они заключаются в параметрах этих функций и небольших «хитростях», которые мы здесь опустим.

    Если вы программируете под ОС Windows и пишите программу для работы в ОС Windows, то стоит пользоваться библиотекой Win32 API для работы с файлами.

    3 Ввод и вывод в языке C++, потоки

    В языке C++ объекты для работы с файлами называются потоками (streams). В данном случае слово «поток» означает то же самое, что и «файл» в языке C.

    Классы для работы с файлами в языке C++ называются std::istream и std::ostream для ввода и вывода соответственно.


    3.1 Глобальные переменные std::cout, std::cin, std::cerr

    В header’е объявлена глобальная переменная std::cout; она используется как стандартный поток вывода на экран. Эта переменная является объектом класса std::ostream .
    В этом классе есть перегруженный оператор , который выводит на экран:

    В данном случае на экран будет выведена единица.

    Аналогично можно выводить переменные: std::cout В данном случае переменная N (целое число) будет выведена на экран в естественной форме. Это можно переписать аналогично через printf() :

    Еще в header’е объявлены переменные std::cin и std::cerr для стандартного потока ввода и потока ошибок соответственно. Они являются объектами классов std::istream и std::ostream соотсветственно.

    Аналогично тому, как stderr отличается от stdin , в языке C++ std::cerr отличается от std::cout отсутствием буферизации.

    В классе std::istream есть перегруженный оператор >>. Можно считывать информацию из стандартного потока ввода (с клавиатуры).

    3.2 Форматированный вывод возможен: std::ios::hex

    Возможен ли форматированный вывод, которым мы пользовались в языке C фунцией printf() ? Наример, как вывести ту же переменную N в 16-ой записи?

    В языке C++ форматированный вывод возможен при помощи вывода на экран специальной управляющей команды:

    В точности то же самое выведет команда printf(«%x», N);

    Чтобы не писать перед кажой переменной ее формат, можно использовать функцию:

    Она установит формат вывода в стандартный поток вывода на экран. Этот подход настолько же мощный, как и использование форматной печати с помощью printf .

    3.3 Операторы >

    Давайте рассмотрим более подробно опрератор std::ostream &operator

    • &os — поток, в который мы будем выводить;
    • N — переменная, которую мы будем выводить;
    • Оператор возвращает ссылку на поток, в результате чего можно писать так: std::cout

    В общем случае вторым параметром может быть любой стандартный тип. Это связано с тем, что этот оператор был перегружен для всех стандартных типов языка C++.

    В случае оператора >> все аналогично.

    Если хочется написать свой оператор Complex , то вывод этих чисел через оператор ifstream, ofstream и fstream .

    Код для открытия файла и его чтения выглядит примерно так:

    ifstream ifs;
    ifs.open(«file1.txt»);

    // далее с помощью оператора >> можно читать из файла, если он успешно открылся;

    Аналогично можно использовать конструктор с параметром: ifs(«file1.txt»); после чего создается объект и открывается по возможности файл.

    В классе istream есть метод close() , который закрывает файл (на подобие работы с файлами в языке C). Однако вызывать этот метод необязательно. Дело в том, что в деструкторе класса этот метод вызовется автоматически.

    Работа с объектами классов ofstream и ofstream и fstream осуществляется по аналогичному сценарию.

    3.5 Класс stringstream

    Класс stringstream наследуется от iostream .
    Используется этот для класс для следующих целей. Если мы хотим выводить комплексные числа не только на экран или в файл, но и в окно какой-нибудь программы (GUI), то как использовать stringstream ? При этом мы не хотим писать один и тот же код программы.

    Можно просто печатать в строку с помощью stringstream .

    Что это такое, когда printf() отправляет вывод в буфер?

    Я переживаю «C PRIMER PLUS», и есть эта тема о «OUTPUT FLUSHING». Теперь он говорит:

    printf() отправляют вывод в промежуточное хранилище, называемое буфером. Время от времени материал в буфере отправляется на экран. стандартные правила C, когда вывод отправляется из буфера на экран, ясно:

    • Он отправляется, когда буфер заполняется.
    • Когда встречается символ новой строки.
    • При надвигающемся входе.

    (Отправка вывода из буфера на экран или файл называется сбросом буфер.)

    Теперь, чтобы проверить приведенные выше утверждения. Я написал эту простую программу:

    Таким образом, ни printf() не содержит новую строку, либо у нее есть какой-то надвигающийся вход (например, оператор scanf() или любой другой оператор ввода). Тогда почему он печатает содержимое на экране вывода.

    Предположим, что первое условие подтверждено истинным. Буфер заполнен (что не может произойти вообще). Помня об этом, я усекал утверждение внутри printf() на

    Тем не менее он печатает инструкцию на консоли.

    Итак, в чем заключена сделка, все вышеперечисленные условия ложны, но все же я получаю вывод на экране. Можете ли вы подробно рассказать. Похоже, я ошибаюсь в понимании концепции. Любая помощь приветствуется.

    EDIT: как было предложено очень полезным комментарием, возможно, выполнение функции exit() после завершения программы вызывает сброс всех буферов, в результате чего вывод на консоли. Но тогда, если мы удерживаем экран перед выполнением exit(). Как это,

    Он все еще выводится на консоль.

    Буферизация вывода — это метод оптимизации. Запись данных на некоторые устройства (жесткие диски f.e.) — дорогостоящая операция; почему появилась буферизация. По сути, он избегает записи данных побайтно (или char -by- char) и собирает их в буфере, чтобы сразу записать несколько KiB данных.

    Будучи оптимизацией, буферизация вывода должна быть прозрачной для пользователя (она прозрачна даже для программы). Это не должно влиять на поведение программы; с буферизацией или без нее (или с разными размерами буфера), программа должна вести себя одинаково. Это то, о чем вы говорили.

    Буфер — это только область памяти, в которой данные, которые должны быть записаны, временно сохраняются до тех пор, пока не будет накоплено достаточное количество данных, чтобы сделать процесс записи на устройство эффективным. Некоторые устройства (жесткий диск и т.д.) Даже не позволяют записывать (или читать) данные небольшими частями, но только в блоках определенного фиксированного размера.

    Правила промывки буфера:

    Это очевидно. Буфер заполнен, его цель выполнена, пусть данные передаются на устройство. Кроме того, вероятно, есть больше данных, поступающих из программы, нам нужно освободить место.

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

    Но почему вывод на терминал требует буферизации? Написание на терминале не дорого. Это правильно, когда терминал физически расположен рядом с процессором. Не также, когда терминал и процессор находятся на половине земного шара друг от друга, и пользователь запускает программу через удаленное соединение.

    Он должен прочитать «когда есть препятствия для ввода на одном устройстве», чтобы он был прояснен.

    Чтение также буферизуется по той же причине, что и запись: эффективность. Код чтения использует свой собственный буфер. Он заполняет буфер при необходимости, затем scanf() , а другие функции ввода-вывода получают свои данные из входного буфера.

    Когда вход должен произойти на том же устройстве, буфер должен быть сброшен (данные, фактически записанные на устройство), чтобы обеспечить согласованность. Программа отправляет некоторые данные на выход, и теперь она ожидает, что она вернет те же данные; почему данные должны быть сброшены на устройство, чтобы код чтения нашел его и загрузил.

    Но почему буферы очищаются при выходе приложения?

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

    Буферы также очищаются, когда связанные файлы закрываются по той же причине. И это то, что происходит, когда приложение выходит: код очистки закрывает все открытые файлы (стандартный ввод и вывод — это просто файлы с точки зрения приложения), закрывая силы, смывающие буферы.

    Часть спецификации exit() в стандарте C (ссылка POSIX):

    Затем все открытые потоки с неписаными буферизованными данными очищаются, все открытые потоки закрываются.

    Таким образом, когда программа выходит, ожидающий вывод сбрасывается, независимо от строк новой строки и т.д. Аналогично, когда файл закрыт ( fclose() ), ожидающий выход записывается:

    Любые неписанные буферизованные данные для потока доставляются в среду хоста для записи в файл; любые непрочитанные буферизованные данные отбрасываются.

    И, конечно, функция fflush() выполняет сброс вывода.

    Правила, указанные в вопросе, не совсем точны.

    Когда буфер заполнен — ​​это правильно.

    Когда встречается новая строка — это неверно, хотя это часто применяется. Если выходное устройство является «интерактивным устройством», то по умолчанию используется буферизация строк. Однако, если выходное устройство является «неинтерактивным» (файл диска, труба и т.д.), Тогда выход не обязательно (или обычно) буферизируется по строке.

    Когда надвигается ввод — это тоже неверно, хотя обычно это работает. Опять же, это зависит от того, являются ли устройства ввода и вывода «интерактивными».

    Режим буферизации вывода можно изменить, вызвав setvbuf() для установки буферизации, буферизации строк или полной буферизации.

    В стандарте говорится (§7.21.3):

    ¶3 Когда поток небуферизирован, символы должны появляться как из источника, так и из пункта назначения как можно скорее. В противном случае символы могут накапливаться и передаваться в или из среды хоста в виде блока. Когда поток полностью буферизирован, символы предназначены для передачи в или из среды хоста в виде блока при заполнении буфера. Когда поток буферизируется по строке, символы предназначены для передачи в среду хоста или из нее как блок, когда встречается символ новой строки. Кроме того, символы предназначены для передачи в виде блока в среду хоста при заполнении буфера, когда ввод запрашивается в небуферизованном потоке или когда запрос запрашивается в потоке с буферизацией, который требует передачи символов из среды хоста, Поддержка этих характеристик определяется реализацией и может быть затронута с помощью функций setbuf и setvbuf .

    ¶7 При запуске программы три текстовых потока предопределены и их явно не нужно открывать — стандартный ввод (для чтения обычного ввода), стандартный вывод (для записи обычного вывода) и стандартная ошибка (для записи диагностического вывода). Как первоначально было открыто, стандартный поток ошибок не полностью буферизирован; стандартные входные и стандартные выходные потоки полностью буферизуются тогда и только тогда, когда можно определить поток, чтобы не ссылаться на интерактивное устройство.

    Кроме того, в §5.1.2.3 Выполнение программы говорит:

    • Динамика входа и выхода интерактивных устройств должна иметь место, как указано в 7.21.3. Цель этих требований состоит в том, чтобы как можно скорее появился небуферизованный или строковый вывод, чтобы убедиться, что сообщения запроса действительно отображаются до того, как программа ожидает ввода.

    Ввод и вывод данных средствами языка C

    В системе ввода-вывода в Си для программ поддерживается единый интерфейс, не зависящий от того, к какому конкретному устройству осуществляется доступ. То есть в Си между программой и устройством находится нечто более общее, чем само устройство. Такое обобщенное устройство ввода или вывода (устройство более высокого уровня абстракции) называется потоком. В то же время конкретное устройство называется файлом. Наша задача — понять, каким обрзом происходит взаимодействие потоков и файлов.
    Файловая система Си предназначена для работы с разными устройствами, в том числе с терминалами, дисководами и накопителями. Даже, если какое-то устройство очень сильно отличается от других устройств, буферизованная файловая система все равно представит его в виде логического устройства, которое называется потоком. Все потоки ведут себя похожим образом. И так как они в основном не зависят от физических устройств, то та же функция, которая выполняет запись в дисковый файл, может ту же операцию выполнить и на другом устройстве. Например, на консоли. Потоки бывают двух видов: текстовые и двоичные.
    В языке Си файлом может быть все, что угодно, начиная в дискового файла и заканчивая терминалом или принтером. Поток связывают с определенным файлом, выполняя обязательную операцию открытия. Как только файл открыт, можно проводить обмен информацией между ним и программой.
    Но не у всех файлов одинаковые возможности. Например, к дисковому файлу прямой доступ возможен, в то время как к некоторым принтерам — он не возможен. Таким образом, вы видите, что напрашивается определенный вывод, являющийся принципом системы ввода-вывода языка Си: все потоки одинаковы, а файлы — нет!
    Если файл может поддерживать запросы на местоположение (указатель текущей позиции), то при открытии такого файла указатель текущей позиции в файле устанавливается в начало файла. При чтении каждого символа из файла (или записи в файл) указатель текущей позиции увеличивается. Тем самым обеспечивается продвижение по файлу.
    Файл отсоединяется от определенного потока (то есть разрывается связь между файлом и потоком) с помощью операции закрытия файла. При закрытии файла, открытого с целью вывода, содержимое (если оно, конечно, есть) связанного с ним потока записывается на внешнее устройство. Этот процесс обычно называют дозаписью потока. При этом гарантируется, что никакая информация случайно не останется в буфере диска.
    Если программа завершает работу нормально, то есть либо main() возвращает управление операционной системе, либо выход происходит через exit(), то все файлы закрываются автоматически.
    В случае же аварийного завершения работы программы, например, в случа краха или завершения путем вызова abort(), файлы не закрываются.
    У каждого потока, связанного с файлом, имеется управляющая структура, содержащая информацию о файле. Она имеет тип FILE. Блок управления файлом — это небольшой блок памяти, временно выделенный операционной системой для хранения информации о файле, который был открыт для использования. Блок управления файлом обычно содержит информацию об идентификаторе файла, его расположении на диске и указателе текущей позиции в файле.
    Для выполнения всех операций ввода-вывода следует использовать только понятия потоков и применять всего лишь одну файловую систему. Ввод или вывод от каждого устройства автоматически преобразуется системой в легко управлемый поток. И это является достижением языка Си.
    Таковы основополагающие замечания относительно существования различных потоков информации и связанных с ними файлов.
    Файловая система языка Си состоит из нескольких взаимосвязанных между собой функций. Для их работы в Си требуется заголовочный файл и такой же аналогичный ему заголовочный файл требуется для работы в С++.
    Ниже приведена таблица основных (часто используемых) функций файловой системы языка Си.

    Имя Что делает эта функция Имя Что делает эта функция
    fopen() Открывает файл feof() Возвращает значение true (истина), если достигнут конец файла
    fclose() Закрывает файл ferror() Возвращает значение true (истина), если произошла ошибка
    putc() Записывает символ в файл remove() Стирает файл
    fputc() То же, что и putc() fflush() Дозапись потока в файл
    getc() Читает символ из файла rewind() Устанавливает указатель текущей позиции в начало файла
    fgetc() То же, что и getc() ftell() Возвращает текущее значение указателя текущей позиции в файле
    fgets() Читает строку из файла fprintf() Для файла то же, что printf() для консоли
    fputs() Записывает строку в файл fscanf() Для файла то же, что scanf() для консоли
    fseek() Устанавливает указатель текущей позиции на определенный байт файла

    Заголовок представляет прототипы функций ввода-вывода в Си и определяет следующие три типа: size_t, fpos_t и FILE. Первые два: size_t, fpos_t представляют собой разновидности такого типа, как целое без знака. Отдельно рассмотрим третий тип: FILE.
    Указатель файла — это то, что соединяет в единое целое всю систему ввода-вывода языка Си. Указатель файла — это указатель на структуру типа FILE. Он указывает на структуру, содержащую различные сведения о файле, например, его имя, статус, и указатель текущей позиции в начало файла. В сущности указатель файла определяет конкретный файл и используется соответствующим потоком при выполнении функции ввода-вывода.
    Чтобы выполнять в файлах операции чтения и записи, программы должны использовать указатели соответствующих файлов. Чтобы объвить переменную-указатель файла необходимо использовать следующий оператор:
    FILE *fp;
    Функция fopen() открывает поток и связывает с этим потоком файл. Затем она возвращает указатель этого файла. Прототип функции имеет вид:
    FILE *fopen(const char *имя_файла, const char *режим);
    Здесь имя_файла — это указатель на строку символов, представляющую собой допустимое имя файла, в которое может входить спецификация файла (включает обозначение логического устройства, путь к файлу и собственно имя файла).
    Режим — определяет, каким образом файл будет открыт. Ниже в таблице показаны допустимые значения режимов.

    Режим Что обозначает данный режим
    r Открыть текстовый файл для чтения
    w Создать текстовый файл для записи
    a Добавить в конец текстового файла
    wb Создать двоичный файл для записи
    rb Открыть двоичный файл для чтения
    ab Добавить в конец двоичного файла
    r+ Открыть текстовый файл для чтения/записи
    w+ Создать текстовый файл для чтения/записи
    a+ Добавить в конец текстового файла или создать текстовый файл для чтения/записи
    r+b Открыть двоичный файл для чтения/записи
    w+b Создать двоичный файл для чтения/записи
    a+b Добавить в конец двоичного файла или создать двоичный файл для чтения/записи

    Приведем фрагмент программы, в котором используется функция fopen() для открытия файла по имени TEST.
    FILE *fp;
    fp = fopen(«test», «w»);
    Следует сразу же указать на недостаточность такого кода в программе. Хотя приведенный код технически правильный, но его обычно пишут немного по-другому.
    FILE *fp;
    if ((fp = fopen(«test», «w»)==NUL)
    <
    printf(«Ошибка при открытии файла.\n\r»)»
    exit(1);
    >

    Рис. 1
    Этот метод помогает при открытии файла обнаружить любую ошибку.
    Например, защиту от записи или полный диск. Причем, обнаружить еще до того, как программа попытается в этот файл что-то записать. Поэтому всегда нужно вначале получить подтверждение, что функция fopen() выполнилась успешно, и лишь затем выполнять c файлом другие операции. Ниже на рисунке 1 приведена небольшую часть программы, которая. подтверждает или не подтверждает открытие файла. Результаты работы указанной программы приведены на рисунке 2.

    Потоковый ввод-вывод
    На уровне потокового ввода-вывода обмен данными производится побайтно. Такой ввод-вывод возможен как для собственно устройств побайтового обмена (печатающее устройство, дисплей), так и для файлов на диске, хотя устройства внешней памяти, строго говоря, являются устройствами поблочного обмена, т.е. за одно обращение к устройству производится считывание или запись фиксированной порции данных. Чаще всего минимальной порцией данных, участвующей в обмене с внешней памятью, являются блоки в 512 байт или 1024 байта. При вводе с диска (при чтении из файла) данные помещаются в буфер операционной системы, а затем побайтно или определенными порциями передаются программе пользователя. При выводе данных в файл они накапливаются в буфере, а при заполнении буфера записываются в виде единого блока на диск за одно обращение к последнему. Буферы операционной системы реализуются в виде участков основной памяти. Поэтому пересылки между буферами ввода-вывода и выполняемой программой происходят достаточно быстро в отличие от реальных обменов с физическими устройствами.
    Функции библиотеки ввода-вывода языка Си, поддерживающие обмен данными с файлами на уровне потока, позволяют обрабатывать данные различных размеров и форматов, обеспечивая при этом буферизованный ввод и вывод. Таким образом, поток — это файл вместе с предоставляемыми средствами буферизации.
    При работе с потоком можно производить следующие действия:
    · открывать и закрывать потоки (связывать указатели на потоки с конкретными файлами);
    · вводить и выводить: символ, строку, форматированные данные, порцию данных произвольной длины;
    · анализировать ошибки потокового ввода-вывода и условие достижения конца потока (конца файла);
    · управлять буферизацией потока и размером буфера;
    · получать и устанавливать указатель (индикатор) текущей позиции
    При открытии потока могут возникнуть следующие ошибки: указанный файл, связанный с потоком, не найден (для режима «чтение»); диск заполнен или диск защищен от записи и т.п. Необходимо также отметить, что при выполнении функции fopen() происходит выделение динамической памяти. При её отсутствии устанавливается признак ошибки «Not enough memory» (недостаточно памяти). В перечисленных случаях указатель на поток приобретает значение NULL. Заметим, что указатель на поток в любом режиме, отличном от аварийного никогда не бывает равным NULL.
    Приведем типичную последовательность операторов, которая используется при открытии файла, связанного с потоком:
    if ((fp = fopen(«t.txt»,»w»)) == NULL)
    perror(«ошибка при открытии файла t.txt \n»);
    exit(0);
    >
    Где NULL — нулевой указатель, определенный в файле stdio.h.
    Открытые на диске файлы после окончания работы с ними рекомендуется закрыть явно. Для этого используется библиотечная функция
    int fclose (указатель_на_поток);
    Открытый файл можно открыть повторно (например, для изменения режима работы с ним) только после того, как файл будет закрыт с помощью функции fclose().
    Когда программа начинает выполняться, автоматически открываются пять потоков, из которых основными являются:
    · стандартный поток ввода (на него ссылаются, используя предопределенный указатель на поток stdin);
    · стандартный поток вывода (stdout);
    · стандартный поток вывода сообщений об ошибках (stderr).
    По умолчанию стандартному потоку ввода stdin ставится в соответствие клавиатура, а потокам stdout и stderr соответствует экран дисплея.
    Одним из наиболее эффективных способов осуществления ввода-вывода одного символа является использование библиотечных функций getchar( ) и putchar(). Прототипы этих функций имеют следующий вид:
    int getchar(void);
    int putchar(int c);
    Функция getchаr( ) осуществляет ввод одного символа. При обращении она возвращает в вызвавшую ее функцию один введенный символ.
    Функция putchar( ) выводит в стандартный поток один символ, при этом также возвращает в вызвавшую ее функцию только что выведенный символ.
    Обратите внимание на то, что функция getchar( ) вводит очередной байт информации (символ) в виде значения типа int. Это сделано для того, чтобы гарантировать успешность распознавания ситуации «достигнут конец файла». Дело в том, что при чтении из файла с помощью функции getchar() может быть достигнут конец файла. В этом случае операционная система в ответ на попытку чтения символа передает функции getchar() значение EOF (End of File). Константа EOF определена в заголовочном файле stdio.h и в разных операционных системах имеет значение 0 или -1. Таким образом, функция getchar() должна иметь возможность прочитать из входного потока не только символ, но и целое значение. Именно с этой целью функция getchar( ) всегда возвращает значение типа int.
    В случае ошибки при вводе функция getchar() также возвращает EOF.
    При наборе текста на клавиатуре коды символов записываются во внутренний буфер операционной системы, Одновременно они отображаются (для визуального контроля) на экране дисплея. Набранные на клавиатуре символы можно редактировать (удалять и набирать новые). Фактический перенос символов из внутреннего буфера в программу происходит при нажатии клавиши . При этом код клавиши также заносится во внутренний буфер. Таким образом, при нажатии на (Клавишу ‘А’ и клавишу (завершение ввода) во внутреннем буфере оказываются: код символа ‘А’ и код клавиши . ) Об этом необходимо помнить, если вы рассчитываете на ввод функцией getchar() одиночного символа.
    Приведём в пример программу копирования из стандартного ввода в стандартный вывод:
    #include
    int main()
    <
    int c;
    while ((c=getchar())!=EOF)
    Putchar(c);
    return 0;
    >
    Для завершения приведенной выше программы копирования необходимо ввести с клавиатуры сигнал прерывания Ctrl+C.
    Одной из наиболее популярных операций ввода-вывода является операция ввода-вывода строки символов. В библиотеку языка Си для обмена данными через Стандартные потоки ввода-вывода включены функции ввода-вывода строк gets() и puts(), которые удобно использовать при создании диалоговых систем. Прототипы этих функций имеют следующий вид:
    char * gets (char * s); /* Функция ввода */
    int puts (char * s); /* Функция вывода */
    Обе функции имеют только один аргумент — указатель s на массив символов. Бели строка прочитана удачно, функция gets( ) возвращает адрес того массива s, в который производился ввод строки. Если произошла ошибка, то возвращается NULL.
    Функция puts() в случае успешного завершения возвращает последний выведенный символ, который всегда является символом ‘\n’. Если произошла ошибка, то возвращается EOF.

    32) Ввод и вывод данных средствами языка C++.

    В языке С имеется весьма развитая библиотека функций ввода-вывода. Однако в самом языке отсутствуют какие-либо предопределенные файловые структуры. Все данные обрабатываются как последовательность байт. Имеется три основных типа функций: потоковые, работающие с консолью и портами ввода-вывода и низкоуровневые.
    Потоковые функции.
    В потоковых функциях файлы данных рассматриваются как поток отдельных символов.
    Когда программа открывает файл для ввода вывода при помощи потоковых функций, то открытый файл связывается с некоторой переменной типа FILE (определенной в stdio.h), содержащей базовую информацию об этом файле. После открытия потока с помощью функции fopen возвращается указатель на эту переменную. Этот указатель используется для ссылки к файлу при всех последующих операциях ввода-вывода и называется указателем потока.
    Все потоковые функции обеспечивают буферизованный, форматированный или неформатированный ввод/вывод. Буферизация потока разгружает приложение. Однако следует иметь ввиду, что при аварийном завершении программы содержимое буферов вывода может быть потеряно.
    Аналогичным образом выглядят функции, работающие с консолью и портами. Они позволяют читать и писать на терминал или в порт ввода/вывода (например в порт принтера). Функции портов ввода/вывода выполняют простое побайтное считывание или запись. Функции ввода/вывода на консоль обеспечивают несколько дополнительных возможностей, например можно определить момент, когда будет введен символ с консоли и т.п.
    Для использования потоковых функций в программу должен быть включен заголовочный файл stdio.h. В нем содержатся описания прототипов функций ввода/вывода, а также — описания ряда констант. Константа EOF определяется как значение, возвращаемое при обнаружении конца файла, BUFSIZE — размер буферов потока, тип FILE определяет структуру, используемую для получения информации о потоке.
    Поток открывается с помощью функций fopen(), fdopen() или freopen(). В момент открытия задаются режим файла и способ доступа. Эти функции возвращают указатель на переменную типа FILE, например
    FILE *file1;
    file1=fopen(“input.dat”,”r”);
    открывает файл input.dat для чтения. Переменная file1 получает указатель на поток.
    Возможные типы доступа:
    “a” – запись в режиме добавления в конец файла,
    ”a+” –тоже, что и “a”, но возможно и чтение,
    ”r” – только для чтения,
    ”r+” – для чтения и записи,
    ”w” – открывается пустой файл для записи,
    ”w+” – открывается пустой файл для записи и чтения.
    Когда начинается выполнение приложения автоматически открывается следующие потоки: стандартное устройство ввода stdin, стандартное устройство вывода stdout, устройство сообщений об ошибках stderr, устройство печати stdprn и стандартное дополнительное устройство stdaux. Эти файловые указатели можно использовать во всех функциях ввода/вывода в качестве указателя на поток. Некоторые функции автоматически используют указатели на поток, например getchar() и putchar() используют stdin и stdout соответственно.
    Для закрытия потоков используются функции fclose() и fcloseall(). Если программа не закрывает поток явно, то он закрывается автоматически по ее завершению.
    Для перемещения по файлу можно использовать функции fseek(), ftell() и rewind().
    Низкоуровневый ввод и вывод.
    Функции низкоуровневого ввода-вывода не выполняю никакой буферизации и форматирования. Они непосредственно обращаются к средствам ввода/вывода операционной системы.
    При открытии файла на этом уровне возвращается описатель файла (file handle), представляющий собой целое число, используемое затем для обращения к этому файлу при дальнейших операциях. Для открытия используется функция open(), для закрытия – функция close().
    Функция read() читает данные в указанный массив, а write() – выводит данные из массива в файл, lseek() – используется для перемещения по файлу.
    Низкоуровневые функции не требуют включения заголовочного файла stdio.h, вместо него используется файл io.h.
    Низкоуровневая система ввода-вывода не вошла в стандарт ANSI C, поэтому ее не рекомендуют для дальнейшего использования.
    Ввод и вывод символов, строк, слов.
    Наиболее общими функциями являются те, которые работают с отдельными символами. Функция getc() вводит один символ из указанного файлового потока в переменную типа int:

    int ic;
    ic=getc(stdin);

    Вводится один символ из потока stdin.
    Функция putc() передает один символ в указанный файловый поток:

    Для стандартных потоков stdin и stdout можно использовать функции getchar() и putchar() соответственно:

    int ic;
    ic=getchar();
    putchar(ic);

    Функции getch() и putch() являются низкоуровневыми функциями. Обычно функция getch() используется для перехвата символа, введенного с клавиатуры сразу после его нажатия. Нажатия клавиши “Enter” не требуется.
    Для ввода/вывода текстовых строк можно использовать функции gets(), fgets(), puts(), fputs(). Функция fgets() имеет вид:
    fgets(имя_массива, размер_массива, указатель_на_поток);
    Она считывает символы в указанный массив и добавляет в конце null-символ. Считывание производится до заполнения массива, или до достижения конца файла. Символ перевода строки переписывается в массив.
    Для ввода и вывода целых чисел можно использовать функции getw() и putw(). Они работают с двоичными файлами.
    Форматированный ввод и вывод.
    Богатый ассортимент средств управления форматом позволяет легко создавать таблицы, графики или отчеты. Функциями, выполняющими этот вывод являются printf() — для стандартного потока вывода stdout, и fprintf() – для любого потока. Функция fprintf() имеет вид:
    fprintf(поток_вывода, “формат”, перем_1, перем_2,…);
    Работает она аналогично printf() и выводит данные в указанный поток вывода.
    Для форматированного ввода используются функции scanf() и fscanf().
    Для преобразования текстовой строки можно использовать sscanf(). Она работает аналогично fscanf(), но данные берет из сроки, а не из файла.
    Потоки cin, cout, cerr.
    В языке С++ имеется другая библиотека ввода/вывода, определяемая заголовочным файлом iostream.h. Ввод/вывод в ней определяется набором специальных классов. Аналогами потоков stdin, stdout и stderr являются cin, cout и cerr. Они открываются автоматически при запуске программы.
    Операции выделения >> и вставки > выделяет данные из входного потока и помещает в указанные переменные, а операция >ivalue>>dvalue>>cvalue;

    Аналогично для вывода:

    printf(“Integer:%d double: %lf”,ivalue,dvalue);
    cout
    #include
    using namespace std;

    int main()
    <
    int num[10];

    for(int i=0; i
    #include
    #include
    using namespace std;

    int main()
    <
    int num[10];
    int i, j, k;
    int size = 10;

    // Меняем элементы местами.
    i = num[k-1];
    num[k-1] = num[k];
    num[k] = i;
    >
    >
    >
    // Конец сортировки.

    // Отображаем отсортированный массив.
    cout
    #include
    using namespace std;

    Илон Маск рекомендует:  fieldset в HTML
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL