指针理解之指针“起源”

看到一篇“指针”的帖子,也想总结一下自己对指针的理解,希望对刚接触编程,刚接触指针的人有帮助。

1.“什么是指针”:类型一组值一组操作的集合,指针类型占一个字长的空间取值范围:0~2^n(n是字长),操作不同于其他类型的便是取地址内容操作,即指针空间的数据作为地址,取指针空间中地址所指向空间中的数据。
指针起源指针不是C语言的独创术语,而是计算机语言无法回避的一个问题存储空间的地址(位置)。无论是指令码还是数据码,都存处在一定存储空间,我们调用的不论是指令码还是数据码都需要知道它所在的存储位置,而“指针”标明,指出了他们所在位置,就像指南针一样,多么形象而贴切的一个计算机术语

但初接触计算机编程的人,没有计算机体系模型的概念,尤其是存储空间(flash,rom,ram,寄存器),被指针一会是数据有一会是地址,颠来覆去,便云里雾里不知在讲什么了。指针的“数据”是对指针变量而言,指针变量空间存的就是指针变量的数据,不过这个数据不是我们想要的数据,而是我们想要的另一个数据所在的存储空间位置,所以地址是对另一块存储空间而言的。
指针这块容易混淆的概念是:指针类型指针基类型。指针类型:空间占一个字长,一般是4字节,32位,有别于其他类型的操作取地址,或者说把自身空间中存的数据,作为地址(将数据再次打入地址寄存器AR,这一块可以看《计算机组成原理》指令执行流程那一部分),取地址空间的内容。指针基类型:是指指针所指向空间的数据类型,可以是基本数据类型char,int,float,double,也可以是自定义类型struct、class,也可以是程序代码区。

指针概念很重要,因为我们在存取大量数据时,不论是大量代码数据(比如中断(调用函数,切换任务)),还是大量一般大量数据(数组、字符串、文件),我们只需要知道要存取大量数据所在的空间就可以了,我们一般存取这些空间的首地址(子程序代码空间所在地址,任务代码所空间的首地址,数组、字符串、文件等大量数据所在空间的首地址)。操作系统里有大量的指针类型,频繁利用指针,指针让数据传递灵活,操作系统代码简洁。


附1:指针的一些概念

1、什么是指针
  指针是一种数据类型,与其它的数据类型不同的是指针是一种“用来存放地址值的”变量。举一个简单的例子:
如果定义了一个整型变量,根据整型变量的特点,它可以存放的数是整数。
如:int a; a=100; 这样就把整型常量赋给了变量a。但是如果写成这样:a=123.33;就会出问题,最后输出变量a的值结果是123。现在说到指针,其实地址值也是一个整型数,如某某变量的地址值为36542,说明这个变量被分配在内存地址值为36542的地方。能不能这样进行推理,既然地址值也是整型数,整型变量正好可以用来存放整型数,那不是一个整型变量可以用来存放地址的值吗。程序写成下面这样:
  int a,b;
      a=&b;
很明显,这样写是错误的。原因在于不能简单地把地址理解为整型数。
应有这样的对应关系: 地址值<--->指针;  整型数<--->int 型变量。
所以有这样的说法:“指针就是地址”(指针就是存放地址值的一种数据类型)
  下面是一段正确的程序:
  int a,*p;
      p=&a;    /*把变量a的地址值赋给指针p*/ 

2、什么是void指针
  void的意思就是“无值”或“无类型”。void指针一般称为“通用指针”或“泛指针”。之所以有这样的名字是因为使用void指针可以很容易地把void指针转换成其它数据类型的指针。例如在为一个指针分配内存空间的时候:
      int *p;
      p=(int *)malloc(......);  本来函数malloc的返回值是void类型,在这里通过在前面加上一个带括号的int*就把void*类型转换成了int*类型。
  所以不能简单的把void看成“无”的意思。void数据类型是一种很重要的数据类型。

3、指针可以相加减吗
  可以相互加减。但是一定要作有意义的运算。当二个指针指向同一个数组的时候,它们相加减是有意义的。如果二个指针分别指向二个不同的数组,那么指针之间的相加减就没有什么意义。指向同一个数组时,其相加减的结果为二个指针之间的元素数目。

