王牌对王牌第一季综艺,黄视频在线观看网站,世界一级毛片,成人黄色免费看

薈聚奇文、博采眾長、見賢思齊
當(dāng)前位置:公文素材庫 > 計劃總結(jié) > 工作總結(jié) > 《C專家編程》總結(jié)

《C專家編程》總結(jié)

網(wǎng)站:公文素材庫 | 時間:2019-05-29 22:40:34 | 移動端:《C專家編程》總結(jié)

《C專家編程》總結(jié)

《C專家編程》總結(jié)

開始讀《C專家編程》之前,有一個很擔(dān)心的問題:94年出的講語言的書,在現(xiàn)在(201*)還有多少是適用的。因此,一邊讀,一邊用VS201*做實驗。最后發(fā)現(xiàn)大部分內(nèi)容都還在用。讀完后,覺得最精彩的部分有二:一是講解如何理解聲明,二是深入地講解數(shù)組名與指針。下文是將看書過程中所做的筆記進(jìn)行的整理。

p.s:以下代碼均在VS201*測試過

1.使用無符號數(shù)時要特別注意(不推薦使用無符號數(shù))

當(dāng)無符號數(shù)與有符號數(shù)在同一條表達(dá)式中出現(xiàn)時,有符號數(shù)會被轉(zhuǎn)換為無符號數(shù)。e.g:

intfeng=-1;

unsignedintyan=5;

