每日一課——C++ 動態內存——高級教程

瞭解動態內存在 C++ 中是如何工做的是成爲一名合格的 C++ 程序員必不可少的。C++ 程序中的內存分爲兩個部分:ios

  • 棧:在函數內部聲明的全部變量都將佔用棧內存。
  • 堆:這是程序中未使用的內存,在程序運行時可用於動態分配內存。

不少時候,您沒法提早預知須要多少內存來存儲某個定義變量中的特定信息,所需內存的大小須要在運行時才能肯定。程序員

常見的動態內存分配方式:編程

在 C++ 中,您能夠使用特殊的運算符爲給定類型的變量在運行時分配堆內的內存,這會返回所分配的空間地址。這種運算符即 new 運算符。數組

若是您再也不須要動態分配的內存空間,能夠使用 delete 運算符,刪除以前由 new 運算符分配的內存。函數

new 和 delete 運算符

下面是使用 new 運算符來爲任意的數據類型動態分配內存的通用語法:學習

new data-type;

在這裏,data-type 能夠是包括數組在內的任意內置的數據類型,也能夠是包括類或結構在內的用戶自定義的任何數據類型。讓咱們先來看下內置的數據類型。例如,咱們能夠定義一個指向 double 類型的指針,而後請求內存,該內存在執行時被分配。咱們能夠按照下面的語句使用 new 運算符來完成這點:測試

double* pvalue  = NULL; // 初始化爲 null 的指針
pvalue  = new double;   // 爲變量請求內存

若是自由存儲區已被用完,可能沒法成功分配內存。因此建議檢查 new 運算符是否返回 NULL 指針,並採起如下適當的操做:spa

double* pvalue  = NULL;
if( !(pvalue  = new double ))
{
   cout << "Error: out of memory." <<endl;
   exit(1);
 
}

malloc() 函數在 C 語言中就出現了,在 C++ 中仍然存在,但建議儘可能不要使用 malloc() 函數。new 與 malloc() 函數相比,其主要的優勢是,new 不僅是分配了內存,它還建立了對象。指針

在任什麼時候候,當您以爲某個已經動態分配內存的變量再也不須要使用時,您能夠使用 delete 操做符釋放它所佔用的內存,以下所示:code

delete pvalue;        // 釋放 pvalue 所指向的內存

下面的實例中使用了上面的概念,演示瞭如何使用 new 和 delete 運算符:

#include <iostream>
using namespace std;
 
int main ()
{
   double* pvalue  = NULL; // 初始化爲 null 的指針
   pvalue  = new double;   // 爲變量請求內存
 
   *pvalue = 29494.99;     // 在分配的地址存儲值
   cout << "Value of pvalue : " << *pvalue << endl;
 
   delete pvalue;         // 釋放內存
 
   return 0;
}

當上面的代碼被編譯和執行時,它會產生下列結果:

Value of pvalue : 29495

malloc和free

1. 定位

    malloc爲C語言stdlib.h庫中的函數,能夠用於動態申請空間,在申請空間以後不會對內存進行必要的初始化。

    C++能夠兼容大部分C語言的內容,malloc/free這一申請/釋放動態內存的方式在C++中用也是能夠使用的。

2. 基本語法:

變量申請示例

char * buffer;
buffer = (char*)malloc(i + 1)

     用於以字節爲單位進行內存分配,不具有內存初始化特性。返回指針的類型爲void*,能夠經過類型轉換(如static_cast<type>、(type)等)轉換爲想要的類型。

數組的動態內存分配

假設咱們要爲一個字符數組(一個有 20 個字符的字符串)分配內存,咱們能夠使用上面實例中的語法來爲數組動態地分配內存,以下所示:

char* pvalue  = NULL;   // 初始化爲 null 的指針
pvalue  = new char[20]; // 爲變量請求內存

要刪除咱們剛纔建立的數組,語句以下:

