Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
void ToUpper(char *); // преобразует строку в верхний регистр
Тин ToUpper() определен как “функция с параметром char * и возвращаемым типом void”. Вот как объявить указатель на функцию такого типа по имени pf:
void (*рf) (char *); // pf - указатель на функцию
Читая это объявление, вы видите, что первая пара круглых скобок связывает операцию * с pf, т.е. pf является указателем на функцию. Это делает (*рf) функцией, a (char * ) — списком ее параметров функции и void — возвращаемым типом. Вероятно, проще всего понять, как создано такое объявление — обратить внимание, что имя функции ToUpper в нем заменено выражением (*pf). Таким образом, если вы хотите объявить указатель на специфичный тип функции, можете объявить функцию этого типа и затем заменить имя функции выражением вида (*pf), получив в результате объявление указателя на функцию. Как упоминалось ранее, первые круглые скобки необходимы из-за правил, регламентирующих приоритеты операций. Если их отбросить, получится что-то совершенно другое:
void *pf(char *); // pf - функция, которая возвращает указатель
Совет
Чтобы объявить указатель на функцию конкретного типа, сначала объявите функцию желаемого типа и затем замените имя функции выражением в форме (*pf); после этого pf становится указателем на функцию данного типа.
Указателю на функцию можно присваивать адрес функции подходящего типа. В этом контексте для представления адреса функции может применяться ее имя:
void ToUpper(char *); void ToLower(char *); int round(double); void (*pf) (char *);
pf = ToUpper; // допустимо, ToUpper - адрес функции
pf = ToLower; // допустимо, ToLower - адрес функции
pf = round; // недопустимо, round - неподходящий тип функции
pf = ToLower(); // недопустимо, ToLower () не является адресом
Последнее присваивание также недопустимо, потому что нельзя использовать функцию void в операторе присваивания.
614 глава 14
Обратите внимание, что указатель pf может указывать на любую функцию, которая принимает аргумент char * и имеет возвращаемый тип void, но не на функции с другими характеристиками.
Подобно тому, как можно применять указатель на данные с целью доступа к ним, вы можете использовать указатель на функцию для обращения к этой функции. На удивление для этого существуют два логически несогласованных синтаксических правила, как иллюстрируется в следующем фрагменте:
void ToUpper(char *); void ToLowertchar *); void (*pf) (char *); char mis[] = "Nina Metier"; pf = ToUpper;
(*pf)(mis); // применить ToUpper к mis (первый синтаксис) pf = ToLower;
pf(mis); // применить ToLower к mis (второй синтаксис)
Каждый подход выглядит логичным. Проанализируем первый подход: так как pf указывает на функцию ToUpper, то *pf — это функция ToUpper, поэтому выражение (*pf) (mis) аналогично ToUpper (mis). Чтобы убедиться в эквивалентности ToUpper и (*pf), достаточно взглянуть на объявления ToUpper и pf. Второй подход можно объяснить так: из-за того, что имя функции является указателем, указатель и имя функций можно применять взаимозаменяемо, следовательно, pf (mis) — это то же самое, что и ToLower (mis). Чтобы удостовериться в эквивалентности pf и ToLower, просто посмотрите на оператор присваивания для pf. Исторически сложилось так, что разработчики С и Unix в Bell Labs избрали первый подход, а разработчики, которые расширяли Unix в Беркли, приняли второй подход. Компилятор K&R С не разрешает вторую форму, но для поддержки совместимости с существующим кодом стандарт ANSI С принимает обе формы ((*pf) (mis) и pf (mis)) как эквивалентные. Последующие стандарты сохранили такой в высшей степени двойственный подход.
Одним из наиболее распространенных случаев использования указателей на данные является аргумент функции, и то же самое относится к указателю на функцию. Например, рассмотрим следующий прототип функции:
void show(void (* fp) (char *), char * str);
Он выглядит запутанным, но в нем объявляются два параметра, fp и str. Параметр fp — это указатель на функцию, a str — указатель на данные. Точнее, fp указывает на функцию, которая принимает параметр char * и имеет возвращаемый тип void, а str указывает на char. Таким образом, имея представленные выше объявления, можно делать вызовы функций вроде приведенных ниже:
show(ToLower, mis); /* show() использует функцию ToLower(): fp = ToLower */ show(pf, mis); /*show() использует функцию, указанную посредством pf: fp = pf */
Каким образом show() применяет переданный указатель на функцию? Для вызова этой функции в show() используется либо синтаксис fp(), либо синтаксис (* fр)():
void show(void (* fp)(char *), char * str)
{
(*fp)(str); /* применить выбранную функцию к str */ puts(str); /* отобразить результат */
}
Здесь функция show() сначала трансформирует строку str, применяя к ней функцию, на которую указывает fp, после чего отображает результирующую строку.
Структуры и другие формы данных 615
Кстати говоря, функции с возвращаемыми значениями могут использоваться двумя разными способами при передаче в качестве аргументов другим функциям. Например, взгляните на следующие операторы:
functionl(sqrt); /* передает адрес функции sqrt */
function2(sqrt(4.О)); /* передает возвращаемое значение функции sqrt */
Первый оператор передает адрес функции sqrt ( ) , и предположительно functionl() будет применять эту функцию в своем коде. Второй оператор сначала вызывает функцию sqrt() и затем передает возвращаемое значение (в этом случае 2.0) функции function2().
Для демонстрации основных идей в листинге 14.16 используется функция show() вместе с набором функций трансформации в качестве аргументов. В листинге также продемонстрировано несколько полезных приемов поддержки меню.
Листинг 14.16. Программа func_ptr.c
616 Глава 14
Структуры и другие формы данных 617
Ниже показаны результаты пробного запуска:
Введите строку (пустая строка - выход из программы):
Does С make you feel loopy?
Введите выбранный вариант из меню: u) нижний регистр 1) верхний регистр
t) поменять местами регистры о) исходный регистр n) следующая строка t
dOES с MAKE YOU FEEL LOOPY?
Введите выбранный вариант из меню: u) нижний регистр 1) верхний регистр
t) поменять местами регистры о) исходный регистр n) следующая строка l
does с make you feel loopy?
Введите выбранный вариант из меню: u) нижний регистр 1) верхний регистр
t) поменять местами регистры о) исходный регистр n) следующая строка n
Введите строку (пустая строка - выход из программы) :
Программа завершена.
Обратите внимание, что функции ToUpper(), ToLower(), Transpose() и Dummy() имеют тот же самый тип, поэтому все они могут быть присвоены указателю pfun. В этой программе в качестве аргумента для show() применяется pfun, но можно также указывать непосредственно любое из имен четырех функций, как в show (Transpose, copy).
Читать дальшеИнтервал:
Закладка: