C++ Primer 学习笔记:数组和指针 (1)
C++ Primer 学习笔记三:数组和指针 (1)
1. 现代C++ 中应当尽量使用vector和迭代器类型,避免使用低级的数组和指针。设计良好的程序只有在性能测试时使用vector无法达到性能要求时,才在类实现的内部使用数组和指针。出于遗留系统的原因,还是必须掌握数组的使用方法。
数组的长度是固定的,一经创建就不能添加新的元素。指针则可以像迭代器一样用于遍历和检查数组中的元素。
2. 数组的维数必须用大于等于1的常量表达式定义,此常量表达式只能包含整型字面值常量,枚举常量或者用常量表达式初始化的整型const对象。非const对象和必须到运行时才确定值的const变量不能用于定义数组的维数。
3. 如果没有显式地提供元素初值,则数组元素会像普通变量一样初始化:
- 在函数体外定义的内置数组,其元素均初始化为0。
- 在函数体内定义的内置数组,其元素无初始化。
- 无论数组在哪里定义,如果其元素为类类型,则自动调用该类的默认构造函数进行初始化;如果该类没有默认构造函数,则必须为该数组的元素提供显式的初始化。
4. 不允许数组直接复制或赋值,数组的下标索引应当为size_t类型。
5. 与迭代器不同的是:指针用于指向单个对象,而迭代器只能用于访问容器内的元素。
6. 避免使用未初始化的指针。如果可能的话,除非所指向的对象已经存在,否则不要先定义指针,这样可以避免一个未初始化的指针;如果必须分开赋值,则应当先将指针赋为空值。
7. void* 可以保存任何类型对象的指针,它只支持以下几种操作:
- 与另一个指针进行比较
- 向函数传递void* 指针或从函数返回void* 指针
- 给另一个void* 指针赋值
不允许使用void* 指针操纵它所指向的对象。
8. 指针和引用的比较:
- 引用总是指向某个对象 ,定义引用时没有初始化是错误的。
- 赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化就始终指向同一个特定对象(这也是为什么引用必须在定义时初始化的原因)。
例如下面的程序:
int ival = 1024, ival2 = 2048; int *pi = &ival, *pi2 = &ival2; pi = pi2 // 现在pi 指向的是ival2。
赋值结束后,pi所指向的ival对象值保持不变,赋值操作修改了pi指针的值,使其指向一个不同的对象。
int &ri = ival, &ri2 = ival2; ri = ri2; // 将ival2 赋值给ival
这个赋值操作修改了ri引用的值 ival对象,而并非引用本身。赋值后两个引用还是分别指向原来关联的对象,此时这两个对象的值相等。
9. 对于数组,数组名会自动转换为指向数组第一个元素的指针。指针的算术操作只有在原指针和计算出来的指针都指向同一个元素,或指向该数组存储空间的下一单元才是合法的。如果指针指向一对象,我们还可以在指针上加1从而获取指向相邻的下一个对象的指针。
如果两个指针指向同一数组或有一个指向该数组末端的下一单元,C++还支持对这两个指针做减法操作:
std::ptrdiff_t n = ip2 – ip
其中,ptrdiff 跟size_t一样,也是与机器相关的类型,可正可负并保证足以存储同一数组间两个指针的差距。
只要指针指向数组元素,就可以对它进行下标操作:
int ia[] = { 0, 2, 4, 6, 8 } ;
int *p = &ia[2]
int j = p[1]
int k = p[-2] // 索引为负数也合法
10. C++ 允许计算数组或对象的超出末端的地址,但不允许对此地址进行解引用操作,而计算数组超出末端位置之后或数组首地址之前的地址都是不合法的。未端的地址只能用来与其它指针比较,或者用作指针算术操作表达式的操作数。
const size_t arr_sz = 5;
int int_arr[arr_sz] = { 0, 1, 2, 3, 4};
for ( int *pbegin = int_arr, *pend = int_arr + arr_sz; pbegin != pend; ++pbegin)
cout<< *pbegin << endl; // 与数组联合使用的指针就是迭代器
Related posts:
太有总结性!
这是简单的笔记,呵呵。