返回首页 - Notes - 2012

数组和指针


基本概述

相对于 vector数组 的缺陷显而易见:长度固定,没有获知数组长度的内置方法

现代 C++ 推荐优先使用 vector,只有当有很高的性能要求时才考虑使用 数组

应该尽量避免使用 数组指针C 风格字符串,取而代之的是 vectoriteratorstring


数组

数组 的维数必须用值大于等于 1 的常量表达式定义,此常量表达式不能含有非 const 变量以及要到运行时才知道其值的变量

如下两例都是错误的

  1. int size = 10; char arr[size];:错误,因为 size 不是 const 变量
  2. char arr[get_size()];:错误,因为 get_size() 的值要到程序运行时才能知道

数组的默认初始化方式:

  1. 在函数体外定义的内置数组,其元素均初始化为 0
  2. 在函数体内定义的内置数组,不进行初始化
  3. 数组元素类型为类类型时,如果该类类型有默认构造函数则调用默认构造函数初始化,如果没有默认构造函数则必须显式初始化

不同于 vector,下面两例都是错误的

  1. int arr2[] = arr1;:一个数组不能使用另一个数组初始化
  2. arr3 = arr1;:不能将一个数组赋值给另一个数组

数组下标的类型为 size_t


指针

取址操作符 “&” 不能用于字面值常量,int *p = &100; 这样的用法是错误的

指针 在定义时一定要记得同时进行初始化,否则容易出现安全隐患,如果实在不能在定义时给出初始化值也应该把指针初始化为 0

指针 直接赋值为 int 型数值是非法的,直接赋 0NULL 除外(NULL 在头文件 cstdlib 中定义,其值也是 0

C++ 提供了一个特殊的 void* 指针,它可以保存任何对象的地址

void* 指针的使用是受限的,不允许使用 void* 指针操纵它所指向的对象

指针引用 的区别:

  1. 引用 在定义的同时必须初始化,而 指针 可以暂时不初始化(不推荐)
  2. 引用 一经定义就不能再更改绑定对象,而 指针 可以改绑
  3. 引用 只是所绑定对象的别名,而 指针 是所绑定对象的地址

数组与指针

在表达式中使用数组名时,该数组名会自动转换成指向数组第一个元素的指针

如果两指针指向的是同一数组,则这两个指针还支持减法运算,p1 - p2 所得的数据类型为 ptrdiff_t(定义于 cstddef 头文件)

解引用操作符的优先级高于加法操作符,必要时必须使用括号以避免歧义

使用下标访问数组时,实际上是在对指向数组的指针进行操作

在数组名上加上数组的长度即可以得到数组的超出末端指针,该指针只能用作比较操作,不能解引用,这与 vectorend() 一样

指针 就相当于 数组迭代器


指针和const

C++ 的要求比 C语言 更严格,有些 const 类型的问题,在 C语言 中只是警告,而在 C++ 中是直接报错,无法通过编译

C++ 要求指向 const 对象的指针也必须具有 const 特性,也就是说如果目标对象是 const 的,那么指针的类型也必须是 const 的(注意,不是指针本身的类型,而是指针指向的类型。对于这一点,C 没有硬性要求,但会发出警告)

  1. const int a = 2; int *p = &a;:错误,因为目标对象是 const 类型的,所以指针指向的类型必须有 const 修饰
  2. const int a = 2; const int *p = &a; p = &b;:正确,指针本身没有 const 修饰,可以改绑

允许将非 const 对象绑定给指向 const 对象的指针,但不能够通过该指针改变对象的值,如需修改只能通过其他途径(指针本身是可以改绑的,const 修饰的是指针指向的对象。这一点,CC++ 是一致的)

  1. int a = 2; const int *p = &a; *p = 3;:错误,不能通过该指针修改对象的值
  2. int a = 2; const int *p = &a; int *b = &a; *b = 3; std::cout << *p << std::endl;:正确,此时 *p 的值为 3

指向 const 的指针可以认为是:“自认为指向了 const 对象的指针,但至于这个对象是不是真的是 const,它不知道”

在实际应用中,指向 const 的指针常用作函数的形参,以确保传递给函数的实际对象在函数中不因形参的改动而被修改

const 指针就好理解了:以 const 修饰指针本身的指针,唯一的特点就是在绑定了对象以后不允许再更改绑定,所以 const 指针在定义时必须初始化

  1. int a = 2; int b = 3; int *const p = &a; p = &b;:最后的 p = &b; 错误,const 指针一经定义就不允许改绑
  2. const int a = 2; int *const p = &a;:错误,C++ 规定,当绑定对象是 const 时,指针所指向的对象也必须是 const,所以应为 const int *const p = &a;,但这样一来,指针和对象就都是不可变更的常量了

一个易错点:如果已经有定义 typedef string * pstr;,则 const pstr p; 扩展开来是什么样的表达式?

  1. 典型错误:const string * p;,把 typedef 当作 #define 看待了
  2. 正解:typedef 定义的是一个指针,而 const 修饰的正是这个指针,所以正确的扩展为 string *const p;
  3. const pstr p;pstr const p; 展开是一样的

审读复杂的 const 声明语句时,应该 从右往左 看,这样就不会把 const pstr p;pstr const p; 当成两个不同的声明了


date : 2012-04-04、2012-04-06