4、什么是NULL指针
  NULL指针是不指向任何一个地址的指针。这样的指针一般是允许的。当一个指针为NULL的时候,不要对它进行存取。

5、什么是“野”指针
  野指针是不由程序员或操作者所能控制的指针。当在一个程序里面定义了一个指针而又没有给这个指针一个具体地址指向的时候,这个指针会随意地指向一个地址,这样的指针就是一个野指针。如果这个地址后面的内存空间没有什么重要的数据则不会造成不好的后果,但是一旦这里面存放了有用的数据,那么这些数据随时都有被野指针存取的危险,如果这样,数据就会被破坏,程序也会崩溃。所以在程序里面是一定要禁止任何野指针的存在。当定义了一个指针的时候,要马上给这个指针分配一个内存地址的指向。这样程序才不会因为指针而出现意外。

6、NULL是什么
  NULL不是被定义为0就是被定义成(void *)0,这二种值基本上是一样的。
  如有这样的语句: if(p==NULL) 或者写成 if(p==0) 其作用是一样。

7、什么是“内存泄漏
  当定义了一个指针的时候,立即要为这个指针分配一个内存空间。这只防止了野指针的产生。当一个指针使用完毕要立即释放掉这个指针所占用的内存空间---这有二方面的意义:  1)避免了内存空间的泿费; 2)防止了内存泄漏。为什么会产生内存泄漏:如果没有及时释放掉指针所占用的内存空间,而在下次使用这个指针时又给这个指针分配了内存空间,这样的次数一多,内存空间就慢慢被消耗掉了。所以形象地称这种现象为内存泄漏。
  如下面这样一个程序:
  void *p;
      for(;;)
      p=malloc(20);      /*这20个字节的内存空间是随意指定的*/
这样的一个小程序,大家不要随便运行它。你可以在集成环境中单步调试运行,可以看一下每步运行后的结果。可以看到,每一次循环都会“吃掉”20个字节的内存,无数次之后,再多的内存也慢慢地“泄漏”,最后没有内存可用就死机。(与这个程序配合需要一段检测整机总的内存容量的程序,以观察内存总量的变化。这里虽然没有这一段程序,但是看得到每次分配的内存地址值是不相同的)

8、near指针和far指针
      在DOS下(实模式)地址是分段的,每一段的长度为64K字节,刚好是16位(二进制的十六位)。
near指针的长度是16位的,所以可指向的地址范围是64K字节,通常说near指针的寻址范围是64K。
far指针的长度是32位,含有一个16位的基地址和16位的偏移量,将基地址乘以16后再与偏移量相加,(所以实际上far指针是20位的长度。)即可得到far指针的1M字节的偏移量。所以far指针的寻址范围是1M字节,超过了一个段64K的容量。例如一个far指针的段地址为0x7000,偏移量为0x1244,则该指针指向地址0x71224.如果一个far指针的段地址是0x7122,偏移量为0x0004,则该指针也指向地址0x71224。
      如果没有指定一个指针是near或far,那么默认是near。所以far指针要显式指定。far指针工作起来要慢一些,因为每次访问一个far指针时,都要将数据段或程序段的数据交换出来。另外,far指针的运算也比较反常,例如上面讲到的far指针指向同一个地址,但是比较的结果却不相同。

9、什么时候使用far指针
        当使用小代码或小数据存储模式时,不能编译一个有很多代码或数据的程序。因为在64K的一个段中,不能放下所有的代码与数据。为了解决这个问题,需要指定以far函数或far指针来使用这部分的空间(64K以外的空间)。许多库函数就是显式地指定为far函数的形式。far指针通常和farmalloc()这样的内存分配函数一起使用。

10、c语言:
(1).int *p;

(2).int **p;

(3).int *p[10];

(4).int (*p)[10];

(5).int *p(int);

(6).int (*p)(int);

(7).int (*p[10])(int);

含义:

1.一个指向整型数据的指针

2.一个指针的指针,它指向的指针指向一个整型数据

3.一个有十个指针的数组,该指针指向整型数据

4.一个指向有十个整型数据数组的指针

5.就一个函数(不是函数指针),该函数有一个整型参数,返回值为一个指向整型的指针

6.一个函数指针,该函数有一个整型的参数,返回值为整型类型

7.一个有十个指针的数组,该数组中的指针指向一个函数,该函数有一个整型参数并返回一个整型数


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章