二維動態數組的申請與釋放_第1頁
二維動態數組的申請與釋放_第2頁
二維動態數組的申請與釋放_第3頁
二維動態數組的申請與釋放_第4頁
二維動態數組的申請與釋放_第5頁
已閱讀5頁,還剩5頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、一維數組是指針,可將二維數組看作是指針的指針:每一行是一個一維數組,而列是指向行的指針。在動態創建時,先分配指向行的指針空間,再循環維每一行申請空間。#include <iostream>using namespace std;int main()/34 /三行四列的二維數組int x,y;int i,n,k;x=3;y=4;int *p;p = new int*x;   /行 /申請行的空間/每行的列申請空間for(i=0; i<x;i+)pi = new int y;/賦值,k=0;for(i=0;i<x;i+)for(n=0;n<y;n+

2、)pin = k;k+;/顯示剛才的賦值for(i=0;i<x;i+)for(n=0;n<y;n+)cout << pin << "t"cout << endl;/刪除剛才申請的內存for(i=0;i<x;i+)delete pi;delete p;return 0;今天歸納總結了一下,希望以后的朋友可以少走些彎路:) 一 :關于指針和堆的內存分配 先來介紹一下指針 :指針一種類型,理論上來說它包含其他變量的地址,因此有的書上也叫它:地址變量。既然指針是一個類型,是類型就有大小,在達內的服務器上或者普通的 機上,都是個字

3、節大小,里邊只是存儲了一個變量的地址而已。不管什么類型的指針,char * ,int * ,int (*) ,string * ,float * ,都是說明了本指針所指向的地址空間是什么類型而已,了解了這個基本上所有的問題都好象都變的合理了。 在C+中,申請和釋放堆中分配的存貯空間,分別使用new和delete的兩個運算符來完成: 指針類型指針變量名=new 指針類型 (初始化); delete 指針名; 例如:1、 int *p=new int(0); 它與下列代碼序列大體等價: 2、int tmp=0, *p=&tmp; 區別:p所指向的變量是由庫操作符new()分配的,位于內存的

4、堆區中,并且該對象未命名。 下面是關于new 操作的說明:部分引自<<C+面向對象開發>> 1、new運算符返回的是一個指向所分配類型變量(對象)的指針。對所創建的變量或對象,都是通過該指針來間接操作的,而動態創建的對象本身沒有名字。 2、一般定義變量和對象時要用標識符命名,稱命名對象,而動態的稱無名對象(請注意與棧區中的臨時對象的區別,兩者完全不同:生命期不同,操作方法不同,臨時變量對程序員是透明的)。 3、堆區是不會在分配時做自動初始化的(包括清零),所以必須用初始化式(initializer)來顯式初始化。new表達式的操作序列如下:從堆區分配對象,然后用括號中的

5、值初始化該對象。 下面是從堆中申請數組 1、申請數組空間: 指針變量名=new 類型名下標表達式; 注意:“下標表達式”不是常量表達式,即它的值不必在編譯時確定,可以在運行時確定。這就是堆的一個非常顯著的特點,有的時候程序員本身都不知道要申請能夠多少內存的時候,堆就變的格外有用。 2、釋放數組空間: delete 指向該數組的指針變量名; 注意:方括號非常重要的,如果delete語句中少了方括號,因編譯器認為該指針是指向數組第一個元素的,會產生回收不徹底的問題(只回收了第一個元素所 占空間),我們通常叫它“內存泄露”,加了方括號后就轉化為指向數組的指針,回收整個數組。delete 的方括號中不

6、需要填數組元素數,系統自知。即使寫了,編譯器也忽略。<<Think in c+>>上說過以前的delete 方括號中是必須添加個數的,后來由于很容易出錯,所以后來的版本就改進了這個缺陷。 下面是個例子,VC上編譯通過 #include<iostream> using namespace std; /#include <iostream.h> /for VC #include <string.h> void main() int n; char *p; cout<<"請輸入動態數組的元素個數"<&l

