参数传递
- 参数传递是指用函数调用的实参来初始化函数形参存储区的过程
- 函数的形参是局部对象,仅仅下函数的作用域内可见
- 每次调用函数时,会创建形参变量,并用传入的实参初始化形参
- 实参初始化形参:形参的类型决定
- 如果形参是引用类型 & :形参 绑定到 实参
- 值类型: 实参 复制赋值 形参
值传递参数
- C++默认参数传递
过程
- 函数调用和返回的控制权传递给被调函数,当前活动函数的执行被挂起
- 当被调函数执行完成时,主调函数从调用语句之后的语句恢复执行
- 函数在执行完函数体的最后一条语句或遇到return语句时返回
- 默认函数的返回值是值传递
函数的活动记录
- 函数在运行时使用的程序运行栈中分配的存储去,一直与该函数相关联,直到函数结束时被自动释放
- 按值传递时,函数不会访问当前调用的实参,函数中处理的只是实参的副本,这些副本在运行栈中存储,改变这些值不会影响实参
- 函数执行结束后,活动记录从栈弹出,局部值消失
适用性
- 特点
- 简单直接,不会改变实参的内容
- 缺点
- 大型 类对象 和 结构体 变量作实参:栈的时间空间开销大
- 无法满足一些必须修改实参值的函数
引用传递参数
- 引用形参绑定到实参
适用性
- 在函数内修改实参值
- 向主调函数传额外的结果
// 在大小为size的数组a中查找val,返回val第一次出现的位置和出现次数
//函数的返回值是元素第一次出现的位置,出现的次数则由参数occurs带回
int look_up(int a[], size_t size, int val, int& occurs)
{
int loc = -1;
occurs = 0;
for (size_t ix = 0; ix < size; ++ix)
if ( a[ix] == val )
{
if ( loc == -1) loc = ix;
++occurs;
}
return loc;
}
- 向函数传大型结构体、类对象:提高效率,可用const避免修改引用参数
struct Huge
{
int stuff[1000];
};
void foo(Huge& h){......}
//或者
void foo(const Huge& h){......}
//函数体内修改h的代码会引起编译错误
- 类的拷贝构造函数和重载的运算符函数
总结:参数传递方式的选择
- 内置类型的小对象:传值的方式更简单直接
- 在函数内改变实参,传引用或传指针
- 传指针比引用复杂一些,但使用起来更清晰明确
- 类类型的对象,尽量使用引用传递参数,效率更高
- 使用const限定可以避免实参被修改
- 特殊要求
- 数组和函数:作参数时必须传指针
- 拷贝构造函数:参数必须传引用
数组参数
数组作参数,传数组第一个元素的地址
- 数组的长度与参数声明无关,如果函数内部使用长度,需要单独长度做参数
void foo( int a[], int size );
- string 和 Vector是对象,不用传长度作参数
- 函数内操作会改变数组元素,可以加const限定
main函数的参数
- main函数的参数表
int main(int argc, char** argv) {...}
用于从命令行接受参数,处理命令行参数
- argc是命令行参数的个数
- 字符串数组argv的每个元素以此保存接受的参数字符串
D:\CPP\> test abc def
//argc = 3
//argv[] = { "test", "abc", "def"}
#include <iostream>
#include <cstring>
using namespace std;
int main(int argc, char* argv[])
{
if(argc != 3)
{
cout<<"参数个数错误!"<<endl;
exit(1); //退出程序,main函数返回1
}
cout << "字符串:"<<argv[1] <<endl;
cout << "字符串:"<< argv[2] <<endl;
cout << "两个字符串是否相同?";
cout << (strcmp(argv[1],argv[2])?"no":"yes") <<endl;
}
不定个数的参数
C++处理不同数量实参函数的方法
- 省略号形参,一般用于与c函数交互的接口程序
- 如果可变部分的实参类型相同,可以传递一个名为initializer_list的标准库类型
- 如果实参类型不同,可以编写可变参数模板
省略号参数
int printf( const char*, ...);
//对于显示声明的参数,进行实参的类型检查,对于...对应的实参挂起类型检查机制
initializer_list参数
- 头文件<initializer_list>
- 用于表示某种特定类型的值的数组,元素无法改变
- 使用
- 定义时要挃定列表中的元素类型
- size()函数获得参数的个数
- begin()和end()函数返回指向第一个参数和尾元素下一位置的指针
- 传递实参序列时,用一对花括号将实参值序列括起来
//程序5.5 不定个数的参数
//输出错误信息的函数error_msg,实参数量可变,都是string类型的
void error_msg(initializer_list<string> lst)
{
for(auto beg = lst.begin(); beg != lst.end(); ++beg)
cout << *beg << " ";
cout << endl;
}
int main()
{
string expected("abcd");
string actual;
cout << "enter a string: " << endl;
cin >> actual;
if(expected != actual)
error_msg({"Error", expected, actual}); //3个实参
else
error_msg({"Okay"}); //1个实参
}