C語言常見錯誤分析_第1頁
C語言常見錯誤分析_第2頁
C語言常見錯誤分析_第3頁
C語言常見錯誤分析_第4頁
C語言常見錯誤分析_第5頁
已閱讀5頁,還剩110頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

C語言常見錯誤及問題分析C語言編程常見錯誤分析C語言是目前世界上最通用的編程語言之一,也是目前研發(fā)使用最多的編程語言。同各種各樣的bug作斗爭,是每一個C程序員每天所面臨的課題。本文將從微觀角度出發(fā),對一些常見出錯類型的案例進行分析,希望大家今后能避免類似的錯誤。數(shù)字和表達式錯誤變量的錯誤數(shù)組和指針的錯誤邏輯和流程的錯誤數(shù)字和表達式的錯誤運算符和優(yōu)先級的錯誤字節(jié)序的錯誤魔鬼數(shù)字宏定義的錯誤sizeof的錯誤最常見的運算符錯誤就是“=”和“==”的誤用intmain(){ intret; ret=GetVars(); if(ret=VOS_OK) { ...... } return0; }錯誤后果:1.變量被錯誤賦值。2.邏輯判斷不正確。建議和結(jié)論:盡管是初級bug但是還是常有發(fā)生,建議寫成“VOS_OK==ret”的形式,這樣在編譯的時候即可發(fā)現(xiàn)這種錯誤?!?+”和“--”在表達式中的應(yīng)用#definemypower(a)((a)*(a))intmain(){ inti=1,j=2; j=mypower(++i); printf("\r\n%i=dj=%d",i,j); return0; }錯誤后果:結(jié)果與期望的不一致建議與結(jié)論:1.對于“++”和“--”這種基本的知識還是應(yīng)該掌握的2.自增和自減變量在本表達式中不要再引用,否則可能依賴編譯器實現(xiàn)3.沒有把握的用法千萬不要用,否則可能導致意想不到的錯誤優(yōu)先級問題也是編碼初期容易出現(xiàn)的問題C語言有眾多的運算符號,它們之間的優(yōu)先級關(guān)系非常復雜,即使是一個熟練的C程序員,要清楚地記住這些優(yōu)先級關(guān)系也絕非易事。if(high<<8|low)==>if((high<<8)|low)if(a|b&&a&c)==>if((a|b)&&(a&c))if(a|b==1)==>if((a|b)==1)建議和結(jié)論:不要使用默認優(yōu)先級,使用括號來保證自己的運算優(yōu)先級,不要考驗字節(jié)的記憶力。字節(jié)序錯誤網(wǎng)絡(luò)設(shè)備和網(wǎng)絡(luò)協(xié)議的開發(fā)涉及到許多字節(jié)序問題。網(wǎng)絡(luò)序:所有設(shè)備、系統(tǒng)都一樣,表示字節(jié)在網(wǎng)絡(luò)中的傳輸順序,也就是設(shè)備接收、發(fā)送數(shù)據(jù)的順序。數(shù)據(jù)總是按照從“高字節(jié)”===>“低字節(jié)”的順序發(fā)。主機序:依賴于CPU,表示的是字節(jié)在內(nèi)存中的存放順序。對于Intel系列CPU:高字節(jié)存放高位,低字節(jié)存放低位;和網(wǎng)絡(luò)序相反;一般稱為“小尾”或者“小端”(littleendian)對于PPC系列CPU:高字節(jié)存放低位,低字節(jié)存放高位;和網(wǎng)絡(luò)序相同;一般稱為“大尾”或者“打端”(bigendian)對于32位int型數(shù)0x12345678,intel和ppc系列CPU的存放格式分別如下:假定有一種協(xié)議報文,報文類型為2個字節(jié),某一特定類型為0xABCD兩個因為字節(jié)序錯誤導致的真實案例案例一:某一種協(xié)議,其中一種報文類型是3,但是在代碼中填寫報文類型時沒有進行字節(jié)序轉(zhuǎn)換,導致對端總是識別報文類型為0x0300,于是對端認為是非法報文,直接作丟棄處理后果:當時使用的是Intel的CPU,這種錯誤類型的報文從來沒有被處理過,當時也沒有做單元測試,錯誤很久以后才被發(fā)現(xiàn)。因為這個報文是用來進行協(xié)議性能優(yōu)化的,修改過后協(xié)議性能得到極大提升。案例二:某一種協(xié)議,報文中有一個字段用DWORD表示報文長度,但是在填寫報文時遺漏了字節(jié)序轉(zhuǎn)換,因為使用的是Intel的CPU,導致對端從收到的報文中提取出的報文長度為類似0x4800000000的巨大數(shù)字。我們字節(jié)的設(shè)備在接收時也遺漏了字節(jié)序轉(zhuǎn)換,所以從收到的報文中反而能正確提取出報文長度,該設(shè)備也一直沒有與cisco的設(shè)備做互通測試,使該問題一直沒有暴露出來。后果:該設(shè)備第一次開局時,與cisco設(shè)備互通,結(jié)果周邊所有cisco的設(shè)備異常重啟(cisco當年設(shè)備的魯棒性也比較差勁?。?。字節(jié)序錯誤不只在報文中存在一.聯(lián)合域定義:union{ ULONGulIP; UCHARszIP[4]; }stIPAddr;如果賦值:stIPAddr.szIP[0]=192;stIPAddr.szIP[1]=168;stIPAddr.szIP[2]=0;stIPAddr.szIP[3]=1;則大端和小端上stIPAddr.ulIP的值不同:大端:stIPAddr.ulIP=0xC0A80001;小端:stIPAddr.ulIP=0x0100A8C0;二.指針強轉(zhuǎn):定義如下變量:ULONGulTool=0x12345678;USHORT*pusTool=(USHORT*)&ulTool;UCHAR*pucTool=(UCHAR*)&ulTool;則在大端和小端上,*pusTool和*pucTool的值是不同的。大端系統(tǒng):*pusTool=0x1234*pucTool=0x12小端系統(tǒng):*pusTool=0x5678*pucTool=0x78建議和結(jié)論:1.填寫報文和解析報文時一定要注意字節(jié)序問題,使用相應(yīng)的宏操作(htonl、ntohl等)2.當取變量的一部分值時,如聯(lián)合體、強制指針轉(zhuǎn)換等,需要考慮字節(jié)序問題3.互通測試很重要魔鬼數(shù)字問題魔鬼數(shù)字是指直接使用數(shù)字,而不是使用預(yù)先定義好的宏、常量、枚舉等,這是一種不好的編程習慣。如下:l=round/3.14159;DeadInt=HelloInt*4;pstPack=malloc(36);pTcp=pIp+20;constdoublePI=3.14159;l=round/PI;#defineDEADTIME4DeadInt=HelloInt*DEADTIME;#definePACKSIZE36pstPack=malloc(PACKSIZE);#defineIPHEADLEN20pTcp=pIp+IPHEADLEN;建議和結(jié)論:1.魔鬼數(shù)字是一種不好的編程習慣,一方面代碼可讀性差,另一方面在修改多出數(shù)字時容易造成遺漏,從而各處使用導致不一致。2.不是所有的數(shù)字都是魔鬼數(shù)字3.有明確意義的數(shù)字應(yīng)該定義長宏、枚舉或者常量,如申請的內(nèi)存大小、函數(shù)的返回值、各種標記位等。宏定義錯誤宏定義最常見的問題就是沒有使用足夠的括號去保證展開的正確性。示例1:#definemul1(a,b)(a*b)#definemul2(a,b)((a)*(b))intmain(){ intx=0; x=mul1(1+2,5);/*x=11*/ x=mul2(1+2,5);/*x=15*/}示例2:#defineadd1(a,b)(a)+(b)#defineadd2(a,b)((a)+(b))intmain(){ intx=0; x=add1(1+2)*5;/*x=11*/ x=add2(1+2)*5;/*x=15*/}建議和結(jié)論:1.宏定義會忠實地進行展開,這個展開過程忽略運算符、優(yōu)先級和函數(shù)。2.宏定義里面的算術(shù)表達式里面的各個參數(shù)需要加括號,整個表達式本身也需要加括號。Sizeof問題Sizeof是一個編譯時處理的操作符,sizeof最常見的問題就是混淆了結(jié)構(gòu)的體積和結(jié)構(gòu)指針的體積。structtheNode{ inta; charb[20];}Node;...intx=0;structNode*pstNode;x=sizeof(Node);//x=24x=sizeof(pstNode);//x=4建議與結(jié)論:1.sizeof是編譯器在編譯時處理的,而不是在程序運行時處理的2.結(jié)構(gòu)指針的體積與結(jié)構(gòu)體的體積是兩回事,在32位機上,指針一般都是32位長的(即4字節(jié)),而結(jié)構(gòu)體的長度則依賴于結(jié)構(gòu)體定義structtheNode{ intb[5]; shortc;}Node;sizeof(Node)=?另一個常見的錯誤是某些結(jié)構(gòu)體定義沒有正確使用#pragmapack,導致結(jié)構(gòu)體體積的計算與理想有偏差。#pragmapack(1)structtheNode{ intb[5]; shortc;}Node;sizeof(Node)=?建議和結(jié)論:1.對齊有利于提高存儲效率,常見的系統(tǒng)一般默認4字節(jié)或8字節(jié)對齊,編譯時編譯器將選取系統(tǒng)對齊和本結(jié)構(gòu)中最?;A(chǔ)結(jié)構(gòu)二者中的較小值作為該結(jié)構(gòu)的實際對齊值。2.這個錯誤經(jīng)常發(fā)生在定義報文結(jié)構(gòu)是時,報文結(jié)構(gòu)一般都應(yīng)該按pack(1)來定義。變量的錯誤變量的類型和存儲全局變量局部變量全局變量:定義在任何函數(shù)的外部,生命周期是在整個程序的周期內(nèi)。-定義時沒有初始化,或者初始化為0的全局變量存放在bss段(對于bss段,操作系統(tǒng)在加載時會自動全部清0)-定義時初始化為非0的全局變量存放在data段局部變量:定義在函數(shù)內(nèi),只能在所在函數(shù)內(nèi)訪問-靜態(tài)局部變量存放在全局堆中,生命周期是在整個程序-普通局部變量存放在棧中,生命周期是在函數(shù)內(nèi)注意:不管什么變量都要注意初始化問題,變量不初始化而直接作為右值使用是一個常犯的錯誤。全局變量在定義是初始化,會使app文件增大。因此,對于全局的大數(shù)組,應(yīng)該盡量避免在定義是初始化,可以在程序執(zhí)行的初始化階段進行初始化。intarray[1000][1000]={1};intmain(intargc,char*argv[]){ return0;}用VC編出來的app大小大約為180Kintarray[1000][1000];intmain(intargc,char*argv[]){ return0;}用VC編出來的app大小大約為4.75M建議和結(jié)論:1.盡量避免對大的全局變量在定義時進行初始化,這樣可以減小app大小,節(jié)省存儲空間2.無論初始化與否,全局變量總是要占用運行時的內(nèi)存空間,因此要避免定義不必要的大型全局變量普遍局部變量是存放在當前任務(wù)或系統(tǒng)棧中,因此避免定義過大的局部變量,從而使堆棧溢出。intmain(intargc,char*argv[]){ intarray[1000][1000]={0}; return0;}有什么問題?示例:intfunc1(){ inta[4000]; func2(0); ...

}intfunc1(){ intb[4000]; func3(0); ...}錯誤后果:1.在嵌入式設(shè)備上,每個任務(wù)的棧大小是有限的,一般在任務(wù)創(chuàng)建是指定(一般是4-40k),一旦發(fā)生??臻g溢出,容易造成棧被寫壞,系統(tǒng)死機2.變量超大等錯誤無法通過編譯等手段發(fā)現(xiàn)3.一旦發(fā)生棧被寫壞,則函數(shù)調(diào)用棧也已被破壞,使得問題難以定位。建議和結(jié)論:1.編寫代碼時不要定義大的局部變量,如果必須要使用大的內(nèi)存,則可以通過malloc從堆中申請。2.使用局部數(shù)組時,要謹防寫越界。3.如果發(fā)生調(diào)用棧損壞,可以從局部變量超大和局部數(shù)組寫越界這個思路開始追查,看看問題出現(xiàn)時,可能發(fā)生的調(diào)用棧。示例:char*func1(){ chararr[200]; strcpy(arr,"abcd"); returnarr;}錯誤后果:1.字符串的內(nèi)存賦值到棧中,這個空間在func1返回后就不再有意義2.如果func1返回后繼續(xù)向arr這個地址寫入內(nèi)容,則會造成棧寫壞,可能導致系統(tǒng)崩潰建議與結(jié)論:1.局部變量一定不要超越其作用域的范圍2.編碼時,在函數(shù)返回指針時要特別注意,千萬不要返回??臻g地址。思考:下面程序有什么問題?structQueueglobal_q;/*定義一個隊列*/...voidospf_routing_calc(){ structQueueNoden; clean_queue(global_q);/*清空隊列*/ ... EnQueue(global_q,n);/*入隊列*/ ... if(err)/*出錯返回*/ { return } clean_queue(global_q);/*清空隊列*/ return;/*計算成功返回*/}建議與結(jié)論:1.局部變量一定不要超出其作用域的范圍2.要特別關(guān)注函數(shù)中異常分支的處理,看看異常分支中有沒有進行必要的資源回收和回退處理。數(shù)組和指針的錯誤訪問越界指針釋放錯誤指針移位錯誤數(shù)組和指針的混用訪問越界數(shù)組和內(nèi)存的訪問越界是一類最常發(fā)生的錯誤,這類錯誤一旦發(fā)生,經(jīng)常會引起內(nèi)存鏈損壞、調(diào)用棧寫壞等嚴重后果常見問題和建議:1.字符緩沖區(qū):在進行字符串操作時(strcpy、strcat等),要確保目的緩沖區(qū)的大小足夠大.(包括后面的‘\0’)2.報文緩沖區(qū):需要考慮各種報文長度,如正常報文、畸形報文、非法報文等3.數(shù)組定義:數(shù)組大小已變化,而引用的地方?jīng)]有作相應(yīng)修改,引起訪問越界。(一般是魔鬼數(shù)字導致修改不全,建議用宏來標識數(shù)組大?。?.數(shù)組下標:檢查數(shù)組下標的合法性,防止下標過大導致數(shù)組訪問越界。5.字符串的’\0’結(jié)尾:定義字符串數(shù)組時忘記后面的’\0’,是一種常見錯誤。如charstr[3]="abc";指針釋放錯誤指針釋放內(nèi)存錯誤是非常大的一類錯誤,一代代的C程序員絞盡腦汁地同這些錯誤作斗爭,在消滅錯誤的同時,他們也在不斷創(chuàng)造新的錯誤!最簡單的一類錯誤就是遺漏指針釋放,導致內(nèi)存泄漏。主要原因:1.異常處理分支、多個處理分支中遺漏內(nèi)存釋放和相關(guān)的資源回收處理。建議:a:關(guān)注各個分支的資源釋放處理,尤其是新增加一個分支時。b:將資源釋放集中處理,整合成一個流程。2.責任主體不清,接口設(shè)計沒有明確釋放主體a:設(shè)計定義接口時,要明確定義資源的申請者和釋放者。引用已釋放的指針也是最常見的一類錯誤。如:free(pIntf);printf("freeinterface%s",pIntf->name);建議與結(jié)論:1.即使是剛釋放的內(nèi)存,也不能再訪問,因為里面的內(nèi)容已經(jīng)沒有意義了。2.養(yǎng)成釋放內(nèi)存后,立即將指針設(shè)成NULL的良好習慣。指針賦值除了容易造成內(nèi)存釋放后再訪問的問題外,還容易導致內(nèi)存重復釋放。pRoute->pIntf=pIntf;...free(pIntf);...if(NULL!=pRoute->pIntf){ ... theID=pRoute->pIntf->theID;/*錯誤訪問*/ free(pRoute->pIntf)/*重復釋放*/ ...}建議與結(jié)論:1.對于等價指針的情況,必須要嚴格明確申請者和釋放者。2.在釋放的時候要將所有的等價指針設(shè)成NULL指針移位錯誤指針可以通過加減運算進行推移。需要注意的是,指針的加、減運算都是基于它所指向的對象尺寸大小進行考慮的,常見的錯誤就是額外的計算了數(shù)據(jù)類型的體積。示例:intarr[100];int*p=arr;p=p+sizeof(int);/*錯誤*/p=p+1;/*正確*/建議和結(jié)論:1.指針偏移時,編譯器已經(jīng)考慮了對象的體積,編程者不需要再畫蛇添足。2.void型指針由于編譯器不知道其對象體積,所以不能進行加、減偏移運算指針和數(shù)組的混用指針和數(shù)組有相同之處,但是在絕大多數(shù)情況下二者含義是不同的,不可混淆。char*b="abc";。chara[4]="abc";1.給指針賦值為數(shù)組首地址,可以通過推移指針來訪問數(shù)組各元素chara[4];char*p=a;通過a[1]和*(p+1)都可以正確訪問數(shù)組2.函數(shù)使用數(shù)組作為參數(shù)時,數(shù)組地址只能以指針的方式傳入,此時通過數(shù)組或指針的方式定義都是可以的。chara[4];intfunc(char*p){ ...}...ret=func(a);char*p=a;流程和邏輯的錯誤統(tǒng)計和計數(shù)的錯誤任務(wù)切換統(tǒng)計和計數(shù)錯誤統(tǒng)計包括很多,如報文數(shù)目統(tǒng)計、錯誤統(tǒng)計、各種表項統(tǒng)計等。統(tǒng)計計數(shù)的常見錯誤一般有以下幾種情況:1.統(tǒng)計計數(shù)變量沒有初始化。2.多個分支時,某些分支中遺漏統(tǒng)計。3.統(tǒng)計計數(shù)變量溢出統(tǒng)計計數(shù)錯誤引起的問題大多不太嚴重,但有時也可能導致嚴重的問題。一個真實的案例:某一子系統(tǒng)采用一個LONG型計數(shù)器記錄系統(tǒng)啟動到當前的毫秒數(shù),并以此進行定時器調(diào)度,不幸的是,這個計數(shù)器沒有進行溢出保護,也就是說0x7FFFFFFF/1000/3600/24=24.8天后,這個計數(shù)器將發(fā)生溢出。后果:這個設(shè)備在實驗室從來沒有這么長時間運行過,問題一直沒有被發(fā)現(xiàn);結(jié)果,一次開局,路由器在網(wǎng)上運行了二十多天,計數(shù)器發(fā)生溢出,定時器系統(tǒng)崩潰,系統(tǒng)重啟。由于沒有調(diào)用棧,重啟時沒有任何操作,問題很難定位;直到又過了二十多天,問題再次出現(xiàn),研發(fā)人員發(fā)現(xiàn)間隔的時間驚人的一致,才發(fā)現(xiàn)了這個問題。建議與結(jié)論:1.統(tǒng)計計數(shù)雖然簡單,但也不可以掉以輕心,分支流程容易遺漏,需要特別關(guān)注。2.對于計數(shù)器一定要考慮什么時候會溢出,以及溢出時的保護處理。任務(wù)切換1.在多任務(wù)編程時,需要考慮任務(wù)切換時對全局資源的保護處理。2.如果多個任務(wù)間有嚴格的時序要求,則需要保證各個任務(wù)間的同步,防止亂序而導致意想不到的結(jié)果。C語言程序設(shè)計常見問題1.下面代碼有什么問題?當我試圖訪問p2是得到了錯誤,為什么?char*p1,p2;p2=(char*)0x80000000;作者的原因是定義兩個char型的指針,但是上述代碼實際上等價于:char*p1,p2;或者char*p1;charp2;因此作者在后面的指針賦值語句時會產(chǎn)生錯誤正確的定義法是:char*p1,*p2;2.C語言的關(guān)鍵字extern在函數(shù)的聲明中起到什么作用?如:externintfunc(int);如果函數(shù)的聲明中帶有關(guān)鍵字extern,除了暗示這個函數(shù)可能在其他源文件里定義外,無其他作用。下面兩個函數(shù)的聲明沒有明顯區(qū)別:externintfunc(int);intfunc(int);3.下面兩種對于定義string_t數(shù)據(jù)類型的方法,哪一種更好?typedefchar*string_t#definestring_tchar*通常講,typedef要比#define好,尤其在對指針的處理上。示例:typedefchar*string_t1#definestring_t2char*string_t1s1,s2;string_t2s3,s4上述變量s1、s2、s3都被定義成了char*,而s4被定義成了char,而不是預(yù)期的char*。根本原因就是#define只是進行字符串的簡單替換。除此之外,宏定義有#ifdef和#ifndef等用來進行邏輯判斷,這是它的長處。4.typedef中的嵌套定義問題。下面定義有問題嗎?typedefstructmystruct{ inta; MY_STRUCTURE*pnext;}MY_STRUCTURE;規(guī)范的做法是:typedefstructmystruct{ inta; structmystruct*pnext;};typedefstructmystructMY_STRUCTURE5.下面的方法定義數(shù)組有問題嗎?constinta=5;intarray[a];這個問題討論的是常量與只讀變量的區(qū)別。常量,如5、“abc”等肯定是只讀的,因為程序中根本沒有地方存放它們的值,別說修改它了。而只讀變量,則是在內(nèi)存中開辟一個地方來存儲它的值,只不過這個值不允許修改。C語言的const就是用來限定一個變量不允許修改的修飾符。上述代碼的a被修飾為只讀變量,但它本質(zhì)上還是變量,而不是常量。C語言規(guī)定,數(shù)組的定義必須是常量,而不能是只讀變量。6.下面的代碼中編譯器會報一個錯誤,為什么?typedefchar*charptr;charstr[4]="abc";constchar*p1=str;constcharptrp2=str;p1++;p2++;p2++有問題,會報錯。因為constcharptrp2與#define不同,不是進行簡單的字符串替換,它實際上定義的是一個常指針,即指針初始化后不允許改變。類似于constlongxyz;只不過charptr是我們自己定義的類型。7.為什么結(jié)構(gòu)體變量不能用“==”和“!=”進行比較?C語言是一種低級語言,沒有一種簡單有效的辦法實現(xiàn)結(jié)構(gòu)體變量的比較。具體原因有兩個:1)結(jié)構(gòu)體對齊問題,導致的一些填充域,這些填充域可能是隨機值,因此按字節(jié)比較;2)如果按域比較,結(jié)構(gòu)體中若含有指針域,則指針域所指內(nèi)容的比較則無法實現(xiàn)。因此結(jié)構(gòu)體的比較往往需要各應(yīng)用模塊根據(jù)自己的需要專門寫一個比較函數(shù)8.如何初始化一個聯(lián)合體的任意成員?typedefunionmyunion{ intx; shorty;}UN;UNux={4,1};//很遺憾,標準C不支持初始化union的任意成員,而只能初始化它的第一個成員。9.下面代碼能告訴我們b在a和c之間嗎?if(a<b<c){ ...}上述代碼實際等價于if((a<b)<c){ ...}意思是,取(a<b)判斷的邏輯結(jié)果,然后再和c比大小。10.C語言的指針很重要,也很靈活,不過它到底有哪些好處?請列舉1.方便使用動態(tài)分配的數(shù)組2.對相同類型或相似類型的多個變量進行通用訪問3.變相改變函數(shù)的只傳遞特性,如將變量地址作為參數(shù)傳入函數(shù),這樣就可以修改該變量的值4.動態(tài)擴展數(shù)據(jù)結(jié)構(gòu),如鏈表、hash表5.遍歷數(shù)組6.節(jié)省函數(shù)調(diào)用代價,將參數(shù)尤其是大個的參數(shù),按指針傳遞,以減少開銷。7.…………11.下面的代碼打印出來的結(jié)果是多少?inti,array[5],*ip;ip=array;for(i=0;i<5;i++){ array[i]=i;}printf("\r\n%d",*(ip+3*sizeof(int)));呵呵。。,具體打印什么我也不清楚。問題就出在ip+3*sizeof(int)上了。指針的相加實際上已經(jīng)考慮了其類型的長度。示例:如果ip所指向的地址為0x80000000,則ip+1所指的地址0x80000004。因此本題中不需要再乘以sizeof(int)了。12.*p++到底是給誰加1?是給指針p還是p所指的內(nèi)容加1?單目操作符和操作的結(jié)合順序是:從右到左一個表達式中單目運算符的執(zhí)行順序是:從左到右因此本題中實際上是對指針p加1,而不是p的內(nèi)容加1,如果要對p的內(nèi)容加1,則用下面的表達式:(*p)++13.我有一個char*類型的指針,恰好指向一個int型,我想讓指針跳過這個int,跳到下一個char,試問下面代碼能否實現(xiàn)?(int*)p++;這種實現(xiàn)標準C不支持,但是主流編譯器默認都會支持,如VC和gcc。雖然這么用一般不會有什么問題,不過還是建議大家不要這么用,上面問題可以直接用下面代碼替代:p+=sizeof(int);14.為什么我不能對void*型的指針進行算術(shù)運算?如:void*p=array;p+=5;前面說過,對指針進行算術(shù)運算(指針加、減運算)時實際上已經(jīng)考慮了該指針所指類型的大小了。同理,如果無法知道該指針類型的大小,則無法進行指針的算術(shù)運算。因為編譯器根本不知道你這個指針所指的變量占幾個字節(jié),也就無法進行指針偏移。15.有些頭文件中將NULL定義為0,為什么?NULL用于表示指針為空指針;一般用于指針變量的初始化。NULL的具體的機器表示也隨機器而定,不過一般都是0.16.在源文件里定義了一個數(shù)組:intarray[5];我能否在另一個文件里聲明一個指針,從而引用這個數(shù)組?externint*array;不可以,程序運行時會告訴你非法訪問!指向類型T的指針并不等價于類型T的數(shù)組。正確的用法是:externintarray[];17.有人說數(shù)組名無法賦值,但是下面程序確實可以工作,難道我記錯了?intfun(charsz[100]){ ... if('\0'==sz[0]) { sz=NONE; } ...}在C語言中,數(shù)組無法真正傳遞給函數(shù),因而在編譯器內(nèi)部這個函數(shù)就被解釋為:intfun(char*sz)因此,C語言函數(shù)參數(shù)若是數(shù)組,則實際傳遞的是一個指針,也就是該數(shù)組的首地址。因此上述函數(shù)當然沒有問題。18.假定有一個整型數(shù)組a,則a和&a有什么區(qū)別?inta[2];a和&a有什么區(qū)別?a是指向數(shù)組第一個元素的指針,而&a則是指向整個數(shù)組的指針。intx,a[2];int*p=NULL;p=a;x=*p;p=&a;19.什么時候需要定義指向數(shù)組的指針而不是數(shù)組元素的指針?如何定義?intarray[2][3]={{1,2,3},{4,5,6}};如果需要對行進行遍歷的話,就需要一個指向行的指針,定義如下:

intarray[2][3]={{1,2,3},{4,5,6}}; int(*p)[3]=0; //int*p2=0; p=&array[1]; //p2=array[1];20.有人寫了一個將整數(shù)轉(zhuǎn)換成字符串的函數(shù),char*itoa(intn){ charbuf[20]; sprintf(buf,"%d",n); returnbuf;}如果按下面調(diào)用,有什么問題? char*p3; p3=itoa(5); { intc; c=1; } printf("%s",p3);char*itoa(intn)函數(shù)返回了??臻g的地址,要知道,??臻g的內(nèi)容在該函數(shù)返回后就不再受到保護,也就是說此時函數(shù)的??臻g的已經(jīng)被系統(tǒng)回收。如果函數(shù)返回了??臻g的內(nèi)存,則很容易出現(xiàn)錯誤的結(jié)果,因為該空間可能已經(jīng)分配給了其他函數(shù)或任務(wù)。21.為什么有些代碼中malloc申請內(nèi)存時的返回值總是強制類型轉(zhuǎn)換一下,不轉(zhuǎn)行不行?char*p=(char*)malloc(100);在C語言引入void*指針類型之前,這種強制轉(zhuǎn)換主要是為了消除編譯告警。在C語言引入了void*指針類型之后,這種轉(zhuǎn)換已經(jīng)沒有必要,但是這是一種良好的編程習慣,建議大家繼續(xù)保持這種強制轉(zhuǎn)換,增加代碼可讀性。22.下面的程序有什么問題?#definePI3.14intfit_size(doublerount){ if((rount/PI==10)||(rount/PI==20)) { return1; } return0}此題同樣是浮點數(shù)比較問題。浮點數(shù)不能直接與某一個整數(shù)進行比較,而是應(yīng)該和一個范圍比較。上面程序應(yīng)該改成:#definePI3.14intfit_size(doublerount){ if((fabs(rount/PI-10)<0.000001)||(fabs(rount/PI-20)<0.000001)) { return1; } return0}23.下面這樣的寫法正確嗎?intfun(inta){ intk=0; switch(a) { default: k=1; break; case1: k=2; break; case2: k=3; break; } return0}這種寫法正確,因為switch……case

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論