Mảng tĩnh so với mảng động trong C ++


91

Sự khác biệt giữa mảng tĩnh và mảng động trong C ++ là gì?

Tôi phải làm một bài tập cho lớp của mình và nó nói rằng không sử dụng mảng tĩnh, chỉ sử dụng mảng động. Tôi đã tìm trong sách và trên mạng, nhưng dường như tôi không hiểu.

Tôi nghĩ rằng tĩnh được tạo vào thời gian biên dịch và động trong thời gian chạy, nhưng tôi có thể nhầm điều này với cấp phát bộ nhớ.

Bạn có thể giải thích sự khác biệt giữa mảng tĩnh và mảng động trong C ++ không?


1
Tĩnh không đối lập với động. Cuốn sách bạn đang sử dụng quá tệ hoặc bạn đang lấy nó ra khỏi ngữ cảnh. Tôi sẽ thêm một câu trả lời mới bên dưới để hy vọng làm rõ điều này.
Joshua Clayton

3
Xem sơ đồ trong câu hỏi này: stackoverflow.com/a/11698458/1143274 Mảng tĩnh không được cấp phát trên ngăn xếp hoặc đống.
Evgeni Sergeev

* mảng cố định so với mảng động
csguy

Câu trả lời:


102

Mảng cục bộ được tạo trên ngăn xếp và có thời lượng lưu trữ tự động - bạn không cần quản lý bộ nhớ theo cách thủ công, nhưng chúng sẽ bị phá hủy khi chức năng của chúng kết thúc. Chúng nhất thiết phải có kích thước cố định:

int foo[10];

Mảng được tạo bằng operator new[]có thời lượng lưu trữ động và được lưu trữ trên heap (về mặt kỹ thuật là "cửa hàng miễn phí"). Chúng có thể có bất kỳ kích thước nào, nhưng bạn cần tự mình phân bổ và giải phóng chúng vì chúng không phải là một phần của khung ngăn xếp:

int* foo = new int[10];
delete[] foo;

18
Điều này đúng, nhưng chỉ để minh họa cách nó hoạt động. Vui lòng không làm điều này bằng mã thực mà thay vào đó hãy sử dụng std :: vector.
Eddy Pronk

23
@Eddy: Nó phụ thuộc vào tình hình về việc liệu một vector là cần thiết
Casebash

6
@Casebash: Bạn thích mảng nào hơn? "Bạn nên luôn thích sử dụng vectơ hoặc deques thay vì mảng." - Herb Sutter (C ++ đặc biệt hơn)
Eddy Pronk

16
@EddyPronk Vì lý do phân mảnh bộ nhớ, người ta có thể sử dụng một mảng cố định như một loại nhóm. Không phải mọi trường hợp đều yêu cầu heap, có những lợi ích đặc biệt khi sử dụng mảng dựa trên ngăn xếp. Bạn đang coi vectơ std :: như một chiếc búa vàng, một mẫu chống phổ biến.
void.pointer

4
@EddyPronk: Tôi khá chắc chắn Herb Sutter có nghĩa là các mảng động, giống như mảng int* foo = new int[N]này bạn phải deletetự làm và do đó hãy cẩn thận khi có ngoại lệ. Mảng tĩnh không có những vấn đề này.
Alexander Malakhov

31

static là một từ khóa trong C và C ++, vì vậy thay vì một thuật ngữ mô tả chung chung, static có ý nghĩa rất cụ thể khi được áp dụng cho một biến hoặc mảng. Để kết hợp sự nhầm lẫn, nó có ba ý nghĩa riêng biệt trong các ngữ cảnh riêng biệt. Do đó, một mảng tĩnh có thể là cố định hoặc động.

Hãy để tôi giải thích:

Đầu tiên là C ++ cụ thể:

  • Thành viên lớp tĩnh là một giá trị không được khởi tạo với hàm tạo hoặc bị xóa bằng hàm hủy. Điều này có nghĩa là thành viên phải được khởi tạo và duy trì theo cách khác. static member có thể là các con trỏ được khởi tạo thành null và sau đó được cấp phát lần đầu tiên một hàm tạo được gọi. (Có, đó sẽ là tĩnh và động)

