自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C++基礎(chǔ)之指針的詳細介紹(一)

開發(fā) 后端
本篇說明C++中的重中又重的關(guān)鍵——指針類型,并說明兩個很有意義的概念——靜態(tài)和動態(tài)。希望對你有幫助,一起來看。

在介紹C++中的指針開始之前,我們一定先要了解數(shù)組的概念以及用法,大家可以看看這篇文章,《淺析C++中的動態(tài)多維數(shù)組》,供參考。

數(shù)組

在C++中是通過變量來對內(nèi)存進行訪問的,但根據(jù)前面的說明,C++中只能通過變量來操作內(nèi)存,也就是說要操作某塊內(nèi)存,就必須先將這塊內(nèi)存的首地址和一個變量名綁定起來,這是很糟糕的。

比如有100塊內(nèi)存用以記錄100個工人的工資,現(xiàn)在要將每個工人的工資增加5%,為了知道各個工人增加了后的工資為多少,就定義一個變量float a1;,用其記錄第1個工人的工資,然后執(zhí)行語句a1 += a1 * 0.05f;,則a1里就是增加后的工資。由于是100個工人,所以就必須有100個變量,分別記錄100個工資。因此上面的賦值語句就需要有100條,每條僅僅變量名不一樣。

上面需要手工重復(fù)書寫變量定義語句float a1;100遍(每次變一個變量名),無謂的工作。因此想到一次向操作系統(tǒng)申請100*4=400個字節(jié)的連續(xù)內(nèi)存,那么要給第i個工人修改工資,只需從首地址開始加上4*i個字節(jié)就行了(因為float占用4個字節(jié))。

為了提供這個功能,C++提出了一種類型——數(shù)組。數(shù)組即一組數(shù)字,其中的各個數(shù)字稱作相應(yīng)數(shù)組的元素,各元素的大小一定相等(因為數(shù)組中的元素是靠固定的偏移來標識的),即數(shù)組表示一組相同類型的數(shù)字,其在內(nèi)存中一定是連續(xù)存放的。在定義變量時,要表示某個變量是數(shù)組類型時,在變量名的后面加上方括號,在方括號中指明欲申請的數(shù)組元素個數(shù),以分號結(jié)束。因此上面的記錄100個工資的變量,即可如下定義成數(shù)組類型的變量:

 

  1. float a[100]; 

 

上面定義了一個變量a,分配了100*4=400個字節(jié)的連續(xù)內(nèi)存(因為一個float元素占用4個字節(jié)),然后將其首地址和變量名a相綁定。而變量a的類型就被稱作具有100個float類型元素的數(shù)組。即將如下解釋變量a所對應(yīng)內(nèi)存中的內(nèi)容(類型就是如何解釋內(nèi)存的內(nèi)容):a所對應(yīng)的地址標識的內(nèi)存是一塊連續(xù)內(nèi)存的首地址,這塊連續(xù)內(nèi)存的大小剛好能容納下100個float類型的數(shù)字。

因此可以將前面的float b;這種定義看成是定義了一個元素的float數(shù)組變量b.而為了能夠訪問數(shù)組中的某個元素,在變量名后接方括號,方括號中放一數(shù)字,數(shù)字必須是非浮點數(shù),即使用二進制原碼或補碼進行表示的數(shù)字。如a[ 5 + 3 ] += 32;就是數(shù)組變量a的第5 + 3個元素的值增加32.又:

 

  1. long c = 23;   
  2. float b = a[ ( c – 3 ) / 5 ] + 10, d = a[ c – 23 ]; 

 

上面的b的值就為數(shù)組變量a的第4個元素的值加10,而d的值就為數(shù)組變量a的第0個元素的值。即C++的數(shù)組中的元素是以0為基本序號來記數(shù)的,即 a[0]實際代表的是數(shù)組變量a中的第一個元素的值,而之所以是0,表示a所對應(yīng)的地址加上0*4后得到的地址就為第一個元素的地址。

