欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
指針數組,數組指針,以及函數指針,以及堆中的分配規則
zhuzhu @ 2005-10-21 15:02

別人做的歸納,系統多了~~
一 :關(guān)于指針和堆的內存分配
先來(lái)介紹一下指針 : 指針一種類(lèi)型,理論上來(lái)說(shuō)它包含其他變量的地址,因此有的書(shū)上也叫它:地址變量。既然指針是一個(gè)類(lèi)型,是類(lèi)型就有大小,在達內的服務(wù)器上或者普通的PC機上,都是4個(gè)字節大小,里邊只是存儲了一個(gè)變量的地址而已。不管什么類(lèi)型的指針,char * ,int * ,int (*) ,string * ,float * ,都是說(shuō)明了本指針所指向的地址空間是什么類(lèi)型而已,了解了這個(gè)基本上所有的問(wèn)題都好象都變的合理了。

在C++中,申請和釋放堆中分配的存貯空間,分別使用new和delete的兩個(gè)運算符來(lái)完成:
指針類(lèi)型 指針變量名=new 指針類(lèi)型 (初始化);
       delete 指針名;
例如:1、 int *p=new int(0);
    它與下列代碼序列大體等價(jià):
2、int tmp=0, *p=&tmp;
區別:p所指向的變量是由庫操作符new()分配的,位于內存的堆區中,并且該對象未命名。
  
下面是關(guān)于new 操作的說(shuō)明?。骸〔糠忠?lt;<C++面向對象開(kāi)發(fā)>>
1、new運算符返回的是一個(gè)指向所分配類(lèi)型變量(對象)的指針。對所創(chuàng )建的變量或對象,都是通過(guò)該指針來(lái)間接操作的,而動(dòng)態(tài)創(chuàng )建的對象本身沒(méi)有名字。
2、一般定義變量和對象時(shí)要用標識符命名,稱(chēng)命名對象,而動(dòng)態(tài)的稱(chēng)無(wú)名對象(請注意與棧區中的臨時(shí)對象的區別,兩者完全不同:生命期不同,操作方法不同,臨時(shí)變量對程序員是透明的)。
3、堆區是不會(huì )在分配時(shí)做自動(dòng)初始化的(包括清零),所以必須用初始化式(initializer)來(lái)顯式初始化。new表達式的操作序列如下:從堆區分配對象,然后用括號中的值初始化該對象。

