2009-11-04 72 views

Trả lời

19

Kích thước mảng cần được biết đến với ANSI 89 C. Phiên bản 99 của thông số đã loại bỏ giới hạn này và cho phép các mảng có kích thước thay đổi.

Dưới đây là tài liệu không có phiên bản GNU của tính năng này

+0

Ồ tôi hiểu rồi. cảm ơn bạn. vì vậy tất cả các phần tử của mảng vẫn nằm trên stack? – root

+0

Có, họ đang có. Nếu đó là xấu, sử dụng malloc như đề xuất trong câu trả lời khác. –

4

Nếu bạn cần phân bổ mảng có kích thước động, bạn phải lấy nó từ heap, với malloc().

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

Nếu bạn bỏ '(int *)', trình biên dịch sẽ tạo ra lỗi nếu bạn quên đưa tệp xác định 'malloc'. Vì vậy, cách tốt nhất là không bao gồm dàn diễn viên. –

+1

'int * a = malloc (s * sizeof * a)' – AnT

0

Bạn đang bối rối hai điều ở đây.

1) Xác định kích thước của một mảng đã được phân bổ (mà tiêu đề của bạn có nghĩa): divide sizeof() cho tổng bằng kích thước của một (nói, là người đầu tiên) yếu tố:

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

2) Tự động phân bổ bộ nhớ như câu hỏi của bạn yêu cầu:

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

sizeof (a)/sizeof (a [0]) xác định kích thước của mảng tại thời gian biên dịch, không phải thời gian chạy nếu nó được cấp phát trên ngăn xếp như khai báo mảng. –

1

Mã này được hỗ trợ bởi đặc tả ngôn ngữ C99. Mã này cũng được hỗ trợ bởi trình biên dịch GCC ở chế độ C89/90 dưới dạng phần mở rộng.

Vì vậy, câu trả lời cho câu hỏi của bạn (tại sao nó "hoạt động") phụ thuộc vào cách bạn đang biên dịch nó. Trong trường hợp chung, điều này thậm chí sẽ không biên dịch bởi trình biên dịch C89/90.

0

Điều quan trọng là phải hiểu cách bộ nhớ được phân bổ cho biến bởi trình biên dịch để đưa ra câu trả lời đúng cho câu hỏi của bạn. Có hai chế độ trong đó bộ nhớ được cấp phát cho biến, nó có thể được trên một đống hoặc nó có thể được trên một ngăn xếp. Bộ nhớ trên một đống được phân bổ động. Vì vậy, một biến được cấp phát bộ nhớ trên một heap có thể được cho kích thước của nó trong thời gian chạy.

Mảng trong trường hợp C được cấp bộ nhớ trên ngăn xếp. Để cung cấp bộ nhớ trên một chồng, kích thước của bộ nhớ nên được biết đến trình biên dịch trong suốt thời gian biên dịch. Vì vậy, trong thời gian chạy mà nhiều bộ nhớ có thể được đặt sang một bên cho biến trên ngăn xếp. Đó là lý do bạn không thể quyết định kích thước của mảng tại thời gian chạy như xa như ngôn ngữ C là có liên quan.

+1

Phân bổ bộ nhớ trên ngăn xếp đơn giản chỉ là vấn đề điều chỉnh con trỏ ngăn xếp - và có * không * lý do cơ bản tại sao con trỏ ngăn xếp chỉ có thể được điều chỉnh theo các giá trị được biết tại thời gian biên dịch. Thật vậy, tiêu chuẩn C gần đây nhất cho phép các biến tự động có kích thước được xác định trong thời gian chạy, và cũng có phần mở rộng chung 'alloca()' cung cấp cùng một điều trong nhiều năm trước * *. – caf

0

Variable Length Arrays là một phần của ngôn ngữ C kể từ C99. Nhưng chúng đã được tạo thành một tính năng trong C11 - có nghĩa là việc triển khai tuân thủ C11 không cần cung cấp (mặc dù, thực tế tất cả việc triển khai hỗ trợ C99 đều cung cấp VLA trong C11).

Bạn có thể kiểm tra xem bạn triển khai không cung cấp VLA bằng cách sử dụng macro __STDC_NO_VLA__ (Nếu được xác định trong chế độ C99 hoặc C11, thì việc triển khai của bạn không hỗ trợ VLAs).

Vì vậy, quyết định một kích thước mảng trong thời gian chạy là có thể trong C hiện đại (> = C99) và mã như dưới đây là tốt:

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

Một nhược điểm rõ ràng của Vlas là nếu s là khá lớn và phân bổ a không thành công. Tệ hơn nữa, không có cách nào để kiểm tra xem phân bổ đã thất bại hay chưa và bạn sẽ gặp phải lỗi thời gian chạy (ví dụ: segfault). Về cơ bản nó là undefined behaviour. Vì vậy, bạn muốn tránh VLAs nếu kích thước mảng quá lớn. Về cơ bản, khi nghi ngờ, hãy phân bổ bộ nhớ động (xem bên dưới).

Một vấn đề khác, ít nghiêm trọng hơn nhiều so với các vấn đề khác, với VLA là chúng có thời lượng lưu trữ tự động tự động (còn gọi là "ngăn xếp được phân bổ"). Vì vậy, nếu bạn muốn cái gì đó kéo dài trong thời gian dài hơn thì phạm vi khối nơi VLA được khai báo, sau đó VLA không có sự trợ giúp.

Trong C89, không có VLA. Vì vậy, việc sử dụng phân bổ bộ nhớ động là cách duy nhất. Mặc dù, có một số tiện ích mở rộng không chuẩn như alloca() tương tự như VLA và có cùng hạn chế như VLA).

int s; 
printf("enter the array size: "); 
scanf("%d",&s); 
int *a = malloc(s * sizeof *a); 
... 
free(a); 
Các vấn đề liên quan