• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看

      ?

      淺析C語(yǔ)言指針

      2014-03-15 20:11:33蘇子偉
      軟件工程 2014年3期
      關(guān)鍵詞:數(shù)組指針指向

      蘇子偉

      指針簡(jiǎn)介

      指針是C語(yǔ)言的一個(gè)最重要的特征,它提供了一種統(tǒng)一的方法,使其能訪問(wèn)遠(yuǎn)程的數(shù)據(jù)結(jié)構(gòu)。但對(duì)C語(yǔ)言初學(xué)者而言,在編程過(guò)程中熟練的使用指針并不能像使用int型變量一樣地輕松愉快,容易上手,往往是不得其精髓。我們知道,不論什么時(shí)候,運(yùn)行一個(gè)程序A,首先都是操作系統(tǒng)自身的加載器把A裝入內(nèi)存,然后CPU才能執(zhí)行。所以A程序的所有要素都會(huì)駐留在內(nèi)存的某個(gè)位置。

      下面我們看一段示例程序。

      #include

      intcmp(int first, int second)

      {

      return ( first > second ? first : second );

      }

      int main(intargc, char **argv)

      {

      inti = 5;

      int j = 9;

      returncmp(i, j);

      }

      首先,編譯器會(huì)為變量i和j開(kāi)辟內(nèi)存空間,用來(lái)存儲(chǔ)i和j的值。同時(shí)也會(huì)為函數(shù)cmp開(kāi)辟空間來(lái)存放其代碼。這樣使得最終的可執(zhí)行程序就變?yōu)榱烁鷥?nèi)存一一對(duì)應(yīng)的序列。操作系統(tǒng)的加載器把這個(gè)可執(zhí)行程序載入內(nèi)存后,cpu就可以按一條條的語(yǔ)句順序執(zhí)行了。

      既然內(nèi)存空間同程序的所有要素是一一對(duì)應(yīng)的,那么怎么區(qū)分各要素的存放位置呢??jī)?nèi)存使用不同的地址存放不同的要素,如下所示。

      由于變量都存放于內(nèi)存地址空間,并且與地址之間是一一對(duì)應(yīng)的,那么利用地址能做些什么呢?我們可以把地址存放到別的變量中,以便我們可以在以后程序的某個(gè)地方使用它。C語(yǔ)言有一個(gè)專門用來(lái)存儲(chǔ)內(nèi)存地址的變量,這就是指針變量,通常我們稱之為指針(pointer)。它是一種變量類型,這種變量方便我們把需要操控的內(nèi)存地址記憶起來(lái)。

      定義指針

      定義指針的運(yùn)算符同乘法運(yùn)算符是一樣的,都用“*”表示。定義一個(gè)指針變量在語(yǔ)法上是簡(jiǎn)單的,同我們定義其他變量的區(qū)別是:首先規(guī)定它指向的變量類型,然后并不是立即就給出其變量的標(biāo)識(shí)符,而是在變量類型同變量標(biāo)識(shí)符之間插入指針運(yùn)算符(星號(hào)),這樣就告訴編譯器這是一個(gè)指針變量。

      C語(yǔ)言中指針可以指向任何的數(shù)據(jù)類型,包括函數(shù)。函數(shù)指針的定義是:函數(shù)返回值+(* + 函數(shù)指針變量標(biāo)識(shí)符)+(函數(shù)的參數(shù)列表)。函數(shù)指針能構(gòu)建出更加清晰的程序結(jié)構(gòu)。編程中經(jīng)常使用的指針定義就是這兩種,當(dāng)然有些定義可能只是語(yǔ)法上面有意義,但是語(yǔ)義上面不一定有具體的意義。例如,int *(*(*(*f)())[])()聲明f是一個(gè)函數(shù)指針,該函數(shù)返回一個(gè)指針,該指針指向數(shù)組,該數(shù)組元素是指針,那些指針指向返回值類型為整型指針的函數(shù)。這樣的聲明可能永遠(yuǎn)也不能應(yīng)用到實(shí)際的代碼中。

      指針和數(shù)組

      數(shù)組是內(nèi)存中一段連續(xù)相同類型的內(nèi)存數(shù)據(jù),這組數(shù)據(jù)的首地址以數(shù)組名字來(lái)標(biāo)識(shí)。所有數(shù)組對(duì)其數(shù)據(jù)的操控都可以使用指針來(lái)實(shí)現(xiàn),同理,指針指向一段內(nèi)存數(shù)據(jù)時(shí),也可以使用數(shù)組下標(biāo)的方式來(lái)實(shí)現(xiàn)操作。

      數(shù)組與指針在使用上的某些地方是非常相似的,但是數(shù)組與指針又有一些細(xì)小的區(qū)別。數(shù)組名表現(xiàn)為一個(gè)靜態(tài)指針,也可以直接把它賦值給指針變量,但它的大小與指針通常是不同的。數(shù)組名的內(nèi)涵在于其指代的實(shí)體是一種數(shù)據(jù)結(jié)構(gòu),這種數(shù)據(jù)結(jié)構(gòu)就是數(shù)組。數(shù)組名可以作為參數(shù)傳入一個(gè)接受參數(shù)為指針的函數(shù)內(nèi)部,但是此時(shí)數(shù)組完全丟失了數(shù)組的本義,變成了完全的指針類型,其常量特性(可以作自增、自減等操作)可以被修改。并且,數(shù)組名不能再重新賦值為其他的數(shù)組名字,而指針變量是可以被重新賦值并指向一段新的內(nèi)存地址的。

      指針的運(yùn)算

      指針的運(yùn)算指的是指針的--、++、-和+運(yùn)算,一個(gè)指針可以加上或者減去一個(gè)整數(shù)。兩個(gè)指針相減得到的是指針之間相隔的元素個(gè)數(shù)。不同的指針變量之間進(jìn)行相加運(yùn)算盡管在語(yǔ)法上是合理的,但是從語(yǔ)義上來(lái)講是沒(méi)有意義的。除了void型指針和函數(shù)指針以外,所有其他類型的指針都可以進(jìn)行指針運(yùn)算。通過(guò)指針變量的增加或減少,指針變量會(huì)指向新的內(nèi)存地址。

      一般來(lái)說(shuō),指針變量自身的大小在理論上是指機(jī)器的字長(zhǎng),但是指針變量的運(yùn)算并不是按照指針變量自身的大小進(jìn)行內(nèi)存偏移的,而是按照指針變量指向的變量類型大小進(jìn)行內(nèi)存偏移的。比如,聲明一個(gè)整形的指針p,假定p的地址是0x4323672,那么++p后p的值變?yōu)?x43236726。偏移的內(nèi)存大小等于整形變量的內(nèi)存大小4(sizeof(int))。同理,double型指針進(jìn)行++運(yùn)算后偏移值就是8(sizeof(double))。

      指針強(qiáng)轉(zhuǎn)

      如同整形變量可以強(qiáng)轉(zhuǎn)為浮點(diǎn)型變量一樣,指針類型也可以通過(guò)強(qiáng)轉(zhuǎn)變成新的指針類型,比如我們可以把整形指針強(qiáng)轉(zhuǎn)為字符型指針。指針強(qiáng)轉(zhuǎn)最誘人的地方就在于對(duì)內(nèi)存數(shù)據(jù)進(jìn)行操控就夠了。指針強(qiáng)轉(zhuǎn)使得指針對(duì)數(shù)據(jù)的操控更具有針對(duì)性,而且通過(guò)指針的默認(rèn)強(qiáng)轉(zhuǎn)可以使得函數(shù)的參數(shù)更簡(jiǎn)單,且傳遞的信息量是不變的。比如,void*作為參數(shù)時(shí)可以把任意的指針變量傳遞到函數(shù)內(nèi)部進(jìn)行相關(guān)的操作。

      下面我們來(lái)看一個(gè)具體的例子。數(shù)據(jù)的內(nèi)存布局如下圖所示,首先是一個(gè)字符型數(shù)據(jù),緊接著的是兩個(gè)整形數(shù)據(jù),最后面是三個(gè)結(jié)構(gòu)體A型數(shù)據(jù)。我們需要做的就是把這些數(shù)據(jù)讀出來(lái)。

      我們先聲明一個(gè)字符型的指針p,使其指向第一個(gè)數(shù)據(jù)的內(nèi)存地址。取完第一個(gè)字符型數(shù)據(jù)后,通過(guò)p++,然后強(qiáng)轉(zhuǎn)指針為整形指針,就可以很方便地取出整形數(shù)據(jù),同理可取出三個(gè)結(jié)構(gòu)體數(shù)據(jù)。

      指針作為參數(shù)

      先看一個(gè)例子,我們有兩個(gè)整形變量,x的值為777,y的值為888,現(xiàn)在想構(gòu)建一個(gè)函數(shù)用來(lái)交換兩個(gè)整形變量的值,使得x的值為888,y的值為777。首先我們以傳值的方式構(gòu)建

      voidswap_value(int Param1,int Param2)

      {

      int Temp = Param1;

      Param1 = Param2;

      Param2 = Temp;

      }

      我們調(diào)用函數(shù)swap_value(x,y)后,發(fā)現(xiàn)x、y的值并沒(méi)有被交換。造成這種結(jié)果的原因是由于函數(shù)調(diào)用時(shí),首先對(duì)傳入的實(shí)參進(jìn)行變量的拷貝,交換的值是形參的值,并不是實(shí)參的值。而原來(lái)的實(shí)參與拷貝后的形參變量所處的內(nèi)存也不同,所以并沒(méi)有交換成功。

      要想實(shí)現(xiàn)函數(shù)內(nèi)部對(duì)這兩個(gè)值的交換,必須使得實(shí)參與拷貝后的形參變量所處的內(nèi)存是相同的。我們知道了原理后,修正函數(shù)參數(shù)列表,以指針的方式重新構(gòu)建函數(shù)如下:

      voidswap_value(int*Param1,int*Param2)

      {

      int Temp=*Param1;

      *Param1=*Param2;

      *Param2=Temp;

      }

      這時(shí)候我們發(fā)現(xiàn)x、y的值被交換了。通過(guò)上面的例子可以看出,使用指針作為參數(shù)可以修改原來(lái)的變量值,使得函數(shù)實(shí)現(xiàn)的機(jī)能更加模塊化,方便了程序的設(shè)計(jì)。

      野指針

      前面我們已經(jīng)討論過(guò)指針變量同內(nèi)存的關(guān)系,了解了指針變量里面存放的是某個(gè)變量的內(nèi)存地址,該地址可以在程序的某個(gè)位置使用,以方便我們更改或取得該變量的值。指針使得我們擁有了操控內(nèi)存的利器,但同時(shí)指針也是一把雙刃劍。我們必須時(shí)刻確保指針變量的值是我們意圖操控的內(nèi)存地址。如果指針變量的值被不受控的更改或者初始化不正確,那么我們就使用了錯(cuò)誤的地址,從而導(dǎo)致程序錯(cuò)誤,通常我們稱這個(gè)導(dǎo)致程序錯(cuò)誤的指針變量為野指針。由于使用了野指針而產(chǎn)生的程序錯(cuò)誤大多時(shí)候是隱蔽的,難于跟蹤的。野指針的產(chǎn)生主要是由于以下幾種情況。

      (1)聲明了指針變量,但是沒(méi)有正確的初始化就使用了該指針變量。

      (2)使用指針變量之前沒(méi)有對(duì)其進(jìn)行安全檢查。

      (3)指針指向的內(nèi)存變?yōu)榱藷o(wú)效值,但沒(méi)有及時(shí)對(duì)指針清零,導(dǎo)致程序某處引用了該指針。

      (4)多個(gè)指針同時(shí)指向同一內(nèi)存區(qū)域,程序某處通過(guò)某個(gè)指針釋放了該內(nèi)存,但是沒(méi)有及時(shí)對(duì)其他的指針清零,導(dǎo)致程序某處進(jìn)行了錯(cuò)誤的引用。

      (5)多線程時(shí),對(duì)全局的指針變量沒(méi)有進(jìn)行鎖處理。

      多級(jí)指針

      定義一級(jí)指針我們使用一個(gè)‘*,在定義多級(jí)指針時(shí),是幾級(jí)指針我們就使用幾個(gè)‘*。例如,聲明一個(gè)整型的二級(jí)指針(int ** ppVar;)。下面以這個(gè)二級(jí)指針為例說(shuō)明一下二級(jí)指針的意義。

      二級(jí)指針變量同樣是保存了一個(gè)地址,這個(gè)地址就是某個(gè)一級(jí)指針變量的地址,而一級(jí)指針變量里面保存了最終需要操作的變量的地址,如下所示。

      0x4323640 0x4323668

      二級(jí)指針變量的值為0x4323640,就是一級(jí)指針變量pVar的地址,變量pVar的值為0x4323668,就是變量Var的地址。如果需要修改變量Var的值,我們可以直接修正**ppVar的值就可以了。

      三級(jí)指針或者更多級(jí)指針的原理與二級(jí)指針的原理是相同的,只是需要索引的內(nèi)存空間的深度增加了。在程序設(shè)計(jì)中,引入多級(jí)指針更多的時(shí)候并不僅僅是為了關(guān)注最后一級(jí)指針?biāo)苋〉玫淖兞?,而更多的是為了使用和操控其中間的級(jí)數(shù)的內(nèi)存值。比如利用二級(jí)指針作為函數(shù)的參數(shù)在某個(gè)函數(shù)內(nèi)部對(duì)其分配內(nèi)存,我們更想利用的是一級(jí)指針變量自身。當(dāng)然,在進(jìn)行程序設(shè)計(jì)時(shí),有時(shí)我們要在可讀性與語(yǔ)法有效性之間做出選擇,在實(shí)現(xiàn)代碼的過(guò)程中能用低級(jí)指針實(shí)現(xiàn)的盡量不要使用多級(jí)指針實(shí)現(xiàn),這樣的代碼更利于維護(hù)。

      小結(jié)

      在C語(yǔ)言中指針的使用非常的廣泛,有時(shí)指針是實(shí)現(xiàn)某個(gè)計(jì)算的唯一方法。同樣的機(jī)能使用指針通常也可以獲得更加高效、緊湊的代碼。指針使得函數(shù)構(gòu)建的機(jī)能更加的模塊化,使得函數(shù)參數(shù)棧更加的短小。同時(shí)在操縱字符串的運(yùn)算中,指針更加簡(jiǎn)單直觀。

      在大項(xiàng)目構(gòu)建時(shí),把函數(shù)指針同數(shù)據(jù)封裝在一起能夠使得代碼編程面向?qū)ο蟮慕Y(jié)構(gòu),使得后期代碼的維護(hù)成本大大降低,代碼的表現(xiàn)也更加具有現(xiàn)實(shí)意義。

      當(dāng)然,使指針具有這些優(yōu)點(diǎn)的前提是能夠熟練地使用它。粗心大意地使用指針變量,更容易引入程序錯(cuò)誤。因此,合理正確地使用指針也就成為了C語(yǔ)言愛(ài)好者和使用者的一門必修課。endprint

      猜你喜歡
      數(shù)組指針指向
      JAVA稀疏矩陣算法
      科學(xué)備考新指向——不等式選講篇
      JAVA玩轉(zhuǎn)數(shù)學(xué)之二維數(shù)組排序
      偷指針的人
      把準(zhǔn)方向盤(pán) 握緊指向燈 走好創(chuàng)新路
      為什么表的指針都按照順時(shí)針?lè)较蜣D(zhuǎn)動(dòng)
      尋找勾股數(shù)組的歷程
      基于改進(jìn)Hough變換和BP網(wǎng)絡(luò)的指針儀表識(shí)別
      ARM Cortex—MO/MO+單片機(jī)的指針變量替換方法
      VB數(shù)組在for循環(huán)中的應(yīng)用
      考試周刊(2012年88期)2012-04-29 04:36:47
      繁昌县| 泗洪县| 灵寿县| 绥阳县| 扎囊县| 广汉市| 沈丘县| 汉沽区| 北流市| 韩城市| 清新县| 丰城市| 台湾省| 四子王旗| 吴江市| 台湾省| 浮梁县| 乃东县| 韶山市| 六盘水市| 南充市| 永嘉县| 平阴县| 独山县| 石河子市| 海南省| 阳山县| 河源市| 临朐县| 张北县| 双流县| 鄂温| 屏东县| 莱阳市| 荆州市| 龙门县| 崇信县| 九龙县| 临颍县| 崇州市| 昆明市|