下面是從堆中申請數組
1、申請數組空間:
指針變量名=new 類(lèi)型名[下標表達式];
注意:“下標表達式”不是常量表達式,即它的值不必在編譯時(shí)確定,可以在運行時(shí)確定。這就是堆的一個(gè)非常顯著(zhù)的特點(diǎn),有的時(shí)候程序員本身都不知道要申請能夠多少內存的時(shí)候,堆就變的格外有用。
2、釋放數組空間:
delete [ ]指向該數組的指針變量名;
注意:方括號非常重要的,如果delete語(yǔ)句中少了方括號,因編譯器認為該指針是指向數組第一個(gè)元素的,會(huì )產(chǎn)生回收不徹底的問(wèn)題(只回收了第一個(gè)元素所占空間),我們通常叫它“內存泄露”,加了方括號后就轉化為指向數組的指針,回收整個(gè)數組。delete [ ]的方括號中不需要填數組元素數,系統自知。即使寫(xiě)了,編譯器也忽略。<<Think in c++>>上說(shuō)過(guò)以前的delete []方括號中是必須添加個(gè)數的,后來(lái)由于很容易出錯,所以后來(lái)的版本就改進(jìn)了這個(gè)缺陷。
下面是個(gè)例子,VC上編譯通過(guò)
#include<iostream>
using namespace std;
//#include <iostream.h>  //for VC
#include <string.h>
void main(){
int n;
char *p;
cout<<"請輸入動(dòng)態(tài)數組的元素個(gè)數"<<endl;
cin>>n; //n在運行時(shí)確定,可輸入17
p=new char[n]; //申請17個(gè)字符(可裝8個(gè)漢字和一個(gè)結束符)的內存空間strcpy(pc,“堆內存的動(dòng)態(tài)分配”);//
cout<<p<<endl;
delete []p;//釋放pc所指向的n個(gè)字符的內存空間return ; }

通過(guò)指針使堆空間,編程中的幾個(gè)可能問(wèn)題

1.動(dòng)態(tài)分配失敗。返回一個(gè)空指針(NULL),表示發(fā)生了異常,堆資源不足,分配失敗。
  data = new double [m]; //申請空間
if ((data ) == 0)…… //或者==NULL
2.指針刪除與堆空間釋放。刪除一個(gè)指針p(delete p;)實(shí)際意思是刪除了p所指的目標(變量或對象等),釋放了它所占的堆空間,而不是刪除p本身,釋放堆空間后,p成了空懸指針,不能再通過(guò)p使用該空間,在重新給p賦值前,也不能再直接使用p。
3.內存泄漏(memory leak)和重復釋放。new與delete 是配對使用的, delete只能釋放堆空間。如果new返回的指針值丟失,則所分配的堆空間無(wú)法回收,稱(chēng)內存泄漏,同一空間重復釋放也是危險的,因為該空間可能已另分配,而這個(gè)時(shí)候又去釋放的話(huà),會(huì )導致一個(gè)很難查出來(lái)的運行時(shí)錯誤。所以必須妥善保存new返回的指針,以保證不發(fā)生內存泄漏,也必須保證不會(huì )重復釋放堆內存空間。
4.動(dòng)態(tài)分配的變量或對象的生命期。無(wú)名變量的生命期并不依賴(lài)于建立它的作用域,比如在函數中建立的動(dòng)態(tài)對象在函數返回后仍可使用。我們也稱(chēng)堆空間為自由空間(free store)就是這個(gè)原因。但必須記住釋放該對象所占堆空間,并只能釋放一次,在函數內建立,而在函數外釋放是一件很容易失控的事,往往會(huì )出錯,所以永遠不要在函數體內申請空間,讓調用者釋放,這是一個(gè)很差的做法。你再怎么小心翼翼也可能會(huì )帶來(lái)錯誤。
類(lèi)在堆中申請內存 :
通過(guò)new建立的對象要調用構造函數,通過(guò)deletee刪除對象要調用析構函數。
CGoods *pc;
pc=new CGoods;  //分配堆空間,并構造一個(gè)無(wú)名對象
                             //的CGoods對象;
…….
delete pc;  //先析構,然后將內存空間返回給堆;        堆對象的生命期并不依賴(lài)于建立它的作用域,所以除非程序結束,堆對象(無(wú)名對象)的生命期不會(huì )到期,并且需要顯式地用delete語(yǔ)句析構堆對象,上面的堆對象在執行delete語(yǔ)句時(shí),C++自動(dòng)調用其析構函數。
正因為構造函數可以有參數,所以new后面類(lèi)(class)類(lèi)型也可以有參數。這些參數即構造函數的參數。
但對創(chuàng )建數組,則無(wú)參數,并只調用缺省的構造函數。見(jiàn)下例類(lèi)說(shuō)明:

class CGoods{
         char Name[21];
         int  Amount;
         float Price;
         float Total_value;
public:
CGoods(){}; //缺省構造函數。因已有其他構造函數,系統不會(huì )再自動(dòng)生成缺省構造,必須顯式聲明。   CGoods(char* name,int amount ,float price){
          strcpy(Name,name);
          Amount=amount;
          Price=price;
          Total_value=price*amount;  }
          ……};//類(lèi)聲明結束
下面是調用機制?。?

void main(){
int n;
CGoods *pc,*pc1,*pc2;
pc=new CGoods(“hello”,10,118000);
//調用三參數構造函數   pc1=new CGoods();  //調用缺省構造函數  cout<<”輸入商品類(lèi)數組元素數”<<endl;
cin>>n;
pc2=new CGoods[n];
//動(dòng)態(tài)建立數組,不能初始化,調用n次缺省構造函數   
……
delete pc;
delete pc1;
delete []pc2;  }

申請堆空間之后構造函數運行;
釋放堆空間之前析構函數運行;
再次強調:由堆區創(chuàng )建對象數組,只能調用缺省的構造函數,不能調用其他任何構造函數。如果沒(méi)有缺省的構造函數,則不能創(chuàng )建對象數組。

