指针
string* str1, str2; // str1是指针,str2是string对象
初始化
int ival=0;
const int ival2=0;
int *p1=ival; // error
int *p2=ival2; //ok[早期写法,现代一般不用]
int *p3=nullptr; //ok
指针与引用比较
定义时,引用必须要初始化,指针可以不用。 引用初始化后,不能改变引用对象,指针可以改变指向。
int val1=1, val2=2;
int &r1=val1; // r1是val1的别名
int &r2=val2; // r2是val2的别名
r1=r2; //并不是改变r1的引用对象,而是将r2的值赋给了r1,也就是val1=val2
指针与const
const对象的指针必须指向const对象,不能指向非const对象。 void也需要使用const修饰,表示指针指向的对象不可修改。
const int ival=0;
int *p1=&ival; // error
const int *p2=&ival; // ok
非const对象的指针可以指向const对象,但不能通过该指针修改对象的值。
int ival=0;
const int *p1=&ival; // ok
*p1=1; // error
const指针 不允许该指针指向其他对象,但可以修改指向对象的值。
int ival=0;
int *const p1=&ival; // ok
*p1=1; // ok
int ival2=2;
p1=&ival2; // error
指向const的const指针 既不允许指针指向其他对象,也不允许修改指向对象的值。
const int ival=0;
const int *const p1=&ival; // ok
*p1=1; // error
int ival2=2;
p1=&ival2; // error
typedef 和 const 的陷阱
先理解 typedef 是“类型别名”,不是文本替换。
typedef string* pstring;
这句话的意思是:pstring 是一个新类型,它的本质是 string*(指向string的指针)。
问题的核心:
const pstring cstr;
大多数人的直觉是把 pstring 展开,变成:
const string* cstr; // 直觉上的理解(错的)
这样理解的话,cstr 是一个指向 const string 的指针(指针可以变,内容不能变)。
但实际上是这样
const 修饰的是 pstring 这个类型整体,而 pstring 是一个指针类型:
const pstring cstr
↓ ↓
不可变 指针类型
所以 const 加在指针上,表示指针本身不可变,等价于:
string* const cstr; // 正确理解:const 指针,指向 string
两种类型的对比:
const string* cstr; // 指向const string 的指针
// 指针能变,但不能通过它修改内容
string* const cstr; // 指向string 的const指针
// 指针不能变(不能指向别处),但内容能改
为什么不能直接文本替换?
typedef string* pstring;
// 如果是文本替换(错误思维):
const pstring -> const string* -> 指向const string的指针
// 实际上是类型替换(正确):
const pstring -> (string*) const -> const指针,指向string
typedef 创建的是一个完整的类型单元,const 只能作用在这个单元上,而不会“钻进去”修改类型内部。
多维数组与指针
int *ip[4]; // array of 4 pointers to int
int (*ip)[4]; // pointer of an array of 4 ints