铺垫:
变量名实质上是一段连续存储空间的别名,是一个标号
程序中通过变量来申请并命名内存空间
通过变量的名字可以使用存储空间
(能不能再名字的基础上在起个名字?)
概念:
1) 可以看做一个已定义变量的别名
引用是c++的语法范畴,不能再用C语言的思想去思考问题(间接修改)
属于c++编译器对c的扩展
引用做函数参数
普通引用在声明时必须用其他的变量进行初始化
引用作为函数参数声明时不进行初始化
#include<IOStream>
using namespace std;
//引用基本用法
void main()
{
int a = 10;
int &b = a;
b = 100;
printf("b:%dn", b);
printf("a:%dn", a);
cout << "hello...." << endl;
system("pause");
return;
}
void main11()
{
int a = 10;
int &b = a;
//int &c; //普通引用必须要初始化
system("pause");
}
void myswap01(int a, int b)
{
int c = 0;
c = a;
a = b;
b = c;
}
void myswap02(int *a,int *b)
{
int c = 0;
c = *a;
*a = *b;
*b = c;
}
void myswap03(int &a, int &b)
{
int c = 0;
c = a;
a = b;
b = c;
}
void main()
{
int x, y;
x = 10;
y = 20;
myswap01(x, y);
printf("x:%d,y:%dn", x, y);
myswap02(&x, &y);
printf("x:%d,y:%dn", x, y);
myswap03(x, y);
printf("x:%d,y:%dn", x, y);
system("pause");
}
//复杂数据类型 的引用
struct Teacher
{
char name[64];
int age;
};
void printfT(Teacher *pT)
{
cout << pT->age << endl;
}
//pT是t1的别名,相当于修改了t1
void printfT2(Teacher &pT)
{
cout << pT.age << endl;
}
//pT和t1是两个不同的变量
void printfT3(Teacher pT)
{
cout << pT.age << endl;
pT.age=45;//只会修改pT变量,不会修改t1变量
}
void main()
{
Teacher t1;
t1.age = 35;
printfT(&t1);
printfT2(t1);//pT是t1的别名
printfT3(t1);//pT是形参,t1拷贝了一份数据,给pT
printf("t1.age:%dn",t1.age);
cout << "hello...." << endl;
system("pause");
return;
}
引用的意义
引用作为其他指针变量的别名而存在,因此在一些场合可以替代指针
引用相对于指针来说具有更好的可读性和实用性
引用的本质
c++编译器背后做了什么工作
单独定义的时候必须初始化--->很像常量
1)引用在c++内部实现是一个常指针
2)c++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占的空间与指针相同
3)从使用的角度,引用会让人误会其只是一个别名,没有自己的储存空间,这是c++为了实用性做出的细节隐藏.
结论:当我们使用引用的语法时,我们不用去关心编译器引用是怎么做了
当我们分析奇怪的语法现象时,才去考虑编译器是怎么做的
#include<iostream>
using namespace std;
void main01()
{
const int c1 = 10;
int a = 10;
int &b = a;//像常量
printf("&a:%dn", &a);
printf("&b:%dn", &b);//a b就是同一块内存空间的门牌号 依附于这个内存空间
cout << "hello.." << endl;
system("pause");
return;
}
//普通引用有自己的空间吗?-->有,和指针所占的一样
struct Teacher
{
char name[64];//64
int age;//4
int &a;//4
int &b;//4
};
//引用的本质一个常量指针
void main()
{
printf("sizeof(Teacher):%dn", sizeof(Teacher);
system("pause");
}
void modifyA(int &a1)
{
a1 = 100;
}
void modifyA2(int* const a1)
{
*a1 = 10;//*实参的地址,去间接修改实参的值
}
void main()
{
int a = 10;
modifyA(a);//指向这个函数调用的时候,我们程序员不需要取a的地址
printf("a:%dn", a);
modifyA2(&a);//如果是指针 需要我们手工去取实参地址
printf("sizeof(Teacher):%dn", sizeof(Teacher));
system("pause");
}
//间接赋值
//间接赋值成立的三个条件
/*
1 定义2个变量
2 建立关系 实参取地址传给形参
3 形参间接修改实参的值
*/
void modifyA3(int *p)
{
*p = 190;//3
}
void main()
{
int a = 10;
int *p = NULL; //1
p = &a;
*p = 100;
{
*p = 200;
}
modifyA3(&a);//2
}
//引用是间接赋值哪几个条件的组合? 2编译器做了
//1 23后2个条件写在一起了 只不过2编译器做了
函数返回值是引用(引用当左值)
c++引用使用时的难点:
当函数返回值为引用时,
若返回栈变量,不能成为其他引用的初始值,不能作为左值使用
若返回静态变量或全局变量 可以成为其他引用的初始值.
即可作为右值使用,也可作为左值使用
#include<iostream>
using namespace std;
int getAA1()
{
int a;
a = 10;
return a;
}
//返回a的本身
int& getAA2()
{
int a;
a = 10;
return a;
}
int* getAA3()
{
int a;
a = 10;
return &a;
}
void main01()
{
int a1 = 0;
int a2 = 0;
a1 = getAA1();
a2 = getAA2();
int &a3= getAA2();
printf("a1:%dn", a1);
printf("a2:%dn", a2);
printf("a3:%dn", a3);
cout << "hello.." << endl;
system("pause");
return;
}
//返回静态/全局
int j()
{
static int a = 10;
a++;
return a;
}
int &j()
{
static int a = 10;
a++;
return a;
}
void main()
{
int a1 = 10;
int a2 = 20;
a1 = j1();
a2 = j2();
int &a3 = j2();
printf("a1:%dn", a1);
printf("a2:%dn", a2);
printf("a3:%dn", a3);
cout << "hello.." << endl;
system("pause");
return;
}
//函数当左值
//返回变量的值
int g()
{
static int a = 10;
a++;
return a;
}
//返回变量本身
int &g()
{
static int a = 10;
a++;
return a;
}
void main()
{
//g1() = 100;//执行这个,函数返回值就是11.不成立err
g2() = 100;//把上面的函数改成了100,所以这个就成立
system("pause");
}
指针的引用
#include<iostream>
using namespace std;
struct Teacher
{
char name[64];
int age;
};
int getTeacher(Teacher **p)
{
Teacher *tmp = NULL;
if (p == NULL)
{
return -1;
}
tmp = (Teacher*)malloc(sizeof(Teacher));
if (tmp == NULL)
{
return -2;
}
p->age = 33;
*p = tmp;
}
//指针的引用做函数参数
int getTeacher2(Teacher* &myp)
{//给myp赋值相当于给主函数中的pT1赋值
myp = (Teacher*)malloc(sizeof(Teacher));
if (myp == NULL)
{
return -1;
}
p->age = 36;
}
void FreeTeacher(Teacher *pT1)
{
if (pT1 == NULL)
{
return;
}
free(pT1);
}
void main()
{
Teacher *pT1 = NULL;
getTeacher(&pT1);//二级指针
cout << "age:" << pT1->age << endl;
FreeTeacher(pT1);
getTeacher2(pT1);//引用
cout << "age:" << pT1->age << endl;
FreeTeacher(pT1);
cout << "hello.." << endl;
system("pause");
return;
}
c++中的const常量
可能分配内存空间,也可能不分配
当const常量为全局,并且需要在其他文件中使用,会分配空间
在使用&操作符,取const常量的地址,会分配
当const修饰引用,会分配
#include<iostream>
using namespace std;
void main()
{
int x = 20;
const int &y = x;//常引用 让变量拥有只读属性 不同通过y去修改x了
//常引用初始化分为2种情况//1)用变量 初始化 常引用
{
int x1 = 30;
const int &y1 = x1;
}
//2)用字面量 初始化 常引用
{
const int a = 40;
int &m = 41;//普通引用 引用一个字面量
//字面量有没有内存地址?-->没有
}
cout << "hello.." << endl;
system("pause");
return;
}
结论:
const &int e==const int* const e
普通引用==int const e
当使用常量对const引用进行初始化时,编译器会为常量值分配空间,并用引用名作为这段空间的别名
使用字面量对const引用初始化后,将生成一个只读变量