boolresult=(fengvoid(*signal(intsig,void(*func)(int)))(int);//signal是一個函數(shù),該函數(shù)接收一個int,一個函數(shù)指針,并返回一個函數(shù)指針

5.左值與右值

左值通常表示存儲結(jié)果的地方(地址),其值在編譯時可知右值通常表示地址的內(nèi)容,其值通常要到運(yùn)行時才知道

6.指針與數(shù)組名不等同的情況(定義為數(shù)組,卻聲明為指針,或者反過來)

前提知識(假設(shè)有定義:intarray[10],*ptr;):

a.使用數(shù)組名下標(biāo)訪問(如:array[1]),會直接將數(shù)組名的地址加上偏移值作為變量的地址(即array[1]的地址)

b.使用指針下標(biāo)訪問(如:ptr[1]),會先取指針指向的內(nèi)容,然后將這個內(nèi)容加上偏移值作為變量的地址(即ptr[1]的地址)

不等同的原因:

當(dāng)定義為數(shù)組,卻聲明為指針時,相當(dāng)于用指針下標(biāo)訪問的方法來解析一個數(shù)組名下標(biāo),即先取數(shù)組第0號元素的內(nèi)容,然后將這個內(nèi)容加上偏移值作為變量的地址,從而訪問了不該訪問的東西。反之亦然。7.指針與數(shù)組等同的情況

a.編譯器將表達(dá)式中的數(shù)組名當(dāng)作指向該數(shù)組第0號元素的指針,下標(biāo)當(dāng)作指針的偏移量,即array[i]會被當(dāng)作*(array+i)

b.編譯器將函數(shù)參數(shù)聲明中的數(shù)組名當(dāng)作指向該數(shù)組第0號元素的指針,即在函數(shù)內(nèi)部得到的是指針,而不是數(shù)組名

基于a情況,可知這條謠言是假的(至少在一維數(shù)組中一定不成立):用指針迭代數(shù)組比用下標(biāo)迭代數(shù)組更快

基于b情況,可解釋為什么在傳遞數(shù)組后,不能用以下方法計算數(shù)組長度

intArrayLength(intarr[]){

returnsizeof(arr)/sizeof(arr[0]);//返回值必定是1,因為此時的arr是一個指針,而不是數(shù)組名}

注意b情況的將數(shù)組改寫為指針并不是遞歸定義的,e.g:

實參charzero[10][10]被改寫為char(*zero)[10],這里將數(shù)組的數(shù)組改寫為數(shù)組的指針

實參char*zero[10]被改寫為char**zero,這里將指針數(shù)組改寫為指針的指針

實參cahr(*zero)[10]不改變,因為此時的zero是指針,而不是數(shù)組8.interposition

interposition指用戶定義的函數(shù)取代庫中聲明完全相同的函數(shù),注意這不是指重載,而是指下面這種:

voidzero();//userdefinedfunctionvoidzero();//libraryfunction

出現(xiàn)interposition時,要特別注意以下情況:

voidzero();//userdefinedfunctionintmain(){

zero();//調(diào)用用戶定義的函數(shù)zero,而不是庫函數(shù)zero

FengYan();//假設(shè)這是另一個庫函數(shù),并且函數(shù)內(nèi)調(diào)用庫函數(shù)zero,此時由于interposition,變成調(diào)用用戶定義的zeroreturn0;}

備注:

出現(xiàn)interposition時,在VS201*會出現(xiàn)warning:inconsistentdlllinkage9.堆棧段作用

a.存儲局部變量

b.函數(shù)調(diào)用時,存儲有關(guān)的維護(hù)信息

c.用作暫時存儲區(qū)。e.g:計算一個很長的表達(dá)式時,會把部分結(jié)果先壓到堆棧中

擴(kuò)展閱讀:C語言要點總結(jié)

《C和指針》《C專家編程》《C陷阱與缺陷》《C語言編程要點》

《編程精粹--Microsoft編寫優(yōu)質(zhì)無錯C程序秘訣》

總結(jié)

說明:總結(jié)的知識點主要源于上面的4本書,《編程精粹--Microsoft編寫優(yōu)質(zhì)無錯C程序秘訣》這本書未做總結(jié),該書有清晰版的pdf格式的電子版。

--wuliming--201*-04-25

wuliming_sc@163.comwuliming_sc@qq.com

目錄

字符與字符串的區(qū)別(c缺陷與陷阱1.5節(jié))....................................................................................................................................4指針與數(shù)組1(c缺陷與陷阱3.1節(jié))................................................................................................................................................5指針與數(shù)組2(c和指針.P141.)......................................................................................................................................................6指針和數(shù)組的相同與不同(c專家編程.P199.).................................................................................................................................8用malloc為字符串分配存儲空間時的注意事項(c缺陷與陷阱3.2節(jié))........................................................................................10字符串常量(c和指針.P269.)........................................................................................................................................................12用字符串常量初始化指針和數(shù)組(c專家編程.P87.)....................................................................................................................13二維數(shù)組下標(biāo)操作的相關(guān)概念(c和指針.P156.)...........................................................................................................................14指向一維、二維數(shù)組的指針(c和指針.P158.)...............................................................................................................................17array_name和&array_name的異同........................................................................................................................................18數(shù)組作為函數(shù)的參數(shù)時,不能通過sizeof運(yùn)算符得到該數(shù)組的大小............................................................................................18用strlen()求字符串的長度(c和指針.P159.)...............................................................................................................................19‘char**’和‘constchar**’的兼容性問題(c專家編程.P19.)..........................................................................................22空指針相關(guān)的問題(c缺陷與陷阱3.5節(jié))......................................................................................................................................23NULL和NUL的區(qū)別..................................................................................................................................................................24未初始化的指針和NULL指針的區(qū)別(c和指針.P95.)..................................................................................................................25理解函數(shù)的聲明(c缺陷與陷阱2.1節(jié)).........................................................................................................................................27函數(shù)參數(shù)的傳值調(diào)用(c和指針.P122.).........................................................................................................................................29函數(shù)指針(c和指針.P260.)...........................................................................................................................................................31作為函數(shù)參數(shù)的多維數(shù)組(c和指針.P159.)..................................................................................................................................32強(qiáng)制類型轉(zhuǎn)換相關(guān)概念(c專家編程.P187.)..................................................................................................................................34malloc()、calloc()、realloc()...................................................................................................................................................36常見的動態(tài)內(nèi)存錯誤(c和指針.P223.).........................................................................................................................................37在程序退出main()函數(shù)之后,還有可能執(zhí)行一部分代碼嗎?........................................................................................................38總線錯誤和段錯誤相關(guān)概念(c專家編程.P157.)...........................................................................................................................39怎樣判斷一個字符是數(shù)字、字母或其它類別的符號?....................................................................................................................40怎樣將數(shù)字轉(zhuǎn)換為字符串?............................................................................................................................................................42怎樣將字符串轉(zhuǎn)換為數(shù)字?............................................................................................................................................................44字符串拷貝和內(nèi)存拷貝函數(shù)..........................................................................................................................................................47字符串和內(nèi)存數(shù)據(jù)比較函數(shù)..........................................................................................................................................................49連接字符串的函數(shù)........................................................................................................................................................................51查找字符/字符串的函數(shù)...............................................................................................................................................................52qsort()函數(shù).............................................................................................................................................................................58bsearch()函數(shù).............................................................................................................................................................................59lsearch(線性搜索)...................................................................................................................................................................60lfind(線性搜索).......................................................................................................................................................................60srand(設(shè)置隨機(jī)數(shù)種子)..........................................................................................................................................................61rand(產(chǎn)生隨機(jī)數(shù))...................................................................................................................................................................61什么是標(biāo)準(zhǔn)預(yù)定義宏?...................................................................................................................................................................62斷言assert(表達(dá)式)相關(guān)概念(c和指針.P342.)........................................................................................................................63連接運(yùn)算符“##”和字符串化運(yùn)算符"#"的作用..........................................................................................................................63注釋掉一段代碼的方法.................................................................................................................................................................66Typedef相關(guān)概念.......................................................................................................................................................................67=不同于==(c缺陷與陷阱1.1節(jié))........................................................................................................................................69詞法分析中的“貪心法”(c缺陷與陷阱1.3節(jié)).......................................................................................................................70運(yùn)算符的優(yōu)先級問題(c缺陷與陷阱2.2節(jié))..............................................................................................................................72

變量的存儲類型及初始化相關(guān)概念(c和指針.P43.)......................................................................................................................73左值和右值相關(guān)的概念(c和指針.P79.)........................................................................................................................................75變量的值和類型相關(guān)的概念(c和指針.P92.).................................................................................................................................76怎樣刪去字符串尾部的空格..........................................................................................................................................................77怎樣刪去字符串頭部的空格..........................................................................................................................................................78怎樣打印字符串的一部分.............................................................................................................................................................79結(jié)構(gòu)的自引用(c和指針.P198.)....................................................................................................................................................80結(jié)構(gòu)的存儲分配(c和指針.P206.)................................................................................................................................................81邊界計算與不對稱邊界(C缺陷與陷阱3.6節(jié))..............................................................................................................................83整數(shù)溢出(C缺陷與陷阱3.9節(jié))....................................................................................................................................................84返回整數(shù)的getchar函數(shù)(C缺陷與陷阱5.1節(jié)).........................................................................................................................85更新順序文件(C缺陷與陷阱5.2節(jié))............................................................................................................................................86隨機(jī)數(shù)的相關(guān)概念(c和指針.P328.).............................................................................................................................................87用遞歸和迭代兩種辦法解fibonacci............................................................................................................................................88

字符與字符串的區(qū)別(c缺陷與陷阱1.5節(jié))

#includeintmain(){

charch="abcdefghijklmnopqrstuvwxyz";charstr[]="abcdefghijklmnopqrstuvwxyz";printf("-----%c-----\\n%s\\n",ch,str);

return0;}

編譯該程序可以通過,但是會產(chǎn)生警告;輸出結(jié)過為:-----z-----

Abcdefghijklmnopqrstuvwxyz//在Dev-C++4.9.9.2編譯環(huán)境中可以通過,但是在VC.0中通不過

指針與數(shù)組1(c缺陷與陷阱3.1節(jié))

c語言中的數(shù)組值得注意的地方有以下兩點:

1、c語言中只有一維數(shù)組,而且數(shù)組的大小必須在編譯期間就作為一個常數(shù)確定下來(C99標(biāo)準(zhǔn)允許變長數(shù)組,GCC編譯器中實現(xiàn)了變長數(shù)組)。然而,c語言中數(shù)組的元素可以是任何類型的對象,當(dāng)然也可以是另外一個數(shù)組。這樣,要仿真出一個多維數(shù)組就不是一件難事。

2、對于一個數(shù)組,我們只能夠做兩件事:確定該數(shù)組的大小,以及獲得指向該數(shù)組下標(biāo)為0的元素的指針。其他有關(guān)數(shù)組的操作,哪怕它們乍看上去是以數(shù)組下標(biāo)進(jìn)行運(yùn)算的,實際上都是通過指針進(jìn)行的。換句話說,任何一個數(shù)組下標(biāo)運(yùn)算都等同于一個對應(yīng)的指針運(yùn)算,因此我們完全可以依據(jù)指針行為定義數(shù)組下標(biāo)的行為。

現(xiàn)在考慮下面的例子:inti;int*p;

intcalendar[12][31];

上面聲明的calendar是一個數(shù)組,該數(shù)組擁有12個數(shù)組類型的元素,其中的每個元素都是一個擁有31個整型元素的數(shù)組。因此,sizeof(calendar)的值是:31×12×sizeof(int)。

考慮一下,calendar[4]的含義是什么?因為calender是一個有著12個數(shù)組類型元素的數(shù)組,它的每個數(shù)組類型元素又是一個有著31個整型元素的數(shù)組,所以calendar[4]是calendar數(shù)組的第5個元素,是calendar數(shù)組中12個有著31個整型元素的數(shù)組之一。因此,calendar[4]的行為也表現(xiàn)為一個有著31個整型元素的數(shù)組的行為。例如,sizeof(calendar[4])的結(jié)果是:31×sizeof(int)。

又如,p=calendar[4];這個語句使指針p指向了數(shù)組calendar[4]中下標(biāo)為0的元素。因為calendar[4]是一個數(shù)組,我們可以通過下標(biāo)的形式來指定這個數(shù)組中的元素:i=calendar[4][7],這個語句也可以寫成下面這樣而表達(dá)的意思保持不變:i=*(calendar[4]+7),還可以進(jìn)一步寫成:i=*(*(calendar+4)+7)。

下面我們再看:p=calendar;這個語句是非法的,因為calendar是一個二維數(shù)組,即“數(shù)組的數(shù)組”,在此處的上下文中使用calendar名稱會將其轉(zhuǎn)換為一個指向數(shù)組的指針。而p是一個指向整型變量的指針,兩個指針的類型不一樣,所以是非法的。顯然,我們需要一種聲明指向數(shù)組的指針的方法:intcalendar[12][31];int(*monthp)[31];monthp=calendar;

int(*monthp)[31]語句聲明的*monthp是一個擁有31個整型元素的數(shù)組,因此,monthp就是一個指向這樣的數(shù)組的指針。monthp指向數(shù)組calendar的第一個元素。

指針與數(shù)組2(c和指針.P141.)

1、數(shù)組的名的值是一個指針常量,不能試圖將一個地址賦值給數(shù)組名;

2、當(dāng)數(shù)組名作為sizeof操作符的操作數(shù)時,sizeof(arrayname)返回的是整個數(shù)組的長度,而不是指向

數(shù)組的指針的長度;

3、當(dāng)數(shù)組名作為單目操作符&的操作數(shù),取一個數(shù)組名的地址所產(chǎn)生的是一個指向數(shù)組的指針,而不是一個指

向某個指針常量值的指針。

4、指針和數(shù)組并不總是相等的。為了說明這個概念,請考慮下面這兩個聲明:

inta[5];int*b;

a和b能夠互換嗎?它們都具有指針值,它們都可以進(jìn)行間接訪問和下標(biāo)操作。但是,它們還是有很大的區(qū)別的:聲明一個數(shù)組時,編譯器將根據(jù)聲明所指定的元素數(shù)量為數(shù)組保留內(nèi)存空間,然后再創(chuàng)建數(shù)組名,它的值是一個常量,指向這段空間的起始位置。聲明一個指針變量時,編譯器只為指針本身保留內(nèi)存空間,它并不為任何整型值分配內(nèi)存空間。而且,指針變量并未被初始化為指向任何現(xiàn)有的內(nèi)存空間,如果它是一個自動變量,它甚至根本不會被初始化。把這兩個聲明用圖的方法表示,可以發(fā)現(xiàn)它們之間存在顯著的不同:ab?因此,上述聲明后,表達(dá)式*a是完全合法的,但表達(dá)式*b卻是非法的。*b將訪問內(nèi)存中某個不確定的位

置,或者導(dǎo)致程序終止。另一方面,表達(dá)式b++可以通過編譯,但是a++卻不能,因為a的值是一個常量。

#include

intmain(){

//注意sizeof(num)的長度應(yīng)該為10*4=40intnum[]={0,1,2,3,4,5,6,7,8,9};printf("sizeof(num)=%d\\n",sizeof(num));//注意sizeof(str)的長度應(yīng)該為11,包括字符串后面的"\\0"charstr[]="0123456789";printf("sizeof(str)=%d\\n",sizeof(str));//注意sizeof(str1)的長度應(yīng)該為10,不包括字符串后面的"\\0",但是,最好將字符串的最后一個字符設(shè)定為空charstr1[]={"0","1","2","3","4","5","6","7","8","9"};printf("sizeof(str1)=%d\\n",sizeof(str1));//&num的類型為"int(*)[10]",表示的是一個指向長度為10的整形數(shù)組的指針int(*ptoint)[10]=#printf("sizeof(ptoint)=%d,(*ptoint)[9]=%d\\n",sizeof(ptoint),(*ptoint)[9]);//&str的類型為"char(*)[11]",表示的是一個指向長度為11的字符數(shù)組的指針,注意str數(shù)組的長度是11,而不是10char(*ptostr)[11]=&str;printf("sizeof(ptostr)=%d,(*ptostr)[9]=%c\\n",sizeof(ptostr),(*ptostr)[9]);//由于p指向的是數(shù)組num[5],所以對下標(biāo)取負(fù)值后,不會超出數(shù)組的正常取值范圍//該例子也說明了為什么下標(biāo)檢查在c語言中是一項困難的任務(wù):下標(biāo)引用可以作用于任意的指針,而不僅僅是數(shù)組名//作用于指針的下標(biāo)引用的有效性即依賴于該指針當(dāng)時恰好指向什么內(nèi)容,也依賴于下標(biāo)的值int*p=num+5;printf("p[-1]=%d,p[0]=%d,p[1]=%d\\n",p[-1],p[0],p[1]);//下面的表達(dá)式中,"num[5]和5[num]"的值是一樣的,把它們轉(zhuǎn)換成對等的間接訪問表達(dá)式,它們都等同于*(num+2)//"5[num]"這個古怪的表達(dá)式之所以可行,緣于C實現(xiàn)下標(biāo)的方法。對編譯器來說,這兩種形式并無差別//但是,決不應(yīng)該編寫形如"5[num]"的表達(dá)式,因為它會大大的影響程序的可讀性printf("num[5]=%d,5[num]=%d\\n",num[5],5[num]);getchar();

}

return0;

輸出結(jié)果為:

指針和數(shù)組的相同與不同(c專家編程.P199.)

在實際應(yīng)用中,數(shù)組和指針可以互換的情形要比兩者不可互換的情形更為常見。讓我們分別考慮“聲明”和“使用”這兩種情況。聲明本身還可以進(jìn)一步分為3種情況:外部數(shù)組的聲明;

數(shù)組的定義(定義是聲明的一種特殊情況,它分配內(nèi)存空間,并可能提供一個初始值);函數(shù)參數(shù)的聲明;

extern,如externchara[];不能改寫為指針的形式

聲明定義,如chara[10];不能改寫為指針的形式數(shù)組

函數(shù)的參數(shù),可以隨意選擇數(shù)組在表達(dá)式中使用的形式或者指針的形式

如c=a[i],可以隨意選擇數(shù)組形式或者是指針形式

也既是:作為函數(shù)參數(shù)時、在語句或表達(dá)式中使用數(shù)組時,我們可以采用數(shù)組或者指針的任何一種形式,除此之外的其他情況下,指針和數(shù)組不要互換。下面就數(shù)組和指針相同的情況做詳細(xì)的說明:規(guī)則1、表達(dá)式中的數(shù)組名被編譯器當(dāng)作一個指向該數(shù)組第一個元素的指針。

假如我們聲明:inta[10];int*p=a;

就可以通過一下任何一種方式來訪問a[i]:

p[i]*(p+i)*(a+i)

事實上,可以采用的方法很多。對數(shù)組的引用如a[i]在編譯時總是被編譯器改寫成*(a+i)的形式,C語言標(biāo)準(zhǔn)要求編譯器必須具備這個概念性的行為。

編譯器自動把下標(biāo)值的步長調(diào)整到數(shù)組元素的大小。如果整型數(shù)的長度是4個字節(jié),那么a[i+1]和a[i]在內(nèi)存中的距離就是4。對起始地址執(zhí)行加法操作之前,編譯器會負(fù)責(zé)計算每次增加的步長。這就是為什么指針總是有類型限制,每個指針只能指向一種類型的原因所在,因為編譯器需要知道對指針進(jìn)行解除引用操作時應(yīng)該取幾個字節(jié),以及每個下標(biāo)的步長應(yīng)取幾個字節(jié)。規(guī)則2、下標(biāo)總是和指針的偏移量相同。

把數(shù)組下標(biāo)作為指針加偏移量是c語言從BCPL(C語言的祖先)繼承過來的技巧。在人們的常規(guī)思維中,在運(yùn)行時增加對c語言下標(biāo)的范圍檢查是不切實際的。因為取下標(biāo)操作只是表示將要訪問該數(shù)組,但并不保證一定要訪問。而且程序員完全可以使用指針來訪問數(shù)組,從而繞過下標(biāo)操作符。在這種情況下,數(shù)組下標(biāo)范圍檢測并不能檢測所有對數(shù)組的訪問的情況。事實上,下標(biāo)范圍檢測被認(rèn)為不值得加入到c語言當(dāng)中。

還有一個說法是,在編寫數(shù)組算法時,使用指針比使用數(shù)組更有效率。這個頗為人們所接收的說法在通常情況下是錯誤的。使用現(xiàn)代的產(chǎn)品質(zhì)量優(yōu)化的編譯器,一維數(shù)組和指針引用所產(chǎn)生的代碼并不具有顯著的差別。不管怎樣,數(shù)組下標(biāo)是定義在指針的基礎(chǔ)上,所以優(yōu)化器常常可以把它轉(zhuǎn)化為更有效率的指針表達(dá)式,并生成相同的機(jī)器指令。

規(guī)則3、在函數(shù)參數(shù)的聲明中,數(shù)組名被編譯器當(dāng)作指向該數(shù)組第一個元素的指針。

在函數(shù)形參定義這個特殊情況下,編譯器必須把數(shù)組形式改寫成指向數(shù)組第一個元素的指針形式。編譯器只

向函數(shù)傳遞數(shù)組的地址,而不是整個數(shù)組的拷貝。這種轉(zhuǎn)換意味著在聲明函數(shù)的時候,以下三種形式都是合法的(同時無論實參是數(shù)組還是真的指針也都是合法的):

my_function(int*turnip){}my_function(intturnip[]){}my_function(intturnip[200]){}

用malloc為字符串分配存儲空間時的注意事項(c缺陷與陷阱3.2節(jié))

11

字符串常量(c和指針.P269.)

當(dāng)一個字符串常量出現(xiàn)在表達(dá)式中時,它的值是指針常量。編譯器把該字符串的一份拷貝存儲在內(nèi)存的某個位置,并存儲一個指向第一個字符的指針。我們可以對字符串常量進(jìn)行下標(biāo)引用、間接訪問以及指針運(yùn)算!皒yz”+1

字符串常量實際上是個指針,這個表達(dá)式計算“指針值加上1”的值。它的結(jié)果也是個指針,指向字符串中的第二個字符y*“xyz”

對一個指針執(zhí)行間接訪問操作時,其結(jié)果就是指針?biāo)赶虻膬?nèi)容。字符串常量的類型是“指向字符的指針”,所以這個間接訪問的結(jié)果就是它所指向的字符:x。注意表達(dá)式的結(jié)果并不是整個字符串,而只是它的第一個字符!皒yz”[2]

