C++知識點7——函數傳參

函數傳參的原理和對象初始化的原理完全一致,用實參去初始化形參

 

函數傳參的兩種形式

1.按值傳參

按值傳參時,實參的拷貝用來初始化形參。

int main(int argc, char const *argv[])
{
	int i=0;
	paratest(i);
	cout<<i<<endl;
	return 0;
}

void paratest(int a)
{
	++a;
	cout<<__func__<<a<<endl;
}

對paratest函數的形參a做的所有操作都不會影響i的值,上述過程相當於如下過程

int a=i; ++a;

a和i是兩個不同的對象,a的變化並不會導致i的變化

 

傳指針參數也是按值拷貝的一種,只不過會改變指針指向的對象,不會改變指針本身

int main(int argc, char const *argv[])
{
	int i=0;
	int *pi=&i;
	paratest(pi);
	cout<<i<<endl;
	return 0;
}

void paratest(int *pa)
{
	*pa=10;
}

輸出結果顯示i的值爲10,這是因爲將i的指針的副本傳入paratest,導致pa也指向i,所以可以通過pa改變i的值,上述過程相當於如下過程

int *pi=&i; int *pa=pi;

第二行代碼導致pa和pi都指向i的地址,所以都可以操作i的數據,但是傳指針參數實質還是按值傳參

 

2.按引用傳參

將函數的形參聲明爲引用,此時向函數中傳參時,傳遞的是實參本身,而不是實參的拷貝,此時形參與實參綁定,形參只不過是實參的別名

int main(int argc, char const *argv[])
{
	int i=0;
	paratest(i);
	cout<<i<<endl;
	return 0;
}

void paratest(int &ra)
{
	ra=10;
}

此時對引用形參操作,就是對實參操作

因爲傳遞的是實參本身,並沒有發生拷貝,省略了傳值過程中的拷貝過程,所以對於大的對象來說,效率更高

而且有些對象不支持拷貝操作,所以傳參時,必須使用引用形參

 

const與函數參數

當非引用或者指針的函數形參有const修飾時,傳遞const對象和非const對象都是OK的

int main(int argc, char const *argv[])
{
	int i=0;
	paratest(i);
	const int ci=10;
	paratest(ci);
	return 0;
}

void paratest(const int a)
{
	cout<<__func__<<a<<endl;
}

上述代碼可以編譯通過,但是不能在函數中修改a

函數const變量的指針或者引用的形參的初始化和const變量的指針或者引用的初始化規則完全一致,見知識點2,3

 

在聲明一個函數時,儘量使用常量引用來聲明形參

int main(int argc, char const *argv[])
{
	string str="asd";
	constreferencepara(str);
 //constreferencepara("asd");
	return 0;
}

void constreferencepara(string &str)
{
    
}

上述代碼的第5行必須註釋掉,否則會報錯

因爲一般的引用無法綁定字面值,但是const變量的引用可以,而且const變量的引用也可以綁定一般的變量,所以如果將函數constreferencepara的參數聲明爲const string &str,那麼就不會報錯

int main(int argc, char const *argv[])
{
	string str="asd";
	constreferencepara(str);
	constreferencepara("asd");
	return 0;
}

void constreferencepara(const string &str)
{

}

此時函數可以傳入參數的範圍變大,擴展性提高,而且傳遞引用不需要拷貝對象,效率提高,所以,建議使用const變量的引用作爲函數形參

 

數組形參

當使用值傳遞的方式傳遞數組參數時,數組參數會轉化爲一個指針,指向數組首元素地址,下列三種函數聲明都是等價的

void func(int *a);
void func(int a[]);
void func(int a[10]);

第三中聲明方式只是期望傳入的數組有10個元素,但是本質和前兩種完全一樣

 

當分別實現這三個函數時,編譯器會報重定義的錯誤

void func(int *a)
{
	cout<<"pointer func"<<endl;
}

void func(int a[])
{
	cout<<"array func"<<endl;
}

void func(int a[10])
{
	cout<<"array func that include 10 ele"<<endl;
}

 

由於向函數中傳入數組時,函數接收到的只是數組首元素的指針,如果在函數中需要遍歷數組,需要人爲指定數組長度

int main(int argc, char const *argv[])
{
	int a[10]={1,2,3,4,5};
	int len=sizeof(a)/sizeof(a[0]);//計算數組長度
	func(a,len);
	return 0;
}

void func(int *a,int len)
{
	for (int i=0;i<len;++i) {
		cout<<a[i]<<endl;
	}
}

這樣做不如使用vector簡潔,建議使用vector代替數組

 

傳遞數組的引用和指針

如果一個函數的形參是數組的引用,那麼必須指定數組長度,因爲引用要綁定某個具體的數組,不能綁定一個長度不確定的數組

void arrayreferpara(int (&arr)[]);

int main(int argc, char const *argv[])
{
	int a[10]={1,2,3,4,5};
	arrayreferpara(a);
	return 0;
}

void arrayreferpara(int (&arr)[10])
{
	for (int i=0;i<10;++i) {
		cout<<arr[i]<<endl;
	}
}

因爲使用數組的引用作爲形參時,傳入的數組參數的個數必須和形參數組的個數一致,所以這種接口的可擴展性不強

 

函數的形參如果是數組的指針也是同理,數組的長度必須指定,因爲數組的指針必須指向一個長度固定的數組

void arrayreferpara(int (*arr)[]);

 

通過數組的指針遍歷數組

int main(int argc, char const *argv[])
{
	int a[10]={1,2,3,4,5};
	arrayreferpara(&a);
	return 0;
}

void arrayreferpara(int (*arr)[10])
{
	for (int *p=arr[0];p!=arr[0]+10;p++) {
		cout<<*p<<endl;
	}
}

 

因爲形參是一個數組的指針,所以可以傳入一個數組的數組,也就是二維數組,道理和指針形參可以傳對應數組相同,下面三個的函數定義完全是一個意思

void arraypointerpara(int (*arr)[10])
{
	
}

void arraypointerpara(int arr[10][10])//第一個維度只是個期望值,可以填任意數
{

}

void arraypointerpara(int arr[][10])
{

}

所以會報重定義的錯,道理同一維數組

這三種形式中,數組形參的第二個唯獨必須確定,因爲二維數組依然是一個一維數組,只不過每個元素都是一個一維數組,每個元素必須確定,所以每個元素的維度必須確定

 

當傳入一個二維數組後,數組的指針指向二維數組的第一個一維數組

int main(int argc, char const *argv[])
{
	int a[2][10]={1,2,3,4,5};
	int dim=sizeof(a)/sizeof(int)/10;
	arrayreferpara(a, dim);
	return 0;
}

void arrayreferpara(int arr[][10], int length)
{
	/*int num=sizeof(arr)/sizeof(int)/10;
	cout<<num<<endl;*/
	for (int (*ap)[10]=&arr[0];ap!=&arr[0]+length;ap++) {
		for (int *p=ap[0];p!=ap[0]+10;++p) {
			cout<<*p<<endl;
		}
	}
}

因爲函數的數組形參接收的是數組名,是一個地址,所以不要在函數內對數組形參做sizeof,否則會出警告

提示sizeof將返回數組指針的大小而不是數組的大小

 

參考:

《C++ Primer》

 

歡迎大家評論交流,作者水平有限,如有錯誤,歡迎指出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章