語言進(jìn)階第四講存儲(chǔ)器與指針_第1頁
語言進(jìn)階第四講存儲(chǔ)器與指針_第2頁
語言進(jìn)階第四講存儲(chǔ)器與指針_第3頁
語言進(jìn)階第四講存儲(chǔ)器與指針_第4頁
語言進(jìn)階第四講存儲(chǔ)器與指針_第5頁
免費(fèi)預(yù)覽已結(jié)束,剩余33頁可下載查看

下載本文檔

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

文檔簡(jiǎn)介

第四講存儲(chǔ)器與指針(Memory&Pointer)張哲

東南大學(xué)國(guó)家專用集成電路系統(tǒng)工程技術(shù)研究中心目錄存儲(chǔ)器,還是存儲(chǔ)器!內(nèi)存陷阱!動(dòng)態(tài)內(nèi)存分配算法指針的基本概念指針是什么?指針是一個(gè)變量,它的值是另外一個(gè)變量的地址0x00C7指針變量int*p0x00C7變量inta上面例中的兩個(gè)0x00C7有什么區(qū)別?指針的基本概念指針的類型指針?biāo)鎯?chǔ)的那個(gè)變量類型,就稱為指針的類型有三個(gè)不同類型的指針:IntI[2],*pI=&I[0];右邊的三個(gè)運(yùn)算有何不同?pI++;CharC[2],*pC=&C[0];pC++;FloatF[2],*pF=&F[0];pF++;指針的三個(gè)要素指針指向的地址(指針的內(nèi)容);指針指向的地址上的內(nèi)容;指針本身的地址。例:intA,*pA,**ppA; pA=&A; ppA=&pA;

&ppAppA*ppA**ppA

&pApA*pA

&AA指針的大?。ㄖ羔樧兞空加玫膬?nèi)存空間)與所用的CPU尋址空間大小和類型有關(guān),而與指針類型無關(guān)。8位CPU的指針長(zhǎng)度為1~2個(gè)字節(jié)(51單片機(jī)的情況較為復(fù)雜,是1~3個(gè)字節(jié));16位CPU的指針長(zhǎng)度為2個(gè)字節(jié)(如MSP430);32位CPU的指針長(zhǎng)度為4個(gè)字節(jié)(如Intel80386)。上面所述是通常情況,并不是全部符合。指針的初始化變量在沒有賦值之前,其值不定的。對(duì)于指針變量,可以表述為:指向不明程序訪問了一個(gè)沒有初始化的指針:int*p;p的內(nèi)存是隨機(jī)的一個(gè)數(shù),比如:

0x3FF0073D程序隨即訪問內(nèi)存地址:

0x3FF0073D0x3FF0073D是哪里的內(nèi)存?說不定正好是Windows老大要用的內(nèi)存,你竟敢訪問!Windows一生氣,藍(lán)屏。

因此,指針在使用前一定要初始化;在使用前一定要確定指針是非空的?。?!

數(shù)組與指針C語言中只有一維數(shù)組,數(shù)組的大小必須在編譯時(shí)作為一個(gè)常數(shù)確定下來。數(shù)組的元素可以是任何類型,甚至是數(shù)組,由此可以方便地得到多維數(shù)組;數(shù)組的任何操作,即使采用數(shù)組下標(biāo)進(jìn)行的運(yùn)算都等于對(duì)應(yīng)的指針運(yùn)算??梢杂弥羔樞袨樘娲鷶?shù)組下標(biāo)的運(yùn)算。

