小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

周立功:安全有效地使用C掌握指針—變量的訪問

 甲基丁酸 2017-07-09

周立功:安全有效地使用C掌握指針—變量的訪問

2017-07-05 電子工程師時(shí)間
電子工程師時(shí)間

ee-technotes

分享電子工程相關(guān)技術(shù)文檔:設(shè)計(jì)技巧,應(yīng)用筆記,參考設(shè)計(jì),設(shè)計(jì)方案


經(jīng)周立功教授授權(quán),特對(duì)本書內(nèi)容進(jìn)行連載。第一章為程序設(shè)計(jì)基礎(chǔ),本文為1.3.2節(jié)變量的訪問。

周立功

1.   間接訪問

指針變量與普通變量沒有任何區(qū)別,由于通過變量名即可獲取變量的值,因此指針變量的值就是它存儲(chǔ)的內(nèi)存地址。如果想要獲取內(nèi)存地址中存儲(chǔ)的值,就必須使用特殊的語法“*”。假設(shè)0x22FF70存儲(chǔ)單元中保存的是ptr的值0x22FF74,則通過ptr就可以找到iNum的值0x64,詳見圖1.7。每當(dāng)指針的指向改變時(shí),便繪制新的箭頭;每當(dāng)變量的值發(fā)生改變時(shí),更新它的值。通過這些操作,即使再復(fù)雜的系統(tǒng),也能夠理解了。顯然指針變量對(duì)所指向的變量的訪問,自然也就成了對(duì)變量的“間接訪問”。即:

* 指針變量

即間接引用操作符(*)返回指針變量指向的內(nèi)容,通常又將“*”稱為解引用指針。當(dāng)指針變量為空指針時(shí),則“*指針變量”毫無意義。


如果ptr指向iNum,&iNum表示變量iNum的地址。使用*ptr等同于iNum,表示存儲(chǔ)在&iNum地址上的值。即除了可以通過*ptr輸出iNum的值,還可以賦值。比如:

printf('%p\n', *ptr);

注意,%p與%x的區(qū)別在于,%p會(huì)將數(shù)字顯示為十六進(jìn)制大寫。


2.  直接訪問

定義變量的目的是通過“變量名”引用“變量的值”,由于程序經(jīng)過編譯后已經(jīng)將“變量名”轉(zhuǎn)換為“變量的地址”,因此對(duì)變量的取值都是通過地址進(jìn)行的,則直接按變量名取值的訪問方式就是“直接訪問”。比如:

iNum  = 0x64;                     //對(duì)變量iNum的直接訪問

*ptr   = 0x80;              //對(duì)變量iNum的間接訪問

顯然,無論是采用間接訪問還是直接訪問,這2個(gè)語句作用是相同的。由于指針變量也是變量,因此在程序中同樣也可以直接使用,而不必通過間接訪問的方法。比如:

int   *ptr1,*ptr2;

ptr1 =ptr2;

即這樣ptr1與ptr2指向同一個(gè)對(duì)象。另,也可以將ptr2指向的值復(fù)制到ptr1中。比如:

 *ptr1 =*ptr2;                     //數(shù)值賦值


綜上所述,指針存儲(chǔ)的是地址,因此直接使用“裸”指針得到的是地址。要獲取或調(diào)整存儲(chǔ)在該地址中的值,必須額外添加的“*”。而變量存儲(chǔ)的是數(shù)據(jù)值,因此直接使用變量得到的是數(shù)據(jù)值。要獲取變量的地址,必須額外添加“&”。


3.   強(qiáng)制類型轉(zhuǎn)換

實(shí)際上指針(存儲(chǔ)單元的地址)也是無符號(hào)整數(shù),因此指針可以與整型變量的類型互相轉(zhuǎn)換。比如:

unsigned int a = 5, b;

b = (unsigned int)&a;

由于&a的類型為unsigned int*,因此需要強(qiáng)制轉(zhuǎn)換&a為unsigned int,只有這樣才能將變量a的地址保存在b中,那么將如何通過b取得a的值呢?必須先將b強(qiáng)制轉(zhuǎn)換為指針,才能讀取a的值,詳見程序清單 1.9。

程序清單 1.9指針類變量類型轉(zhuǎn)換范例程序

1       #include

2       int main(int argc, char *argv[])

3       {

4                 unsigned int a = 5, b;

5

6                 printf('&a=%x\n%&b=%x\n',&a, &b);

7                 b = (unsigned int)&a;               //將&a轉(zhuǎn)換為unsigned int型整數(shù)

8                 printf('(unsigned int*)&b = %x\n', (unsigned int *)&b);  //輸出b的地址

9               printf('(unsignedint *)b = %x\n', (unsigned int *)b);        //輸出b的值,即a的地址

10             printf('*(unsignedint *)b = %x\n', *(unsigned int *)b);    //將b強(qiáng)制轉(zhuǎn)換為指針再取得a的值

11               return0;

12     }

在C語言中也常常遇到這樣的情況,如果要將數(shù)據(jù)0x05存入絕對(duì)地址0x22FF74中,那么下面這條語句是否正確呢?

*0x22FF74= 0x05;

這是非法的。因?yàn)?x22FF74是int型整數(shù),而*間接訪問操作只能用于指針表達(dá)式。


既然通過指針可以向其指向的內(nèi)存地址寫入數(shù)據(jù),那么這里的內(nèi)存地址0x22FF74就是指針,因此必須先通過強(qiáng)制轉(zhuǎn)換將0x22FF74轉(zhuǎn)換為指向“unsigned int *”類型。然后通過“*”向0x22FF74內(nèi)存寫入數(shù)據(jù),“*(unsigned int *)0x22FF74”表示讀取0x22FF74地址里面的內(nèi)容,其內(nèi)容就是保存在地址為0x22FF74存儲(chǔ)器內(nèi)的數(shù)據(jù)。比如:


*(unsigned int *)0x22FF74 = 0x05;

printf('*(unsigned int *)0x22FF74 = 0x%x\n', *(unsigned int*)0x22FF74);

上述方法不是用于訪問某個(gè)變量,而是通過地址訪問內(nèi)存中某個(gè)特定的位置,比如,系統(tǒng)通過與輸入輸出設(shè)備控制器之間的通信,以及與I/O的輸入輸出操作來獲得相應(yīng)的結(jié)果。事實(shí)上,計(jì)算機(jī)與設(shè)備控制器的通信就是通過在某個(gè)特定內(nèi)存地址讀取和寫入值來實(shí)現(xiàn)的,表面上看起來這些操作訪問的是內(nèi)存,其實(shí)際上訪問的是設(shè)備控制器接口。


在強(qiáng)制類型轉(zhuǎn)換運(yùn)算符中和類型作為sizeof的操作數(shù)時(shí),雖然初學(xué)者對(duì)一些復(fù)雜的類型名感到難以理解,但實(shí)際上卻有規(guī)律可循。其聲明規(guī)則為在標(biāo)識(shí)符(變量名或函數(shù)名)的聲明中,將標(biāo)識(shí)符取出后,剩下的部分自然就是類型名。比如:

void (*func)();

其類型名為“void (*)()”。void (*)()是將void (*func)()的標(biāo)識(shí)符func去掉后形成的,所以該類型名被解釋為指向返回void函數(shù)的指針,func是指向返回void函數(shù)的指針。


同理,double*[3]是將double *p[3]的標(biāo)識(shí)符p去掉后形成的,所以該類型名被解釋為指向double的指針數(shù)組,p是指向double的數(shù)組(元素3個(gè))的指針。


在指針的定義中,void *表示通用指針的類型,它可以作為兩個(gè)具有特定類型指針之間相互轉(zhuǎn)換的橋梁。注意,“從C99版本開始,將void *類型指針賦值給其它類型指針時(shí),不再需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換”。比如:

int *pInt,;

void *pVoid;

pInt =pVoid;

當(dāng)函數(shù)可以接受任何類型的指針時(shí),則將其聲明為void *類型指針。比如:

void*memcpy(void *dst, const void *s2, size_t n);

其作用是從s2復(fù)制n個(gè)字符到dst,并返回dst的值,任何類型的指針都可以傳入memcpy()函數(shù)中。如果void作為函數(shù)的返回類型,則表示不返回任何值。如果void位于參數(shù)列表中,則表示沒有參數(shù)。size_t是C標(biāo)準(zhǔn)庫中預(yù)定義的類型,專門用于保存變量的大小。


如果要開發(fā)可移植性高的程序,應(yīng)該避免對(duì)指針進(jìn)行強(qiáng)制類型轉(zhuǎn)換,同時(shí)不要用強(qiáng)制類型轉(zhuǎn)換掩蓋編譯器提示的警告。


綜上所述,指針存儲(chǔ)的是地址,直接使用指針得到是地址;要獲得或調(diào)整存儲(chǔ)在該地址中的值,必須添加額外的“*”。變量存儲(chǔ)的是數(shù)據(jù)值,因此直接使用變量得到的是數(shù)據(jù)值;而要獲得變量的地址,就必須額外添加“&”。注意,sizeof操作符可以用在void指針上,無法將這個(gè)操作符用在void上,比如:

size_t size = sizeof(void *);

size_t size = sizeof(void);

size_t類型表示C中任何對(duì)象所能達(dá)到的最大長(zhǎng)度,它是無符號(hào)整數(shù)。size_t用作sizeof操作符的返回值類型,同時(shí)也是很多函數(shù)參數(shù)類型,比如,malloc和strlen。

注意,打印size_t類型的值時(shí),由于它是無符號(hào)整數(shù),因此不能選錯(cuò)格式,通常推薦的格式為%zu或%u或%lu。


閱讀

''

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多