之前我们了解了指针,知道如何定义一个指针,接着知道二级指针如何使用。下面我们简单的来回忆一下:
int a = 10; //一个×××变量 int *p = &a; //一个指向×××的指针 int **q = &p; //q是一个指向p的指针,即它是一个指向×××的指针的指针
在这里我们要认识一个新的指针,函数指针,即指向函数的指针。例:
int (*fun)(); //fun是函数指针,它所指向的函数返回值为×××
解析:我们首先要知道这是一个声明,其中这两个花括号也代表了不同的含义。第二个花括号是函数调用操作符,第一个花括号中间接访问操作符迫使间接访问在函数调用之前进行,因此这里使fun成为一个函数指针,它所指向的函数返回值为×××。
int *(*fun)(); //fun是函数指针,它所指向的函数返回值为×××指针
与上述声明不同的是,返回值不同。
int *fun[10]; //一个包含10个元素的指针数组 int (*fun[10])(); //fun为10个元素的一个函数指针数组
如果函数有参数,我们必须把函数的参数加上,使用完整的函数原型,当然声明时可以不写形参变量名。例:
int (*fun)(int , char); int (*fun[10])(int ,char);
下面我们来讲一讲函数指针的应用吧!
最常见的两个用途是回调函数和转换表。
回调函数:用户把一个函数指针作为参数传递给其他函数,后者将回调用户的函数。
在这里,我们用冒泡排序的方法来实现一下字符串,×××数组的比较吧。
#include<stdio.h> #include<string.h> int int_cmp(void *a1, void *a2) //×××数组的比较 { return *(int *)a1-*(int *)a2; } int str_cmp(void *s1, void *s2) //字符串的比较 { return strcmp((char *)*(int *)s1,(char *)*(int *)s2); } void swap(void *p, void *q, int size) //将两值交换 { //我们需要交换函数作用于任何类型的值,因此把参数 int i = 0; 声明为(void *),一个指向未知类型的指针 char tmp; for(i = 0;i < size;i++) { tmp = *((char*)p+i); *((char*)p+i) =*((char*)q+i); *((char*)q+i) = tmp; } } void bubble(void *ptr, int size , int len ,int(*cmp)(void *p,void *q)) //冒泡排序 { int i = 0,j = 0; for(i = 0;i < size-1;i++) { for(j = 0;j <size-1-i;j++) { if(cmp((char *)ptr+j*len,(char *)ptr+(j+1)*len) > 0) { swap((char *)ptr+j*len,(char *)ptr+(j+1)*len,len); } } } } int main() { int arr[]={1,3,4,5,7,8,9,6,2,10}; char *str[]= {"ddddd","ccccd","bbbbb","aasas","bbbbd"}; int i=0 ; int size = sizeof(arr)/sizeof(arr[0]); int sz = sizeof(str)/sizeof(str[0]); bubble(arr, size, sizeof(int), int_cmp); //回调函数int_cmp for(i = 0;i < size;i++) { printf("%d ",arr[i]); } printf("\n"); bubble(str,sz,sizeof(char *),str_cmp); //回调函数str_cmp for(i = 0;i <sz;i++) { printf("%s\n",str[i]); } return 0; }
转移表:在这里,我们可以用转移表来实现一个袖珍式计算器。比如原始的计算器函数可以写为:
#include<stdio.h> #include<stdlib.h> enum jl { EXIT, ADD, SUB, MUL, DIV }; void menu() { printf(" 1.add 2.sub\n"); printf(" 3.mul 4.div\n"); printf(" 0.exit \n"); } int _add(int num1,int num2) { return num1 + num2; } int _sub(int num1,int num2) { return num1 - num2; } int _mul(int num1,int num2) { return num1 * num2; } int _div(int num1,int num2) { return num1 / num2; } int main() { int select = 1; int ret = 0; int num1 = 0,num2 = 0; while(select) { menu(); printf("请选择:\n"); scanf("%d",&select); if(select != 0) { printf("请输入两个整数:\n"); scanf("%d%d",&num1,&num2); } switch(select) { case ADD: ret = _add( num1, num2); break; case SUB: ret = _sub( num1, num2); break; case MUL: ret = _mul( num1, num2); break; case DIV: ret = _div( num1, num2); break; case EXIT: exit(1); break; } printf("ret = %d\n",ret ); } return 0; }
而知道了转移表后,我们可以这样写:
#include<stdio.h> #include<stdlib.h> void menu() { printf(" 1.add 2.sub\n"); printf(" 3.mul 4.div\n"); printf(" 0.exit \n"); } int _add(int num1,int num2) { return num1 + num2; } int _sub(int num1,int num2) { return num1 - num2; } int _mul(int num1,int num2) { return num1 * num2; } int _div(int num1,int num2) { return num1 / num2; } int main() { int (*fun[5])(int ,int ) = {0, _add, _sub, _mul, _div}; int select = 1; int ret = 0; int num1 = 0,num2 = 0; while(select) { menu(); printf("请选择:\n"); scanf("%d",&select); if(select != 0) { printf("请输入两个整数:\n"); scanf("%d%d",&num1,&num2); ret = fun[select](num1,num2); printf("ret = %d\n",ret ); } } return 0; }
在这里,转移表就是一个函数指针数组。对于函数指针,大家肯定有了新的认识吧。