## C++primer之函數的參數傳遞以及參數的類型
## 一:函數的基本知識
(1)函數要素:返回類型,函數名字,形參(參數之間用逗號隔開)
(2)函數調用機制:我們通過調用運算符來執行函數,其中運算符就是括號
(3)當我們調用函數時,主調函數被暫停執行,被調函數開始執行,當被調函數遇到return語句時,return語句完成兩項工作,1:返回return語句中的值。2:將控制權從被調函數轉移到主調函數。函數的返回值用于初始化調用表達式的結果。
(4)函數的實參和形參必須類型一致,或者實參可以通過隱式轉換到形參類型
下面舉個例子:
~~~
#include<iostream>
using namespace std;
int function(int a) //函數返回類型,名字,參數
{ //函數體
int c=1;
while(a!=1)
{
c=c*(a--);
}
return c; //返回值
}
int main ()
{
cout<<function(5)<<endl; //調用運算符()執行函數
return 0;
}
~~~
運行結果是:

談到函數中的參數,他們是局部對象,既生命期就是在函數開始執行到函數結束執行期間(生命期:就是對象在程序中存在的時間),形參和定義在函數中的變量都是局部變量,同時,局部變量會隱藏外層作用域中的同名的變量。
下面舉個例子:
~~~
//局部靜態變量
#include<iostream>
using namespace std;
int Increase()
{
static int a;
a++;
return a;
}
//與局部變量的區別在于: 在函數退出時,
//這個變量始終存在,靜態局部變量延長了局部變量的生命周期.
//但不能被其它 函數使用, 當再次進入該函數時, 將保存上次的結果。
//其它的特點與局部變量一樣。
int main()
{
for(int i=0;i<5;i++)
cout<<"After the function,the result is "<<Increase()<<endl;;
//函數調用結束,該變量仍然存在,沒有被銷毀,繼續累加,但是由于是局部的,只能在函數內被訪問。
return 0;
}
~~~

## 二:參數傳遞
(1)傳值調用,實參通過拷貝給形參,形參和實參是兩個相互獨立的對象,兩者之間互相不影響。
(2)傳引用調用(主推使用,好處多多):形參是引用類型,即當函數被調用時,形參就是實參的另一個名字,函數中對形參的操縱就是對實參本身的操作(夠通俗吧)

(3)指針形參,當執行指針拷貝時,以指針參數傳遞,指針形參:此時將復制實參的指針:形參的改變不會引起實參的改變,但是形參指向的內容可以發生變化。
文字太乏味,舉個例子大家就知道了。
~~~
//三種參數傳遞傳遞
#include<iostream>
using namespace std;
int Increase1(int a) //<span style="color:#ff0000;">拷貝的值傳遞</span>
{
a++;
return a;
}
int Increase2( int &a) //<span style="color:#ff0000;">引用參數傳遞</span>
{
a++;
return a;
}
int Increase3( int *p) //<span style="color:#ff0000;">指針參數傳遞</span>
{
(*p)++;
return (*p);
}
int main()
{
int c=5;
Increase1(c);
cout<<"After the Increase1,the result is "<<c<<endl;
//以拷貝的方式進行調用,c的值不會變,
Increase2(c);
cout<<"After the Increase2,the result is "<<c<<endl;
//以引用的形式進行調用,c的值發生改變。
Increase3(&c);
cout<<"After the Increase3,the result is "<<c<<endl;
//以指針參數傳遞,指針形參:此時將復制實參的指針:形參的改變不會引起實參的改變,但是形參指向的內容可以發生變化。
return 0;
}
~~~
運行截圖是:
?
我們建議使用,引用類型的形參代替指針(指針還是用在函數外邊好).
為什么使用引用參數呢?
我們應該避開那些拷貝傳遞,拷貝傳遞費時費力,占資源,使用引用,我們就是直接在對象上操作,不需要拷貝,指針參數也是一樣。無論任何是時候,我們都盡量不適用“傳值調用”。
使用引用類型的形參還有一個好處就是,我們要從一個函數中得到多個值,而不是單單一個。舉個例子,有一字符串,里面有很多單詞,要求,計算出第一個第一個空格(也就是第一個單詞后的空格),和所有空格數量,此時要計算出兩個值,則我們可以如下:
~~~
#include<iostream>
using namespace std;
#include <string>
int find_char(<span style="color:#ff0000;">const string s,int &a</span>)
{
cout<<"the string is "<<s<<endl;
decltype(s.size()) i=0; //i 的類型個s.size 一樣
i=s.find(' ',0); //從索引0開始找第一個為空格的,返回索引,失敗返回-1
for(auto b=s.begin();b!=s.end();b++) //使用C++迭代器查找string中總的空格數
{
if(*b==' ')
<span style="color:#ff0000;">a++; //這個引用參數雖然沒有輸出,但是我們仍然可以得到它,這就是引用的好處</span>
}
return i;
}
int main()
{
string s="Zheng zhengzhou university software institute";
int k=0;
cout<<"the blank characters of first index is "<<find_char(s,k)<<endl;
cout<<"the sum of black characters have "<<k<<endl; //引用形參,形參改變,實參也跟著改變。
return 0; //<span style="color:#ff0000;">實現了一個返回值,卻可以得到兩個有用的參數</span>
}
~~~

