[Cvičení 1] | [Obsah] | [Cvičení 3] |
Pole je homogenní datový typ, tedy všechny položky pole jsou stejné. V případě struktur jde o heterogenní datový typ. Struktura tedy obsahuje několik položek různých datových typů, které ovšem spolu logicky souvisejí. Struktura umožňuje „společné“ pojmenování všech sdružených údajů, s nimiž se potom v programu pohodlněji pracuje.
Struktura je obecně definována následujícím zápisem:struct [jméno struktury] { typ jméno_položky; typ jméno_položky; ... } proměnná;Struktura je uvedena klíčovým slovem
struct
. Pojmenování struktury jménem je nepovinné a zpravidla se ani nepoužívá (pouze v případě,
že struktura odkazuje sama na sebe). V bloku definic položek struktury se uvádějí jednotlivé položky struktury.
Ukážeme se definici proměnné bod
typu struktura, která má dvě položky (x-ovou a y-ovou souřadnici):
struct { float x; float y; } bod;K položkám struktury přistupujeme pomocí tečkové notace, tedy položku
x
a y
proměnné bod nastavíme takto:
bod.x = 3.5; bod.y = 4;
V paměti je proměnná bod uložena následovně
Pomocí typedef
můžeme definovat uživatelský typ, např. TBod:
typedef struct { float x; float y; } TBod;Proměnné typu
TBod
deklarujeme jako každé jiné proměnné:
TBod b1,b2;
Inicializovat položky struktury lze již při deklaraci:
TBod b1 = {3,4};Statické pole struktur deklarujeme
TBod pole_bodu[10]
, k položkám pole přistupujeme pole_bodu[0].x = 3;
Je možné deklarovat také ukazatel na strukturu a paměť pro data alokovat dynamicky:
TBod *b3; b3 = (TBod*)malloc(sizeof(TBod)); ... free(b3); /* uvolnění paměti */K položkám bodu b3 přitupujeme standardně pomocí „*“ a „.“:
*b3.x = 4;
. Programátoři
v jazyce C používají častěji jiný zápis: b3 -> x = 4;
, tedy pokud je nějaká proměnná ukazatel na strukturu,
pro přístup k položkám zapisují místo hvězdičky a tečky „šipku“ (znaky minus a větší zapsané bez mezery);
oba zápisy *b3.x = 4
a b3 -> x = 4
jsou v jazyce C ekvivalentní.
Strukturu můžeme předat funkci jako parametr, předává se buď struktura sama nebo ukazatel na strukturu (což je výhodnější z hlediska paměťových nároků, pokud struktura zabírá více paměti; nezapomeňme, že v případě předání struktury se na zásobník předává kopie dat). Definici funkce, která počítá vzdálenost bodu od počátku, je v tabulce 1. Tabulka ukazuje 2 funkce, u první se předává jako parametr samotná struktura, u druhé ukazatel na strukturu.
Předání samotné struktury | Předání ukazatele na strukturu |
double vzdalenost1(TBod b) { return sqrt (b.x*b.x + b.y*b.y); } |
double vzdalenost2(TBod *b) { return sqrt (b->x*b->x + b->y*b->y); |
Tabulka 1: Předávání struktur funkcím
Funkce voláme se skutečnými parametry následovně:
vzdalenost1(b1); vzdalenost1(*b3); vzdalenost2(&b1); vzdalenost2(b3);
Poznámka: Uvědomte si, že pokud bychom neměli strukturu, musely by mít funkcevzdalenost1
avzdalenost2
místo jednoho dva parametry.
Napište program, kde nadeklarujete strukturovaný typ pro uložení bodu v prostoru.
Definujte dva body (dvě proměnné), jejichž souřadnice načtete z klávesnice.
Napište dvě funkce, jedna vrací vdálenost bodu od počátku (inspirujte se funkcí
vzdalenost1
), druhá funkce má dva body jako parametry a vrací vzdálenost
mezi nimi.
Řešení:
Položka | Délka položky | Popis |
typ | 2 byty | 2 znaky „BM“ |
velikost | 4 byty | celková velikost souboru |
rezervováno1 | 2 byty | rezervováno pro pozdější použití, musí být na 0 |
rezervováno2 | 2 byty | rezervováno pro pozdější použití, musí být na 0 |
posun | 4 byty | posun obrazových dat od začátku této hlavičky (struktury) |
Tabulka 2: Hlavička formátu BMP
Předpokládejme, že pracujeme na platformě Intel (uložení dat little-endian, tj. slabiky nižšího řádu jsou uloženy na nižších adresách), dále že
sizeof(unsigned short)=2
a sizeof(unsigned int)=4
. Strukturu, která odpovídá hlavičce souboru, nadeklarujeme následovně:
typedef struct { unsigned char B; unsigned char M; unsigned int velikost; unsigned short res1; unsigned short res2; unsigned int posun; } THeadBMP;Nadeklarujeme proměnnou pro hlavičku:
THeadBMP hlavicka;
vst
, který byl otevřen pomocí fopen
v binárním módu:
fread((void*)&hlavicka,sizeof(THeadBMP),1,vst)
.
Upozornění: Překladače většinou v rámci optimalizace přístupu do paměti neukládají položky struktur těsně za sebou, ale zarovnávají je na adresy dělitelné nějakou mocninou 2, např. gcc standardně na 2, Microsoft C++ na adresy dělitelné 4. V takovém případě by mezi položkami B, M a velikost byla v paměti mezera a velikost struktury v paměti by byla větší než velikost skutečné hlavičky v souboru. Funkce fread by načetla více dat a v jednotlivých položkách by nebyly správné hodnoty. Museli bychom tedy v překladači tuto optimalizaci (zarovnání struktur - structure alignment) vypnout. Např. v gcc použijeme přepínač překladu-fpack-struct=1
, popř. lze použít makro#pragma pack(1)
(zarovnat na 1 byte - pack(1) je makro z důvodu kompatibility s překladači Microsoft):#pragma pack(1) typedef struct { unsigned char B; unsigned char M; unsigned int velikost; unsigned short res1; unsigned short res2; unsigned int posun; } THeadBMP;
Ukázka:
Code Gear: bitmapa.cbp, bitmapa.c, obrazek.bmp
[Cvičení 1] | [Obsah] | [Cvičení 3] |