---------------------下面我們再來(lái)看一下指針數組和數組指針―――――――――――――
如果你想了解指針最好理解以下的公式 :
(1)int*ptr;//指針所指向的類(lèi)型是int

  (2)char*ptr;//指針所指向的的類(lèi)型是char

  (3)int**ptr;//指針所指向的的類(lèi)型是int* (也就是一個(gè)int * 型指針)

  (4)int(*ptr)[3];//指針所指向的的類(lèi)型是int()[3] //二維指針的聲明

(1)指針數組:一個(gè)數組里存放的都是同一個(gè)類(lèi)型的指針,通常我們把他叫做指針數組。
比如 int * a[10];它里邊放了10個(gè)int * 型變量,由于它是一個(gè)數組,已經(jīng)在棧區分配了10個(gè)(int * )的空間,也就是32位機上是40個(gè)byte,每個(gè)空間都可以存放一個(gè)int型變量的地址,這個(gè)時(shí)候你可以為這個(gè)數組的每一個(gè)元素初始化,在,或者單獨做個(gè)循環(huán)去初始化它。
例子:
int * a[2]={ new int(3),new int(4) };     //在棧區里聲明一個(gè)int * 數組,它的每一個(gè)元素都在堆區里申請了一個(gè)無(wú)名變量,并初始化他們?yōu)椋澈停?,注意此種聲明方式具有缺陷,VC下會(huì )報錯
例如?。?
int * a[2]={new int[3],new int[3]};
delete a[0];
delet a[10];
但是我不建議達內的學(xué)生這么寫(xiě),可能會(huì )造成歧義,不是好的風(fēng)格,并且在VC中會(huì )報錯,應該寫(xiě)成如下?。?
int * a[2];
a[0]= new int[3];
a[1]=new int[3];
delete a[0];
delet a[10];
這樣申請內存的風(fēng)格感覺(jué)比較符合大家的習慣;由于是數組,所以就不可以delete a;編譯會(huì )出警告.delete  a[1];
注意這里 是一個(gè)數組,不能delete [] ;
( 2 ) 數組指針?。?一個(gè)指向一維或者多維數組的指針;
int * b=new int[10]; 指向一維數組的指針b ;
注意,這個(gè)時(shí)候釋放空間一定要delete [] ,否則會(huì )造成內存泄露, b 就成為了空懸指針.

int (*b2)[10]=new int[10][10]; 注意,這里的b2指向了一個(gè)二維int型數組的首地址.
注意:在這里,b2等效于二維數組名,但沒(méi)有指出其邊界,即最高維的元素數量,但是它的最低維數的元素數量必須要指定!就像指向字符的指針,即等效一個(gè)字符串,不要把指向字符的指針說(shuō)成指向字符串的指針。這與數組的嵌套定義相一致。
int(*b3) [30] [20];  //三級指針――>指向三維數組的指針;
int (*b2) [20];     //二級指針;
b3=new int [1] [20] [30];
b2=new int [30] [20];
     兩個(gè)數組都是由600個(gè)整數組成,前者是只有一個(gè)元素的三維數組,每個(gè)元素為30行20列的二維數組,而另一個(gè)是有30個(gè)元素的二維數組,每個(gè)元素為20個(gè)元素的一維數組。
     刪除這兩個(gè)動(dòng)態(tài)數組可用下式:
delete [] b3;  //刪除(釋放)三維數組;
delete [] b2;  //刪除(釋放)二維數組;
再次重申:這里的b2的類(lèi)型是int (*) ,這樣表示一個(gè)指向二維數組的指針。
b3表示一個(gè)指向(指向二維數組的指針)的指針,也就是三級指針.

( 3 ) 二級指針的指針
看下例 :
int (**p)[2]=new (int(*)[3])[2];
      p[0]=new int[2][2];
      p[1]=new int[2][2];
      p[2]=new int[2][2];
      delete [] p[0];
      delete [] p[1];
      delete [] p[2];
      delete [] p;
