• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Róznica między tablicą dynamiczną a statyczną

VPS Starter Arubacloud
+2 głosów
2,786 wizyt
pytanie zadane 19 lutego 2018 w C i C++ przez foruminfa Początkujący (310 p.)

Mógłby ktoś wyjaśnić jaka jest różnica miedzy tablicą dynamiczną a tą zwykłą i o co chodzi z alokacją pamięci ? Nie mogę sobie wyobrazić jak to działa. Ponizej wklejam zdjęcie jak to jest opisane w jednej z książek. Na poczatku jest napisane ze program obliczy ile pamieci potrzebuje. Jak np. Tworze tablice dynamiczna to podaje w nawiasie klamerkowym  jej rozmiar, tak samo w statycznej podaje rozmiar. iec chyba jak podaje od razu rozmiar to podaje ile pamieci bede potrzebowac ?Dalej jest jeszcze napisane( ale tego już nie wkleiłem) że po zwolnieniu pamięci zostaje ona zwrocona do wolnego zasobu i moze byc przydzielona później. Gdzie ta pamiec jest zwalniana ? Jak zamkne program to folder z tym plikiem bedzie mial mniejszy rozmiar po zwolnieniu pamieci ?  Nie wiem jak to romumieć. Wydaje mi się że wszędzie ta alokacja jest opisana takim trudnym jezykiem, bez podania zadnych konkretów, to dla mnie jakas abstrakcja

 

 

 

2
komentarz 19 lutego 2018 przez niezalogowany
Najpierw poczytaj o tym jak działa komputer. Żebyś już wiedział o jaką pamięć chodzi.

4 odpowiedzi

+4 głosów
odpowiedź 19 lutego 2018 przez Maciej3206 Użytkownik (570 p.)
Spróbuję w prosty sposób to wyjaśnić. Komputer wykonując napisany kod rezerwuje miejsce w pamięci, dlatego musi otrzymać informację jakiego rodzaju dane będzie przechowywal oraz ile tych danych będzie przechowywal ( wielkość tablicy). Podczas statycznego deklarowania tablicy podaje się właśnie typ przechowywanych danych i jej wielkość (np: int tab [10] - tablica o 10 komorkach przechowujaca dane typu całkowitego - int). Często jednak ilosc elementów przechowywanych w tablicy nie jest znana podczas pisania programu, bo np: ilość ta podaje użytkownik i chcąc oprogramowac taki przypadek sa dwa rozwiazania. 1. Deklarujemy statyczna tablicę mocno przewymiarowana, licząc ze użytkownik wybierze mniejszą wielkość. 2. Deklarujemy tablicę dynamicznie. Każda komórka tablicy ma swój (jeden) adres, czyli kazda tablica ma tyle samo komórek, ile adresów tych komórek i przy deklarowaniu dynamicznym oprogramowujemy następujący przypadek: "zapytaj użytkownika ile ma być adresów w tablicy i "stwórz" tablicę o takiej wielkości i to działa. Adresy określa się wskaźnikiem (wskaźnik, to adres) . Wskaźnik, to normalna zmienna, tylko poprzedzona *. Przykładowa deklaracja tablicy jednowymiarowej (można dynamicznie deklarować także tablice wielowymiarowe) int wlk_tab; nasepnie zapytanie o wielkość tablicy, wczytanie tej wielkosci i jej zapisanie w zmiennej wlk_tab; int *tab; tab=new int [wlk_tab].
komentarz 20 lutego 2018 przez Beginer Pasjonat (22,110 p.)
A jeśli zadeklarujemy w ten sposób:

int rozmiar;

float tab = (rozmiar);  // tu powinny być nawiasy kwadratowe (piszę z tabletu)

Użytkownik, jako dane wprowadzi np. rozmiar = 100.

To taki sposób nazwał byś statycznym, czy dynamicznym. deklarowaniem tablicy?
komentarz 21 lutego 2018 przez Maciej3206 Użytkownik (570 p.)
Taki sposób deklaracji także nazwałbym dynamicznym, jednak nie każdy kompilator to rozumie i w podręcznikach, które czytałem taki sposób deklaracji tablicy nie był przedstawiany
+3 głosów
odpowiedź 19 lutego 2018 przez Wiciorny Ekspert (269,120 p.)
np.odpowiedź sobie na pytanie, skąd wiesz jak długa ma być tablica  gdy coś chcesz wziąć od użytkownika ? :)

A co jeśli nagle chciałbyś zmienić rozmiar tej tablicy? Potem poczytaj jak kolega napisał o pamięci, głównie o tym, co by było gdyby twój program był mega długi i zamiast działać szybko - działałby jak ślimak

