2012年软考软件设计师辅导:C语言指针引发的联想

来源:微学教育网发布时间:2012-04-27

  刚接触编程的时候,用的就是C语言,学的时候用的开发软件是Turbo C,很经典的一款IDE了(现在应该没人在用了吧)。刚学习C的时候,主要就是学习其语法,先用一些语法来做出一些简单的小功能,写一些简单的小逻辑。

  学着学着,就学到了指针了,我记得那本书上讲了,指针是C的核心,学C语言一定要掌握指针。知道了其重要性之后,就更加认真地去学,不过当时还不清楚为什么C的指针是那么重要,它到底有什么影响。后来一步一步地学习,通过了解其它的相关知识,顺藤摸瓜地了解到了很多之前不懂的东西。我也十分不了解,为什么要叫成指针呢?当然我个人对这个名字还是挺不爽的。因为首先名字就给人感觉很深奥、很难以理解。

  其实说白了指针就是一种数据类型(int 、char、double),指针,说到底它还是一个变量,跟int、char类型的变量无性质差别。由于指针存的是一个内存地址,所以指针类型的变量所占的字节大小,会因它所处在的CPU所能寻址到的地址最大值有关。

  说到内存地址,那么必须简单了解下计算机的运作。一个程序是怎么运行起来的呢?这是CPU的功劳了,CPU的全称“中央处理器”,听到中央两个字就知道它有多么重要了。不过说白了CPU就是一个处理器,它处理的目标是指令,指令就是二进制,CPU它做的是最苦最累的一份活了,没有目的的,没有止境地读出一条指令,执行它,然后下一条,指令它,它的好处是,它不会出错,真有一天它出错了,那么一定是你的错。当你的CPU烧了的时候,请谅解它,并检讨下平时怎么虐待它的。然后再买个更经得起虐待的CPU。

  对了,CPU它的指令是从哪里来的呢?--可执行程序,可执行程序存在硬盘上,可是CPU到硬盘拿数据的速度太慢了(我也问过为什么不能做到很快)。众所周知,CPU运算速度那不是普通地快的,所以怎么能允许硬盘拖后腿呢,这样的话,变成CPU跟硬盘一样快了(不怕狼一样的敌人,就怕猪一样的队友,硬盘会降低CPU的智商的)?所以内存它登场了,CPU跟内存打交道的速度则相对较快,总之比硬盘快太多太多了(所以内存比硬盘贵,内存4G多少钱,硬盘500G多少?差价太多啦)。不过CPU其实还是不怎么喜欢跟内存打交道(主要原因还是:CPU真TM太快了,内存还是很慢),所以CPU跟内存之间本身还有一层缓存,就是我们平时说的一级缓存、二级缓存,这个缓存造价相对比内存要贵得多,所以容量也不大,这样就更需要有效地利用了。执行一个文件,大体的流程是这样:CPU从硬盘上读出这个文件,再把这个文件载入到内存上,此后就通过内存来交互了。

  内存,其实就是由很多个字节有序组成的一块东东,比如说1G的内存条,那么就是由1024*1024*1024大小的字节组成。记得我那时候刚接触计算机的时候,听说一个进程的内存空间是4G(32位操作系统,32位CPU下),那假如我仅有1G的物理内存呢(我配的电脑内存是1G的)?进程的内存是多少?还是4G!这就涉及到了虚拟内存的概念了。越扯越远了,虚拟内存就是把硬盘的空间当成“内存”来用,具体怎么用呢?其实就是交换了,把当前内存上的不那么重要的数据,写在硬盘上,腾出更多的物理空间来给我们的程序,那么硬盘充当的角色就是虚拟空间了,至于选哪些数据放到硬盘上,系统有它的一套选择方式。像WINDOWS下有pagefile.sys这个文件,linux下有swap分区,其实就是拿来做交换存放用的。由于上面讲过了,CPU直接读硬盘是非常慢的,虚拟内存是能力有限的,所以如果想机子快一点的话,还是乖乖地加多物理内存吧。

  对于汇编程序来说,基本上没有什么数据类型的概念的,在汇编程序中,如果想定义一个数字,要先衡量下这个数值将会用到的最大最小值,从而来决定要多少个字节来存储。是的,C的数据类型也是这个概念,int值跟short没什么本质差别,就是字节数的不同而已,C语言在编译的时候,就是把C代码翻译成汇编,所谓的编译器就是干的这事,它就是一个翻译软件,从一门语言翻译成另一门语言,如果定义了一个int变量,那么编译的时候,编译器会分配4个字节的空间来存放那个变量(不考虑字节对齐的情况)。

  为啥说C语言是一门很灵活的语言呢?那是因为它有了指针,为什么指针就那么了不起呢?原因很简单,你可以访问整个内存地址,你想访问哪里,就直接指过去,比如你知道在内存里第0x1000个字节里面存有你需要的数据,你可以直接把一个指针赋值成0x1000,然后通过*号进行解引用取得值(在以前的操作系统中,操作内存的自由度比较高,但在现在整个物理内存的管理是由操作系统管理好的了,每一个字节都在它的掌握中,你乱指的话,系统直接把你崩溃掉,至少你的程序不会影响到其它进程)。C提供的思想是:程序员永远都清楚自己在做什么,就算指针乱指(野指针)导致程序错误,那么也是由程序员自己负责,所以……,指针这把锋利的刀,用起来方便,但也很容易伤了自己。跟其它语言不一样,像JAVA里面只有引用,引用原理上来讲也是一个指针,但是这个指针并不能让你随心所欲地用,这个引用只能指向你可以指的东西。因为JAVA本身有对引用进行管理,所以安全性则相对较高。

  对于指针,最常见的情况下是用来对某一个变量做修改,如果在一个函数里面传一个int值的参数进去:

   int fun(int a)

   {

   a = 10;

   return a;

   }

   int b = 0;

   fun(b);

  这样调用后b是不会有变化的,因为传进去函数的参数,在传进去的时候,仅仅只是一个拷贝而已,但是如果

   int fun(int* a)

   {

   *a = 10;//通过解引用给那个地址里面的内容赋值成10

   }

   fun(&b);

  这样把b的地址传过去,那么a就是b的地址的拷贝(这里也是有拷贝,只是说拷贝的是一个地址,并不是内容),但是通过a里面存着的地址,从而找到这个地址里面的内容(星号是取地址内容),把这个地址的内容改写成10,那样的话,b才真正给改变了。

   OK,乱扯完毕,可能有些东西并不是太严谨,不过大体意思知道就好了。