Hai được kế thừa từ C:

  • trong một hàm, một biến tĩnh là một biến có vị trí bộ nhớ được bảo toàn giữa các lần gọi hàm. Nó tĩnh ở chỗ nó chỉ được khởi tạo một lần và giữ nguyên giá trị của nó giữa các lần gọi hàm (sử dụng statics làm cho một hàm không chạy lại, tức là không an toàn)

  • các biến tĩnh được khai báo bên ngoài các hàm là các biến toàn cục chỉ có thể được truy cập từ bên trong cùng một mô-đun (tệp mã nguồn với bất kỳ # bao gồm nào khác)

Câu hỏi (tôi nghĩ) bạn muốn hỏi là sự khác biệt giữa mảng động và mảng cố định hoặc thời gian biên dịch. Đó là một câu hỏi dễ hơn, các mảng thời gian biên dịch được xác định trước (khi chương trình được biên dịch) và là một phần của khung ngăn xếp hàm. Chúng được cấp phát trước khi chức năng chính chạy. mảng động được cấp phát trong thời gian chạy với từ khóa "mới" (hoặc họ malloc từ C) và kích thước của chúng không được biết trước. phân bổ động không được tự động dọn dẹp cho đến khi chương trình ngừng chạy.


4
+1, câu trả lời của bạn là chính xác và chính xác nhất và đáng lẽ sẽ nhận được nhiều phiếu bầu hơn.
Z boson

Nếu bạn khai báo kích thước của mảng bằng new[]toán tử, làm thế nào để kích thước không được biết cho đến thời gian chạy? tứcint* p = new int[10]
wulfgarpro

"Chúng được cấp phát trước khi chức năng chính chạy." Tại sao phải phân bổ các biến ngăn xếp trước khi khối liên quan được nhập?
AlwaysLearning

Các biến ngăn xếp (thường là các biến cục bộ trong một hàm) có kích thước và vị trí được xác định trước trong khung ngăn xếp và toàn bộ ngăn xếp được cấp phát trước khi chạy hàm chính, @AlwaysLearning. Khi nhập khung ngăn xếp thông qua lệnh gọi hàm, con trỏ ngăn xếp được cập nhật, nhưng khung ngăn xếp mới nằm trong ngăn xếp. Không còn ngăn xếp nào được phân bổ. Trên thực tế, quá lớn các biến (ví dụ như một mảng khổng lồ) hoặc quá nhiều lệnh gọi hàm mở cùng một lúc dẫn đến tràn ngăn xếp, trang web này được đặt tên.
Joshua Clayton

@JoshuaClayton Tôi nghĩ điều này không thể chính xác. Làm thế nào bạn có thể phân bổ các khung ngăn xếp (lưu ý số nhiều) cho một hàm đệ quy khi bạn không biết nó sẽ được nhập bao nhiêu lần?
AlwaysLearning

11

Tôi nghĩ ngữ nghĩa đang được sử dụng trong lớp của bạn là khó hiểu. Những gì có thể có nghĩa là "tĩnh" chỉ đơn giản là "kích thước không đổi", và những gì có thể có nghĩa là "động" là "kích thước thay đổi". Trong trường hợp đó, một mảng kích thước không đổi có thể trông như thế này:

int x[10];

và một "động" sẽ chỉ là bất kỳ loại cấu trúc nào cho phép tăng hoặc giảm bộ nhớ cơ bản trong thời gian chạy. Hầu hết thời gian, std::vectorlớp từ thư viện chuẩn C ++ sẽ là đủ. Sử dụng nó như thế này:

std::vector<int> x(10); // this starts with 10 elements, but the vector can be resized.

std::vectorđã operator[]được định nghĩa, vì vậy bạn có thể sử dụng nó với cùng ngữ nghĩa như một mảng.


1
Tôi nghĩ rằng khá rõ ràng rằng bởi "mảng động", chúng chỉ đơn giản có nghĩa là một mảng được cấp phát động (nghĩa là một trong đó kích thước có thể được chỉ định động, trong thời gian chạy). Thíchnew int[10]
jalf

@jalf: Tôi lo lắng hơn về thuật ngữ 'tĩnh'. Tôi thích gọi một "mảng động" là một mảng có kích thước được phân bổ hoặc thay đổi vì lợi ích của tính nhất quán.
Ben Collins

Điểm tốt vì một mảng tĩnh có thể tự động và được triển khai trên ngăn xếp hoặc là toàn cục và được triển khai trong phần dữ liệu. Cả hai đều tĩnh nhưng bên trong mã truy cập chúng có thể rất khác nhau.
Z boson

9

Mảng tĩnh được cấp phát bộ nhớ tại thời điểm biên dịch và bộ nhớ được cấp phát trên ngăn xếp. Trong khi đó, các mảng động được cấp phát bộ nhớ trong thời gian chạy và bộ nhớ được cấp phát từ heap.

int arr[] = { 1, 3, 4 }; // static integer array.   
int* arr = new int[3]; // dynamic integer array.

4
Mảng toàn cục là một mảng tĩnh và nó được triển khai trong một phần dữ liệu chứ không phải từ ngăn xếp.
Z boson

8

Điều quan trọng là phải có định nghĩa rõ ràng về ý nghĩa của các thuật ngữ. Thật không may, dường như có nhiều định nghĩa về ý nghĩa của mảng tĩnh và mảng động.

Biến tĩnh là các biến được định nghĩa bằng cách sử dụng cấp phát bộ nhớ tĩnh . Đây là một khái niệm chung độc lập với C / C ++. Trong C / C ++, chúng ta có thể tạo các biến tĩnh với phạm vi toàn cục, tệp hoặc cục bộ như sau:

int x[10]; //static array with global scope
static int y[10]; //static array with file scope
foo() {
    static int z[10]; //static array with local scope

Các biến tự động thường được thực hiện bằng cách sử dụng cấp phát bộ nhớ dựa trên ngăn xếp . Một mảng tự động có thể được tạo trong C / C ++ như sau:

foo() {
    int w[10]; //automatic array

Có gì các mảng, x, y, zwcó điểm chung là kích thước cho mỗi người trong số họ là cố định và được xác định tại thời gian biên dịch.

Một trong những lý do quan trọng để hiểu sự khác biệt giữa mảng tự động và mảng tĩnh là lưu trữ tĩnh thường được triển khai trong phần dữ liệu (hoặc phần BSS ) của tệp đối tượng và trình biên dịch có thể sử dụng địa chỉ tuyệt đối để truy cập các mảng. điều này là không thể với lưu trữ dựa trên ngăn xếp.

Điều thường có nghĩa là một mảng động không phải là một mảng có thể thay đổi kích thước mà là một mảng được triển khai bằng cách sử dụng cấp phát bộ nhớ động với kích thước cố định được xác định tại thời điểm chạy. Trong C ++, điều này được thực hiện bằng cách sử dụng newtoán tử .

foo() {
   int *d = new int[n]; //dynamically allocated array with size n     

Nhưng có thể tạo một mảng tự động với kích thước các bản sửa lỗi được xác định trong thời gian chạy bằng cách sử dụng alloca:

foo() {
    int *s = (int*)alloca(n*sizeof(int))

Đối với một mảng động thực sự, người ta nên sử dụng một cái gì đó giống như std::vectortrong C ++ (hoặc một mảng có độ dài thay đổi trong C ).

Điều gì có nghĩa là cho nhiệm vụ trong câu hỏi của OP? Tôi nghĩ rõ ràng rằng những gì được muốn không phải là một mảng tĩnh hoặc tự động mà là một mảng sử dụng cấp phát bộ nhớ động bằng cách sử dụng newtoán tử hoặc một mảng có kích thước không cố định bằng ví dụ std::vector.


3

Tôi nghĩ trong bối cảnh này, nó có nghĩa là nó tĩnh theo nghĩa là kích thước được cố định. Sử dụng std :: vector. Nó có một hàm resize ().


2

Bạn có thể có một mảng động giả trong đó kích thước được người dùng đặt trong thời gian chạy, nhưng sau đó được cố định sau đó.

int size;
cin >> size;
int dynamicArray[size];

Không phải là một phần của C ++ tiêu chuẩn (trong C99 và là phần mở rộng của trình biên dịch cho gcc).
crashmstr

1

Mảng tĩnh :

  1. Mảng tĩnh được cấp phát bộ nhớ tại thời điểm biên dịch.
  2. Kích thước là cố định.
  3. Nằm trong không gian bộ nhớ ngăn xếp.
  4. Ví dụ. : int array [10]; // mảng có kích thước 10

Mảng động:

  1. Bộ nhớ được cấp phát tại thời gian chạy.
  2. Kích thước không cố định.
  3. Nằm trong không gian bộ nhớ Heap.
  4. Ví dụ. : int * array = new int [10];

0

Đúng vậy, mảng tĩnh được tạo tại thời điểm biên dịch trong khi mảng động được tạo trong thời gian chạy. Trong trường hợp có sự khác biệt về vị trí bộ nhớ của chúng thì tĩnh nằm trên ngăn xếp và động được tạo trên heap. Mọi thứ nằm trên heap đều cần quản lý bộ nhớ cho đến khi và trừ khi có bộ thu gom rác như trong trường hợp .net framework có mặt, nếu không sẽ có nguy cơ rò rỉ bộ nhớ.


0

Mảng tĩnh: Hiệu quả. Không cần phân bổ động hoặc phân bổ giao dịch.

Mảng được khai báo trong C, C ++ trong hàm bao gồm cả sửa đổi tĩnh là tĩnh. Ví dụ: static int foo [5];


1
@adm rút lại, điều đó đúng nhưng câu hỏi không bao giờ được trả lời tốt. Câu trả lời tốt nhất là câu trả lời Joshua Clayton, nhưng tôi nghĩ rằng một câu trả lời tốt hơn là này một stackoverflow.com/questions/17775066/...
Z boson

@Zboson Thật tốt khi biết, cảm ơn. Heh và tôi mới nhận ra rằng tôi đã đưa ra nhận xét đó gần một năm trước.
rút lại

-3

meens mảng tĩnh với việc cung cấp cho các phần tử trong mảng

meens mảng động mà không cung cấp cho các phần tử trong mảng

thí dụ:

     char a[10]; //static array
       char a[];  //dynamic array

Tôi nghĩ anh ấy nói đúng. Khi bạn đặt độ dài chính xác cho mảng thì đó là mảng tĩnh và khi bạn không cung cấp độ dài thì đó là mảng động. nhưng vì anh ấy không biết viết tiếng Anh nên mọi người đánh dấu câu trả lời này.
muhammad tayyab
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.