C++引用与指针

本文最后更新于:2020年4月13日 晚上

引用与指针

引用

大部分时候,当我们使用引用时,使用的是左值引用,lvalue reference,C++11 中新增了一种引用,右值引用,rvalue reference ,主要用于内置类。

引用是为对象起了另外一个名字,引用类型 引用 另外一种类型。通过将声明符写成&d的形式来定义引用类型。

1
2
3
int ival = 1024;
int &refVal = ival; //refVal 指向ival,实际上refVal就是ival的另一个名字
int &refVal2; // error,引用必须被初始化!

一般在初始化的时候,初始值会被拷贝到新建的对象之中。

然而在定义引用中,程序是把引用和它的初始值**绑定(bind)**在一起,而非拷贝。

一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另外一个对象,因此引用必须初始化。

此外:因为引用本身不是一个对象,所以不能定义引用的引用

1
2
3
4
5
refVal = 2;				//对引用的操作实际上就是对对象本身的操作。

int &refVal3 = refVal; //将refVal3绑定到了refVal绑定的对象上。

int &refVal4 = 10; //error,引用类型的初始值必须是一个对象

指针

指针是指向另外一种类型的复合类型。

指针的定义

1
2
int *ip1;		//指向Int型对象的指针
double *dp1;

获取对象的地址

指针是存放某个对象的地址,获取对象的地址需要使用取地址符 &

1
2
int ival = 42;
int *p = &ival; //p是指向ival的指针

指针值

指针的值也就是地址,应当属于下列四种状态之一。

  • 指向一个对象
  • 指向紧邻对象所占空间的下一个位置
  • 空指针,即指针没有指向任何一个对象‘
  • 无效指针,除上述情况之外的其他值

试图拷贝或者说是以其他方式访问无效指针的值都将会引发错误,访问无效指针的后果无法预计。

使用指针访问对象

如果指针指向了一个对象,那么可以使用 解引用符 * 来访问对象。

1
2
3
4
5
int ival = 24;
int *p = &ival;

cout << *p;
*p = 0;

’&‘ 和 ‘*’ 的多重含义

1
2
3
4
5
6
int i = 42;
int &r = i; //&紧随类型名出现,是声明的一部分,r是一个引用
int *p; //*紧随类型名出现,是声明的一部分,p是一个指针
p = &i; //&出现在表达式之中,是一个取地址符
*p = i; //*出现在表达式之中,是一个解引用符
int &r2 = *p; //&是声明的一部分,而*是解引用符

空指针

空指针 null pointer,不指向任何对象。

1
2
3
4
5
6
int *p1 = nullptr;		//等价于int *p1 = 0

int *p2 = 0; //直接将p2初始化为字面常量0

//需要先 #include cstdlib
int *p3 = NULL; //等价于int *p3 = 0

得到空指针最直接的办法就是使用字面值nullptr来初始化指针,这是C++11 新标准引入的方法。nullptr是特殊类型的字面值,它可以被转换成任意其他的指针类型。

void* 指针

待续……

指针与引用的异同点

指针和引用类似,实现了对其他对象的间接访问。

指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象。

引用必须在定义时赋值(或者说是绑定),而指针无须在定义时进行赋值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。


demo

1
2
3
char *p1 = "abc";

char p2[] = "abc";

上述两者不同,对p1来说,不能修改p1指向的内存,即它是类似 char const *p1 ,p1是指向文字常量区的指针变量。

p2呢,可以改变数组元素,因为它的实际上是将”abc”拷贝到数组p2之中。

1
2
3
4
5
char p3[100];

p3 = "abc"; //这样是错误的,数组名是一个常量

strcpy(p3,"abc");
1
2
3
4
5
6
7
8
9
10
11
12
13
int a,b,c;

int *p[] = {&a,&b,&c};
// p是指针数组,他是数组,每个元素都是指针 int*,指向int

char a,b,c;
char *p[] = {&a,&b,&c}; //这种不常用

char *p2[] = {"hello","abc","mike"};//这种常用

//p2是指针数组,是数组,每个元素都是指针char *,保存了三个字符串的首元素地址
p2[0] = "hello";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
char *p2[] = {"hello","abc","mike"};

char **p2 = {"hello","abc","mike"}; //err错误
//p2是char**类型,它要指向char *类型

char *tmp;
char **p = &tmp;

char *str[] = {"hello","abc","mike"};
//str首元素是char*类型
//&str[0]代表首元素的地址,str等价于&str[0],类型是char *
char **p3 = str; //等价于char **p3 = &str[0];

//故函数参数:fun(str),定义时 是void fun(char **p)
// 如果char *str[] 作为函数参数,可以改为char **str;

//下面三者等价,编译器都当作char **p处理
void fun(char **p);
void fun(char *p[]);
void fun(char *p[100])