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

分享

小議char *和C語言的字符串...

 wangzai117 2006-04-27
 小議char *和C語言的字符串

作者:乾坤一笑

來源:http://blog./smileonce/archive/2005/06/26/8330.html

摘要:介紹了C語言中的char *和字符串,比較深入

前幾天和清風(fēng)雨交談strncpy()函數(shù)的時(shí)候,他認(rèn)為“如果一個(gè)函數(shù)有一個(gè)char * str的參數(shù),那么str一定是一個(gè)字符串”,而我對(duì)此不以為然。難得到了周末,抽得出功夫,談?wù)勎覍?duì)char *含義的認(rèn)識(shí),與大家共同討論一下。

C語言是開發(fā)操作系統(tǒng)的首選語言,在很多方面都能從C代碼中看到機(jī)器的固有性質(zhì)。比如,PASCAL語言的數(shù)組索引是從1開始計(jì)數(shù),而C語言就是從0開始計(jì)數(shù)。從0開始計(jì)數(shù)不太符合一般人的正常思維模式,但是為什么C語言要采用這種設(shè)計(jì)方式呢?因?yàn)镃語言最初主要是為操作系統(tǒng)開發(fā)人員和編譯器設(shè)計(jì)人員設(shè)計(jì)的——對(duì)于經(jīng)常需要考察內(nèi)存地址的開發(fā)人員,偏移量的概念在他們腦子里面根深蒂固。要把100個(gè)int型的整數(shù)放在從地址0x0000開始的一段內(nèi)存中,如果系統(tǒng)是按Byte編址的,那么第100個(gè)元素(其數(shù)組索引為99)的要放入的地址必然是:0x0000 + sizeof(int) * 99, 而不是乘以100,所以索引以0開始是很有好處的。(C語言的底層特性請(qǐng)參考P.V.D.L的《Expert C Programming——Deep C Secrets》,中文版《C專家編程》)

同樣而言,C語言對(duì)所謂字符串的處理也和其他語言不同。(參見拙著《我用錯(cuò)了strcat() 》文后的評(píng)論) 它同樣體現(xiàn)了便于系統(tǒng)設(shè)計(jì)的特點(diǎn)。例如unix系統(tǒng)總是把設(shè)備都映射為文件,對(duì)I/O流、光驅(qū)、硬盤、modem的訪問最終都轉(zhuǎn)換為了對(duì)文件的處理。而文件,也可以看作是一個(gè)長長的字符數(shù)組(文件以EOF結(jié)尾)。C語言沒有專門定義字符串?dāng)?shù)據(jù)類型(如其他語言中的string),它用以‘\0‘結(jié)尾的字符數(shù)組來表示一個(gè)邏輯意義上的字符串。C語言用一些對(duì)于字符數(shù)組的處理函數(shù)(特別是對(duì)以‘\0‘結(jié)尾的字符數(shù)組的處理函數(shù))來處理所謂的以‘\0‘結(jié)尾的字符串,并把他們放在string.*、stdio.*等一些標(biāo)準(zhǔn)庫文件中。string這個(gè)字眼也就對(duì)人造成了某些誤解,好像是C語言中定義了字符串這種類型一樣。其實(shí)C語言只定義了char、int、float、void、poiner這幾種基本類型,這正是C語言簡潔之處。至于所謂的字符串,只是對(duì)字符數(shù)組的一種特殊應(yīng)用而已。

由于沒有了“字符串類型”,“傳char *參數(shù)就是傳一個(gè)字符串進(jìn)來”之說自然也不攻自破。那么char *真正的含義是什么?我們不妨用大家最熟悉的int來對(duì)比一下。

#include <stdio.h>

