Podstawy informatyki Struktury Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka
Struktura Struktura jest agregatem (różnych) typów danych. Składa się z kilku związanych zmiennych, zwanych składowymi albo polami. W przeciwieństwie do tablic, gdzie wszystkie elementy są jednego typu, każda składowa struktury może mieć inny typ. Informacje zawarte w strukturze powinny być ze sobą logicznie powiązane. Wszystkie składniki struktury są przez domniemanie publiczne (dostępne z zewnątrz).
Struktura vs klasa struct nowy_typ { … }; class nowy_typ { … }; class nowy_typ { public: … }; struct nowy_typ { private: … };
Definicja struktury Definicja struktury: struct nazwa_typu { typ1 skladnik1; typ2 skladnik2;... } lista_zmiennych; nazwa_typu jest nowym typem, który może być używany tak, jak inne nazwy typów. lista_zmiennych jest listą rzeczywistych obiektów nowego typu. Jeden z powyższych elementów może być pominięty.
Przykłady struct osoba{ string imie; string nazwisko; int wiek; }; osoba JA,TY,ON,ONA; struct{ string imie; string nazwisko; int wiek; } JA,TY,ON,ONA; Składowe struktury są przechowywane w pamięci w dokładnie tej samej kolejności, w jakiej są zadeklarowane.
Wielkość struktury cout << sizeof(JA) << endl; cout << sizeof(osoba) << endl; 60 imie 28Bnazwisko 28Bwiek 4B
Odwoływanie się do składników Aby odwołać się do składowej obiektu danego typu strukturalnego, należy określić zarówno nazwę tego obiektu oraz nazwę składowej, rozdzielając je operatorem. obiekt_strukturalny.składnik POST () [] PRE + - ! ~ * & 15 14* / % > 11 >= 10== != 9& 8^ 7| 6&& 5|| 4? : 3= *= /= %= += -= >= &= |= ^= 2 1,
Struktury Jak każdy inny typ może być przekazywana jako parametr do funkcji. Obiekt typu strukturalnego może być zwracany przez funkcję – sposób na zwrócenie kilku obiektów! Nazwy składowych struktury nie powodują konfliktów z innymi zmiennymi lub składowymi innych struktur o tej samej nazwie. Nazwa składowej struktury jest związana z nazwą struktury. Struktury można zagnieżdżać.
Funkcja przyjmująca obiekt strukturalny #include using namespace std; struct licz_zes { double re,im; }; double modul(licz_zes A) { return sqrt(pow(A.re,2)+pow(A.im,2)); } int main() { licz_zes A; A.re=1; A.im=1; cout<<modul(A)<<endl; return 0; }
Funkcja zwracająca obiekt strukturalny #include using namespace std; struct licz_zes { double re,im; }; licz_zes przeciwna(licz_zes A) { A.re=-A.re; A.im=-A.im; return A; } int main() { licz_zes A,B; A.re=1; A.im=1; B=przeciwna(A); cout<<B.re<<endl<<B.im<<endl; cout<<B<<endl; return 0; } BŁĄD
Struktura zawierająca tablicę #include using namespace std; struct tablica { int tab[3]; }; tablica przeciwne(tablica t) { for (int i=0; i<3; i++) t.tab[i]=-t.tab[i]; return t; } int main() { tablica T,T1; for (int i=0; i<3; i++) T.tab[i]=i; for (int i=0; i<3; i++) cout<<T.tab[i]<<endl; T1=przeciwne(T); for (int i=0; i<3; i++) cout<<T1.tab[i]<<endl; for (int i=0; i<3; i++) cout<<T.tab[i]<<endl; return 0; }
Struktura zawierająca tablicę #include using namespace std; struct tablica { int tab[3]; }; tablica przeciwne(tablica &t) { for (int i=0; i<3; i++) t.tab[i]=-t.tab[i]; return t; } int main() { tablica T,T1; for (int i=0; i<3; i++) T.tab[i]=i; for (int i=0; i<3; i++) cout<<T.tab[i]<<endl; T1=przeciwne(T); for (int i=0; i<3; i++) cout<<T1.tab[i]<<endl; for (int i=0; i<3; i++) cout<<T.tab[i]<<endl; return 0; }
Wskaźniki do struktur Wskaźnik do struktury definiuje się w sposób analogiczny do wskaźników do innych typów: osoba JA,*WSK; WSK=&JA; Można teraz sięgnąć do wnętrza obiektu JA za pomocą wskaźnika WSK: używamy do tego operatora -> cout imie<<endl; POST () []. -> PRE + - ! ~ * & 15 14* / % > 11 >= 10== != 9& 8^ 7| 6&& 5|| 4? : 3= *= /= %= += -= >= &= |= ^= 2 1,
Wskaźniki do struktur Operator strzałkowy składa się ze znaku minus oraz znaku większy; między znakami nie może być spacji. obiekt_strukturalny.składnik wskaźnik_do_obiektu_strukturalnego->składnik Struktury są przekazywane do funkcji w całości (jeżeli są przekazywane przez wartość). W przypadku dużych struktur (np. zawierających tablice) lepiej jest przekazywać taki obiekt przez wskaźnik lub referencję.
Pola bitowe Jest to pewien szczególny rodzaj struktury, której składowymi są pola składające się z określonej liczby bitów. Definiujemy je, określając za nazwą pola liczby bitów, które to pole zajmuje. Dozwolone są pola bez nazwy. Pole musi być typu całkowitego i używa się je, jak każdy obiekt typu całkowitego z tym wyjątkiem, że nie można pobrać adresu tego pola.
Definicja pola bitowego struct dane { unsigned short int a:4, b:8, c:4; } odczyt; odczyt.a=0x0; odczyt.b=0xf0; odczyt.c=0xf; cout<<hex<<odczyt.a<<odczyt.b<<odczyt.c<<endl; cout<<odczyt<<endl; 0f0f BŁĄD cb ba ab bc
Unia Unia jest pojedynczym obszarem pamięci, dzielonym przez kilka zmiennych. Zmienne te mogą być różnych typów. W danej chwili może być przechowywana tylko jedna zmienna.
Definicja unii Definicja unii: union liczba { unsigned short int usi; unsigned int ui; }; Podczas przydzielania pamięci wszystkie pola otrzymują ten sam adres. Unia ta ma rozmiar równy rozmiarowi największego pola. Rozmiar ten jest ustalany w momencie kompilacji. Do pola unii odnosimy się używając operatorów. i -> Zawartość unii jest interpretowana przez użycie nazwy jednej ze składowych unii. ui usi
Używanie unii Unii zazwyczaj używamy w ten sposób, że zapisujemy wartość korzystając z jednego z pól, a odczytujemy używając tego samego pola. Unię można czasem używać do „konwersji typów”, ale wymaga to bardzo dużej znajomości danej maszyny i środowiska programistycznego. Można także używać unii do „zaszyfrowywania” danych. Inicjalizacja unii: unię inicjalizuje się tylko daną odpowiadającą typowi pierwszego składnika tej unii.
Przykład 1 union liczba { unsigned short int usi; unsigned int ui; } licz; licz.ui=0xffffffff; cout << hex << licz.ui << endl; cout << hex << licz.usi << endl; licz.usi=0x0000; cout << hex << licz.ui << endl; cout << hex << licz.usi << endl; ffffffff ffff ffff ff ff ff ff 00 00
Unia anonimowa Unią anonimową jest unia, która nie ma nazwy. union { unsigned short int usi; unsigned int ui; }; Do składowych takiej unii odnosimy się po prostu podając nazwę tego składnika (bez użycia kropki), np. ui=0xffffffff; usi=0x0000;
Przykład 2 union { char a; unsigned short int b; }; b=0x4142; cout<<a<<endl; cout ('B')<<endl; B
Zastosowanie unii i pól bitowych void wypisz(int a){ for (int i=3; i>=0; i--) cout >i & 0x01); } int main(){ struct dane { unsigned short int a:4,b:4,c:4,:4; }; union { unsigned short int dana; dane bity; }; dana=0x0011; cout<<"a\t";wypisz(bity.a); cout<<"\nb\t";wypisz(bity.b); bity.c=bity.a+bity.b; cout<<"\nc\t";wypisz(bity.c); cout<<"\n\ndana\t"<<dana<<endl; } a0001 b0001 c0010 dana = = =529
Metody składowe struktury Struktura może być wyposażona w metody (funkcje) wykonujące operacje na danych. struct licz_zes { double re,im; void wypisz(); void zmien(); };
Definiowanie metod struct licz_zes { double re,im; void wypisz(); void zmien(); }; void licz_zes::wypisz() { cout<<"RE: "<<re<<endl; cout<<"IM: "<<im<<endl; } void licz_zes::zmien() { cin>>re>>im; } 18:: POST () []. -> PRE + - ! ~ * & 15 14* / % > 11 >= 10== != 9& 8^ 7| 6&& 5|| 4? : 3= *= /= %= += -= >= &= |= ^= 2 1,
Definiowanie metod struct licz_zes { double re,im; void wypisz(); void zmien(); }; void licz_zes::wypisz() { cout<<"RE: "<<re<<endl; cout<<"IM: "<<im<<endl; } void licz_zes::zmien() { cin>>re>>im; } struct licz_zes { double re,im; void wypisz() { cout<<"RE: "<<re<<endl; cout<<"IM: "<<im<<endl; } void zmien() { cin>>re>>im; } }; FUNKCJE inline
Używanie metod int main() { licz_zes A,*W; W=&A; A.zmien(); W->wypisz();... cout<<sizeof(A)<<endl; } 16
Operacje na obiektach strukturalnych struct licz_zes { double re,im; void wypisz(); void zmien(); }; void licz_zes::wypisz() { cout<<"RE: "<<re<<endl; cout<<"IM: "<<im<<endl; } void licz_zes::zmien() { cin>>re>>im; } int main() { licz_zes A,B,C; A.zmien(); B.zmien(); C=A+B; C.wypisz(); return 0; } BŁĄD Kompilator nie potrafi dodawać liczb zespolonych
Operacje na obiektach strukturalnych struct licz_zes { double re,im; void wypisz(); void zmien(); }; void licz_zes ::wypisz() { cout<<"RE: "<<re<<endl; cout<<"IM: "<<im<<endl; } void licz_zes ::zmien() { cin>>re>>im; } licz_zes dodaj(licz_zes A, licz_zes B) { licz_zes C; C.re=A.re+B.re; C.im=A.im+B.im; return C; } int main() { licz_zes A,B,C; A.zmien(); B.zmien(); C=dodaj(A,B); C.wypisz(); return 0; }
Operacje na obiektach strukturalnych struct licz_zes { double re,im; void wypisz(); void zmien(); }; void licz_zes ::wypisz() { cout<<"RE: "<<re<<endl; cout<<"IM: "<<im<<endl; } void licz_zes ::zmien() { cin>>re>>im; } licz_zes operator+(licz_zes A, licz_zes B) { licz_zes C; C.re=A.re+B.re; C.im=A.im+B.im; return C; } int main() { licz_zes A,B,C; A.zmien(); B.zmien(); C=A+B; C.wypisz(); return 0; }
this -wskaźnik do obiektu na rzecz którego wywołano funkcję licz_zes A,B,C; A.zmien(); B.zmien(); C.zmien(); Wskaźnik this jest (zawsze) przekazywany do funkcji. this void licz_zes ::zmien() { cin>>re>>im; } cin>>A.re>>A.im; cin>>B.re>>B.im; cin>>C.re>>C.im; this=&A; this=&B; this=&C; void licz_zes ::zmien() { cin>>this->re>>this->im; }
Modyfikator static Modyfikator static użyty przy definiowaniu składnika struktury sprawia, że ten składnik jest wspólny dla wszystkich obiektów strukturalnych.
Modyfikator static struct ulamek{ int l; static int m; void wypisz(); void zmien(); }; int ulamek::m=1; void ulamek::wypisz() { cout<<l<<"/"<<m<<endl; } void ulamek::zmien() { cin>>l>>m; } int main() { ulamek A,B; A.zmien(); A.wypisz(); B.zmien(); B.wypisz(); A.wypisz(); cout<<sizeof(A); } 1 2 1/ /4 1/4 4
Stałe obiekty struct ob { double w_x,w_y; string kol; void wypisz(); void przesun(double, double); void pomaluj(string kolor); }; void ob::pomaluj(string kolor){kol=kolor;} void ob::wypisz() { cout<<"x = "<<w_x<<endl; cout<<"y = "<<w_y<<endl; cout<<"kolor: "<<kol<<endl;} void ob::przesun(double a, double b) { w_x+=a;w_y+=b;} int main() { ob samochod={1,1,"szary"}; ob dom={2,2,"zielony"}; samochod.przesun(1,2); samochod.wypisz(); dom.przesun(5,5); dom.wypisz(); return 0; }
Stałe obiekty struct ob { double w_x,w_y; string kol; void wypisz(); void przesun(double, double); void pomaluj(string kolor); }; void ob::pomaluj(string kolor){kol=kolor;} void ob::wypisz() { cout<<"x = "<<w_x<<endl; cout<<"y = "<<w_y<<endl; cout<<"kolor: "<<kol<<endl;} void ob::przesun(double a, double b) { w_x+=a;w_y+=b;} int main() { ob samochod={1,1,"szary"}; const ob dom={2,2,"zielony"}; samochod.przesun(1,2); samochod.wypisz(); dom.przesun(5,5); dom.wypisz(); return 0; } BŁĄD
Stałe obiekty struct ob { double w_x,w_y; string kol; void wypisz() const; void przesun(double, double); void pomaluj(string kolor); }; void ob::pomaluj(string kolor){kol=kolor;} void ob::wypisz() const { cout<<"x = "<<w_x<<endl; cout<<"y = "<<w_y<<endl; cout<<"kolor: "<<kol<<endl;} void ob::przesun(double a, double b) { w_x+=a;w_y+=b;} int main() { ob samochod={1,1,"szary"}; const ob dom={2,2,"zielony"}; samochod.przesun(1,2); samochod.wypisz(); dom.wypisz(); return 0; }
Stałe obiekty struct ob { double w_x,w_y; string kol; void wypisz() const; void przesun(double, double); void pomaluj(string kolor) const; }; void ob::pomaluj(string kolor) const {kol=kolor;} void ob::wypisz() const { cout<<"x = "<<w_x<<endl; cout<<"y = "<<w_y<<endl; cout<<"kolor: "<<kol<<endl;} void ob::przesun(double a, double b) {w_x+=a;w_y+=b;} int main() { ob samochod={1,1,"szary"}; const ob dom={2,2,"zielony"}; samochod.przesun(1,2); samochod.wypisz(); dom.pomaluj("czerwony"); dom.wypisz(); return 0; } BŁĄD
Stałe obiekty struct ob { double w_x,w_y; mutable string kol; void wypisz() const; void przesun(double, double); void pomaluj(string kolor) const; }; void ob::pomaluj(string kolor) const {kol=kolor;} void ob::wypisz() const { cout<<"x = "<<w_x<<endl; cout<<"y = "<<w_y<<endl; cout<<"kolor: "<<kol<<endl;} void ob::przesun(double a, double b) {w_x+=a;w_y+=b;} int main() { ob samochod={1,1,"szary"}; const ob dom={2,2,"zielony"}; samochod.przesun(1,2); samochod.wypisz(); dom.pomaluj("czerwony"); dom.wypisz(); return 0; }
Struktura wektor struct wektor { int n; double *W; void wypisz(); }; void wektor::wypisz() { for (int i=0;i<n;i++) cout << W[i] << "\t"; cout << endl; } int main() { wektor X,Y; X.n=2;X.W=new double[2]; X.W[0]=1;X.W[1]=2; X.wypisz(); Y.n=2;Y.W=new double[2]; Y.W[0]=3;Y.W[1]=4; Y.wypisz(); Y=X; Y.wypisz(); X.wypisz(); Y.W[1]=3; Y.wypisz(); X.wypisz(); return 0; }
Prezentacja udostępniona na licencji Creative Commons: Uznanie autorstwa, Na tych samych warunkach 3.0. Pewne prawa zastrzeżone na rzecz autorów. Zezwala się na dowolne wykorzystywanie treści pod warunkiem wskazania autorów jako właścicieli praw do prezentacji oraz zachowania niniejszej informacji licencyjnej tak długo, jak tylko na utwory zależne będzie udzielana taka sama licencja. Tekst licencji dostępny jest na stronie: