我不了解C ++指针算法

时间:2014-12-31 11:30:24

标签: c++ c pointers integer pointer-arithmetic

我有以下程序,它定义了2个整数和一个指向整数的指针。

#include <stdio.h>

int main() {

    int bla=999;
    int a=42;
    int* pa=&a;

    printf("%d \n", *pa);
    printf("%d \n", pa);

    pa++;
    //*pa=666; //runs (no error), but the console is showing nothing at all

    printf("%d \n", *pa);
    printf("%d \n", pa);

    pa++;
    //*pa=666; //runs and changes the value of *pa to 666;

    printf("%d \n", *pa);
    printf("%d \n", pa);

}

输出结果为:

42

2686740

2686744

2686744 //这个值很奇怪,我想

999

2686748

地址对我有意义,但第四个值很奇怪,因为它正是int的地址。有人可以解释这种行为吗?

当我评论* pa = 666(第一个外观)时,控制台什么都没有显示,所以这里有一些错误,但编译器没有显示错误。也许这是因为我的系统上的int的大小,我有一个64位的Windows-os,所以也许int是64位而不是32?并且因为在第二次增量之后* pa值是999而不是第一次增加?

我确信,有很多C程序员可以解释发生了什么:)

6 个答案:

答案 0 :(得分:5)

int* pa=&a;

pa是指向整数的指针,并且定义了访问*pa

指针递增后,指针指向某个内存(在p之后),这个内存未由您分配或者您不知道,因此取消引用它会导致未定义的行为。

pa++;

*pa是UB

编辑:

使用正确的格式说明符打印@haccks指出的指针值%p

答案 1 :(得分:2)

您使用错误的格式说明符来打印地址。这将调用未定义的行为,并且一旦调用UB,所有投注都将关闭。请改用%p

printf("%p \n", (void *)pa);  

另一个问题是执行pa++;后,您正在访问未分配的内存和UB的另一个原因。

答案 2 :(得分:2)

输出并不奇怪,可以预料到:main()中有三个变量,所有这些变量都存储在堆栈中,并且恰好是一个接着一个。其中一个变量是指针本身。因此,当您取消引用第三行中的指针时,您将获得指针本身的当前值。

然而,这个输出是不可预测的,它是未定义的行为:你只允许使用指针算法来访问单个内存对象中的数据,在你的情况下,内存对象只是一个int 。因此,在第一个*pa之后访问pa++是非法的,并且该程序可以从该点开始执行任何操作。

更具体地说,不能保证哪些其他变量遵循某个变量,它们遵循哪个顺序,或者根本没有可访问的内存。即使在第一个*pa之后阅读pa++也会导致程序崩溃。正如您所见,在许多情况下您将不会遇到崩溃(这很容易调试),但代码仍然深受打击。

答案 3 :(得分:2)

你并不比编译器聪明。

正如另一个答案所说,你所做的是未定义的行为。使用pa你只是做无意义的,它与定义目标的任何可推算的算法都不对应:它没有意义。

但是我会向你提出一个可能出现的情况。虽然很多都可能是错误的,因为编译器会进行优化。

int bla=999;
int a=42;
int* pa=&a;

这些变量在堆栈上分配。

撰写pa = &a时,您说“我希望指针pa等于a的地址”。

编译器可能已经按顺序或声明分配了内存,这可能会产生类似的结果:

  • bla的地址为0x00008880
  • a的地址为0x00008884
  • pa的地址为0x00008888

当你执行pa++时,你告诉:将int的指针移动到内存中int的下一个位置。 由于整数是32位,因此您正在进行pa = pa + 4bytes,即pa = 0x00008888

请注意,偶然!,您可能指向pa指针的地址。 所以现在指针pa包含它自己的地址......这非常深奥,可以被称为ouroboros

然后你再问pa++ ... pa = pa + 4 bytespa = 0x0000888c

所以现在你可能正在访问一个未知的内存区域。它可能是访问冲突。如果您想要阅读或写作,这是未定义的行为。

答案 4 :(得分:1)

当您第一次指定指针时,它指向2686740。指针是一个整数指针,整数使用4个字节(通常,在你的机器上它使用4个字节)。这意味着pa++会将值增加到4,即2686744。再做一次导致2686748

如果要查看生成的汇编代码,可以切换局部变量的顺序。代码运行时,排序为apabla。由于您没有明确控制此排序,因此打印输出被视为未定义

在您第一次执行pa++指针指向自身之后,这就是您获得&#34;奇怪值的原因&#34;

正如许多其他答案所提到的,这不是指针的好用,应该避免。在这种情况下,您无法控制指针指向的内容。更好地使用指针算法将指向数组的开头,然后执行pa++指向数组中的下一个元素。您可能遇到的唯一问题是递增超过数组的最后一个元素

答案 5 :(得分:0)

您是否尝试通过指针a增加*pa中的值?

如果是,请执行:(*pa)++。括号是至关重要的,因为它们意味着“获取指针的值”,然后使用该地址递增引用的任何内容。

这与*pa++完全不同,*pa只返回{{1}}指向的值,然后递增指针(而不是它引用的东西)。

C语法的一小陷阱。 K&amp; R有几页专门讨论这个问题,我建议你尝试一些例子。