|
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í unionu. 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.