同樣可以推斷出上面這個表達(dá)式的值就是字符z。

#include

//接受一個無符號整型值,把它轉(zhuǎn)換成字符,并打印出來

//如果是打印16進(jìn)值的數(shù),可以用這種方法:putchar("0123456789ABCDEF"[value%16])voidbinary_to_ascii(unsignedlongvalue){

unsignedlongquotient;quotient=value/10;if(quotient!=0)binary_to_ascii(quotient);putchar("0123456789"[value%10]);}

intmain(){

//字符串常量實際上是個指針,這個表達(dá)式計算"指針值加上1"的值。它的結(jié)果也是個指針,

//指向字符串中的第二個字符:yprintf("%s\\n","xyz"+1);

//對一個指針執(zhí)行間接訪問操作時,其結(jié)果就是指針?biāo)赶虻膬?nèi)容。

//字符串常量的類型是"指向字符的指針",所以這個間接訪問的結(jié)果就是它所指向的字符:xprintf("%c\\n",*"abcdefg");

//同樣可以推斷出上面這個表達(dá)式的值就是字符zprintf("%c\\n","abcdefg"[3]);

binary_to_ascii(1234567);

getchar();

return0;}

用字符串常量初始化指針和數(shù)組(c專家編程.P87.)

定義指針時,編譯器并不為指針?biāo)傅膶ο蠓峙淇臻g,它只是分配指針本身的空間,除非在定義時同時賦給指針一個字符串常量進(jìn)行初始化。例如,下面的定義創(chuàng)建一個字符串常量(為其分配內(nèi)存):char*p=“breadfruit”;

注意只有對字符串常量才是如此。不能指望為浮點數(shù)之類的變量分配空間,如:float*pip=3.14;/*錯誤,無法通過編譯*/

在ANSIC中,初始化指針時所創(chuàng)建的字符串常量被定義為只讀。如果試圖通過指針修改這個字符串值,程序會出現(xiàn)未定義的行為。在有些編譯器中,字符串常量被存放在只允許讀取的文本段中,以防止它被修改。

數(shù)組也可以用字符串常量進(jìn)行初始化:chara[]=“gooseberry”;

與指針相反,由字符串常量初始化的數(shù)組是可以修改的。比如下面的語句:strncpy(a,“black”,5);將數(shù)組的值修改為“blackberry”。

#include#include

intmain(void){

char*p="thisisaexample";

//char*pi=3.14;//這樣定義是錯誤的,無法通過編譯

//p[0]="T";//修改該字符串常量時,編譯是沒問題,但是運(yùn)行時會出現(xiàn)異常

chara[]="gooseberry";strncpy(a,"black",5);

printf("%s\\n",p);printf("%s\\n",a);

return0;}

二維數(shù)組下標(biāo)操作的相關(guān)概念(c和指針.P156.)

14

15

16

指向一維、二維數(shù)組的指針(c和指針.P158.)

17

array_name和&array_name的異同

前者是指向數(shù)組中第一個元素的指針,后者是指向整個數(shù)組的指針。chara[MAX];/*arrayofMAXcharacters*/char*p=a;/*p為指向數(shù)組的指針*/

char*pa=&a;/*該語句是不正確的,pa的類型為"char*",而&a的類型為"char(*)[MAX]’*/char(*pb)[MAX]=&a;/*該語句是正確的,pb的類型為"char(*)[MAX]"*/

#include

voidmain(){

chara[5]={"a","b","c","d","\\0"};char*p=a;

//運(yùn)行下面這句后,vc6.0提示的錯誤為:cannotconvertfrom"char(*)[5]"to"char*",&a的類型應(yīng)該是指向一個數(shù)組的指針//char*pa=&a;

//所以,應(yīng)該定義一個指向相同類型和大小的數(shù)組的指針來獲得“&a”的值char(*point_to_str)[5];point_to_str=&a;

printf("%d\\n%d\\n",&p,&point_to_str);printf("%s\\n%s\\n",p,point_to_str);}

運(yùn)行結(jié)果為:12450441245040abcdabcd

數(shù)組作為函數(shù)的參數(shù)時,不能通過sizeof運(yùn)算符得到該數(shù)組的大小

當(dāng)把數(shù)組作為函數(shù)的參數(shù)時,你無法在程序運(yùn)行時通過數(shù)組參數(shù)本身告訴函數(shù)該數(shù)組的大小,因為函數(shù)的數(shù)組參數(shù)相當(dāng)于指向該數(shù)組第一個元素的指針。這意味著把數(shù)組傳遞給函數(shù)的效率非常高,也意味著程序員必須通過某種機(jī)制告訴函數(shù)數(shù)組參數(shù)的大小。為了告訴函數(shù)數(shù)組參數(shù)的大小,人們通常采用以下兩種方法:第一種方法是將數(shù)組和表示數(shù)組大小的值一起傳遞給函數(shù),例如memcpy()函數(shù)就是這樣做的:memcpy(dest,source,length);

第二種方法是引入某種規(guī)則來結(jié)束一個數(shù)組,例如在C語言中字符串總是以ASCII字符NUL("\\0")結(jié)束,而一個指針數(shù)組總是以空指針結(jié)束。請看下述函數(shù),它的參數(shù)是一個以空指針結(jié)束的字符指針數(shù)組,這個空指針告訴該函數(shù)什么時候停止工作:

voidprintMany(char*strings[]){

inti=0;

while(strings[i]!=NULL){

puts(strings[i++]);}}

C程序員經(jīng)常用指針來代替數(shù)組下標(biāo),因此大多數(shù)C程序員通常會將上述函數(shù)編寫得更隱蔽一些:voidprintMany(char*strings[]){

while(*strings){

puts(*strings++);}}