注意此地方的指針類(lèi)型為int (*),碰到這種問(wèn)題就把外邊的[2]先去掉,然后回頭先把int ** p=new int(*)[n]申請出來(lái),然后再把外邊的[2]附加上去;
p代表了一個(gè)指向二級指針的指針,在它申請空間的時(shí)候要注意指針的類(lèi)型,那就是int (*)代表二級指針,而int (**)顧名思義就是代表指向二級指針的指針了。既然是指針要在堆里申請空間,那首先要定義它的范圍:(int(*)[n])[2],n 個(gè)這樣的二級指針,其中的每一個(gè)二級指針的最低維是2個(gè)元素.(因為要確定一個(gè)二級指針的話(huà),它的最低維數是必須指定的,上邊已經(jīng)提到)。然后我們又分別為p[0],p[1],p[2]…在堆里分配了空間,尤其要注意的是:在釋放內存的時(shí)候一定要為p[0],p[1],p[2],單獨delete[] ,否則又會(huì )造成內存泄露,在delete[]p 的時(shí)候一定先delete p[0]; delete p[1],然后再把給p申請的空間釋放掉 delete [] p ……這樣會(huì )防止內存泄露。

(3)指針的指針;
int ** cc=new (int*)[10]; 聲明一個(gè)10個(gè)元素的數組,數組每個(gè)元素都是一個(gè)int *指針,每個(gè)元素還可以單獨申請空間,因為cc的類(lèi)型是int*型的指針,所以你要在堆里申請的話(huà)就要用int *來(lái)申請;
看下邊的例子  (vc & GNU編譯器都已經(jīng)通過(guò));
      int ** a= new int * [2];     //申請兩個(gè)int * 型的空間
      a[1]=new int[3];        //為a的第二個(gè)元素又申請了3個(gè)int 型空間,a[1]指向了此空間首地址處
      a[0]=new int[4];        ////為a的第一個(gè)元素又申請了4個(gè)int 型空間,a[0] 指向了此空間的首地址處
      int * b;
      a[0][0]=0;
      a[0][1]=1;
      b=a[0];
 delete [] a[0]       //一定要先釋放a[0],a[1]的空間,否則會(huì )造成內存泄露.;
      delete [] a[1];
 delete [] a;
      b++;
      cout<<*b<<endl;       //隨機數
注意?。阂驗閍 是在堆里申請的無(wú)名變量數組,所以在delete 的時(shí)候要用delete [] 來(lái)釋放內存,但是a的每一個(gè)元素又單獨申請了空間,所以在delete [] a之前要先delete [] 掉 a[0],a[1],否則又會(huì )造成內存泄露.
(4) 指針數組?。?
   
我們再來(lái)看看第二種?。憾S指針數組
int *(*c)[3]=new int *[3][2];
如果你對上邊的介紹的個(gè)種指針類(lèi)型很熟悉的話(huà),你一眼就能看出來(lái)c是個(gè)二級指針,只不過(guò)指向了一個(gè)二維int * 型的數組而已,也就是二維指針數組。
例子?。?
int *(*b)[10]=new int*[2][10];//
b[0][0]=new int[100];
b[0][1]=new int[100];
*b[0][0]=1;
cout <<*b[0][0]<<endl;    //打印結果為1
delete [] b[0][0];
delete [] b[0][1];
delete [] b;
cout<<*b[0][0]<<endl;    //打印隨機數
 這里只為大家還是要注意內存泄露的問(wèn)題,在這里就不再多說(shuō)了。
如果看了上邊的文章,大家估計就會(huì )很熟悉,這個(gè)b是一個(gè)二維指針,它指向了一個(gè)指針數組

第二種?。?
int **d[2];表示一個(gè)擁有兩個(gè)元素數組,每一個(gè)元素都是int ** 型,這個(gè)指向指針的指針:)
   d不管怎樣變終究也是個(gè)數組,呵呵,
   如果你讀懂了上邊的,那下邊的聲明就很簡(jiǎn)單了:
   d[0]=new int *[10];
   d[1]=new int * [10];
delete [] d[0];
delete [] d[1];
具體的就不再多說(shuō)了 :)
二?。骸『瘮抵羔槨?

關(guān)于函數指針,我想在我們可能需要寫(xiě)個(gè)函數,這個(gè)函數體內要調用另一個(gè)函數,可是由于項目的進(jìn)度有限,我們不知道要調用什么樣的函數,這個(gè)時(shí)候可能就需要一個(gè)函數指針;

