![動態(tài)內存分配_第1頁](http://file4.renrendoc.com/view5/M01/33/07/wKhkGGZBPzWAVauSAABpB29yO4A929.jpg)
![動態(tài)內存分配_第2頁](http://file4.renrendoc.com/view5/M01/33/07/wKhkGGZBPzWAVauSAABpB29yO4A9292.jpg)
![動態(tài)內存分配_第3頁](http://file4.renrendoc.com/view5/M01/33/07/wKhkGGZBPzWAVauSAABpB29yO4A9293.jpg)
![動態(tài)內存分配_第4頁](http://file4.renrendoc.com/view5/M01/33/07/wKhkGGZBPzWAVauSAABpB29yO4A9294.jpg)
![動態(tài)內存分配_第5頁](http://file4.renrendoc.com/view5/M01/33/07/wKhkGGZBPzWAVauSAABpB29yO4A9295.jpg)
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
動態(tài)內存分配1本章主要內容基本數據類型的初始化單個對象內存的動態(tài)分配與釋放對象數組內存的動態(tài)分配與釋放使用new和delete在空閑存儲區(qū)中存儲字符串多維數組內存的動態(tài)分配與釋放內存分配:靜態(tài)與動態(tài)靜態(tài)內存分配:編譯器在處理程序源代碼時(即編譯時)分配。動態(tài)內存分配:程序執(zhí)行時調用運行時刻庫函數來分配。靜態(tài)與動態(tài)內存分配的三個主要區(qū)別:靜態(tài)對象是有名字的變量,我們直接對其進行操作。而動態(tài)對象是沒有名字的變量,我們通過指針間接地對它進行操作。靜態(tài)對象的分配與釋放由編譯器自動處理。程序員需要理解這一點,但不需要做任何事情。相反,動態(tài)對象地分配與釋放,必須由程序員顯示地管理,相對來說比較容易出錯。
內存分配內存分配:靜態(tài)與動態(tài)效率與靈活性之間的平衡準則不同。靜態(tài)內存分配是在程序執(zhí)行之前進行的因而效率比較高,但是它缺少靈活性,它要求在程序執(zhí)行之前就知道所需內存的類型和數量。例如:利用靜態(tài)分配的字符串數組,我們無法很容易地處理和存儲任意的文本文件一般來說存儲未知數目的元素需要動態(tài)內存分配的靈活性。
內存分配概述在C語言中進行內存的動態(tài)分配與釋放,我們使用malloc()和free()函數。C++中不再使用C語言中的malloc()和free()函數進行內存的動態(tài)分配與釋放。因為:malloc()函數在運行時從自由內存中分配存儲單元。在C++中創(chuàng)建對象時會發(fā)生兩件事情:(1)為對象分配內存;(2)調用構造函數來初始化那個內存。而構造函數不允許向它傳遞內存地址來進行初始化。在C++中使用new和delete來進行內存的動態(tài)分配與釋放。new會觸發(fā)類對象的構造函數delete會觸發(fā)類對象的析構函數
動態(tài)內存分配動態(tài)申請內存操作符new語法格式:類型名T*指針變量名P=
new類型名T(初值列表);功能:在程序執(zhí)行期間,申請用于存放T類型對象的連續(xù)的、未命名的內存空間,并依初值列表賦以初值。結果值:成功:T類型的指針,指向新分配的內存。失?。?(NULL)new運算符是一個一元運算符。它隱含地生成一個函數來調用函數operatornew(),從這個函數返回被分配內存對象的指針。
動態(tài)內存分配釋放內存操作符delete語法格式:delete指針變量名P;delete[]指針變量名P;功能:釋放指針P所指向的內存。P必須是new操作的返回值。delete表達式首先調用析構函數,然后釋放內存(經常調用free())。若正在刪除的指針是0,則將不發(fā)生任何事情,是安全的。故開發(fā)人員經常在刪除指針后立即把指針賦值為0以免對它刪除兩次(對一個對象刪除兩次可能會產生某些問題)。使用deletevoid*可能會出錯如果想對一個void*類型指針進行delete操作,要注意這將可能成為一個程序錯誤,除非指針所指的內容是非常簡單的,因為它將不執(zhí)行析構函數。一個void*指針被初始化時指向“元”數據(它沒有指向含有析構函數的對象),在調用delete刪除void*指針時不會發(fā)生什么錯誤,因為所需要的僅是釋放指針本身(對象)的這塊內存。但這樣只會釋放對象的內存,不調用析構函數,從而也就不會釋放指針所指向的數據的內存,這樣就會引起內存泄漏。編譯這樣的程序時,編譯器會認為我們知道所做的一切,從而編譯器不會給出任何警告。所以對于void指針必須轉換為適當的類型。如何為單個對象分配動態(tài)內存語法格式:
數據類型T*指針變量名P=new數據類型T(初始化列表);示例:
int*ptrInt=newint;//Oneint
double*ptrDouble=newdouble;//Onedoublefloat**ptrPtrFloat=newfloat*;//Onepointer-to-float不同類型所占用的不同的空間由編譯器自動處理。
動態(tài)內存分配如何初始化基本類型C++中很重要的一點就是遵循PITA規(guī)則,即要在創(chuàng)建對象時初始化對象而不是先創(chuàng)建對象然后再賦值??梢栽谌魏螘r候初始化由空閑存儲區(qū)分配的單個對象。初始化方法:在特定的類型后面使用圓括號內的初始化值來完成。
new數據類型T(初始化列表);
動態(tài)內存分配示例:
int*ptrInt=newint(100);double*ptrDouble=newdouble(1.414);float*ptrFloat=newfloat(3.1415926F);float**ptrPtrFloat=newfloat*(ptrFloat);
動態(tài)內存分配如何初始化基本類型空圓括號的含義在new表達式中,可以在類型名后使用空圓括號:new數據類型T();功能:將初始化為數據類型T的默認值。
動態(tài)內存分配new數據類型T;與new數據類型T();的區(qū)別示例:
int*ptrInt1=newint;//Valueisunknown
int*ptrInt1=newint();//Valueiszero說明:第一種情況下,在空閑存儲區(qū)中創(chuàng)建了一個int類型對象,但其值未知。在第二種情況下,在空閑存儲區(qū)中創(chuàng)建了一個int類型對象并初始化為int在全局作用域中的值(默認值)。而所有的全局基本類型在默認情況下的初始值為0,故第二種情況在創(chuàng)建了對象后將其值初始化為0。
動態(tài)內存分配如何釋放單個對象的空閑空間語法格式:delete指針變量名P;指針變量名P=NULL;功能:釋放指針P所指向的內存。P必須是new操作的返回值。刪除基于0的指針(空指針)總是一種安全的操作。
動態(tài)內存分配如何為對象數組分配空閑空間語法格式:數據類型T*指針變量名P=new數據類型T[元素個數];功能:在空閑空間分配對象數組,指針P指向數組的第一個元素。如果在方括號中的表達式的值為0,則就會分配沒有元素的數組,new表達式返回的指針是非0值,并且與其他指向任何對象的指針都不同。如果這個值在運行期間被確定是無效的,則結果不可預知。
動態(tài)內存分配如何為對象數組分配空閑空間示例:
//Arrayof5intsint*ptrInt=newint[5];
//Arrayof6doubles
intdimension=6;double*ptrDouble=newdouble[dimension];
動態(tài)內存分配如何為對象數組分配空閑空間不可能初始化數組:在C++中并沒有語法來真正的初始化空閑存儲區(qū)中的各個元素(不遵循PITA規(guī)則)。對于所有的基本數據類型而言,每個元素的值都是未知的,所能做的就是在創(chuàng)建數組之后,再給每個元素賦值,如下所示:
intconstdimension=5;
//Allocatespacefor5ints,alluninitializedint*ptrInt=newint[dimension];
//Providesomemeaningfulvaluesfor(inti=0;i<dimension;++i)
ptrInt[i]=i;說明:空閑存儲區(qū)中用戶自定義數據類型的數組可以被初始化。
動態(tài)內存分配如何釋放對象數組的空閑空間語法格式:delete[]指針變量名P;功能:釋放空閑存儲區(qū)中的對象數組內存空間。說明:必須用方括號“[]”來通知編譯器這是一個對象數組,該代碼的任務是將從數組創(chuàng)建時存放在某處的對象數量取回并為數組的所有對象調用析構函數。當刪除用戶自定義數據類型的數組時非常重要。同釋放單個對象一樣,針對包含0值的指針使用delete被認為是安全的。
動態(tài)內存分配保持平衡涉及到new以及delete的主要規(guī)則相當簡單:使用delete來平衡每一個new。如果在new語句中使用了方括號(即分配了對象數組),必須在delete后使用方括號。無論何時使用new,一定要確保使用正確的delete格式。
動態(tài)內存分配如何分配和刪除多維數組可以為任意維數的數組分配空間,并非僅能為一維數組分配空間。示例:
introws=3;
intconstcols=5;
double(*ptr)[cols]=newdouble[rows][cols];
//……delete[]ptr;
動態(tài)內存分配如何分配和刪除多維數組示例說明:二維數組的元素是一維數組的集合(行)。故為了創(chuàng)建一個指向一維數組的指針,包含*ptr的圓括號是必須的。ptr+1代表了第二個一維數組的開始(第一行,第0列),而不是第二個double元素(第0行,第一列)。當使用new從空閑存儲區(qū)中給數組分配空間時,所有的維數(除了第一維)都必須讓編譯器知道并且必須是正數。這就是rows可以在運行期間確定,而cols必須是常量從而讓編譯器知道的原因。如何分配和刪除多維數組當刪除數組時,注意delete語句的格式與一維數組的格式相同。即列的數目不需要指定。使用typedef可以簡化語法。如:
introws=3;
intconstcols=5;
typedefdoubleONE_DIM[cols];
ONE_DIM*ptr=newONE_DIM[rows];
//……delete[]ptr;命名該空間當使用new在空閑存儲區(qū)中為一個對象分配空間時,會得到一個指向對象的指針,然后解引用這個指針來訪問該對象。但是也可以不使用解引用的指針來訪問空閑存儲區(qū)中的對象,為此,只需要解引用有new返回的地址并創(chuàng)建別名,然后就可以簡單地使用這個別名來引用這個對象。不過因為delete需要所分配的空閑存儲區(qū)的地址,故注意要小心使用取地址運算符&。
double&refFreeStore=*newdouble(3.1416);
refFreeStore=3.1415926;//changethecontent
//……
delete&refFreeStore;
//releasethespace兩個程序輸出示例intmain(){ int*ptrFreeStore=newint(1);
int&refFreeStore=*ptrFreeStore; cout<<refFreeStore<<endl; ptrFreeStore=newint(2); cout<<refFreeStore<<endl; delete&refFreeStore; deleteptrFreeStore;}intmain(){ int*ptrFreeStore=newint(1);
int*&refPtrFreeStore=ptrFreeStore; cout<<*refPtrFreeStore<<endl; deleterefPtrFreeStore; ptrFreeStore=newint(2); cout<<*refPtrFreeStore<<endl; deleterefPtrFreeStore;}運行結果:11運行結果:12例1動態(tài)創(chuàng)建對象舉例usingnamespacestd;classPoint{public:Point(){X=Y=0;cout<<"DefaultConstructorcalled.\n";}Point(intxx,intyy){X=xx;Y=yy;cout<<"Constructorcalled.\n";}~Point(){cout<<"Destructorcalled.\n";}intGetX(){returnX;}intGetY(){returnY;} voidMove(intx,inty) {X=x;Y=y;}private:intX,Y;};intmain(){cout<<"StepOne:“<<endl;Point*Ptr1=newPoint;deletePtr1;cout<<"StepTwo:“<<endl;Ptr1=newPoint(1,2);deletePtr1;}運行結果:StepOne:DefaultConstructorcalled.Destructorcalled.StepTwo:Constructorcalled.Destructorcalled.26例2動態(tài)創(chuàng)建對象數組舉例usingnamespacestd;classPoint{
//類的聲明同例1,略};intmain(){Point*Ptr=newPoint[2];//創(chuàng)建對象數組
Ptr[0].Move(5,10);//通過指針訪問數組元素的成員
Ptr[1].Move(15,20);//通過指針訪問數組元素的成員
cout<<"Deleting...“<<endl;delete[]Ptr;//刪除整個對象數組}運行結果:DefaultConstructorcalled.DefaultConstructorcalled.Deleting...Destructorcalled.Destructorcalled.28例3動態(tài)數組類usingnamespacestd;classPoint{
//類的聲明同例1…
};classArrayOfPoints{public:ArrayOfPoints(intn){numberOfPoints=n;points=newPoint[n];}~ArrayOfPoints(){cout<<"Deleting...“<<endl;numberOfPoints=0;delete[]points;}Point&Element(intn){returnpoints[n];}private:Point*points;intnumberOfPoints;};29intmain(){ intnumber; cout<<"Pleaseenterthenumberofpoints:"; cin>>number;
//創(chuàng)建對象數組
ArrayOfPointspoints(number);
//通過指針訪問數組元素的成員
points.Element(0).Move(5,10);
//通過指針訪問數組元素的成員
points.Element(1).Move(15,20);}30運行結果如下:Pleaseenterthenumberofpoints:2DefaultConstructorcalled.DefaultConstructorcalled.Deleting...Destructorcalled.Destructorcalled.31動態(tài)創(chuàng)建多維數組new類型名T[下標表達式1][下標表達式2]…;如果內存申請成功,new運算返回一個指向新分配內存首地址的指針,是一個T類型的數組,數組元素的個數為除最左邊一維外各維下標表達式的乘積。例如:char(*fp)[3];fp=newchar[2][3];char(*fp)[3];fpfp+1fp[0][0]fp[0][1]fp[0][2]fp[1][0]fp[1][1]fp[1][2]33淺拷貝與深拷貝淺拷貝實現對象間數據元素的一一對應復制。深拷貝當被復制的對象數據成員是指針類型時,不是復制該指針成員本身,而是將指針所指的對象進行復制。淺拷貝與深拷貝例5對象的淺拷貝usingnamespacestd;classPoint{
//類的聲明同例1//……};classArrayOfPoints{
//類的聲明同例3//……};淺拷貝與深拷貝intmain(){ intnumber; cin>>number;ArrayOfPointspointsArray1(number);pointsArray1.Element(0).Move(5,10);pointsArray1.Element(1).Move(15,20);
ArrayOfPointspointsArray2(pointsArray1);
cout<<"CopyofpointsArray1:“<<endl;cout<<"Point_0ofarray2:"<<pointsArray2.Element(0).GetX()<<",“<<pointsArray2.Element(0).GetY()<<endl;cout<<"Point_1ofarray2:"<<pointsArray2.Element(1).GetX()<<",“<<pointsArray2.Element(1).GetY()<<endl;36pointsArray1.Element(0).Move(25,30);pointsArray1.Element(1).Move(35,40);cout<<"AfterthemovingofpointsArray1:“<<endl;cout<<"Point_0ofarray2:"<<pointsArray2.Element(0).GetX()<<","<<pointsArray2.Element(0).GetY()<<endl;cout<<"Point_1ofarray2:"<<pointsArray2.Element(1).GetX()<<",“<<pointsArray2.Element(1).GetY()<<endl;}37運行結果如下:Pleaseenterthenumberofpoints:2DefaultConstructorcalled.DefaultConstructorcalled.CopyofpointsArray1:Point_0ofarray2:5,10Point_1ofarray2:15,20AfterthemovingofpointsArray1:Point_0ofarray2:25,30Point_1ofarray2:35,40Deleting...Destructorcalled.Destructorcalled.Deleting...接下來程序出現異常,也就是運行錯誤。38拷貝前拷貝后pointsArray1的數組元素占用的內存pointsnumberOfPointspointsArray1pointsnumberOfPointspointsArray1pointsArray1的數組元素占用的內存pointsnumberOfPointspointsArray239淺拷貝例6對象的深拷貝usingnamespacestd;classPoint{
//類的聲明同例1};classArrayOfPoints{public:ArrayOfPoints(ArrayOfPoints&pointsArray);
//其它成員同例3};淺拷貝與深拷貝ArrayOfPoints::ArrayOfPoints(ArrayOfPoints&pointsArray){numberOfPoints=pointsArray.numberOfPoints;points=newPoint[numberOfPoints];for(inti=0;i<numberOfPoints;i++)
points[i].Move(
pointsArray.Element(i).GetX(),
pointsArray.Element(i).GetY());}intmain(){
//同例5}41程序的運行結果如下:Pleaseenterthenumberofpoints:2DefaultConstructorcalled.DefaultConstructorcalled.DefaultConstructorcalled.DefaultConstructorcalled.CopyofpointsArray1:Point_0ofarray2:5,10Point_1ofarray2:15,20AfterthemovingofpointsArray1:Point_0ofarray2:5,10Point_1ofarray2:15,20Deleting...Destructorcalled.Destructorcalled.Deleting...Destructorcalled.Destructorcalled.42拷貝前pointsArray1的數組元素占用的內存pointsnumberOfPointspointsArray1拷貝后pointsnumberOfPointspointsArray1pointsArray1的數組元素占用的內存pointsnumberOfPointspointsArray243深拷貝*44/106對象成員的另一種訪問方式聲明形式類名*對象指針名;例:PointA(5,10);Piont*ptr=NULL;ptr=&A;通過指針訪問對象成員對象指針名->成員名ptr->getx()相當于(*ptr).getx();
指針44*45/106曾經出現過的錯誤例子classFred;//前向引用聲明classBarney{Fredx;//錯誤:類Fred的聲明尚不完善
};classFred{Barneyy;};classFred; //前向引用聲明classBarney{Fred*x; };classFred{Barneyy;};45指向類的非靜態(tài)成員的指針申明通過指向成員的指針只能訪問公有成員聲明指向成員的指針聲明指向公有數據成員的指針類型說明符類名::*指針名;
聲明指向公有函數成員的指針類型說明符(類名::*指針名)(參數表);46類的非靜態(tài)成員的指針使用指向數據成員的指針說明指針應該指向哪個成員指針名=&類名::數據成員名;通過對象名(或對象指針)與成員指針結合來訪問數據成員對象名.*類成員指針名或:對象指針名—>*類成員指針名47類的非靜態(tài)成員的函數指針使用指向函數成員的指針初始化指針名=類名::函數成員名;通過對象名(或對象指針)與成員指針結合來訪問函數成員(對象名.*類成員指針名)(參數表);或:(對象指針名—>*類成員指針名)(參數表);48指向類的非靜態(tài)成員的指針例13訪問對象的公有成員函數的不同方式intmain(){PointA(4,5);//聲明對象A Point*p1=&A;//聲明對象指針并初始化
//聲明成員函數指針并初始化
int(Point::*p_GetX)()=Point::GetX;
//(1)使用成員函數指針訪問成員函數
cout<<(A.*p_GetX)()<<endl;
//(2)使用對象指針訪問成員函數
cout<<(p1->GetX)()<<endl;
//(3)使用對象名訪問成員函數
cout<<A.GetX()<<endl; }49例15通過指針訪問類的靜態(tài)函數成員#include<iostream>usingnamespacestd;classPoint//Point類聲明{public://外部接口(公有數據成員)
//其它函數略
staticvoidGetC()//靜態(tài)函數成員
{cout<<"Objectid="<<countP<<endl;}private://私有數據成員
intX,Y; staticintcountP; //靜態(tài)數據成員引用性說明};//函數實現略intPoint::countP=0; //靜態(tài)數據成員定義性說明50intmain(){
//指向函數的指針,指向類的靜態(tài)成員函數
void(*gc)()=Point::GetC; PointA(4,5); //聲明對象A cout<<"PointA,"<<A.GetX()<<","<<A.GetY(); gc();//輸出對象序號,通過指針訪問靜態(tài)函數成員
PointB(A); //聲明對象B cout<<"PointB,"<<B.GetX()<<","<<B.GetY(); gc();//輸出對象序號,通過指針訪問靜態(tài)函數成員}51引用的概念引用:
為一個變量、函數等對象規(guī)定一個別名,該別名稱為引用。此后,對別名的操作即是對別名所代表的對象的操作。即引用變量創(chuàng)建了變量和對象的別名。引用雖是一種類型,但不是值,只能用它標識另一個對象。從理論意義上說,引用是一種映射,把一個標識符映射到一個對象。從直觀意義上說,引用是用一個標識符給一個對象起了一個別名,引用標識對象,就是用一個別名標識對象。52引用的創(chuàng)建(聲明)創(chuàng)建(聲明)引用:創(chuàng)建引用與定義指針類似,只不過將*換成&。引用只有聲明,沒有定義。因為引用不占存儲空間,而定義要分配存儲空間。創(chuàng)建(聲明)引用格式如下:
類型&別名[=別名所代表的對象];例:
inti=0;
int
&ir=i;//定義引用ir作為對象i的別名
ir=2;//形式上向ir賦值,實際上是向i賦值,等同于i=2;
int*p=&ir;//形式上取ir的地址,實際上是取i的地
//址,等同于int*p=&i;
53引用的初始化引用若不是作為函數參數的,則必須初始化(PITA),并且必須引用某個“真實”的變量或對象。否則發(fā)生編譯錯誤。方法:一般使用相同類型的變量來初始化。例:intsomeVar=1;
int&ref=someVar;引用總是作為目標的別名使用。也就是說:引用一旦初始化,它就維系在所代表的對象上,再也分不開。任何對該引用的賦值,都是對引用所維系目標賦值,而不是將引用維系到另一目標上。即一旦引用變量被聲明并初始化,在引用的作用域內,不能再作為其他對象的引用(別名)。54創(chuàng)建對數組的引用可以創(chuàng)建對數組的引用。例:intconstdimension=5;doublearray1[dimension]={0.0};double(&refArray1)[dimension]=array1;//……doubleconstarray2[dimension]={0.0
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 新版華東師大版八年級數學下冊《16.1.2分式的基本性質通分》聽評課記錄3
- 五年級數學下冊聽評課記錄《3.1 分數乘法(一)》(3)-北師大版
- 2025年自返式取樣器合作協(xié)議書
- 蘇科版七年級數學上冊《2.6.2有理數的乘法與除法》聽評課記錄
- 小學二年級數學口算題大全
- 七年級上冊歷史第10課《秦末農民大起義》聽課評課記錄
- 五年級下冊口算練習
- 人教版數學八年級下冊《一次函數的概念》聽評課記錄1
- 白酒銷售工作計劃書范本
- 聚合支付渠道服務協(xié)議書范本
- 2025年汽車加氣站作業(yè)人員安全全國考試題庫(含答案)
- 化工過程安全管理導則安全儀表管理課件
- 高三日語一輪復習日語助詞「に」和「を」的全部用法課件
- 【化學】高中化學手寫筆記
- 中國高血壓防治指南-解讀全篇
- 2024年監(jiān)控安裝合同范文6篇
- 2024年山東省高考政治試卷真題(含答案逐題解析)
- 煙葉復烤能源管理
- 食品安全管理員考試題庫298題(含標準答案)
- 執(zhí)業(yè)醫(yī)師資格考試《臨床執(zhí)業(yè)醫(yī)師》 考前 押題試卷絕密1 答案
- 非ST段抬高型急性冠脈綜合征診斷和治療指南(2024)解讀
評論
0/150
提交評論