5.4. Указатели на функции Указатели при вызове функций.
Указатели при вызове функций. До сих пор мы рассматривали функцию как минимальный исполняемый модуль программы, обмен данными с которым происходит через набор параметров функции и с помощью значений, возвращаемых функцией в точку вызова. Теперь перейдем к вопросу о том, почему в языке Си функция введена как один из производных типов. Необходимость в таком типе связана, например, с задачами, в которых функция (или ее адрес) должна выступать в качестве параметра другой функции или в качестве значения, возвращаемого другой функцией. Обратимся к уже рассмотренному ранее выражению "вызов функции" (точнее, к более общему варианту вызова):
обозначение_функции (список_фактических_параметров)
где обозначение_функции (только в частном случае это идентификатор) должно иметь тип "указатель на функцию, возвращающую значение конкретного типа".
В соответствии с синтаксисом языка указатель на функцию - это выражение или переменная, используемые для представления адреса функции. По определению, указатель на функцию содержит адрес первого байта или первого слова выполняемого кода функции (арифметические операции над указателями на функции запрещены).
Самый употребительный указатель на функцию - это ее имя (идентификатор). Именно так указатель на функцию вводится в ее определении:
тип имя_функции (спецификация_параметров)
тело_функции
Прототип
тип имя_функции (спецификация_параметров);
также описывает имя функции именно как указатель на функцию, возвращающую значение конкретного типа.
Имя_функции в ее определении и в ее прототипе - указатель-константа. Он навсегда связан с определяемой функцией и не может быть "настроен" на что-либо иное, чем ее адрес. Для идентификатора имя_функции термин "указатель" обычно не используют, а говорят об имени функции.
Указатель на функцию как переменная вводится отдельно от определения и прототипа какой-либо функции. Для этих целей используется конструкция:
тип (* имя_указателя) (спецификация _параметров);
где тип - определяет тип возвращаемого функцией значения;
имя_указателя - идентификатор, произвольно выбранный программистом;
спецификация_параметров - определяет состав и типы параметров функции.
Например, запись
определяет указатель-переменную с именем point на функции без параметров, возвращающие значения типа int.
Важнейшим элементом в определении указателя на функции являются круглые скобки. Если записать
то это будет не определением указателя, а прототипом функции без параметров с именем funct, возвращающей значения типа int*.
В отличие от имени функции (например, funct) указатель point является переменной, т.е. ему можно присваивать значения других указателей, определяющих адреса функций программы. Принципиальное требование - тип указателя-переменной должен полностью соответствовать типу функции, адрес которой ему присваивается.
Мы уже говорили, что тип функции определяется типом возвращаемого значения и спецификацией ее параметров. Таким образом, попытка выполнить следующее присваивание
будет ошибочной, так как типы возвращаемых значений для point и funct различны.
Неконстантный указатель на функцию, настроенный на адрес конкретной функции, может быть использован для вызова этой функции. Таким образом, при обращении к функции перед круглыми скобками со списком фактических параметров можно помещать: имя_функции (т.е. константный указатель); указатель-переменную того же типа, значение которого равно адресу функции; выражение разыменования такого же указателя с таким же значением. Следующая программа иллюстрирует три способа вызова функций.
Результат выполнения программы:
Все варианты обращения к функциям с использованием указателей-констант (имен функций) и указателей-переменных (неконстантных указателей на функции) в программе продемонстрированы и снабжены комментариями. Приведем общий вид двух операций вызова функций с помощью неконстантных указателей:
(*имя_указателя) (список_фактических_параметров)
имя_указателя (список_фактических_параметров)
В обоих случаях тип указателя должен соответствовать типу вызываемой функции, и между формальными и фактическими параметрами должно быть соответствие. При использовании явного разыменования обязательны круглые скобки, т.е. в нашей программе будет ошибочной запись
Это полностью соответствует синтаксису языка. Операция '( )' - "круглые скобки" имеет более высокий приоритет, чем операция разыменования '*'. В этом ошибочном вызове вначале выполнится вызов point( ), а уж к результату будет применена операция разыменования.
При определении указателя на функции он может быть инициализирован. В качестве инициализирующего выражения должен использоваться адрес функции того же типа, что и тип определяемого указателя, например:
Массивы указателей на функции. Такие массивы по смыслу ничем не отличаются от массивов других объектов, однако форма их определения несколько необычна:
тип (*имя_массива [размер] ) (спецификация_параметров);
где тип определяет тип возвращаемых функциями значений;
имя_массива - произвольный идентификатор;
размер - количество элементов в массиве;
спецификация_параметров - определяет состав и типы параметров функций.
Пример:
где parray - массив указателей на функции, каждому из которых можно присвоить адрес определенной выше функции int fic (char) и адрес любой функции с прототипом вида
int имя-функции (char);
Массив в соответствии с синтаксисом языка является производным типом наряду с указателями и функциями. Массив функций создать нельзя, однако, как мы показали, можно определить массив указателей на функции. Тем самым появляется возможность создавать "таблицы переходов" (jump tables), или "таблицы передачи управления". С помощью таблицы переходов удобно организовывать ветвления с возвратом по результатам анализа некоторых условий. Для этого все ветви обработки (например, N+1 штук) оформляются в виде однотипных функций (с одинаковым типом возвращаемого значения и одинаковой спецификацией параметров). Определяется массив указателей из N+1 элементов, каждому элементу которого присваивается адрес конкретной функции обработки. Затем формируются условия, на основе которых должна выбираться та или иная функция (ветвь) обработки. Вводится индекс, значение которого должно находиться в пределах от 0 до N включительно, где (N+1) - количество ветвей обработки. Каждому условию ставится в соответствие конкретное значение индекса. По конкретному значению индекса выполняются обращение к элементу массива указателей на функции и вызов соответствующей функции обработки:
имя_массива [индекс] (список_фактических_параметров);
(*имя массива [индекс]) (список_фактических_параметров);
Описанную схему использования массивов указателей на функции удобно применять для организации меню, точнее, программ, которыми управляет пользователь с помощью меню.
Пример выполнения программы:
В программе для упрощения нет защиты от неверно введенных данных, т.е. возможен выход индекса за пределы, определенные для массива pact[ ] указателей на функции. При такой ситуации результат непредсказуем.
- Предисловие
- Раздел 1. Полный курс программирования на стандартном языке Си Глава 1. Базовые понятия языка
- 1.1. Алфавит, идентификаторы, служебные слова Алфавит
- Идентификатор
- Служебные (ключевые) слова
- 1.2. Константы и строки
- Символы, или символьные константы.
- Целые константы.
- Вещественные константы.
- Предельные значения и типы арифметических констант.
- Целые константы и выбираемые для них типы
- Данные вещественных типов
- Нулевой указатель.
- Строки, или строковые константы.
- 1.3. Переменные и именованные константы Переменная как объект.
- Определение переменных.
- Предельные значения переменных.
- Основные типы данных
- Инициализация переменных.
- Именованные константы.
- 1.4. Операции
- Знаки операций.
- Приоритеты (ранги) операций
- Унарные (одноместные) операции.
- 1.5. Разделители
- Квадратные скобки.
- Круглые скобки.
- Запятая.
- Точка с запятой.
- Двоеточие.
- Многоточие.
- Звездочка.
- Обозначение присваивания.
- Признак препроцессорных средств.
- 1.6. Выражения и приведение арифметических типов
- Отношения и логические выражения.
- Присваивание (выражение и оператор).
- Приведение типов.
- Правила преобразования типов
- Правила стандартных арифметических преобразований
- Выражения с поразрядными операциями.
- Условное выражение.
- Глава 2. Введение в программирование на языке си
- 2.1. Структура и компоненты простой программы
- Текст программы и препроцессор.
- Структура программы.
- Функция форматированного вывода.
- Программы печати предельных констант.
- Применимость вещественных данных.
- Выделение лексем из текста программы.
- 2.2. Элементарные средства программирования Деление операторов языка Си на группы.
- Программа оценки машинного нуля.
- Трассировочная таблица
- Ввод данных.
- Вычисление объема цилиндра.
- Сумма членов ряда Фибоначчи.
- 2.3. Операторы цикла Три формы операторов цикла.
- Приближенное значение экспоненты.
- Оператор break.
- Сумма отрезка степенного ряда.
- Оператор continue.
- Суммирование положительных чисел.
- 2.4. Массивы и вложение операторов цикла Массивы и переменные с индексами.
- Вычисление среднего и дисперсии.
- Упорядочение в одномерных массивах.
- Инициализация массивов.
- 2.5. Функции Определение функций.
- Функция для вычисления объема цилиндра.
- Функция для вычисления скалярного произведения векторов.
- Обращение к функции и ее прототип.
- Вычисление биномиального коэффициента.
- Вычисление объема цилиндра
- Вычисление площади треугольника.
- Скалярное произведение векторов.
- 2.6. Переключатели
- Глава 3. Препроцессорные средства
- 3.1. Стадии и команды препроцессорной обработки
- Стадии препроцессорной обработки.
- Директивы препроцессора.
- 3.2. Замены в тексте Директива #define.
- Цепочка подстановок.
- 3.3. Включение текстов из файлов
- 3.4. Условная компиляция Директивы ветвлений.
- Операция defined.
- 3.5. Макроподстановки средствами препроцессора
- Моделирование многомерных массивов.
- Отличия макросов от функций.
- Препроцессорные операции в строке замещения.
- 3.6. Вспомогательные директивы
- Препроцессорные обозначения строк.
- Реакция на ошибки.
- Пустая директива.
- Прагмы.
- 3.7. Встроенные (заранее определенные) макроимена
- Глава 4. Указатели, массивы, строки
- 4.1. Указатели на объекты Адреса и указатели.
- Операции над указателями.
- Арифметические операции и указатели.
- Указатели и отношения.
- 4.2. Указатели и массивы Указатели и доступ к элементам массивов.
- Массивы динамической памяти.
- Функции для выделения и освобождения памяти
- Массивы указателей и моделирование многомерных массивов.
- "Матрица" со строками разной длины.
- 4.3. Символьная информация и строки
- Ввод-вывод символьных данных.
- Внутренние коды и упорядоченность символов.
- Строки, или строковые константы.
- Строки и указатели.
- Глава 5. Функции
- 5.1. Общие сведения о функциях Определение функции.
- Описание функции и ее тип.
- Вызов функции.
- 5.2. Указатели в параметрах функций Указатель-параметр.
- Имитация подпрограмм.
- 5.3. Массивы и строки как параметры функций Массивы в параметрах.
- Резюме по строкам-параметрам.
- 5.4. Указатели на функции Указатели при вызове функций.
- Указатели на функции как параметры
- Указатель на функцию как возвращаемое функцией значение.
- Библиотечные функции с указателями на функции в параметрах.
- 5.5. Функции с переменным количеством параметров
- Доступ к адресам параметров из списка.
- Макросредства для переменного числа параметров.
- Примеры функций с переменным количеством параметров.
- 5.6. Рекурсивные функции
- 5.7. Классы памяти и организация программ Локализация объектов.
- Глобальные объекты.
- Динамическая память
- Внешние объекты.
- 5.8. Параметры функции main( )
- Глава 6. Структуры и объединения
- 6.1. Структурные типы и структуры Производные типы.
- Структурный тип.
- Определение структур.
- Выделение памяти для структур.
- Инициализация и присваивание структур.
- Доступ к элементам структур.
- 6.2. Структуры, массивы и указатели Массивы и структуры в качестве элементов структур.
- Массивы структур.
- Указатели на структуры.
- Указатели как средство доступа к компонентам структур.
- Указатели на структуры как компоненты структур.
- 6.3. Структуры и функции
- Имитация абстрактных типов данных.
- 6.4. Динамические информационные структуры Статическое и динамическое представление данных.
- Односвязный список.
- Рекурсия при обработке списка.
- 6.5. Объединения и битовые поля Объединения.
- Битовые поля.
- Глава 7. Ввод и вывод
- 7.1. Потоковый ввод-вывод
- 7.1.1. Открытие и закрытие потока
- 7.1.2. Стандартные файлы и функции для работы с ними
- Ввод-вывод отдельных символов.
- Ввод-вывод строк.
- Форматный ввод-вывод.
- Спецификаторы форматной строки для функции форматного вывода
- Спецификаторы форматной строки для функции форматного ввода
- 7.1.3. Работа с файлами на диске
- Двоичный (бинарный) режим обмена с файлами.
- Строковый обмен с файлами.
- Позиционирование в потоке.
- Трехъязычный словарь "Цифры
- 7.2. Ввод-вывод нижнего уровня
- 7.2.1. Открытие / закрытие файла
- 7.2.2. Чтение и запись данных
- 7.2.3. Произвольный доступ к файлу
- Глава 8. Примеры разработки программ
- 8.1. Программа с объектами разных классов памяти Постановка задачи.
- Программная реализация.
- 8.2. Структуры и обработка списков в основной памяти Постановка задачи.
- Функция main( ).
- Функция init( ) - "Инициализировать базу данных".
- Функция delete() - "Удалить все сведения о сотруднике из базы данных".
- Функция fr( ) - "Возвратить освобожденный элемент в список свободных элементов".
- Функция input( ) - "Ввести в базу данных сведения о новом сотруднике".
- Функция print( ) - "Печать списка занятых элементов".
- Сохранение (восстановление) базы данных.
- 8.3. Сортировка на основе бинарного дерева Статические и динамические данные.
- Управление динамической памятью.
- Сортировка с помощью бинарного дерева.
- Печать результатов сортировки.
- Раздел 2. Выполнение программ в разных операционных системах Глава 9. Подготовка и выполнение программ
- 9.1. Подготовка программ в операционной системе unix
- 9.1.1. Команда make
- Формат файла описаний зависимостей модулей.
- Формат команды make.
- Макроопределения.
- Встроенные правила.
- 9.1.2. Библиотеки объектных модулей
- Стандартные библиотеки.
- Создание и сопровождение собственных библиотек.
- 9.2. Сборка и выполнение программ в интегрированной среде Turbo с 2.0
- 9.2.1. Состав системы программирования Turbo с 2.0
- 9.2.2. Экран интегрированной среды Turbo с 2.0
- 9.2.3. Система меню среды Turbo с 2.0
- 9.2.4. Настройка среды Turbo с
- Создание рабочего каталога.
- Установка в среде Turbo с 2.0 полных имен каталогов.
- Настройка параметров управления проектом.
- 9.5. Окно определения проекта
- Сборка и выполнение программы.
- 1. Команды управления курсором:
- 2. Команды вставки и удаления:
- 3. Команды обработки блоков текста:
- 4. Дополнительные команды:
- 9.3.2. Экран интегрированной среды
- 9.3.3. Система меню интегрированной среды
- Задание полных имен основных и рабочего каталогов.
- Выбор стандарта языка Си.
- Установка параметров подсистемы Make.
- Создание проекта.
- Задание аргументов командной строки.
- Сохранение параметров настройки интегрированной среды.
- Сборка и выполнение программы.
- Работа в интегрированной среде в последующих сеансах.
- Раздел 3. Практикум по программированию на языке Си Глава 10. Задачи по программированию
- 10.1. Ознакомительная работа
- 10.2. Итерационные методы и ряды
- Варианты заданий по итерационным методам и рядам
- 10.3. Работа со строками. Указатели, динамические одномерные массивы
- 10..1. Варианты задач по обработке строк*
- 10.3.2. Рекомендации по обработке строк
- 10.3.3. Пример выполнения задания по обработке строк
- 10.4. Многомерные динамические массивы с переменными размерами
- 10.4.1. Варианты задач для 1-й части задания по многомерным массивам (правила формирования многомерного массива)
- 10.4.2. Варианты для 2-й части задания по многомерным массивам
- 10.4.3. Пример выполнения задания по многомерным динамическим массивам
- 10.5. Функции и указатели
- 10.6. Функции и массивы
- 10.7. Работа со структурами
- 10.7.1. Варианты структур для выполнения работы
- 10.8. Списки и деревья
- 10.8.1. Списки
- 10.8.2. Деревья
- Приложение 1. Таблицы кодов ascii
- Коды управляющих символов (0 31)
- Символы с кодами 32 127
- Символы с кодами 128 255 (Кодовая таблица 866 - ms-dos)
- Символы с кодами 128 255 (Кодовая таблица 1251 - ms Windows)
- Приложение 2. Константы предельных значений
- Приложение 3. Стандартная библиотека функций языка Си
- Функции для работы с терминалом в текстовом режиме (файл conio.H)
- Специальные функции
- Литература
- Содержание
- Раздел 1. Полный курс программирования на стандартном языке Си 4
- Глава 1. Базовые понятия языка 4
- Глава 2. Введение в программирование на языке си 33
- Глава 3. Препроцессорные средства 73
- Глава 4. Указатели, массивы, строки 91
- Глава 5. Функции 114
- Глава 6. Структуры и объединения 155
- Глава 7. Ввод и вывод 186
- Глава 8. Примеры разработки программ 218
- Раздел 2. Выполнение программ в разных операционных системах 256
- Глава 9. Подготовка и выполнение программ 256
- Раздел 3. Практикум по программированию на языке Си 282
- Глава 10. Задачи по программированию 282
- Подбельский Вадим Валерьевич Фомин Сергей Сергеевич программирование на языке си
- 101000, Москва, ул. Покровка, 7 Телефон (095) 925-35-02, факс (095) 925-09-57