盡管你不能改變一個數(shù)組名的值,但是strings是一個數(shù)組參數(shù),相當(dāng)于一個指針,因此可以對它進(jìn)行自增運(yùn)算,并且可以在調(diào)用puts()函數(shù)時對strings進(jìn)行自增運(yùn)算。

用strlen()求字符串的長度(c和指針.P159.)

庫函數(shù)strlen的原型為:size_tstrlen(charconst*string);

strlen返回一個類型為size_t的值。這個類型是在頭文件stddef.h中定義的,它是一個無符號整型類型。在表達(dá)式中使用無符號數(shù)可能導(dǎo)致不可預(yù)期的結(jié)果。例如,下面兩個表達(dá)式看起來是相等的:

if(strlen(str1)>=strlen(str2))…if(strlen(str1)-strlen(str2)>=0)…

但事實上它們是不相等的,第1條語句會按照預(yù)想的那樣工作,但第2條語句的結(jié)果將永遠(yuǎn)是真的。strlen的結(jié)果是無符號數(shù),所以操作符>=左邊的表達(dá)式也將是無符號數(shù),而無符號數(shù)決不可能是負(fù)的。表達(dá)式中如果同時包含了無符號數(shù)和有符號數(shù),可能會產(chǎn)生奇怪的結(jié)果。和上面的一對語句一樣,下面兩條語句并不相等,原因相同。

if(strlen(str1)>=10)…if(strlen(str1)-10>=0)…

如果將strlen的結(jié)果值強(qiáng)制轉(zhuǎn)換成int,就可以消除這個問題。類似的,sizeof()的返回類型也是size_t,和strlen()一樣,也存在類似的現(xiàn)象(sizeof()是一個運(yùn)算符,不是函數(shù))。

對無符號類型的建議:

盡量不要在代碼里面使用無符號類型,以免增加不必要的復(fù)雜性。尤其是,不要僅僅因為無符號數(shù)不存在負(fù)值而用它來表示數(shù)量。

盡量使用像int這樣的有符號類型,這樣在涉及升級混合類型的復(fù)雜細(xì)節(jié)時,不必?fù)?dān)心邊界情況。

對于返回類型為無符號的函數(shù)(strlen()、sizeof()),最好將結(jié)果轉(zhuǎn)換成整型((int)strlen(…)、(int)sizeof(…)),這樣可以避免出現(xiàn)比較微妙的bug(在java里面,就沒有無符號數(shù))。

#include#include#include

intmain(){

charstr1[]="0123456789";charstr2[]="abcdefghijk";

//sizeof()的返回類型也是無符號類型,無符號類型的運(yùn)算結(jié)果也被轉(zhuǎn)換成無符號類型,不可能為負(fù)//(int)sizeof(str1)(int)sizeof(str2)>0這個表達(dá)式將得到預(yù)期結(jié)果if(sizeof(str1)-sizeof(str2)>0){printf(""sizeof(str1)-sizeof(str2)"的計算結(jié)果是無符號型的,不可能為負(fù)\\n");}if(strlen(str1)>=strlen(str2)){printf("strlen的返回值為無符號整型類型,把兩個無符號整型類型做比較,會得到預(yù)期的結(jié)果\\n");}if(strlen(str1)-strlen(str2)>=0){printf("strlen(str1)=%d\\n",strlen(str1));printf("strlen(str2)=%d\\n",strlen(str2));

printf("(strlen(str1)-strlen(str2)>=0)表達(dá)式的值為:%d\\n",strlen(str1)-strlen(str2)>=0);printf(""strlen(str1)-strlen(str2)"的結(jié)果是無符號類型,無符號數(shù)不可能是負(fù)值,所以該條件永遠(yuǎn)成立\\n");}//注意:sizeof()和strlen()取得的值是不相等的//sizeof()求得的長度包括字符串末尾的那個空字符"\\0"http://strlen()求得的長度不包括字符串末尾的空字符printf("sizeof(str1)=%d\\nstrlen(str1)=%d\\n",sizeof(str1),strlen(str1));

getchar();return0;}

‘char**’和‘constchar**’的兼容性問題(c專家編程.P19.)

有時候必須非常專注的閱讀ANSIC標(biāo)準(zhǔn)才能找到某個問題的答案。一位銷售工程師把下面的代碼作為測試?yán)影l(fā)給SUN的編譯器小組。

#include

voidfoo(constchar**P){}

intmain(intargc,char**argv){

foo(argv);

return0;}

在VC6.0下編譯這段代碼,編譯器會發(fā)出警告:

cannotconvertparameter1from"char**"to"constchar**"

提交代碼的工程師想知道為什么會產(chǎn)生類似的警告,他認(rèn)為,實參char*s與形參constchar*p應(yīng)該是相容的,標(biāo)準(zhǔn)庫中所有的字符串處理函數(shù)都是這樣的。那么,為什么實參char**argv與形參constchar**P實際上不能相容呢?答案是肯定的,它們并不相容,F(xiàn)在我們回顧一下標(biāo)準(zhǔn)中有關(guān)簡單賦值的部分,它位于ANSIC第6.3.16.1節(jié),描述了下列約束條件:要使上述賦值形式合法,必須滿足下列條件之一:

兩個操作數(shù)都是指向有限定符或無限定符的相容類型的指針,左邊指針?biāo)赶虻念愋捅仨毦哂杏疫呏羔標(biāo)赶蝾愋偷娜肯薅ǚ?/p>

正是這個條件,使得函數(shù)調(diào)用中實參char*能夠與形參constchar*匹配。它之所以合法,是因為在下面的代碼中:char*cp;

constchar*cpp;cpp=cp;

左操作數(shù)是一個指向有const限定符的char的指針;右操作數(shù)是一個指向沒有限定符的char的指針;

char類型和char類型是相容的,左操作數(shù)所指向的類型具有右操作數(shù)所指向類型的限定符(無),再加上自身的限定符const(注意反過來不能賦值)。

標(biāo)準(zhǔn)第6.3.16.1節(jié)沒有說明char**實參與constchar**形參是否相容。標(biāo)準(zhǔn)6.1.2.5節(jié)中講述實例的部分聲稱:constfloat*類型并不是一個有限定符的類型,它的類型是“指向一個具有const限定符的float類型的指針”,也就是說const限定符是修飾指針?biāo)赶虻念愋,而不是指針。類似地,constchar**也是一個沒有限定符的指針類型,它的類型是“指向有const限定符的char類型的指針的指針”。由于char**和constchar**都是沒有限定符的指針類型,但它們所指向的類型不一樣(前者指向char*,后者指向constchar*),因此它們是不相容的。因此類型為char**的實參和類型為constchar**的形參是不相容的,編譯器會產(chǎn)生一條診斷信息。

空指針相關(guān)的問題(c缺陷與陷阱3.5節(jié))

#include#includeintmain(){char*p=NULL;if(p==(char*)0){printf("pisanullpoint\\n");}else{printf("pisnotanullpoint\\n");}//該語句不會引起編譯錯誤,但是運(yùn)行時會出現(xiàn)異常if(strcmp(p,(char*)0)==0){printf("can"tdereferencep\\n");}

//該語句不會引起編譯錯誤,但是運(yùn)行時會出現(xiàn)異常printf("%d",*p);

getchar();return0;}

NULL和NUL的區(qū)別

NULL是在頭文件中專門為空指針定義的一個宏。NUL是ASCII字符集中第一個字符的名稱,它對應(yīng)于一個零值。C語言中沒有NUL這樣的預(yù)定義宏。注意:在ASCII字符集中,數(shù)字0對應(yīng)于十進(jìn)制值48,不要把數(shù)字0和"\\0"(NUL)的值混同起來。

NULL可以被定義為(void*)0,而NUL可以被定義為"\\0"。NULL和NUL都可以被簡單地定義為0,這時它們是等價的,可以互換使用,但這是一種不可取的方式。為了使程序讀起來更清晰,維護(hù)起來更容易,你在程序中應(yīng)該明確地將NULL定義為指針類型,而將NUL定義為字符類型。

對指針進(jìn)行解引用操作可以獲得它的值。從定義來看,NULL指針并未指向任何東西。因此,對一個NULL指針進(jìn)行解引用操作是非法的。在對指針進(jìn)行解引用操作之前,必須確保它并非NULL指針。

未初始化的指針和NULL指針的區(qū)別(c和指針.P95.)

未初始化的指針

NULL指針

26

理解函數(shù)的聲明(c缺陷與陷阱2.1節(jié))

27

28

函數(shù)參數(shù)的傳值調(diào)用(c和指針.P122.)

#include

charga[]="abcdefghijklm";

voidmy_array_func(charca[10]){

//&ca相當(dāng)于一個指向字符數(shù)組的指針的地址

char**pp=&ca;

printf("&ca=%#x\\n",&ca);printf("ca=%#x\\n",ca);

printf("&(ca[0])=%#x\\n",&(ca[0]));printf("&(ca[1])=%#x\\n",&(ca[1]));

printf("sizeof(ca)=%d\\n\\n",sizeof(ca));}

voidmy_pointer_func(char*pa){

//&pa相當(dāng)于一個指向字符數(shù)組的指針的地址

char**pp=&pa;

printf("&pa=%#x\\n",&pa);printf("pa=%#x\\n",pa);

printf("&(pa[0])=%#x\\n",&(pa[0]));printf("&(pa[1])=%#x\\n",&(pa[1]));

printf("sizeof(pa)=%d\\n\\n",sizeof(pa));}

intmain(){

//&ga相當(dāng)于一個指向字符數(shù)組的指針的地址char(*pp)[14]=&ga;

printf("&ga=%#x\\n",&ga);printf("ga=%#x\\n",ga);

printf("&(ga[0])=%#x\\n",&(ga[0]));printf("&(ga[1])=%#x\\n",&(ga[1]));

printf("sizeof(ga)=%d\\n\\n",sizeof(ga));my_array_func(ga);my_pointer_func(ga);getchar();

return0;}

