Не фиксированное число аргументов
Язык программирования С допускает использование переменного числа аргументов. Признаком функции с переменным числом аргументов является многоточие в списке параметров прототипа функции. Встретив «...», компилятор прекращает контроль соответствия типов параметров для такой функции. Естественно, что функция с переменным числом аргументов должна иметь способ определения точного их числа при каждом вызове. Функции с переменным числом аргументов должны иметь как минимум один фиксированный (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; просмотров: 1737;