C++基础02-C++对c的拓展

25 篇文章 1 订阅
22 篇文章 2 订阅

变量名实质上是一段连续存储空间的别名,是一个标号(门牌号)

通过变量来申请并命名内存空间.

通过变量的名字可以使用存储空间.

变量名,本身是一段内存的引用,即别名(alias). 引用可以看作一个已定义变量的别名。

引用的语法:Type& name = var;

int a=10;  //c编译器分配4个字节内存, a内存空间的别名

int &b=a;  //b就是a的引用

3.1.3 规则

1 引用没有定义,是一种关系型声明。声明它和原有某一变量(实体)的关系。故而类型与原类型保持一致,且不分配内存。与被引用的变量有相同的地址。

2 声明的时候必须初始化,一经声明,不可变更

3 可对引用,再次引用。多次引用的结果,是某一变量具有多个别名

4 &符号前有数据类型时,是引用。其它皆为取地址

 

const int a;

int const b;

//第⼀个第⼆个意思⼀样 代表⼀个常整形数

const int *c;

//第三个 c是⼀个指向常整形数的指针(所指向的内存数据不能被修改,但是本⾝可以修改)

int * const d;

//第四个 d 常指针(指针变量不能被修改,但是它所指向内存空间可以被修改)

const int * const e ;

//第五个 e⼀个指向常整形的常指针(指针和它所指向的内存空间,均不能被修改)

const 常量是由编译器处理的,提供类型检查和作用域检查

 #define 宏定义由预处理器处理,单纯的文本替换  

引用作为函数参数

       普通引用在声明时必须用其它的变量进行初始化,引用作为函数参数声 明时不进行初始化

引用作为函数的返回值(引用当左值)

I. 当函数返回值为引用时,

         若返回栈变量: 不能成为其它引用的初始值(不能作为左值使用)

         若返回静态变量或全局变量 可以成为其他引用的初始值(可作为右值使用,也可作为左值使用)

        如果返回值为引用可以当左值

        如果返回值为普通变量不可以当左值。

普通引用有自己的存储空间吗?

        1)引用在C++中的内部实现是一个常指针

               Type& name <===> Type* const name

        2)C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占 用的空间大小与指针相同

        3)从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。

这是C++为了实用性而做出的细节隐藏。

从右向左看,&或*哪个离变量近, 哪个便起主要作用。int*&a=p_a; 把int*看成类型

int  b=12;

int  &a=b;

int* p_a=&b;

int* &a=p_a;

const引用

const 引用有较多使用。它可以防止对象的值被随意修改。因而具有一 些特性。

(1)const 对象的引用必须是 const 的,将普通引用绑定到 const 对象是不 合法的。这个原因比较简单。既然对象是 const 的,表示不能被修改,引用当然 也不 能修改,必须使用 const 引用。实际上,

           const int a=1;

           int &b=a;

这种写法是不合法 的,编译不过。

(2)const 引用可使用相关类型的对象(常量,非同类型的变量或表达式)初 始化。这个是 const 引用与普通引用最大的区别。

          const int &a=2; 是合法的。

          double x=3.14;

          const int &b=a;

也是合法的。

//int &m = 41; //error , 普通引⽤ 引⽤⼀个字⾯量 请问字⾯量有没有内存地址

const int &m = 43; //c++编译器 会 分配内存空间

// int temp = 43

// const int &m = temp;

#include	<iostream>
using namespace	std;	
int	main(void)	
{	
//1>	⽤变量 初始化 常引⽤
int	x1	=	30;	
const int &y1=x1;	//⽤x1变量去初始化 常引⽤
//2>⽤字⾯量 初始化 常量引⽤
const int a	= 40;		//c++编译器把a放在符号表中
//int &m = 41;	//error	,	普通引⽤ 引⽤⼀个字⾯量 请问字⾯量有没有内存地址
26
const int &m = 43;		//c++编译器 会 分配内存空间
//	int	temp = 43
//	const int &m = temp;
return 0;	
}

 

