2015-11-02 212 views
0

因此,您可以使用「新」運算符在運行時動態分配內存。但是關於以下情況的:動態與靜態內存分配

#include <iostream> 

using namespace std; 

int main() 
{ 
    int size; 

    cin >> size; 

    int a[size]; 
} 

這裏的數組的大小不可能在編譯時是已知的,並且它在運行時確定。這與動態分配的內存有何不同?

這個問題的部分原因是該聲明this頁動機:

有聲明一個正常的數組,並使用一個新的內存塊分配動態內存之間的實質性區別。 最重要的區別是常規數組的大小需要是一個常量表達式,因此它的大小必須在運行之前在程序設計時確定,而由new執行的動態內存分配允許在運行時使用任何變量值作爲大小來分配內存。

+0

這不是合法的C++。這是一個C VLA,這些不是C++規範的一部分。如果你的編譯器接受它,它必須是一個擴展。嘗試用'-pedantic'編譯。但要回答你的問題,這仍然是動態分配,儘管基於堆棧而不是基於堆。 –

+0

「動態分配」是一個通用的計算機科學術語,人們在沒有精確含義的情況下使用它。在C++標準中,「動態分配」僅指由'new'或'operator new'分配的內存。在C標準中,該術語根本不用。 –

回答

1

這在C中是合法的,但不是C++。但是,一些C++編譯器允許它作爲擴展。 This question covers that part in more detail

它與典型的動態內存分配的不同之處在於,內存分配在堆棧(而不是堆)上,並具有自動存儲持續時間(意味着它在作用域結束時自動釋放)。當執行退出包含a的作用域時,它將自動釋放。通過new/malloc分配的內存不是這種情況。

它仍然是一種動態內存分配形式(顯然,因爲內存必須動態分配到堆棧上),但它不是人們通常在使用該術語時所指的動態內存分配類型。

1

在ISO C99中允許使用變長自動數組,並且作爲擴展GCC在C90模式和C++中接受它們。這些數組與其他自動數組一樣聲明,但是其長度不是常量表達式。存儲在聲明點處分配,並在包含聲明的塊作用域退出時解除分配。例如:

FILE * 
concat_fopen (char *s1, char *s2, char *mode) 
{ 
    char str[strlen (s1) + strlen (s2) + 1]; 
    strcpy (str, s1); 
    strcat (str, s2); 
    return fopen (str, mode); 
} 

跳轉或突破數組名的範圍會取消分配存儲空間。跳入範圍是不允許的;你會得到一個錯誤信息。

作爲擴展,GCC接受可變長度數組作爲結構或聯合的成員。例如:

void 
foo (int n) 
{ 
    struct S { int x[n]; }; 
} 

您可以使用函數alloca獲得更像變長數組的效果。函數alloca在許多其他C實現中可用(但不是全部)。另一方面,變長數組更優雅。

這兩種方法還有其他區別。存在分配alloca的空間,直到包含函數返回。只要數組名稱的作用域結束,就會釋放可變長度數組的空間。 (如果在同一個函數中同時使用變長數組和alloca,則取消分配變長數組也會釋放最近使用alloca分配的任何內容。)

也可以使用可變長度數組參數的功能:

struct entry 
tester (int len, char data[len][len]) 
{ 
    /* ... */ 
} 

陣列的長度被計算一次時,存儲被分配和被記住用於陣列的情況下,範圍你用sizeof訪問它。

如果您想先傳遞數組並且之後再傳遞數組,則可以在參數列表中使用前向聲明 - 另一個GNU擴展。

struct entry 
tester (int len; char data[len][len], int len) 
{ 
    /* ... */ 
} 

分號之前的「廉政LEN」是一個參數forward聲明,並提供使len個數據時的聲明被解析聞名的名字的目的。

您可以在參數列表中寫入任意數量的此類參數前向聲明。它們可以用逗號或分號分隔,但最後一個必須以分號結尾,後面跟着「真實」參數聲明。每個前向聲明必須與參數名稱和數據類型中的「真實」聲明相匹配。 ISO C99不支持參數前向聲明。