W08 dynamiczna alokacja pamieci, PWR - Informatyka W4, podstawy programowania
[ Pobierz całość w formacie PDF ]
DYNAMICZNE PRZYDZIELANIE PAMIECI Pamięć komputera, dostępna dla programu, dzieli się na cztery obszary: · kod programu , · dane statyczne ( np. stałe i zmienne globalne programu), · dane automatyczne ® zmienne tworzone i usuwane automatycznie przez kompilator na tzw. stosie ( ang. stack ) np. zmienne lokalne wewnątrz funkcji void przykladowa_funkcja(void) { float zmienna_lokalna; zmienna_lokalna=10; } · dane dynamiczne ® organizowane przez menadŜera-zarządcę pamięci dynamicznej, moŜna je tworzyć i usuwać w dowolnym momencie pracy programu, w pamięci wolnej komputera ® na tzw. stercie ( ang. heap ) Zmienne dynamiczne: ® odpowiedzialnym za ich utworzenie (rezerwację pamięci) oraz za ich usunięcie (zwolnienie pamięci) jest programista !!! ® dostęp do takiej zmiennej moŜliwy jest jedynie poprzez jej adres w pamięci (przechowywany w zmiennej wskaźnikowej) ® korzystanie z nieprzydzielonego obszaru najprawdopodobniej spowoduje błąd! ® próba zwolnienia juŜ zwolnionego obszaru spowoduje błąd! Przykład ® ilustracja czasu „Ŝycia” zmiennych zmienna statyczna « komputer na własność (cały czas) zmienna lokalna « komputer w laboratorium (tylko na czas zajęć) zmienna dynamiczna « komputer z wypoŜyczalni (na dowolny czas) Dostęp do obiektu za pomocą wska ź nika-adresu-odsyłacza WSKA Ź NIK ® OBIEKT numer telefonu ® telefon adres internetowy ® strona HTML na serwerze adres pocztowy ® mieszkanie numer PESEL ® Kowalski Jan numer pokoju ® wynajęty apartament w hotelu numerek z szatni ® dynamicznie przydzielone miejsce-wieszak w szatni M. Piasecki, JĘZYKI PROGRAMOWANIA (1) - 1 - Dynamiczne przydzielanie pamięci W języku „ C ” do dynamicznego przydzielania pamięci (tworzenia zmiennych dynamicznych) słuŜyły specjalne funkcje z bibliotek: <alloc.h> lub <stdlib.h> void * malloc( size_t rozmiar ); // przydział bloku o zadanej wielkosci void * calloc( size_t il_elementow, size_t rozmiar); // przydział tablicy void * realloc( void * stary_wskaznik, size_t nowy_rozmiar); // zmiana wielko ś ci void free( void * wskaznik); // zwolnienie wskazywanego obszaru np. void main( void ) { int * wsk; // zmienna wska ź nikowa do zapami ę tania adresu liczby int · · · wsk = ( int * ) malloc( sizeof( int ) ); // przydzielenie pami ę ci na liczb ę int if ( wsk == NULL ) { printf( ” Bł ą d przydziału pami ę ci ” ); return ; · · · * wsk = 10; // przykładowe operacje na dynamicznej liczbie int * wsk * = 2; printf( ”%d”, * wsk ); scanf( ”%d”, wsk ); · · · free( wsk ); // zwolnienie pami ę ci przed zako ń czeniem programu } Przykład operacji na dynamicznej tablicy o dowolnej ilo ś ci elementów: np. void main( void ) { int rozmiar_tablicy; double * tablica_liczb; printf( ” Ile liczb chcesz wprowadzi ć : ” ); scanf( ”%d”, &rozmiar_tablicy ); if ( tablica_liczb = ( double * ) calloc( rozmiar_tablicy, sizeof(double) ) ) { for( int i = 0; i < rozmiar_tablicy, i++ ); * ( tablica_liczb+i ) = 100; // tablica_liczb[ i ] = 100; · · · free( tablica_liczb ); } } M. Piasecki, JĘZYKI PROGRAMOWANIA (1) - 2 - Dynamiczne przydzielanie pamięci ” do dynamicznego przydzielania pamięci moŜna nadal wykorzystywać funkcje z biblioteki <alloc.h> ale duŜo lepiej jest korzystać z nowych operatorów: new oraz delete ++ <wskaźnik_na_obiekt> = new <typ_obiektu> [ parametry_inicjalizacyjne ] ; delete <wskaźnik_na_obiekt> ; np. int * wsk ; // wska ź nik na zmienn ą typu całkowitego wsk = new int ; // utworzenie nowego obiektu (nowej zmiennej int ) if ( wsk != NULL ) { * wsk = 10 ; // przypisanie warto ś ci (poprzez wska ź nik) printf( ”%d” , * wsk ); // wydrukowanie zawarto ś ci zmiennej dynam. · · · delete wsk ; // usuni ę cie zmiennej dynam. (zwolnienie pami ę ci) } Porównanie utworzenia zwykłej tablicy i tablicy dynamicznej: // operacja utworzenia zwykłej tablicy const ROZMIAR_TABLICY = 100; double zwykła_tablica[ ROZMIAR_TABLICY ]; // operacja utworzenia i zwolnienia tablicy dynamicznej int rozmiar_tablicy; cout << ” Ile liczb chcesz wprowadzi ć : ” ; cin >> rozmiar_tablicy ; double * tablica_dynamiczna; tablica_dynamiczna = new double [ rozmiar_tablicy ]; · · · for( int i=0; i<rozmiar_tablicy; i++) tablica_dynamiczna[ i ] = 10.5; · · · for( int i=0; i<rozmiar_tablicy; i++) cout<<endl<<” tablica[ ” << i+1 << ” ]= ” << tablica_dynamiczna[ i ]; · · · delete [ ] tablica_dynamiczna; M. Piasecki, JĘZYKI PROGRAMOWANIA (1) - 3 - Dynamiczne przydzielanie pamięci W języku „ C Przykład 1 - pojedyncza realokacja (zmiana rozmiaru) tablicy jednowymiarowej void main( ) { // utworzenie 10-cio elementowej tablicy zawieraj ą cej liczby z przedziału -50 ¸ 50 int rozmiar=10; long * tablica = new long [ rozmiar ]; for ( int i=0; i< rozmiar; i++) tablica[ i ] = random(101)-50; cout<<endl<<" Zawartosc tablicy po wylosowaniu elementów: "<<endl; for ( int i=0; i<rozmiar ; i++) cout << endl <<" tab[ " << i << " ]= " << tablica[ i ]; cout<<endl<<" Rozmiar tablicy: "<<rozmiar<<endl; // policzenie ile z wylosowanych liczb ma dodatni ą warto ść int ilosc_dodatnich=0; for ( int i=0; i<rozmiar; i++) if ( tablica[i]>0 ) ilosc_dodatnich++; // usuni ę cie wszystkich liczb ujemnych ® z jednoczesnym zmniejszeniem tablicy long * nowa_tablica = new long [ilosc_dodatnich]; if ( nowa_tablica==NULL ) cout<<" UWAGA - blad tworzenia nowej tablicy "; else { int j=0; for ( int i=0;i<rozmiar;i++) if ( tablica[i]>0 ) { nowa_tablica[ j ]=tablica[ i ]; j++; } delete [ ] tablica; tablica=nowa_tablica; rozmiar=ilosc_dodatnich; } cout<<endl<<" Zawartosc tablicy po usunieciu liczb ujemnych: "<<endl; for ( int i=0; i<rozmiar ; i++) cout << endl <<" tab[ " << i << " ]= " << tablica[ i ]; cout<<endl<<" Rozmiar tablicy: "<<rozmiar<<endl; cin.get(); delete [ ] tablica; } M. Piasecki, JĘZYKI PROGRAMOWANIA (1) - 4 - Dynamiczne przydzielanie pamięci Przykład (2) – inna wersja programu przykład (1) ® z wykorzystaniem funkcji bool USUN_UJEMNE( long * &wsk_tablicy, int &rozmiar_tablicy) { int ilosc_dodatnich=0; for ( int i=0; i<rozmiar_tablicy; i++) if ( wsk_tablicy[i]>0 ) ilosc_dodatnich++; long * nowa_tablica = new long [ilosc_dodatnich]; if ( nowa_tablica==NULL ) return false ; int j=0; for ( int i=0; i<rozmiar_tablicy; i++) if ( wsk_tablicy[i]>0 ) { nowa_tablica[ j ]=wsk_tablicy[ i ]; j++; } delete [ ] wsk_tablicy; wsk_tablicy=nowa_tablica; rozmiar_tablicy=ilosc_dodatnich; return true ; } long * LOSUJ_UJEMNE_i_DODATNIE( int ilosc_liczb) void WYSWIETL( long * tablica, int rozmiar_tablicy); bool USUN_UJEMNE( long * &wsk_tablicy, int &rozmiar_tablicy); void main( ) { int n=10; long *tablica = LOSUJ_UJEMNE_i_DODATNIE (n); WYSWIETL( tablica,n); cin.get(); if ( USUN_UJEMNE(tablica,n)== false ) cout<<" UWAGA - blad operacji usuwania ujemnych "; cout<<endl<<endl<<" Po wywolaniu funkcji USUN_UJEMNE: "<<endl; WYSWIETL( tablica,n); cin.get(); delete [ ] tablica; } M. Piasecki, JĘZYKI PROGRAMOWANIA (1) - 5 - Dynamiczne przydzielanie pamięci [ Pobierz całość w formacie PDF ] |