const引用的原理

const 引用的目的是,禁止通过修改引用值来改变被引用的对象

结论:

1)const int & e 相当于 const int * const e

2)普通引用 相当于 int *const e

3)当使用常量(字面量)对const引用进行初始化时,C++编译器会为常量值

分配空间,并将引用名作为这段空间的别名

4)使用字面量对const引用初始化后,将生成一个只读变量

 

 

内存四区:

1引用的基本语法:

#if 1
#include<iostream>
using namespace std;
//1 引用没有定义, 是一种关系型声明。声明它和原有某一变量(实体)的关
//系。故 而类型与原类型保持一致, 且不分配内存。与被引用的变量有相同的地
//址。
//2 声明的时候必须初始化, 一经声明, 不可变更。
//3 可对引用, 再次引用。多次引用的结果, 是某一变量具有多个别名。
//4 & 符号前有数据类型时, 是引用。其它皆为取地址。
void test01() {
	int a = 10;
	int &b = a;
	cout << a << endl;  //10
	b = 20;
	cout << a << endl;   //20
	cout << b << endl;   //20

	a = 30;
	{
		int *p = &a; 
		*p = 12;
		cout << *p << endl; //12
		cout << a << endl;  //12
	}
	cout << a << endl;   //12
	cout << b << endl;   //12
	

}
void test02() {
	int a = 10;
	int *p = &a;
	*p = 12;
	cout << *p << endl; //12
	cout << a << endl;  //12
}

void test03() {
	const int a = 10;
	int *p = (int *)&a;
	*p = 12;
	cout << *p << endl; //12
	cout << a << endl;  //10
}

void test04() {
	int a = 10;
	int &b = a;

	int *p = &a;
	*p = 30;

	p = &b;
	*p = 20;

	int &re = a;
	re = 50;
	cout << a << endl;  //50
	cout << b << endl;  //50
	cout << re << endl;  //50
	int ff = 10;
	re = ff;
	cout << a << endl;  //10
	cout << b << endl;  //10
	cout << re << endl;  //10

}

void test05() {
	int	a=1, b=0;
	int	&r = a;
	r = b;	//错误,不可更改原有的引⽤关系
	//float &rr = b;	//错误,引⽤类型不匹配	cout<<&a<<&r<<endl;	//变量与引⽤具有相>同的地址。
	int	&ra = r;	//可对引⽤更次引⽤,表⽰	a	变量有两个别名,分别是	r	和	ra
}
void test06() {
	int a = 10;
	int &b = a;
	int c = 20;
	b = c;
	b = 50;
	cout << a << endl;  //50
	cout << b << endl;  //50
	cout << c << endl;  //20  b并不是c的引用

}

void test07() {
	int a = 10;
	int &b = a;
	b = 100;
	cout << a << endl;  //100
	cout << b << endl;  //100
	int c = 20;
	b = c;
	b = 200;
	cout << a << endl;  //200
	cout << b << endl;  //200
	cout << c << endl;  //20 c的值未更改 b并不是c的别名
}
int& test08() {
	int a;
	return a;   //返回的是a的别名,函数调用完释放a,那么a的引用将不知道指向何处,所以test08()值会乱码
}
int& test09() {
	int a=0;
	return a;   //返回的是a的别名,函数调用完释放a,那么a的引用将不知道指向何处,所以test08()值会乱码
	const int &a1 = 100;
}
int main() {
	//test01();
	//test02();
	//test03();
	//test04();
	//test05();
	//test06();
	//test07();
	int a = 100;
	test08() = a;//test08() = a  //修改局部变量的值 错误
	cout << test08() << endl; //-858993460
	cout << test09() << endl; //0   //不懂
	int a1= 100;
	test09() = a1;
	cout << test09() << endl; //0
	cout << a1 << endl;    //100
	return 0;
}
#endif

 2引用当函数参数

