Функции с переменным количеством параметров
Можно создавать функции, количество параметров у которых при компиляции определения функции не определено. Кроме того могут быть не известными и типы параметров. Количество и типы параметров становятся известными только в момент вызова функции, когда явно задан список фактических параметров.
Формат заголовка такой функции:
Тип имя (спецификация_явных_параметров, …)
Явные параметры обязательные. Многоточие после запятой извещает компилятор, что дальнейший контроль соответствия количества и типов параметров при обработке вызова функции проводить не нужно.
Пример:
long summa (int k, …)
{
int *p=&k;
long t=0;
for(;k;k--)t+=*(++p);
return t;
}
У каждой функции c переменным количеством параметров есть механизм определения количества и типов списка параметров функции при ее вызове. Существует два подхода:
1) Предусматривает передачу в функцию значения реального количества фактических параметров. Значения реального количества используемых фактических параметров можно передавать в функцию с помощью одного из явно задаваемых параметров.
2) Предполагает добавление в конец списка реально использованных фактических параметров специального параметра-индикатора с уникальным значением, которое будет сигнализировать об окончании списка. В теле функции параметры последовательно перебираются, и их значения сравниваются с заранее известным концевым признаком.
В обоих подходах переход от одного фактического параметра к другому выполняется с помощью указателей.
Рассмотрим пример программы, которая включает функцию с изменяемым списком параметров, первый из которых (единственный обязательный) определяет число действительно используемых при вызове необязательных фактических параметров ( т.е. по первому подходу ).
Пример
#include <stdio.h>
long summa (int k, …) //k - число суммируемых параметров
{
int *p=&k;
long t=0;
for(; k; k--) t+=*(++p);
return t;
}
main()
{
long r,p;
r=summa(2,6,4);
p=summa(6,1,2,3,4,5,6);
printf (“r=%d\n”,r);
printf (“p=%d\n”,p);
}
Результат выполнения программы:
r=10
p=21
Для доступа к списку параметров используется указатель p типа int*. Вначале ему присваивается адрес явно заданного параметра k, т.е. он устанавливается на начало списка параметров в памяти (в стеке). Затем в цикле указатель p перемещается по адресам следующих фактических параметров, соответствующих неявным формальным параметрам. С помощью операции (* p) выполняется выборка их значений. Параметром цикла суммирования служит аргумент k, значение которого уменьшается на 1 после каждой итерации и, наконец, становится равным 0.
Особенность функции – возможность работы только с целочисленными фактическими параметрами, так как указатель p после обработки значения очередного параметра перемещается вперед на величину sizeof(int) и должен быть всегда установлен на начало следующего параметра.
Следующий пример содержит функцию для вычисления произведения переменного количества параметров. Признаком окончания фактических параметров служит параметр с нулевым значением ( т.е. по второму подходу ).
Пример
#include <stdio.h>
double prod (double arg, …)
{
double aa = 1.0; // Формируемое произведение
double *p=&arg; // Настроили указатель на первый параметр
if(*p == 0.0) return 0.0;
for(; *p; p++) aa*=*p;
return aa;
}
void main()
{
double r, p;
r=prod(2.0, 4.0, 3.0, 0.0);
p=prod(1.4, 3.0, 0.0, 16.0);
printf (“r=%d\n”,r);
printf (“p=%d\n”,p);
}
Результат выполнения программы:
r=9.0
p=4.4
В функции prod перемещение указателя p по списку фактических параметров выполняется всегда за счет изменения p на величину sizeof(double). Поэтому все фактические параметры при обращении к функции prod должны иметь тип double. В вызовах функции проиллюстрированы некоторые варианты задания параметров. Обратите внимание на вариант с нулевым значением параметра в середине списка. Параметры вслед за этим значением игнорируются.
Чтобы функция с переменным количеством параметром могла воспринимать параметры различных типов, необходимо в качестве исходных данных каким-то образом передавать ей информацию о типах параметров. Для однотипных параметров возможно, например, такое решение – передавать с помощью дополнительного обязательного параметра признака типа параметров. Запишем функцию, выбирающую минимальное из значений параметров, которые могут быть двух типов: или только long, или только int. Признак типа параметра будем передавать как значение первого обязательного параметра. Второй обязательный параметр определяет количество параметров, из значений которых выбирается минимальное. В следующей программе предложен один из вариантов решения сформулированной задачи:
#include <stdio.h>
long minimum (char z, int k, …)
{
if(z==’i’)
{
int *pi=&k+1; // настроили на первый необязательный параметр
int min =*pi; // значение первого необязательного параметра
for (; k; k--, pi++)
min = min >*pi? *pi: min;
return (long) min;
}
if(z==’l’)
{
long *pl = (long*)(&k+1);
long min = *pl; // Значение первого параметра
for (;k;k--,pl++)
min = min >*pl? *pl: min;
return (long)min;
}
printf(“неверно задан 1-й параметр”);
return 2222L;
}
void main()
{
long p,p1;
p=minimum(‘l’,2,10L,20L);
p1=minimum(‘i’, 3,11,2,3);
}
Библиотечные функции языка Си
Стандартной библиотекой языка Си (также известная как libc, crt) называется часть стандарта ANSI C, посвященная заголовочным файлам и библиотечным функциям. Является описанием реализации таких операций как:
- файловый и консольный ввод-вывод;
- обработка строк;
- вычисление математических функций;
- конвертация типов данных.