🍓引用和指针
2022-5-1
| 2023-8-2
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property

 
引用和指针都是复合类型,复合类型是指基于其他类型定义的类型

引用

C++11新增了右值引用,一般的引用指的是左值引用。引用为对象起了另外一个名字,语法格式:
 
通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量名。不能定义引用类型的引用,但可以定义任何其他类型的引用
一般在初始化变量时,初始值会被拷贝到新建的对象中。然而定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,将无法再令引用重新绑定到另一个对象,因此引用必须初始化
 
定义了一个引用之后,对其进行的所有操作都是在与之绑定的对象上进行的:
为引用赋值, 实际上是把值赋给了与引用绑定的对象;获取引用的值,实际上是获取了与引用绑定的对像的值;同理,以引用作为初始值, 实际上是以与引用绑定的对象作为初始值。
 
引用不是对象,它只是为一个已经存在的对象所起的另外一个名字,所以不能定义引用的引用
声明语句中引用的类型实际上被用于指定它所绑定的对象类型。大部分情况下,引用的类型要和与之绑定的对象严格匹配。引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起:
 
可以在一个类型定义行中定义多个引用,必须在每个引用标识符前添加&符号:
 

指针

与引用类似,指针也实现了对其他对象的间接访问,但指针与引用相比又有很多不同点:
  • 指针本身就是一个对象,允许对指针赋值和拷贝,而且在生命周期内它可以先后指向不同的对象
  • 指针不需要在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值
从根本上看,指针是一个值为内存地址的变量(或数据对象)。正如int类型变量的值是整数,指针变量的值是地址。
 
通过将声明符写成*d 的形式来定义指针类型,其中d是变量名称。如果在一条语句中定义了多个指针变量,则每个量前都必须有符号*
 

获取对象的地址

指针存放某个对象的地址,要想获取对象的地址,需要使用取地址符:
p定义为一个指向int类型的指针,随后初始化p令其指向名为iint对象。因为引用不是对象,没有实际地址,所以不能定义指向引用的指针
声明语句中指针的类型实际上被用于指定它所指向的对象类型。大部分情况下,指针的类型要和它指向的对象严格匹配。
 

利用指针访问对象

如果指针指向一个对象,可以使用解引用(dereference)符 * 来访问该对象:
 
给解引用的结果赋值,就是给指针所指向的对象赋值:
解引用操作仅适用于那些确实指向了某个对象的有效指针。
 
某些符号有多重含义
&及和*这样的符号, 既能用作表达式里的运算符,也能作为声明的一部分出现,符号的上下文决定了符号的意义:
 

指针值

指针的值(即地址)应属于下列状态之一:
  • 指向一个对象
  • 指向紧邻对象所占空间的下一个位置
  • 空指针,即指针没有指向任何对象
    • 空指针不指向任何对象,在试图使用一个指针前代码可以先检查它是否为空。得到空指针最直接的办法是用字面值nullptr来初始化指针:
      旧版本通常使用NULL(预处理变量,定义于头文件cstdlib中,值为0)给指针赋值,但在C++11中,最好使用nullptr初始化空指针。
      int变量直接赋给指针是错误的操作, 即使int变量的值恰好等于0也不行:
      建议初始化所有指针:使用未经初始化的指针是引发运行时错误的一大原因。如果不清楚指针应指向何处, 就把它初始化为nullptr或者0。
  • 无效指针,即上述情况之外的其他值
试图拷贝或以其他方式访问无效指针的值都会引发错误。编译器并不负责检查此类错误,这一点和试图使用未经初始化的变量是一样的,访问无效指针的后果无法预计,因此需要清楚指针是否有效。
 

赋值和指针

指针和引用都能提供对其他对象的间接访问,然而在具体实现细节上二者有很大不同:
  • 引用本身并非一个对象。一旦定义了引用,就无法令其再绑定到另外的对象,之后每次使用这个引用都是访问它最初绑定的那个对象
  • 指针和它存放的地址之间就没有这种限制了。和其他任何变量(只要不是引用) 一样,给指针赋值就是令它存放一个新的地址,从而指向一个新的对象。
 
赋值永远改变的是等号左侧的对象:
 

指针与判断

有效的指针值可以用于条件判断,空指针被判断为false,任何其它值被判断为true 。给定两个相同类型的有效指针,如果它们指向同一个地址,那么它们就被认为是相同的,==将返回true。两个同时为空指针的指针也被认为是相同的。由于条件判断或者比较操作用到了指针的值,因而,无效指针将导致以上行为未定义。
 

void*指针

void*是一种特殊的指针类型,可以存放任意对象的地址,但不能直接操作void*指针所指的对象:
void* 指针只能做几种操作:与其它指针比较、传递给函数或者从函数中返回,赋值给其它的 void* 指针。
void* 指针不能解引用,因而也不能对操作其指向的对象,因为不知道对象的类型,也不知道对象拥有的操作。要对指向的对象进行操作,必须将指针的类型进行强转。
void* 指针的作用在于引用一块内存,而不是使用指针来访问指向的对象。
 
 

复合类型的声明

变量包括一个基本数据类型(base type)和一组声明符
当在一个声明语句中声明多个变量时,每个声明符都说明它对应的变量与基础类型的关系,这与别的声明符是独立的,因而,一个声明语句中可以定义多个不同类型的变量:
 
类型修饰只修饰自己,不是这条语句中所有变量。
 

指向指针的指针

C++对于声明符中修饰符的个数并没有限制。以指针为例, 指针是内存中的对象, 像其他对象一样也有自己的地址, 因此允许把指针的地址再存放到另一个指针当中。
使用**表示指针的指针,***表示指针的指针的指针:
notion image
 

指向指针的引用

引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用:
离变量名最近的符号(此例中是&r的符号&)对变量的类型有最直接的影响,因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么,此例中的符号*说明r引用的是一个指针。最后,声明的基本数据类型部分出 r引用的是一个 int指针。
  • C++
  • 变量const限定符
    目录