1·引用:
引用(reference)为对象起了另外一个新的名字通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量名:
int ival = 1024;int& refval = ival;int& refval2;//报错:引用必须被初始化
1.1为什么引用必须被初始化?
变量在初始化的过程中,初始值会被拷贝到新建的对象中。
定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用和它的初始对象绑定在一起,无法绑定到另外的一个对象,所以必须初始化
在这里举个例子,比如我们定义一个int 类型的变量并将它初始化为10,那么计算就会在内存当中分配一块内存空间,保存10整个值,给整个内从空间起了一个名字叫a,而b是对a的引用,所以相当与这块内存空间有两个名字,但其实说的是一回事
假设我们不给初始化的时候,那么就不知道它到底指的是哪里
引用并非对象,不分配内存空间,它只是为一个已经存在的对象所起的另外一个名字
通过下面的代码测试我们来看下
我们在这里定义了一个引用之后,对其进行所有的操作都是在与之绑定的对象上进行的
为引用赋值,实际上是 把值赋给了与引用绑定的对象。获取引用的值,实际上是获取了与引用绑定对像的值。
int ival = 1024;int& refval = ival;//int& refval2;//报错:引用必须被初始化//refval = 2;//将2赋值给refval指向的对象,此处即是复赋值给了 ival//正确:refval绑定到了那个与refval的对象上,这里即ivalint& refval3 = refval;//利用绑定的对象来初始化其它变量int i = refval;
1.2引用的定义
允许在一条语句中定义多个引用,其中每个引用标识符都必须以符号&开头
//定义了一个变量i与i2并对其初始化为 1024与2048int i = 1024, i2 = 2048;//定义了 一个引用 并将其与i进行对应的绑定,定义了一个变量r2并将i2的值赋给它 i=1024,r2=2048int& r = i, r2 = i2;//定义了一个变量i3,定义了一个引用绑定i3 ri=1024int i3 = 1024, & ri = i3;//定义了2个引用,分别绑定了i3,和i2 r3=1024,r4=2048int& r3 = i3, & r4 = i2;
1.3引用的注意事项
- 左值引用不能够引用一个常量,必须为一个对象
- 引用的类型必须一致
int & r = 4;//error 引用不能够引用一个常量double x = 3.14;int& m = x;// error 引用的类型必须一致
1.4引用的几个小练习
1·4.1 一下是否合法
int ival = 1.01;//合法定义了一个整形变量,但初始值给了一个浮点型,所以这里会出现数据丢失现象int& rval1 = 1.01;//左值引用不能够引用一个常量int& rval2 = ival;//合法,因为引用了一个对象,且类型一致int& rval3;//错误引用必须进行对应的初始化
1·4·2 以下哪些赋值时不合法的?为什么?哪些时合法的?它们执行了哪些操作
在这里我错了,如果高进度引用低精度是可以的,但低进度赋值和引用高精度是不可以的
int i = 0, & r1 = i;double d = 0, & r2 = d;//合法r2是对d的引用,此时d的值为3.14159r2 = 3.14159;//r2=r1是将r1的值赋值给r2,因为r1是int类型,所以此时会进行强转成double d 和r2=1.00000r2 = r1;//i是一个int 类型,所以在之类 i=3--在这里我错了,如果高进度引用低精度是可以的,但低进度赋值和引用高精度是不可以的i = r2;//r1是一个引用,=d 会造成数据丢失,变成3r1 = d;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-trBtVhCC-1652102162293)(C:/Users/kexib/AppData/Roaming/Typora/typora-user-images/image-20220509113356061.png)]
1·4·2执行下面的代码将会输出什么样的结果
int i, & r1 = i;i = 5; //这句执行完 i=5,r1=5r1 = 10;//这句执完2者都为10;
2·指针
**指针(pointer)**是“指向的另外一种类型的复合类型”
- 指针本身就是一个对象,允许对指针进行赋值和拷贝
- 在生命周期内它可以指向几个不同的对象
- 指针在定义时无需初始化,如果不进行初始化,也将拥有一个随机值
2·1指针的定义
将声明符写成 *d的形式,d为变量名。
*如果在一条语句中定义了多个指针变量,则需要在每个前面都加上 **
我们在这里可以清晰的看到,n,x都是指针类型,m是整形
在定义指针的时候还有一点要注意那就是不能够定义指向引用的指针因为引用时不是对象没有地址,同时左引用也不能引用常量
2·2指针获取对象的地址
指针存放某个对象的地址,想要获取该地址,需要使用取地址符(操作符 &)
2.3.1指针的大小
- 在32位操作系统下,所有的指针都只占4个字节
- 在64位操作系统下,所有的指针都占8个字节
为什么指针的大小会是这样呢?
因为在计算机当中,只有整数寄存器次啊可以存放指针(内存数据的地址)
在32位操作系统当中,地址的大小是32bit,因此其最大寻址空间位2^32,也就位4个字节
在32位操作系统当中,地址的大小是64bit,因此其最大寻址空间位2^64,也就位8个字节
在32位操作系统当中,地址的大小是32bit,因此其最大寻址空间位2^32,也就位4个字节
我们用代码来验证一下
-
在64位操作系统下
2·在32位操作系统下
2.3指针值
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置
- 空指针,意味着没有指向任何对象
- 无效指针,也就时上述情况之外的其他值
2.4利用指针访问对象
如果指针指向了一个对象,则允许他通过 **解引用符(*)**来访问该对象
2.5&与*这样的符号,既能够作用于表达式里的运算符,也能够作为声明的一部分出现,符号的上下文决定了符号的意义
int i = 42;int& r = i;//&紧随类型名出现,因此是声明的一部分,r是一个引用int* p;//*紧随类型名出现,p是一个指针p = &i;//&在表达式中为取地址符*p = i;//* 出现咱表达式中,是一个解引符int& r2 = *p;//&是声明的一部分,*是一个解引符
2.6空指针
空指针(null pointer)不指向任何对象,在试图使用一个指针指针代码首先要检查其是否为空
生成空指针的几种办法
int* p1 = nullptr;//在C11的标准下,使用nullptr来初始化空指针,所以最好使用nullptr来进行初始化int* p2 = 0;//需要首先调用#include <cstdlib>int* p3 = NULL;
//错误不能把int 变量直接赋值给指针int zer0 = 0;int* p1 = zer0;
2.7 赋值和指针
int i = 42;int* pi = 0;//pi被初始化,但没有指向任何对象int* pi2 = &i;//pi2被初始化,存i的地址int* pi3;//定义于内存块中,pi3无法确定pi3 = pi2;//pi3和pi2指向同一个对象pi2 = 0;//不指向任何对象了
赋值永远改变的是等号左侧的对象
pi=&ival;//pi的值被改变,指向了ival;
*pi=0;//ival的值被改变,指针p并没有变
任何非0指针对应的条件都是true
int ival = 1024;int* p = 0;int* p2 = &ival;if(p)//为falseif(p2)//为true
2.8 void * 指针
特殊类型的指针,可以存放任意对象的地址 *但不能够直接操作void 指针指向的对象,因为并不知道所指的对象是什么类型
double obj = 3.14, * pd = &obj;void* pv = &obj;//pv 可以保存任何类型的指针pv = pd;*pv = 5.89;//error 不能够指针操作pv 指向的对象
2.9对应练习题
-
编写代码分别更改指针的值,以及指针所指向对象的值
int i = 0, *p = &i;int x = 10;*p = 5;//将i的值改为5p = &x;//将p指向的地址改为x的地址
-
请叙述下面代码的作用
int i = 42;int* p1 = &i;//p1指向i*p1 = *p1 * *p1;//修改i的指为 42*42
2.下述哪些是非法的?
int i = 0;double* p = &i;//错误int 类型不能够初始化double类型的实体int* pi = i;//int 类型的变量不能够初始化其指针int* p = &i;
3.假设p是一个int 类型的指针,请阐述下面的含义
if(p);//p不为一个空指针则为true
if(*p)//p所指对象的值部位0则为true
4·给定一个指针p,是否知道它指向了一个合法的对象吗?如果能,请说你的思路
如果不是一个void * ,就可以,首先编译器会帮助我们进行判断,并给出提示错误。其次我们可以尝试输出指针所指对象的指。非法时编译器会报错,但如果是一个void 指针,我们没有办法访问内存空间所存的对象,也就无法判断其是否指向了一个合法的对象
5.在下面这段代码中,为什么p合法而lp非法
int i=42;
void *p=&i;
long *lp=&i;
//因为void 指针可以存放任意类型的地址 而long 指针只能存放long 类型的地址
一个int 类型的指针,请阐述下面的含义
if(p);//p不为一个空指针则为true
if(*p)//p所指对象的值部位0则为true
4·给定一个指针p,是否知道它指向了一个合法的对象吗?如果能,请说你的思路
如果不是一个void * ,就可以,首先编译器会帮助我们进行判断,并给出提示错误。其次我们可以尝试输出指针所指对象的指。非法时编译器会报错,但如果是一个void 指针,我们没有办法访问内存空间所存的对象,也就无法判断其是否指向了一个合法的对象
5.在下面这段代码中,为什么p合法而lp非法
int i=42;
void *p=&i;
long *lp=&i;
//因为void 指针可以存放任意类型的地址 而long 指针只能存放long 类型的地址
总结. 说明指针和引用的主要区别
-
指针变量存放某个对象的地址;引用则是对象的别名
-
程序为指针变量分配存储区;引用不会分配内从区域
-
解引用时指针需要加*;而引用不需要
-
指针可以指向不同对象的地址;而引用只能绑定初始化对象的地址,之后无法改变
-
指针变量可以初始化为空;而没有所谓的空引用
-
指针在作为形参的时候需要判断其合法性是否为空;引用不需要
-
对指针sizeof()得到的是指针的大小;对引用则是变量的大小
-
指针的化可以由2级指针,3级指针;而引用没有引用的引用
-
++引用与++指针操作不一样
- 引用操作直接反应到所引用的实体
- 指针++,则指向下一个对象的地址,不更改其所指的内容
-
不可以对函数中的局部变量或对象以引用或指针方式返回
-
如果返回的是指针时,要成为全局变量次啊可以–标识符的实体不受函数的影响
为什么会是这样?
#include<iostream> using namespace std; int * val(int a, int b) {int c = a + b;int* p = &c;return p; } int main() {int* p = val(2,4);return 0; }
-
//当我将C改成全局的时候就不会出现这种情况
int c;
int * val(int a, int b) {c = a + b;int* p = &c;return p;
}
int main() {int* p = val(2,4);return 0;}