S pomocí pointerů na funkce lze v omezené míře pracovat s funkcemi vyššího řádu. Pointer na funkci je adresa, kde je funkce uložena v paměti. S pomocí této adresy lze funkci volat. Podobně jako u polí, jméno funkce degeneruje na pointer na funkci.
Pointer na funkci sebou nese i typové informace: typ návratové
hodnoty a počet a typy argumentů. Zápis tohoto typu podobný jako zápis
hlavičky funkce bez jmen argumentů, pouze jméno funkce nahradíme
(*)
.
int (*)(int*, int) // typ pointer na fci, ktera vraci int,
// jeji argumenty jsou typu int* a int.
Při definici proměnné se identifikátor píše dovnitř závorky za
*
.
int (*fce_ptr)(int*, int); // definice pointeru
Předchozí syntax je trochu nešikovná, proto se často používá
typedef
.
typedef int (*p_fun)(int* , int); // typ se jmenuje p_fun
; // definice promenne p_fun ptr
S pointery na funkce nelze provádět aritmetiku, ani aplikovat operátory adresy a dereference (resp, tyto operátory nedělají nic). Můžeme ovšem funkci volat, syntax volání je přitom stejná jako u běžného volání funkce.
typedef int (*p_fun)(int* , int);
int array_sum(int *array, int n) {
int r = 0;
for (int i = 0; i < n; i += 1) {
+= i;
ret }
return ret;
}
int array_product(int *array, int n) {
int ret = 1;
for (int i = 0; i < n; i += 1) {
+= i;
ret }
return ret;
}
int main() {
int a[] = { 1, 2, 3, 4, 5 };
int n = sizeof(a)/sizeof(*a);
= array_sum; // reduce ukazuje na funkci array_sum
p_fun reduce ("%i\n", reduce(a, m)); // vytiskne 15, vola array_sum
printf= array_product;
reduce ("%i\n", reduce(a, m)); // vytiskne 120, vola array_product
printfreturn 0;
}
S pointery na funkce lze pracovat jako s jinými typy v C. Lze tvořit jejich pole, předávat je do funkcí jako argumenty, mohou být návratovými hodnotami funkcí atd.
Pointer na funkci může být neplatný, v tom případě vede pokus o volání k nedefinovanému chování. Pointeru na funkci je možné přiřadit 0 a pointery na funkce lze porovnávat.
Jedno z využití pointerů na funkce je tvorba analogii generických funkcí známých z jiných jazyků. Ideou je, že funkci naprogramujeme jednou a ona poté pracuje pro více typů. Ukážeme si to na příkladu binárního vyhledávání.
typedef int compare_fn(void *, void *); // argumenty jsou void*, aby byla funkce obecna
int compare_int(void *a, void *b) {
int *aa = a; // tuto funkci budeme volat pouze s int*,
int *bb = b; // muzeme bezpecne pretypovat
if (*aa < *bb) return -1;
if (*bb < *aa) return 1;
return 0;
}
int compare_long(void *a, void *b) {
long* aa = a;
long* bb = b;
if (*aa < *bb) return -1;
if (*bb < *aa) return 1;
return 0;
}
//
// genericka funkce pro binarni vyhledavani
//
int binary_search(void *array, // pole, ve kterem vyhledavame
void *key, // ukazatel na hodnotu klice
size_t n, // pocet prvku pole
size_t element_size, // velikost jednoho prvku v bajtech
* cmp) // funkce pro porovnani dvou prvku
compare_fn{
unsigned char* bytes = array;
int l = 0;
int p = n-1;
while (l <= p) {
int s = (l + p) / 2;
unsigned char* s_ptr = bytes + s * element_size; // tady adresu prvku na indexu s
int cmp_result = cmp(key, s_ptr); // zjistime vysledek porovnani
if (!cmp_result) {
return s;
}
else if (cmp_result > 0) { // klic je vetsi
= s + 1;
l }
else {
= s - 1;
p }
}
return -1;
}
//
// pro jednotlive typy vytvorem funkce tvorici rozhrani
//
int binary_search_int(int* array, int key, size_t n) {
return binary_search(array, &key, n, sizeof(int), compare_int);
}
int binary_search_long(long* array, long key, size_t n) {
return binary_search(array, &key, n, sizeof(long), compare_long);
}
int main() {
int array_int[20];
long array_long[20];
for(int i = 0; i < 20; i += 1) {
[i] = i;
array_int[i] = i;
array_long}
int key_int_ok = 10;
int key_int_fail = 30;
long key_long_ok = 5;
long key_long_fail = -3;
("index of %i in array_int is %i\n",
printf,
key_int_ok(array_int, key_int_ok, 20));
binary_search_int
("index of %i in array_int is %i\n",
printf,
key_int_fail(array_int, key_int_fail, 20));
binary_search_int
("index of %li in array_long is %i\n",
printf,
key_long_ok(array_long, key_long_ok, 20));
binary_search_long
("index of %li in array_long is %i\n",
printf,
key_long_fail(array_long, key_long_fail, 20));
binary_search_long
return 0;
}
S použitím předchozího příkladu vytvořte funkci pro binární vyhledávání zlomků.
Napište funkci
double* map(double (*fce)(double), double* input, int len)
,
která na hodnoty pole input
aplikuje funkci
fce
a vrátí pole výsledných hodnot. Velikost pole
input
parametrem len
.
Napište funkci
double akumulator(double (*fce)(double, double), double numbers[], int len)
,
která zpracuje pomocí předané funkce fce
hodnoty z pole
numbers
, jehož velikost je dána parametrem
len
. Můžete předpokládat, že len
je vždy
alespoň 2.