//摘自《c專家編程》p216頁,做了部分修改

運(yùn)行結(jié)果為:

從結(jié)果可以看出,數(shù)組參數(shù)的地址和數(shù)組參數(shù)的第一個元素的地址是不一樣的,比如&ca和ca的值。

函數(shù)指針(c和指針.P260.)

31

作為函數(shù)參數(shù)的多維數(shù)組(c和指針.P159.)

#include

intfunc1(int*vec){printf("一維數(shù)組做為參數(shù):通過"intfunc1(int*vec)"的形式調(diào)用函數(shù)\\n");return0;}

intfunc2(intvec[]){printf("一維數(shù)組做為參數(shù):通過"intfunc2(intvec[])"的形式調(diào)用函數(shù)\\n");return0;}

voidfunc3(intmat[3][10]){

printf("二維數(shù)組做為參數(shù):通過"voidfunc3(intmat[3][10])"的形式調(diào)用函數(shù)\\n");

return;}

voidfunc4(intmat[][10]){

printf("二維數(shù)組做為參數(shù):通過"voidfunc4(intmat[][10])"的形式調(diào)用函數(shù)\\n");return;}

voidfunc5(int(*mat)[10]){

printf("二維數(shù)組做為參數(shù):通過"voidfunc5(int(*mat)[10])"的形式調(diào)用函數(shù)\\n");return;}

voidfunc6(int**p){

printf("二維數(shù)組做為參數(shù):通過"voidfunc6(int**p)"的形式調(diào)用函數(shù)\\n");return;}

intmain(){

intvector[10]={1,2,3,4,5,6,7,8,9,10};func1(vector);func2(vector);intmatrix[3][10]={{1,2,3,4,5,6,7,8,9,10},{1,2,3,4,5,6,7,8,9,10},{1,2,3,4,5,6,7,8,9,10}};func3(matrix);func4(matrix);func5(matrix);//將matrix參數(shù)傳遞給函數(shù)"voidfunc6(int**p)"會出現(xiàn)異常//func6(matrix);

getchar();return0;}

只有當(dāng)二維數(shù)組是一個指向字符串的指針數(shù)組時,函數(shù)的聲明才可以采取char**my_array的形式。這是因為字符串和指針都有一個顯示的越界值(分別是NUL和NULL),可以作為結(jié)束標(biāo)記。至于其它的類型,并沒有一種類似的通用且可靠的值,所以并沒有一種內(nèi)置的方法知道何時到達(dá)數(shù)組某一維的結(jié)束位置。即使是指向字符串的指針數(shù)組,通常也需要一個計數(shù)參數(shù)argc,以紀(jì)錄字符串的數(shù)量。

#include#include

voidmy_func(char**p){

while(*p!=NULL)printf("%s\\n",*p++);}

intmain(){

char*p[]={"one","two","three","four","five",NULL};

my_func(p);

return0;}

強(qiáng)制類型轉(zhuǎn)換相關(guān)概念(c專家編程.P187.)

強(qiáng)制類型轉(zhuǎn)換(cast)這個術(shù)語從C語言一誕生就開始使用,即用于類型轉(zhuǎn)換,也用于消除類型歧義?梢院苋菀椎匕涯撤N類型的數(shù)據(jù)強(qiáng)制轉(zhuǎn)換為基本類型的數(shù)據(jù):在括號里寫上新類型的名稱,然后把它們放在需要轉(zhuǎn)化類型的表達(dá)式的前面。在強(qiáng)制轉(zhuǎn)換一個更為復(fù)雜的類型時,可以采取如下的方法:1、2、3、

作為一個例子,程序員經(jīng)常發(fā)現(xiàn)他們需要強(qiáng)制類型轉(zhuǎn)換以便使用qsort()庫函數(shù)。這個庫函數(shù)接收4個參數(shù),其中一個是指向比較函數(shù)的指針,qsort()函數(shù)的聲明如下:

voidqsort(void*buf,size_tnum,size_tsize,int(*comp)(constvoid*ele1,constvoid*ele2));

一個對象的聲明,它的類型就是想要轉(zhuǎn)換的結(jié)果類型;

刪去標(biāo)識符以及任何類似extern之類的存儲限定符,并把剩余的內(nèi)容放在一對括號里面;把第二步產(chǎn)生的內(nèi)容放在需要進(jìn)行類型轉(zhuǎn)換的對象的左邊。

當(dāng)調(diào)用qsort函數(shù)時,可以向它傳遞一個你所喜歡的比較函數(shù)。你的比較函數(shù)將接收實際的數(shù)據(jù)類型而不是void*參數(shù),就像下面這樣:

intintcompare(constint*i,constint*j){return*i-*j;}

這個函數(shù)并不與qsort()的comp()參數(shù)完全匹配,所以要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。假定有一個數(shù)組a,它具有10個元素,需要對它們進(jìn)行排序,根據(jù)上面列出的3個步驟,可以發(fā)現(xiàn)對qsort()的調(diào)用將會是下面這個樣子:qsort(a,10,sizeof(a[0]),(int(*)(constvoid*,constvoid*))intcompare);

#include#include

//對整型數(shù)進(jìn)行排序

intintcompare(constint*i,constint*j){

return*i-*j;}

//對double類型的數(shù)進(jìn)行排序

intdoublecompare(constdouble*i,constdouble*j){

if(*i>*j)return1;elseif(*i<*j)return-1;elsereturn0;}

intmain(){

intbase[]={3,102,5,-2,98,52,18,56,38,70};inti,len=sizeof(base)/sizeof(base[0]);for(i=0;i

printf("\\n");

qsort(base,len,sizeof(base[0]),(int(*)(constvoid*,constvoid*))intcompare);for(i=0;i

printf("%d,",base[i]);

}

printf("\\n\\n");

doublebase1[]={1.2,2.6,3.4,8.6,14.3,0.2,7.9,1.6,9.2,10.8,5.55};intlen1=sizeof(base1)/sizeof(base1[0]);for(i=0;i

printf("%5.2f,",base1[i]);}

printf("\\n");

qsort(base1,len1,sizeof(base1[0]),(int(*)(constvoid*,constvoid*))doublecompare);for(i=0;i

printf("%5.2f,",base1[i]);

}

return0;}

malloc()、calloc()、realloc()

函數(shù)malloc()和calloc()都可以用來分配動態(tài)內(nèi)存空間,但兩者稍有區(qū)別。malloc()函數(shù)有一個參數(shù),即要分配的內(nèi)存空間的大小:

void*malloc(size_tsize);

calloc()函數(shù)有兩個參數(shù),分別為元素的數(shù)目和每個元素的大小,兩個參數(shù)的乘積就是要分配的空間的大。簐oid*calloc(size_tnumElements,size_tsizeOfElement);如果調(diào)用成功,函數(shù)malloc()和calloc()都將返回所分配的內(nèi)存空間的首地址。

malloc()函數(shù)和calloc()函數(shù)的主要區(qū)別是前者不能初始化所分配的內(nèi)存空間,而后者能。如果由malloc()函數(shù)分配的內(nèi)存空間原來沒有被使用過,則其中的每一位可能都是0;反之,如果這部分內(nèi)存空間曾經(jīng)被分配、釋放和重新分配,則其中可能遺留各種各樣的數(shù)據(jù)。也就是說,使用malloc()函數(shù)的程序開始時(內(nèi)存空間還沒有被重新分配)能正常運(yùn)行,但經(jīng)過一段時間后(內(nèi)存空間已被重新分配)可能會出現(xiàn)問題。

calloc()函數(shù)會將所分配的內(nèi)存空間中的每一位都初始化為零,也就是說,如果你是為字符類型或整數(shù)類型的元素分配內(nèi)存,那么這些元素將保證會被初始化為零;如果你是為指針類型的元素分配內(nèi)存,那么這些元素通常(但無法保證)會被初始化為空指針;如果你是為實數(shù)類型的元素分配內(nèi)存,那么這些元素可能(只在某些計算機(jī)中)會被初始化為浮點型的零。

為了明確是為一個數(shù)組分配內(nèi)存空間,有些程序員會選用calloc()函數(shù)。但是,除了是否初始化所分配的內(nèi)存空間這一點之外,絕大多數(shù)程序員認(rèn)為以下兩種函數(shù)調(diào)用方式?jīng)]有區(qū)別:calloc(numElements,sizeOfElement);malloc(numElements*sizeOfElement);

需要解釋的一點是,理論上(按照ANSIC標(biāo)準(zhǔn))指針的算術(shù)運(yùn)算只能在一個指定的數(shù)組中進(jìn)行,但是在實踐中,即使C編譯程序或翻譯器遵循這種規(guī)定,許多C程序還是沖破了這種限制。因此,盡管malloc()函數(shù)并不能返回一個數(shù)組,它所分配的內(nèi)存空間仍然能供一個數(shù)組使用(對realloc()函數(shù)來說同樣如此,盡管它也不能返回一個數(shù)組)?傊(dāng)你在calloc()函數(shù)和malloc()函數(shù)之間作選擇時,你只需考慮是否要初始化所分配的內(nèi)存空間,而不用考慮函數(shù)是否能返回一個數(shù)組。

realloc函數(shù)用于修改一個原先已經(jīng)分配的內(nèi)存塊的大小。使用這個函數(shù),你可以使一塊內(nèi)存擴(kuò)大或者縮小。如果它用于擴(kuò)大一個內(nèi)存塊,那么這塊內(nèi)存原先的內(nèi)容依然保留,新增加的內(nèi)存添加到原先內(nèi)存塊的后面,新內(nèi)存并未以任何方法進(jìn)行初始化。如果它用于縮小一個內(nèi)存塊,該內(nèi)存塊尾部的部分內(nèi)存便被拿掉,剩余部分內(nèi)存的原先內(nèi)容依然保留。如果原先的內(nèi)存塊無法改變大小,realloc將分配另外一塊正確大小的內(nèi)存,并把原先那塊內(nèi)存的內(nèi)容復(fù)制到新的塊上,因此,在使用realloc之后,就不能再使用指向舊內(nèi)存的指針,而是應(yīng)該改用realloc所返回的新指針。

