C语言指针运算符详解

描述

概述

在C语言中,当你有一个指向数组中某个元素的指针时,你可以对该指针执行某些算术运算,例如加法或减法。这些运算可以用来遍历数组中的元素,如ptr[i]等价于*(ptr + i)。然而,如果你的操作使得指针指向了数组以外的位置(除了数组结束位置之后的一个位置之外),那么这个指针的行为就是未定义的。

例如:

如果ptr指向数组的第一个元素,那么ptr + 1将指向第二个元素。

如果ptr指向数组的最后一个元素,那么ptr + 1将指向数组结束之后的一个虚构位置,这是允许的,但是试图访问该位置(如*(ptr + 1))将导致未定义行为。

如果ptr指向数组的最后一个元素,那么ptr + 2指向的位置超出了数组的范围,这将导致未定义行为。

未定义行为意味着编译器可以做出任何事情,包括但不限于程序崩溃、数据损坏或其他不可预测的结果。因此,在编写涉及指针操作的代码时,确保指针始终在安全范围内是非常重要的。在实际编程中,常常会用到边界检查来防止这类问题的发生。

详述

创建一个指向数组末尾之后的指针在标准中是有明确定义的,并且本规则允许这种操作。但是,引用通过这种方式创建的指针会导致未定义的行为,并且此规则禁止这样做。

本规则适用于所有形式的数组索引:

整数表达式 + 整数表达式 

指针表达式 + 整数表达式 

指针表达式 += 整数表达式 

指针表达式 -= 整数表达式 

++ 指针表达式 

-- 指针表达式 

指针表达式++ 

指针表达式--

整数表达式 [指针表达式] 

指针表达式 [整数表达式]

注意:对于指针算术的目的,标准将不是数组成员的对象视为具有单个元素的数组。

理由

虽然一些编译器可以在编译时确定数组边界是否超出,但在运行时通常不会对无效数组下标进行检查。使用无效数组下标可能导致程序出现错误行为。

由于它们不容易通过静态分析或手动审查来检查,因此运行时推导出的数组下标值最令人担忧。如果可能的话,应该提供代码以检查此类下标值的有效性,并根据需要采取适当的行动。

如果从上述表达式之一获得的结果不是一个指向由指针表达式所指向的数组元素或一个超过该数组末尾的一个元素的指针,则其行为是未定义的。有关更多信息,请参阅C90第6.3.6节、C99第6.5.6节。

多维数组是“数组的数组”。本规则不允许导致指针指向不同子数组的指针算术。不应使用数组下标跨越“内部”边界的数组下标,因为这样的行为是未定义的。

示例

使用+运算符也会违反规则18.4。  

 

int32_t f1( int32_t * const a1, int32_t a2[10][1]) 
{
  /* Compliant/non-Compliant depending on the value of a1 */
  int32_t *p = &a1[3];     
  return *(a2 + 9); /* Compliant */
}


void f2(void)
{
    int32_t data = 0;
    int32_t b = 0;
    int32_t c[10] = {0};
    // 5-element array of 2-element arrays of int32_t
    int32_t d[5][2] = {0}; 
 
    int32_t *p1 = &c[0];    //Compliant
    int32_t *p2 = &c[10];   // Compliant - points to one beyond
    int32_t *p3 = &c[11];   // Non - compliant - undefined, points to two beyond
    
    data = *p2;




    data = f1(&b, c);
    data = f1(c, c);
    
    p1++;         /*Compliant*/
    c[-1] = 0;    /*Non-Compliant - undefined, array bounds exceeded*/
    data = c[10];    /*Non-Compliant - undefined,dereference of address one beyond*/
   
    d[3][1] = 0;         /*Compliant*/
    data = *(*(d + 3) + 1);      /*Compliant*/
    data = d[2][3];      /*Non-compliant - undefined, internal boundary exeeded*/
    
    p1 = d[1];
    data = p1[1];
}

 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分