取消引用包含对象地址的绑定指针(数组数组)

时间:2015-08-17 06:11:31

标签: c arrays pointers language-lawyer memcpy

对于REF的不同值

,是否定义了以下内容?
#include <stdio.h>

#define REF 1
#define S 1

int main(void) {
    int a[2][S] = {{1},{2}};
    int *q = REF ? a[1] : 0;
    int *p = a[0] + S;
    memcpy (&q, &p, sizeof q);
    printf ("q[0] = %d\n", q[0]);
    return 0;
}

请注意p指向a[0]的最后一个元素之后,而不指向数组a[0]中的元素,因此不能解引用。但p中存储的地址是a[1][0]的地址。 p在语义上(故意?)指向“{,1}} ”,但物理上指向a[0]

指针的位模式的副本是否可以在原始物理上实际上在语义上指向对象?

另见

我基本上用不同的“角度”问了同样的C / C ++问题:

2 个答案:

答案 0 :(得分:4)

给出

int blah(int x, int y)
{
  int a[2][5];
  a[1][0] = x;
  a[0][y] = 9;
  return a[1][0];
}

标准中的任何内容都不会禁止编译器将其重新编码为int blah(int x, int y) { return x; },也不会在y>=5时捕获(或执行任何操作),因为a[0]a[1]是不同的每个五个元素的数组。在间接访问的结构的最后一个元素是单元素数组的情况下,编译器通常包括允许该数组上的指针算术产生指向结构外部存储的指针的代码。虽然标准禁止这样的指针算法,但它能够实现在C99之前无法以任何符合标准的方式实际实现的有用构造。

请注意,向a[0]添加5会产生与int*相同的a[1],但事实上是&#34;过去&#34;}指针比较等于一个指针,该指针识别存储器中的下一个对象并不意味着它可以安全地用于访问后一个对象。这种访问通常可以起作用,但这并不意味着编译器必须让它们这样做。

答案 1 :(得分:1)

  

指针的位模式的副本可以在语义上指向   对象当原来只有物理上做什么?

没有这样的区别,因为a[0] + Sa[1]相同,假设内部数组以S大小声明。

以下内容:

int a[2][S];

声明两元素数组,其中每个元素都是S的数组 - 类型为int的元素。数组是有条理地存储的,并且在其元素之前/之间/之后没有填充。

我们将证明,a[0] + S == a[1]成立。它可以改写为:

*(a + 0) + S == *(a + 1)

通过指针算法,RHS将1 * sizeof(*a)个字节添加到a,这与内部数组的大小相同。 LHS稍微复杂一点,因为在a取消引用之后执行了添加,因此它增加了:

S * sizeof(**a)个字节,

当双方指向相同类型的同一对象(相同的内存位置)时,双方都保证相等。因此,您可以将其重写为&#34;绝对&#34;单字节形式为:

(char *)a + S * sizeof(**a) == (char *)a + sizeof(*a)

这减少为:

S * sizeof(**a) == sizeof(*a)

我们知道,子阵列*a具有S类型的**a个元素(即int),因此两个偏移量都是相同的。 Q.E.D。