int main(int argc, char *argv[])
{
int b[3] = { 17, 18, 19 };
int a = 5;
int d = 2103157716;
int * i; // pay attention to this variable(注意:這個(gè)指針 i)

i = b;
printf("%d \n", *i);  // i points to a array, *i gets the first number of the array, 
                          // i 是指向一個(gè)數(shù)組的 *i 是這個(gè)數(shù)組的第一個(gè)元素 // *i does not get the all elements of the array. (注: *i 不是指向所有的元素的)
i = b + 1; // okey, i can get whichever element of the array.
                        // 好了, i 得到了那個(gè)數(shù)組的第二個(gè)元素了(想想是不是呢)
printf("%d \n", *i); printf("Int size: %d \n", sizeof(int)); printf("Address0: %#x \n", i); // if i++, the value of i add by sizeof(int) i++; printf("Address1: %#x \n", i); i = &a; // i also can point to a int variable. as i is a pointer, we shoule printf("%d \n", *i); // use & to get the address of a. printf("%#x \n", d); // I use a big number to prove that int * is only a pointer, i = &d; // which is not tightness to int type. printf("%#x \n", *((unsigned char*)i)); return 0; }

代碼中的int * i就是我們關(guān)注的焦點(diǎn)。它是一個(gè)指向int指針。也就是說:i指向一個(gè)內(nèi)存地址,從這個(gè)地址開始存儲(chǔ)了一個(gè)數(shù)據(jù)。int * i中的int標(biāo)明應(yīng)該使用int類型(長度為sizeof(int)個(gè)字節(jié))來從這個(gè)地址取數(shù)據(jù),也就是說要一次取sizeof(int)個(gè)byte的數(shù)據(jù)來拼成最后的結(jié)果。最后一個(gè)例子也證明了這一點(diǎn):如果我們強(qiáng)制用unsigned char的大小的數(shù)據(jù)類型來對(duì)這個(gè)地址操作,就只能取出數(shù)據(jù)的一部分。反過來說,如果用較大數(shù)據(jù)類型來取實(shí)際存儲(chǔ)較小數(shù)據(jù)類型的數(shù)據(jù),就有可能越界操作內(nèi)存,取回一些雜亂的內(nèi)容或?qū)е孪到y(tǒng)崩潰。int b[]這個(gè)數(shù)組,標(biāo)明有一組數(shù),放在以&b開始地址的內(nèi)存空間內(nèi),每個(gè)元素占用了sizeof(int)個(gè)byte的內(nèi)存單元;如果有類似于i=&b;i++;的操作,i的值就每次遞增sizeof(int)而不是1,這樣確保了i每次都能恰好取回一個(gè)正確的int。

同理,char * c也是如此。如果我們定義了一個(gè)char *的變量c,那么c也只不過是一個(gè)指向內(nèi)存中某個(gè)地址的指針而已。之所以標(biāo)明它是char *的類型,就是說要以sizeof(char)為單位去內(nèi)存中取數(shù)。所以,我們應(yīng)該稱呼char * c為指向char類型的指針——而不是說c就是字符串。為什么傳一個(gè)char *指針給printf(),strlen()之類的函數(shù),它就能把它當(dāng)作一個(gè)字符串來處理呢?沒錯(cuò),我們不是定義了‘\0‘來表示一個(gè)"字符串"的終結(jié)么?我們只需從起始地址不斷累加,遍歷字符數(shù)組的每一個(gè)元素,直到找到一個(gè)‘\0‘為止,就算是處理一個(gè)字符串了——從起始地址到‘\0‘為止的字符數(shù)組元素構(gòu)成一個(gè)“字符串”,這就是C語言設(shè)計(jì)字符串的原理。

所以,當(dāng)一個(gè)函數(shù)要求傳入一個(gè)char *的參數(shù),并不一定這個(gè)參數(shù)就一定是字符串(以‘\0‘結(jié)尾的字符數(shù)組),char *只是一個(gè)字符指針而已,它僅僅提供了一個(gè)內(nèi)存地址和每次遍歷元素的偏移量而已。究竟函數(shù)對(duì)傳入的參數(shù)有什么要求,還要視函數(shù)的具體實(shí)現(xiàn)而定。(我想ANSI C應(yīng)該對(duì)參數(shù)有所要求和規(guī)定,可惜偶沒有ANSI C文件,無法參考。 )C語言一般約定是用char * str來表示以‘\0‘結(jié)尾的字符數(shù)組,但是由于某些實(shí)現(xiàn)上的效率的考慮,往往沒有嚴(yán)格遵守這個(gè)約定。C語言的設(shè)計(jì)理念中沒有強(qiáng)調(diào)使用者一定要使用遵守這個(gè)約定,不遵守這個(gè)約定也不違背C語言的基本語法規(guī)則。這或許可以看作是C語言和創(chuàng)造和使用它的黑客群體崇尚自由的一種特色、一種精神文化吧。


小練習(xí):
1)參照上面int *的例子來編寫一個(gè)類似代碼驗(yàn)證一下char *是否也有類似特性。
2)C語言這么設(shè)計(jì)字符串會(huì)在那些方面的處理上有為難之處。
3)考察C語言標(biāo)準(zhǔn)庫函數(shù)中,有那些函數(shù)傳入char*的參數(shù)是一定要求以‘\0‘結(jié)尾的,那些函數(shù)對(duì)char *參數(shù)不做這個(gè)檢查。

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=670277

    本站是提供個(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)論公約

    類似文章 更多