未知的C代码输出
下面的代码如何给出20362036的答案 以下C代码的输出是什么?假设x的地址是十进制的2000,整数需要四个字节的内存未知的C代码输出,c,pointers,undefined-behavior,unsigned-integer,C,Pointers,Undefined Behavior,Unsigned Integer,下面的代码如何给出20362036的答案 以下C代码的输出是什么?假设x的地址是十进制的2000,整数需要四个字节的内存 int main() { unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; printf("%u, %u, %u", x+3, *(x+3), *(x+2)+3); } 虽然x和x[0]的地址相同,但它们的类型不
int main()
{
unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6},
{7, 8, 9}, {10, 11, 12}};
printf("%u, %u, %u", x+3, *(x+3), *(x+2)+3);
}
虽然x和x[0]的地址相同,但它们的类型不同,因此大小也不同
您应该在主函数的末尾添加return 0。此外,您的打印声明应如下所示:
printf("%p, %p, %p\n", (void *)(x+3), (void *)*(x+3), (void *)(*(x+2)+3));
/* ^^ ^^ ^^^^ ^^^^^^^^^ ^ ^^^^^^^^ ^^^^^^^^^ ^ */
对于定义良好的bahviour。正如您刚刚发现的那样,如果您不发布精心编制的代码,人们可能会对您有点苛刻。要打印地址,请使用%p或PRIXPTR和uintptr的casts等宏 仅使用%p,您的代码可能应为:
#include <stdio.h>
int main(void)
{
unsigned int x[4][3] =
{
{ 1, 2, 3 }, { 4, 5, 6 },
{ 7, 8, 9 }, { 10, 11, 12 }
};
printf("%p\n", (void *)x);
printf("%p, %p, %p\n", (void *)(x+3), (void *)(*(x+3)), (void *)(*(x+2)+3));
return 0;
}
十六进制0x24当然是36位小数。编辑:正如乔纳森·莱夫勒指出的,我应该在打印%p之前将其转换为void*
也许这将澄清内存寻址方面的情况:
#include <stdio.h>
int main() {
unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
// Output: Address, 1
printf("%p, %u\n", (void*)(x), **x);
// Output: Address + 12, 4
printf("%p, %u\n", (void*)(x+1), **(x+1));
// Output: Address + 24, 7
printf("%p, %u\n", (void*)(x+2), **(x+2));
// Output: Address + 4, 2
printf("%p, %u\n", (void*)((*x)+1), *(*(x)+1));
return 0;
}
未定义的行为当您试图用%u打印x+3时,您有未定义的行为……没错,这是UB,但可能仍然有一些道理。@asimes:UB与问题的目的无关,而不是根本问题。代码可以很容易地修复,然后再进行推理。UB是一个C的新手可以轻松制作的。请记住,并不是所有提出这一问题的人都是专家。@asimes:我同意——如果问题本质上是关于UB的,那么就没有必要深入研究,或者这样做也没有什么意义。那么这些问题问你从x=++x+x++;,得到了什么;?等等都是毫无意义的。这不属于那个类别,我想你可能会同意。严格地说,在使用%p打印之前,你应该将指针转换为void*。在当前的机器上,这不太可能是一个实际问题,但我在一台机器上学习了C语言,在出现void*之前的几天里,内存位置的char*地址的值与同一内存位置的int*地址的值不同,我可以补充一句——这告诉你这是很久以前的事了——所以char*是“通用指针”。@JonathanLeffler,说实话,我根本没有意识到这一点。我很好奇,在什么情况下,这会对你学习的机器产生影响?IIRC,如果你将内存位置的char*地址打印为hex,你会得到一个值,比如0x80049268;如果为同一内存位置打印int*地址,则会得到一个值0x00049268。这是很久以前的事了,当我们得到一个额外的1MIB内存时,我们非常高兴,它将机器上的内存增加了一倍。这意味着程序要使用1.25MIB,而不仅仅是0.25MIB,因为o/s占用了大约0.75MIB。因此,使用32位地址的高位表示它是字节地址而不是字地址不是问题;有很多未使用的位。十六进制中可能还有一个“因子2”;我现在不记得了,它可能是一种稍微不同的编码方式。但有一点不同。不声明extern char*malloc是一个可怕的bug;在使用它之前,这是在几天前有一个声明它。在这样的环境中,你要学会小心。@JonathanLeffler,哇,我很高兴我三年前学会了C。。。坦白地说,int*如何不给出0x80049268,我仍然不清楚。我假设那个上下文中的字是16位,而字节是8位?即使这是真的,我仍然不明白地址的差异是从哪里来的
0x7fff5800a440
0x7fff5800a464, 0x7fff5800a464, 0x7fff5800a464
#include <stdio.h>
int main() {
unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
// Output: Address, 1
printf("%p, %u\n", (void*)(x), **x);
// Output: Address + 12, 4
printf("%p, %u\n", (void*)(x+1), **(x+1));
// Output: Address + 24, 7
printf("%p, %u\n", (void*)(x+2), **(x+2));
// Output: Address + 4, 2
printf("%p, %u\n", (void*)((*x)+1), *(*(x)+1));
return 0;
}
#include <stdio.h>
int main() {
unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
printf("%p, %u\n", (void*)(x), **x); // Output: Address, 1
printf("%u\n", x[0][0]); // Output: 1
printf("%p, %u\n", (void*)(x+1), **(x+1)); // Output: Address + 12, 4
printf("%u\n", x[1][0]); // Output: 4
printf("%p, %u\n", (void*)(x+2), **(x+2)); // Output: Address + 24, 7
printf("%u\n", x[2][0]); // Output: 7
printf("%p, %u\n", (void*)((*x)+1), *(*(x)+1)); // Output: Address + 4, 2
printf("%u\n", x[0][1]); // Output: 2
return 0;
}