指针算法:C 程序中的奇怪结果


#include<cstdio>
int main(){
    int a=10,b=20;
    int *p=&a;
    *(p-1)=100;
    printf("%d, %d, %dn",a,b,*(p-1));
//  printf("%d, %d, %dn",&a,&b,(p-1));
    return 0;
}

为什么第一个 printf(第 6 行)显示的结果不同,无论第二个(第 7 行)是否在注释中?我正在使用 C 编译器(TDM-GCC 4.8.1 64 位)

p不指向数组,因此表达式*(p-1)具有未定义的行为。这意味着,一旦*(p-1)=100被执行,从技术上讲,程序可以按照它喜欢的任何方式运行。

在实践中可能发生的情况是,您正在覆盖堆栈上的一些内存,这可能会导致各种副作用。

如果你对代码进行Valgrind,该工具将标记它。

您的代码会递减p指向的内容并在那里存储 100。由于p被初始化为a的地址,因此您将100存储在某个随机内存地址。 我想你想要:

*p = 100;

您正在尝试修改派生指针p的对象a之外的内存位置。结果是未定义的行为,这意味着任何结果都是可能的,甚至是看似不可能的结果。

为您的

问题给出明确答案的唯一方法是检查编译器的汇编器输出(如果可以获得此类输出)或生成的机器代码。在这种情况下,对象a通常会在堆栈上分配,并且其他printf调用的存在可能会更改编译器在同一代码块内的堆栈上分配项的方式。

@valtah和@NPE的回复是正确的。如果你更详细地了解正在发生的事情,你就会明白为什么:

如果我们查看此执行的堆栈帧(或激活记录):

----------------------------------------------------------   向上:保存状态 |退货地址 | 一 |  乙 | P |-----------------------------------------------------|----                                       ^             |                                       |            |                                       .-------------'                                      &a

您将看到 &a 是堆栈上存储a的地址,这也分配给p 。当您使用该值 (p-1) 时,它可能会计算堆栈上其他位置的位置。(一个好的编译器会知道它不是一个数组指针,并在这一点上给出语义错误。许多编译器只会计算地址。当您为其赋值时,可能会将一个项目的值更改为远离 a 的地址。这可能是b,也可能是退货地址。然后,这将更改程序的执行状态。

这正是代码注入攻击用来控制系统的机制。这是安全违规代码。

现在想到了一个问题。这些代码从何而来?你是写的,还是在某处读过的。它肯定会告诉专家您正在使用的代码类型......

:-)

相关内容

最新更新