之前我們瞭解了指針,知道如何定義一個指針,接着知道二級指針如何使用。下面我們簡單的來回憶一下:
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; }
在這裏,轉移表就是一個函數指針數組。對於函數指針,大家肯定有了新的認識吧。