7、t;endl; cin>>n; /n在運行時確定,可輸入17 p=new charn; /申請17個字符(可裝8個漢字和一個結束符)的內存空間strcpy(pc,“堆內存的動態分配”);/ cout<<p<<endl; delete p;/釋放pc所指向的n個字符的內存空間return ; 通過指針使堆空間,編程中的幾個可能問題 動態分配失敗。返回一個空指針(NULL),表示發生了異常,堆資源不足,分配失敗。 data = new double m; /申請空間 if (data ) = 0) /或者=NULL 指針刪除與堆空間釋放。刪除一個指針p(dele

8、te p;)實際意思是刪除了p所指的目標(變量或對象等),釋放了它所占的堆空間,而不是刪除本身,釋放堆空間后,成了空懸指針,不能再通過p使用該空間,在重新給p賦值前,也不能再直接使用p。 內存泄漏(memory leak)和重復釋放。new與delete 是配對使用的, delete只能釋放堆空間。如果new返回的指針值丟失,則所分配的堆空間無法回收,稱內存泄漏,同一空間重復釋放也是危險的,因為該空間可能已另分 配,而這個時候又去釋放的話,會導致一個很難查出來的運行時錯誤。所以必須妥善保存new返回的指針,以保證不發生內存泄漏,也必須保證不會重復釋放堆內 存空間。 動態分配的變量或對象的生命期

9、。無名變量的生命期并不依賴于建立它的作用域,比如在函數中建立的動態對象在函數返回后仍可使用。我們也稱堆空間為自由 空間(free store)就是這個原因。但必須記住釋放該對象所占堆空間,并只能釋放一次,在函數內建立,而在函數外釋放是一件很容易失控的事,往往會出錯,所以永遠 不要在函數體內申請空間,讓調用者釋放,這是一個很差的做法。你再怎么小心翼翼也可能會帶來錯誤。 類在堆中申請內存 : 通過new建立的對象要調用構造函數,通過deletee刪除對象要調用析構函數。 CGoods *pc; pc=new CGoods; /分配堆空間,并構造一個無名對象 /的CGoods對象; . delete

10、 pc; /先析構,然后將內存空間返回給堆; 堆對象的生命期并不依賴于建立它的作用域,所以除非程序結束,堆對象(無名對象)的生命期不會到期,并且需要顯式地用delete語句析構堆對象,上面的 堆對象在執行delete語句時,C+自動調用其析構函數。 正因為構造函數可以有參數,所以new后面類(class)類型也可以有參數。這些參數即構造函數的參數。 但對創建數組,則無參數,并只調用缺省的構造函數。見下例類說明: class CGoods char Name21; int Amount; float Price; float Total_value; public: CGoods(); /缺省構

11、造函數。因已有其他構造函數,系統不會再自動生成缺省構造,必須顯式聲明。 CGoods(char* name,int amount ,float price) strcpy(Name,name); Amount=amount; Price=price; Total_value=price*amount; ;/類聲明結束 下面是調用機制: void main() int n; CGoods *pc,*pc1,*pc2; pc=new CGoods(“hello”,10,118000); /調用三參數構造函數 pc1=new CGoods(); /調用缺省構造函數 cout<<”輸入商品

12、類數組元素數”<<endl; cin>>n; pc2=new CGoodsn; /動態建立數組,不能初始化,調用n次缺省構造函數 delete pc; delete pc1; delete pc2; 申請堆空間之后構造函數運行; 釋放堆空間之前析構函數運行; 再次強調:由堆區創建對象數組,只能調用缺省的構造函數,不能調用其他任何構造函數。如果沒有缺省的構造函數,則不能創建對象數組。 -下面我們再來看一下指針數組和數組指針 如果你想了解指針最好理解以下的公式 : (1)int*ptr;/指針所指向的類型是int (2)char*ptr;/指針所指向的的類型是char (3

13、)int*ptr;/指針所指向的的類型是int* (也就是一個int * 型指針) (4)int(*ptr)3;/指針所指向的的類型是int()3 /二維指針的聲明 ()指針數組:一個數組里存放的都是同一個類型的指針,通常我們把他叫做指針數組。 比如 int * a10;它里邊放了個int * 型變量,由于它是一個數組,已經在棧區分配了個(int * )的空間,也就是位機上是個byte,每個空間都可以存放一個int型變量的地址,這個時候你可以為這個數組的每一個元素初始化,在,或者單獨做 個循環去初始化它。 例子: int * a2= new int(3),new int(4) ; /在棧區里聲

