指針(3) 函數指針、函數指針數組、函數指針數組的指針 補充:回調函數

接着指針2,繼續學習指針!

三、數組參數、指針參數(此處不細講,只看兩個問題理解一下就好)

       1.當一個函數的參數部分爲一級指針時,函數能接受什麼參數?

       1)對應的類型的一級指針     2)對應類型的一維數組名

 如:void f(int *a,int n) ;     void f(int a[],int n);

        2.當函數的參數爲二級指針時,可以接收什麼參數?

        1)應用於二維數組: void f(int a[][n],int n,int m)  對於二維數組做參數一定要先指定列數!

        2)普通二級指針:void f(int **p){}   int a=0; int *p=&a; f(&p);   

       //此處只能傳入普通二級指針,不能傳入二維數組   原因:由於二維數組要先確定長度問題,因此不能像一維數組那樣直接用

           數組名代替一級指針當參數

四、函數指針

        1.函數指針:是指向函數的指針變量。因此“函數指針”本身首先應是指針變量,只不過該指針變量指向函數。

           函數指針有兩個用途:調用函數和做函數的參數。

        2.函數指針的聲明方法爲:

          返回值類型 ( * 指針變量名) ([形參列表]);

          如:void (*pfun)(int,int); //聲明瞭一個無返回值類型,帶兩個int 類型參數的函數指針。pfun是一個指針

          注:區別於指針函數: void *pfun(int,int);//這是一個函數聲明語句  pfun是函數名。

          編碼示例:

#include <stdio.h>
int max(int a,int b);
int min(int a,int b);
int main()
{
	int a=3,b=8;
	int (*pfun)(int,int);//定義函數指針變量
        int res;
	pfun=max;
	res=pfun(a,b);
	printf("max:%d\n",res);

	pfun=min;
	res=pfun(a,b);
	printf("min:%d\n",res);
	return 0;
}
int max(int a,int b)
{
	return a>b? a:b;
}
int min(int a,int b)
{
	return a<b? a:b;
}

總結:函數指針能代替相應類型的函數名工作。

補充:函數名就相當於每個函數的入口地址。所以當函數指針指向函數時就相當於找到了打開函數的鑰匙,所以可以用函數指針進入函數。

五、函數指針數組、函數指針數組的指針

      1.函數指針數組:存放函數地址的數組。即數組元素全爲函數指針的數組。

       如:int  (*parr[10])();//該數組可存放10個int類型,無參函數的地址

       用途:當要操作多個函數時可考慮用函數指針數組。

       示例:轉移表(計數器的實現)

#include <stdio.h>
int add(int x,int y);//加
int sub(int x,int y);//減
int mul(int x,int y);//乘
int div(int x,int y);//除
void show();//菜單顯示
void calc(int input,int x,int y,int (*p[5])(int,int));//計算器!
int main()
{
	int x=0,y=0;
	int input=1;
        //定義一個函數指針數組 p
	int (*p[5])(int,int)={0,add,sub,mul,div};//轉移表
        calc(input,x,y,p);
	return 0;
}
void calc(int input,int x,int y,int (*p[5])(int,int))
{
	int result=0;
	while(input)
	{
	    show();
	    printf( "請選擇:" );
            scanf( "%d", &input); 
		if(input==0) 
		{
			printf("停止計算!\n");
			break;
		}
		if(input>=1&&input<5)
		{
			printf("請輸入操作數:\n");
		        scanf("%d %d",&x,&y);
			result=p[input](x,y);
			printf("result=%d\n",result);
		}	
	}
}
void show()
{
	printf( "*****************\n" );
	printf( "*0:close        *\n");
	printf( "*1:+         2:-*\n" );
	printf( "*3:*	     4:/*\n" ); 
	printf( "*****************\n" ); 
    
}
int add(int x,int y)
{
	return x+y;
}
int sub(int x,int y)
{
	return x-y;
}
int mul(int x,int y)
{
	return x*y;
}
int div(int x,int y)
{
	return x/y;
}

      2.函數指針數組的指針:是一個指針,指向函數指針數組。即數組元素全爲函數指針的數組。

       如:  void (*(*ppfunArr)[5]) (int,int); //就是定義了一個指針,這個指針指向的是一個長度爲5的數組,而這個數組中存儲都是 無參帶兩個int類型參數的函數的指針(地址)。可能看起來比較繞一些!下面,我將計算器用函數指針數組的指針 來實現一下。其實改動的地方不多。

       重點理解:函數指針數組 是數組! 而函數指針數組的指針是指針變量的概念! 類似之前講過的 數組 和數組指針!只是在這 裏類型不僅是平常我們見的基本類型。此處類型可以看成是函數!

