C代码、指针及其内容。试题
我有一个旧考试的代码 第一次打印生成5a9b1740 问题是第二次打印会产生什么C代码、指针及其内容。试题,c,pointers,C,Pointers,我有一个旧考试的代码 第一次打印生成5a9b1740 问题是第二次打印会产生什么 x:未知,因为我们不知道*k代表什么 y:35 z:ffff ffff。为什么? p:5c9b1748。为什么? 编辑:很抱歉造成混淆,第一个打印是5a9b1740,第二个是5c9b1748。不是5a9b1740,5c961748。在这方面对问题进行了编辑 { int x = 4; int y = 15; int *k = &x; int z; int *
- x:未知,因为我们不知道*k代表什么
- y:35
- z:ffff ffff。为什么?
- p:5c9b1748。为什么?
编辑:很抱歉造成混淆,第一个打印是5a9b1740,第二个是5c9b1748。不是5a9b1740,5c961748。在这方面对问题进行了编辑
{
int x = 4;
int y = 15;
int *k = &x;
int z;
int *p;
*k = *k * (*k + 1); /* x = x * (x+1) i.e. 20 */
y = x + y; /* y = 20 + 15 i.e. 35 */
k = &z; /* fine, though the content is not initialised */
int a[] = {7,9,3,8};
p = a;
printf("%x\n",(unsigned int)p);
x = *k + 1; /* x = z +1 which is unknown because content of z still not initialised */
p = p + 2; /* pointing to 3 now */
z = *p - 4; /* z= 3 - 4 ; i.e. -1 */
printf("%d %d %x %x\n",x,y,z,(unsigned int)p);
}
结果将有符号整数(z
)打印为无符号整数,在本例中,该整数在两个补码十六进制表示中表示为-1,但在32位中显示为无符号整数,即“ffff ffff”。起初,我被没有初始化的
z
弄糊涂了,但结果证明这是无关紧要的。在我看来,p的值实际上是不可预测的。
从第一次打印的“5a9b1740”判断,该值应大于两个整数的大小,即大多数系统上的“5a9b1748”。但这与您显示的输出不匹配(在编辑问题之前或之后;请注意5c9b1748-5a9b1740=2000008和5c961748-5a9b1740=1FB 0008。这两者都不能用显示的代码来解释。由于某些原因,人们看不到巨大的差异,只关注少数最不重要的字节…
如果这两个值来自程序的不同运行,那么它可以用有意随机化来解释差异。(感谢格哈德让我寻找解释。)p.s.第3号: 结果表明,问题中给出的地址不是程序执行的实际结果,而是赋值文本中给出的示例值。因此,有一种可能的输入错误:要么两个地址都以
5c9b…
开头,要么两个地址都以w/5a9b…
开头
p、 美国第2号:
请同时参考评论。仅检查地址的最后2~4位数字,我忽略了奇怪的地址间隔b/wprint
行的第一和第二个结果
让我们一行一行地说:
- 第1行:
- 第2行:
- 第3行:
- 第4行:
- 第5行:
- 第7行:
- 第8行:
- 第9行:
- 第11行:
- 第12行:
- 第13行:
- 第14行:
- 第15行:
- 第16行:
- 第17行:
p、 是的,我今天没有别的事可做。这是明显的未定义的行为。编译器可以按照它喜欢的任何顺序排列变量,甚至可以在没有备份存储的情况下保留变量(它只是将值保存在寄存器中,看到它从未被使用过,或者每次使用它时都可以推断出它的值,并且永远不需要存储它。您不能通过添加到指针来合法地指向引用对象之外。对于一个相当愚蠢的编译器(或者没有任何优化),上面的说法可能是正确的。也可能不是 对于上述示例,请使用例如
gcc-O2-g
编译一些程序并对其进行调试。当单步执行调试器时,调试器通常会在源代码中看似随机地跳转,完全跳过一些语句,告诉您一些变量已优化,等等
x
:未知,因为我们不知道*k
包含什么
从技术上讲,当执行x=*k+1;
时,*k
的值是不确定的,因为它指向z
,并且z
当时未初始化。这意味着该值要么是未指定的(即,它可以有任何值)要么是陷阱表示(即,它不表示有效值,并且在读取时可能触发错误)。如果该值恰好是陷阱表示,则会调用读取
在某些情况下,读取未初始化的变量仍然可以是未定义的,即使它不是陷阱表示,但是这里的情况并非如此,因为z
已获取其地址
y:35
在这一点上:
*k = *k * (*k + 1);
y = x + y;
k
指向x
,4的值为4,因此第一行与x=4*(4+1)
相同。这将x
设置为20,然后将其与y
(15)的当前值相加,得到35
z:ffff ffff,为什么
p:5c9b1748。为什么
请看以下几行:
p = a;
p = p + 2;
z = *p - 4;
第一行将p
指向a
的第一个元素,该指针的值为5a9b1740,与第一行printf
中的值相同。下一行将其指向该元素之后的两个元素。假设系统上的int
为4字节,这意味着指针的原始值增加了2*4=8p
的值现在为5a9b1740+8=5a9b1748
当
p
现在指向a
的第三个元素,该元素的值为3时,下一行将z
设置为-1。然后使用%x
格式说明符打印该值,该说明符将该值解释为无符号int
并以十六进制打印。假设2的补码表示为负数(再次)给一个4字节的int
进行编号,该值的表示形式为ffffff
。当读取为无符号int
时,这就是打印的地址。p:5c961748这是数组a[]在内存堆栈中放置的地址。只需调用“a”表示a的地址,它相当于“&a[0]”,因此它是数组中第一个元素的地址。在第二个printf
调用中,z
的十六进制值ffffffff
取决于一个未声明的假设,即unsigned int
正好是32位宽。unsigned int
由于十六进制值5c961740,已知至少是31位宽代码>先前打印。十六进制值5c961748
为int y = 15; // y is defined and set to value 15
int *k = &x; // pointer k is set to point x
int z; // z is defined but uninitialized
int *p; // pointer p is defined but uninitialized
*k = *k * (*k + 1);
// k was set to point x (above)
// so, *k = x
// and x = x * (x + 1) => x = 4 * 5 = 20
y = x + y
// y = 20 + 15 = 35
k = &z;
// k is set to point z (but z is still uninitialized)
int a[] = {7, 9, 3, 8};
// array 'a' is defined
p = a;
// p is set to point the first int element of array 'a'
printf("%x\n", (unsigned int)p);
// printing the memory address of p
// same as printing the memory address of array 'a'
x = *k + 1;
// k was set to point z
// but z is still uninitialized
// so, x = z + 1 is unpredictable so far
// x is, whatever the value z plus 1
p = p + 2;
// p was set to point first integer element of array 'a'
// so, after p = p + 2, p = address of 'a' + 2 * sizeof(int)
// since sizeof(int) = 4 bytes, p is now address(a) + 8
// p is now pointing to the third element of array 'a'
// that is, p is pointing to '3'; *p = 3
z = *p - 4;
// p was set to point third element of array 'a'
// *p was '3'
// so, z = *p - 4 means z = 3 - 4 = -1
printf("%d %d %x %x\n", x, y, z, (unsigned int)p);
// x is, what ever the value of z plus 1
// y is 35
// z is -1; its hex representation if ffff ffff
// p is address of array a plus 2; p = &a[0] + 2
// that is; p is now, address of array 'a' + 2 * sizeof(int)
*k = *k * (*k + 1);
y = x + y;
p = a;
p = p + 2;
z = *p - 4;