Dodatkowo  biorąc pod uwagę fakt, że wskaźnik pracuje na adresie pamięci, przydzielając odp. ilość na zmienne i znająć ich rozmiar możesz- umiejętnie z użyciem liczb przesuwać wskaźnik [ jako inny alternatywny sposób ]
+1 głos
odpowiedź 19 lutego 2018 przez Piotr Wilk Nowicjusz (200 p.)

"Jak zamkne program to folder z tym plikiem bedzie mial mniejszy rozmiar po zwolnieniu pamieci ? "

Nie. Chodzi tu o pamięć RAM komputera , a nie miejsca na dysku. Tak jak koledzy powyżej , poczytaj sobie o typach pamięci w komputerze.

Pytasz jaka jest różnica? Otóż posłużę się tu przykładem z  książki "Symfonia C++" Jerzego Grębosza. Mamy radar w wieży kontroli lotów i program obsługujący wyświetlanie na ekranie monitora ikonki samolotów , które przelatują niedaleko. Normalnie zrobiłbyś pewnie tablicę przechowującą takie samoloty , i później użył jej do wyświetlania ich (tzn użył byś pewnie do tego jakiejś funkcji , ale to pomińmy) . No ale jak dużą musiałbyś tą tablice zrobić? Przecież nie wiesz ile samolotów będzie na ekranie w jednym momencie. Ustawisz t[15] , a samolotów będzie 20 no i lipa.

Więc tu z pomocą przychodzi nam właśnie dynamiczna alokacja pamięci. Dzięki niej , kiedy tylko pojawi się nowy samolot to po prostu zrobisz zmienną , która go przechowa w trakcie działania programu , a nie określając na sztywno wszystkie dane.

W tym odcinku pan Mirosław Zelent dokładnie wytłumaczył to zagadnienie jak i jego budowę i zastosowanie:

https://www.youtube.com/watch?v=0DQl74alJzw&index=11&list=PLOYHgt8dIdoxx0Y5wzs7CFpmBzb40PaDo&t=494s

Gorąco zachęcam obejrzeć jeśli nie widziałeś.

PS sam czytałem tą książkę , której zdjęcie wstawiłeś , jednak muszę przyznać , że nie jestem z niej bardzo zadowolony i autor często właśnie nie tłumaczy zagadnień w sposób klarowny , często z niedpowidzeniami.

Pozdrawiam smiley

komentarz 20 lutego 2018 przez DragonCoder Nałogowiec (36,500 p.)
Teoretycznie wiem ile maksymalnie moze pojawic sie samolotow w danym momencie. Zakladajac, ze lotnisko w hamburgu przyjmuje dana ilosc samolotow dziennie oraz wiem o ktorej mam przylot i jaki zasieg ma radar moge wyznaczyc liczbe punktow w tym momencie. Wiec logicznie przyklad ten jest prawidlowy, gdy nie wiem o jakim czasie mowily.
+1 głos
odpowiedź 21 lutego 2018 przez mokrowski Mędrzec (155,460 p.)

To będzie pewne uproszczenie ale wystarczające do tego by zrozumieć.

Zakładając że mówimy o systemach typu GNU/Linux czy MS Windows (a nie o wbudowanych lub na nietypowych architekturach innych niż von Neumanna https://pl.wikipedia.org/wiki/Architektura_von_Neumanna ), pamięć dla języka C i C++ jest w nich podzielona na główne 3 obszary (tu nie będę komplikował dokonując jeszcze dokładniejszego podziału):

1. Pamięć statyczną - zajmowaną w trakcie uruchomienia programu przez zmienne/struktury/obiekty inicjowane jeszcze przed main() oraz struktury poprzedzone static alokowane w funkcjach, klasach czy metodach.

2. Pamięć automatyczną - zajmowaną na stosie przez zmienne które występują międzyinnymi w zakresach kodu takich jak funkcje/metody.

3. Pamięć dynamiczną - przydzielaną ze sterty poprzez malloc(...) i pochodne w C i new w C++.

Pamięć automatyczna (czyli stosu), ma wielkość ograniczoną przez kompilator. Można oczywiście w trakcie kompilacji wymusić jej wielkość, ale alokowanie w niej dużych struktur (np. tablic), może skończyć się błędem... braku pamięci :-) Domyślnie jest jej ok 2 do 4MB (dla wymienionych systemów - rząd wielkości). Pamięć ta ma tę zaletę że po zakończeniu zakresu (najprościej klamer lub funkcji/metody), automatycznie jest zwalniana i dla C++ niszczona przez wywołanie destruktora (znów uproszczenie ale nie będę wchodził w szczegóły).

