函數指針

    之前我們瞭解了指針,知道如何定義一個指針,接着知道二級指針如何使用。下面我們簡單的來回憶一下:

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;
}

在這裏,轉移表就是一個函數指針數組。對於函數指針,大家肯定有了新的認識吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章