Złożone typy danych
Typ wyliczeniowy
Posługiwanie się wprost literałami liczbowymi jako identyfikatorami nie jest najlepszym pomysłem. Zamiast tego warto używać typu wyliczeniowego:
enum Kolor { CZARNY, BIALY, CZERWONY, ZIELONY, NIEBIESKI }; enum Kolor c = BIALY; if( c == BIALY ){ c = CZERWONY; }
Zwyczajowo wartości typu wyliczeniowego piszemy wielkimi literami, aby zaznaczyć, że są one stałe.
Struktury
Struktury (struct
) umożliwiają
definiowanie typów, których zmienne
mogą zawierać w sobie składowe różnych typów.
struct Punkt { double x, y; }; struct Adres { char miejscowosc[100]; char ulica[100]; int nr_domu; int kod; };
Warto zwrócić uwagę, że po nawiasie klamrowym zamykającym musi się pojawić średnik.
Gdy już mamy zdefiniowane typy strukturalne jak powyżej, zadeklarujmy zmienne tych typów.
struct Punkt p1; p1.x = 1.0; p1.y = 2.25; struct Adres adres; strncpy(adres.miejscowosc, "Lublin", sizeof(adres.miejscowosc)); strncpy(adres.ulica, "Akademicka", sizeof(adres.ulica)); adres.nr_domu = 9; adres.kod = 20033;
Wielkość zmiennej typu strukturalnego jest nie mniejsza od sumy rozmiarów składowych. Dlaczego nie zawsze równa? Zmienne typów większych od 1 B najczęściej nie są umieszczane w pierwszym wolnym miejscu dostępnej pamięci operacyjnej, lecz pod adresem równym wielokrotności rozmiaru zmiennej (nie dotyczy to tablic). Ta sama zasada odnosi się do składowych w strukturach. Więcej o tym można znaleźć w poradniku The Lost Art of C Structure Packing.
Operator ->
Mając wskaźnik p
do struktury,
możemy się dostać do jej składowej przy użyciu wyrażenia (*p).skladowa
.
Istnieje krótszy sposób,
wykorzystujący operator ->
:
p->skladowa
.
struct Adres *tablica_wskaznikow_na_adres[10]; int i; for(i=0; i<10; ++i){ tablica_wskaznikow_na_adres[i] = malloc(sizeof Adres); tablica_wskaznikow_na_adres[i]->kod = 20033; // niżej to samo inaczej: (*tablica_wskaznikow_na_adres[i]).kod = 20033; }
Unie
Unie (union
) tym różnią się od struktur, że ich rozmiar jest równy rozmiarowi największej
składowej.
Dzieje się to jednak kosztem tego, że w danym momencie pamiętana jest tylko
jedna składowa (ta, która była ostatnio zapisana).
union Unia { int a; double b; char c; }; union Unia u; u.a = 2012; u.c = 0xff; // == 255 printf("%d\n", u.a);
typedef
Słowo kluczowe typedef
umożliwia
stworzenie aliasu dla dowolnego typu.
Załóżmy, że deklarujemy zmienną pewnego typu;
jeśli dodamy na początku deklaracji słowo typedef
,
nazwa dotychczasowej zmiennej będzie oznaczała
nazwę typu.
typedef int Dlugosc; typedef int *Pint; typedef Pint Int_tab3[3]; Dlugosc a = 12; Int_tab3 tab = {&a, &a, &a};
W powyższym przykładzie Dlugosc
to alias dla typu int
, natomiast Int_tab3
to
alias dla typu tablic trzyelementowych o elementach typu Pint
czyli wskaźnikach na int
.
Zadania
-
Zdefiniuj typ strukturalny do przechowywania informacji o wektorach na płaszczyźnie. Napisz funkcję, która przyjmuje jako parametr taki wektor i zwraca jego długość.
-
Napisz funkcję, która przyjmuje wskaźnik do wektora jak w poprzednim zadaniu i zmienia jego zwrot.
-
Zdefiniuj typ strukturalny
Punkt3D
do przechowywania informacji o punktach w przestrzeni trójwymiarowej. Napisz funkcję, która przyjmuje dwa parametry takiego typu i zwraca odległość między oboma punktami. -
Zdefiniuj strukturę
Zespolona
służącą do przechowywania liczb zespolonych. Zdefiniowana struktura powinna zawierać polaim
orazre
typudouble
służące do przechowywania części liczby zespolonej odpowiednio urojonej i rzeczywistej.Napisz funkcję
zesp_suma
, która dostaje dwa parametry typuZespolona
i zwraca ich sumę. Analogicznie zdefiniuj funkcjęzesp_iloczyn
. -
Zdefiniuj strukturę
Osoba
, która wśród swoich składowych pól będzie zawierała napis do przechowywania imienia oraz zmienną całkowitą do przechowywania roku urodzenia.Napisz funkcję, która przyjmuje tablicę struktur
Osoba
oraz jej rozmiar i wypisuje imię najstarszej osoby.