zoukankan      html  css  js  c++  java
  • C语言学习趣事_戏说间接引用和解析引用

          在C语言中,对变量的使用实质上是对计算机内存中存储内容的访问,通过对内存空间的引用来实现写入和读取。(注:C中有一个特殊的关键字register,

    用来声明非存储在内存当中的变量,register用来要求将变量存储在计算机的寄存器当中,这样的变量主要的目的是加快CPU访问的速率)REGISTER关键字是

    特定时期的产物,在内存访问速度很慢的时代用register定义的变量,确实存储在计算机CPU的寄存器当中,现在来说由于内存的访问速率也很快,很多编译器在

    编译的时候,会将register变量也存储在内存当中。这里主要讨论简介引用和解析引用,因此对register就不再讨论。

          间接引用是指在汇编语言指令中不直接指出内存的地址,而是通过一个寄存器或者一个内存空间来访问另外一个内存空间。

    Exp:

          mov    ax,[bx]

    这样就实现了一个间接引用,这条语句并不是直接的访问bx寄存器,而是访问bx指向的内存空间。在C中我们通过指针来实现间接引用。

    Exp:

            int     var1;

            int      *pvar=NULL;

            pvar=&var1;

            *pvar=10;

    这样就实现了一个间接引用,通过一个内存空间来访问另一个内存空间,于是就实现了间接引用。在计算机的世界里面间接引用也叫做间接寻址。

    上面的C语言实现翻译成汇编指令可能为下面的形式:

           mov    [ax], 10       ;ax中存储的内容就是变量var1的内存地址,实际上还可能涉及到物理地址的偏移量计算

    汇编语言与C语言的最大区别就是可以显式的访问寄存器和直接计算得到某个内存地址,其他的像循环语句等其他C语言控制结构在汇编中一样可以实现,

    在汇编语言中可以显式的指定程序执行的开始地址,可以通过ORG指令来实现,具体就不讨论了。

    1、间接引用

         我们可以通过几个实例来看看间接引用:

         int  var1;

         int  var2;

         int  *pvar1=NULL;

         int   **pvar=NULL;

          pvar1=&var1;  //间接引用的必须条件,通过 & 运算符来实现将一个内存空间的地址放到另外一个内存空间中。

          pvar=&pvar1;  //间接引用, 因为pvar1也是一个变量,指针变量,因此在C中也有一个与之对应的内存空间,

          *pvar1=10; //这里的意思就是将整型字面值放到*pvar1指向的内存空间,

          pvar=&var2, // 这里是不对的,虽然我们也可以通过一定的方式使之可以顺利的运行,但是如果那样做的话,可能会引入未知的错误。

    如果实在想通过pvar来间接引用var2的话,怎么办呢? 那就和下面一样:

          *pvar=&var2;

    然后像下面这样来引用var2;

          *(*pvar)=10;   //var2=10

    2、解析引用

        我也不知道这么说是否恰当,但是 * 运算在对地址进行运算的时候,很多权威的文档都这么说,我也就跟着说了,其实*的解释没有什么

    特别的,那就是:

         *  取出的是存储在一个内存空间区域(内存区域1)的内容,并且将取出的内容解释为另外一块内存区域(内存区域2)。然后我们就可以对

    内存区域2进行访问。

         如果进行多重的解析运算,那么就会涉及到更多的内存区域, 就像前面所说的:

    Exp:

         int  var1;    //var1 内存空间1,这里可以简单理解为 var1这个标示符指向内存空间1,虽然我们并没显式的指出这个指向

         int  var2;    //var2 内存空间 2

         int  *pvar1=NULL; //pvar1 内存空间3

         int   **pvar=NULL;// pvar  内存空间4

         pvar1=&var1;    // 将内存空间1的位置放置到内存空间3里面,形成了一个指向关系 

         pvar1=10;      //将整型字面值10,放置到内存空间3指向的内存空间 1 里面。

         *pvar=&pvar1, // 形成一个多重指向,pvar 指向 pvar1, 而**pvar将指向  内存空间1 

    3、 关于定义指针变量解析运算符的位置

    Exp:

          int  *p;

        int*   p;

    上面的两种定义的方式在本质上没有区别, 但是如果涉及到更多的变量定义的话就可能引起误解。

    我的习惯是每个变量定义单独占用一行:

    Exp:

          int   *p1,

                 *p2;

    这样就很清楚了。

    如果涉及到typedef的话,那么就会另外的情形了,

    Exp:

         typedef   int     *INT;

         INT   var1;

         INT   *var2;

    很不幸的是很多人在这个地方会犯错, 我也曾经犯过错,原本想声明一个指向int变量的指针var2,结果是定义了一个指向int *类型的指针

    变量。

    现在我的习惯是: 

        1、在非typedef定义时*运算符靠近变量

        2、在typedef定义新的的类型标示符时*靠近原来的类型标识符。

    Exp:

        int   *p,   *pp;

        typedef    int*   PINT;

    这样意图就很明显了,并且不容易引起误解。

    4、指针的四则运算

       两个指针变量相加是未定义的行为, 

       两个指针变量想减的结果返回两个内存空间的距离,

       两个指针变量相称是未定义的行为,

       两个指针变量相除是未定义的行为,

       指针变量和整型值相加减是指针移动其指向的位置。

       指针变量和整型值相乘除是未定义的行为。

    Exp:

        size_t   (strlen)(const char *str)

        {

             char *start;

             start=str;

             while(*start)

              {

                     start++;

               }

              return  (start-str);

         }

    5、 理解指针

         理解指针最主要的是要有指向的概念,如果单纯的从变量存储的角度来理解,可能会遇到很多疑问。

       

         指向这个词还真有点特殊,关键是要明白间接引用。

            

  • 相关阅读:
    Android 五大布局
    jdk6的安装以及环境变量的设置
    PLSQL Developer图形化窗口创建数据库全过程
    未能加载文件或程序集“Oracle.DataAccess, " 64位OS运行32位程序的问题
    Android SDK 无法连接到GOOGLE 下载安装包
    Android开发之旅:环境搭建
    Android开发把项目打包成apk
    在 VMware Workstation 虚拟机中创建共享文件夹的步骤〔图解〕
    谈谈对于企业级系统架构的理解
    C#图片处理之: 获取数码相片的EXIF信息
  • 原文地址:https://www.cnblogs.com/volcanol/p/2189690.html
Copyright © 2011-2022 走看看