




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
動態(tài)內存分配首先介紹程序運行時動態(tài)內存分配(dynamicmemoryallocation)的概念與方法。到目前為止,本教材介紹的程序設計中,變量和對象在內存中的分配都是編譯器在編譯程序時安排好了的,這帶來了極大的不便,如數組必須大開小用,指針必須指向一個已經存在的變量或對象。動態(tài)內存分配解決了這個問題。
堆內存分配
C/C++定義了4個內存區(qū)間:代碼區(qū),全局變量與靜態(tài)變量區(qū),局部變量區(qū)即棧區(qū),動態(tài)存儲區(qū),即堆(heap)區(qū)或自由存儲區(qū)(freestore)。堆內存的分配與釋放
通常定義變量(或對象),編譯器在編譯時都可以根據該變量(或對象)的類型知道所需內存空間的大小,從而系統在適當的時候為他們分配確定的存儲空間。這種內存分配稱為靜態(tài)存儲分配;
有些操作對象只在程序運行時才能確定,這樣編譯時就無法為他們預定存儲空間,只能在程序運行時,系統根據運行時的要求進行內存分配,這種方法稱為動態(tài)存儲分配。所有動態(tài)存儲分配都在堆區(qū)中進行。當程序運行到需要一個動態(tài)分配的變量或對象時,必須向系統申請取得堆中的一塊所需大小的存貯空間,用于存貯該變量或對象。當不再使用該變量或對象時,也就是它的生命結束時,要顯式釋放它所占用的存貯空間,這樣系統就能對該堆空間進行再次分配,做到重復使用有限的資源。堆的概念1、new運算符返回的是一個指向所分配類型變量(對象)的指針。對所創(chuàng)建的變量或對象,都是通過該指針來間接操作的,而且動態(tài)創(chuàng)建的對象本身沒有名字。2、一般定義變量和對象時要用標識符命名,稱命名對象,而動態(tài)的稱無名對象(請注意與棧區(qū)中的臨時對象的區(qū)別,兩者完全不同:生命期不同,操作方法不同,臨時變量對程序員是透明的)。3、堆區(qū)是不會在分配時做自動初始化的(包括清零),所以必須用初始化式(initializer)來顯式初始化。new表達式的操作序列如下:從堆區(qū)分配對象,然后用括號中的值初始化該對象。堆空間申請、釋放說明堆0Pi1.用初始化式(initializer)來顯式初始化int*pi=newint(0);2.當pi生命周期結束時,必須釋放pi所指向的目標:
deletepi;注意這時釋放了pi所指的目標的內存空間,也就是撤銷了該目標,稱動態(tài)內存釋放(dynamicmemorydeallocation),但指針pi本身并沒有撤銷,它自己仍然存在,該指針所占內存空間并未釋放。堆空間申請、釋放演示下面是關于new操作的說明1、new運算符返回的是一個指向所分配類型變量(對象)的指針。對所創(chuàng)建的變量或對象,都是通過該指針來間接操作的,而動態(tài)創(chuàng)建的對象本身沒有名字。
2、一般定義變量和對象時要用標識符命名,稱命名對象,而動態(tài)的稱無名對象(請注意與棧區(qū)中的臨時對象的區(qū)別,兩者完全不同:生命期不同,操作方法不同,臨時變量對程序員是透明的)。3、堆區(qū)是不會在分配時做自動初始化的(包括清零),所以必須用初始化式(initializer)來顯式初始化。new表達式的操作序列如下:從堆區(qū)分配對象,然后用括號中的值初始化該對象。
#include<iostream.h>#include<string.h>voidmain(){ intn; char*pc; cout<<"請輸入動態(tài)數組的元素個數"<<endl;
cin>>n;
//n在運行時確定,可輸入17
pc=newchar[n];//申請17個字符(可裝8個漢字和一個結束符)的內存空間 strcpy(pc,“堆內存的動態(tài)分配”);// cout<<pc<<endl; delete[]pc;//釋放pc所指向的n個字符的內存空間 return;}動態(tài)一維數組的建立與撤銷1.變量n在編譯時沒有確定的值,而是在運行中輸入,按運行時所需分配堆空間,這一點是動態(tài)分配的優(yōu)點,可克服數組“大開小用”的弊端,在表、排序與查找中的算法,若用動態(tài)數組,通用性更佳。一定注意:delete[]pc是將n個字符的空間釋放,而用deletepc則只釋放了一個字符的空間;2.如果有一個char*pc1,令pc1=p,同樣可用delete[]pc1來釋放該空間。盡管C++不對數組作邊界檢查,但在堆空間分配時,對數組分配空間大小是紀錄在案的。3.沒有初始化式(initializer),不可對數組初始化。
動態(tài)一維數組的說明動態(tài)數組舉例(1)(本小題10分)讀懂如下程序:#include<iostream.h>#include<math.h>doubleTriangleArea(){inti;doubledTArea;7double*pds=newdouble[5];8if(!pds)9{cout<<"Errormemoryallocation!"<<endl;10return-1;11}pds[0]=0;for(i=1;i<4;i++){cout<<"thesideis:";cin>>pds[i];pds[0]+=pds[i]/2;}pds[4]=pds[0];for(i=1;i<4;i++)pds[0]*=(pds[4]-pds[i]);dTArea=sqrt(pds[0]);23delete[]pds;returndTArea;}voidmain(){doubledArea;dArea=TriangleArea();if(dArea==-1)cout<<"Theprogramfailed!"<<endl;elsecout<<"Theareaoftriangleis"<<dArea<<endl;}讀懂各個小題程序,為了便于提問,程序的每行前面加有行號,請對所提的問題作出準確的相應解答。請寫出下列問題答案:第7行起何作用?(2分)答:第8-11行可否省去?并說明原因。(2分)答:第23行起何作用?(2分)答:此程序功能是什么?若對三次“thesideis:”提示回答分別為3,4,5,請寫出執(zhí)行結果輸出的內容。(4分)答:指針數組一個數組里存放的都是同一個類型的指針,通常我們把他叫做指針數組。比如int*a[2];它里邊放了2個int*型變量.int*a[2];
a[0]=newint[3];
a[1]=newint[3];
deletea[0];
deletea[1];
注意這里是一個數組,不能delete[];
數組指針一個指向一維或者多維數組的指針.int*b=newint[10];指向一維數組的指針b;
注意,這個時候釋放空間一定要delete[],否則會造成內存泄露,b就成為了空懸指針int(*b2)[10]=newint[10][10];注意,這里的b2指向了一個二維int型數組的首地址.
注意:在這里,b2等效于二維數組名,但沒有指出其邊界,即最高維的元素數量,但是它的最低維數的元素數量必須要指定!就像指向字符的指針,即等效一個字符串,不要把指向字符的指針說成指向字符串的指針。int(*b3)[30][20];
//三級指針――>指向三維數組的指針;
int(*b2)[20];
//二級指針;――>指向二維數組的指針;
b3=newint[1][20][30];
b2=newint[30][20];
刪除這兩個動態(tài)數組可用下式:
delete[]b3;
//刪除(釋放)三維數組;
delete[]b2;
//刪除(釋放)二維數組;float(*cp)[30][20];//三級指針;float(*bp)[20];//二級指針;cp=newfloat[1][20][30];bp=newfloat[30][20];兩個數組都是由600個浮點數組成,前者是只有一個元素的三維數組,每個元素為30行20列的二維數組,而另一個是有30個元素的二維數組,每個元素為20個元素的一維數組。刪除這兩個動態(tài)數組可用下式:delete[]cp;//刪除(釋放)三維數組;delete[]bp;//刪除(釋放)二維數組;多維數組比較與辨識constintm=4,n=6;
//行列數//1、先看二維數組的動態(tài)創(chuàng)建:voidmain(){double**data;
data=newdouble*[m];
//申請行if((data)==0){cout<<"Couldnotallocate.bye...";exit(-1);}for(intj=0;j<m;j++){data[j]=newdouble[n];
//設置列if(data[j]==0){cout<<"Couldnotallocate.Bye...";exit(-1);}}//空間申請結束,下為初始化
for(inti=0;i<m;i++)for(intj=0;j<n;j++)data[i][j]=i*n+j;動態(tài)創(chuàng)建和刪除一個m*n個元素的數組。采用指針數組方式來完成二維數組的動態(tài)創(chuàng)建。
display(data);//2、二維數組的輸出,此處略。//3、再看二維數組的撤銷與內存釋放:for(inti=0;i<m;i++)delete[]data[i];
//注意撤銷次序,先列后行,與設置相反delete[]data;return;}二維數組的內存釋放可以做成函數,調用語句de_allocate(data);voidde_allocate(double**data){for(inti=0;i<m;i++)delete[]data[i];delete[]data;return;}
在VC++平臺上演示本例。3.內存泄漏(memoryleak)和重復釋放。new與delete是配對使用的,delete只能釋放堆空間。如果new返回的指針值丟失,則所分配的堆空間無法回收,稱內存泄漏,同一空間重復釋放也是危險的,因為該空間可能已另分配,所以必須妥善保存new返回的指針,以保證不發(fā)生內存泄漏,也必須保證不會重復釋放堆內存空間。4.動態(tài)分配的變量或對象的生命期。無名對象的生命期并不依賴于建立它的作用域,比如在函數中建立的動態(tài)對象在函數返回后仍可使用。我們也稱堆空間為自由空間(freestore)就是這個原因。但必須記住釋放該對象所占堆空間,并只能釋放一次,在函數內建立,而在函數外釋放是一件很容易失控的事,往往會出錯。
7.1.2堆對象與構造函數
通過new建立的對象要調用構造函數,通過deletee刪除對象也要調用析構函數。CGoods*pc;pc=newCGoods;//分配堆空間,并構造一個無名//的CGoods對象;…….deletepc;//先析構,然后將內存空間返回給堆;
堆對象的生命期并不依賴于建立它的作用域,所以除非程序結束,堆對象(無名對象)的生命期不會到期,并且需要顯式地用delete語句析構堆對象,上面的堆對象在執(zhí)行delete語句時,C++自動調用其析構函數。正因為構造函數可以有參數,所以new后面類(class)類型也可以有參數。這些參數即構造函數的參數。但對創(chuàng)建數組,則無參數,并只調用缺省的構造函數。見下例類說明://下面注意如何使用:voidmain(){intn;CGoods*pc,*pc1,*pc2;pc=newCGoods(“夏利2000”,10,118000);
//調用三參數構造函數
pc1=newCGoods();//調用缺省構造函數cout<<’輸入商品類數組元素數’<<endl;cin>>n;pc2=newCGoods[n];
//動態(tài)建立數組,不能初始化,調用n次缺省構造函數
……deletepc;deletepc1;delete[]pc2;}此例告訴我們堆對象的使用方法:申請堆空間之后構造函數運行;釋放堆空間之前析構函數運行;再次強調:由堆區(qū)創(chuàng)建對象數組,只能調用缺省的構造函數,不能調用其他任何構造函數。如果沒有缺省的構造函數,則不能創(chuàng)建對象數組。otherName堆字符串拷貝前堆字符串otherName*thisName
拷貝后
圖7.1淺拷貝
對象pcName堆字符串第一個對象堆字符串對象pcName對象pc1Name
兩個對象
圖7.1淺拷貝
voidmain(){ CGoodspc;//調用缺省構造函數
CGoodspc1(pc);//調用拷貝構造函數}
//程序執(zhí)行完,對象pc1和pc將被析構,此時出錯。淺拷貝帶來的問題析構時,如用缺省的析構函數,則動態(tài)分配的堆空間不能回收。如果用有“deleteName;”語句的析構函數,則先析構pc1時,堆空間已經釋放,然后再析構pc
時出現了二次釋放的問題。這時就要重新定義拷貝構造函數,給每個對象獨立分配一個堆字符串,稱深拷貝。對象pcName堆字符串拷貝前堆字符串對象pcName對象pc1Name
淺拷貝后
圖7.1淺拷貝
對象pcName堆字符串拷貝前堆字符串對象pcName對象pc1Name
深拷貝后
圖7.1深拷貝
堆字符串2深拷貝——自定義拷貝構造CGoods(CGoods&other){//自定義拷貝構造
this->Name=newchar[21];strcpy(this->Name,other.Name);this->Amount=other.Amount;this->Price=other.Price;this->Total_value=other.Total_value;}//學生類定義:classstudent{ char*pName;//指針成員public: student(); student(char*pname); student(student&s);//拷貝構造函數 ~student(); student&operator=(student&s);
//拷貝賦值操作符};//缺省構造函數:student::student(){pName=NULL;cout<<“Constructor缺省\n";}[例7.3]定義copystructor和拷貝賦值操作符(copyAssignmentOperator)實現深拷貝。
//帶參數構造函數:student::student(char*pname){if(pName=newchar[strlen(pname)+1])strcpy(pName,pname);cout<<"Constructor"
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)院考試試題及答案
- 安全用電考試試題及答案
- 公務員調解面試題及答案
- 技校招生考試試題及答案
- 考公務員面試題及答案
- 深圳社工考試試題及答案
- 金融基礎考試試題及答案
- 2025年地理高考復習 微專題 地球運動與生產生活(講義)(解析版)
- 2025簡易原材料采購合同樣本下載
- 2025福建泉州市仙公山風景名勝區(qū)有限公司招聘7人筆試參考題庫附帶答案詳解
- ISOTS 22163專題培訓考試
- 六年級下冊數學課件-第4單元 比例 整理和復習 人教版(共21張PPT)
- JJF(魯) 142-2022 稱重式雨量計校準規(guī)范
- Adobe-Illustrator-(Ai)基礎教程
- 程序的運行結果PPT學習教案
- 圓柱鋼模計算書
- 合成寶石特征x
- 查擺問題及整改措施
- 年度研發(fā)費用專項審計報告模板(共22頁)
- 隧道工程隧道支護結構設計實用教案
- 得力打卡機破解Excel工作表保護密碼4頁
評論
0/150
提交評論