14、明一個int * 數組,它的每一個元素都在堆區里申請了一個無名變量,并初始化他們為和,注意此種聲明方式具有缺陷,VC下會報錯 例如: int * a2=new int3,new int3; delete a0; delet a10; 但是我不建議達內的學生這么寫,可能會造成歧義,不是好的風格,并且在VC中會報錯,應該寫成如下: int * a2; a0= new int3; a1=new int3; delete a0; delet a10; 這樣申請內存的風格感覺比較符合大家的習慣;由于是數組,所以就不可以delete a;編譯會出警告.delete a1; 注意這里 是一個數組,不能del

15、ete ; ( ) 數組指針: 一個指向一維或者多維數組的指針; int * b=new int10;指向一維數組的指針b ; 注意,這個時候釋放空間一定要delete ,否則會造成內存泄露, b 就成為了空懸指針. int (*b2)10=new int1010; 注意,這里的b2指向了一個二維int型數組的首地址. 注意:在這里,b2等效于二維數組名,但沒有指出其邊界,即最高維的元素數量,但是它的最低維數的元素數量必須要指定!就像指向字符的指針,即等效一個字符串,不要把指向字符的指針說成指向字符串的指針。這與數組的嵌套定義相一致。 int(*b3) 30 20; /三級指針>指向三維

16、數組的指針; int (*b2) 20; /二級指針; b3=new int 1 20 30; b2=new int 30 20; 兩個數組都是由600個整數組成,前者是只有一個元素的三維數組,每個元素為30行20列的二維數組,而另一個是有30個元素的二維數組,每個元素為20個元素的一維數組。 刪除這兩個動態數組可用下式: delete b3; /刪除(釋放)三維數組; delete b2; /刪除(釋放)二維數組; 再次重申:這里的b2的類型是int (*) ,這樣表示一個指向二維數組的指針。 b3表示一個指向(指向二維數組的指針)的指針,也就是三級指針. ( 3 ) 二級指針的指針 看下例

17、 : int (*p)2=new (int(*)3)2; p0=new int22; p1=new int22; p2=new int22; delete p0; delete p1; delete p2; delete p; 注意此地方的指針類型為int (*),碰到這種問題就把外邊的2先去掉,然后回頭先把int * pnew int(*)n申請出來,然后再把外邊的附加上去; p代表了一個指向二級指針的指針,在它申請空間的時候要注意指針的類型,那就是int (*)代表二級指針,而int (*)顧名思義就是代表指向二級指針的指針了。既然是指針要在堆里申請空間,那首先要定義它的范圍:(int(*

18、)n)2,n 個這樣的二級指針,其中的每一個二級指針的最低維是個元素.(因為要確定一個二級指針的話,它的最低維數是必須指定的,上邊已經提到)。然后我們又分別 為p0,p1,p2在堆里分配了空間,尤其要注意的是:在釋放內存的時候一定要為p0,p1,p2,單獨delete ,否則又會造成內存泄露,在deletep 的時候一定先delete p0; delete p1,然后再把給p申請的空間釋放掉 delete p 這樣會防止內存泄露。 ()指針的指針; int * cc=new (int*)10; 聲明一個個元素的數組,數組每個元素都是一個int *指針,每個元素還可以單獨申請空間,因為cc的類型

