(一)、二維數組與二級指針參數數組
二維數組作參數:ide
二維數組作參數與一維數組作參數同樣,傳遞的都是首元素的地址,只不過二維數組的每一個元素又是一個一維數組 。函數
例:int arr[5][10];url
這是一個5行10列的×××數組,能夠將它當作一個只有5個元素的一維數組,只不過每一個元素又是一個大小爲10的一維數組。spa
fun(arr);咱們來分析一下當arr做爲實參是,須要什麼類型的形參來接受它???指針
arr做爲參數時,表明首元素地址,要接受這個地址必須是一個指針或者是一個數組,可是他的每一個元素的類型是int[10]。get
因此咱們能夠用一個指向類型爲int [10]的數組指針來接受arr[5][10],即:int (*p)[10] 。 一樣也能夠用一個數組來接受arr,即:int arr1[][10],這裏第二維的大小不能省略,在這裏int arr1[][10] 也能夠被解析成int (*arr1)[10];input
二級指針作參數:回調函數
例:char *p[5];it
這是一個大小爲5,每一個元素都是char *類型的數組,當他做爲實參時,須要什麼樣類型的形參來接受他呢???
fun(p); 分析:既然p是一個數組,那麼數組在做爲實參時,實際上傳遞過去的是首元素的地址,可是p的每個元素都是一個char *類型,也是一個地址,因此形參的類型應該是char **。
總結:
數組名只有在sizeof()和取&時纔不發生降級,其他地方都表明首元素地址。
(二)、函數指針
函數指針: 是一個指向函數的指針
聲明:
例:void (*p)(); 首先p是一個指針,它指向一個返回值爲空,參數爲空的函數。
初始化:
要明確,函數指針本質仍是一個指針,既然是指針,那麼就必須給他進行初始化才能使用它,下面來看一看函數指針的初始化,定義一個返回值爲空參數爲空的函數:void fun()。
p=fun;
p=&fun;
這兩種初始化的方式都是正確的。由於函數名在被編譯後其實就是一個地址,因此這兩種方式本質上沒有什麼區別。
調用:
p();
(*p)();
這兩種方式都是正確的。p裏面存的fun的地址,而fun與&fun又是同樣的。
例:分析一下(*(void (*) () ) 0 ) ()是個什麼東東!!!
首先,void (*) ();是一個返回值爲空,參數爲空的函數指針類型。
void (*) () 0 ; 它的做用是把0強制類型轉換成一個返回值爲空,參數爲空的函數指針。
(*(void (*) () )0) ; 找到保存在0地址處的函數。
(*(void (*) () ) 0 ) (); 對這個函數進行調用。
用途:
一、回調函數:用戶將一個函數指針做爲參數傳遞給其餘函數,後者再「回調」用戶的函數,這種方式稱爲「回調函數」,若是想要你編寫的函數在不一樣的時候執行不一樣的工做,這時就可使用回調函數。回調函數也算是c語言裏面爲數很少的一個高大上的東西。
二、轉換表:轉換表本質上是一個函數指針數組,說白了就是一個數組,只不過數組裏面存放的所有都是函數指針。
例:實現一個計算器
#include<stdio.h> #include<stdlib.h> #include<assert.h> int Add(int a, int b) { return a + b; } int Sub(int a, int b) { return a - b; } int Mul(int a, int b) { return a *b; } int Div(int a, int b) { assert(b != 0); return a / b; } int operator(int (*fun)(int,int)) //回調函數 { int a = 0; int b = 0; printf( "請輸入操做數:" ); scanf( "%d%d", &a, &b); return (*fun )(a,b); } int main() { printf( "*************************************\n" ); printf( "*0.exit 1.Add****\n" ); printf( "*2.Sub 3.Mul****\n" ); printf( "*4.Div *********\n" ); int(*fun[5])(int ,int); //轉換表 fun[1] = Add; fun[2] = Sub; fun[3] = Mul; fun[4] = Div; int input = 1; while (input) { printf( "請選擇> " ); scanf( "%d", &input); if (input<0 || input>4) { printf( "選擇無效\n" ); } else if (input == 0) { break; } else { int ret = operator(fun[input]); printf( "%d\n", ret); } } system( "pause"); return 0; }
在這個計算器程序中,就使用到了轉換表fun[]。fun[]裏面存放了加減乘除四個函數,根據input的不一樣,fun[input]調用不一樣的函數。這種方式與switch() case的功能比較類似,不過轉換表比switch()case更簡單。
函數指針數組:
函數指針數組是一個指針數組,也就是一個數組,只不過裏面存放的全都是函數指針。
聲明:例: char* (*p[5])(int,int);
p與[5]先結合成一個數組,因此這是一個大小爲5的數組,數組元素的類型是一個函數指針,這個函數指針指向一個返回值爲char *,有兩個參數,且參數類型爲int,int的數組。
能夠這樣理解:char * (*)(int,int) p[5]; 其中char*(*)(int int)是p[5]的類型。
函數指針數組的指針:
函數指針數組的指針是一個數組指針,本質上是一個指針,只不過指向的是一個存放函數指針的數組。
聲明:例:char *(*(*p)[5])(int,int);
*與p先結合成一個指針,因此p是一個指針,指針所指向的是一個大小爲5的數組,這個數組存放的是函數指針,這些函數指針所指向的類型是返回值爲char *,有兩個int型參數的函數。
能夠這樣理解: char *(*[5])(int,int) *p; p是一個指針,類型是char*(*[5])(int,int).
總結:指針數組,是一個數組,裏面存放的是指針。
數組指針,是一個指針,指向一個數組的指針。
函數指針數組,是一個數組,裏面存放的是函數指針。
函數指針數組指針,是一個指針,指向一個存放函數指針的數組。
其實規律很簡單,強調的都是最後兩個字,最後兩個字是什麼他就是什麼,而前面的字就是他的類型。