logo
Подбельский Фомин_Программирование на языке СИ_

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

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

Результат выполнения программы:

5.000000

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

В функциях с переменным количеством параметров есть один уязвимый пункт - если при "чтении" параметров с помощью макроса va_arg( ) указатель выйдет за пределы явно использованного списка фактических параметров, то результат, возвращаемый макросом va_arg( ), не определен. Таким образом, в нашей функции set_array() количество явно заданных параметров переменного списка ни в коем случае не должно быть меньше значения первого фактического параметра (заменяющего int k).

В основной программе main( ) определен указатель double * array, которому присваивается результат (адрес динамического массива), возвращаемый функцией set_array( ). Затем с помощью указателя array в цикле выполняется доступ к элементам массива, и их значения выводятся на экран дисплея.

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

Результат выполнения программы:

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

printf(char* format, ...);

scanf(char* format, ...);

В обоих функциях форматная строка, связанная с указателем format, содержит спецификации преобразования (%d - для десятичных чисел, - для вещественных данных в форме с плавающей точкой, %f - для вещественных значений в форме с фиксированной точкой и т.д.). Кроме того, эта форматная строка в функции printf( ) может содержать произвольные символы, которые выводятся на дисплей без какого-либо преобразования. Чтобы продемонстрировать особенности построения функций с переменным числом параметров, классики языка Си [1] рекомендуют самостоятельно написать функцию, подобную функции printf( ). Последуем их совету, но для простоты разрешим использовать только спецификации преобразования "%d" и "%f".

Результат выполнения программы:

Интересной особенностью предложенной функции miniprint( ) и ее серьезных прародителей - библиотечных функций языка Си printf( ) и scanf( ) - является использование одного явного параметра и для задания типов последующих параметров, и для определения их количества. Для этого в строке, определяющей формат вывода, записывается последовательность спецификаций, каждая из которых начинается символом '%'. Предполагается, что количество спецификаций равно количеству параметров в следующем за форматом списке. Конец обмена и перебора параметров определяется по достижению конца форматной строки, когда *р= = '\0'.