## 三:初始化時忽略形參的const特性
我們使用實參初始化形參時,可以忽略形參的頂層const,通俗一點來說,當形參是const類型,實參是否是const 類型都一樣。反之也成立(當實參是常量類型,形參是否是常量類型都一樣),只是當形參是常量類型,函數中不允許改編實參。
例子如下:
~~~
//實參初始化形參時,可以忽略形參是否是const類型
#include<iostream>
using namespace std;
int add1(const int &a)
{
cout<<a<<endl;
return 1;
}
int add2(int a,int b)
{
cout<<"After the add2,the result is "<<a+b<<endl;
return 1;
}
int main()
{
const int a=9;
int b=10;
add1(a); //形參是常量,實參是非常量,只要在程序中不改變形參的值即可:
add1(b); //使用const實參初始化const形參肯定是沒有問題的。
const int c=11;
const int d=12;
add2(c,d); //形參是非常量,實參是常量。
return 0;
}
~~~

上面的例子告訴我們,盡量使用常量的引用,當在函數中不改變參數時,我們設置為常量。把函數不會改變的形參定義成普通的引用是一種常見的錯誤,這么做帶給函數的調用者一種誤導,既函數可以修改它的實參值,使用引用而非常量引用也會極大地限制所能接受的實參類型,例如,我們不能把const 對象,傳給普通的引用形參。
## 四:形參是數組
當形參是數組時候,若形參是:a[10],a,a[],這三種形式都一樣,原理是:數組會被轉換成指針,我們外函數傳遞數組,其實就是為數組傳遞數組的首元素的指針。
例如一下程序:
~~~
#include<iostream> //顯式的傳入一個數組大小的參數
using namespace std;
int print(const char *a,int b) //數組作為形參的,傳遞的其實是手首元素指針,其中參數1也可以寫成:a[],a[10]
{
for(int i=0;i<b;i++)
cout<<a[i]<<endl;
return 0;
}
int main()
{
char a[]="helloworld";
//重載函數,編譯器根據參數的類型個數判斷調用哪個
print(a,10); //其實有11個元素,最后一個元素為空
return 0;
}
~~~
## 五:函數的返回類型
(1)存在返回值,返回值類型與函數返回類型一致,或者可以隱式轉換,返回值通過return 返回到主調函數中。其中,一個返回引用的的函數可以充當左值,其原理和變量可以充當左值是一樣的。
(2)沒有返回值,既renturn ;即可,也可以沒有這句話,函數會自動隱式添加這句話。
舉個例子
~~~
<span style="font-size:18px;">//返回類型是引用可以當左值
#include<iostream>
using namespace std;
int& function(int &a)
{
cout<<"Before the change,the a is"<<a<<endl;
return a;
}
int main()
{
int a=4;
function(a)=50;
cout<<"after the change,the a is"<<a<<endl;
return 0;
}</span>
~~~
第一遍看C++primer,以后還得多看,多想,多練。暫且到這吧
