指针
(1)指针本身就是个对象,允许对指针赋值和拷贝。生命周期内它可以先后指向几个不同的对象。
(2)指针无需在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
(3)指针存放某个对象的地址。可以使用取地址符 &
来获取地址
(4)如果指针指向了一个对象,可以使用解引用符 *
来访问该对象
(5)void*
可以存放任意对象的地址。但是我们对该地址中到底是个什么类型的对象并不了解。可以拿它和别的指针比较、作为函数的输入输出,或者赋值给另一个void指针。但是不能直接操作void指针所指向的对象,因为我们并不知道这个对象到底是什么类型。
(6)**
表示指向指针的指针。***
表示指向指针的指针的指针,以此类推
(7)指向指针的引用
。引用不是对象,没有实际地址,所以不能定义指向引用的指针。但是指针是对象,因此存在对指针的引用
(8)空指针
:空指针不指向任何对象。得到空指针最直接的办法就是用字面值 nullptr
来初始化指针(c++ 11引入),nullptr 是一种特殊类型的字面值,可以被转换成任意其他的指针类型。
(9)我们之前一直用NULL来给指针赋值。NULL是一个预处理变量
,在 cstdlib
中定义,它的值就是0。预处理器在编译过程之前运行的,预处理变量不属于命名空间std,由预处理器负责管理,因此在使用预处理变量之前不需要加上std::。当遇到一个预处理变量时,预处理器会自动地将它替换为实际值,用NULL和0初始化指针是一样的。
指针简单的定义和使用:
#include <iostream>
#include <cstdlib>
using namespace std;
int main(){
int i = 23;
int *p1 = &i; //p1被初始化,存放i的地址
int *p2; //p2被初始化,没有指向任何对象
p2 = p1; //p2和p1指向同一个对象i
*p2 = 12; //p2所指向的对象被改变了(此处是指针指向的对象被改变了)
p2 = 0; //p2不指向任何对象(此处是指针改变了)
return 0;
}
指向指针的引用:
//指向指针的引用
#include <iostream>
#include <cstdlib>
using namespace std;
int main(){
int i = 1024;
int *p;
int *&r = p; //r是对指针p的引用。此处从右向左解读,&r可以知道r是一个引用,*&r可以知道 r引用的是一个指针
r = &i; //r引用了一个指针,也就是p指向i
*r = 0; //解引用r得到i,也就是将i的值改为0
cout << i << endl;
return 0;
}
指向指针的指针
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
double* (*a)[3][6]; // a 是指向二维指针的数组,数组中存储的元素都是double*
cout << sizeof(a) << endl; // a 是一个指针,所以sizeof(a)的值是4
cout << sizeof(*a) << endl; // *a 表示一个二维数组,元素类型是double*,是一个指针,占用字节数为4。sizeof(*a) = 3 * 6 * 4 = 72
cout << sizeof(**a) << endl; // *a 表示一个二维数组,**a为数组的首元素,即*a[0],*a[0]也是一个数组,长度为6,元素类型为double *,即6 * 4 = 24
cout << sizeof(***a) << endl; // ***a是数组的一个元素,类型为double *,故sizeof(***a) = 4
cout << sizeof(****a) << endl; // ****a 类型为double,故sizeof(****a) = 8
return 0;
}
指向数组的指针
对于一个数组 array[10]
,
array
是数组的名字,&array
获取的是这个数组的地址,而且这个地址的值等于 &array[0]
(首元素的地址)。虽然他们的值相等,但是含义是不一样的: