1

我有这两个陈述:

printf("%u",a+1);

printf("%u",(int *)a+1);

实际上,当我遇到这种困惑时,我正在编写此代码。

#include<stdio.h>

int main()
{
  int a[2][2]={1,2,3,4};
  int i,j;
  int *p[] = { (int*)a, (int*)a+1, (int*)a+2 };
  for(i=0; i<2; i++){
    for(j=0; j<2; j++){
      printf("%d %d %d %d",* (*(p+i)+j), *(*(j+p)+i), *(*(i+p)+j), *(*(p+j)+i));
    }
  }
  return 0; 
}

Output:

1 1 1 1
2 2 2 2
2 2 2 2
3 3 3 3

为了理解上述程序的输出,我知道如果我知道上述两个语句之间的区别,那么产生这个输出的区别就可以解决。

我目前的理解: (a+1)会给我数组第二个元素的地址。在这种情况下,一个二维数组可以可视化为 2 个一维数组,每个数组有 2 个元素。所以(a+1)会给我地址a[1][0],但是为什么(int *)a+1给我地址a[0][1]呢?

请解释程序的区别和输出。

谢谢。

4

3 回答 3

3

成语(int*)a+1被解释为((int*)a) + 1)。也就是说,演员阵容优先于加法。因此,它的计算结果为(int*) a),它是数组的地址,为 ptr-to-int,偏移 1,返回数组中的第二个元素 ( 2)。

编程的两个关键规则:

规则 1:编写代码时,让布局反映功能。
规则 2:阅读代码时,请阅读功能,而不是布局。(推论:调试代码,而不是注释。)

从概念上讲,当您声明

int a[2][2]={1,2,3,4};

你设想一个像这样的二维数组:

  1 2
  3 4

但 C 实际上将数据存储在连续的内存块中,如下所示:

  1 2 3 4

它在计算索引时“记住”数据代表一个 2×2 数组。但是当你a从它的原始类型转换为 时int *,你是在告诉编译器忘记它的原始声明,实际上失去了它的二维性并变成了一个简单的ints 向量。

以下是如何理解 的声明p

int *p[] = { (int*) a,  (int*) a+1,     (int*) a+2 };     // As written
int *p[] = { (int*) a,  ((int*) a) + 1, ((int*) a) + 2 }; // As interpreted
int *p[] = { &a[0][0],  &a[0][1],       &a[1][0] };       // Resulting values

从这里,您可以看到它p是一个一维向量数组:

p[0] = { 1, 2, 3 }
p[1] = { 2, 3 }
p[2] = { 3 }

如果您认识到这一点(p+i) == (i+p),那么最后两项与该行中的前两项相同

printf("%d %d %d %d\n",* (*(p+i)+j), *(*(j+p)+i), *(*(i+p)+j), *(*(p+j)+i));

这相当于:

printf("%d %d %d %d\n", p[i+j], p[j+i], p[i+j], p[j+i]);

有趣的是,因为以下都是等价的:

a[i]
*(a+i)
*(i+a)

那么写i[a]代表相同的值是完全合法的。换句话说,编译器允许您编写

printf("%d %d %d %d\n", p[i], i[p], p[1], 1[p]);

当然,你的技术主管最好不要让你写那个。如果你在我的小组里写这个,你就会被解雇。;-)

于 2012-04-08T12:48:39.733 回答
2

无,两者都会产生未定义的行为。打印指针值的正确格式是%p. 将指针void*发送到printf.

于 2012-04-08T12:30:54.863 回答
0

多维 C 数组的行为类似于彼此相邻布置的一维数组。因此,如果您a(通常(int **)(int *)a[0]. 因此(int *) a + 1&a[0][1]。否则你的理解是正确的,这就是为什么a + 1得到你&a[1][0]

(此行为由标准指定;但这并不能使其成为良好的编程习惯。)

于 2012-04-08T12:31:37.597 回答