inta[4],*p; p=a;//等價(jià)于p=&a[0]; *(a+2)=0;//等價(jià)于a[2]=0; p[2]=0;//等價(jià)于a[2]=0;數(shù)組與指針但數(shù)組不同于指針:數(shù)組名a是指向數(shù)組起始位置的“常量”。因此,不能對(duì)數(shù)組名進(jìn)行賦值操作。例: inta[4],*p; p=a; a=p; p++; a++;數(shù)組與指針但數(shù)組不同于指針:數(shù)組名a是指向數(shù)組起始位置的“常量”。因此,不能對(duì)數(shù)組名進(jìn)行賦值操作。例: inta[4],*p; p=a;//正確 a=p;//錯(cuò)誤 p++;//正確 a++;//錯(cuò)誤空指針是個(gè)特殊指針值,也是唯一對(duì)任何指針類型都合法的指針值。一個(gè)指針變量具有空指針值,表示它當(dāng)時(shí)沒指向有意義的東西,處于閑置狀態(tài)??罩羔樦涤?表示,這個(gè)值絕不會(huì)是任何程序?qū)ο蟮牡刂?。給一個(gè)指針賦值0就表示要它不指向任何有意義的東西。為了提高程序的可讀性,標(biāo)準(zhǔn)庫定義了一個(gè)與0等價(jià)的符號(hào)常量NULL,程序里可以寫:p=NULL;//注意不要與空字符NUL混淆,NUL等價(jià)于‘\0’或者:p=0;注意:在編程時(shí),應(yīng)該將處于閑置的指針賦為空指針;在調(diào)用指針前一定要判斷是否為空指針,只有在非空情況下才能調(diào)用。通用指針通用指針可以指向任何類型的變量。通用指針的類型用(void*)表示,因此也稱為void指針。下面的第三行定義了兩個(gè)通用指針: intn,*p; double*q; void*gp1,*gp2;可以直接把任何變量的地址賦給通用指針,例如,有了上面定義,下面賦值是合法的: gp1=(void*)&n;可以把通用指針的值賦給普通的指針。如果被賦值指針與通用指針?biāo)缸兞康念愋筒环枰獙憦?qiáng)制轉(zhuǎn)換: p=(int*)gp1;函數(shù)指針函數(shù)指針即指向函數(shù)地址的指針。利用該指針可以知道函數(shù)在內(nèi)存中的位置。因此也可以利用函數(shù)指針調(diào)用函數(shù)。函數(shù)指針的定義方法:

<類型>(*<函數(shù)指針名>)(......)

例如:

int(*func)(void)

這里,func就是一個(gè)函數(shù)指針。

注意:int*func(void)和int(*func)(void)的區(qū)別

int*func(void);

int(*func)(void);函數(shù)指針函數(shù)指針即指向函數(shù)地址的指針。利用該指針可以知道函數(shù)在內(nèi)存中的位置。因此也可以利用函數(shù)指針調(diào)用函數(shù)。函數(shù)指針的定義方法:

<類型>(*<函數(shù)指針名>)(......)

例如:

int(*func)(void)

這里,func就是一個(gè)函數(shù)指針。

注意:int*func(void)和int(*func)(void)的區(qū)別

int*func(void);//這是返回一個(gè)整型指針的函數(shù)

int(*func)(void);//這是一個(gè)函數(shù)指針函數(shù)指針的使用例

:假定有下面的函數(shù)聲明

intptr;

intfn(int);

int(*fp)(int);

指出下面的語句是否合法?,為什么?。

fp=fn;

fp=fn(5);

fp=&ptr;函數(shù)指針的使用例

:假定有下面的函數(shù)聲明

intptr;

intfn(int);

int(*fp)(int);

指出下面的語句是否合法?,為什么?。

fp=fn;//正確,將函數(shù)fn的地址賦給fp

fp=fn(5);//錯(cuò)誤,返回給fp的結(jié)果不是一個(gè)函數(shù)地址。

fp=&ptr;//錯(cuò)誤,ptr的地址不在程序代碼區(qū),兩種數(shù)據(jù)類型不能轉(zhuǎn)換。從上面的例子可以看出:不能將普通變量的地址賦給函數(shù)指針;不能將函數(shù)的調(diào)用賦給函數(shù)指針可以將函數(shù)名賦給一個(gè)函數(shù)指針函數(shù)指針的用途一旦函數(shù)可以通過指針被傳遞、被記錄,這開啟了許多應(yīng)用,特別是下列三者多態(tài)(polymorphism):指用一個(gè)名字定義不同的函數(shù),這函數(shù)執(zhí)行不同但又類似的操作,從而實(shí)現(xiàn)“一個(gè)接口,多種方法”多線程(multithreading):將函數(shù)指針傳進(jìn)負(fù)責(zé)建立多線程的API中:例如Win32的CreateThread(...pF...)?;卣{(diào)(call-back):所謂的回調(diào)機(jī)制就是:「當(dāng)發(fā)生某事件時(shí),自動(dòng)呼叫某段程序代碼」。事件驅(qū)動(dòng)(event-driven)的系統(tǒng)經(jīng)常透過函數(shù)指針來實(shí)現(xiàn)回調(diào)機(jī)制,例如Win32的WinProc其實(shí)就是一種回調(diào),用來處理窗口的訊息。函數(shù)指針數(shù)組例:在一個(gè)計(jì)算器的例子中,有如下一些語句:

