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

Функции с переменным числом параметров - еще одна важная особенность Си.

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

В списке типов аргументов в качестве имени типа допускается также конструкция void *, которая специфицирует аргумент типа "указатель на любой тип". Для доступа к переменному списку параметров можно использовать указатели.

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

Для работы со списками аргументов есть стандартные функции языка, использованные в листинге.

#include <stdio.h>
#include <stdarg.h>

void sum(char *msg, ...) {
 //считает сумму любого числа параметров и выводит ее с сообщением msg
 //число параметров это функции переменно, концом списк служит значение 0
 int total = 0;
 va_list ap; //тип для хранения информации, передаваемой в va_start, va_arg, va_end
 int arg; //очередной целочисленный аргумент
 va_start(ap, msg); //инициализирует список параметров
 while ((arg = va_arg(ap,int)) != 0) { //извлекает следующий параметр типа int
  total += arg; //накопление суммы 
 }
 printf(msg, total);
 va_end(ap); //очищаем и закрываем список параметров
}

void main(void) {
 sum("Сумма 1=%d\n",1,2,3,4,0);
 sum("Сумма 2=%d\n",10,20,0);
}

Альтернативный подход - первым параметром такой функции передавать количество остальных параметров.

#include <stdio.h>

int sum (int kol, ... ) {
 //Параметр kol задаёт количество остальных параметров
 //Функция суммирует их и возвращает полученную сумму
 int *ptr=&kol; //Указываем на начло строки параметров
 int s=0;
 for (;kol;kol--) { //Пока не сделано kol шагов
  s+=*++ptr; //Прибавляем параметр к сумме и переходим к следующему
 }
 return s;
}
void main () {
 printf ("\nsum(3,1,2,3)=%d",sum(3,1,2,3)); //==6
 printf ("\nsum(1,1)=%d",sum(1,1)); //==1
 printf ("\nsum(0)=%d",sum(0)); //==0
 fflush(stdin); getchar();
}

Нужно учесть, что в последнем случае мы "закладываем" в код x86-совместимую архитектуру процессора, неявно предполагая, что параметры будут переданы через стек и расположатся в памяти вполне определённым образом.

Рейтинг@Mail.ru

вверх гостевая; E-mail