数组和指针
指针里面存了一个对象的地址,与迭代器类似也可以进行解引用操作。对指针进行解引用操作可以访问它所指向的对象。
指针的定义和初始化
1 | string *pstring; |
语句把 pstring 定义为一个指向 string 类型对象的指针变量。
在声明语句中,* 可以用在指定类型的对象列表的任何位置。
1 | double dp, *dp2; |
定义了一个 double 类型的 dp 对象和一个指向 double 类型对象的指针 dp2
另一种指针声明风格
1 | string* ps; |
这样容易把 string** 误认为一种数据类型,认为在同语句中定义的其他变量也是指向 string* 类型的指针,例如
1 | string* ps1, ps2; |
实际上只有 ps1 是指针变量,ps2 并非指针。这样容易造成混淆,所以如果真的喜欢第二种的话请尽量分开声明。
注:未初始化的指针是无效的(但是语法允许),初始化为0值的指针代表的是它不指向任何对象。区别于引用,没有初始化的引用是错误 的
注2[最佳实践]:如果可能的话,除非所指向的对象已经存在,否则不要先定义指针,这样可以避免定义一个未初始化的指针;如果必须分开定义的话,一定要将指针初始化为0。
把 int 型变量赋给指针是非法的,即使该 int 是 0。但是可以把数字 0 或在编译时可获得 0 值得 const 量赋给指针。如下:
1 | int zero = 0; |
void *指针
void* 表明该指针与一地址值相关,但不清楚指向的对象类型。不允许使用 void* 来操纵它所指向的对象。
指针的算数操作
只要两个指针指向同一数组或有一个指向该数组末端的下一单元,可以对着两个指针进行做差
1 | ptrdiff_t n = ip2 - ip; |
两个指针做差的结果是 标准库类型 ptrdiff_t 数据。这是一个 signed 整型。因为两个指针的距离可以是负数。
下标和指针
在使用下标访问数组时,实际上是对指向数组元素的指针做下标操作。只要指针指向数组元素,就能操作
1 | int *p = &ia[2]; //p指向ia数组的第二个元素 |
注:C++允许计算数组或对象的超出末端地址,但是 不能 对其解引用。计算超出末端地址或者数组首地址之前的地址都是不合法的!
指针和 const 限定符
指针和 const 可以排列出两种类型:const double *cptr 和 double *const cptr。前者是“(自以为)指向 const 的指针”,而后者是“const 指针”。
(自以为)指向 const 的指针指向的值可以不是 const 对象,但是不能通过这个指针来修改对象的值,但是可以修改指针指向的对象。此时指针指向的是 const double 类型。也叫底层const
const 指针 指向任何对象,只是不能改变它指向的对象(指针本身是const)。但是如果该指针指向的对象不是 const 类型,那么可以通过该指针修改对象的值,但是不能修改这个指针指向的对象。也叫顶层const
也可以将二者结合起来,形成一个既不能改变指向对象也不能改变对象值的指针,即 const double *const pptr = \π
注:const int ci = 42; 其中的 ci 也是顶层 const,用于声明引用的 const 都是底层 const。如 const int &r = ci;
指针和 typedef
如下代码经常容易搞错
1 | typedef string *pstring; |
对 cstr 来说,它的数据类型是 const 指针 ,也就是 string \const cstr*。此时的基本数据类型是指针。
所以在用 typedef 写 const 类型定义时,最好将 const 放在类型后面
C风格字符串
尽量少用,能用 string 就用 string
在前面学习的过程中经常使用 <string.h> 中的 strcat() 和 strcpy() 方法,但是这两个函数由于没有字符复制的限制,所以很容易造成漏洞。所以要尽量采用安全的字符串拼接和复制方法。
1 |
|
注:每次执行复制或者拼接操作时,最后一个参数一定要记得算上null结束符!!
注2:使用 strlen() 函数带来的返回值里面 不包含 结束符null。
创建动态数组
通过 new 和 delete 分配的变量在堆上。有两种办法
1 | int *pia = new int[10]; //创建了一个10个元素的没有被初始化的数组 |
尤其是当数组为 const 数组时,两种语句的差距才体现出来。
1 | const int *pci_bad = new const int[100]; //不行,因为const数组的元素没有被初始化 |
回收动态数组的空间时,使用 delete [ ] pointer 的语句。其中 [ ] 一定不能漏掉。否则编译器不报错但是运行时也要报错。
新旧代码的兼容
string 类中提供了一个 c_str() 方法来将 string 类的字符串转换成 *const char ** 的格式。如
1 | string st2("something"); |
使用数组初始化 vector 对象
使用数组初始化 vector 对象,必须指出用于初始化式的第一个元素以及最后一个元素的下一位置的地址。如下
1 | const size_t arr_size = 6; |
注:此处的“第一个元素”并不代表数组的首元素!
空指针
C++11中使用nullptr来初始化空指针,同时避免使用NULL(包含在