18. 函數(shù)指針
C語言中的函數(shù)實際上都是指向一段代碼的指針(這段代碼就是函數(shù)的實現(xiàn)).就像創(chuàng)建指向結構體, 變量的指針一樣, 你也可以把一個指針指向函數(shù). 函數(shù)指針的主要用途在于給其他函數(shù)傳"回調(diào)"(callback), 或者用來模擬類和對象.
函數(shù)指針的形式是這樣的:
int (*POINTER_NAME)(int a, int b)
和函數(shù)的聲明看起來很相似, 區(qū)別在于:
- 在函數(shù)名字外面包了一層指針的語法
- 函數(shù)的聲明是一條語句, 而函數(shù)指針是一個變量
當你定義了一個函數(shù)指針后, 這個指針變量的使用方法就像它指向的指針一樣, 只是換了一個名字.
int (*tester)(int a, int b) = sort_order; //注意 sort_order 不要帶括號
printf ("TEST: %d is same as %d\n", tester(2, 3), sort_order(2, 3));
如果 函數(shù)指針 指向的 函數(shù) 的 返回值 是 指針 的話, 是這個樣子的:
首先函數(shù)長這樣 :
char *func(int a) {}
把函數(shù)名用指針包上:char *(*func)(int a)
然后改個名字 :char *(*p_func)(int a)
解決了函數(shù)指針的基本定義, 來看函數(shù)指針的另一個問題: 怎么把一個函數(shù)指針以參數(shù)的形式傳進另一個函數(shù)呢? 函數(shù)的參數(shù)都是有類型的, 那么首先要讓函數(shù)指針有自己的類型. 我們知道函數(shù)是由返回值和參數(shù)決定的, 那么函數(shù)指針的類型也是如此, 我們用 typedef
來定義一個函數(shù)指針的類型:
typedef int (*func_type) (int a, int b);
這樣, 就可以用 func_type 來作為函數(shù)的類型了, 這類型的函數(shù)返回值為一個 int, 參數(shù)為兩個 int.
我們來看下面一段代碼
這里主要看 typedef, 定義了一個函數(shù)的類型.
然后程序最后的 test_sorting, 傳入了三個函數(shù)指針.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
/** Our old friend die from ex17. */
void die(const char *message)
{
if(errno) {
perror(message);
} else {
printf("ERROR: %s\n", message);
}
exit(1);
}
// a typedef creates a fake type, in this
// case for a function pointer
typedef int (*compare_cb)(int a, int b);
/**
* A classic bubble sort function that uses the
* compare_cb to do the sorting.
*/
int *bubble_sort(int *numbers, int count, compare_cb cmp)
{
int temp = 0;
int i = 0;
int j = 0;
int *target = malloc(count * sizeof(int));
if(!target) die("Memory error.");
memcpy(target, numbers, count * sizeof(int));
for(i = 0; i < count; i++) {
for(j = 0; j < count - 1; j++) {
if(cmp(target[j], target[j+1]) > 0) {
temp = target[j+1];
target[j+1] = target[j];
target[j] = temp;
}
}
}
return target;
}
int sorted_order(int a, int b)
{
return a - b;
}
int reverse_order(int a, int b)
{
return b - a;
}
int strange_order(int a, int b)
{
if(a == 0 || b == 0) {
return 0;
} else {
return a % b;
}
}
/**
* Used to test that we are sorting things correctly
* by doing the sort and printing it out.
*/
void test_sorting(int *numbers, int count, compare_cb cmp)
{
int i = 0;
int *sorted = bubble_sort(numbers, count, cmp);
if(!sorted) die("Failed to sort as requested.");
for(i = 0; i < count; i++) {
printf("%d ", sorted[i]);
}
printf("\n");
free(sorted);
}
int main(int argc, char *argv[])
{
if(argc < 2) die("USAGE: ex18 4 3 1 5 6");
int count = argc - 1;
int i = 0;
char **inputs = argv + 1;
int *numbers = malloc(count * sizeof(int));
if(!numbers) die("Memory error.");
for(i = 0; i < count; i++) {
numbers[i] = atoi(inputs[i]);
}
test_sorting(numbers, count, sorted_order);
test_sorting(numbers, count, reverse_order);
test_sorting(numbers, count, strange_order);
free(numbers);
return 0;
}