2021-10-07

本文详细探讨了C++中函数参数的传递方式,包括值传递、引用传递和指针传递,特别是const引用的使用。文章指出,引用传递能避免大对象的拷贝,提高效率,而const引用则用于保护参数不被修改。此外,还讲解了数组作为函数参数时的处理,以及多维数组的传递方法。文章以实例解析了各种参数传递的细节,强调了理解和应用这些概念的重要性。
摘要由CSDN通过智能技术生成

第八天

简单记录一下今天。很忙,上午第一节9.30下课,去离退休处报销医药费,查验的人说我没签字,也没明细,只有发票,不能报销,第一节课的时候辅导员突然催交申请书,还是先回宿舍写了申请书交上去,然后又打车去医院打印发票,回来以后再去校医院签字,然后再去报销,就已经12:50了。下午还得去马区盖章,1:30的车,吃了点饭又去赶校车,到了就2:30,盖章五分钟,突然发现流水号错了,又去网站上重新打印,联系科技处老师,折腾到3:30发现不能改了?后来就再问指导老师,老师那儿也不能改,到了4:50回到学校,又给验证码的老师问了一下,他说没问题,等到授权了再改也行。白忙活了,5:00,去学工办重新签字,签完字被辅导员拉去做迎新志愿者,听一个简单的培训,5:40,回到宿舍了,收拾包,6:10去的图书馆,今天学的东西,让我更压抑了,下面再说。
现在21:38,开始
今天学的函数的相关操作,有点难,有点绕,但是觉得学到了一点东西,比昨天好一点

1.函数

参数传递

实参与形参交互。

1.如果形参是引用类型,那么它将会绑定到实参上
2.否则,一般地,实质就是实参向形参的拷贝
当形参是引用类型,那么就是引用传递(就是绑定)
当形参是一般类型,那么就是传值调用(字面的意思)

void reset (int *ip){
	*ip = 0; //改变了ip的指向 
	ip = 0; //只是改变了局部拷贝 
}

但是上述函数的实参必须是地址


int i  = 42;
reset(&i);

综上,函数的实参和形参的代换,可以认为就是一种赋值或者是拷贝形式*p = &i;

传引用参数
void reset(int &i){
	i = 0;
}
int j = 42;
reset(j); //j采用引用传值,它的值被改变

这里的实参也发生了改变,跟上述的赋值或者拷贝形式一样的,这里也可以这么认为
但是拷贝大容量的类对象或者容器对象很低效,甚至有的类型不支持拷贝操作。当类型不支持拷贝操作的时候,函数只能通过引用形参访问该类型的对象,字符串不支持直接拷贝,同传递。

bool isShorter(const string &s1, const string &s2){
	return s1.size() < s2.size();
}

上述例子只是对两个对象进行比较,不需要对实参进行改变,这里用const更好,当函数无需修改时隐形形参的值最好使用常量引用

下面使用形参返回额外信息

string::size_type find_char(const_string &s, char c, string::size_type &occurs){
	auto ret = s.size();
	occurs = 0;
	for (decltype(ret) i = 0; i != s.size(); ++i)
		if (s[i] == c){
			if (ret == s.size()){
				ret = i;	//这里看到第一个i直接改变值,后面就不会再出现
			}
			++occurs; //出现一个就加一次
		}
		return ret;  //出现次数通过occurs隐式返回
}

代码意思不多说了,这里简答说一下几个类型,做一个总结
string::size_type 代表的是对字符串计数的数字,是整型,例如ret = s.size()
decltype(a) b = 0 将b定义成和a一样的类型
但是c++里面又auto就很不错了,对于里面出现的类型,最起码作为左值声明的时候基本上不会出现错误

const形参和实参

这里再简单的说一下顶层const和底层const,顶层const对值,对具体的规定对象,但是底层const对应的地址

const int ci = 42;//这里是顶层const,ci的值不允许改变
int i = ci; //正确,但是拷贝成功了以后,自动忽略顶层const,i就是一般类型
int * const p = &i; //const是顶层的,不能给p赋值
*p = 0; //通过p改变了i