常見的動態(tài)內(nèi)存錯誤(c和指針.P223.)

在使用動態(tài)內(nèi)存分配的程序中,常常會出現(xiàn)許多錯誤。這些錯誤包括對NULL指針進(jìn)行解引用操作、對分配的內(nèi)存進(jìn)行操作時越過邊界、釋放并非動態(tài)分配的內(nèi)存、試圖釋放一塊動態(tài)分配的內(nèi)存的一部分以及一塊動態(tài)內(nèi)存被釋放之后還繼續(xù)使用它。以下是一些需要注意的事項:

1、在請求動態(tài)內(nèi)存分配時,要檢查所請求的內(nèi)存是否成功分配。

2、操作內(nèi)存時,不要超過動態(tài)分配的內(nèi)存的邊界。對分配的內(nèi)存之外的區(qū)域進(jìn)行訪問可能會破壞別的數(shù)據(jù),產(chǎn)生一些莫名其妙的很難發(fā)現(xiàn)的bug。

3、傳遞給free的指針必須是一個從malloc、calloc、realloc函數(shù)返回的指針。

4、動態(tài)分配的內(nèi)存必須整塊一起釋放,不允許釋放一塊動態(tài)分配的內(nèi)存的一部分(realloc函數(shù)可以縮小一塊動態(tài)分配的內(nèi)存,有效地釋放它尾部的部分內(nèi)存)。

在程序退出main()函數(shù)之后,還有可能執(zhí)行一部分代碼嗎?

可以,但這要借助C庫函數(shù)atexit()。利用atexit()函數(shù)可以在程序終止前完成一些—清理‖工作如果將指向一組函數(shù)的指針傳遞給atexit()函數(shù),那么在程序退出main()函數(shù)后(此時程序還未終止)就能自動調(diào)用這組函數(shù)。在使用atexit()函數(shù)時你要注意這樣兩點:

第一:由atexit()函數(shù)指定的要在程序終止前執(zhí)行的函數(shù)要用關(guān)鍵字void說明,并且不能帶參數(shù);第二:由atexit()函數(shù)指定的函數(shù)在入棧時的順序和調(diào)用atexit()函數(shù)的順序相反,即它們在執(zhí)行時遵循后進(jìn)先出(LIFO)的原則。

#include#include

voidmy_exit1(void){

printf("my_exit1()function!\\n");}

voidmy_exit2(void){

printf("my_exit2()function!\\n");}

voidmain(){

atexit(my_exit1);atexit(my_exit2);

printf("now,eixtthisprogram...\\n");}

輸出結(jié)果為:

now,eixtthisprogram...my_exit2()function!my_exit1()function!

總線錯誤和段錯誤相關(guān)概念(c專家編程.P157.)

在UNIX上編程時,經(jīng)常會遇到如下兩個常見的運(yùn)行時錯誤:buserror

(總線錯誤)

segmentationfault(段錯誤)

總線錯誤

總線錯誤幾乎都是由于未對齊的讀或?qū)懺斐傻。它之所以稱為總線錯誤,是因為出現(xiàn)未對齊的內(nèi)存訪問請求時,被堵塞的組件就是地址總線。對齊的意思就是數(shù)據(jù)項只能存儲在地址是數(shù)據(jù)項大小的整數(shù)倍的內(nèi)存位置上。在現(xiàn)代的計算機(jī)架構(gòu)中,尤其是RISC架構(gòu),都需要數(shù)據(jù)對齊,因為與任意的對齊有關(guān)的額外邏輯會使整個內(nèi)存系統(tǒng)更大且更慢。通過迫使每個內(nèi)存訪問局限在一個cache行或一個單獨(dú)的頁面內(nèi),可以極大地簡化如cache控制器或內(nèi)存管理單元這樣的硬件。

我們表達(dá)“數(shù)據(jù)項不能跨越頁面或cache邊界”規(guī)則的方法多少有些間接,因為我們用地址對齊這個術(shù)語來陳述這個問題,而不是直截了當(dāng)說是禁止內(nèi)存跨頁訪問,但它們說的是同一回事。例如,訪問一個8字節(jié)的double數(shù)據(jù)時,地址只允許是8的整數(shù)倍。所以一個double數(shù)據(jù)可以存儲于地址24、8008、32768,但不能存儲于地址1006,頁和cache的大小是經(jīng)過精心設(shè)計的,這樣只要遵守對齊規(guī)則就可以保證一個原子數(shù)據(jù)項不會跨越一個頁或cache塊的邊界。

段錯誤

段錯誤通常是由于解除引用一個未初始化或非法值的指針引起的。以發(fā)生頻率為序,最終可能導(dǎo)致段錯誤的常見編程錯誤是:

1、壞指針錯誤:在指針賦值之前就用它來引用內(nèi)存;或者向庫函數(shù)傳遞一個壞指針(如果調(diào)試器顯示系統(tǒng)程序中出現(xiàn)了段錯誤,很可能并不是系統(tǒng)程序引起的段錯誤,問題可能就出現(xiàn)在自己的代碼中);或者指針被釋放后還繼續(xù)訪問它的內(nèi)容。

2、改寫錯誤:越過數(shù)組邊界寫入數(shù)據(jù),在動態(tài)分配的內(nèi)存空間以外寫入數(shù)據(jù),或改寫一些堆管理數(shù)據(jù)結(jié)構(gòu)(在動態(tài)分配的內(nèi)存之前的區(qū)域?qū)懭霐?shù)據(jù)就很容易發(fā)生這種情況)。

3、指針釋放引起的錯誤:釋放同一塊內(nèi)存兩次,或釋放一塊未曾使用malloc分類的內(nèi)存,或釋放一個無效的指針。一個極為常見的與釋放內(nèi)存有關(guān)的錯誤就是在for(p=start;p;p=p->next)這樣的循環(huán)中迭代一個鏈表,并在循環(huán)體內(nèi)使用free(p)這樣的語句。這樣,在下一次循環(huán)迭代時,程序就會對已經(jīng)釋放的指針進(jìn)行解除引用操作,從而導(dǎo)致不可預(yù)料的結(jié)果。

怎樣判斷一個字符是數(shù)字、字母或其它類別的符號?

在頭文件ctype.h中定義了一批函數(shù),它們可用來判斷一個字符屬于哪一類別。下面列出了這些函數(shù):-----------------------------------------------------------------------------函數(shù)字符類別返回非零值的字符

-----------------------------------------------------------------------------isdigit()十進(jìn)制數(shù)0--9

isxdigit()十六進(jìn)制數(shù)0--9,af,或A--Fisalnum()字母數(shù)字符號0--9,a--Z,或A--Zisalpha()字母az或A--Zislower()小寫字母azisupper()大寫字母A--Z

isspace()空白符空格符,水平制表符,垂直制表符,換行符,換頁符,或回車符isgraph()非空白字符任何打印出來不是空白的字符(ASCII碼從21到7E)isprint()可打印字符

所有非空白字符,加上空格符

ispunct()標(biāo)點符除字母數(shù)字符號以外的所有非空白字符

iscntrl()控制字符除可打印字符外的所有字符(ASCII碼從00到1F,加上7F)------------------------------------------------------------------------------調(diào)用上述這些宏而不是自己編寫測試字符類別的程序有三點好處:首先,這些宏運(yùn)算速度快,因為它們的實現(xiàn)方式通常都是利用位屏蔽技術(shù)來檢查一個表,所以即使是進(jìn)行一項相當(dāng)復(fù)雜的檢查,也比真正去比較字符的值要快得多。其次,這些宏都是正確的。如果你自己編寫一個測試程序,你很容易犯邏輯上或輸入上的錯誤,例如引入了一個錯誤的字符(或漏掉了一個正確的字符)。第三,這些宏是可移植的。信不信由你,并非所有的人都使用同樣的含PC擴(kuò)充字符的ASCII字符集。也許今天你還不太在意,但是,當(dāng)你發(fā)現(xiàn)你的下一臺計算機(jī)使用的是Unicode字符集而不是ASCII字符集,你就會慶幸自己原來沒有按照字符集中的字符值來編寫程序。

其他字符轉(zhuǎn)換函數(shù):

isascii(測試字符是否為ASCII碼字符)

intisascii(intc);

檢查參數(shù)c是否為ASCII碼字符,也就是判斷c的范圍是否在0到127之間。若參數(shù)c為ASCII碼字符,則返回TRUE,否則返回NULL(0)。

toascii(將整型數(shù)轉(zhuǎn)換成合法的ASCII碼字符)

inttoascii(intc);

toascii()會將參數(shù)c轉(zhuǎn)換成7位的unsignedchar值,第八位則會被清除,此字符即會被轉(zhuǎn)成ASCII碼字符。將轉(zhuǎn)換成功的ASCII碼字符值返回。

tolower(將大寫字母轉(zhuǎn)換成小寫字母)

inttolower(intc);

若參數(shù)c為大寫字母則將該對應(yīng)的小寫字母返回。返回轉(zhuǎn)換后的小寫字母,若不須轉(zhuǎn)換則將參數(shù)c值返回。

toupper(將小寫字母轉(zhuǎn)換成大寫字母)

inttoupper(intc);

若參數(shù)c為小寫字母則將該對映的大寫字母返回。返回轉(zhuǎn)換后的大寫字母,若不須轉(zhuǎn)換則將參數(shù)c值返回。

以isalmun為例,說明這些函數(shù)的用法[剩余的其他函數(shù)跟它類似]:intisalnum(intc)

檢查參數(shù)c是否為英文字母或阿拉伯?dāng)?shù)字,若參數(shù)c為字母或數(shù)字,則返回TRUE,否則返回NULL。此為宏定義,非真正函數(shù)。

#include#includeintmain(){

charstr[]="123c@#FDsP[e?";

