2009-11-04 79 views
11

據我所知,在編譯c時間之前,數組需要具有特定的大小。可以在運行時確定數組的大小c?

我想知道爲什麼這段代碼仍然有效?

int s; 
printf("enter the array size: "); 
scanf("%d",&s); 

int a[s]; // Isn't s value determined at run time? 

回答

19

數組大小需要用ANSI 89 C.已知的99版本的規範刪除了這個限制,並允許可變大小的數組。

這裏是文檔沒有此功能

+0

哦,我明白了。謝謝。所以數組的所有元素仍然位於堆棧上? – root 2009-11-04 22:43:36

+0

是的,他們是。如果不好,請按照其他答案中的建議使用malloc。 – 2009-11-04 23:24:27

4

如果您需要使用動態大小分配數組,則必須使用malloc()從堆中獲取數組。

int *a = (int*)malloc(sizeof(int) * s) 
+2

如果放棄'(int *)'強制轉換,如果忘記包含定義'malloc'的文件,編譯器將會生成一個錯誤。因此最好不要包含演員。 – 2009-11-04 22:43:46

+1

'int * a = malloc(s * sizeof * a)' – AnT 2009-11-04 23:15:21

0

您在這裏混淆了兩個東西的GNU版本。

1)確定一個已分配的陣列的大小(這您的標題意味着):由一個的尺寸(比如,第一)元件的總的分頻sizeof()

sizeof(a)/sizeof(a[0]) 

2)動態分配內存作爲您的問題要求:

int *a = (int*)malloc(s * sizeof(int)); 
+0

sizeof(a)/ sizeof(a [0])在編譯時確定數組的大小,而不是像數組聲明那樣在堆棧中分配時的運行時。 – 2017-02-14 16:54:19

1

此代碼由C99語言規範支持。 GCC編譯器在C89/90模式下也支持該代碼作爲擴展。

所以,你的問題的答案(爲什麼它「有效」)取決於你如何編譯它。在一般情況下,這甚至不會被C89/90編譯器編譯。

0

瞭解內存如何通過編譯器分配給變量以正確回答您的問題非常重要。有兩種模式將內存分配給變量,它可以位於堆上,也可以位於堆棧上。動態分配堆上的內存。因此,在堆中分配內存的變量可以在運行時給出其大小。

C中的數組在堆棧中被賦予內存。爲了在堆棧中提供內存,編譯期間編譯器應該知道內存的大小。所以在運行期間,可以爲堆棧上的變量預留多少內存。就C語言而言,這是您無法在運行時決定數組大小的原因。

+1

在堆棧上分配內存只是調整堆棧指針的問題 - 並且沒有*堆棧指針只能通過編譯時已知值調整的根本原因。事實上,最新的C標準允許自動變量的大小在運行時確定,並且還有一個通用的擴展'alloca()',它在* that *之前幾年提供了相同的東西。 – caf 2009-11-05 00:22:43

0

Variable Length Arrays自從C99以來一直是C語言的一部分。 但是它們已經作爲C11中的一個特性被製成 - 意味着符合C11的實現不需要提供它(儘管實際上支持C99的所有實現當然都在C11中提供了VLA)。

您可以使用宏__STDC_NO_VLA__(如果它在C99或C11編譯模式中定義,那麼您的實現不支持VLA)檢查您的實現是否不提供VLA。

所以決定在運行時的陣列的尺寸是可能的現代C(> = C99)和代碼類的下面是細:

int s; 
printf("Enter the array size: "); 
scanf("%d", &s); 
int a[s]; 

VLAS的一個明顯的缺點是,如果s是相當大的和a分配失敗。更糟的是,沒有辦法檢查分配是否失敗,並且會遇到運行時錯誤(例如,segfault)。它本質上是undefined behaviour。所以如果數組大小太大,你想避免使用VLA。基本上, 當有疑問時,去動態內存分配(見下文)。

與VLA相比,另一個問題嚴重得多,它們具有自動存儲時間段(又名「堆棧分配」)。所以如果你想要一些持續時間更長的話,那麼塊範圍(其中聲明瞭VLA),那麼VLA是沒有幫助的。

C89,沒有VLA。所以使用動態內存分配是唯一的方法。雖然有一些非標準的擴展,如alloca()與VLA類似,但與VLA具有相同的缺點)。

int s; 
printf("enter the array size: "); 
scanf("%d",&s); 
int *a = malloc(s * sizeof *a); 
... 
free(a);