#if 1
#include<iostream>
using namespace std;
void change_value1(int c) { //int c=a; c是局部变量需要复制 重新开辟栈空间
	c = 100;
}
void change_value2(int *c) {//int *c=a; 指针c存放a的地址。改变*c就是改变a的值
	                         //不需要额外复制
	*c = 200;
}
void change_value3(int &c) { //int &c=a; 形参c是实参a的引用,不需要额外复制
	c = 300;
}

void test01() {
	int a = 0;
	change_value1(a);
	cout << "change_value1:" << a << endl;  //0
	a = 0;
	change_value2(&a);
	cout << "change_value2:" << a << endl;  //200
	a = 0;
	change_value3(a);
	cout << "change_value3:" << a << endl;  //300
}

struct student {
	int id;
	char name[64];
};
void PrintStudent1(student s) {   //不建议使用 值拷贝
	cout << s.id << "  " << s.name << endl;
}
void PrintStudent2(student *s) {
	cout << s->id << "  " << s->name << endl;
}
void PrintStudent3(student &s) {
	cout << s.id << "  " << s.name << endl;
}
void test02() {
	student s1 = { 10,"sdsd" };
	PrintStudent1(s1);  //不建议使用
	PrintStudent2(&s1);
	PrintStudent3(s1); 
}
int main() {
	//test01();
	test02();
	return 0;
}
#endif

3引用的本质

#if 1
#include<iostream>
using namespace std;

//当研究引用时,可以将引用当做一个常指针研究
//当使用引用编程时,就把引用理解为变量的别名就OK了
struct typeA {
	int &a;
};
struct typeB {
	int *a;
};
//引用的所占用的大小 跟指针相等
void test01() {
	cout << "sizeof(struct typeA):" << sizeof(typeA) << endl;  //4 32位系统
	cout << "sizeof(struct typeB):" << sizeof(typeB) << endl;  //4 32位系统
}
struct student {
	int id;
	char name[64];
};
//引用声明时必须初始化 常量声明时也必须初始化 引用可能是常量
//引用可能是常指针 int * const p;
void modify1(int *const a) {  //int *const a=main::&a; 可以改变a的值但不能改变a指向
	*a = 300;
	//a++;   错误
}
void modify2(int &a) {  //int &a=main::a; 
	                    //当我们将引用作为函数参数传递的时候,编译器会替我们将实参,取地址给引用
	a = 200;            //对一个引用操作 赋值时,编译器替我们隐藏*操作
}
void modifyStudent(int *const a) {  //int *const a 可以改变a的值但不能改变a指向
	*a = 300;
	//a++;   错误
}

void test02() {
	int a = 10;
	int &re = a;
	int *const p = &a;
}
int main(){
	test01();
	return 0;
}
#endif

4常量指针

#if 1
#include<iostream>
using namespace std;
int main() {
	int const a = 0;  //在常量区
	int *const p1 = NULL; //在常量区
	//p1++; ERROR
	*p1 = 30;
	int const *p2 = NULL;  //在常量区
	p2++;
	//*p2 = 40; ERROR
	return 0;
}
#endif

5引用作为函数返回值

#if 1
#include<iostream>
using namespace std;

int getA1() {
	int tempValue = 10;
	return tempValue;
}
void getA2(int *a) {
	*a = 20;
}

int &getA3() {
	int a = 10;
	return a;  //int &temp=a;将temp传到外部 返回的是别名
}
int &getA4() {
	static int a = 10;
	return a;
}
char *getmen(int num) {
	char *p = NULL;
	p = (char *)malloc(num);
	return p;  //值拷贝
}

int getmen2(char **pp, int num) {
	char *p = NULL;
	p = (char *)malloc(num);
	*pp = p;
	return 0;
}


