Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Технология программиования_Си.docx
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
33 Кб
Скачать
☆

Блочный ввод-вывод

Часто приходится работать с массивами структурных переменных. Если такой массив нужно записать в файл, то можно использовать операции форматного вывода, а именно, создать цикл, в котором с помощью fprintf в файл будут записываться отдельные поля структурных переменных. Аналогично при вводе (чтении информации из файла). Получается трудоёмкая операция, которая может быть упрощена. Можно посчитать размер массива структурных переменных и, зная адрес начала и размер, считать весь массив, как блок байт памяти. Тогда весь массив можно записать в файл одним блоком, и точно так же восстановить блок памяти при чтении из памяти. Для этого используются функции fread и fwrite.

unsigned fread(void *ptr, unsigned size, unsigned n, FILE *fp).

ptr – указатель на блок памяти, с которого будет считываться нформация, size – размер одного элемента данных, N – количество элементов данных. Функция возвращает количество прочитанных элементов.

Аналогичные элементы у функции fwrite, она возвращает количество записанных элементов.

Функции с переменным числом аргументов.

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

printf(“Строка”);

printf(“Строка %d”, 1);

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

Однако, есть ситуации, когда функции с переменным числом аргументов очень полезны. Это функции, у которых количество фактических параметров в вызове может отличаться от количества формальных параметров в описании функции. В Си допускается только большее количество фактических параметров, а в других языках допускаются обе ситуации – и больше и меньше. Возможность создания функции с переменным числом аргументов ставит много вопросов. Если фактическому параметру соответствует формальный, то внутри функции формальный параметр это локальная переменная, которая на время вычисления функции хранит значение фактического параметра. Но если для фактического параметра нет соответствующего формального, то нужно как то решить вопрос доступа к значению фактического параметра внутри функции. Нужно как то реализовать последовательный перебор таких параметров. Определить, когда заканчивается список фактических параметров и т.д. Для реализации функции с переменным числом аргументов, в заголовочном файле stdarg.h определён набор макросов для разных операций.

Объявление функции с переменным числом аргументов.

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

Int printf(char* format, …)

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

Реализация функций с переменным числом аргументов.

Обрабатывая вызов функции, компилятор помещает фактические параметры во фрейм вызова (т.е. в стек). Зная типы параметров, можно с помощью указателя перемещаться между этими данными. Для функции с фиксированным числом аргументов для этого нет необходимости, для функции с переменным числом перебор реализуется с помощью макросов. После подключения заголовочного файла в теле функции необходимо описать переменную специального типа va_list (variable argument list). Это указатель на void.

va_list lptr

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

Для printf это будет выглядеть так:

va_start(lptr, format).

После того как указатель на переменную часть списка инициализирован, для чтения отдельных аргументов используется макрос vaarg

#define va_arg(ap, type) (*((type*)(ap)++)

Int var;

Var = va_arg(lptz, int);

Мы научились перебирать из переменной части списка, но нужно выяснить, когда этот перебор нужно закончить. Здесь в каждом случае программист должен решить, как ему удобно определить длину списка. Это зависит от задачи. Например, в функции printf – количество дополнительных аргументов определяется количеством спецификаций формата. Если мы знаем, что аргументами будут числа не равные 0 или только положительные, то можно завершать список, например 0 или 1. Можно фиксировать часть списка аргументов, добавить переменную, через которую каждый раз мы будем указывать, сколько дополнительных параметров будет передано в данном вызове функции.