switch(oper){

case

ADD:

result=add(op1,op2);

break;

case

SUB:

result=sub(op1,op2);

break;

...}

對(duì)于一個(gè)復(fù)雜的計(jì)算器,switch語句將非常長(zhǎng)。我們可以用函數(shù)指針數(shù)組來完成。

double

add(double,double);

double

sub(double,double);

...

double

(*oper_func[])(double,double)={add,sub,...};第2個(gè)步驟是用下面語句替換前面整條switch語句:

result=oper_func[oper](op1,op2);

oper從數(shù)組中選擇正確的函數(shù)指針,而函數(shù)調(diào)用操作符將執(zhí)行這個(gè)函數(shù)。關(guān)于函數(shù)指針引用的說明標(biāo)準(zhǔn)寫法:(*pf)(arg1,arg2,…);ANSIC中允許的簡(jiǎn)寫:pf(arg1,arg2,…);注意:以上的寫法是簡(jiǎn)寫形式ASIXWindow中的函數(shù)指針typedefstructwindow_class{ U8 wndclass_id; STATUS(*create)(char*caption,U32style,U16x,U16y,U16width,U16hight,U32wndid,U32menu,void**ctrl_str,void*exdata); STATUS(*destroy)(void*ctrl_str); STATUS(*msg_proc)(U32win_id,U16asix_msg,U32lparam,void*data,U16wparam,void*reserved); STATUS(*msg_trans)(void*ctrl_str,U16msg_type,U32areaId,P_U16data,U32size,PMSGtrans_msg); STATUS(*repaint)(void*ctrl_str,U32lparam); STATUS(*move)(void*ctrl_str,U16x,U16y,U16width,U16hight,void*reserved); STATUS(*enable)(void*ctrl_str,U8enable); STATUS(*caption)(void*ctrl_str,char*caption,void*exdata); STATUS(*information)(void*ctrl_str,structasix_window*wndinfo);}WNDCLASS;ASIXWindow中的函數(shù)指針WNDCLASSWindowClass[]={{WNDCLASS_WIN, wn_create, wn_destroy, wn_msgproc, wn_msgtrans,wn_repaint, NULL,NULL,wn_caption,NULL},{WNDCLASS_BUTTON,Btn_create,Btn_destroy, Btn_msg_proc,Btn_msg_trans,Btn_repaint,NULL,Btn_enable,Btn_caption,NULL},{WNDCLASS_SELECT,sl_create,sl_destroy,sl_msg_proc,sl_msg_trans,sl_repaint,NULL,sl_enable, sl_caption,NULL},{WNDCLASS_SELECTCARD,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL},{WNDCLASS_MENU,menu_create,menu_destroy,menu_msgproc,menu_msgtrans,mn_repaint,NULL,NULL,NULL,NULL},{WNDCLASS_LIST, Lbox_create, Lbox_destroy,Lbox_msgproc,Lbox_msgtrans,lb_repaint,NULL,NULL,NULL,NULL},{WNDCLASS_KEYBD,kbd_create, kbd_destroy, kbd_msgproc,kbd_msgtrans,kbd_repaint,NULL,NULL,NULL,NULL},{WNDCLASS_SCROLL,sb_create, sb_destroy, sb_msgproc, sb_msgtrans,sb_repaint, NULL,sb_enable,NULL,NULL},{WNDCLASS_KEYBAR,kb_create, kb_destroy, kb_msgproc, kb_msgtrans,NULL,NULL, NULL,NULL, NULL},#ifdefASIX_DEBUG {WNDCLASS_TEST,tst_create,tst_destroy,tst_msgproc,tst_msgtrans,NULL,NULL,NULL,NULL,NULL} #endif };內(nèi)存陷阱!看看這段代碼有什么問題?char*DoSomething(…){ chari[32*1024]; memset(i,0,32*1024); … returni;{兩個(gè)重大問題:1,臨時(shí)變量是通過堆棧實(shí)現(xiàn)的,太大的臨時(shí)變量數(shù)組會(huì)沖掉堆棧2,返回堆棧中的地址是非常危險(xiǎn)的,因?yàn)槎褩V械闹涤肋h(yuǎn)是不確定的看看這段代碼有什么問題?voidDoSomething(…){ inti; intj; intk; memset(&k,0,3*sizeof(int)); …}這段代碼的作用是將3個(gè)臨時(shí)變量清零但是這段代碼有兩個(gè)假設(shè):1,編譯器將I,j,k三個(gè)變量通過堆棧表示2,壓棧順序是I,j,k(假設(shè)堆棧是滿遞減堆棧)3,如果K在寄存器怎么辦?對(duì)K取地址操作將產(chǎn)生DataAboart關(guān)于臨時(shí)變量不要對(duì)臨時(shí)變量作取地址操作,因?yàn)槟悴恢谰幾g器是否將這個(gè)變量映射到了寄存器不要返回臨時(shí)變量的地址,或臨時(shí)指針變量,因?yàn)槎褩V械膬?nèi)容是不確定的(出了這個(gè)函數(shù),存放在堆棧中的局部變量就沒有意義了?。┎灰谏暾?qǐng)大的臨時(shí)變量數(shù)組,你的臨時(shí)變量是在堆棧中實(shí)現(xiàn)的,你有多大的堆棧呢?問題?現(xiàn)在要為一個(gè)矩形區(qū)域申請(qǐng)一塊內(nèi)存保存這塊的數(shù)據(jù),如果每個(gè)Pixle占用2個(gè)bit,如何分配內(nèi)存?Char*buffer;buffer=malloc(x*y/4);Buffer=malloc(x*y/4+1);看看這段代碼有什么問題?char*DoSomething(…){ char*p,*q; if((p=malloc(1024))==NULL)returnNULL; if((q=malloc(2048))==NULL)returnNULL; … returnp;}如果q沒有申請(qǐng)到,首先應(yīng)該釋放p,然后再返回NULL!看看這段代碼有什么問題?voidFreeWindowsTree(windows*Root){ if(Root!=NULL) { window*pwnd; /*釋放pwndRoot的子窗口..*/ for(pwnd=Root->Child;pwnd!=NULL;pwnd=pwnd->Sibling) FreeWindowTree(pwnd); if(Root->strWndTitle!=NULL) FreeMemory(Root->strWndTitle); FreeMemory(Root); }}Pwnd已經(jīng)被釋放了,但是在for循環(huán)中被再次引用關(guān)于動(dòng)態(tài)內(nèi)存總是檢查動(dòng)態(tài)內(nèi)存分配是否成功后再引用該指針!在分配struct空間是總是使用sizeof分配內(nèi)存時(shí)寧濫勿缺(別忘了加一)總是Free由malloc()函數(shù)返回的指針按照ANSIC標(biāo)準(zhǔn)Free函數(shù)是沒有返回值的錯(cuò)誤處理時(shí)不要忘了其他已分配空間的釋放動(dòng)態(tài)內(nèi)存分配算法問題的提出按照調(diào)用者的要求分配合適大小的Mem,返回該內(nèi)存塊的首指針。如果沒有足夠的內(nèi)存返回空指針。用戶不再使用該內(nèi)存時(shí)可以調(diào)用Free函數(shù)釋放該內(nèi)存塊快速分配算法并盡量減少內(nèi)存碎片的情況ptrSize=1為了方便管理,我們將內(nèi)存按照8

溫馨提示

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

評(píng)論

0/150

提交評(píng)論