應(yīng)該注意不能這樣寫:

  1. long a[0]; 

 

定義0個元素的數(shù)組是無意義的,編譯器將報錯,不過在結(jié)構(gòu)或類或聯(lián)合中符合某些規(guī)則后可以這樣寫,那是C語言時代提出的一種實現(xiàn)結(jié)構(gòu)類型的長度可變的技術(shù)。

還應(yīng)注意上面在定義數(shù)組時不能在方括號內(nèi)寫變量,即

  1. long b = 10;   
  2. float a[ b ];//是錯誤的 

 

因為編譯此代碼時,無法知道變量b的值為多少,進而無法分配內(nèi)存。可是前面明明已經(jīng)寫了b = 10;,為什么還說不知道b的值?那是因為無法知道b所對應(yīng)的地址是多少。

因為編譯器編譯時只是將b和一個偏移進行了綁定,并不是真正的地址,即b所對應(yīng)的可能是Base - 54,而其中的Base就是在程序一開始執(zhí)行時動態(tài)向操作系統(tǒng)申請的大塊內(nèi)存的尾地址,因為其可能變化,故無法得知b實際對應(yīng)的地址(實際在 Windows平臺下,由于虛擬地址空間的運用,是可以得到實際對應(yīng)的虛擬地址,但依舊不是實際地址,故無法編譯時期知道某變量的值)。

但是編譯器仍然可以根據(jù)前面的long b = 10;而推出Base - 54的值為10?。恐攸c就是編譯器看到long b = 10;時,只是知道要生成一條指令,此指令將10放入Base - 54的內(nèi)存中,其它將不再過問(也沒必要過問),故即使才寫了long b = 10;編譯器也無法得知b的值。

上面說數(shù)組是一種類型,其實并不準確,實際應(yīng)為——數(shù)組是一種類型修飾符,其定義了一種類型修飾規(guī)則。關(guān)于類型修飾符,后面將詳述。

字符串

要查某個字符對應(yīng)的ASCII碼,通過在這個字符的兩側(cè)加上單引號,如'A'就等同于65.而要表示多個字符時,就使用雙引號括起來,如:"ABC".而為了記錄字符,就需要記錄下其對應(yīng)的ASCII碼,而ASCII碼的數(shù)值在-128到127以內(nèi),因此使用一個 char變量就可以記錄一個ASCII碼,而為了記錄"ABC",就很正常地使用一個char的數(shù)組來記錄。如下:

程序無論執(zhí)行多少遍,在申請內(nèi)存時總是申請固定大小的內(nèi)存,則稱此內(nèi)存是靜態(tài)分配的。前面提出的定義變量時,編譯器幫我們從棧上分配的內(nèi)存就屬于靜態(tài)分配。每次執(zhí)行程序,根據(jù)用戶輸入的不同而可能申請不同大小的內(nèi)存時,則稱此內(nèi)存是動態(tài)分配的,后面說的從堆上分配就屬于動態(tài)分配。

很明顯,動態(tài)比靜態(tài)的效率高(發(fā)票長度的利用率高),但要求更高——需要電腦和打印機,且需要收銀員的素質(zhì)較高(能操作電腦),而靜態(tài)的要求就較低,只需要已經(jīng)印好的發(fā)票聯(lián),且也只需收銀員會寫字即可。

同樣,靜態(tài)分配的內(nèi)存利用率不高或運用不夠靈活,但代碼容易編寫且運行速度較快;動態(tài)分配的內(nèi)存利用率高,不過編寫代碼時要復(fù)雜些,需自己處理內(nèi)存的管理(分配和釋放)且由于這種管理的介入而運行速度較慢并代碼長度增加。

靜態(tài)和動態(tài)的意義不僅僅如此,其有很多的深化,如硬編碼和軟編碼、緊耦合和松耦合,都是靜態(tài)和動態(tài)的深化。

地址

