前言
本文介绍C++中函数参数的情况,包括参数的两种基本传递方式,数组参数以及可变参数以及参数的使用技巧。
一、参数传递
如前文所述,每次调用函数,都会重新创建其形参,并用传入的形参对参数进行初始化。
1.1 引用传递
当形参是引用类型,引用形参是其绑定对象的别名,也就说,它对应的实参被引用传递。
对引用的操作实际上是作用于所引用的对象。如:
void reset(int &i){
i = 0;
}
改变了i所指的对象。
为了防止不当操作,当函数无需修改引用形参的值时,最好使用常量引用(const int &i)
否则,也是对函数调用者的一种误导,误以为该参数能够改变,可以认为定义常量是c++提供的一种保护机制,防止操作出现错误,又提供了更加有效的提示。
1.2 传值调用
当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象,也就说,这样的实参被传值调用。函数对形参做的所有操作都不会影响实参。
可以这么理解,被拷贝的副本被保存在正在运行的程序的栈中,随着函数调用的结束,这个栈也会被清理掉(被系统释放),它的存在是有一个生命周期的。
1.2.1 指针形参
传入指针形参时,其所指对象可以通过解引用*来改变,如对p指针所指的对象进行赋值:
*p = x;
但是关键来了,指针是c++中最容易产生错误而饱受诟病的一大特色,最好是使用引用类型的形参代替指针。
二、数组形参
由前文可知,不能拷贝数组,使用数组名实际传递的是指向数组首元素的指针(除了在sizeof()运算符)
2.1 数组存在的问题和管理方案
2.1.1 存在的问题
数组是以指针传递,不知道其维度很容易出现数组越界。
2.1.2 解决方案
(1)使用标记制定数组长度,比如c语言风格的字符串char类型,其最后还有一个空字符。
void print(const char *cp)
{
if(cp)
while(*cp) //只要当前指针所指非空字符
cout << *cp++;;
}
可以利用这个信息来管理
(2)使用标准库规范
begin()、end()函数,非数组的成员对象,得将数组名作为成员函数进行调用,返回分别指向数组首元素和尾元素下一个位置的指针,为什么是下一个位置,只有这两个函数差值即为目前的元素数,各位自己佐证。
(3)显示传递一个表示数组大小的形参end(j) - begin(j),j为所操作的数组。
2.2 数组应用参数
C++语言允许将变量定义为数组的引用,如:
void print(int (&arr)[10])
{
for(auto elem : arr)
cout <<elem << endl;
}
arr两端的括号不能少,原因是[]符号,角标符号比&引用符号优先级高,后续会出一篇介绍运算符优先级的文章。
2.3 传递多维数组
C++语言中实际上没有真正的多维数组,所谓所谓数组其实是数组的数组,理解这一点对今后多维数组的使用大有裨益。
和数组一样,当多维数组传递给函数时,实际上传递的是指向数组首元素的指针。
因为首元素本身就是一个数组,所以指针就是一个指向小一维元素的指针,二维一下比较好想象,更多维度需要比如三维本身元素是二维数组,以此扩展...
三、可变形参参数
3.1 initializer_list
为一种标准库类型,该对象的元素永远是常量,即无法改变其类型,这一点和vector和string不同。
将要传的参数放在这个模板中。
3.2 省略符参数
只能出现在形参列表的最后一个位置,其形式有两种
(1)void foo(parm_list, ...);
(2) void foo(...);
...部分表示后面的形参是可选的,其之前声明的那部分形参parm_list正常按其类型初始化。
四、Tips
(1)任意两个形参不能同名
(2)函数调用时使用的实参必须与形参类型相同或者前者能转化之。如double丢失精度变为int
(3)形参列表可以为空,不能省略,即()不能少
(4)函数最外层作用于中的局部变量不能使用与函数形参一样的名字
(5)好的形参能够增加可读性,比如使用与现实意义贴近的命名...
更多欢迎评论区互动,码字不易,点赞收藏加关注,跟着无神一起学cs