Pamięć statyczna, dostępna jest (w zasadzie) w całym programie (to wielkie uproszczenie ale nie będę teraz opisywał możliwości uzyskania do niej dostępu przez wskaźniki, łączność wewnętrzną/zewnętrzną itp). Jej zaletą jest to że .. pamięta stan. Dla elementów "przed main()", masz gwarancję że zostaną wyzerowane przez część uruchamiającą program w systemie operacyjnym (dla C++ będą uruchomione ich konstruktory), dla elementów w funkcjach, funkcja (metoda) będzie pamiętała stan tej zmiennej a będzie ją inicjowała przy 1 wejściu do niej. Co ciekawe C++ od C++11 robi to atomowo.

Pamięć dynamiczna, alokowana ze sterty (nazywanej w standardzie C++ storage ze względu na obsługę różnych architektur sprzętowych), może być przydzielana na etapie działającego programu. Jeśli jednak ciągle będziesz alokował tę pamięć bez jej zwalniania, także i ją wyczerpiesz. Dodatkowo ciągła alokacja i dealokacja może powodować jej fragmentację. Dla architektur wbudowanych ważne jest także że alokacja nie jest deterministyczna (może zajmować różne odcinki czasu ze względu na poszukiwanie ciągłej wolnej przestrzeni zażądanej pamięci). Brak dealokacji i "zgubienie wskaźnika" do tej pamięci, to utrata zasobów nazywana wyciekiem pamięci.

I teraz dochodząc do sedna. Jeśli wiesz że danych będzie ... nie wiadomo ile na początku działania programu lub będzie ich sporo (ponad to na co pozwala stos), będziesz decydował się na alokację dynamiczną. 

Jeśli wiesz już na wstępie ile i jakich danych potrzebujesz lub masz arch. wbudowaną, najprawdopodobniej będziesz alokował statycznie jeszcze przed main() i nie dotkniesz malloc()/new.

Poniżej przykładowy pozbawiony logiki kod który ilustruje "jaka pamięć jest gdzie":

#include <iostream>

int global_table1[10]; // Wypełniona zerami statyczna część pamięci dostępna dla całości
                       // tej mikrej aplikacji. Będzie widoczna dla linkera na zewnątrz.
                       
static int global_table2[10]; // To co wyżej ale nie będzie widoczna dla linkera na zewnątrz.

// Jakaś klasa...
struct MyClass {
    double getValues(size_t i) const {
        return values[i];
    }
private:
    int values[20];
    static double dValues[10];
};

double MyClass::dValues[10]{}; // Uruchomienie konstruktora danych statycznych. Tu będą zera... 

MyClass myClass1; // Obiekt inicjowany statycznie przed wykonaniem main()

int foo() {
    int data[20]; // Dane automatyczne niszczone po wyjściu z funkcji
    static int value = 10; // Dane statyczne które przetrwają wywołanie foo()
                           // i będą inicjowane 1 raz w trakcie 1 wejścia do funkcji.
    return value++;        // Licznik będzie inkrementowany dla każdego wywoałnia.
}

int main() {
    MyClass myClass2; // Obiekt automatyczny inicjowany w funkcji main()
    {
        MyClass myClass3; // Obiekt automatyczny inicjowany po wejściu do zakresu (klamer)
                          // i niszczony po wyjściu z klamer.
    }
    std::cout << foo() << '\n'; // Zwraca 10...
    std::cout << foo() << '\n'; // Zwraca 11 a wartość licznika value w foo() to 12.

    MyClass * myClassPtr; // Wkaźnik na obiekt z MyClass
    {
        myClassPtr = new MyClass(); // Przypisanie do wskaźnika pamięci ze sterty
        // Po wyjściu z tych klamer, nie nastąpi dealokacja z myClassPtr bo dane są na
        // stercie... 
        
        // Uwaga: Błąd, wyciek pamięci...
        int * data = new int[20]; // Po wyjściu z tych klamer... tracisz wskaźnik i masz wyciek pamięci.
    }
    std::cout << myClassPtr->getValues(3) << '\n';

    // Sprzątamy myClassPtr
    delete myClassPtr;
}
// Wynik:
// 10
// 11
// 0

Oczywiście to co napisałem to uproszczenie ale wystarczające byś zrozumiał :-)

Podobne pytania

0 głosów
1 odpowiedź 1,800 wizyt
0 głosów
2 odpowiedzi 500 wizyt
pytanie zadane 4 października 2018 w C i C++ przez uther1455 Nowicjusz (140 p.)

92,453 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...