仅使用指向一个元素的指针访问数组元素的上一个和下一个成员

时间:2017-10-11 18:17:27

标签: c arrays pointers

(改编自this deleted question。)

假设我们有一个数组int a[n],我们有一个指向数组中间元素的指针(即int *p = &a[y],其中0

如果将p传递给我们无法直接访问数组的函数,如何在给定的数组元素之前和之后立即访问这些元素,以便将它们一起添加?

例如,如果a在范围内,则总和可以很容易地得到:

int sum = a[y-1] + a[y+1];

但是在a不在范围内的函数中:

int sum_prev_next(int *p)
{
   ...
}

这样称呼:

sum = sum_prev_next(&a[y]);

该函数如何访问上一个和下一个元素以返回总和?

2 个答案:

答案 0 :(得分:5)

假设有问题的指针没有指向数组的第一个或最后一个元素,您可以使用指针算法来访问数组的前一个和下一个元素。

int sum_prev_next(int *p)
{
   return *(p-1) + *(p+1);
}

或等效地:

int sum_prev_next(int *p)
{
   return p[-1] + p[1];
}

负数组下标可能不常见,但在这种情况下定义明确。用图表可以更好地解释这一点:

        p-1
        |   p   p+1
        |   |   |
        v   v   v
  -------------------------
a | 0 | 1 | 2 | 3 | 4 | 5 |
  -------------------------

如果p指向a[2],则p[-1]a[1]相同,p[1]a[3]相同。

重要的是要注意,此函数的前提条件是p不指向数组的第一个或最后一个元素。如果确实如此,则访问p[-1]p[1]将通过在数组开始之前创建指向一个指针的指针或通过取消引用指向一个结尾的指针来调用undefined behavior。 array(创建一个指向结尾的指针)。

答案 1 :(得分:2)

根据数组下标的定义(C标准,6.5.2.1数组下标)

  

2后缀表达式后跟方括号[]中的表达式   是数组对象元素的下标。该   下标运算符[]的定义是E1 [E2]与...相同   (*((E1)+(E2)))。由于适用于的转换规则   binary +运算符,如果E1是数组对象(等效于指针   到数组对象的初始元素),E2是一个整数,   E1 [E2]表示E1的第E2个元素(从零开始计数)。

此声明

int sum = a[y-1] + a[y+1];

可以等同地重写

int sum = *( a + y - 1 ) + *( a + y + 1 );

反过来可以像

一样重写
int sum = *( ( a + y ) - 1 ) + *( ( a + y ) + 1 );

其中子表达式a + y表示定义为

的指针p
int *p = &a[y];

或(相同),如

int *p = a + y;

因为根据标准转换(C标准,6.3.2.1左值,数组和函数指示符)

  

除非它是sizeof运算符或一元&的操作数。   operator,或者是用于初始化数组的字符串文字, an   具有类型''数组类型''的表达式将转换为   带有''指向类型'的指针的表达式,指向初始值   数组对象的元素并且不是左值。如果是数组   对象具有寄存器存储类,行为未定义。

因此声明可以像

一样重写
int sum = *( p - 1 ) + *( p + 1 );

现在再次回到C标准的第一个引用

int sum = p[-1] + p[1];

反之亦然如果有上述声明,我们可以像

一样重写它
int sum = *( p - 1 ) + *( p + 1 );

考虑p之类的定义

int *p = a + y;

声明可以像

一样重写
int sum = *( ( a + y ) - 1 ) + *( ( a + y ) + 1 );

int sum = *( a + ( y - 1 ) ) + *( a + ( y + 1 ) );

给出了

int sum = a[y-1] + a[y+1];