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.