第三条意思是可以改变p的指向,但是不能通过改变地址来改变指向的值
上面说再用实参传递值的时候可以自动忽略顶层const,也就是一般的声明了

void fcn(const int i)//能够读取i,但是不能通过i向实参写值
void fcn(int i) //这里重新定义了fcn,会报错,并不是重载函数
指针或引用形参与const
int i = 42;     
const int *cp = &i;		//不能通过cp改变i 
const int &r = i;		//r不能改变i 
const int &r2 = 42;		//r绑定在字面值上 
int *p = cp;			//p的类型和cp的类型不匹配 
int &r3 = r;			//r3的类型和r的类型不匹配 
int &r4 = 42;			// 不能用字面值初始化

一些简单的初始话,理解了好长时间,得多看,一段时间不看就忘了

reset (&i);      //int *
reset (&ci);	//不能用指向const int的指针初始化int*		
reset (&i);		//int& 
reset (&ci);	//不能用普通引用绑定 
reset (42);		//不能用数值常量绑定啊 
reset (ctr);	//ctr是无符号类型,不行

使用引用而非常量引用也会极大的限制函数所能接受的实参类型。我们不能把const对象、字面值或者需要类型转换的对象传递给普通的引用形参。

//不良设计:第一个形参的类型为const string&
string::size_type find_char(string &s, char c, string::size_type &occurs);

解释一下,如果或说是下面这个,那么就只能将其作用于string对象,简单的引用定义就是,上面的是对于一般的字符常量可以通过。
但是如果是下面的

find_char("Hello World", 'o', ctr);

第一个参数相当于常量,当然就编译不通过
还有一个更加复杂的问题,假如说一个函数里面定义了调用了另一个函数

bool is_sentence (const string &s){
	string::size_type ctr = 0;
	return find_char(s, '-', ctr) == s.size() - 1 && ctr == 1;
} 

如上,如果说传入的是一个常量string,那么在find_char中的编译会发生错误,因为其中的s不被定义,默认为不能接受常量引用,只能就收一般引用。
解决该问题有两种思路,第一种是修改is_sentence的形参类型,但是这不能从根本上解决问题,因为一旦还是一个常量string还是无法进行处理。正确的修改方法是修改find_char的形参,但是如果find_char的形参不能修改。
第二种方法是在is_sentence的函数内部修改,可以将传入的常量string存入一个s的变量,作为一个副本,再传入find_char中。

数组形参
void print(const int*);		 
void print(const int[]);     //函数的意图是作用一个数组 
void print(const int[10]);   //这里的维度说明我们希望传入的数组中含有多少个元素

尽管表现形式不同,但是上述三个语句是等价的
实参传入形参形式,同赋值形式&a[0],a
上面就说明数组是以指针的形式传递给函数的,所以函数一开始并不知道数组的确切尺寸
下面利用c++的标准库规范来说明一下

void print(const int *beg, const int *end){
	while (beg != end)
		cout << *beg++ << endl;
}
void print(begin(j), end(j));

一种方法

void print(const int ia[], size_t size){
	for (size_t i = 0; i != size; ++i){
		cout << ia[i] << endl;
		}
	}
print (j, end(j) - begin(j));	

当函数不需要对数组元素进行读写操作的时候,数组形参应该是指向const的指针。只有当函数确实要改变元素值的时候,才把形参定义成指向非向量的指针。
下面对于数组的一部分

void print(int (&arr) [10]){
	for (auto elem : arr)
		cout << elem << endl;
		}
	}	

上述(&arr)[10]是绑定再arr上的一个存有10个整型的数组。

传递多维数组方法
void print (int matrix[] [10], int rowSize)
void print (int (&matrix)[10], int rowSize)

今天先到这了,11点了,整理速度还是不大快啊,还是注意力不太集中,最重要的是有些地方看第一遍还好,看第二遍就看不大明白了,明天继续加油把,我是想先学完class类再开始看的,有点纠结,太费时间了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值