C 语言常见误解/指标/指标运算

指标(三)指标运算

编辑

问:假如有两个指标型态都是 int*, 可以相减得知他们相差多远吗?

答:一般来说不行。两个指标必须指向相同阵列的元素,或是该阵列最后一个元素超过一格的位置,才能相减比较。阵列太大也有可能出状况,请看下一个问题。(另外参考这个问题和 clc FAQ 5.17 看实际例子)


问:指标相减得到的距离是什么型态?

答:是有号整数型态 ptrdiff_t. 注意如果因为阵列太大导致这个型态无法表示之间的距离,则相减视为严重的错误。请务必检查 PTRDIFF_MAXPTRDIFF_MIN 确保此型态满足程式所需。


问:我知道阵列和指标不同,但既然阵列在很多地方都会自动转型成指标,如果把 int a[100] 的型态理解成 int * const(不能改内容的指标)会有什么陷阱呢?

答:一个经典的例子是如果第一个档案写

int a[100];

第二个档案写

extern int * const a;

则在很多实作中,第二个档案内存取 a[0] 时,编译器会把第一个档案 a[0] 的内容硬当作 int 指标 p 再把 *p 当作计算结果,进而发生严重的错误。在这例子中 C99 (N1256) 并不要求编译器发出任何错误讯息。


问:如果一个结构是

  struct {
     int heap[1024];
     int stack[1];
  };

那可以用 .stack[-1] 去存取 heap 的内容吗?

答:不行。首先要考虑填充的问题,heap 和 stack 中间不一定连续。就算确定没有填充,阵列存取等价于先做指标运算后再解参照,而指标运算只能在同一阵列内部或超出最后一个元素一格的位置之间移动。也就是说,符合标准的编译器可以额外加上阵列范围检查。


问:如果一个阵列 a 型态为 int[5][5] 可以用 a[1][10] 去存取吗?阵列不是连续的吗?

答:这样存取不保证成功。虽然阵列是连续的,看起来也可以存取,但是不行。阵列存取等价于指标运算加上解参照,在这例子中等价于 *(*(a+1)+10) 这个表达式。但指标运算只能在同一阵列内部或超出最后一个元素一格的位置之间移动。+10 违反了这个限制。(请一同参考指标相减的规则。)标准允许实作主动检查指标是否超过范围,甚至用完全不同的方法表示阵列。(参考 N1256 Annex J.2p1clc FAQ 5.17 看实际例子)