前面說過“地址就是一個數(shù)字,用以唯一標識某一特定內(nèi)存單元”,而后又說“而地址就和長整型、單精度浮點數(shù)這類一樣,是數(shù)字的一種類型”,那地址既是數(shù)字又是數(shù)字的類型?不是有點矛盾嗎?

如下:浮點數(shù)是一種數(shù)——小數(shù)——又是一種數(shù)字類型。即前面的前者是地址實際中的運用,而后者是由于電腦只認識狀態(tài),但是給出的狀態(tài)要如何處理就必須通過類型來說明,所以地址這種類型就是用來告訴編譯器以內(nèi)存單元的標識來處理對應(yīng)的狀態(tài)。

指針

已經(jīng)了解到動態(tài)分配內(nèi)存和靜態(tài)分配內(nèi)存的不同,現(xiàn)在要記錄用戶輸入的定單數(shù)據(jù),用戶一次輸入的定單數(shù)量不定,故選擇在堆上分配內(nèi)存。假設(shè)現(xiàn)在根據(jù)用戶的輸入,需申請1M的內(nèi)存以對用戶輸入的數(shù)據(jù)進行臨時記錄,則為了操作這1M的連續(xù)內(nèi)存,需記錄其首地址,但又由于此內(nèi)存是動態(tài)分配的,即其不是由編譯器分配(而是程序的代碼動態(tài)分配的),故未能建立一變量來映射此首地址,因此必須自己來記錄此首地址。

因為任何一個地址都是4個字節(jié)長的二進制數(shù)(對32位操作系統(tǒng)),故靜態(tài)分配一塊4字節(jié)內(nèi)存來記錄此首地址。檢查前面,可以將首地址這個數(shù)據(jù)存在unsigned long類型的變量a中,然后為了讀取此1M內(nèi)存中的第4個字節(jié)處的4字節(jié)長內(nèi)存的內(nèi)容,通過將a的值加上4即可獲得相應(yīng)的地址,然后取出其后連續(xù)的4個字節(jié)內(nèi)存的內(nèi)容。但是如何編寫取某地址對應(yīng)內(nèi)存的內(nèi)容的代碼呢?

前面說了,只要返回地址類型的數(shù)字,由于是地址類型,則其會自動取相應(yīng)內(nèi)容的。但如果直接寫:a + 4,由于a是unsigned long,則a + 4返回的是unsigned long類型,不是地址類型,怎么辦?

C++對此提出了一個操作符——“*”,叫做取內(nèi)容操作符(實際這個叫法并不準確)。其和乘號操作符一樣,但是它只在右側(cè)接數(shù)字,即*( a + 4 )。此表達式返回的就是把a的值加上4后的unsigned long數(shù)字轉(zhuǎn)成地址類型的數(shù)字。

但是有個問題:a + 4所表示的內(nèi)存的內(nèi)容如何解釋?即取1個字節(jié)還是2個字節(jié)?以什么格式來解釋取出的內(nèi)容?如果自己編寫匯編代碼,這就不是問題了,但現(xiàn)在是編譯器代我們編寫匯編代碼,因此必須通過一種手段告訴編譯器如何解釋給定的地址所對內(nèi)存的內(nèi)容。

C++對此提出了指針,其和上面的數(shù)組一樣,是一種類型修飾符。在定義變量時,在變量名的前面加上“*”即表示相應(yīng)變量是指針類型(就如在變量名后接“[]”表示相應(yīng)變量是數(shù)組類型一樣),其大小固定為4字節(jié)。如:

  1. unsigned long *pA; 

 

也就是說,某個地址的類型為指針時,表示此地址對應(yīng)的內(nèi)存中的內(nèi)容,應(yīng)該被編譯器解釋成一個地址。

因為變量就是地址的映射,每個變量都有個對應(yīng)的地址,為此C++又提供了一個操作符來取某個變量的地址——“&”,稱作取地址操作符。其與“數(shù)字與”操作符一樣,不過它總是在右側(cè)接數(shù)字(而不是兩側(cè)接數(shù)字)。

