void main()
{
int a[]={3,5,6,10,2};
int *p;
p=&a;
int **q;
q=&p;
p=p+2;
(*p)++;
printf("%u\n",p);
printf(" %u \n",&a);
printf("%u",q);
}
这将输出为:
738565800
738565792
738565784
q
的值如何始终打印8小于a的地址?有人可以解释这种关系吗?
答案 0 :(得分:1)
使用%p
说明符打印地址
printf("%p\n", (void*)p);
printf(" %p \n",(void *)&a);
printf("%p", (void *)q);
使用%u
说明符打印指针值会调用未定义的行为。 %u
期待unsigned int
您可以使用sizeof
函数来计算这些类型的大小
printf("%zu\n",sizeof(p)); // 4
printf("%zu \n",sizeof(&a)); // 4
printf("%zu",sizeof(q)); // 4
答案 1 :(得分:1)
让我们删除程序中不必要的错误,并修复它以正确打印指针(如haccks所示):
int a[]={3,5,6,10,2};
int *p;
printf("%p\n", (void*)&p);
printf("%p\n", (void*)&a);
我猜测它在你的系统上的行为方式相同(我无法确定;这种东西是依赖于实现的。)
编译器(或OS)按顺序为地址变量分配地址(降序或升序 - 这可能不同)。看起来你的系统给前面在源代码中声明的变量提供了更大的地址。
地址的差异是每个变量的大小(以字节为单位)。
您可以直观地显示变量的存储:
+------+
| p | (address 0x7fff759edd88)
| p | (... continued at address 0x7fff759edd8c)
+------+
| a[0] | (address 0x7fff759edd90)
| a[1] | (address 0x7fff759edd94)
| a[2] | (address 0x7fff759edd98)
| a[3] | (address 0x7fff759edd9c)
| a[4] | (address 0x7fff759edda0)
+------+
请注意,您的原始程序会以相当迂回的方式打印p
的地址(首先将其分配给q
,然后打印q
)。
答案 2 :(得分:0)
这不是你的问题(anatolyg回答了你提出的问题),但你的类型不匹配。表达式&a
的类型是int (*)[5]
(指向int
的5元素数组的指针)。类型对于指针以及其他所有内容都很重要。假设您希望p
成为int
的简单指针,您只需编写
int *p;
p = a;
除非它是sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则表达式为“N-element array of T
“将转换为”指向T
的指针“的表达式,表达式的值将是数组的第一个元素的地址;所以,在这种情况下,不需要使用&
运算符。
另外,请使用int main( void )
代替void main()
。
这两个问题都应该由您的编译器标记;确保在启用所有警告的情况下进行编译。
答案 3 :(得分:0)
对于C语言级别的代码行为没有任何有意义的解释。您的代码示例包含错误代码以及生成未定义行为的代码。因此,您观察到的结果只能通过该未定义行为的半随机半实现相关表示来解释。
特别是,您的代码中存在以下问题。
p = &a;
这是非法的。 &a
的类型为int (*)[5]
,p
的类型为int *
。 C中不允许从这种不兼容类型中分配。这是C中的约束违规,即它通常应该导致编译错误。
void main()
C中的函数main
需要返回int
,而不是void
。
printf("%u\n",p);
printf(" %u \n",&a);
printf("%u",q);
尝试使用%u
格式说明符打印指针值会导致未定义的行为。 %u
需要unsigned int
参数,而不是指针参数。
现在,这种破坏代码的典型行为(如果你设法强制它通过一些宽松的编译器)通常会产生以下内容。您观察到的q
的值是指针p
在内存中的位置。您观察到的&a
的值是数组a
在内存中的位置。因此,您观察到的8个字节的差异仅意味着p
和a
在内存中彼此相距8个字节。 p
位于较低的地址,而a
位于较高的地址。这就是它的全部内容。