АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

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

Читайте также:
  1. III. ФУНКЦИИ ДЕЙСТВУЮЩИХ ЛИЦ
  2. III. Функции семьи
  3. Wait функции
  4. Абсолютные и относительные ссылки. Стандартные формулы и функции. Логические функции
  5. Акцентная структура слова в русском языке. Система акцентных противопоставлений. Функции словесного ударения.
  6. Акцентная структура слова в русском языке. Функции словесного ударения.
  7. Алгоритм нахождения глобального экстремума функции
  8. Анализ аргументов. Логический анализ информации.
  9. Аппарат государства – это система государственных органов, обладающих государственной властью и осуществляющих функции государства.
  10. Аргументы функции main(): argv и argc
  11. Бактерицидные функции
  12. Бесконечно малые функции.

Постоянная работа с функциями типа printf или scanf вызывает у программистов зависть – это же функции с переменным количеством аргументов. А как написать свою функцию, обрабатывающую столько параметров, сколько будет задано в обращении, и, естественно, допускающую задание разного количества аргументов?

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

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

double mid_var(int n,...)

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

int *ip=&n;

Продвинем указатель ip на 1, т.е. переместимся на адрес начала следующего параметра, и занесем его в новый указатель dp уже типа double:

ip++; //переход на адрес первого слагаемого double *dp=(double *)ip; //преобразование типа указателя

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

double mid_var(int n,...){ int *ip=&n+1; double *dp=(double *)ip; double s=0.; for(int j=0; j<n; j++) s += dp[j]; //или s += *(dp+j); или s += *(dp++); return s/n;}

Теперь попытаемся построить аналогичную функцию, которая суммирует свои аргументы до тех пор, пока не встречает нулевое слагаемое. Она устроена еще проще:

double mid_var(double a1,...){ double *dp=&a1; double s=0; int c=0; while(*dp!= 0) { s += *(dp++); c++; } return s/c;}

Аналогичные функции можно построить, когда список передаваемых параметров состоит из переменного количества однотипных указателей. Только здесь придется использовать не просто указатели типа *dp, а "двойные" указатели типа **dp. И доставать значения нужных данных придется также через двойные указатели s += (**dp);

В файле stdarg.h находится несколько функций (точнее, макроопределений) которые обеспечивают перемещение по списку параметров, завершающемуся нулем:

va_list p; //объявление указателя на список параметровva_start(p,p1); //установка указателя списка на последний явный параметрva_arg(p,тип); //перемещение указателя на очередной неявный параметрva_end(p); //уничтожение указателя на список параметров

Продемонстрируем использование этих средств на примере той же самой функции mid_var:

double mid_var(int n,...) //функции передают количество параметров{ va_list p; double s=0,c=0; va_start(p,n); while(n--) //до тех пор, пока n!= 0 { s += va_arg(p,double); c++; } va_end(p); return s/c;}

Если список параметров начинается с первого слагаемого a1, то программа меняется очень незначительно:

double mid_var(double a1,...){ va_list p; double s=0,c=0,u=a1; va_start(p,a1); do {s += u; c++; } while(u=va_arg(p,double)); //до тех пор, пока u!= 0 va_end(p); return s/c;}

На наш взгляд, применение обычных указателей выглядит несколько проще, чем использование стандартных средств.


1 | 2 | 3 | 4 | 5 | 6 |

Поиск по сайту:



Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.003 сек.)