for(inti=0;str[i]!=0;i++){

if(isalnum(str[i]))

printf("%cisanalphanumericcharacter\\n",str[i]);}

return0;}

怎樣將數(shù)字轉(zhuǎn)換為字符串?

C語言提供了幾個標(biāo)準(zhǔn)庫函數(shù),可以將任意類型(整型、長整型、浮點型等)的數(shù)字轉(zhuǎn)換為字符串。以下是用itoa()

#include#include

intmain(){

intnum=435443435;charstr[30];

itoa(num,str,10);

printf("Thenumber"num"is%dandthestring"str"is%s.\\n",num,str);getchar();return0;}

函數(shù)將整數(shù)轉(zhuǎn)換為字符串的一個例子:

itoa()函數(shù)有3個參數(shù):第一個參數(shù)是要轉(zhuǎn)換的數(shù)字,第二個參數(shù)是要寫入轉(zhuǎn)換結(jié)果的目標(biāo)字符串,第三個參數(shù)是轉(zhuǎn)移數(shù)字時所用的基數(shù)。在上例中,轉(zhuǎn)換基數(shù)為10。

----------------------------------------------------------函數(shù)名作用

----------------------------------------------------------itoa()將整型值轉(zhuǎn)換為字符串ltoa()將長整型值轉(zhuǎn)換為字符串ultoa()將無符號長整型值轉(zhuǎn)換為字符串

----------------------------------------------------------

請注意,上述函數(shù)與ANSI標(biāo)準(zhǔn)是不兼容的。能將整數(shù)轉(zhuǎn)換為字符串而且與ANSI標(biāo)準(zhǔn)兼容的方法是使用sprintf()函數(shù),請看下例:

#include#include

intmain(){

intnum=123456;charstr[50];

sprintf(str,"%d",num);

printf("Thenumber"num"is%dandthestring"str"is%s.\\n",num,str);

getchar();return0;}

gcvt(將浮點型數(shù)轉(zhuǎn)換為字符串,取四舍五入)

char*gcvt(doublenumber,size_tndigits,char*buf);

gcvt()用來將參數(shù)number轉(zhuǎn)換成ASCII碼字符串,參數(shù)ndigits表示顯示的位數(shù)。gcvt()與ecvt()和fcvt()不同的地方在于,gcvt()所轉(zhuǎn)換后的字符串包含小數(shù)點或正負(fù)符號。若轉(zhuǎn)換成功,轉(zhuǎn)換后的字符串會放在參數(shù)buf指針?biāo)傅目臻g。該函數(shù)返回一字符串指針,此地址即為buf指針。

ecvt():將雙精度浮點型值轉(zhuǎn)換為字符串,轉(zhuǎn)換結(jié)果中不包含十進(jìn)制小數(shù)點fcvt():以指定位數(shù)為轉(zhuǎn)換精度,其余同ecvt()

#include#include

intmain(){

doublea=123.45546;doubleb=-1234.56;charptr[20]={0};

gcvt(a,7,ptr);

printf("avalue=%s\\n",ptr);char*p=gcvt(b,5,ptr);printf("bvalue=%s\\n",p);}

怎樣將字符串轉(zhuǎn)換為數(shù)字?

下列函數(shù)可以將字符串轉(zhuǎn)換為數(shù)字:

------------------------------------------------------------------------函數(shù)名

作用

------------------------------------------------------------------------atof()將字符串轉(zhuǎn)換為雙精度浮點型值atoi()將字符串轉(zhuǎn)換為整型值atol()將字符串轉(zhuǎn)換為長整型值

strtod()將字符串轉(zhuǎn)換為雙精度浮點型值,并報告不能被轉(zhuǎn)換的所有剩余數(shù)字strtol()將字符串轉(zhuǎn)換為長整值,并報告不能被轉(zhuǎn)換的所有剩余數(shù)字strtoul()將字符串轉(zhuǎn)換為無符號長整型值,并報告不能被轉(zhuǎn)換的所有剩余數(shù)字

------------------------------------------------------------------------atof(將字符串轉(zhuǎn)換成浮點型數(shù))doubleatof(constchar*nptr);

atof()會掃描參數(shù)nptr字符串,跳過前面的空格字符,直到遇上數(shù)字或正負(fù)符號才開始做轉(zhuǎn)換,而再遇到非數(shù)字或字符串結(jié)束時("\\0")才結(jié)束轉(zhuǎn)換,并將結(jié)果返回。參數(shù)nptr字符串可包含正負(fù)號、小數(shù)點或E(e)來表示指數(shù)部分,如123.456或123e-2。該函數(shù)返回轉(zhuǎn)換后的浮點型數(shù)。atof()與使用strtod(nptr,(char**)NULL)結(jié)果相同。atoi(將字符串轉(zhuǎn)換成整型數(shù))intatoi(constchar*nptr);

atoi()會掃描參數(shù)nptr字符串,跳過前面的空格字符,直到遇上數(shù)字或正負(fù)符號才開始做轉(zhuǎn)換,而再遇到非數(shù)字或字符串結(jié)束時("\\0")才結(jié)束轉(zhuǎn)換,并將結(jié)果返回。該函數(shù)返回轉(zhuǎn)換后的整型數(shù)。atoi()與使用strtol(nptr,(char**)NULL,10);結(jié)果相同。atol(將字符串轉(zhuǎn)換成長整型數(shù))longatol(constchar*nptr);

atol()會掃描參數(shù)nptr字符串,跳過前面的空格字符,直到遇上數(shù)字或正負(fù)符號才開始做轉(zhuǎn)換,而再遇到非數(shù)字或字符串結(jié)束時("\\0")才結(jié)束轉(zhuǎn)換,并將結(jié)果返回。該函數(shù)返回轉(zhuǎn)換后的長整型數(shù)。atol()與使用strtol(nptr,(char**)NULL,10);結(jié)果相同。

#include#include

intmain(){

char*a0="-1000";char*b0="456";

intc0=atoi(a0)+atoi(b0);

printf("atoi:c0=%d\\n",c0);

char*a1="-100.23";char*b1="200e-2";

floatc1=atof(a1)+atof(b1);printf("atof:c1=%f\\n",c1);

char*a2="4563453";char*b2="4563431237";

longc2=atol(a2)+atol(b2);printf("atol:c2=%ld\\n",c2);}

strtod(將字符串轉(zhuǎn)換成浮點數(shù))

doublestrtod(constchar*nptr,char**endptr);

strtod()會掃描參數(shù)nptr字符串,跳過前面的空格字符,直到遇上數(shù)字或正負(fù)符號才開始做轉(zhuǎn)換,到出現(xiàn)非數(shù)字或字符串結(jié)束時("\\0")才結(jié)束轉(zhuǎn)換,并將結(jié)果返回。若endptr不為NULL,則會將遇到不合條件而終止的nptr中的字符指針由endptr傳回。參數(shù)nptr字符串可包含正負(fù)號、小數(shù)點或E(e)來表示指數(shù)部分。如123.456或123e-2。該函數(shù)返回轉(zhuǎn)換后的浮點型數(shù)。strtol(將字符串轉(zhuǎn)換成長整型數(shù))

longintstrtol(constchar*nptr,char**endptr,intbase);

strtol()會將參數(shù)nptr字符串根據(jù)參數(shù)base來轉(zhuǎn)換成長整型數(shù)。參數(shù)base范圍從2至36,或0。參數(shù)base代表采用的進(jìn)制方式,如base值為10則采用10進(jìn)制,若base值為16則采用16進(jìn)制等。當(dāng)base值為0時則是采用10進(jìn)制做轉(zhuǎn)換,但遇到如"0x"前置字符則會使用16進(jìn)制做轉(zhuǎn)換。一開始strtol()會掃描參數(shù)nptr字符串,跳過前面的空格字符,直到遇上數(shù)字或正負(fù)符號才開始做轉(zhuǎn)換,再遇到非數(shù)字或字符串結(jié)束時("\\0")結(jié)束轉(zhuǎn)換,并將結(jié)果返回。若參數(shù)endptr不為NULL,則會將遇到不合條件而終止的nptr中的字符指針由endptr返回。該函數(shù)返回轉(zhuǎn)換后的長整型數(shù),否則返回ERANGE并將錯誤代碼存入errno中(ERANGE指定的轉(zhuǎn)換字符串超出合法范圍)

strtoul(將字符串轉(zhuǎn)換成無符號長整型數(shù))

unsignedlongintstrtoul(constchar*nptr,char**endptr,intbase);

strtoul()會將參數(shù)nptr字符串根據(jù)參數(shù)base來轉(zhuǎn)換成無符號的長整型數(shù)。參數(shù)base范圍從2至36,或0。參數(shù)base代表采用的進(jìn)制方式,如base值為10則采用10進(jìn)制,若base值為16則采用16進(jìn)制數(shù)等。當(dāng)base值為0時則是采用10進(jìn)制做轉(zhuǎn)換,但遇到如"0x"前置字符則會使用16進(jìn)制做轉(zhuǎn)換。一開始strtoul()會掃描參數(shù)nptr字符串,跳過前面的空格字符串,直到遇上數(shù)字或正負(fù)符號才開始做轉(zhuǎn)換,再遇到非數(shù)字或字符串結(jié)束時("\\0")結(jié)束轉(zhuǎn)換,并將結(jié)果返回。若參數(shù)endptr不為NULL,則會將遇到不合條件而終止的nptr中的字符指針由endptr返回。該函數(shù)返回轉(zhuǎn)換后的長整型數(shù),否則返回ERANGE并將錯誤代碼存入errno中(ERANGE指定的轉(zhuǎn)換字符串超出合法范圍)

#include#includeintmain(){

chara[]="1000000000abcde";charb[]="1000000000abcde";charc[]="ffffOPQRST";char**p;

printf("a=%d,p=%s\\n",strtol(a,p,10),*p);printf("b=%d,p=%s\\n",strtol(b,p,2),*p);printf("c=%d,p=%s\\n",strtol(c,p,16),*p);}

