指針理解之指針“起源”

看到一篇“指針”的帖子,也想總結一下自己對指針的理解,希望對剛接觸編程,剛接觸指針的人有幫助。

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.一個有十個指針的數組,該數組中的指針指向一個函數,該函數有一個整型參數並返回一個整型數


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