Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование / WORD / Лекции по ЯП (часть 3).doc
Скачиваний:
138
Добавлен:
15.04.2015
Размер:
1.34 Mб
Скачать

Функции, возвращающие указатели

В прототипе и заголовке такой функции должен присутствовать знак ссылки по указателю (*). Общая форма объявления подобных функций:

тип *func(список_параметров);

В этом операторе объявляется функция func(), которая возвращает указатель на переменную заданного типа.

Пример такой функции: double *funcl(список_параметров);

Здесь объявляется функция, возвращающая указатель типа double.

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

double (*func)(...); /* Указатель на функцию, возвращающую double */

double *func(...); /* Функция, возвращающая указатель на double */

Указатели не являются ни типом целое (int), ни типом беззнаковое целое (unsigned int). Их значениями являются адреса памяти данных определенного типа.

Встраиваемые функции

Функции этого типа появились в стандарте С-99.

Сам термин "встраиваемые" возник оттого, что вместо вызова функции выполняется ее прямая вставка (встраивание) в тело вызывающей функции.

Обычно встраиваемые функции невелики по размеру. Компилятор пытается выполнить их самым быстрым возможным способом.

Функцию можно сделать встраиваемой, добавив к ее объявлению ключевое слово inline.

Пример.

inline int sum( int a, ini b )

{

return (a + b);

}

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

Рекурсивные функции

В языке С функции могут вызывать сами себя. Функция называется рекурсивной, если оператор в теле функции содержит вызов этой же функции. Классический пример рекурсивной функции - это вычисление факториала числа N! = 1*2*3*...*N.

Назовем эту функцию factorial().

factorial(int n)

{

int a;

if (n==l) return 1;

a = factorial(n-l)*n;

return a;

}

Вызов функции в рекурсивной функции не создает новую копию функции, а создает в памяти новые копии локальных переменных и параметров. Из рекурсивной функции надо предусмотреть выход, иначе это вызовет "зависание" системы.

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

Нам уже встречались библиотечные функции, принимающие переменное количество аргументов например, printf() или scanf().

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

void f(int a, int b, ...);

или

void f(int a, int b...);

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

  • Как в функции printf() строка формата полностью определяет тип и число параметров через спецификации формата.

  • Можно зарезервировать какое-либо значение как завершающее.

  • Можно передавать число параметров в качестве фиксированного параметра.

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

Средства для работы с переменным списком аргументов определены в заголовочном файле stdarg.h. Они используются внутри функции для получения аргументов из списка. Эти средства включают в себя:

va_list

Тип данных для указателя на аргументы.

va_start(list, last_fixed)

Макрос для инициализации списка аргументов.

va_arg(list, arg_type)

Макрос для получения аргументов по очереди из списка.

va_end(list)

Макрос для очистки лишних данных после получения всех аргументов.

где list – переменная типа va_list;

last_fixed – последний фиксированный параметр;

arg_type – тип аргумента.

Как работает этот механизм. Передаваемые функции параметры располагаются в памяти непосредственно друг за другом. Тип va_list – это указатель на void. Макрос va_start устанавливает этот указатель за последним фиксированным параметром, а это можно сделать, так как его адрес и тип известны. Макрос va_arg, используя приведение к типу, указанному в качестве второго параметра, возвращает значение, на которое указывает первый параметр, и передвигает указатель на размер переменной данного типа. Эта реализация накладывает некоторые ограничения. В Borland C++ надо аккуратно использовать нефиксированные параметры char, unsigned char, так как они занимают в памяти 1 байт, а в стеке под них отводится 2 байта.