19、是int*型的指針,所以你要在堆里申請的話就要用int *來申請; 看下邊的例子 ( & GNU編譯器都已經通過); int * a= new int * 2;/申請兩個int * 型的空間 a1=new int3;/為a的第二個元素又申請了個int 型空間,a1指向了此空間首地址處 a0=new int4;/為a的第一個元素又申請了個int 型空間,a0 指向了此空間的首地址處 int * b; a00=0; a01=1; b=a0; delete a0/一定要先釋放a0,a1的空間,否則會造成內存泄露.; delete a1; delete a; b+; cout<<*

20、b<<endl; /隨機數 注意:因為a 是在堆里申請的無名變量數組,所以在delete 的時候要用delete 來釋放內存,但是a的每一個元素又單獨申請了空間,所以在delete a之前要先delete 掉 a0,a1,否則又會造成內存泄露. () 指針數組: 我們再來看看第二種:二維指針數組 int *(*c)3=new int *32; 如果你對上邊的介紹的個種指針類型很熟悉的話,你一眼就能看出來c是個二級指針,只不過指向了一個二維int * 型的數組而已,也就是二維指針數組。 例子: int *(*b)10=new int*210;/ b00=new int100; b01

21、=new int100; *b00=1; cout <<*b00<<endl; /打印結果為 delete b00; delete b01; delete b; cout<<*b00<<endl; /打印隨機數 這里只為大家還是要注意內存泄露的問題,在這里就不再多說了。 如果看了上邊的文章,大家估計就會很熟悉,這個b是一個二維指針,它指向了一個指針數組 第二種: int *d2;表示一個擁有兩個元素數組,每一個元素都是int * 型,這個指向指針的指針:) d不管怎樣變終究也是個數組,呵呵, 如果你讀懂了上邊的,那下邊的聲明就很簡單了: d0=n

22、ew int *10; d1=new int * 10; delete d0; delete d1; 具體的就不再多說了 :) 二:函數指針 關于函數指針,我想在我們可能需要寫個函數,這個函數體內要調用另一個函數,可是由于項目的進度有限,我們不知道要調用什么樣的函數,這個時候可能就需要一個函數指針; int a();這個一個函數的聲明; ing (*b)();這是一個函數指針的聲明; 讓我們來分析一下,左邊圓括弧中的星號是函數指針聲明的關鍵。另外兩個元素是函數的返回類型(void)和由邊圓括弧中的入口參數(本例中參數是空)。注 意本例中還沒有創建指針變量-只是聲明了變量類型。目前可以用這個變量

23、類型來創建類型定義名及用sizeof表達式獲得函數指針的大小: unsigned psize = sizeof (int (*) (); 獲得函數指針的大小 / 為函數指針聲明類型定義 typedef int (*PFUNC) (); PFUNC是一個函數指針,它指向的函數沒有輸入參數,返回int。使用這個類型定義名可以隱藏復雜的函數指針語法,就我本人強烈建議我們大內弟子使用這種方式來定義; 下面是一個例子,一個簡單函數指針的回調(在GNU編譯器上通過,在VC上需要改變一個頭文件就OK了) #include<iostream> /GNU 編譯器 g+ 實現 using namesp

24、ace std; /* /vc 的實現 #include "stdafx.h" #include <iostream.h> */ #define DF(F) int F() cout<<"this is in function "<<#F<<endl; return 0; /聲明定義DF(F)替代 int F();函數; DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g); DF(h); DF(i); /聲明定義函數 a b c d e f g h i / int (*pfunc)(); /一個簡單函數指針的聲明 typedef int(*FUNC)(); /一個函數指針類型的聲明 FUNC ff = a,b,c,d,e,f,g,h,i; /聲明一個函數指針數組,并初始化為以上聲明的a,b,c,d,e,f,g,h,i函數 FUNC func3(FUNC vv) /定義函數func3,傳入一個函數指針,并且返回一個同樣類型的函數指針 vv(); return vv; /*FUNC func4(int (*vv)() /func3的另一種實現 vv(); return vv; */ int main() for(int i=0;i&

溫馨提示

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

評論

0/150

提交評論