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》

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

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