回 帖 发 新 帖 刷新版面

主题:还是关于指针

先贴代码:


    int zippo[4] = {10, 20, 30, 40};
    int * p = zippo;

    printf("取值%d 地址%p\n", *p, p);    /* 第一条printf */
    printf("取值%d 地址%p\n", *p, p++); /* 第二条printf */

我心里认为打印的结果是:
取值10 地址0X22FF60
取值10 地址0X22FF60
因为第二条printf指针p使用的的++是后缀形式,可是真正的打印结果却很诡异
取值10 地址0X22FF60
取值20 地址0X22FF60

间接取值的结果为什么不一样?那从代码和实际打印的结果来看,好像顺序反了。。。


为了弄明白事情真相,我又改了代码:
    int zippo[4] = {10, 20, 30, 40};
    int * p = zippo;

    printf("取值%d 地址%p\n", *p, p);    /* 第一条printf */
    printf("地址%p 取值%d\n", p++, *p); /* 第二条printf */

我心里认为结果是:
取值10 地址0X22FF60
地址0X22FF60 取值20

实际结果却是:
取值10 地址0X22FF60
地址0X22FF60 取值10

我觉得事情越来越诡异,顺序好像是反过来的……第二条printf的取值应该是zippo的第二个元素20啊,怎么会是10呢,纳闷。


我又改了代码,把两条printf语句整合成一条:
    int zippo[4] = {10, 20, 30, 40};
    int * p = zippo;

    printf("取值%d 地址%p 地址%p 取值%d\n", *p, p, p++, *p);

我认为结果是:取值10 地址0X22FF60 地址0X22FF60 取值20

可是实际打印结果是:取值20 地址0X22FF64 地址0X22FF60 取值10

天啊,这都怎么回事啊?是编译器的问题还是自己的问题啊,那个地址是编译器给的,抄出来希望能更好讲述我的问题。我真是二丈和尚摸不着头脑啊,想了几天还是找不出个能解释这种现象的理由,实在是太郁闷了。

求讲解、求指点。最好能详细一些,我不知道因为怎样百度能找到我想要的答案……所以,求助没有办法的办法,我也知道自己想出来能自己最有帮助,可我实在是想不出,为何结果是这样的。哪里有说得不对请指出,我使用的编译器是Dev-c++

回复列表 (共16个回复)

沙发

你代码的操作属"未定义"行为,ANSI C没有具体的标准,各种编译器会给出不同的解释;gcc可能会是从代码的右端开始进行的。
c primer plus 中建议不要使用这样的操作。

板凳

未定义?怎么说?

3 楼

在您的编译器中,printf打印是从右端开始的。从右边到左来计算便可理解了。

4 楼

不要在函数调用时又用X++又用X,这样就是未定义的。。。

5 楼


难道指针不能这样用吗?书中并没有说到呀,我不能理解

6 楼

教科书没说的东西海了去了。
注释
缩进
风格
版本管理
……
我们跟你说绝对不是在害你,而是在帮你。

7 楼

[quote]在您的编译器中,printf打印是从右端开始的。从右边到左来计算便可理解了。在函数中都这样的
[/quote]

8 楼

我不是那个意思,我是说,书里没有说而已

9 楼

嗯,我们也没有别的意思,只是一本书确实难以容下太多的东西,而BBS正好弥补了这个不足:)

10 楼

确实,一两本书不可能容纳很多东西。有的东西要多参考别人的意见,然后自己在多思考,并且也不见得自己能够思考得全面。在BBS中把问题贴出来,和大家讨论, 结合几个人的思路也许就豁然开朗了。
那时侯刚来论坛的时候,很多大牛热心的帮我解决问题,感觉那段时间进步的很快。
比如说为什么printf("取值%d 地址%p\n", *p, p++); 这样的语句是未定义的呢?我是这样理解的:
一般而言,编译器会这样来处理这个语句:
   1. 把最右边的p如栈
   2. p自增
   3. 把*p入栈
   4. 把字符串"取值%d 地址%p\n"入栈
   5. 调用函数printf
这样,很显然1,2和3是有数据相关的,在执行3以前2必须完成,2以前1必须完成。
还有一种是这样
   1. 把最右边的p如栈
   3. 把*p入栈
   4. 把字符串"取值%d 地址%p\n"入栈
   2. p自增 //也可能放的5后面
   5. 调用函数printf
这样1和3,4这三个语句基本上可以同时执行,很显然这样的效率要比上面的好一些。
但是前面那种情况让人更容易理解。 c标准并没有把它规定死,把它留给实现者来决定。

未定义的行为并不是错误,可以这样用(但最好不要这样用,除非您完全不要考虑移植)。

我来回复

您尚未登录,请登录后再回复。点此登录或注册