zoukankan      html  css  js  c++  java
  • 两道题题引发的思考

    两道题题引发的思考

    写在前面

    下周的讨论课又到我讲论文了,这几天都在看论文、准备ppt,选了一篇好难的论文啊,看了这么久了,还是不够清晰。。。所以决定先换下思路,做点题。

    题1

    下面的代码输出是什么

    void add(int *p)
    {
        (*p)++;
        printf("%d",*p);
        if (*p>5)
        {
            return;
        }
        add(p);
    }
    
    int main()
    {
        int i=0;
        add(&i);
        
        system("pause");
        return 0;
    }
    

    分析
    这个题目看起来还是比较友好的。首先我们来分析一下add()函数。其实看名字就能知道它是在做加法啦,不要更明显好吗=。=
    这个函数没有返回值,函数参数是一个int型的指针,函数体中首先对指针p指向的内容做自增操作,然后打印出自增后的值,接着判断自增后的值与5的关系,如果大于5,则返回。
    接下来看看main函数在干啥。main中首先声明了一个int型的变量i,并初始化为0,然后把i的地址传入add函数中。
    最后看看函数的执行过程:
    第一步:i = 0,执行add(0),则*p = 0,执行(*p)++后,*p = 1,因此打印出1, 此时 *p >5不成立,因此执行add(1)
    第二步:add(1), 则 *p = 1, 执行(*p )++后,*p = 2,因此打印出2, 此时 *p >5不成立,因此执行add(2)
    。。。
    第五步:add(4), 则 *p = 4, 执行(*p)++后,*p = 5,因此打印出5,此时 *p >5仍然不成立,因此执行add(5)
    第六步:add(5),则 *p = 5, 执行(*p)++后,*p = 6,因此打印出6, 此时 *p >5成立,因此函数返回
    所以最后的输出是:123456,运行截图如下:
    enter description here

    题2

    下面的代码输出是什么

    int main()
    {
        int a[5]={1,2,3,4,5};
        int *p=(int *)(&a+1);
        printf("%d",*(p-1));
    
        system("pause");
        return 0;
    }
    

    这个题目看起来就不如第一题那么容易了。在没有运行代码之前,我是这么理解的:&a就是数组的首地址,也就是a[0]的地址,那么&a+1应该就是a[1]的地址了,也就是说p指向a[1],最后输出*(p-1),那么应该输出的是a[0],结果应该是1。竟然已经分析到这了,那我们先看看结果吧:
    enter description here
    突然有种被打脸了的感觉。。。这和我预期的不太一样啊。为什么会这样呢?
    为了更好的理解这个结果,我们将上述代码进行拆分,并把中间结果也输出来观察
    首先,输出&a+1和&a以及&a[0],它们是内存中的三个地址,分别如下:
    enter description here
    从输出中可以看出,&a和&a[0]是同一个地址,而&a+1是&a上进行了偏移。为了计算这个偏移量,我手动用计算器计算了两个地址之间的偏移量,得出的结果是14。到这里的时候我直接懵了,14是个什么鬼?从哪里冒出来的?为啥不是4?就算不是4,那也应该是4的倍数的吧?这个14真的是让我困扰了好久。一开始我以为是自己在计算器上输入错了,但是测试了几遍,都是这个结果。然后我真的好懵。。师兄过来说,你用的是十六进制啊。。。那十六进制的14不就是20么,20?不就刚好是数组的大小么?这个时候似乎有些豁然开朗了。。
    事实上,尽管&a和&a[0]是相同的,但本质上是有所区别的,a是一个数组起始地址,而a[0]只是数据第一个元素的地址,&a+1是在&a的基础上偏移了“一个单位”,而这“一个单位”,是a指向的内容占的空间,也就是整个数组的空间,因此这个时候&a+1并不是指向a[1], 而是下图中紫色的位置。因此很容易看出*(p-1) = 5.
    enter description here
    而&a[0]+1是在a[0]的基础上偏移“一个单位”,此时的“一个单位”是以a[0]为参考的,因此是4个字节。
    我们可以再添加几句打印语句:

        cout<<(&a+1)-&a<<endl;
        cout<<(int *)(&a+1)-(int *)&a<<endl;
        cout<<(char *)(&a+1)-(char *)&a<<endl;
    

    enter description here
    看到上图中的结果了吗?对于第一句,a是一个单位,因此&a+1只比&a多了1
    而第二句中,我们把这个单位转换为int *了,a数据里面有几个整型数据呢?当然是5啦
    对于第三句,把单位转换成char *,那么一个包含5个整型的数组的大小自然是20了,这时的单位就是字节了
    把数组类型改成double也是一样的道理,只是最后一句话打印的结果是40。换成char数组也是相似的,只是要注意char数组中,默认最后一个字符是。

    总结

    又是关于指针的,看来是该找个时间总结一下指针的一些常见用法了,今天先到这里了,滚去看论文了。。

  • 相关阅读:
    CodeForces 19D Points (线段树+set)
    FZU 2105 Digits Count
    HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
    HDU 5634 Rikka with Phi (线段树)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
  • 原文地址:https://www.cnblogs.com/scut-linmaojiang/p/5317056.html
Copyright © 2011-2022 走看看