delete [] pvalue;        // 刪除 pvalue 所指向的數組
下面是 new 操做符的通用語法,能夠爲多維數組分配內存,以下所示:

一維數組

// 動態分配,數組長度爲 m
int *array=new int [m];
 
//釋放內存
delete [] array;

二維數組

int **array
// 假定數組第一維長度爲 m, 第二維長度爲 n
// 動態分配空間
array = new int *[m];
for( int i=0; i<m; i++ )
{
    array[i] = new int [n]  ;
}
//釋放
for( int i=0; i<m; i++ )
{
    delete [] arrary[i];
}
delete [] array;

二維數組實例測試:

#include <iostream>
using namespace std;
 
int main()
{
    int **p;  
    int i,j;   //p[4][8]
    //開始分配4行8列的二維數據  
    p = new int *[4];
    for(i=0;i<4;i++){
        p[i]=new int [8];
    }
 
    for(i=0; i<4; i++){
        for(j=0; j<8; j++){
            p[i][j] = j*i;
        }
    }  
    //打印數據  
    for(i=0; i<4; i++){
        for(j=0; j<8; j++)    
        {  
            if(j==0) cout<<endl;  
            cout<<p[i][j]<<"\t";  
        }
    }  
    //開始釋放申請的堆  
    for(i=0; i<4; i++){
        delete [] p[i];  
    }
    delete [] p;  
    return 0;
}

三維數組

int ***array;
// 假定數組第一維爲 m, 第二維爲 n, 第三維爲h
// 動態分配空間
array = new int **[m];
for( int i=0; i<m; i++ )
{
    array[i] = new int *[n];
    for( int j=0; j<n; j++ )
    {
        array[i][j] = new int [h];
    }
}
//釋放
for( int i=0; i<m; i++ )
{
    for( int j=0; j<n; j++ )
    {
        delete[] array[i][j];
    }
    delete[] array[i];
}
delete[] array;

三維數組測試實例:

#include <iostream>
using namespace std;
 
int main()
{  
    int i,j,k;   // p[2][3][4]
 
    int ***p;
    p = new int **[2];
    for(i=0; i<2; i++)
    {
        p[i]=new int *[3];
        for(j=0; j<3; j++)
            p[i][j]=new int[4];
    }
 
    //輸出 p[i][j][k] 三維數據
    for(i=0; i<2; i++)  
    {
        for(j=0; j<3; j++)  
        {
            for(k=0;k<4;k++)
            {
                p[i][j][k]=i+j+k;
                cout<<p[i][j][k]<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    }
 
    // 釋放內存
    for(i=0; i<2; i++)
    {
        for(j=0; j<3; j++)
        {  
            delete [] p[i][j];  
        }  
    }      
    for(i=0; i<2; i++)  
    {      
        delete [] p[i];  
    }  
    delete [] p; 
    return 0;
}

對象的動態內存分配

對象與簡單的數據類型沒有什麼不一樣。例如,請看下面的代碼,咱們將使用一個對象數組來理清這一律念:

#include <iostream>
using namespace std;
 
class Box
{
   public:
      Box() {
         cout << "調用構造函數!" <<endl;
      }
      ~Box() {
         cout << "調用析構函數!" <<endl;
      }
};
 
int main( )
{
   Box* myBoxArray = new Box[4];
 
   delete [] myBoxArray; // 刪除數組
   return 0;
}

若是要爲一個包含四個 Box 對象的數組分配內存,構造函數將被調用 4 次,一樣地,當刪除這些對象時,析構函數也將被調用相同的次數(4次)。

當上面的代碼被編譯和執行時,它會產生下列結果:

調用構造函數!
調用構造函數!
調用構造函數!
調用構造函數!
調用析構函數!
調用析構函數!
調用析構函數!
調用析構函數!

若是這篇文章對你有用的話,關注下圖瞭解更多幫助你更好的學習編程噢~海量免費資源+技術指導

相關文章
相關標籤/搜索