C++函数参数与参数传递

参数传递

  • 参数传递是指用函数调用的实参来初始化函数形参存储区的过程
    • 函数的形参是局部对象,仅仅下函数的作用域内可见
    • 每次调用函数时,会创建形参变量,并用传入的实参初始化形参
  • 实参初始化形参:形参的类型决定
    • 如果形参是引用类型 & :形参 绑定到 实参
    • 值类型: 实参 复制赋值 形参

值传递参数

  • 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个实参
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值