Struktury czyli rekordy w C/C++ Wprowadzenie do programowania w języku C struktury. pola bitowe, unie Struktury (rekordy) są złożonymi zmiennymi, składającymi się z elementów różnych typów zwanych polami, taką grupę pól można traktować jako jeden obiekt a nie zestaw obiektów oddzielnych. struct MOUSE_EVENT int x, y; /* Pozycja kursora myszki na ekranie */ unsigned char buttons; /* Informacja o stanie przycisku */ int double_click; /* Czy podwójne kliknięcie? */ ; struct WINDOW_INFO int x, y; /* Pozycja lewego górnego narożnika okna */ int w, h; /* w szerokość okna, h wysokość okna */ int frame_type; /* Typ wzorca ramki */ char * title; /* Wskaźnik do obszaru tytułu okna */ ; Odwoływanie się do pól struktur hipotetyczna funkcja obsługi void process_mouse_event( struct MOUSE_EVENT me ) if( me.buttons & M_LEFT_BUTTON_PRESSED ) if( me.double_click ) find_object_on_pos( me.x, me.y ); Odwoływanie się do pól struktur, wskaźniki hipotetyczna funkcja obsługi void process_mouse_event( struct MOUSE_EVENT * me ) if( me->buttons & M_LEFT_BUTTON_PRESSED ) /* zamiast (*me).buttons */ if( me->double_click ) find_object_on_pos( me->x, me->y ); Struktury mogą być zagnieżdżane struct EVENT int event_kind; /* Kod rodzaju zdarzenia */ struct MOUSE_EVENT mouse_ev; /* Rekord opisu zdarzenia dot. myszki */ struct KEYBD_EVENT keybd_ev; /* Rekord opisu zdarzenia dot. klawiatury */ ; struct EVENT ev; if( ev.kind == FROM_MOUSE ) if( ev.mouse_ev.duble_click ) find_object_on_pos( ev.mouse_ev.x, ev.mouse_ev.y );
Wprowadzenie do programowania w języku C struktury. pola bitowe, unie Deklarowanie struktur, specyfikacja typedef Alternatywne sposoby deklaracji zmiennych strukturalnych struct POINT struct POINT int x, y; int x, y; p1, p2, p3; ; struct POINT p1, p2, p3; POINT to etykieta struktury, w języku C nie jest to nazwa typu (w C++ tak). Deklaracja struktury może nie zawierać etykiety, lecz to mało użyteczna rzecz. struct int x, y, radius; c1, c2, c3; Aby skrócić zapis można używać deklaracji typedef: typedef struct int x, y, radius CIRCLE; typedef struct MOUSE_EVENT MOUSE_EVENT_STRUCT; CIRCLE c1, c2, c3; MOUSE_EVENT_STRUCT ev, * ev_ptr = NULL; Aby uniknąć zastanawiania się nad nazwami: struct _POINT_3D int x, y, z; ; typedef struct _POINT_3D POINT_3D; Składowa struktury (pole) nie może być tego samego typu co właśnie deklarowana struktura ale może być wskaźnikiem: struct A ( struct A a ); /* Błąd */ struct A ( struct A * a ); /* OK */ Ogólnie, w przypadku wskaźników można użyć niekompletnej deklaracji: struct A; /* Niekompletna deklaracja */ struct B struct A * pa; ; Pola bitowe struct EVENT_TYPE unsigned char from_mouse : 1; unsigned char from_keybd : 1; unsigned char from_timer : 1; event_source; event_source.from_mouse = 1; event_source.from_keybd = event_source.from_timer = 0; if( event_source.from_mouse )
Wprowadzenie do programowania w języku C struktury. pola bitowe, unie Pola bitowe zachowują się jak małe zmienne całkowite. Mogą być deklarowane tylko w strukturach, uniach i klasach (C++). Nie wolno pobierać adresu pola bitowego: &event_source.from_mouse jest niedozwolone. Ogólnie, deklaracja pola bitowego przyjmuje postać: specyfikator-typu <identyfikator-pola-bitowego> : szerokość-pola gdzie specyfikator-typu to char, unsigned char, int lub unsigned int. Specyfikacja szerokość-pola musi wystapić, nie może ona przekraczać rozmiaru typu określonego przez specyfikator-typu. struct BIT_FIELDS int i : 2; unsigned int j : 2; int : 3; int k : 1; a; a.i = 3 a.i == -1 ( bin: 11 ) a.i = 6 a.i == -2 ( bin: 10 ) a.k = 0 a.k == 0 ( bin: 0 ) a.k = 1 a.k == -1 ( bin: 1 ) 7 6 5 4 3 2 1 0 1 0 0 0 0 0 1 1 k nieu ywane j i Pola bitowe są rozwiązaniem mocno zależnym od implementacji. Zatem mogą one zachowywać się inaczej po zmianie środowiska systemowego lub nawet tylko kompilatora. Ograniczają one przenośność kodu źr dłowego. Unie Unia jest zmienna, która w różnych momentach może zawierać obiekty różnych typów i rozmiarów. W damym momencie tylko jeden obiekt jest aktywny. Wszystkie składowe unii są pamiętane w tym samym miejscu pamięci, rozmiar unii jest równy rozmiarowi największej składowej. union EVENT_INFO struct MOUSE_EVENT mouse_ev; /* Rekord opisu zdarzenia dot. myszki */ struct KEYBD_EVENT keybd_ev; /* Rekord opisu zdarzenia dot. klawiatury */ struct TIMER_EVENT timer_ev; /* Rekord opisu zdarzenia dot. klawiatury */ ; struct EVENT unsigned char from_mouse : 1; /* 1 gdy zdarzenie pochodzi od myszki */ unsigned char from_keybd : 1; /* 1 gdy zdarzenie pochodzi od klawiat. */ unsigned char from_timer : 1; /* 1 gdy zdarzenie pochodzi od timera */ union EVENT_INFO ei; /* Unia zdarzeń -- 3 in 1 */ event; get_event_info( &event ); if( event.from_mouse ) if( event.ei.mouse_ev.double_click ) find_object_on_pos( event.ei.mouse_ev.x, event.ei.mouse_ev.y );
Dynamiczny przydział pamięci void * malloc( size_t size ); Wprowadzenie do programowania w języku C dynamiczne struktury danych Rezultatem funkcji malloc jest wskaźnik do obszaru pamięci przeznaczonego dla obiektu o rozmiarze size. Rezultatem jest NULL jeżeli polecenie nie może być zrealizowane. Obszar nie jest inicjowany. void * calloc( size_t nitems, size_t size ); Rezultatem funkcji calloc jest wskaźnik do obszaru pamięci przeznaczonego dla nitems obiektów o rozmiarze size. Rezultatem jest NULL jeżeli polecenie nie może być zrealizowane. Obszar jest inicjowany zerami. void * realloc( void * ptr, size_t size ); Funkcja dokonuje próby zmiany rozmiaru bloku wskazywanego przez ptr, który był poprzednio przydzielony wywołaniem funkcji calloc lub malloc. Zawartość wskazywanego obszaru pozostaje niezmieniona. Jeżeli nowy rozmiar jest większy od poprzednio przydzielonego, dodatkowe bajty mają nieokreśloną wartość. Jeżeli nowy rozmiar jest mniejszy, bajty z różnicowego obszaru są zwalniane. Jeżeli ptr == NULL to funkcja działa jak malloc. Rezultatem funkcji jest wskaźnik na obszar pamięci o nowym rozmiarze (może być ulokowany w pamięci w innej lokalizacji niż poprzednio). Rezultatem jest NULL w przypadku błędu lub próby przydziału bloku o zerowym rozmiarze. void free( void * ptr ); Zwalnia obszar pamięci wskazywany przez ptr. Parametr musi być wskaźnikiem do obszaru pamięci przydzielonego uprzednio przez malloc, calloc lub realloc. int n = 300; char * s; if( ( s = ( char * )malloc( n * sizeof( char ) ) )!= NULL ) strcpy( s, "Dynamicznie przydzielony napis" ); for( i = 0; s[ i ]!= \0 ; i++ ) putchar( s[ i ] ); free( s ) Alternatywne konstrukcje lecz calloc zeruje pamięć a malloc nie s = (char *)malloc(n*sizeof(char)) s = (char *)calloc(n,sizeof(char)) int queue_len = 32; struct EVENT * queue; if( (queue=(struct EVENT *)calloc(queue_len,sizeof(struct EVENT)))!= NULL ) set_application_queue( queue ); free( queue );
Wprowadzenie do programowania w języku C dynamiczne struktury danych Rekurencyjne struktury danych Jednokierunkowa lista inwersyjna. Program przykładowy wczytuje linie tekstu z stdin, magazynuje je w liście, następnie wyświetla w odwrotnej kolejności. Wprowadzanie kończy naciśnięcie znaku odpowiadającego znacznikowi końca pliku (^Z Dos/Windows, ^D Unix). #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_LEN 128 struct _NAME char name[ MAX_LEN ]; /* Pole do przechowywania napisu */ struct _NAME * prev; /* Odsyłacz do poprzedniego elementu listy */ ; typedef struct _NAME NAME; int main() NAME * = NULL; /* Wskaźnik na koniec tworzonej listy */ NAME * = NULL; /* Wskaźnik pomocniczy */ char buffer[ MAX_LEN ]; /* Bufor odczytywanej linii */ /* Czytaj linie dopóki nie wprowadzono znaku konca pliku (^Z lub ^D) */ while( gets( buffer )!= NULL ) if( ( = ( NAME * )malloc( sizeof( NAME ) ) )!= NULL ) strcpy( ->name, buffer ); /* Zapamiętaj linię w el-cie listy */ ->prev = ; /* Dołącz element do listy */ = ; /* Teraz nowy element jest ostatni */ /* Wykorzystanie napisów zgromadzonych w liście */ for( = ;!= NULL; = ->prev ) printf( "\n%s", ->name ); /* Zwolnienie pamięci przydzielonej elementom listy*/ while(!= NULL ) = ; = ->prev; free( ); return 0;
WskaŸniki przed rozpoczêciem tworzenia listy Wprowadzenie do programowania w języku C dynamiczne struktury danych NAME * = NULL; NAME * = NULL; = ( NAME * )malloc( sizeof( NAME ) ) Przydzia³ pamiêci dla nowego elementu ->prev = ; Ustalenie odsy³acza do poprzedniego elementu = ; Do³¹czenie elementu do listy = ( NAME * )malloc( sizeof( NAME ) ); Przydzia³ pamiêci dla kolejnego elementu ->prev = ; Ustalenie odsy³acza do poprzedniego elementu = ; Do³¹czenie elementu do listy
Wprowadzenie do programowania w języku C dynamiczne struktury danych Lista dwukierunkowa program przykładowy, temat jak poprzednio #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_LEN 80 typedef struct _NAME char name[ MAX_LEN ]; /* Pole do przechowywania napisu */ struct _NAME * next; /* Odsyłacz do następnego elementu listy */ struct _NAME * prev; /* Odsyłacz do poprzedniego elementu listy */ NAME; int main() NAME * = NULL, * = NULL; /* Początek i koniec listy */ NAME * ; char buffer[ MAX_LEN ]; while( gets( buffer )!= NULL ) if( ( = ( NAME * )malloc( sizeof( name ) ) )!= NULL ) strcpy( ->name, buffer ); if( == NULL ) /* Czy lista jest pusta? */ ->next = ->prev = NULL; /* Nie ma poprz. i następnego */ = = ; /* Początek == koniec */ else ->next = NULL; /* Nie ma nastepnego to ostatni element */ ->prev = ; /* Ostatni elem. staje się poprz. dla nowego */ ->next = ; /* Nowy element staje się następnym dla ostat.*/ = ; /* Teraz nowy element staje się ostatnim */ /* if-else */ /* if */ /* while */ /* Maszerujemy po liście od początku do końca */ for( = ;!= NULL; = ->next ) printf( "\n%s", ->name ); /* Maszerujemy po liście od końca do początku*/ for( = ;!= NULL; = ->prev ) printf( "\n%s", ->name ); /* Zwolnienie pamięci przydzielonej elementom listy*/ while(!= NULL ) /* Zwolnienie pamięci */ = ; = ->next; free( ); return 0;
Wprowadzenie do programowania w języku C dynamiczne struktury danych WskaŸniki przed rozpoczêciem tworzenia listy NAME * = NULL; NAME * = NULL; NAME * = NULL; = ( NAME * )malloc( sizeof( NAME ) ) Przydzia³ pamiêci dla nowego elementu ->next = ->prev = NULL; Ustalenie odsy³acza do nastêpnego/poprzedniego elementu = = ; Do³¹czenie elementu do listy = ( NAME * )malloc( sizeof( NAME ) ); Przydzia³ pamiêci dla kolejnego elementu = ; ->next = ; Do³¹czenie elementu do listy ->next = NULL; ->prev = ;