“&”的右側(cè)只能接地址類型的數(shù)字,它的計算(Evaluate)就是將右側(cè)的地址類型的數(shù)字簡單的類型轉(zhuǎn)換成指針類型并進而返回一個指針類型的數(shù)字,正好和取內(nèi)容操作符“*”相反。

上面正常情況下應(yīng)該會讓你很暈,下面釋疑。

  1. unsigned long a = 10, b, *pA;   
  2. pA = &a;  
  3. b = *pA;   
  4. ( *pA )++; 

上面的第一句通過“*pA”定義了一個指針類型的變量pA,即編譯器幫我們在棧上分配了一塊4字節(jié)的內(nèi)存,并將首地址和pA綁定(即形成映射)。然后“&a”由于a是一個變量,等同于地址,所以“&a”進行計算,返回一個類型為unsigned long*(即unsigned long的指針)的數(shù)字。

應(yīng)該注意上面返回的數(shù)字雖然是指針類型,但是其值和a對應(yīng)的地址相同,但為什么不直接說是unsigned long的地址的數(shù)字,而又多一個指針類型在其中攪和?因為指針類型的數(shù)字是直接返回其二進制數(shù)值,而地址類型的數(shù)字是返回其二進制數(shù)值對應(yīng)的內(nèi)存的內(nèi)容。因此假設(shè)上面的變量a所對應(yīng)的地址為2000,則a;將返回10,而&a;將返回2000.

再來看取內(nèi)容操作符“*”,其右接的數(shù)字類型是指針類型或數(shù)組類型,它的計算就是將此指針類型的數(shù)字直接轉(zhuǎn)換成地址類型的數(shù)字而已(因為指針類型的數(shù)字和地址類型的數(shù)字在數(shù)值上是相同的,僅僅計算規(guī)則不同)。

所以:

  1. b = *pA; 

 

返回pA對應(yīng)的地址,計算此地址的值,返回類型為unsigned long*的數(shù)字2000,然后“*pA”返回類型unsigned long的地址類型的數(shù)字2000,然后計算此地址類型的數(shù)字的值,返回10,然后就只是簡單地賦值操作了。同理,對于++( *pA )(由于“*”的優(yōu)先級低于前綴++,所以加“()”),先計算“*pA”而返回unsigned long的地址類型的數(shù)字2000,然后計算前綴++,最后返回unsigned long的地址類型的數(shù)字2000.

如果你還是未能理解地址類型和指針類型的區(qū)別,希望下面這句能夠有用:地址類型的數(shù)字是在編譯時期給編譯器用的,指針類型的數(shù)字是在運行時期給代碼用的。如果還是不甚理解,在看過后面的類型修飾符一節(jié)后希望能有所幫助。

本文續(xù)篇>>

責任編輯:于鐵 來源: 互聯(lián)網(wǎng)
相關(guān)推薦

2011-07-14 17:17:21

C++指針

2011-07-14 23:27:05

C++引用

2011-07-14 16:26:01

2011-07-20 16:43:34

C++

2011-07-15 01:38:56

C++this指針

2011-07-14 16:56:21

2011-06-21 10:37:56

const

2011-07-15 10:08:11

C++運算符重載

2011-07-13 11:12:43

C++MFC

2011-07-20 18:03:54

CC++

2010-02-01 10:22:51

C++數(shù)據(jù)指針

2011-07-13 16:14:53

C++引用指針

2011-07-20 13:57:06

C++STL

2009-08-21 15:16:23

C#使用指針

2011-07-15 01:29:39

C++析構(gòu)函數(shù)

2011-07-15 01:20:58

C指針函數(shù)函數(shù)指針

2011-07-20 15:58:53

C++引用

2011-07-13 16:49:59

C++

2010-01-28 13:57:19

C++指針基礎(chǔ)

2011-07-20 13:57:06

C++STL
點贊
收藏

51CTO技術(shù)棧公眾號