輸出結(jié)果為:

a=1000000000,p=abcdeb=512,p=abcdec=65535,p=OPQRST

字符串拷貝和內(nèi)存拷貝函數(shù)

strcpy(拷貝字符串)

定義函數(shù):char*strcpy(char*dest,constchar*src);

strcpy()函數(shù)只能拷貝字符串。strcpy()函數(shù)將源字符串src的每個字節(jié)拷貝到目的字符串dest中,src字符串末尾的"\\0"也被拷貝過去。strcpy()函數(shù)返回參數(shù)dest的起始地址。如果參數(shù)dest所指的內(nèi)存空間不夠大,可能會造成緩沖溢出的錯誤情況(程序員必須保證目標(biāo)字符數(shù)組的空間足夠容納需要復(fù)制的字符串。如果src字符串比dest字符串長,多余的字符仍將被復(fù)制,它們將覆蓋原先存儲于dest數(shù)組后面的內(nèi)存空間的值),在編寫程序時請?zhí)貏e留意,或者用strncpy()來取代。如果參數(shù)src和dst在內(nèi)存中出現(xiàn)重疊,其結(jié)果是未定義的。

strncpy(拷貝字符串)

定義函數(shù):char*strncpy(char*dest,constchar*src,size_tn);

strncpy()會將參數(shù)src字符串拷貝前n個字符至參數(shù)dest所指的地址。函數(shù)返回參數(shù)dest的字符串起始地址。

注意n的取值范圍,不要超過src和dest的長度。

#include#include

intmain(){

chara1[30]="string(1)";charb1[]="STRING(2)";

printf("beforestrcpy():%s\\n",a1);

printf("afterstrcpy():%s\\n",strcpy(a1,b1));

chara2[30]="string(1)";charb2[]="STRING(2)";

printf("beforestrncpy():%s\\n",a2);

printf("afterstrncpy():%s\\n",strncpy(a2,b2,6));}

memcpy(拷貝內(nèi)存內(nèi)容)

定義函數(shù):void*memcpy(void*dest,constvoid*src,size_tn);

memcpy()用來拷貝src所指的內(nèi)存內(nèi)容前n個字節(jié)到dest所指的內(nèi)存地址上。與strcpy()不同的是,memcpy()會完整的復(fù)制n個字節(jié),不會因為遇到字符串結(jié)束"\\0"而結(jié)束。memcpy()函數(shù)可以拷貝任意類型的數(shù)據(jù)。memcpy()函數(shù)返回指向dest的指針。指針src和dest所指的內(nèi)存區(qū)域不可重疊。在拷貝字符串時,通常都使用strcpy()函數(shù);在拷貝其它數(shù)據(jù)(例如結(jié)構(gòu))時,通常都使用memcpy()函數(shù)。memmove(拷貝內(nèi)存內(nèi)容)

定義函數(shù):void*memmove(void*dest,constvoid*src,size_tn);

memmove()與memcpy()一樣都是用來拷貝src所指的內(nèi)存內(nèi)容前n個字節(jié)到dest所指的地址上。不同的是,當(dāng)src和dest所指的內(nèi)存區(qū)域重疊時,memmove()仍然可以正確的處理,不過執(zhí)行效率上會比使用memcpy()略慢些。該函數(shù)返回指向dest的指針。

#includeintmain(){

chara[30]="string(1)";charb[]="string(2)";

printf("beforestrcpy():%s\\n",a);

printf("afterstrcpy():%s\\n",strcpy(a,b));

a[30]="string(1)";b[]="string(2)";

printf("beforestrncpy():%s\\n",a);

printf("afterstrncpy():%s\\n",strncpy(a,b,6));}

memccpy(拷貝內(nèi)存內(nèi)容)

定義函數(shù):void*memccpy(void*dest,constvoid*src,intc,size_tn);memccpy()用來拷貝src所指的內(nèi)存內(nèi)容前n個字節(jié)到dest所指的地址上。與memcpy()不同的是,memccpy()會在復(fù)制時檢查參數(shù)c是否出現(xiàn),若是則返回dest中值為c的下一個字節(jié)地址。該函數(shù)返回指向dest中值為c的下一個字節(jié)指針。返回值為NULL表示在src所指內(nèi)存前n個字節(jié)中沒有值為c的字節(jié)。

#include#includeintmain(){

chara[]="string(a)";charb[]="string(b)";char*p;

p=(char*)memccpy(a,b,"k",sizeof(b));

if(p==NULL){

//注意p為NULL的情況,這時不能讀取p所指的地方的內(nèi)容printf("thereturnpointerofmymccpyisnull!\\n");}else{

printf("memccpy():%s,*p=%c\\n",a,*p);}}

bcopy(拷貝內(nèi)存內(nèi)容)

定義函數(shù):voidbcopy(constvoid*src,void*dest,intn);

bcopy()與memcpy()一樣都是用來拷貝src所指的內(nèi)存內(nèi)容前n個字節(jié)到dest所指的地址,不過參數(shù)src與dest在傳給函數(shù)時是相反的位置。建議使用memcpy()取代。

字符串和內(nèi)存數(shù)據(jù)比較函數(shù)

strcmp(比較字符串)

intstrcmp(constchar*s1,constchar*s2);

strcmp()用來比較參數(shù)s1和s2字符串。字符串大小的比較是以ASCII碼表上的順序來決定,此順序亦為字符的值。strcmp()首先將s1第一個字符值減去s2第一個字符值,若差值為0則再繼續(xù)比較下個字符,若差值不為0則將差值返回。例如字符串"Ac"和"ba"比較則會返回字符"A"(65)和"b"(98)的差值(-33)。若參數(shù)s1和s2字符串相同則返回0。s1若大于s2則返回大于0的值。s1若小于s2則返回小于0的值。

strcoll(采用目前區(qū)域的字符排列次序來比較字符串)intstrcoll(constchar*s1,constchar*s2);

strcoll()會依環(huán)境變量LC_COLLATE所指定的字符排列次序來比較s1和s2字符串。若參數(shù)s1和s2字符串相同則返回0,s1若大于s2則返回大于0的值,s1若小于s2則返回小于0的值。若LC_COLLATE為"POSIX"或"C",則strcoll()與strcmp()作用完全相同。

strcasecmp(忽略大小寫比較字符串)

intstrcasecmp(constchar*s1,constchar*s2);

strcasecmp()用來比較參數(shù)s1和s2字符串,比較時會自動忽略大小寫的差異。若參數(shù)s1和s2字符串相同則返回0,s1長度大于s2長度則返回大于0的值,s1長度若小于s2長度則返回小于0的值。

strncasecmp(忽略大小寫比較字符串)

intstrncasecmp(constchar*s1,constchar*s2,size_tn);

strncasecmp()用來比較參數(shù)s1和s2字符串前n個字符,比較時會自動忽略大小寫的差異。若參數(shù)s1和s2字符串相同則返回0。s1若大于s2則返回大于0的值,s1若小于s2則返回小于0的值。

strcmpi()或stricmp():對兩個字符串進(jìn)行大小寫不敏感的比較。strncmp():對兩個字符串的一部分進(jìn)行大小寫敏感的比較。strnicmp():對兩個字符串的一部分進(jìn)行大小寫不敏感的比較。

#include#include

intmain(){

char*a="aBcDeF";char*b="AbCdEf";char*c="aacdef";char*d="ABCDEF";

printf("strcmpi(a,b):%d\\n",strcmpi(a,b));printf("stricmp(a,b):%d\\n",stricmp(a,b));printf("strcmp(a,d):%d\\n",strcmp(a,d));

printf("strncmp(a,b,3):%d\\n",strncmp(a,b,3));printf("strnicmp(a,b,3):%d\\n",strnicmp(a,b,3));

getchar();return0;}

memcmp(比較內(nèi)存內(nèi)容)

intmemcmp(constvoid*s1,constvoid*s2,size_tn);

memcmp()用來比較s1和s2所指的內(nèi)存區(qū)間前n個字符。字符串大小的比較是以ASCII碼表上的順序來決定。memcmp()首先將s1第一個字符值減去s2第一個字符的值,若差為0則再繼續(xù)比較下個字符,若差值不為0則將差值返回。例如,字符串"Ac"和"ba"比較則會返回字符"A"(65)和"b"(98)的差值(-33)。若參數(shù)s1和s2所指的內(nèi)存內(nèi)容都完全相同則返回0值。s1若大于s2則返回大于0的值。s1若小于s2則返回小于0的值。

bcmp(比較內(nèi)存內(nèi)容)

intbcmp(constvoid*s1,constvoid*s2,intn);

bcmp()用來比較s1和s2所指的內(nèi)存區(qū)間前n個字節(jié),若參數(shù)n為0,則返回0。若參數(shù)s1和s2所指的內(nèi)存內(nèi)容都完全相同則返回0值,否則返回非零值。建議使用memcmp()取代。

#include#includeintmain(){

char*a="aBcDeF";char*b="AbCdEf";char*c="aacdef";char*d="aBcDeF";

printf("memcmp(a,b):%d\\n",memcmp((void*)a,(void*)b,6));printf("memcmp(a,c):%d\\n",memcmp((void*)a,(void*)c,6));printf("memcmp(a,d):%d\\n",memcmp((void*)a,(void*)d,6));}

友情提示:本文中關(guān)于《《C專家編程》總結(jié)》給出的范例僅供您參考拓展思維使用,《C專家編程》總結(jié):該篇文章建議您自主創(chuàng)作。

來源:網(wǎng)絡(luò)整理 免責(zé)聲明:本文僅限學(xué)習(xí)分享,如產(chǎn)生版權(quán)問題,請聯(lián)系我們及時刪除。


《C專家編程》總結(jié)》由互聯(lián)網(wǎng)用戶整理提供,轉(zhuǎn)載分享請保留原作者信息,謝謝!
鏈接地址:http://www.taixiivf.com/gongwen/748323.html
相關(guān)文章