|
Napřed si zrekapitulujeme problémy s programem z minulého cvičení,
tak, jak se jeví z těch programů, které jsem našel v Odevzdávárně. Ty jsou zhusta způsobeny
nejasnostmi s adresováním ‑ ukazateli a poli, které jak víme, jsou synonymické.
Připomeňme, že (znakový) řetězec je souvislá oblast paměti (pole znaků), kde je alespoň jeden znak
'\0'
.
Pokud ono pole ukazatelů je ve funkci výstupním parametrem, pak musí být typu
***char
a při jejím volání se zadává
adresa onoho ukazatele na pole řetězců &poleRetezcu
.
Naše konkrétní realisace (cca) byla:
Neostýchejte se používat papír (nejen k hygienickým nebo obalovým účelům) a psací náčiní
a kreslete si obrázky. (Když budete učit, tak tabuli.)
Chceme-li spojit (aggregate) spolu nějaké logicky sounaléžející údaje, každý jiného typu. Příkladem budiž
jména a příjmení, datum a místo narození, PSČ, adresa, rodinný stav, případný partner, počet dětí
a případné další údaje vztahující se k jednomu člověku. Nebo údaje konkrétího automobilu: SPZ,
majitel, značka, typ, barva, čísla karoserie a motoru …
Příkladů bychom mohli uvádět více, takže ještě jeden: název země, státní zřízení, hlavní město,
oficiální jazyky, počet obyvatel, rozloha atd.
V jazyku C se pro takto dohromady dané údaje používá
struct
. V češtině se někdy, zejména
při používání jiných programovacích jazyků používá termín záznam (v Pascalu
record
).
Jednodušší je nadefinovat si struct
jakožto typ ‑ lépe se s ní potom pracuje.
#include <stdlib.h> #include <stdio.h> /** * Priklad struktury a jejiho pouziti * * @file structExamp.c * @author Ales Zlamal */ #define DELKA_RETEZCU 32 #define DELKA_ORIENTACNIHO_CISLA 8 #define DELKA_PRIJMENI 48 typedef struct tagData { unsigned char den; unsigned char mesic; unsigned int rok; } datum; typedef struct tagAdresy { char ulice[DELKA_RETEZCU]; char orientacniCislo[DELKA_ORIENTACNIHO_CISLA]; unsigned int prvniCastPSC; unsigned int druhaCastPSC; char obec[DELKA_RETEZCU]; char zeme[DELKA_RETEZCU]; } adresa; typedef struct tagOsoby { char jmena[DELKA_RETEZCU]; char prijmeni[DELKA_PRIJMENI]; datum datumNarozeni; char mistoNarozeni[DELKA_RETEZCU]; adresa bydliste; } osoba; /** * Nacte udaje o osobe * * @param[out] p adresa promenne osoba, jejiz polozky se nactou */ void nacti(osoba *p); /** * Vypise udaje o osobe * * @param[in] name struktura osoba */ void vytiskni(osoba name); /** * Nacte retezec ze standardniho vstupu nejdele v zadane delce a odstrani prechod na novy radek * * @param[out] d pamet, kam se ma ulozit nacteny retezec * @param[out] e o jedna zvetsena maximalni delka nacitaneho retezce */void ctiRetez(char *d, int e); int main() { osoba zadatel; nacti(&zadatel); printf("\n\nZadano bylo:\n"); vytiskni(zadatel); return EXIT_SUCCESS; } void ctiRetez(char *d, int e) { fgets(d, e, stdin); *(d + strlen(d) - 1) = '\0'; } void nacti(osoba *p) { printf("Zadejte (krestni jmen[o|a]: "); ctiRetez(p->jmena, DELKA_RETEZCU); printf(" prijmeni: "); ctiRetez(p->prijmeni, DELKA_PRIJMENI); printf(" cisly den mesic rok narozeni: "); scanf(" %hhu %hhu %u", &(p->datumNarozeni.den), &(p->datumNarozeni.mesic), &(p->datumNarozeni.rok)); getchar(); printf(" misto narozeni: "); ctiRetez(p->mistoNarozeni, DELKA_RETEZCU); printf(" bydliste - ulice: "); ctiRetez(p->bydliste.ulice, DELKA_RETEZCU); printf(" bydliste - (orientacni) cislo: "); ctiRetez(p->bydliste.orientacniCislo, DELKA_ORIENTACNIHO_CISLA); printf(" bydliste - PSC: "); scanf(" %u %u", &(p->bydliste.prvniCastPSC), &(p->bydliste.druhaCastPSC)); getchar(); printf(" bydliste - obec: "); ctiRetez(p->bydliste.obec, DELKA_RETEZCU); printf(" bydliste - zeme: "); ctiRetez(p->bydliste.zeme, DELKA_RETEZCU); } void vytiskni(osoba name) { printf(" (krestni jmen[o|a]: %s\n", name.jmena); printf(" prijmeni: %s\n", name.prijmeni); printf(" cisly den mesic rok narozeni: %hhu %hhu %u\n", name.datumNarozeni.den, name.datumNarozeni.mesic, name.datumNarozeni.rok); printf(" misto narozeni: %s\n", name.mistoNarozeni); printf("bydliste - ulice: %s\n", name.bydliste.ulice); printf("bydliste - (orientacni) cislo: %s\n", name.bydliste.orientacniCislo); printf("bydliste - PSC: %u %u\n", name.bydliste.prvniCastPSC, name.bydliste.druhaCastPSC); printf("bydliste - obec: %s\n", name.bydliste.obec); printf("bydliste - zeme: %s\n", name.bydliste.zeme); }
Všimněte si, že práce se (datovou) strukturou je, pokud je definována jakožto typ, jednodušší. Používejte jmenovku (tag), přestože jsme ji zatím nepoužili. To příjde později a umožní nám (datovou) strukturu použít v jistém smyslu rekursivně.
Můžeme v (datové) struktuře používat ukazatele:
typedef struct tagOsoby { char *jmena; char *prijmeni; datum *datumNarozeni; char *mistoNarozeni; adresa *bydliste; } osoba;Pak ale budeme mít problémy, při zapisování či čtení (datových) struktur ze a do souborů.
Napište program, kde budete v datové struktuře mít jména, příjmení a telefonní čísla. Zadáte několik osob v jejich poli a následně zadáte jméno, respective jméno a příjmení a program vypíše telefonní číslo či čísla osob se zadaným jménem anebo jménem a příjmením.
V současné době a na úvodních úrovních práce s jazykem C union
nebudeme s užitkem používat.
Příkladně: pokud bychom dříve chtěli používat stejná data jak pro muže tak pro ženy, kdy muži měli povinnou vojenskou
presenční službu a neměli gynekologické prohlídky, tak bychom pro ušetření
mohli union
používat. Může potom být několik různých datových struktur na stejném místě v paměti,
ikdyž v jednom okamžiku právě jen jednu jedinou určitou z nich. Musíme se potom nějak dovědět jakou: použít další položku.
Uvedeme si zde příklad použití smysluplného užití union
u. Nevíme-li jak jsou uložena čísla
v procesoru na němž pracujeme, pak můžeme
#include <stdlib.h> #include <stdio.h> /** * Priklad unionu a jeho pouziti * * @file unionExamp.c * @author Ales Zlamal */ typedef union tagNumber { unsigned long longNumber; unsigned char bytes[8]; } number; int main() { number n; printf("%zu\n", sizeof(long int)); n.longNumber = 0x0123456789ABCDEFL; printf("| |\n|"); for (int i = 0; i < 8; ++i) { printf("%02hhX", n.bytes[i]); } printf("|\n"); return EXIT_SUCCESS; }
Přesto nemůžete union
úplně pominout:
může se objevit u colloquia v „teoretických” otázkách.