[英]What is the difference between these two statements?
我有这两个声明:
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
为了理解上面程序的 output,我知道如果我知道上面两个语句之间的区别,就可以解决造成这个 output 的区别。
我目前的理解: (a+1)
会给我数组第二个元素的地址。 在这种情况下,二维数组可以可视化为 2 1-d arrays,每个数组有 2 个元素。 所以(a+1)
会给我a[1][0]
的地址,但为什么(int *)a+1
会给我a[0][1]
的地址?
请说明区别和程序的output。
谢谢。
成语(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 实际上将数据存储在 memory 的一个连续块中,如下所示:
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]);
当然,你的 tech lead 最好不要让你这么写。 如果你在我的小组里这样写,你就会被解雇。 ;-)
无,两者都会产生未定义的行为。 打印指针值的正确格式是%p
。 将指针发送到printf
时将指针指向void*
。
多维 C arrays 表现得像单维 arrays 并排放置。 因此,如果您将a
(通常(int **)
) 转换为(int *)
,您会得到与a[0]
相同的结果。 因此(int *) a + 1
是&a[0][1]
。 否则你的理解是正确的,这就是为什么a + 1
得到你&a[1][0]
。
(此行为由标准指定;但这并不是好的编程习惯。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.