#include "stdafx.h"
int add(int x,int y);
int sub(int x,int y);
int mul(int x,int y);
int div(int x,int y);
void show();
//改1:void calc(int input,int x,int y,int (*p[5])(int,int))
void calc(int input,int x,int y,int (*(*pparr)[5])(int,int));//將參數 函數指針 改爲函數指針參數的指針
int main()
{
	int x=0,y=0;
	int input=1;
	//定義一個函數指針數組
	int (*p[5])(int,int)={0,add,sub,mul,div};//轉移表
	//定義一個函數指針數組指針
	int (*(*pparr)[5])(int,int)=&p;
        calc(input,x,y,pparr);
	return 0;
}
void calc(int input,int x,int y,int(*(*pparr)[5])(int,int))
{
	int result=0;
	while(input)
	{
		show();
	        printf( "請選擇:" );
                scanf( "%d", &input); 
		if(input==0) 
		{
			printf("停止計算!\n");
			break;
		}
		if(input>=1&&input<5)
		{
			printf("請輸入操作數:\n");
		        scanf("%d %d",&x,&y);
			//改2:result=p[input](x,y);
                        //將數組名改爲指針變量  p[i](x,y)==(*pparr)[i](x,y)
			result=(*pparr)[input](x,y);
			printf("result=%d\n",result);
		}	
	}
}
void show()
{
	printf( "*****************\n" );
	printf( "*0:close        *\n");
	printf( "*1:+         2:-*\n" );
	printf( "*3:*	     4:/*\n" ); 
	printf( "*****************\n" ); 
    
}
int add(int x,int y)
{
	return x+y;
}
int sub(int x,int y)
{
	return x-y;
}
int mul(int x,int y)
{
	return x*y;
}
int div(int x,int y)
{
	return x/y;
}

 總結:在我看來,凡是指向數組的指針,加上*後都可以代替數組名來使用。

 不管是之前講過的 數組和數組指針   還是在這裏講的 函數指針數組和函數指針數組的指針其實本質上是一樣的東西,只是由後者的類型變複雜了,所以理解起來會困難一些!

學習完這一次課的內容,給我最深的感悟就是,所有複雜的東西都是從最原始的逐漸添加枝葉變成的大樹。遇到大問題的時候就

將其一步步簡化爲小的問題去逐個理解吸收。只有理解完了小的,最後才能拼成一個完整的知識體系。就如本章內容,其實最根

本的東西還是數組,指針的問題。

補充:

回調函數:

回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作爲  參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這  是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條  件發生時由另外的一方調用的,用於對該事件或條件進行響應。

編碼示例: 簡單選擇排序,用回調函數實現

#include <stdio.h>
void sort(int *a,int n,bool (*pFun)(int,int));
void output(int *a,int n);
//升序
bool less(int x,int y);
//降序
bool greater(int x,int y);
int main(int argc, char* argv[])
{
	int a[5]={2,1,4,5,3};
	output(a,5);
	printf("升序:\n");
	sort(a,5,less);
	output(a,5);
	pirntf("降序\n");
       sort(a,5,greater);
	output(a,5);
	return 0;
}
//不用回調函數時:只能單獨進行升序或是降序排列  void sort(int *a,int n);
//用函數指針做參數,實現函數調用
void sort(int *a,int n,bool (*pFun)(int,int))//1.加一個參數,傳遞比較方法
{
	int k;int tmp;
	for(int i=0;i<n;i++)
	{
		k=i;
		for(int j=i+1;j<n;j++)
		{
			//if(a[j]>a[k])||if(a[j]<a[k])
			if(pFun(a[j],a[k]))//2.調用函數實現比較操作
				k=j;
		}
		if(k!=i)
		{
			tmp=a[k];a[k]=a[i];a[i]=tmp;
		}
	}
	
}
void output(int *a,int n)
{
	printf("\n");
	for(int i=0;i<n;i++)
	{
		printf("%d ",a[i]);
	}
	printf("\n");
}
bool less(int x,int y)
{
	return x<y;
}
bool greater(int x,int y)
{
	return x>y;
}

用了回調函數後就可以將降序和升序的選擇,作爲一個函數指針 的參數傳入排序函數中。

如果感興趣,可以先自己寫好普通的排序,再在自己的代碼上改成與上面類似的回調函數。畢竟看十遍不如自己敲一遍!

以上內容是全由個人對現階段所學知識進行的總結整理,如果有任何問題歡迎指出!謝謝。

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