Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Итог_Пособие C++.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.03 Mб
Скачать

1.12.1 Указатель на функцию

Указатель на функцию содержит адрес памяти, по которому располагается данная функция. Имя функции является адресом начала программного кода функции (как и в случае с массивом). Указатель на функцию объявляется следующим образом:

Тип (* имя_указателя)(список_параметров_функции)

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

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

// Пример 1.18 - универсальный вариант поиска в массиве

#include <iostream>

using namespace std;

// функция возвращает позицию первого найденного элемента

// или -1, если такой элемент не найден в массиве

int search(int a[],int n,int s, bool(*compare)(int,int)){

for (int i=0;i<n;i++)

if(compare(a[i],s))return i+1;

return -1;

}

bool cmp1(int a, int b){ // сравнение на точное равенство

if (a==b)return true; else return false;

}

bool cmp2(int a, int b){ // сравнение на равенство последней цифры

if (a%10==b%10)return true; else return false;

}

int main() { // демонстрация работы функций

int a[]={1,4,12,2,3,4,11};

int l = search(a,7,2,cmp1);

cout << l << endl;

l = search(a,7,2,cmp2);

cout << l << endl;

system("pause"); return 0;

}

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

Язык C++ поддерживает возможность написания функций с переменным числом параметров. Для этого при объявлении функции в конце списка параметров ставится многоточие (…). В стандартной библиотеке наиболее типичными примерами таких функций являются printf и scanf.

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

printf("%d %f %s", 5, 3.14, "abc");

Первый (обязательный) параметр функции представляет собой так называемую строку формата. В ней встречаются спецификаторы формата (начинающиеся со знака '%'), с помощью которых функция printf понимает, сколько дополнительных параметров передано в функцию и какие они имеют типы. Спецификаторы %d, %f и %s говорят о том, что в функцию переданы три дополнительных аргумента типов int, double и char* соответственно.

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

// Пример 1.19 - функция с переменным числом параметров

#include <iostream>

int sum(int n, ...) { // может верно работать не во всех компиляторах!

int res = 0;

for (int i = 0, *p = &n + 1; i < n; i++, p++)

res += *p;

return res;

}

int main() {

std::cout << sum(2, 3, 5) << std::endl; // 8

std::cout << sum(4, 1, 2, 3, 4) << std::endl; // 10

}

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

Более правильным подходом к написанию функций с переменным числом аргументов является использование специальных макросов va_start, va_arg, va_end из заголовочного файла stdarg.h. Данные макросы делают примерно то же самое, что мы выше делали вручную, но при этом гарантируется корректное получение параметров из стека. Ниже приведён правильный вариант написания функции sum:

// Пример 1.20 - функция с переменным числом параметров

// с использованием стандартных макросов

#include <iostream>

#include <stdarg.h>

int sum(int n, ...) {

int res = 0;

va_list args;

//встаём на первый параметр

va_start(args, n);

for (int i = 0; i < n; i++) {

//получаем следующий параметр, указывая его тип

res += va_arg(args, int);

}

va_end(args); // обеспечиваем правильное восстановление стека

return res;

}

int main() {

std::cout << sum(2, 3, 5) << std::endl; // 8

std::cout << sum(4, 1, 2, 3, 4) << std::endl; // 10

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]