1.引用的基础:为某一变量的同一地址取一个别名。
#include<iostream>
using namespace std;
int main()
{
int a = 0;
int &b = a;
printf("b:%d\n", b);
b = 100;
printf("a:%d\n", a);
a = 200;
printf("b:%d\n", b);
//a就是b,b就是a;
return 0;
}
2.引用是C++ 的概念范畴:
当出现引用的语法时,请不要再用C语言的语法思想来思考;
3.引用作为函数参数:
e.g.要实现a和b两个数值的交换:
若采用以下代码:
#include<stdio.h>
void myswamp(int a,int b) {
int c;
c = a;
a = b;
b = c;
}
int main()
{
int x,y;
x = 10;
y = 20;
myswamp(x, y);
printf("x:%d,\ny:%d\n", x, y);
return 0;
}
则无法实现交换功能;
在C语言中,以指针作为函数参数时,可以实现交换:
#include<stdio.h>
int myswamp(int *a, int *b) {
int c;
c =*a;
*a = *b;
*b = c;
return 0;
}
int main()
{
int x, y;
x = 10;
y = 20;
myswamp(&x, &y);
printf("x:%d,\ny:%d\n", x, y);
return 0;
}
上述代码则可以实现数值交换。
也可以在C++中以引用作为函数参数实现上述功能:
#include<iostream>
using namespace std;
void myswamp(int &a, int &b) {
int c;
c = a;
a = b;
b = c;
}
int main()
{
int x, y;
x = 10;
y = 20;
myswamp(x, y);//把实参x赋给形参a,y和b也一样;相当于a和b分别是x和y的引用
printf("x:%d,\ny:%d\n", x, y);
return 0;
}
//***********************************************************************************************************************************************
复杂数据类型做函数参数引用:
#include<iostream>
using namespace std;
struct Teacher {
char name[64];
int age;
};
void printfT1(Teacher *pT) {
cout << pT->age << endl;
}
void printfT2(Teacher &pT) {
cout << pT.age << endl;
}
void printfT3(Teacher pT) {
cout << pT.age << endl;
}
//对比三个函数的不同;
int main()
{
Teacher T1;
T1.age = 35;
printfT1(&T1);
printfT2(T1);//pT是T1的别名;
printfT3(T1);//pT是形参,T1拷贝一份给pT;---->pT=T1;
return 0;
}
思考引用的意义:
引用的意义:
1)引用作为其它变量的别名而存在,因此在一些场合可以代替指针
2)引用相对于指针来说具有更好的可读性和实用性
//*****************************************************************************************************************************************************
引用本质的思考:
C++编译器在背后做了哪些工作??
#include<iostream>
using namespace std;
int main()
{
const int c1 = 10;
int a = 0;
int &b = a;//引用和const一样,都需要在定义的时候初始化,这一点引用和const很像;
printf("&a:%d\n", &a);
printf("&b:%d\n", &b);//引用变量的地址和原变量的地址一样,引用就是为这个内存地址起了个别名;
return 0;
}
思考2:
引用在定义时是否占据了内存空间??
#include<iostream>
using namespace std;
struct Teacher {
char name[64];
int age;
int &a; //很像指针所占的内存空间的大小----4个字节----指针就是4个字节,和类型没有关系;
int &b;
};
int main()
{
printf("sizeof(Teacher):%d", sizeof(Teacher));//76=64+4+4+4;---所以占空间
return 0;
}
综上所述:
可以知道引用的本质就是:
1)引用在C++中的内部实现是一个常指针
Type& name Type* const name
2)C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。
3)从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏
有如下:
void modifyA(int &a) {
a = 100;
}
void modifyA(int *const a) {
*a = 10; //*实参的地址去间接的修改实参的值;
}
调用这个函数时编译器的实际操作;
如果形参是指针,则需要程序员手动的取实参的地址;
modifyA(*a);
所以:
#include<iostream>
using namespace std;
int main()
{
int a = 10;
modifyA(a);//在执行这个函数操作时,程序员不需要再手动取地址;
return 0;
}
联想间接赋值:
/*
请仔细对比间接赋值成立的三个条件
1定义两个变量 (一个实参一个形参)
2建立关联 实参取地址传给形参
3*p形参去间接的修改实参的值
请问:引用赋值的使用场景,是这三个条件哪几个条件的组合?
*/
#include<iostream>
using namespace std;
void modifyA0(int *p) {
*p = 200;//3.(第三个条件)
}
int main()
{
int a = 10;
int *p = NULL; //间接赋值成立的三个条件:1.定义两个变量。
p = &a;
modifyA0(&a);//2.联立关联。
return 0;
}
回答:
引用结论
1)引用在实现上,只不过是把:间接赋值成立的三个条件的后两步和二为一
//当实参传给形参引用的时候,只不过是c++编译器帮我们程序员手工取了一个实参地址,传给了形参引用(常量指针)
引用的使用注意::::
2)当我们使用引用语法的时,我们不去关心编译器引用是怎么做的
当我们分析奇怪的语法现象的时,我们才去考虑c++编译器是怎么做的
/./****************************************************************************************************************************************************
引用的难点:
//当函数的返回值是引用时:
#include<iostream>
using namespace std;
int getAA1() {
int a;
a = 10;
return a;
}
//返回引用;
//返回的是a的本身
int& getAA2() {
int a;
a = 10;
return a;//a 是局部变量
}
//返回指针;
int* getAA3() {
int a = 10;
return &a;
}
int main()
{
int a1 = getAA1();
int a2 = getAA2();
int &a3 = getAA2();//用两个方法接受引用;----存在bug
printf("a1:%d,a2:%d,a3:%d\n", a1, a2, a3);
return 0;
}
//当函数作为左值时:
#include<iostream>
using namespace std;
//g1是返回变量的值,是一个数
int g1() {
static int a = 10;
a++;
return a;
}
//返回变量本身,返回变量的内存空间
int& g2() {
static int a = 10;
a++;
printf("a=%d", a);
return a;
}
int main()
{
//g1() = 100; //g1()--->相当于是数字11,数字11不能当左值;
g2() = 100; //相当于--->a=100;----->函数返回值当左值
g2();
return 0;
}
//主要看变量的内存空间时全局变量;
有结论:
/*
C++引用使用时的难点:
1.当函数返回值为引用时
若返回栈变量(局部变量)
不能成为其它引用的初始值
不能作为左值使用
2.若返回静态变量或全局变量
可以成为其他引用的初始值
即可作为右值使用,也可作为左值使用
C++链式编程中,经常用到引用,运算符重载专题
*/
//****************************************************************************************************************************************************
//指针的引用:
1.)C语言中一级指针作为形参:
#include<stdio.h>
struct Teacher {
char name[64];
int age;
};
//一级指针作为函数形参时的代码
void getTeacher(Teacher *p) {//函数int的意思:在被调用函数里面,获取内存资源;---->二级指针
p->age = 33;
}
int main()
{
Teacher T1;
getTeacher(&T1);
cout <<"age is: "<< T1.age << endl;
return 0;
}
2.C语言中二级指针作为形参:
#include<stdio.h>
int getTeacher(Teacher **p) {
Teacher *temp = NULL;//中间变量,传递值;
if (p == NULL) {
return -1;//返回值在这里
}
temp = (Teacher *)malloc(sizeof(Teacher));
if (temp == NULL) {
return -2;//返回值在这里
}
temp->age = 33;
*p = temp;//p是实参的地址,*是实参的地址,就是间接的修改实参的值
}
int main()
{
Teacher *pT1 = NULL; //这里是结构体指针,所以操作函数形参要用二级指针;
getTeacher(&pT1);
cout << "age : " << pT1 ->age<< endl;
return 0;
}
3.C++中指针的引用:
#include<iostream>
using namespace std;
int getTeacher2(Teacher* &myp) {//是个引用
myp = (Teacher*)malloc(sizeof(Teacher));//给myp赋值,相当于给main中的pt1赋值;
if (myp == NULL) {
return -1;
}
myp->age = 36;
}
void FreeTeacher(Teacher *pt1) {
if (pt1 == NULL)
return;
free(pt1);
}
int main()
{
Teacher *pt1 = NULL;
getTeacher2(pt1);
cout << "age is :" << pt1->age << endl;
FreeTeacher(pt1);//释放指针指向的内部空间;
return 0;
}
//*****************************************************************************************************************************************************
//常引用:
#include<iostream>
using namespace std;
int main()
{
//普通引用:
int a = 10;
int &b = a;
//常引用:
int x = 20;
const int &y = x;//常引用---作用是让比变量引用只读属性---不能通过y去修改x;
//常引用的初始化:
//1.用变量 初始化 常引用:
{
int x1 = 30;
const int &y1 = x1; //用x1变量取初始化常引用;
}
//2.用字面量 初始化 常引用:
{
const int a = 10; //C++编译器把a放在符号表中
//int &m = 41; //普通引用引用一个字面量--请问字面量有没有内存地址?----没有!
//引用:就是给内存取多个别名
const int &m = 43;//加上const之后,就可以引用字面量;
//C++编译器会多给m分配一个内存空间,但是43还是没有内存地址。
}
return 0;
}
//案例:
//常引用的案例:
struct Teacher {
char name[64];
int age;
};
int printTeacher(const Teacher &myp) {
//常引用 让实参变量 拥有只读属性
//myp.age = 36;
printf("myp.age:%d \n", myp.age);
}
结论:
/*
const引用的结论:
1.const& 相当于 const int* const;
2.普通引用 相当于 int* const;
3.当使用常量(字面量)对const引用进行初始化时,C++编译器会为常量分配空间,并将引用名作为这段空间的别名;
4.使用字面量对const引用的初始化,将生成一个只读变量;
*/