This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
dydaktyka:cprog:2016:dynamic_memory_allocation [2017/01/16 06:36] pkleczek [Zmiana rozmiaru bloku pamięci – funkcja realloc] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Dynamiczna alokacja pamięci ====== | ||
- | |||
- | W języku C można wyróżnić dwie podstawowe metody alokacji (przydzielania) pamięci: | ||
- | * **alokacja statyczna** -- ilość pamięci zostaje z góry określona na etapie pisania programu (poprzez odpowiednie deklaracje zmiennych); pamięć jest zwalniana automatycznie -- po zakończeniu bloku programu, w którym była deklarowana (chyba, że obiekt został zadeklarowany jako ''static''), lub po zakończeniu programu | ||
- | <code c> | ||
- | int a; | ||
- | char str[] = "Hello!"; | ||
- | float tab[5];</code> | ||
- | * **alokacja dynamiczna** -- program przydziela dowolne ilości pamięci w trakcie pracy, poprzez wywołanie odpowiednich funkcji; pamięć musi być jawnie zwolniona (z użyciem odpowiedniej funkcji) | ||
- | <code c> | ||
- | int* tab; | ||
- | tab = malloc(5 * sizeof(*tab)); | ||
- | free(tab);</code> | ||
- | |||
- | Dynamiczna alokacja pamięci pozwala przede wszystkim na: | ||
- | * utworzenie tablicy o rozmiarze obliczanym dopiero podczas działania programu | ||
- | * dostęp do zmiennych utworzonych wewnątrz funkcji po wyjściu z nich | ||
- | |||
- | ===== Przydzielanie pamięci – funkcja "malloc" ===== | ||
- | |||
- | Funkcja [[http://www.cplusplus.com/reference/cstdlib/malloc/?kw=malloc|malloc()]] (od //memory allocation//) rezerwuje blok wolnej pamięci o zadanym rozmiarze (w bajtach) i zwraca adres jego pierwszego bajtu. W przypadku nieznalezienia wymaganego obszaru ''malloc()'' zwraca wskaźnik zerowy (dla przypomnienia -- wskaźnik o wartości ''0''). | ||
- | |||
- | Ponieważ rezerwowany blok może być zmienną dowolnego typu, funkcja ta zwraca uniwersalny "wskaźnik na ''void''". Przypisanie takiego wskaźnika do wskaźnika dowolnego innego typu jest operacją dozwoloną przez standard języka. | ||
- | |||
- | Aby utworzyć tablicę typu ''double'' o zadanym rozmiarze z użyciem funkcji ''malloc()'' można napisać następujący kod: | ||
- | <code c> | ||
- | int rozmiar = 10; | ||
- | double* tab; | ||
- | tab = malloc(rozmiar * sizeof(*tab)); | ||
- | </code> | ||
- | |||
- | Powyższy kod zarezerwuje obszar pamięci dla 10 wartości typu wskazywanego przez ''tab'' (czyli ''double'') i przypisze adres wskaźnikowi ''tab''. Zauważ, że zmienna ''tab'' została zadeklarowana jako wskaźnik do pojedynczej wartości ''double'', a nie do bloku 10 takich wartości. Dlaczego? Ponieważ nazwa tablicy jest zarazem adresem jej pierwszego elementu, powyższe przypisanie umożliwia korzystanie z ''tab'' jak ze zwykłej nazwy tablicy (np. ''tab[0]'' to wartość jej pierwszego elementu). | ||
- | |||
- | ===== Korzystanie z tablic dynamicznych ===== | ||
- | |||
- | Z tablic utworzonych w sposób dynamiczny korzysta się identycznie jak z tablic utworzonych statycznie: | ||
- | <code c> | ||
- | int rozmiar = 10; | ||
- | double* tab = malloc(rozmiar * sizeof(*tab)); | ||
- | tab[3] = 4; | ||
- | printf("%d\n", tab[3]); | ||
- | </code> | ||
- | |||
- | |||
- | ===== Zwalnianie pamięci – funkcja "free" ===== | ||
- | |||
- | Funkcja [[http://www.cplusplus.com/reference/cstdlib/free/?kw=free|free()]] zwalnia dynamicznie przydzieloną pamięć (i tylko taką -- próba zwalniania pamięci przydzielonej statycznie to błąd). Argumentem funkcji ''free()'' jest adres obszaru pamięci do zwolnienia. | ||
- | |||
- | Na przykład: | ||
- | <code c> | ||
- | double* tab; | ||
- | tab = malloc(8 * sizeof(*tab)); | ||
- | free(tab); | ||
- | </code> | ||
- | |||
- | :!: System operacyjny wyznacz limit pamięci, jaki może wykorzystać dany program -- jego przekroczenie powoduje "ubicie" programu. Zapominając zwolnić przydzieloną pamięć można łatwo doprowadzić do //[[https://pl.wikipedia.org/wiki/Wyciek_pami%C4%99ci|wycieku pamięci]]// i w konsekwencji właśnie do przedwczesnego zakończenia programu... | ||
- | |||
- | ===== Zmiana rozmiaru bloku pamięci – funkcja "realloc" ===== | ||
- | |||
- | Funkcja [[http://www.cplusplus.com/reference/cstdlib/realloc/|realloc()]] służy do zmiany rozmiaru zaalokowanego dynamicznie bloku pamięci. Jej pierwszym argumentem jest adres bloku pamięci, a drugim -- nowy rozmiar (w bajtach). | ||
- | |||
- | Do zwalniania pamięci przydzielonej przez ''realloc()'' służy również funkcja ''free()''. | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | double* tab; | ||
- | int rozmiar_1 = 10; | ||
- | int rozmiar_2 = 20; | ||
- | |||
- | tab = malloc(rozmiar_1 * sizeof(*tab)); // pierwotnie `tab` ma rozmiar 10 bajtow | ||
- | tab = realloc(tab, rozmiar_2 * sizeof(*tab)); // teraz `tab` ma rozmiar 20 bajtow | ||
- | free(tab); | ||
- | </code> | ||
- | |||
- | ===== Alokacja pamięci dla tablicy dwuwymiarowej ===== | ||
- | |||
- | Aby utworzyć dynamiczną tablicę dwuwymiarową, najpierw alokujemy pamięć dla "wierszy", a następnie dla "kolumn". Podczas zwalniania pamięci postępujemy na odwrót -- najpierw zwalniamy pamięć przydzieloną dla "kolumn", a potem dla "wierszy". | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | #include <stdio.h> | ||
- | #include <stdlib.h> | ||
- | |||
- | int main () | ||
- | { | ||
- | int w = 6; //liczba wierszy | ||
- | int k = 3; // liczba kolumn | ||
- | double **tab2d; | ||
- | int i; | ||
- | |||
- | tab2d = malloc(w * sizeof(double*)); // alokacja pamięci "wierszy" | ||
- | |||
- | for(i = 0; i < w; i++) { | ||
- | tab2d[i] = malloc(k * sizeof(double)); // alokacja pamięci "kolumn" | ||
- | } | ||
- | |||
- | for(i = 0; i < w; i++) { | ||
- | free(tab2d[i]); // zwolnienie pamieci kolumn" | ||
- | } | ||
- | |||
- | free(tab2d); //uwolnienie pamieci "wierszy" | ||
- | tab2d = NULL; | ||
- | |||
- | return 0; | ||
- | } | ||
- | </code> | ||
- | |||
- | ===== Zadania podsumowujące ===== | ||
- | |||
- | W poniższych ćwiczeniach każdorazowo zadbaj o poprawne zwolnienie przydzielonej dynamicznie pamięci! | ||
- | ==== Zadanie DAL1D ==== | ||
- | |||
- | ([size=10]poziom trudności:[/size] {{stars>1/4}}) | ||
- | |||
- | Napisz program który alokuje dynamicznie jednowymiarową tablicę (wybranego typu), wypełnia ją losowymi liczbami, a następnie wypisuje jej elementy na ekran. | ||
- | |||
- | ==== Zadanie DAL1DCHG ==== | ||
- | |||
- | ([size=10]poziom trudności:[/size] {{stars>1/4}}) | ||
- | |||
- | Zmodyfikuj program z [[dydaktyka:cprog:2015:dynamic_memory_allocation#zadanie_dal1d|zadania DAL1D]] tak, aby po utworzeniu tablicy i zainicjalizowaniu jej elementów program powiększył jej rozmiar dwukrotnie (nowe elementy wypełniając zerami) i ponownie wypisał jej elementy na ekran. | ||
- | |||
- | /* | ||
- | ==== Fotoszop ==== | ||
- | |||
- | ([size=10]poziom trudności:[/size] {{stars>1/4}}) | ||
- | |||
- | Wykonaj zadania w ramach polecenia [[dydaktyka:cprog:2015:photoshop:exercises:dynamic_image_allocation|Dynamiczna alokacja tablicy-obrazu]]. | ||
- | */ | ||
- | |||
- | ==== Zadanie DAL2D ==== | ||
- | |||
- | ([size=10]poziom trudności:[/size] {{stars>2/4}}) | ||
- | |||
- | Napisz program który alokuje dynamicznie tablicę przechowującą w wierszach następujące wyrazy: | ||
- | <code> | ||
- | Oto | ||
- | tablica | ||
- | dynamiczna. | ||
- | </code> | ||