一、函數(shù)特殊參數(shù)
- 數(shù)組做函數(shù)參數(shù)
int sum_arr(char arr[], int n)
{
//函數(shù)內(nèi)部使用 arr[i]或者*(arr+i)來操作元素即可
}
//等價于
int sum_arr(char *arr, int n)
{
//函數(shù)內(nèi)部使用 arr[i]或者*(arr+i)來操作元素即可
}
//不要試圖將數(shù)組類型和元素個數(shù)結(jié)合為一個形參
int sum_arr(char arr[n])
{
//這種形參表示法肯定是錯誤的
}
//使用多維(例子是n行4列)數(shù)組作為形參悴务。列數(shù)必須明確指定
int sum_arr(char arr[][4], int n)
{
//也可以使用 char (*arr)[4] 睹限,但是上面那種表示法更為直觀的看到是個二維數(shù)組
}
char數(shù)組(或字符串)換成其他類型如int、double數(shù)組讯檐,也都一樣羡疗。
arr[] 和*arr 都只表示為一個指針,因此函數(shù)實參傳入一個數(shù)組名或者字符串常量就可以(兩者都只表示為首元素的地址)别洪,就達到了給指針指向?qū)嶋H地址的目的叨恨。
arr[] 更顯示的告訴我們,形參是一個數(shù)組挖垛,而不是一個單獨的元素變量痒钝。
*arr 更顯示的告訴我們,形參是一個指針痢毒,不是一個普通的變量送矩,要給他賦地址值。
注意:將數(shù)組名作為參數(shù)哪替,也算是值傳遞栋荸,不過傳遞的值是數(shù)組的首地址。
優(yōu)點:可以節(jié)省復(fù)制整個數(shù)組所需的時間和內(nèi)存凭舶。只是簡單傳遞地址進來就行晌块。
缺點:這樣會使函數(shù)直接操作原始數(shù)據(jù),增加了原始數(shù)據(jù)被破壞的風(fēng)險帅霜。
==》解決這個問題匆背,比較好的方法就是使用const限定符。當然如果就是想直接修改原數(shù)組數(shù)據(jù)义屏,那么就直接按上面的方法靠汁。
二、用const限制指針的能力
- 指針和const
const 常用于修飾指針闽铐,表示只給這個指針“只讀”權(quán)限蝶怔,即只能通過這個指針來讀取指向的內(nèi)存地址中的值,而不能通過這個指針來修改指向的內(nèi)存地址中的該值兄墅。
int age = 20;
const int * pt = &age;
//只能說明不能通過pt指針來修改age變量的值踢星,其他的都不能說明。
//比如隙咸,*pt = 21; 或者 *pt = *pt + 1; 都是錯誤的沐悦。也就是說(*pt)是常量const成洗。
注意:
1、age變量的值藏否,還是可以通過其他方式改變的瓶殃,比如 age = 21; 或者age = age +1;
或者指向另一個普通指針,再通過指針修改副签。這都因為age不是const限定的遥椿。
如果是 const int age = 20; 那么age就不能改了。
2淆储、pt指針冠场,也可以被賦給其他地址值,從而指向其他的地址本砰,比如 pt = &myage;
這是因為只說了(*pt)是const碴裙,沒有說pt是const。
如果是 int const * pt = &age; 那就說明指針pt是const了点额,指向的地址只能是age的地址不能改變舔株,
但是注意并沒有說age的值不能修改,所以age的值還是可以通過*pt來修改的还棱。
- 禁止將const變量的地址賦給常規(guī)指針
const int age = 20;
int * pt = &age; //這是非法操作督笆。
const * pr = &age; //這個可以有,pr為指向const的指針
- 函數(shù)形參要傳入數(shù)組時诱贿,盡量用const修飾指針
int sum_arr(const char *arr, int n)
{
//或?qū)?arr 換成 arr[] 也可以。
//使用const限定符咕缎,就不能通過arr指針對傳遞過來的數(shù)組實參做修改珠十,而是只讀權(quán)限
}
- 盡可能的使用const
1、這樣可以避免由于無意間修改數(shù)據(jù)而導(dǎo)致其他錯誤凭豪。
2焙蹭、使用const使得函數(shù)能夠處理const和非const實參。否則只能接受非const數(shù)據(jù)嫂伞。
三孔厉、函數(shù)指針
- 獲取函數(shù)的地址
函數(shù)名(不帶括號和參數(shù))就是函數(shù)的地址,比如getName就是函數(shù)名帖努,
而getName()帶上括號可能就是一次函數(shù)調(diào)用后的返回值name撰豺。用函數(shù)名來作為另一個函數(shù)的參數(shù)時,一定要注意不能帶括號拼余。
- 聲明一個函數(shù)指針
先要知道函數(shù)原型污桦,比如
int add(int i, int j);
(形參可以只留下類型,有變量值ij也好匙监,更清楚)
然后對用函數(shù)原型就可以聲明函數(shù)指針:int (*p_func)(int i, int j);
也就是直接將函數(shù)名add 用(*p_func)來代替即可凡橱。
賦值:p_func = add; 這樣就讓函數(shù)指針指向了具體的函數(shù)地址小作。
注意:必須是函數(shù)指針的聲明中函數(shù)類型以及形參列表完全一致,才能完成賦值稼钩。
- 使用函數(shù)指針來調(diào)用函數(shù)
//比如有如下函數(shù)原型顾稀,表示不同的算法。假設(shè)下面已經(jīng)簡單實現(xiàn)了這幾個函數(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); //除法
//聲明一個函數(shù)指針
int (*p_func)(int i, int j);
//再寫一個函數(shù)坝撑,使用上面的函數(shù)指針作為參數(shù)静秆,來智能使用哪種算法
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)效果一樣诡宗。
不過(*p_func)(x,y) 給人的直觀感受更強,一看就知道這是一個函數(shù)指針击儡,設(shè)計的時候可以更靈活使用它塔沃。