int a();這個(gè)一個(gè)函數的聲明;
ing (*b)();這是一個(gè)函數指針的聲明;
讓我們來(lái)分析一下,左邊圓括弧中的星號是函數指針聲明的關(guān)鍵。另外兩個(gè)元素是函數的返回類(lèi)型(void)和由邊圓括弧中的入口參數(本例中參數是空)。注意本例中還沒(méi)有創(chuàng )建指針變量-只是聲明了變量類(lèi)型。目前可以用這個(gè)變量類(lèi)型來(lái)創(chuàng )建類(lèi)型定義名及用sizeof表達式獲得函數指針的大?。?
unsigned psize = sizeof (int (*) ()); 獲得函數指針的大小
// 為函數指針聲明類(lèi)型定義
typedef int (*PFUNC) ();

PFUNC是一個(gè)函數指針,它指向的函數沒(méi)有輸入參數,返回int。使用這個(gè)類(lèi)型定義名可以隱藏復雜的函數指針語(yǔ)法,就我本人強烈建議我們大內弟子使用這種方式來(lái)定義;

下面是一個(gè)例子,一個(gè)簡(jiǎn)單函數指針的回調(在GNU編譯器上通過(guò),在VC上需要改變一個(gè)頭文件就OK了)

#include<iostream>              //GNU 編譯器 g++ 實(shí)現
using namespace std;
/*                              //vc 的實(shí)現
#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)();              //一個(gè)簡(jiǎn)單函數指針的聲明
typedef int(*FUNC)();   //一個(gè)函數指針類(lèi)型的聲明

FUNC ff[] = {a,b,c,d,e,f,g,h,i};   //聲明一個(gè)函數指針數組,并初始化為以上聲明的a,b,c,d,e,f,g,h,i函數

FUNC func3(FUNC vv){    //定義函數func3,傳入一個(gè)函數指針,并且返回一個(gè)同樣類(lèi)型的函數指針
     vv();
     return vv;
}

/*FUNC func4(int (*vv)()){      //func3的另一種實(shí)現
     vv();
     return vv;
}*/

int main(){
     for(int i=0;i<sizeof(ff)/sizeof (FUNC);i++){  //循環(huán)調用函數指針
             FUNC r=func3(ff[ i ]);
             cout<<r()<<endl;                //輸出返回值,只是返回了0
     }
     return 0;
}
到目前為止,我們只討論了函數指針及回調而沒(méi)有去注意ANSI C/C++的編譯器規范。許多編譯器有幾種調用規范。如在Visual C++中,可以在函數類(lèi)型前加_cdecl,_stdcall或者_pascal來(lái)表示其調用規范(默認為_(kāi)cdecl)。C++ Builder也支持_fastcall調用規范。調用規范影響編譯器產(chǎn)生的給定函數名,參數傳遞的順序(從右到左或從左到右),堆棧清理責任(調用者或者被調用者)以及參數傳遞機制(堆棧,CPU寄存器等)。
好了,先到此為止吧,寫(xiě)這篇文章耗費了基本上快半天的時(shí)間了,很多事情還沒(méi)有做,等改天有時(shí)間再回來(lái)整理,所有的源程序都放在openlab3服務(wù)器上我的目錄下lib/cpp下,大家可以去拿。不知道的登陸openlab3 然后cd ~chengx/lib/cpp就可以看到了。

還有很復雜的聲明可能也是一種挑戰 比如<<Think in c++>>里的
int (*(*f4())[10]();的聲明,f4是一個(gè)返回指針的函數,該指針指向了含有10個(gè)函數指針的數組,這些函數返回整形值;不是這個(gè)函數有特別之處,而是Bruce Eckel 說(shuō)的“從右到左的辨認規則”是一種很好的方法,值得我們去學(xué)習,感謝他:)

最后我想應該跟大家說(shuō)一下,寫(xiě)程序應該就象JERRY所說(shuō)的:簡(jiǎn)單就是美;我們應該遵循一個(gè)原則 : KISS (Keep It Simple,Stupid ,盡量保持程序簡(jiǎn)單 出自 :《Practical C programming》),把自己的程序盡量的簡(jiǎn)單明了,這是個(gè)非常非常好的習慣。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
new,delete和指針
看完這篇你還能不懂C語(yǔ)言/C 內存管理?
也談野指針
原創(chuàng )?。簭氐琢私庵羔様到M,數組指針以及函數指針
【C語(yǔ)言核心基礎】基本運算、變量、數組、指針、函數、結構體...
C語(yǔ)言難點(diǎn)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久