15. Struktury I
  1. Struktura je typ, kter² reprezentuje u╛ivatelsky definovanou mno╛inu pojmenovan²ch slo╛ek (prvk∙). Tyto slo╛ky mohou b²t libovolnΘho typu a mohou mφt libovolnΘ po°adφ. Struktury se deklarujφ pomocφ klφΦovΘho slova struct, nap°.

  2. struct TStruktura {                                // TStruktura je oznaΦenφ struktury
        deklarace slo╛ek struktury
    };
    ...
    struct TStruktura s, *ps, poleS[10]     // s je struktura TStruktura, ps je ukazatel na strukturu TStruktura
                                                                  // poleS je pole prvk∙ typu TStruktura
    Pokud vynechßme jmΘno (oznaΦenφ) struktury, dostaneme tzv. nepojmenovanou strukturu. NepojmenovanΘ struktury se mohou pou╛φvat p°i deklaraci prom∞nn²ch danΘho strukturovΘho typu, ale nikde jinde ji╛ dal╣φ objekty tohoto typu definovat nem∙╛eme:
    struct { ... } s, *ps, poleS[10];
    P°i deklarovßnφ struktur je mo╛nΘ pomocφ typedef (stejn∞ jako pro jinΘ typy - poslednφ identifikßtor na °ßdku je nov² nßzev pro typ popsan² mezi typedef a tφmto identifikßtorem) vytvo°it nov² specifikßtor datovΘho typu:
    typedef struct TStruktura { ... } STRUKT;
    STRUKT s, *ps, poleS[10];                  // totΘ╛ jako p∙vodnφ deklarace
    V∞t╣inou nenφ zapot°ebφ pojmenovßnφ struktury a typedef souΦasn∞. M∙╛eme je ale pou╛φt. Je takΘ mo╛nΘ vytvo°it specifikßtor nepojmenovanΘ struktury.
    Seznam deklaracφ slo╛ek uzav°en² ve slo╛en²ch zßvorkßch deklaruje typy a jmΘna slo╛ek struktury.
    Funkce m∙╛e vracet strukturu nebo ukazatel na strukturu. Struktura m∙╛e b²t p°edßna jako parametr funkce p°φmo, jako ukazatel nebo odkaz na strukturu.
    P°φstup ke slo╛kßm struktur se provßdφ prost°ednictvφm operßtor∙ .a ->. Operßtor .se naz²vß p°φm² selektor slo╛ky, operßtor -> se naz²vß nep°φm² selektor slo╛ky (v²raz ukazs->m je synonymum pro (*ukazs).m - pou╛φvß se, kdy╛ mßme ukazatel na strukturu).
    struct TStructura {
        int i;
        char str[2];
        double d;
    } s, *ukazs = &s;
    ...
    s.i = 3;                     // p°i°azenφ slo╛ce i struktury s
    ukazs->d = 1.23;    // p°i°azenφ slo╛ce d struktury s (struktura je identifikovanß ukazatelem ukazs)
    Pokud jednou ze slo╛ek struktury B je struktura A, pak slo╛ky struktury A mohou b²t zp°φstupn∞ny dvojφ aplikacφ selekΦnφch operßtor∙. Struktury je mo╛no p°i°azovat jen v tom p°φpad∞, ╛e jsou stejnΘho typu.
    Ukazatel na strukturu typu A se m∙╛e objevit v deklaraci jinΘ struktury B je╣t∞ p°edtφm, ne╛ je A deklarovßno. Nap°.
    struct A;                                    // p°edb∞╛nß deklarace
    struct B { struct A *pa; };
    struct A { struct B *pb; };
    Prvnφ deklarace A se naz²vß p°edb∞╛nß, proto╛e A prozatφm nenφ celß definovßna. Takovßto p°edb∞╛nß deklarace staΦφ k tomu, aby jsme mohli pou╛φt v definici B ukazatel na A, nebo╗ B nepot°ebuje znßt velikost A.
  3. P°edpoklßdejme, ╛e si chceme udr╛ovat adresß° sv²ch znßm²ch. Vytvo°φme tedy strukturu se slo╛kami, kterΘ se obvykle pou╛φvajφ v adresß°i. Nap°.

  4. struct adresar {
      char jmeno[20];
      char prijmeni[20];
      char ulice[50];
      char mesto[20];
      int psc;
      bool pritel;
    };
    Struktura mß 4 znakovΘ, jednu celoΦφselnou a jednu logickou slo╛ku. Po deklaraci struktury ji m∙╛eme pou╛φt. Nejprve je nutno vytvo°it instanci struktury (prom∞nnou pro ulo╛enφ struktury). To provedeme takto:
    adresar zaznam;
    Tento p°φkaz alokuje pam∞╗ pro strukturu a p°i°adφ alokovanou pam∞╗ prom∞nnΘ zaznam. Nynφ, kdy╛ mßme instanci struktury, m∙╛eme p°i°adit hodnoty jejφm slo╛kßm:
    strcpy(zaznam.jmeno, "Karel");
    strcpy(zaznam.prijmeni, "Novak");
    strcpy(zaznam.ulice, "Palackeho 876");
    strcpy(zaznam.mesto, "Pardubice"
    zaznam.psc = 53002;
    zaznam.pritel = false;
    Toto lze provΘst takΘ p°φmo p°i deklaraci struktury:
    adresar zaznam = { "Karel", "Novak", "Palackeho 876",
                       "Pardubice", 53002, false};
    Stejn∞ jako m∙╛eme mφt pole cel²ch Φφsel nebo pole znak∙, m∙╛eme mφt i pole struktur. Nap°.
    adresar seznam[5];
    strcpy(seznam[0].jmeno, "Karel");
    seznam[4].pritel = false;
    // atd.
    Zde pou╛φvßme operßtor indexace a operßtor selektoru slo╛ky.
  5. Zdrojov² soubor je textov² soubor obsahujφcφ zdrojov² k≤d programu. P°ekladaΦ p°ebφrß soubory zdrojovΘho k≤du, zpracovßvß je a vytvß°φ strojov² k≤d, kter² m∙╛e b²t spu╣t∞n na poΦφtaΦi.

  6. P°i na╣em seznamovßnφ s programovßnφm, °e╣φme samΘ jednoduchΘ ·lohy. P°i vytvß°enφ reßln²ch aplikacφ se bude jednat o podstatn∞ slo╛it∞j╣φ ·lohy. Normßlnφ program se obvykle sklßdß z n∞kolika zdrojov²ch soubor∙. Programov² k≤d je rozd∞len do n∞kolika r∙zn²ch zdrojov²ch soubor∙ z n∞kolika d∙vod∙. Zßkladnφm d∙vodem je udr╛ovßnφ k≤du t²kajφcφho se jednoho problΘmu v jednom souboru, co╛ umo╛≥uje v p°φpad∞ pot°eby snadnΘ nalezenφ jistΘ Φßsti k≤du.
    P°i p°ekladu, je nejprve p°elo╛en ka╛d² zdrojov² soubor (CPP) do objektovΘho souboru (OBJ) a potom ka╛d² p°elo╛en² modul je sestaven sestavovacφm programem do jednoho spustitelnΘho souboru (EXE). Sestavovacφ program takΘ p°ipojφ dal╣φ pot°ebnΘ soubory, jako jsou soubory zdroj∙ (RES) a knihovnφ soubory (LIB).
    Deklarace pro t°φdy a struktury jsou dr╛eny v odd∞len²ch souborech nazvan²ch hlaviΦkovΘ soubory. Tyto soubory majφ p°φponu H nebo HPP. HlaviΦkovΘ soubory obsahujφ pouze deklarace t°φd, struktur a funkcφ. Nenφ vhodnΘ vklßdat do nich k≤d p°φkaz∙. Z tohoto pravidla je jedna v²jimka. Do hlaviΦkov²ch soubor∙ je mo╛no vklßdat vlo╛enΘ (inline) funkce. S tφm se ale seznßmφme pozd∞ji.
    Jestli╛e pot°ebujeme vytvo°it hlaviΦkov² soubor, pak zvolφme File | New a na strßnce New dvojit∞ klikneme na ikonu Text. C++ Builder vytvo°φ nov² textov² soubor a zobrazφ jej v Editoru k≤du. Zadßme k≤d na╣eho hlaviΦkovΘho souboru a ulo╛φme vytvo°en² soubor s p°φponou H.
    Po vytvo°enφ hlaviΦkovΘho souboru pro t°φdu nebo strukturu, m∙╛eme direktivou include vlo╛it tento hlaviΦkov² soubor do libovolnΘho zdrojovΘho souboru, ve kterΘm deklaraci t°φdy nebo struktury pot°ebujeme.
    HlaviΦkovΘ soubory obvykle vytvß°φme tak, aby bylo zaji╣t∞no, ╛e do programu budou vlo╛eny pouze jednou. Pou╛φvßme k tomu direktivy podmφn∞nΘho p°ekladu (viz zadßnφ 1 v kapitole 10).
    HlaviΦkovΘ soubory mohou obsahovat vφce ne╛ jednu deklaraci t°φdy nebo struktury. Pou╛itφ samostatnΘho hlaviΦkovΘho souboru pro ka╛dou t°φdu nebo strukturu ale pomßhß udr╛ovat organizaci projemtu a usnad≥uje op∞tovnΘ pou╛itφ t°φd a struktur v dal╣φch programech. N∞kdy je mo╛no vlo╛it skupinu svßzan²ch t°φd do jednoho hlaviΦkovΘho souboru.

  7. Nynφ se pokusφme vytvo°it konzolovou aplikaci, ve kterΘ u╛ivatel zadß t°i jmΘna a adresy a ulo╛φ tyto zßznamy do pole struktur. Po zadßnφ t∞chto informacφ, jsou informace zobrazeny na obrazovce. Dßle je mo╛no zadat Φφslo zßznamu, kter² chceme op∞tovn∞ zobrazit. V tΘto aplikaci definici struktury uvedeme v samostatnΘm hlaviΦkovΘm souboru. Nejprve nßsleduje v²pis vlastnφho programu.

  8. #include <iostream.h>
    #include <conio.h>
    #include <stdlib.h>
    #pragma hdrstop
    #include "structur.h"
    void zobrazZaznam(int, adresar adrZaz);
    int main(int argc, char **argv)
    {
      adresar seznam[3];
      cout << endl;
      int index = 0;
      do {
        cout << "JmΘno: ";
        cin.getline(seznam[index].jmeno, sizeof(seznam[index].jmeno)-1);
        cout << "P°φjmenφ: ";
        cin.getline(seznam[index].prijmeni,
                    sizeof(seznam[index].prijmeni)-1);
        cout << "Ulice: ";
        cin.getline(seznam[index].ulice, sizeof(seznam[index].ulice)-1);
        cout << "M∞sto: ";
        cin.getline(seznam[index].mesto, sizeof(seznam[index].mesto)-1);
        cout << "PsΦ: ";
        char buff[10];
        cin.getline(buff, sizeof(buff)-1);
        seznam[index].psc = atoi(buff);
        index++;
        cout << endl;
      } while (index < 3);
      clrscr();
      for(int i = 0; i < 3; i++) {
        zobrazZaznam(i, seznam[i]);
      }
      cout << "Zadej Φφslo zßznamu: ";
      int zaz;
      do {
        zaz = getch();
        zaz -= 49;
      } while (zaz < 0 || zaz > 2);
      adresar pom = seznam[zaz];
      clrscr();
      zobrazZaznam(zaz, pom);
      getch();
      return 0;
    }
    void zobrazZaznam(int cis, adresar adrZaz)
    {
      cout << "Zßznam " << (cis + 1) << ":" << endl;
      cout << "JmΘno: " << adrZaz.jmeno << " " << adrZaz.prijmeni << endl;
      cout << "Adresa: " << adrZaz.ulice << endl;
      cout << "        " << adrZaz.mesto << endl;
      cout << "        " << adrZaz.psc << endl << endl;
    }
    a hlaviΦkov² soubor STRUCTUR.H je tento (ulo╛φme jej do stejnΘho adresß°e jako zdrojov² soubor):
    #ifndef _STRUCTUR_H
    #define _STRUCTUR_H
    struct adresar {
      char jmeno[20];
      char prijmeni[20];
      char ulice[50];
      char mesto[20];
      int psc;
    };
    #endif
    V programu vidφme n∞kolik nßm zatφm neznßm²ch v∞cφ. Program pou╛φvß funkci getline t°φdy cin k zφskßnφ vstupu od u╛ivatele. Je to z d∙vodu nep°φjemnΘho chovßnφ operßtoru >> p°i Φtenφ text∙, kterΘ mohou obsahovat mezery. Druh² parametr getline je pou╛it k omezenφ dΘlky vstupujφcφho °et∞zce (zajistφme tφm nep°epsßnφ informacφ za koncem slo╛ky). Operßtor sizeof je pou╛it k urΦenφ velikosti slo╛ky a tedy k urΦenφ, kolik znak∙ je do nφ mo╛no bezpeΦn∞ ulo╛it.
    Funkce atoi je takΘ novß (je pou╛ita p°i Φtenφ po╣tovnφho sm∞rovacφho Φφsla). Tato funkce p°ebφrß znakov² °et∞zec a p°evßdφ jej na celoΦφselnou hodnotu. Zadan² text pro slo╛ku psc je nutno p°evΘst na celΘ Φφslo.
    Funkce zobrazZaznam mß dva parametry. Prvnφ parametr udßvß Φφslo zobrazovanΘho zßznamu. Zßznamy jsou Φφslovßny od nuly a jeliko╛ ve v²pisu dßvßme p°ednost jejich Φφslovßnφ od 1, p°iΦφtßme k tomuto Φφslu p°ed v²pisem jedniΦku. Druh² parametr funkce zobrazZßznam je instance struktury adresar. Je pou╛ita lokßlnφ instance tΘto struktury a uvnit° funkce je jejφ obsah zobrazen.
    V tomto p°φpad∞ p°edßvßme strukturu hodnotou. Tzn. b∞hem volßnφ funkce je vytvo°ena kopie struktury. Toto nenφ moc efektivnφ, proto╛e vytvo°enφ kopie n∞jakou dobu trvß a spot°ebovßvß mφsto v pam∞ti. Je v²hodn∞j╣φ p°edßvat strukturu odkazem, ale to zatφm neumφme.
    Funkci zobrazZaznam volßme na dvou mφstech v na╣em programu. Na t∞chto mφstech by mohl b²t uveden obsah t∞la funkce a program by pracoval stejn∞. Vlo╛enφm tohoto k≤du do funkce se sna╛φme zabrßnit opakovanΘmu v²skytu stejnΘho k≤du. Pokud se v na╣em programu opakovan∞ vyskytuje stejn² k≤d, je vhodnΘ z n∞j ud∞lat funkci, kterou pak volßme, kdy╛ tento k≤d je zapot°ebφ provΘst.
    Podφvejme se je╣t∞ na nßsledujφcφ k≤d:
    do {
      zaz = getch();
      zaz -= 49;
    } while (zaz < 0 || zaz > 2);
    Tento k≤d Φte znak z klßvesnice pomocφ funkce getch (zatφm jsme ji pou╛φvali k Φekßnφ na konci programu). Tato funkce vracφ k≤d stisknutΘ klßvesy. Proto╛e ASCII hodnota klßvesy 1 je 49, klßvesy 2 je 50, atd., zφskßme odeΦtenφm 49 od k≤du p°eΦtenΘho znaku Φφselnou hodnotu klßvesy zmen╣enou o 1 (nap°. p°i stisknutΘ klßvese 1 dostaneme hodnotu 0). Tento cyklus tedy probφhß tak dlouho, dokud nestiskneme n∞kterou z klßves 1, 2 nebo 3.
    Podφvejme se je╣t∞ na °ßdek
    adresar pom = seznam[zaz];
    Tento k≤d vytvß°φ instanci struktury adresar a p°i°adφ ji obsah jednΘ struktury z pole struktur. Je zde mo╛no pou╛φt operßtor p°i°azenφ, proto╛e p°ekladaΦ vφ, jak kopφrovat jednu strukturu do jinΘ. M∙╛eme tedy snadno vytvo°it kopii celΘ struktury.
  9. Pokuste se upravit p°edchozφ program tak, aby bylo mo╛no zadßvat vφce zßznam∙ (a╛ 9).
  10. V p°edchozφ konzolovΘ aplikaci jsme p°eΦetli ·daje o n∞kolika osobßch. Tyto ·daje je mo╛no vlo╛it do binßrnφho souboru. Musφme deklarovat:

  11. FILE *soubor;
    a p°ed ukonΦenφ programu vlo╛φme p°φkazy (p°edpoklßdßme, ╛e aktußlnφ poΦet zßznam∙ je ulo╛en v prom∞nnΘ n):
    if ((soubor = fopen("KART.DTA", "wb")) == NULL) {
      cout << "Nelze vytvo°it soubor" << endl;
      return 1;
    }
    for (i = 0; i < n; i++)
      fwrite(&seznam[i], sizeof(adresar), 1, soubor);
    fclose(soubor);
    Prove∩te tyto zm∞ny a program vyzkou╣ejte. Funkce fwrite zapisuje poΦet v∞t urΦen² t°etφm parametrem do souboru urΦenΘho Φtvrt²m parametrem. DΘlku v∞ty urΦuje druh² parametr a poΦßtek prvnφ v∞ty urΦuje prvnφ parametr.
  12. Soubor vytvo°en² v p°edchozφm zadßnφ je mo╛no op∞t naΦφst a pou╛φvat v jinΘm programu. Nßsledujφcφ program ukazuje, jak informace ze souboru ulo╛it do pole v pam∞ti a vypsat je na obrazovce.

  13. #include "struktur.h"
    FILE *soubor;
    int n, i;
    adresar veta[10];
    if ((soubor = fopen("KART.DTA", "rb")) == NULL) {
      cout << "Nelze otev°φt soubor" << endl;
      return 1;
    }
    i = 0;
    while (fread(&veta[i], sizeof(adresar), 1, soubor) > 0)
      i++;
    n = i;
    fclose(soubor);
    for (i = 0; i < n; i++)
      zobrazZaznam(i, veta[i]);
    Vyzkou╣ejte. Vlo╛enφm hlaviΦkovΘho souboru STRUCTUR.H zajistφme, ╛e program bude pracovat se stejnou strukturou zßznamu.
  14. P°ejdeme op∞t k aplikacφm GUI. Nejprve se zaΦneme zab²vat formulß°em. Mimo vlastnostφ, se kter²mi jsme se ji╛ seznßmili, mß formulß° dal╣φ d∙le╛itΘ vlastnosti. Vlastnost BorderStyle urΦuje styl okraje formulß°e (nap°. hodnota bsNone urΦuje formulß° bez okraj∙, tzn. nelze m∞nit jeho velikost). M∞≥te tuto vlastnost a vyzkou╣ejte, jak se zm∞na projevφ na vzhledu a chovßnφ formulß°e za b∞hu aplikace.
  15. Formulß° mß dßle vlastnost BorderIcons (ikony rßmu formulß°e, tj. minimalizaΦnφ a maximalizaΦnφ tlaΦφtka apod.). P°ed jmΘnem tΘto vlastnosti je v Inspektoru objekt∙ uveden znak + (indikace, ╛e vlastnost se sklßdß z podvlastnostφ). Klikneme-li dvojit∞ na takto oznaΦenΘm jmΘn∞ vlastnosti, jsou na nßsledujφcφch °ßdcφch zobrazeny podvlastnosti a znak + se zm∞nφ na - (op∞tovn²m dvojit²m kliknutφm se vrßtφme k p∙vodnφmu zobrazenφ). P°i tomto ?rozbalenφ? vlastnosti, m∙╛eme jednotlivΘ podvlastnosti nastavovat samostatn∞. Pokuste se z formulß°e odstranit maximalizaΦnφ tlaΦφtko (BorderStyle musφ b²t nastaveno na bsSizeable; zm∞na se projevφ a╛ p°i spu╣t∞nφ aplikace).
  16. Vlastnosti Position a WindowState urΦujφ zp∙sob zobrazenφ formulß°e na obrazovce. Position urΦuje, zda formulß° zφskß pozici a velikost danou p°i nßvrhu, nebo zda se pou╛ije velikost a pozice navr╛enß Windows za b∞hu aplikace. WindowState urΦuje poΦßteΦnφ stav formulß°e (minimalizovan², maximalizovan² nebo normßlnφ). Pokuste se zm∞nit n∞kterou z t∞chto vlastnostφ a vyzkou╣ejte jak se zm∞na projevφ.
  17. Vlastnost ShowHint komponenty urΦuje, zda komponenta zobrazφ nßpov∞du, kdy╛ se na nφ na okam╛ik zastavφme kurzorem my╣i. Zobrazen² text je urΦen vlastnostφ Hint. Umφst∞te na formulß° n∞jakou komponentu a zajist∞te pro nφ zobrazovßnφ nßpov∞dy.
  18. Komponentu Panel lze pou╛φvat pro uklßdßnφ dal╣φch komponent. M∙╛eme z nφ vytvo°it nap°. stavov² °ßdek nebo na nφ vlo╛it komponenty, kterΘ tvo°φ n∞jak² logick² celek. Vlastnost Align urΦuje umφst∞nφ komponenty. Mo╛nΘ hodnoty tΘto vlastnosti majφ nßsledujφcφ v²znam: alTop (panel je umφst∞n na hornφ okraj formulß°e, zabφrß celou ╣φ°ku formulß°e a sleduje i zm∞nu ╣φ°ky formulß°e; obdobn∞ platφ i pro dal╣φ hodnoty tΘto vlastnosti), alRight (panel je umφst∞n na prav² okraj formulß°e), alBottom (spodnφ okraj), alLeft (lev² okraj), alClient (celß plocha formulß°e) a alNone (nem∞nφ se; z∙stßvß tak jak nastavil u╛ivatel). Umφst∞te na formulß° komponentu panelu a vyzkou╣ejte vliv hodnot vlastnosti Align na umφst∞nφ komponenty.
  19. U komponenty Panel lze pomocφ vlastnostφ BevelInner, BevelOuter, BevelWidth, BorderStyle a BorderWidth m∞nit zp∙sob orßmovßnφ panelu. Nastavte hodnotu vlastnosti BevelWidth na 10 (pro lep╣φ viditelnost) a vyzkou╣ejte vliv zm∞n ostatnφch t∞chto vlastnostφ na zobrazenφ okraje.
15. Struktury I