这两个陈述有什么区别?

时间:2012-04-08 12:23:44

标签: c arrays pointers

我有这两个陈述:

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个1维阵列,每个阵列具有2个元素。因此(a+1)会向我提供a[1][0]的地址,但为什么(int *)a+1会向我提供a[0][1]的地址?

请解释程序的差异和输出。

感谢。

3 个答案:

答案 0 :(得分: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 *时,你告诉编译器忘记它的原始声明,实际上失去了它的二维性并成为int的简单向量第

以下是如何理解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]);

当然,您的技术主管最好允许您编写。如果你在我的小组中写下这个,那你就被解雇了。 ; - )

答案 1 :(得分:2)

无,都产生未定义的行为。打印指针值的正确格式为%p。将指针发送到void*时,将指针投向printf

答案 2 :(得分:0)

多维C数组的行为类似于彼此相邻的单维数组。因此,如果您将a(通常为(int **))投射到(int *),您将获得与a[0]相同的内容。因此(int *) a + 1&a[0][1]。否则,您的理解是正确的,这就是a + 1为您提供&a[1][0]

的原因

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