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

时间:2015-01-24 17:08:26

标签: c pointers

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

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

4 个答案:

答案 0 :(得分:1)

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

*p = 100;

答案 1 :(得分:1)

p未指向数组,因此表达式*(p-1)具有undefined behaviour。这意味着,一旦*(p-1)=100被执行,从技术上讲,程序可以以任何方式运行。

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

如果您Valgrind代码,该工具会将其标记出来。

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

@valtah和@NPE的回复是正确的。如果你更详细地了解发生了什么,你可以看到原因:

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

----------------------------------------------------------
   SP| saved state | return address |  a   |   b  |  p  |
-----------------------------------------------------|----
                                       ^             |
                                       |             |
                                       .-------------'
                                      &a

您会看到&amp; a是a存储在堆栈中的地址,并且也分配给p。当您使用值(p-1)时,它可能会计算堆栈中其他位置的位置。 (一个好的编译器会知道它不是一个数组指针,并且此时会产生语义错误。)许多编译器只会计算地址。为其指定值时,可能会将一个项目的值更改为a的地址。这可以是b,也可以是返回地址。然后,这会改变程序的执行状态。

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

现在我想到了这个问题。该代码来自哪里?你是在写它,还是在某处读过它。它肯定告诉专家你正在使用的代码类型......

: - )