一、函數(shù)特殊參數(shù)
- 數(shù)組做函數(shù)參數(shù)
int sum_arr(char arr[], int n)
{
//函數(shù)內(nèi)部使用 arr[i]或者*(arr+i)來(lái)操作元素即可
}
//等價(jià)于
int sum_arr(char *arr, int n)
{
//函數(shù)內(nèi)部使用 arr[i]或者*(arr+i)來(lái)操作元素即可
}
//不要試圖將數(shù)組類型和元素個(gè)數(shù)結(jié)合為一個(gè)形參
int sum_arr(char arr[n])
{
//這種形參表示法肯定是錯(cuò)誤的
}
//使用多維(例子是n行4列)數(shù)組作為形參。列數(shù)必須明確指定
int sum_arr(char arr[][4], int n)
{
//也可以使用 char (*arr)[4] ,但是上面那種表示法更為直觀的看到是個(gè)二維數(shù)組
}
char數(shù)組(或字符串)換成其他類型如int、double數(shù)組,也都一樣。
arr[] 和*arr 都只表示為一個(gè)指針,因此函數(shù)實(shí)參傳入一個(gè)數(shù)組名或者字符串常量就可以(兩者都只表示為首元素的地址),就達(dá)到了給指針指向?qū)嶋H地址的目的。
arr[] 更顯示的告訴我們,形參是一個(gè)數(shù)組,而不是一個(gè)單獨(dú)的元素變量。
*arr 更顯示的告訴我們,形參是一個(gè)指針,不是一個(gè)普通的變量,要給他賦地址值。
注意:將數(shù)組名作為參數(shù),也算是值傳遞,不過(guò)傳遞的值是數(shù)組的首地址。
優(yōu)點(diǎn):可以節(jié)省復(fù)制整個(gè)數(shù)組所需的時(shí)間和內(nèi)存。只是簡(jiǎn)單傳遞地址進(jìn)來(lái)就行。
缺點(diǎn):這樣會(huì)使函數(shù)直接操作原始數(shù)據(jù),增加了原始數(shù)據(jù)被破壞的風(fēng)險(xiǎn)。
==》解決這個(gè)問(wèn)題,比較好的方法就是使用const限定符。當(dāng)然如果就是想直接修改原數(shù)組數(shù)據(jù),那么就直接按上面的方法。
二、用const限制指針的能力
- 指針和const
const 常用于修飾指針,表示只給這個(gè)指針“只讀”權(quán)限,即只能通過(guò)這個(gè)指針來(lái)讀取指向的內(nèi)存地址中的值,而不能通過(guò)這個(gè)指針來(lái)修改指向的內(nèi)存地址中的該值。
int age = 20;
const int * pt = &age;
//只能說(shuō)明不能通過(guò)pt指針來(lái)修改age變量的值,其他的都不能說(shuō)明。
//比如,*pt = 21; 或者 *pt = *pt + 1; 都是錯(cuò)誤的。也就是說(shuō)(*pt)是常量const。
注意:
1、age變量的值,還是可以通過(guò)其他方式改變的,比如 age = 21; 或者age = age +1;
或者指向另一個(gè)普通指針,再通過(guò)指針修改。這都因?yàn)閍ge不是const限定的。
如果是 const int age = 20; 那么age就不能改了。
2、pt指針,也可以被賦給其他地址值,從而指向其他的地址,比如 pt = &myage;
這是因?yàn)橹徽f(shuō)了(*pt)是const,沒(méi)有說(shuō)pt是const。
如果是 int const * pt = &age; 那就說(shuō)明指針pt是const了,指向的地址只能是age的地址不能改變,
但是注意并沒(méi)有說(shuō)age的值不能修改,所以age的值還是可以通過(guò)*pt來(lái)修改的。
- 禁止將const變量的地址賦給常規(guī)指針
const int age = 20;
int * pt = &age; //這是非法操作。
const * pr = &age; //這個(gè)可以有,pr為指向const的指針
- 函數(shù)形參要傳入數(shù)組時(shí),盡量用const修飾指針
int sum_arr(const char *arr, int n)
{
//或?qū)?arr 換成 arr[] 也可以。
//使用const限定符,就不能通過(guò)arr指針對(duì)傳遞過(guò)來(lái)的數(shù)組實(shí)參做修改,而是只讀權(quán)限
}
- 盡可能的使用const
1、這樣可以避免由于無(wú)意間修改數(shù)據(jù)而導(dǎo)致其他錯(cuò)誤。
2、使用const使得函數(shù)能夠處理const和非const實(shí)參。否則只能接受非const數(shù)據(jù)。
三、函數(shù)指針
- 獲取函數(shù)的地址
函數(shù)名(不帶括號(hào)和參數(shù))就是函數(shù)的地址,比如getName就是函數(shù)名,
而getName()帶上括號(hào)可能就是一次函數(shù)調(diào)用后的返回值name。用函數(shù)名來(lái)作為另一個(gè)函數(shù)的參數(shù)時(shí),一定要注意不能帶括號(hào)。
- 聲明一個(gè)函數(shù)指針
先要知道函數(shù)原型,比如
int add(int i, int j);(形參可以只留下類型,有變量值ij也好,更清楚)
然后對(duì)用函數(shù)原型就可以聲明函數(shù)指針:int (*p_func)(int i, int j);
也就是直接將函數(shù)名add 用(*p_func)來(lái)代替即可。
賦值:p_func = add; 這樣就讓函數(shù)指針指向了具體的函數(shù)地址。
注意:必須是函數(shù)指針的聲明中函數(shù)類型以及形參列表完全一致,才能完成賦值。
- 使用函數(shù)指針來(lái)調(diào)用函數(shù)
//比如有如下函數(shù)原型,表示不同的算法。假設(shè)下面已經(jīng)簡(jiǎn)單實(shí)現(xiàn)了這幾個(gè)函數(shù)定義
int add(int i, int j); //加法
int subtract(int i, int j); //減法
int multiply(int i, int j); //乘法
int divide(int i, int j); //除法
//聲明一個(gè)函數(shù)指針
int (*p_func)(int i, int j);
//再寫一個(gè)函數(shù),使用上面的函數(shù)指針作為參數(shù),來(lái)智能使用哪種算法
int result(int x, int y, int (*p_func)(int, int) )
{
printf("result is : %d", p_func(x, y) ); //也可以使用*p_func(x,y),效果一樣
}
//最后main函數(shù)調(diào)用result函數(shù)
int main()
{
result(2, 3, add); //返回2+3的結(jié)果5
result(2, 3, multiply); //返回2*3的結(jié)果6
return 0;
}
- 函數(shù)指針的調(diào)用使用,兩種方法都可以。p_func(x, y) 和(*p_func)(x,y)效果一樣。
不過(guò)(*p_func)(x,y) 給人的直觀感受更強(qiáng),一看就知道這是一個(gè)函數(shù)指針,設(shè)計(jì)的時(shí)候可以更靈活使用它。