Функции форматного вывода и ввода printf и scanf

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

int printf (char *format, arg1, arg2, . . . );

Функция printf преобразует, форматирует и печатает свои аргументы arg1, arg2 и т.д. в стандартном выводе (обычно на экране) в соответствии с информацией, заданной аргументом format, и возвращает количество напечатанных символов.

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

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

· Число, задающее минимальную ширину поля. Преобразованный аргумент будет занимать поле по крайней мере указанной ширины. При необходимости лишние позиции слева (или справа при левостороннем выравнивании) будут заполнены пробелами.

· Точка, отделяющая ширину поля от величины, устанавливающей точность.

· Число (точность), задающее максимальное количество печатаемых символов строки, или количество цифр после десятичной точки – для плавающего значения, или минимальное количество цифр – для целого значения.

· Буква h, если печатаемое целое должно рассматриваться как short, или l (латинская буква «эль»), если целое должно рассматриваться как long.

 

Перечень символов-спецификаторов и задаваемые ими преобразования вывода

Символ-спецификатор Тип аргумента Вид печати
d, i int Десятичное целое
O int Беззнаковое восьмеричное целое (без ведущего нуля)
x, X int Беззнаковое шестнадцатиричное целое (без ведущих и ), для 10,11, … ,15 используются abcdef или ABCDEF
u int Беззнаковое десятичное целое
C int Одиночный символ
S char * Печатаются символы, расположенные до нуль-символа (‘\0’), или в количестве, заданном точностью
F double [ - ]m.dddddd, где количество цифр d задается точностью (по умолчанию равно 6)
e, E double [ - ]m.dddddde±xx или [ - ]m.ddddddE±xx, где количество цифр d задается точностью (по умолчанию равно 6)
g, G double Применяется %e или %E, если порядок меньше, чем -4, или больше или равен точности; в противном случае применяется %f. «Хвостовые» нули и «хвостовая» десятичная точка не печатаются
P void * Указатель (представление зависит от реализации)
%   Печатается знак %

 

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

int scanf (char *format, arg1, arg2, . . . );

Функция scanf читает символы из стандартного входного потока (обычно с клавиатуры), интерпретирует их согласно спецификациям строки format и рассылает результаты в свои аргументы arg1, arg2 и т.д. Эти аргументы, каждый из которых должен быть указателем, определяют, где будут запоминаться должным образом преобразованные данные.

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

fflush(stdin);

Строка format, управляющая преобразованиями ввода, может включать в себя следующие элементы:

· Пробелы или табуляции, которые игнорируются.

· Обычные литеры (исключая %), которые, как ожидается, совпадут с очередными непробельными символами входного потока.

· Спецификации преобразования, каждая из которых начинается со знака % и завершается символом-спецификатором типа преобразования. В промежутке между ними могут располагаться, причем в указанном здесь порядке: знак * (признак подавления присваивания); число, определяющее ширину поля; буква h, l или L, указывающая на размер получаемого значения.

 

Перечень символов-спецификаторов и задаваемые ими преобразования ввода

Символ-спецификатор Вводимые данные Тип аргумента
D Десятичное целое int *
I Целое, которое может быть восьмеричным (с ведущим 0) или шестнадцатиричным (с ведущими или ) int *
O Восьмеричное целое (с ведущим нулем или без него) int *
u Беззнаковое десятичное целое unsigned int *
X Шестнадцатиричное целое (с ведущими или или без них) int *
C Следующие символы ввода (по умолчанию один) размещаются в указанном месте. Пробельные символы не пропускаются; чтобы прочесть очередной символ, отличный от пробельного, используйте %1s char *
S Строка символов (без обрамляющих кавычек). Завершающий нуль-символ (‘\0’) будет добавлен char *
e, f, g Число с плавающей точкой, возможно со знаком; обязательно присутствие либо десятичной точки, либо экспоненциальной части, а возможно, и обеих вместе float *
% Сам знак %, никакое присваивание не выполняется  

 

Перед символами-спецификаторами d, i, o, u, x может стоять буква h, указывающая на то, что соответствующий аргумент должен иметь тип short * (а не int *), или l (латинская «эль»), указывающая на тип long *. Аналогично, перед символами-спецификаторами e, f, g может стоять буква l, указывающая, что тип аргумента – double * (а не float *).

 

Тема 11. Файлы

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

FILE *fp;

где FILE - имя типа по аналогии с char, int, float, double; fp - переменная-указатель на файл.

Далее нужно открыть файл, т.е. связать указатель файла с конкретным файлом, который или уже существует или будет создаваться. Для этого используется функция fopen(<имя файла>, <режим>), например:

fp = fopen("myFile1", "w");

Здесь "myFile1" - имя файла, "w" - режим использования файла. Возможны следующие режимы:

"r" - чтение существующего файла;

"w" - запись в файл (если он существует, то его содержимое уничтожается; если файл

отсутствует, то он будет создан;

"a" - добавление в конец файла (если файл отсутствует, то он будет создан).

Чтобы выполнялись и чтение и запись нужно в стринг режима добавить знак "+". Для бинарных (двоичных) файлов в стринг режима нужно добавить букву "b", а для текстовых файлов - букву "t" (последнее подразумевается по умолчанию).

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

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

Пример 1. Запишем в файл myFile1 данные, а затем выполним чтение этих данных из файла:

int n1 = 123, n2 = 6789, n3, n4;

char m1[] = "Character_data", m2[50];

 

fprintf(fp, "%d %d %s", n1, n2, m1); //запись данных в файл из n1, n2 и массива m1

fclose(fp); //закрытие файла

 

fp = fopen("myFile1", "r"); //открытие файла на чтение

fscanf(fp, "%d%d%s", &n3, &n4, m2); //чтение данных из файла в n3, n4 и массив m2

fclose(fp); //закрытие файла

 

puts("------ Numbers and string: ------");

printf("%d %d %s", n3, n4, m2); //вывод данных на экран из n3, n4 и массива m2

puts(""); //переход к новой строке

 

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

fp = fopen("myFile1", "w+"); //открытие файла на запись и чтение

fprintf(fp, "%d %d %s", n1, n2, m1); //запись данных в файл

 

rewind(fp); //переход к началу файла

 

fscanf(fp, "%d%d%s", &n3, &n4, m2); //чтение данных из файла

fclose(fp); //закрытие файла

 

printf("%d %d %s\n", n3, n4, m2); //вывод данных на экран

 

Пример 2. Запишем в файл, а затем прочитаем из него структуру данных:

struct student {

char familia[50];

int N_zachetki, god_rogdenia;

} stu = {"Ivanov_Ivan_Ivanovich", 572203, 1987};

 

fp = fopen("myFile2", "w+"); //открытие файла на запись и чтение

 

fprintf(fp, "%s %d %d", stu.familia, stu.N_zachetki, stu.god_rogdenia); //запись данных

//в файл

rewind(fp); //переход к началу файла

fscanf(fp, "%s%d%d", m2, &n3, &n4); //чтение данных из файла

fclose(fp); //закрытие файла

 

puts("------ Struktura: ---------------");

printf("%s %d %d\n", m2, n3, n4); //вывод данных на экран

 

Пример 3. Запишем в файл и прочитаем из него массив данных:

int mas1[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};

int mas2[10];

 

fp = fopen("myFile3", "w+"); //открытие файла на запись и чтение

 

for (int i=0; i<10; ++i)

fprintf(fp, "%d ", mas1[i]);

 

rewind(fp); //переход к началу файла

 

for (i=0; i<10; ++i)

fscanf(fp, "%d", &mas2[i]);

 

fclose(fp);

 

puts("------ Massiv: ------------------");

for (i=0; i<10; ++i)

printf("%d ", mas2[i]);

 

Замечание 1. Если при чтении достигнут конец файла, то следующая функция чтения fscanf возвращает константу EOF (End Of File). Поэтому, если неизвестно, сколько данных содержится в файле, то можно организовать чтение в цикле и выйти из него по условию, например, так:

while (1)

{

. . .

if (fscanf(fp, "%d ", &n) == EOF)

break; //выход из цикла

. . .

}

Замечание 2. Для работы с символьной информацией можно также использовать функции fgets и fputs, которые похожи на функции gets и puts, но отличаются тем, что в них добавлен еще один аргумент - указатель файла, а в функцию fgets - еще и агрумент, задающий число считываемых символов (может быть считано меньше символов, если встретится символ перевода строки или символ конца файла).

Рассмотренный выше пример с двумя числами n1 и n2 и стрингом m1 можно записать с использованием функций fgets и fputs следующим образом:

fp = fopen("myFile4", "w+"); //открытие файла на запись и чтение

fprintf(fp, "%d %d ", n1, n2); //запись чисел n1 и n2 в файл

fputs(m1, fp); //запись стринга m1 в файл

 

rewind(fp); //переход к началу файла

 

fscanf(fp, "%d%d ", &n3, &n4); //чтение чисел из файла в n3 и n4

fgets(m2, 15, fp); //чтение стринга из файла в m2

fclose(fp); //закрытие файла

 

puts("------ Numbers and string: ------");

printf("%d %d %s\n", n3, n4, m2); //вывод данных на экран