中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
水滴石穿C語(yǔ)言之指針綜合談 - C語(yǔ)言、C++編程技術(shù)館 - 博客園

    概述

    Joel Spolsky認(rèn)為,對(duì)指針的理解是一種aptitude,不是通過(guò)訓(xùn)練就可以達(dá)到的。雖然如此,我還是想談一談這個(gè)C/C++語(yǔ)言中最強(qiáng)勁也是最容易出錯(cuò)的要素。

    鑒于指針和目前計(jì)算機(jī)內(nèi)存結(jié)構(gòu)的關(guān)聯(lián),很多C語(yǔ)言比較本質(zhì)的特點(diǎn)都孕育在其中,因此,本篇和第六、第七兩篇我都將以指針為主線,結(jié)合在實(shí)際編程中遇到的問(wèn)題,來(lái)詳細(xì)談?wù)勱P(guān)于指針的幾個(gè)重要方面。

    指針類型的本質(zhì)分析

    1、指針的本質(zhì)

    指針的本質(zhì):一種復(fù)合的數(shù)據(jù)類型。下面我將以下面幾個(gè)作為例子進(jìn)行展開(kāi)分析:

    a)、int *p;b)、int **p;c)、int (*parValue)[3];d)、int (*pFun)();

    分析:

    所謂的數(shù)據(jù)類型就是具有某種數(shù)據(jù)特征的東東,比如數(shù)據(jù)類型char,它的數(shù)據(jù)特征就是它所占據(jù)的內(nèi)存為1個(gè)字節(jié), 指針也很類似,指針?biāo)赶虻闹狄舱紦?jù)著內(nèi)存中的一塊地址,地址的長(zhǎng)度與指針的類型有關(guān),比如對(duì)于char型指針,這個(gè)指針占據(jù)的內(nèi)存就是1個(gè)字節(jié),因此指針也是一種數(shù)據(jù)類型,但我們知道指針本身也占據(jù)了一個(gè)內(nèi)存空間地址,地址的長(zhǎng)度和機(jī)器的字長(zhǎng)有關(guān),比如在32位機(jī)器中,這個(gè)長(zhǎng)度就是4個(gè)字節(jié),因此指針本身也同樣是一種數(shù)據(jù)類型,因此,我們說(shuō),指針其實(shí)是一種復(fù)合的數(shù)據(jù)類型,

    好了,現(xiàn)在我們可以分析上面的幾個(gè)例子了。

    假設(shè)有如下定義:

    int nValue;那么,nValue的類型就是int,也就是把nValue這個(gè)具體變量去掉后剩余的部分,因此,上面的4個(gè)聲明可以類比進(jìn)行分析:

    a)、int *

    *代表變量(指針本身)的值是一個(gè)地址,int代表這個(gè)地址里面存放的是一個(gè)整數(shù),這兩個(gè)結(jié)合起來(lái),int *定義了一個(gè)指向整數(shù)的指針,類推如下:

    b)、int **

    指向一個(gè)指向整數(shù)的指針的指針。

    c)、int (*)[3]

    指向一個(gè)擁有三個(gè)整數(shù)的數(shù)組的指針。

    d)、int (*)()

    指向一個(gè)函數(shù)的指針,這個(gè)函數(shù)參數(shù)為空,返回值為整數(shù)。

    分析結(jié)束,從上面可以看出,指針包括兩個(gè)方面,一個(gè)是它本身的值,是一個(gè)內(nèi)存中的地址;另一個(gè)是指針?biāo)赶虻奈?,是這個(gè)地址中所存放著具有各種各樣意義的數(shù)據(jù)。

    2、對(duì)指針本身值的分析

    下面例子考察指針本身的值(環(huán)境為32位的計(jì)算機(jī)):

    void *p = malloc( 100 );請(qǐng)計(jì)算sizeof ( p ) = ?

    char str[] = “Hello” ;char *p = str ;

    請(qǐng)計(jì)算sizeof ( p ) = ?

    void Func ( char str[100])

    {

    請(qǐng)計(jì)算 sizeof( str ) = ? //注意,此時(shí),str已經(jīng)退化為一個(gè)指針,詳情見(jiàn)

    //下一篇指針與數(shù)組

    }

    分析:上面的例子,答案都是4,因?yàn)閺纳厦娴挠懻摽梢灾?,指針本身的值?duì)應(yīng)著內(nèi)存中的一個(gè)地址,它的size只與機(jī)器的字長(zhǎng)有關(guān)(即它是由系統(tǒng)的內(nèi)存模型決定的),在32位機(jī)器中,這個(gè)長(zhǎng)度是4個(gè)字節(jié)。

    3、對(duì)指針?biāo)赶蛭锏姆治?/strong>

    現(xiàn)在再對(duì)指針這個(gè)復(fù)合類型的第二部分,指針?biāo)赶蛭锏囊饬x進(jìn)行分析。

    上面我們已經(jīng)得到了指針本身的類型,那么將指針本身的類型去掉 “*”號(hào)就可得到指針?biāo)赶蛭锏念愋停謩e如下:

    a)、int

    所指向物是一個(gè)整數(shù)。

    b)、int*

    所指向物是一個(gè)指向整數(shù)的指針。

    c)、int ()[3]

    ()為空,可以去掉,變?yōu)閕nt [3],所指向物是一個(gè)擁有三個(gè)整數(shù)的數(shù)組。

    d)、int ()()

    第一個(gè)()為空,可以去掉,變?yōu)閕nt (),所指向物是一個(gè)函數(shù),這個(gè)函數(shù)的參數(shù)為空,返回值為整數(shù)。

    4、附加分析

    另外,關(guān)于指針本身大小的問(wèn)題,在C++中與C有所不同,這里我也順帶談一下。

    在C++中,對(duì)于指向?qū)ο蟪蓡T的指針,它的大小不一定是4個(gè)字節(jié),這主要是因?yàn)樵谝攵嘀靥摂M繼承以及虛擬函數(shù)的時(shí)候,有些附加的信息也需要通過(guò)這個(gè)指針進(jìn)行傳遞,因此指向?qū)ο蟪蓡T的指針會(huì)增大,不論是指向成員數(shù)據(jù),還是成員函數(shù)都是如此,具體與編譯器的實(shí)現(xiàn)有關(guān),你可以編寫(xiě)個(gè)很小的C++程序去驗(yàn)證一下。另外,對(duì)一個(gè)類的靜態(tài)成員(static member,可以是靜態(tài)成員變量或者靜態(tài)成員函數(shù))來(lái)說(shuō),指向它的指針只是普通的函數(shù)指針,而不是一個(gè)指向類成員的指針,所以它的大小不會(huì)增加,仍舊是4個(gè)字節(jié)

    指針運(yùn)算符&和*

    “&和*”,它們是一對(duì)相反的操作,‘&’取得一個(gè)物的地址(也就是指針本身),‘*’得到一個(gè)地址里放的物(指針?biāo)赶虻奈铮?。這個(gè)東西可以是值(對(duì)象)、函數(shù)、數(shù)組、類成員(class member)等等。

    參照上面的分析我們可以很好地理解&與*.

    使用指針的好處?

    關(guān)于指針的本質(zhì)和基本的運(yùn)算符我們討論過(guò)了,在這里,我想再籠總地談一談使用指針的必要性和好處,為我們今后的使用和對(duì)后面篇章的理解做好鋪墊。簡(jiǎn)而言之,指針有以下好處:

    1)、方便使用動(dòng)態(tài)分配的數(shù)組。

    這個(gè)解釋我放在本系列第六篇中進(jìn)行講解。

    2)、對(duì)于相同類型(甚至是相似類型)的多個(gè)變量進(jìn)行通用訪問(wèn)。

    就是用一個(gè)指針變量不斷在多個(gè)變量之間指來(lái)指去,從而使得非常應(yīng)用起來(lái)非常靈活,不過(guò),這招也比較危險(xiǎn),需要小心使用:因?yàn)槌霈F(xiàn)錯(cuò)誤的指針是編程中非常忌諱的事情。

    3)、變相改變一個(gè)函數(shù)的值傳遞特性。

    說(shuō)白了,就是指針的傳地址作用,將一個(gè)變量的地址作為參數(shù)傳給函數(shù),這樣函數(shù)就可以修改那個(gè)變量了。

    4)、節(jié)省函數(shù)調(diào)用代價(jià)。

    我們可以將參數(shù),尤其是大個(gè)的參數(shù)(例如結(jié)構(gòu),對(duì)象等),將他們地址作為參數(shù)傳給函數(shù),這樣可以省去編譯器為它們制作副本所帶來(lái)的空間和時(shí)間上的開(kāi)銷。

    5)、動(dòng)態(tài)擴(kuò)展數(shù)據(jù)結(jié)構(gòu)。

    因?yàn)橹羔樋梢詣?dòng)態(tài)地使用malloc/new生成堆上的內(nèi)存,所以在需要?jiǎng)討B(tài)擴(kuò)展數(shù)據(jù)結(jié)構(gòu)的時(shí)候,非常有用;比如對(duì)于樹(shù)、鏈表、Hash表等,這幾乎是必不可少的特性。

    6)、與目前計(jì)算機(jī)的內(nèi)存模型相對(duì)應(yīng),可按照內(nèi)存地址進(jìn)行直接存取,這使得C非常適合于一些較底層的應(yīng)用。

    這也是C/C++指針一個(gè)強(qiáng)大的優(yōu)點(diǎn),我會(huì)在后面講述C語(yǔ)言的底層操作時(shí),較詳細(xì)地介紹這個(gè)優(yōu)點(diǎn)的應(yīng)用。

    7)、遍歷數(shù)組。

    據(jù)個(gè)例子來(lái)說(shuō)吧,當(dāng)你需要對(duì)字符串?dāng)?shù)組進(jìn)行操作時(shí),想一想,你當(dāng)然要用字符串指針在字符串上掃來(lái)掃去。

    …實(shí)在太多了,你可以慢慢來(lái)補(bǔ)充^_^.

    指針本身的相關(guān)問(wèn)題

    1、問(wèn)題:空指針的定義

    曾經(jīng)看過(guò)有的。h文件將NULL定義為0L,為什么?

    答案與分析:

    這是一個(gè)關(guān)于空指針宏定義的問(wèn)題。指針在C語(yǔ)言中是經(jīng)常使用的,有時(shí)需要將一個(gè)指針置為空指針,例如在指針變量初始化的時(shí)候。

    C語(yǔ)言中的空指針和Pascal或者Lisp語(yǔ)言中的NIL具有相同的地位。那如何定義空指針呢?下面的語(yǔ)句是正確的:

    char *p1 = 0;int *p2;if (p != 0)

    {……

    } p2 = 0;也就是說(shuō),在指針變量的初始化、賦值、比較操作中,0會(huì)被編譯器理解為要將指針置為空指針。至于空指針的內(nèi)部表示是否是0,則隨不同的機(jī)器類型而定,不過(guò)通常都是0.但是在另外一些場(chǎng)合下,例如函數(shù)的參數(shù)原型是指針類型,函數(shù)調(diào)用時(shí)如果將0作為參數(shù)傳入,編譯器則不能將其理解為空指針。此時(shí)需要明確的類型轉(zhuǎn)換,例如:

    void func (char *p);func ((char *)0);一般情況下,0是可以放在代碼中和指針關(guān)聯(lián)使用的,但是有些程序員(數(shù)量還不少呦!也許就包括你在內(nèi))不喜歡0的直白,認(rèn)為其不能表示作為指針的特殊含義,于是要定義一個(gè)宏NULL,來(lái)明確表示空指針常量。這也是對(duì)的,人家C語(yǔ)言標(biāo)準(zhǔn)就明確說(shuō):“ NULL應(yīng)該被定義為與實(shí)現(xiàn)相關(guān)的空指針常量”。但是將NULL定義成什么樣的值呢?我想你一定見(jiàn)過(guò)好幾種定義NULL的方法:

   #define NULL 0

    #define NULL (char *)0

    #define NULL (void *)0

    在我們使用的絕大多數(shù)計(jì)算系統(tǒng)上,例如PC,上述定義是能夠工作的。然而,世界上還有很多其它種類的計(jì)算機(jī),其CPU也不是Intel的。在某些系統(tǒng)上,指針和整數(shù)的大小和內(nèi)部表示并不一致,甚至不同類型的指針的大小都不一致。為了避免這種可移植性問(wèn)題,0L是一種最為安全的、最妥帖的定義方式。0L的含義是: “值為0的整數(shù)常量表達(dá)式”。這與C語(yǔ)言給出的空指針定義完全一致。因此,建議采用0L作為空指針常量NULL的值。

    其實(shí) NULL定義值,和操作系統(tǒng)的的平臺(tái)有關(guān), 將一個(gè)指針定義為 NULL, 其用意是為了保護(hù)操作系統(tǒng),因?yàn)橥ㄟ^(guò)指針可以訪問(wèn)任何一塊地址, 但是,有些數(shù)據(jù)是不許一般用戶訪問(wèn)的,比如操作系統(tǒng)的核心數(shù)據(jù)。 當(dāng)我們通過(guò)一個(gè)空(NULL)的指針去方位數(shù)據(jù)時(shí),系統(tǒng)會(huì)提示非法, 那么系統(tǒng)又是如何知道的呢??

    以windows2000系統(tǒng)為例, 該系統(tǒng)規(guī)定系統(tǒng)中每個(gè)進(jìn)程的起始地址(0x00000000)開(kāi)始的某個(gè)地址范圍內(nèi)是存放系統(tǒng)數(shù)據(jù)的,用戶進(jìn)程無(wú)法訪問(wèn), 所以當(dāng)用戶用空指針(0)訪問(wèn)時(shí),其實(shí)訪問(wèn)的就是0x00000000地址的系統(tǒng)數(shù)據(jù),由于該地址數(shù)據(jù)是受系統(tǒng)保護(hù)的,所以系統(tǒng)會(huì)提示錯(cuò)誤(指針訪問(wèn)非法)。

    這也就是說(shuō)NULL值不一定要定義成0,起始只要定義在系統(tǒng)的保護(hù)范圍的地址空間內(nèi),比如定義成(0x00000001, 0x00000002)都會(huì)起到相同的作用,但是為了考慮到移植性,普遍定義為0 .

    2、問(wèn)題:與指針相關(guān)的編程規(guī)則&規(guī)則分析

    指針既然這么重要,而且容易出錯(cuò),那么有沒(méi)有方法可以很好地減少這些指針相關(guān)問(wèn)題的出現(xiàn)呢?

    答案與分析:

    減少出錯(cuò)的根本是徹底理解指針。

    在方法上,遵循一定的編碼規(guī)則可能是最立竿見(jiàn)影的方法了,下面我來(lái)闡述一下與指針相關(guān)的編程規(guī)則:

    1) 未使用的指針初始化為NULL .

    2) 在給指針?lè)峙淇臻g前、分配后均應(yīng)作判斷。

    3) 指針?biāo)赶虻膬?nèi)容刪除后也要清除指針本身。

    要牢記指針是一個(gè)復(fù)合的數(shù)據(jù)結(jié)構(gòu)這個(gè)本質(zhì),所以我們不論初始化和清除都要同時(shí)兼顧指針本身(上述規(guī)則1,3)和指針?biāo)赶虻膬?nèi)容(上述規(guī)則2,3)這兩個(gè)方面。

    遵循這些規(guī)則可以有效地減少指針出錯(cuò),我們來(lái)看下面的例子:

 void Test(void)
{
 char *str = (char *) malloc(100);
 strcpy(str, “hello”);
 free(str);
 if(str != NULL)
 {
  strcpy(str, “world”);
  printf(str);
 }
}

    請(qǐng)問(wèn)運(yùn)行Test函數(shù)會(huì)有什么樣的結(jié)果?

    答:

    篡改動(dòng)態(tài)內(nèi)存區(qū)的內(nèi)容,后果難以預(yù)料,非常危險(xiǎn)。因?yàn)閒ree(str);之后,str成為野指針,if(str != NULL)語(yǔ)句不起作用。

    如果我們牢記規(guī)則3,在free(str)后增加語(yǔ)句:

    str = NULL;

    那么,就可以防止這樣的錯(cuò)誤發(fā)生。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服