Tablica statyczna a tablica dynamiczna w C ++


91

Jaka jest różnica między tablicą statyczną a tablicą dynamiczną w C ++?

Muszę zrobić zadanie dla mojej klasy i mówi, aby nie używać tablic statycznych, tylko tablice dynamiczne. Zajrzałem do książki i online, ale nie rozumiem.

Myślałem, że statyczny został utworzony w czasie kompilacji, a dynamiczny w czasie wykonywania, ale mogę pomylić to z alokacją pamięci.

Czy możesz wyjaśnić różnicę między tablicą statyczną a tablicą dynamiczną w C ++?


1
Statyczny nie jest przeciwieństwem dynamiki. Albo książka, której używasz, jest okropna, albo wyrywasz ją z kontekstu. Zamierzam dodać nową odpowiedź poniżej, aby to wyjaśnić.
Joshua Clayton

3
Zobacz diagram w tym pytaniu: stackoverflow.com/a/11698458/1143274 Tablice statyczne nie są przydzielane na stosie ani na stercie.
Evgeni Sergeev

* tablica stała vs tablica dynamiczna
csguy

Odpowiedzi:


102

Tablice lokalne są tworzone na stosie i mają automatyczny czas przechowywania - nie musisz ręcznie zarządzać pamięcią, ale są niszczone, gdy funkcja, na której się kończy, się kończy. Koniecznie mają stały rozmiar:

int foo[10];

Tablice utworzone za pomocą operator new[]mają dynamiczny czas trwania i są przechowywane na stercie (technicznie rzecz biorąc, „magazyn darmowy”). Mogą mieć dowolny rozmiar, ale musisz je przydzielić i zwolnić, ponieważ nie są częścią ramki stosu:

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

18
To prawda, ale tylko po to, aby zilustrować, jak to działa. Nie rób tego w prawdziwym kodzie, ale zamiast tego użyj std :: vector.
Eddy Pronk

23
@Eddy: To zależy od sytuacji, czy wektor jest potrzebny
Casebash,

6
@Casebash: W jakiej sytuacji wolałbyś tablicę? „Zawsze powinieneś preferować używanie wektorów lub deques zamiast tablic”. - Herb Sutter (bardziej wyjątkowy C ++)
Eddy Pronk

16
@EddyPronk Ze względu na fragmentację pamięci można użyć stałej tablicy jako pewnego rodzaju puli. Nie każdy przypadek wymaga stosu. Stosowanie tablic opartych na stosie ma szczególne zalety. Traktujesz std :: vector jako złoty młotek, powszechny anty-wzór.
void.pointer

4
@EddyPronk: Jestem prawie pewien, że Herb Sutter miał na myśli tablice dynamiczne, takie jak int* foo = new int[N]te, które musisz mieć dla deletesiebie, dlatego uważaj w przypadku wyjątku. Tablice statyczne nie mają tych problemów.
Alexander Malakhov

31

static jest słowem kluczowym w C i C ++, więc zamiast ogólnego terminu opisowego, static ma bardzo specyficzne znaczenie, gdy zostanie zastosowane do zmiennej lub tablicy. Aby pogłębić zamieszanie, ma trzy różne znaczenia w oddzielnych kontekstach. Z tego powodu tablica statyczna może być stała lub dynamiczna.

Pozwól mi wyjaśnić:

Pierwsza jest specyficzna dla C ++:

  • Statyczny element członkowski klasy to wartość, która nie jest tworzona za pomocą konstruktora ani usuwana za pomocą destruktora. Oznacza to, że element członkowski musi zostać zainicjowany i utrzymany w inny sposób. statyczny element członkowski może być wskaźnikami zainicjowanymi na wartość null, a następnie przydzielonymi przy pierwszym wywołaniu konstruktora. (Tak, to byłoby statyczne i dynamiczne)

