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数组中,默认最后一个字符是。

    总结

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

  • 相关阅读:
    Boot.ini
    CCP4 SET
    Install GTK+ GLIB
    C head file
    Changes in Python
    ubuntu
    错误: 配置节中设置 validateRequest=false 可以禁用请求验证
    c++中冒号(:)和双冒号(::)的用法
    C++学习之类和结构体
    C++中双冒号的作用
  • 原文地址:https://www.cnblogs.com/scut-linmaojiang/p/5317056.html
Copyright © 2011-2022 走看看