zl程序教程

您现在的位置是:首页 >  其它

当前栏目

引用的理解

理解 引用
2023-09-27 14:25:49 时间

目录

1 引用的基本概念

2 引用作为函数参数的意义

3 引用的意义和本质

4 引用作为函数返回值

5 指针的引用

const引用


1 引用的基本概念

 

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;



/*
1 引用没有定义,是一种关系型声明。声明它和原有某一变量(实体)的关
系。故 而类型与原类型保持一致,且不分配内存。与被引用的变量有相同的地
址。
2 声明的时候必须初始化,一经声明,不可变更。
3 可对引用,再次引用。多次引用的结果,是某一变量具有多个别名。
4 &符号前有数据类型时,是引用。其它皆为取地址。
*/

int printA(int &a) //引用作为函数参数的时候不需要初始化, 因为形参一定会被赋值的。
{
	cout << "a = " << a << endl;

	return 0;
}

int main(void)
{
	int a = 10;  //在内存上开辟4个字节, a就代表这个4个字节内存

	int *p = &a;  //让一个指针 指向这个4个字节的空间

	*p = 20;

	cout << "a = " << a << endl;

	//c++提供了另一种对 变量的间接操作的方式, 就是使用引用
	int & b = a; //定义一个引用b 指向a, b此时就是变量的a的别名
	//double &c = a;
	b = 40;

	cout << "a = " << &a << endl;
	cout << "b = " << b << endl;


	cout << "&a = " << &a << endl;
	cout << "&b =" << &b << endl;

	//int & c; //只是单纯定义一个引用, 不初始化,   引用一定要初始化


	int &bb = b; //对b引用再次 引用, 实际上是b的别名

	cout << "bb = " << bb << endl;
	cout << "&bb =" << &bb << endl;

	return 0;
}

 

2 引用作为函数参数的意义

 

 

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;

struct Teacher
{
	int id;
	char name[64];
};

void printT(Teacher t) //局部临时变量,  会发生值拷贝
{
	cout << "id = " << t.id << endl;
	cout << "name = " << t.name << endl;
	t.id = 100;
}

void printT2(Teacher *t) 
{
	cout << "id = " << t->id << endl;
	cout << "name = " << t->name << endl;
	t->id = 100;
}

void printT3(Teacher &t)//Teacher & t = t1;  t 就是t1的一个别名 

//在理解引用的时候,  就当变量的别名来理解。
{
	cout << "id = " << t.id << endl;
	cout << "name = " << t.name << endl;
	t.id = 1000;
}


//交换不成功
void my_swap01(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
}