Dwa są dziedziczone po C:

  • w funkcji zmienna statyczna to taka, której lokalizacja pamięci jest zachowywana między wywołaniami funkcji. Jest statyczny, ponieważ jest inicjowany tylko raz i zachowuje swoją wartość między wywołaniami funkcji (użycie statyki powoduje, że funkcja nie jest ponownie wprowadzana, tj. Nie jest bezpieczna dla wątków)

  • zmienne statyczne zadeklarowane poza funkcjami to zmienne globalne, do których można uzyskać dostęp tylko z poziomu tego samego modułu (plik z kodem źródłowym z innymi # dołączeniami)

Pytanie (myślę), które chciałeś zadać, dotyczy różnicy między tablicami dynamicznymi a tablicami ustalonymi lub kompilowanymi w czasie. To jest łatwiejsze pytanie, tablice w czasie kompilacji są określane z góry (podczas kompilacji programu) i są częścią ramki stosu funkcji. Są przydzielane przed uruchomieniem funkcji głównej. tablice dynamiczne są przydzielane w czasie wykonywania za pomocą słowa kluczowego „new” (lub rodziny malloc z C), a ich rozmiar nie jest z góry znany. alokacje dynamiczne nie są automatycznie czyszczone, dopóki program nie przestanie działać.


4
+1, Twoja odpowiedź jest najbardziej dokładna i dokładna i powinna była otrzymać więcej głosów.
Bozon Z

Jeśli deklarujesz rozmiar tablicy za pomocą new[]operatora, jak to się dzieje, że rozmiar nie jest znany do czasu uruchomienia? ieint* p = new int[10]
wulfgarpro

„Są przydzielane przed uruchomieniem funkcji głównej”. Po co alokować zmienne stosu przed wprowadzeniem odpowiedniego bloku?
AlwaysLearning

Zmienne stosu (zazwyczaj zmienne lokalne w funkcji) mają predefiniowany rozmiar i pozycję w ramce stosu, a cały stos jest przydzielany przed uruchomieniem funkcji głównej @AlwaysLearning. Podczas wprowadzania ramki stosu za pomocą wywołania funkcji wskaźnik stosu jest aktualizowany, ale nowa ramka stosu znajduje się w stosie. Nigdy więcej stosów nie zostanie przydzielonych. W rzeczywistości zbyt duża liczba zmiennych (na przykład olbrzymia tablica) lub zbyt wiele wywołań funkcji otwartych w tym samym czasie powoduje przepełnienie stosu, od którego pochodzi nazwa tej witryny.
Joshua Clayton

@JoshuaClayton Myślę, że to nie może być poprawne. Jak możesz przydzielić ramki stosu (zwróć uwagę na liczbę mnogą) dla funkcji rekurencyjnej, jeśli nie wiesz, ile razy zostanie ona wprowadzona?
AlwaysLearning

11

Myślę, że semantyka używana na zajęciach jest myląca. Przez „statyczny” prawdopodobnie rozumie się po prostu „stały rozmiar”, a przez „dynamiczny” prawdopodobnie chodzi o „zmienny rozmiar”. W takim przypadku tablica o stałym rozmiarze może wyglądać następująco:

int x[10];

a „dynamiczna” byłaby po prostu dowolną strukturą, która pozwala na zwiększenie lub zmniejszenie podstawowej pamięci w czasie wykonywania. W większości przypadków std::vectorwystarczy klasa ze standardowej biblioteki C ++. Użyj tego w ten sposób:

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

std::vectorzostał operator[]zdefiniowany, więc można go używać z tymi samymi semantyki jako tablica.


1
Myślę, że jest dość jasne, że przez „tablicę dynamiczną” oznaczają one po prostu tablicę alokowaną dynamicznie (to znaczy taką, w której rozmiar można określić dynamicznie w czasie wykonywania). Jaknew int[10]
jalf

@jalf: Bardziej martwiłem się terminem „statyczny”. W celu zachowania spójności wolę nazywać „tablicę dynamiczną” tablicą o przydzielonym lub zmiennym rozmiarze.
Ben Collins,

Dobra uwaga, ponieważ tablica statyczna może być automatyczna i zaimplementowana na stosie lub globalna i zaimplementowana w sekcji danych. Oba są statyczne, ale wewnętrznie kod, który uzyskuje do nich dostęp, może być bardzo różny.
Bozon Z

9

Tablice statyczne są przydzielane do pamięci w czasie kompilacji, a pamięć jest przydzielana na stosie. Natomiast tablice dynamiczne są przydzielane w czasie wykonywania, a pamięć jest przydzielana ze sterty.

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

4
Tablica globalna jest tablicą statyczną i jest zaimplementowana w sekcji danych, a nie ze stosu.
Bozon Z

8

Ważne jest, aby mieć jasne definicje tego, co oznaczają terminy. Niestety wydaje się, że istnieje wiele definicji tego, co oznaczają tablice statyczne i dynamiczne.

Zmienne statyczne to zmienne zdefiniowane przy użyciu statycznej alokacji pamięci . To jest ogólna koncepcja niezależna od C / C ++. W C / C ++ możemy tworzyć zmienne statyczne o zasięgu globalnym, plikowym lub lokalnym w następujący sposób:

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

Zmienne automatyczne są zwykle implementowane przy użyciu alokacji pamięci opartej na stosie . Tablicę automatyczną można utworzyć w C / C ++ w następujący sposób:

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

Co te tablice, x, y, zi wmają wspólną cechą jest to, że wielkość dla każdego z nich jest stała i jest określona w czasie kompilacji.

Jednym z powodów, dla których ważne jest zrozumienie różnicy między tablicą automatyczną a tablicą statyczną, jest to, że statyczna pamięć jest zwykle zaimplementowana w sekcji danych (lub sekcji BSS ) pliku obiektowego, a kompilator może używać adresów bezwzględnych, aby uzyskać dostęp do tablic co jest niemożliwe w przypadku przechowywania na stosie.

Zwykle pod pojęciem tablicy dynamicznej nie rozumie się takiej, której rozmiar można zmieniać, ale zaimplementowaną przy użyciu dynamicznej alokacji pamięci o stałym rozmiarze określanym w czasie wykonywania. W C ++ odbywa się to za pomocą newoperatora .

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

Ale możliwe jest utworzenie automatycznej tablicy z rozmiarem poprawek zdefiniowanym w czasie wykonywania za pomocą alloca:

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

W przypadku prawdziwej tablicy dynamicznej należy użyć czegoś takiego jak std::vectorw C ++ (lub tablicy o zmiennej długości w C ).

Co oznaczało zadanie w pytaniu PO? Myślę, że jest jasne, że to, co było pożądane, nie było tablicą statyczną lub automatyczną, ale taką, która albo wykorzystywała dynamiczną alokację pamięci za pomocą newoperatora, albo tablicę o nie ustalonym rozmiarze, używając np std::vector.


3

Myślę, że w tym kontekście oznacza to, że jest statyczny w tym sensie, że rozmiar jest stały. Użyj std :: vector. Posiada funkcję resize ().


2

Możesz mieć tablicę pseudo dynamiczną, w której rozmiar jest ustawiany przez użytkownika w czasie wykonywania, ale potem jest ustalany.

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

Nie jest częścią standardowego C ++ (w C99 i jako rozszerzenie kompilatora dla gcc).
crashmstr

1

Tablica statyczna :

  1. Tablice statyczne są przydzielane w pamięci w czasie kompilacji.
  2. Rozmiar jest ustalony.
  3. Znajduje się w pamięci stosu.
  4. Na przykład. : int tablica [10]; // tablica o rozmiarze 10

Tablica dynamiczna:

  1. Pamięć jest przydzielana w czasie wykonywania.
  2. Rozmiar nie jest ustalony.
  3. Znajduje się w przestrzeni pamięci sterty.
  4. Na przykład. : int * array = new int [10];

0

Tak, prawda, tablica statyczna jest tworzona w czasie kompilacji, podczas gdy tablica dynamiczna jest tworzona w czasie wykonywania. Jeśli chodzi o różnicę w ich lokalizacjach w pamięci, statyczne znajdują się na stosie, a dynamiczne są tworzone na stercie. Wszystko, co znajduje się na stercie, wymaga zarządzania pamięcią, dopóki nie jest obecny moduł wyrzucania elementów bezużytecznych, jak w przypadku platformy .net, w przeciwnym razie istnieje ryzyko wycieku pamięci.


0

Tablica statyczna: wydajność. Nie jest wymagana dynamiczna alokacja ani cofanie alokacji.

Tablice zadeklarowane w C, C ++ w funkcji łącznie z modyfikatorem statycznym są statyczne. Przykład: static int foo [5];


1
@admdrew, to prawda, ale na to pytanie nigdy nie udzielono dobrej odpowiedzi. Najlepszą odpowiedzią jest odpowiedź Joshuy Claytona, ale myślę, że lepszą odpowiedzią jest to stackoverflow.com/questions/17775066/ ...
Bozon Z

@Zboson Dobrze wiedzieć, dzięki. Heh i ja właśnie zdaliśmy sobie sprawę, że napisałem ten komentarz prawie rok temu.
admdrew

-3

statyczne aranżacje oznaczają podawanie elementów z boku tablicy

dynamiczne znaki aranżacyjne bez podawania elementów po stronie tablicy

przykład:

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

Myślę, że powiedział poprawnie. Jeśli masz dokładną długość tablicy, jest to tablica statyczna, a jeśli nie podajesz długości, jest to tablica dynamiczna. ale ponieważ nie umie pisać po angielsku, dlatego ludzie zaznaczają tę odpowiedź.
muhammad tayyab
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.