指针操作以及指针有关注意事项
一、解引用操作生成左值
二、关键概念:给指针赋值或通过指针进行赋值
对于初学指针者,给指针赋值和通过指针进行赋值这两种操作的差别确实让人费解。谨记区分的重要方法是:如果对左操作数进行解引用,则修改的是指针所指向的值;如果没有使用解引用操作,则修改的是指针本身的值。
三、指针和引用的比较
第一个区别在于引用总是指向某个对象:定义引用时没有初始化是错误的。第二个重要区别则是复制行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象(这就是为什么引用必须在定义时初始化的原因)。
四、指向指针的指针
指针本身也是可用指针指向的内存对象。指针占用内存空间存放其值,因此指针的存储地址可存放在指针中。
int ia[] = {0, 2, 4, 6, 8};
int *ip =ia; // ip points to ia[0]
ip = &ia[4]; // ip points to last element in ia
ip = ia; // ok: ip points to ia[0]
int *ip2 = ip + 4; // ok: ip2 points to ia[4], the last element in ia
指针的算数操作只有在原指针和计算出来的新指针都指向同一个数组的元素,或指向该数组存储空间的下一单元时才是合法的。如果指针指向一对象,我们还可以在指针上加1从而获取指向相邻的下一个对象的指针。
五、C++还支持对这两个指针做减法操作:
ptrdiff_t n = ip2 - ip; // ok: distance between the pointers
结果是4,这两个指针所指向的元素间隔为4个对象。两个指针减法操作的结果是标准库类型ptrdiff_t的数据。与size_t类型一样,ptrdiff_t也是一种与机器相关的类型,在cstddef头文件中定义。size_t是unsigned类型,而ptrdiff_t则是signed_t整型。
允许在指针上加减0,使指针保持不变。如果一指针具有0值,则在该指针上加0仍然是合法的,结果得到另一个值为0的指针。也可以对两个空指针做减法操作,得到的结果仍是0。
六、解引用和指针算术操作之间的相互作用
在指针上加一个整型数值,其结果仍然是指针。允许在这个结果上直接进行解引用操作,而不必先把它赋给一个新指针:
int last = *(ia + 4); // ok: initializes last to 8, the value of ia[4]
加法操作两边用圆括号括起来是必要的。如果写为:
last = *ia + 4;// ok: last = 4, equivalent to ia[0]+4
意味着对ia进行解引用,获得ia所指元素的值ia[0],然后加4。
七、计算数组的超出末端指针
const size_t arr_size = 5;
int arr[arr_size] = {1, 2, 3, 4, 5};
int *p = arr; // ok: p points to arr[0]
int *p2 = p + arr_size; // ok: p2 points one past the end of arr
// use caution -- do not dereference!
C++允许计算数组或对象的超出末端的地址,但不允许对此地址进行解引用操作。而计算数组超出末端位置之后或数组首地址之前的地址都是不合法的。
可使用此超出末端指针的当做一个哨兵,如同在vector中使用的end变量一般,用于输出和遍历数组,这是一个好习惯