void test01() {
	int a = 0;
	a = getA1();  //将返回值10拷贝给了a。要是有多个结构体会很浪费空间
	char *pp = NULL;
	pp = getmen(10);

	int main_a = 0;
	main_a = getA3();  //main_a=temp; 值拷贝
	cout << main_a << endl;  //10
	cout << main_a << endl;  //10

	//引用作为返回值,不要返回局部变量的引用。否则可能会出错 getA3函数被回收(没有权限访问,之前的变量覆盖)
	//引用如果当函数返回值的话,函数可以当左值
	int &main_a_re = getA3();
	cout << main_a_re << endl; //10
	cout << main_a_re << endl;  //-858993460

	int &main_a_re1 = getA4(); 
	cout << main_a_re1 << endl;  //10
	cout << main_a_re1 << endl;   //10
	cout << main_a_re1 << endl;   //10

	getA4() = 1000;
}

int main() {
	test01();
	return 0;
}
#endif

6引用指针

#if 1
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

struct teacher {
	int id;
	char name[64];
};
int get_mem(struct teacher** tpp) {
	teacher *tp = NULL;
	tp = (teacher*)malloc(sizeof(teacher));
	if (tp == NULL) {
		return 0;
	}
	tp->id = 100;
	strcpy(tp->name, "li4");
	*tpp = tp;
	return 0;
}
void Free_teacher(struct teacher **tpp) {
	if (tpp == NULL) {
		return;
	}
	struct teacher *tp = *tpp;
	if (tp != NULL) {
		free(tp);
		*tpp = NULL;
	}
}
void test01() {
	struct teacher *tp = NULL;
	get_mem(&tp);
	cout << tp->id << " " << tp->name << endl;
	Free_teacher(&tp);

}
int get_mem2(struct teacher * &tp) { //struct teacher *为整体相当于int
	tp = (struct teacher *)malloc(sizeof(struct teacher));
	if (tp == NULL) {
		return -1;
	}
	tp->id = 1000;
	strcpy(tp->name, "wangwu");
	return 0;

}
void Free_teacher2(struct teacher * &tp) {
	if (tp != NULL) {
		free(tp);
		tp = NULL;
	}

}
void test02() {
	struct teacher *tp = NULL;
	get_mem2(tp);
	cout << tp->id << " " << tp->name << endl;
	Free_teacher2(tp);
}
int main() {
	test01();
	test02();
	return 0;
}
#endif

7const引用

#if 1
#include<iostream>
using namespace std;
void test01() {
	//如果对一个常量进行引用,则必须是一个const引用
	//相反 如果一个普通变量,用一个const引用是可以的
	const int a = 10; //安全性较高
					  //int &b = a;  //错误 将 "int &" 类型的引用绑定到 "const int" 类型的初始值设定项时,
					  //限定符被丢弃	03C++对C的拓展
	const int &re = a;

	int b = 20;  //安全性较低
	const int &re2 = b;
	// ret2 = 200; 错误
	b = 30;
	cout << b << endl;    //30
	cout << re2 << endl;  //30 const引用的目的是,禁止通过修改引用值来改变被引用的对象。
						  //但可以通过改变被引用的对象改变引用值

}

void test02() {
	//int &ref = 10; //错误 引用了不合法的内存 不可以
	const int &ref = 10; //加入const后,编译器处理方式为:int tmp=10;const int &ref=tmp;对临时变量的引用
	//ref =10;  //错误
	int *p = (int*)&ref;
	*p = 1000;
	cout << ref << endl;  //1000
}

//引用使用场景:通常用来修饰形参
void showValue(int &val) {
	val += 1000;  //如果只是想显示内容 而不进行修改就使用const进行修饰
	cout << "value:" << val << endl;
}

void showValue(const int &val) {
	//val += 1000;  //编译错误
	cout << "value:" << val << endl;
}

void test03() {
	int a = 10;
	showValue(a);  //1010
}
int main() {
	test01();
	cout << "--------" << endl;
	test02();
	cout << "------------" << endl;
	test03();
	return 0;
}
#endif

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chde2Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值