Не фиксированное число аргументов


Язык программирования С допускает использование пе­ременного числа аргументов. Признаком функции с перемен­ным числом аргументов является многоточие в списке па­раметров прототипа функции. Встретив «...», компилятор прекращает контроль соответствия типов параметров для та­кой функции. Естественно, что функция с переменным числом аргументов должна иметь способ определения точного их числа при каждом вызове. Функции с переменным числом аргументов должны иметь как минимум один фиксированный (1-й) аргумент для того, чтобы была возможность «привязаться» к адресу копии этого аргумента в стеке. Для определения действительного числа переданных в вызове аргументов предлагается использовать следующие 2 метода:

· число действительно переданных аргументов в вызове содержится в 1-м аргументе,

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

Пример

void example(int, …);

…………………………….

void example(int argl, ...)

{

int * рtr = &argl; /* установка yказaтeля на первый аргумент */

рrintf("\nФункции ЕХАМРLE передано всего %d аргумента(ов):\n",

argl);

/* Печать всех пеpeдaнных в функцию фактических apгyмeнтoв */

for (; argl; argl--)

{

printf (" %d", * рtr);

ptr++;

}

}

Дополнительные возможности по использованию функций с переменным числом аргументов открывaют специальные типы и макро, включенные в заголовочный файл stdarg.h. Используется рассмотренный ранее метод определения. конца списка по заранее известному значению. Для упрощения работы с переменным числом apгyмeнтов в айле stdarg.h определен особый тип

typedef void *va_list;

Тип va_list используется для описания указателя на нача­ло списка переданных функции фактических аргументов, на­пример:

void example(int argl, ...)

{va_list ptr; ... }

Для задания начального значения указателю типа va_list ис­пользуется макро va_start( ). Макро описано в stdarg.h так:

#define va_start(ap, parmN) (ар=… )

Формальный аргумент parmN - это имя последнего фикси­рованного параметра в списке параметров функции с пере­менным числом аргументов, т. е. значение, к адресу которого осуществляется "привязка" указателя ptr. Особенность такой "привязки" заключается в том, что указатель устанавливает­ся на адрес памяти после фиксированного аргумента. Напри­мер, для приведенной ранее функции example() инициализа­ция указателя ptr выполняется так:

va_start ( ptr, argl);

Доступ к значениям в списке фактических параметров вы­полняется через макро va_arg(), которое описано в файле <stdarg. h так: .

#define va_arg( ар, tуре)(*( (type * )( ap))++)

Формальный аргумент ap – это имя указателя, используемого для доступа к элементам списка фактических параметров; type – тип переменных (неявно предполагается, что все элементы списка имеют один и тот же тип). Тип возвращаемого макро va_arg(ap, type) значения совпадает с type.

Признаком завершения списка параметров служит зара­нее определенное значение, не совпадающее ни с одним из передаваемых фактических аргументов.

Приведем переработанный пример, где в функции example() с переменным числом аргументов ис­пользуются paccмoтpeнныe макро va_list, va_start(), vф_аrg().

Пример

void example(int,…);

…………………………………………………

void example(int arg1, ...)

{

int number = 1, value;

va_list рtr; /* указатель для доступа к списку параметров */

printf(" %d", arg1); /* печать фиксированного аргументa */

/* установка указателя на первый nocлe фиксированного аргумент */

va_staгt(ptr, arg1);

/* Печать переданных в функцию фактических аргументов */

while( (value = va_arg( ptr, int)) != EOL)

{

printf(" %d", value); number++;

}

рrintf("\n Функции EXAМPLE пеpeдaнo всего %d аргумента( ов ):\n",

number );

}

 

 

Внешние переменные

Любая программа на языке С есть множество внешних объектов, - ли­бо переменных, либо функций. Определение «внешние» используется глав­ным образом для того, чтобы подчеркнуть отличие от «внутренних» объ­ектов – аргументов, автоматических статических или регистровых переменных, определяемых внутри функции. Внешние переменные определены вне любой из функций и, сле­довательно, доступны для многих функций. Сами функции всегда внешние, так как язык не позволяет определять функции внутри других функций.

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

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

Вторая причина использования внешних переменных связана с иници­ацией. В частности, внешние массивы можно инициировать, а автоматиче­ские массивы - нет.

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

Пример

Ввод строк, определение самой длинной строки и ее распечатка.

#include ..

#define MAXLINE 1000 /* максимальная длина строки*/

char line [MAXLINE]; /* входная строка – внешняя переменная*/

char save [MAXLINE]; /*самая длинная строка – внешняя переменная */

int max; /* внешняя переменная – длина максимальной строки*/

main( ) /*поиск самой длинной строки*/

{

int len, getline( ), copy( );

extern int max; // две необязательные декларации, поскольку max, line, save

extern char save[]; // декларированы выше по тексту

max = 0;

while ((len = getline( ))>0)

if (len>max)

{

max = len; copy( );

}

if (max>0) /* строка вводилась*/

printf (“%s”, save);

return 0;

}

getline( ) /* ввод строк в line; должно быть описано в getline( ) */

{

int c,i;

extern char line[];

…………………….

Посимвольный ввод в массив line и добавление в конце строки символа ‘\0’; для ввода используется getchar( )

return (длина введенной строки);

}

void copy( ) /*копирование строки из line в save*/

{

int i;

extern char line[], save[]; //избыточные декларации

i=0;

while ((save[i]) = line[i]) != ’\0’)

++i;

}

Разработку getline( ) предлагается выполнить самостоятельно.

Копирование строк выполняется до обнаружения символа ‘\0’ в массиве line. Формат «%s» используется для распечатки строк, полученных из массива строк. Здесь, в примере, переменные line, max, save – внешние переменные.



Дата добавления: 2016-05-26; просмотров: 1666;


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

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.013 сек.