函數(shù)的基本構(gòu)成
- 輸入
- 實參傳值給形參
- 傳值參數(shù):拷貝復制,基本類型和指針。
int n = 0; i = 42;
int *p = &n, *q = &i;
*p = 42; // n的值發(fā)生改變,p的值并不會發(fā)生改變。
p = q; // p 的指向發(fā)生了改變
所以說,指針作為形參,只是存儲了變量的地址。就是說調(diào)用函數(shù)的時候,實參地址傳遞給形參,形參拷貝實參的值,也就是地址。說明了參數(shù)調(diào)用時,發(fā)生的是值拷貝。但是通過解引用運算符(*)可以進行實參的賦值操作
void reset (int *ip){
*ip = 0; // 解引用操作,改變其所指對象的值;
ip = 0; // 只改變了ip 的局部拷貝,并不影響實參的值。
}
換句話來說,由于指針也是對象,所以當指針作為形參時,指針的值完成了從實參到形參的拷貝。形參作為被調(diào)函數(shù)的局部參數(shù)。當調(diào)用結(jié)束后,函數(shù)的形參被銷毀。
經(jīng)典例子
// 并不能交換實參的值
int a = 1; b= 2;
void swap(int x, int y){
int temp;
temp = x;
x = y;
y = temp;
}
理解思路:程序順序執(zhí)行的時候,其實是不斷地開棧清棧的過程,作為聲明的全局變量,他擁有屬于他的內(nèi)存。調(diào)用函數(shù)的過程是值拷貝的過程。被調(diào)函數(shù)想改變?nèi)值淖兞?,只有可能通過綁定地址來操作。因為本質(zhì)上來說,形參與實參都會開辟內(nèi)存,只不過形參的生存期僅在函數(shù)調(diào)用的時間段。當被調(diào)用結(jié)束后,形參的生存期結(jié)束。釋放內(nèi)存。引用和指針都是一種綁定的操作。
但是現(xiàn)在基本上程序中基本上不會出現(xiàn)這種代碼,因為形參基本上都是傳引用參數(shù),這樣的好處有很多,避免了拷貝會出現(xiàn)的大規(guī)模開內(nèi)存的情況。因此,引用傳遞參數(shù)會天然的綁定到實參中,如果程序的本意并不是改變實參,那么常見const 形參,如果要改變實參,就可以使用引用,避免拷貝。
- 傳引用參數(shù)
綁定類型的典范,建議使用引用作為形參,來避免拷貝。
當不修改,實參的值時:建議使用 const 引用傳參。
修改實參時,也建議通過引用來避免拷貝運算。 - 初始化與賦值操作是兩種不同的操作
- 非const 的初始化操作注意值對應。
- const 形參注意底層const 的誤區(qū)。
建議常量引用的類型避免了底層const的報錯;
void fcn(const int i) // fcn 能讀取i ,但不能寫;
void fcn(int i ) // 重復定義,因為初始化的時候會忽略掉頂層const
- 數(shù)組作為形參
數(shù)組這種類型不允許拷貝(感覺所有占大內(nèi)存的數(shù)據(jù)類型都是不允許拷貝的會消耗棧的空間)。所以當其作為形參時,數(shù)組會被轉(zhuǎn)化成指針。
void print(const int*);
void print(const int[]);//等價表達
void print(const int[10]);//傳遞的函數(shù)類型是const int *
- 由于數(shù)組有大小限制,因此要特別注意數(shù)組形參的大小。
void print(const int *beg, const int *end){
while (beg != end)
cout << *beg++ << endl;
}
void print(const int ia[], size_t size){
for (size_t i = 0; i != size; i++) // for (auto elem : ia)
cout << ia[i] << endl; // cout << elem << endl;
}
- 多維數(shù)組
多維數(shù)組的定義實際上是數(shù)組的內(nèi)容是數(shù)組。因此執(zhí)行拷貝操作,實際上是做的將指針指向數(shù)組。
void print (int (*matrix) [10],int rowsize)
void print (int matrix[] [10], int rowsize) // 等價操作
[] 下標操作符,& 取地址操作符,實質(zhì)上都會反饋迭代器操作,也就是指針。
- main :處理命令行選項
有時候要給main 函數(shù)傳遞參數(shù),根據(jù)一組選項來確定函數(shù)要執(zhí)行的操作。
int main (int argc,char *argv[]); // argv大小為argc的裝著C風格字符串的數(shù)組。
int main (int argc, char **argv[]) //等價寫法
- 形參可變
intitializer_list <T> lst; 存儲可變大小的相同類型的一種形參,支持迭代器操作。
2.返回值
- 可以飲用返回,不發(fā)生臨時變量的拷貝動作,同時還可以作為左值;
deltype (左值) 返回 引用類型。引用類型是可以作為左值的,也就是說要賦值。 - auto 和 deltype 的用法
略 - 不要返回局部對象的引用或者指針
- 返回數(shù)組數(shù)組指針的寫法
int arr[10];
int *p1[10]; // 十個指針的數(shù)組
int (*p) [10] = &arr; // 指向數(shù)組的指針
int (*func(int i))[10];
auto func(int i) -> int (*) [10];
- 函數(shù)指針和lambda 表達式
bool lengthCompare(const string &, const string &);
bool (*pf) (const string &,const string &);// 函數(shù)指針
pf = lengthCompare;// pf 指向lengthCompare 函數(shù)
pf = &lengthCompare //等價說法,&可選;