定义:
指针是一个变量,它储存着另一个的变量的地址(在计算机中储存的位置)。
符号:
-
&:一元运算符,后面紧跟一个变量名,会返回该变量的地址。
-
*:一元运算符,后面紧跟一个(指针中保存的)地址,会返回该地址指向的值。
-
->:指针成员访问修饰符,当一个指向类/结构体的指针需要访问所指向对象的成员时,需要使用该符号,其中:
class Myclass{
private:
int a;
...
};
Myclass ptr;
ptr->a
相当于:
(*ptr).a
多重指针 --- 指向指针的指针:
我们知道,指针也是一个数据,因此,它也会有自己对应的地址,那么,我们就可以定义另一个指针b,让该指针指向(指向x的)指针a:
int x=12345;
int* a = &x; //定义指针a指向x
int** b = &a; //定义指针b指向a
此时,如果我们想通过b访问x:
std::cout << x << endl
<< *a << endl
<< **b << endl;
结果:
12345
12345
12345
这对于初学者可能有些费解,我们不妨这么想,将int*看作另一种数据类型:
#typedef int * INTPTR
int x=12345;
INTPTR a = &x;
INTPTR* b = &a;
这样就容易理解了。
以此,我们实际上可以无限套娃下去(然而没有什么实际的用途):
int floor_=1234567890;
int* ptr1 = &floor_;
int** ptr2 = &ptr1;
int*** ptr3 = &ptr2;
int**** ptr4 = &ptr3;
int***** ptr5 = &ptr4;
int****** ptr6 = &ptr5;
int******* ptr7 = &ptr6;
int******** ptr8 = &ptr7;
int********* ptr9 = &ptr8;
int********** ptr10 = &ptr9;
std::cout<< floor_ << endl
<< *ptr1 << endl
<< **ptr2 << endl
<< ***ptr3 << endl
<< ****ptr4 << endl
<< *****ptr5 << endl
<< ******ptr6 << endl
<< *******ptr7 << endl
<< ********ptr8 << endl
<< *********ptr9 << endl
<< **********ptr10 << endl ;
(结果就不用写了吧)
NULL指针:
- 在VS中,输入NULL,我们可以看到弹出的关于宏NULL的定义:
#define NULL 0
所以,NULL的实际值就是0
- 使用:在声明一个指针时,我们可能暂时不知道将它赋予何值,那么就可以这么做:
int* a=NULL;
- 意义:在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
- 检查:我们可以使用if()判断一个指针是否为空指针:
int* ptr=NULL; try{ if(!ptr){throw"The ptr is NULL!";} }catch(const char* err){ std::cerr<<err; } /* 运行结果: The ptr is NULL! */
- 帮助:如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以防止误用一个未初始化的指针。很多时候,未初始化的变量存有一些垃圾值,导致程序难以调试。
- 关于nullptr:C++11中引入了nullptr标识符。它与NULL有什么不同呢?再次查看NULL的定义:
#define NULL 0
我们可以知道,NULL是一个int类型的值。看一看C语言中关于NULL的定义:
#define NULL ((void*)0)
在这里,NULL是一个指向void的指针。问题来了,我们一向知道,C++是兼容C的,那么为甚么关于NULL的定义却不同呢?实际上,这与C++的重载机制(关于重载,可查阅重载运算符与重载函数)相关。看下面这段代码:
void f(int){...} void f(char*){...} f(NULL);
如果C++让NULL也支持void *的隐式类型转换,这样编译器就不知道应该调用哪一个函数。因此,C++将NULL定义成了(int)0,解决了函数重载的匹配问题,但却引入了另一个问题,还是这段代码:
void f(int){...} void f(char*){...} f(NULL);//将调用f(int)
由于NULL是(int)0,程序会调用f(int),但从程序员的角度,NULL表示空指针,应调用f(char*)。这就是为什么要引入nullptr关键字。
-
nullptr的使用:nullptr关键字用于标识空指针,是std::nullptr_t类型的(constexpr)变量。它可以转换成任何指针类型和bool布尔类型(主要是为了兼容普通指针可以作为条件判断语句的写法),但是不能被转换为整数。
char *p1 = nullptr; // 正确 int *p2 = nullptr; // 正确 bool b = nullptr; // 正确. if(b)判断为false