void my_swap02(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

void my_swap03(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}

int main(void)
{
	Teacher t1 = {1, "zhang3"};

	printT(t1);

	cout << t1.id << endl;

	printT2(&t1);

	cout << t1.id << endl;


	printT3(t1); 
	cout << t1.id << endl;


	int a = 10;
	int b = 20;

	my_swap01(a, b);
	cout << "a = " << a << ", b = " << b << endl;

	my_swap02(&a, &b);
	cout << "a = " << a << ", b = " << b << endl;

	my_swap03(a, b);
	cout << "a = " << a << ", b = " << b << endl;


	return 0;
}

 

3 引用的意义和本质

 

能给同一块内存空间起不同的别名,a 和b 都是同一块内存空间的门牌号。

 

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;


struct TypeA
{
	int *a;
};

struct TypeB
{
	double &a;
};

struct Teacher
{
	int id;
	char name[64];
};


void motifyTeacher(Teacher &t) //
{
	t.id = 100; // 如果说t是一个常指针, *t 就是指针指向内存空间  (*t).id = 100
	//当你要试图修改或者获取已经初始化的引用的时候, 编译器会有一个隐藏的*的操作
}

void motifyA(int *const a)   //常指针 也是一个常量, 也是必须要初始化,  也不能被修改
{
	*a = 100;
}

void motifyB(int &a)
{
	a = 1000; //a 实际上是一个常量指针, 但是如果你给一个a赋值,编译器会有一个隐形的操作, *
}

//在研究引用的时候 ,可以将引用理解为 一个 常指针
//在理解引用的时候, 可以将引用理解为 一个变量的别名

void test()
{
	int value = 20;
	Teacher t1 = { 1, "zhangsan" };

	motifyA(&value);

	cout << "value = " << value << endl;

	motifyB(value);  // int value --> int &a  , int& a = value 给引用指定指向哪个变量的时候, 编译器提供又有了一个隐形的操作
						// a = &value;

	cout << "value = " << value << endl;

	motifyTeacher(t1);  //如果说 motifyTeacher 的形参是一个常指针,Teacher *const t = &t1;
								//编译器发现 Teacher &t 形参是一个引用, Teacher &t = &t1;
								//当给引用初始化的时候, 会有一个&  的隐形操作
}


void motifyAA(int *a)
{
	*a = 100;   //间接的赋值
}

void motifyBB(int &a) //int &a = a;    a = &a;
{
	a = 200; //*a = 200
}

void test2()
{
	int a = 10; //条件一


	motifyAA(&a); //int*a = &a; //建立了关联

	motifyBB(a);
}


int main(void)
{
	int a = 10;
	int b = 20;

	const int c_a = 10;

	//c_a = 20;//常量在初始化之后,不能够再修改了

	int &re = a; //引用必须初始化.  引用在初始化之后,也不能够被改变
	re = b; // a = b 而不是 让re引用指向b

	cout << "re = " << re << endl;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	re = 100; //是该的a 还是b?

	cout << "re = " << re << endl;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	//1 引用 可能是一个 常量?

	cout << "sizeof(TypeA): " << sizeof(TypeA) << endl;
	cout << "sizeof(TypeB):" << sizeof(TypeB) << endl;

	//通过对引用求大小, 发现不管引用是什么类型 都是4个字节,都跟指针的大小一样。

	//2 引用可能是一个 指针?


	test();
	
	return 0;
}

4 引用作为函数返回值

值的返回放在了寄存器

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;

int getA1()
{
	int a = 10;
	return a;
} //value_a = a; 

int &getA2()
{
	int a = 10;
	return a;
} //匿名的引用 int & = a;  //  int &temp = &a;

int &getBB()
{
	static int b = 100;
	return b;
}

int main(void)
{
	int value_a = 0;

	value_a = getA1();   //正确

	cout << "value_a " << value_a << endl;


	value_a = getA2();// int value_a = temp;   // int value_a = *temp; //这是一个值拷贝
	cout << "value_a " << value_a << endl;
	cout << "value_a " << value_a << endl;


	int &r_a = getA2(); //没有值拷贝动作  ,禁止
	//当函数返回值,是一个局部变量的引用的时候,不能再用引用来接收。
	cout << "r_a  " << r_a << endl;
	cout << "r_a  " << r_a << endl;


	int &r_b = getBB(); //此时的r_b 就是 getBB中的 static int b
	//当函数返回值,不是子函数内部局部变量,就可以用引用进行接收,
	cout << "r_b " << r_b << endl;
	cout << "r_b " << r_b << endl;

	r_b = 2000; //此时r_b 就是getBB中的b的别名, 修改r_b 就是修改 b

	int value_b = getBB();  // 会有一个临时的引用 int &temp = b;  value_b = *temp; //发生了值拷贝
	//getBB();//getBB 就是b的别名
	//int value_b = *(getBB());
	//int value_b = static b;
	cout << "value_b " << value_b << endl;

	getBB() = 3000; //static b  = 3000; //当引用作为函数的返回值的时候,只要这个引用是合法的,就可以当左值。


	//三目运算符
	int a = 10;
	int b = 20;

	(a < b ? a : b) = 30;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	return 0;
}

5 指针的引用

 

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;


struct Teacher
{
	int id;
	char name[64];
};

int getTeacher(Teacher **pp)
{
	Teacher *p = NULL;

	p = (Teacher *)malloc(sizeof(Teacher));
	if (p == NULL)
	{
		cout << "error" << endl;
		return -1;
	}
	memset(p, 0, sizeof(Teacher));
	p->id = 30;
	strcpy(p->name, "zhang3");

	*pp = p;

	return 0;
}

int getTeacher02(Teacher* &tr) //tr 就是main中的tp 
{
	tr = (Teacher*)malloc(sizeof(Teacher));
	if (tr == NULL) {
		cout << "error" << endl;
		return -1;
	}

	tr->id = 40;
	strcpy(tr->name, "li4");

	return 0;
}

void freeTeacher02(Teacher * &tr)
{
	if (tr != NULL) {
		free(tr);
		tr = NULL;
	}
}

void freeTeacher(Teacher **pp)
{
	if (pp == NULL) {
		return;
	}
	Teacher *p = *pp;

	if (p != NULL) {
		free(p);
		*pp = NULL;
	}
}

int main(void)
{
	Teacher *tp = NULL;

	//getTeacher(&tp);
	getTeacher02(tp);

	cout << tp->id << ",  " << tp->name << endl;

	//freeTeacher(&tp);
	freeTeacher02(tp);

 
	
	return 0;
}

 

const引用

 

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;

//const引用一般用在形参上,来限制  被引用的变量不能被修改,
void printX(const int & re )
{
	cout << "re " << re << endl;
}

int main(void)
{
	const int a = 10; // a必须初始化
	//int & b = a;
	const int &b = a;

	//如果是一个const 常量, 必须用const 引用来接收它
	int x = 3.14;
	const int &re1 = x;


	cout << "re1 " << re1 << endl;
	x = 20;
	cout << "re1 " << re1 << ", x: " << x << endl;


	const int &re2 = 10;// 用const 引用 引用一个字面量
									// 当用一个const 引用  去引用一个字面量的时候, 字面量他是没有地址,
									//引用是无法 对字面量取地址的, 临时创建一个 int temp, 10 --->temp
									//const int &re2 = temp;
									//用re2 就是代表 temp,re2是const的引用,你无法去改变temp的值
	//int &re2 = 10;         //非常量引用 必须是左值。 左值就是可以放在=左边的表达式,左值是可以赋值,是有内存空间的
									//如果想对一个字面量做引用的话,只能用 const 的引用

	cout << "re2 = " << re2 << endl;

	cout << "sizeof(re2)" << sizeof(re2) << endl;

	return 0;
}

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