Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C代码、指针及其内容。试题_C_Pointers - Fatal编程技术网

C代码、指针及其内容。试题

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 *

我有一个旧考试的代码

第一次打印生成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 *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/w
print
行的第一和第二个结果

让我们一行一行地说:

  • 第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=8
p
的值现在为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;