(一)、二維數組與二級指針參數
二維數組做參數:
二維數組做參數與一維數組做參數一樣,傳遞的都是首元素的位址,隻不過二維數組的每個元素又是一個一維數組 。
例:int arr[5][10];
這是一個5行10列的×××數組,可以将它看成一個隻有5個元素的一維數組,隻不過每個元素又是一個大小為10的一維數組。
fun(arr);我們來分析一下當arr作為實參是,需要什麼類型的形參來接受它???
arr作為參數時,代表首元素位址,要接受這個位址必須是一個指針或者是一個數組,但是他的每個元素的類型是int[10]。
是以我們可以用一個指向類型為int [10]的數組指針來接受arr[5][10],即:int (*p)[10] 。 同樣也可以用一個數組來接受arr,即:int arr1[][10],這裡第二維的大小不能省略,在這裡int arr1[][10] 也可以被解析成int (*arr1)[10];
二級指針做參數:
例:char *p[5];
這是一個大小為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 ) (); 對這個函數進行調用。
用途:
1、回調函數:使用者将一個函數指針作為參數傳遞給其他函數,後者再“回調”使用者的函數,這種方式稱為“回調函數”,如果想要你編寫的函數在不同的時候執行不同的工作,這時就可以使用回調函數。回調函數也算是c語言裡面為數不多的一個高大上的東西。
2、轉換表:轉換表本質上是一個函數指針數組,說白了就是一個數組,隻不過數組裡面存放的全部都是函數指針。
例:實作一個電腦
#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).
總結:指針數組,是一個數組,裡面存放的是指針。
數組指針,是一個指針,指向一個數組的指針。
函數指針數組,是一個數組,裡面存放的是函數指針。