16. Struktury II
  1. Složkou struktury může být i bitové pole. Bitové pole je celočíselná složka o délce 1 až 32 bitů. Délku bitového pole a volitelný identifikátor specifikujeme následovně:

  2. specifikátor_typu ident_bitového_pole:šířka;
    kde specifikátor_pole je char nebo int (nebo jejich bezznaménkové verze). Jednotlivé bity jsou v daném slově přidělovány od nejnižšího po nejvyšší bit. Výraz šířka nelze vynechat a musí vést na celočíselnou konstantu v rozsahu 1 až 32. Pokud v deklaraci bitového pole není uveden identifikátor, je daný počet bitů blokován a toto pole je dále nepřístupné. Tímto způsobem je možné vytvářet nejrůznější masky (např. pro hardwarové registry), v nichž některé bity nemají význam.
    Bitová pole je možno deklarovat pouze ve strukturách, svazech a třídách. Struktury mohou obsahovat jakoukoli kombinaci bitových polí a "nebitových" typů. K jejich zpřístupňování se používají tytéž selektory jako pro jiné složky struktury.
  3. Svazy odpovídají záznamům s variantní částí. Svaz je odvozený typ, který má mnoho syntaktických a funkčních vlastností struktur. Hlavním rozdílem mezi strukturou a svazem je to, že ve svazu může být v daný časový okamžik "aktivní" pouze jedna jeho složka. Délka svazu je tedy dána délkou jeho největší složky. V kterýkoli okamžik je možné uchovat hodnotu pouze jedné jeho složky.

  4. union TSvaz {
      ing i;
      double d;
      char ch;
    } mu, *muptr = μ
    Proměnná mu typu TSvaz může být použita pro uchování 4 slabikového celého čísla, 8 slabikového reálného čísla nebo jednoslabikového znaku, ale v daný okamžik vždy pouze jednoho z nich.
  5. Barva zobrazovaných znaků a barva pozadí znaků (v konzolové aplikaci) se může také zadávat funkcí textattr (hlavičkový soubor conio.h). Parametr této funkce je možno vyjádřit jako bitové pole (4 bity barva znaku, 3 bity barva pozadí a 1 bit blikání; blikání je možno používat pouze v DOSu - v okně konzolové aplikace je požadavek na blikání znaků ignorován). Na tyto bity se v některých případech můžeme také dívat jako na jedinou hodnotu, které říkáme atribut znaku. Pro spojení obou typů použijeme svaz. Je to ukázáno v následujícím programu.

  6. union barva {
      unsigned char atribut;
      struct {
        unsigned popredi : 4;
        unsigned pozadi : 3;
        unsigned blikani : 1;
      } slozky;
    };
    int main(int argc, char **argv)
    {
      barva b;
      b.slozky.blikani = 1;
      b.slozky.pozadi = BLUE;
      b.slozky.popredi = GREEN;
      textattr(b.atribut);
      cprintf("Zkouška barvy\n\r");
      return 0;
    }
    Vidíme, že s proměnnou b zpočátku pracujeme tak, že se odkazujeme na její složky a potom ji používáme celou najednou jako atribut. Pro přeložení tohoto programu musíme vložit hlavičkový soubor conio.h.
    Podobným způsobem můžeme přistupovat k různým informacím, které jsou uloženy na několika bitech ve slovu.
  7. Výčtový datový typ se používá pro přiřazení mnemonických identifikátorů množině celočíselných hodnot. Např. deklarace

  8. enum dny { ne, po, ut, st, ct, pa, so } den;
    definuje výčtový typ dny, proměnnou den tohoto typu a množinu výčtových konstant ne, po, ...
    V C++ je možné proměnné výčtového typu přiřadit pouze hodnotu tohoto typu nebo některou výčtovou konstantu tohoto typu. Např.
    den = po;
  9. Následující strukturu můžeme použít pro uložení informací o nějaké osobě:

  10. enum pohlavi {muz, zena};
    struct osoba {
      char jmeno[25];
      pohlavi pohl;
      union {
        float plat;
        double vaha;
      };
    };
    Struktura umožňuje sledovat jméno, pohlaví a u mužů plat, zatímco u žen váhu (nebo obráceně). V předchozí kapitole jsme vytvářeli konzolovou aplikaci udržující informace o našich známých. Do definice struktury v této aplikaci přidejte svaz (ve smyslu předchozí ukázky) a proveďte další potřebné změny. Hodnoty výčtového typu není možno číst přímo datovým proudem cin.
  11. Rozšiřte předchozí zadání tak, aby kartotéka vašich známých byla uložena v binárním souboru. Po spuštění programu zjistěte, zda soubor s kartotékou existuje. Pokud neexistuje, zadávejte data z klávesnice, pokud existuje načtěte je ze souboru. Hodnoty z kartotéky vypište na obrazovku. Zajistěte také možnost zadávání údajů o další osobě. Při ukončení programu vždy data zapište do souboru.
  12. Možnosti používání výčtových typů si ukážeme na následující aplikaci GUI. Začneme s vývojem nové aplikace. Nejprve na formulář (na levou stranu) vložíme GroupBox (jeho Caption změníme na ?Zajímá mě?), na GroupBox vložíme pod sebe 4x komponentu RadioButton (při jejich vkládání musí být vybrána komponenta GroupBox; jinak jsou RadioButtony vloženy přímo na formulář) a změníme jejich vlastnosti Caption na Historie, Literatura, Biologie a Psychologie. Dále na formulář vložíme tlačítko s textem Co mě zajímá a komponentu Label (zde zobrazený text vyprázdníme). Nastavení voličů je vhodné určovat pomocí výčtového typu. Nadefinujeme tedy výčtový typ TZajem a proměnnou Zajem tohoto typu. Dále vytvoříme obsluhy kliknutí na jednotlivých voličích a obsluhu stisknutí tlačítka. Pokud jsme neměnili názvy komponent potom dostaneme (pozor následuje výpis celého programu):

  13. #include <vcl.h>
    #pragma hdrstop
    #include "Unit1.h"
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    enum TZajem {Nic, Historie, Literatura, Biologie, Psychologie};
    TZajem Zajem = Nic;
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::RadioButton1Click(TObject *Sender)
    {
      Zajem = Historie;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::RadioButton2Click(TObject *Sender)
    {
      Zajem = Literatura;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::RadioButton3Click(TObject *Sender)
    {
      Zajem = Biologie;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::RadioButton4Click(TObject *Sender)
    {
      Zajem = Psychologie;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      switch (Zajem) {
        case Historie: Label1->Caption = "Zajímám se o historii"; break;
        case Literatura: Label1->Caption = "Zajímám se o literaturu"; break;
        case Biologie: Label1->Caption = "Zajímám se o biologii"; break;
        case Psychologie: Label1->Caption ="Zajímám se o psychologii";
                          break;
        default: Label1->Caption = "Nezajímám se o nic";
      }
    }
    Vyzkoušejte tuto aplikaci a zjistěte jak pracuje.
  14. V kapitole "Příkazy řídící běh programu I" jsme vytvářeli jednoduchý textový editor. Doplňte tuto aplikaci tak, že na formulář vložíme tři voliče : Vlevo, Doprostřed a Vpravo, kterými budete ovlivňovat zarovnávání zobrazeného textu (vlastnost Alignment). Na formulář přidejte další tlačítko, kterým (prostřednictvím komponenty ColorDialog) budete měnit barvu textu v komponentě Memo (vlastnost Font.Color).

Kontrolní otázky:

  1. Může být více proměnných stejného jména?
  2. Můžeme používat samotnou strukturu bez vytvoření její instance?
  3. Co je to globální proměnná?
  4. Může struktura obsahovat různé typy dat (char, int, float, atd.)?
  5. Jak přistupujeme ke složkám struktury?
  6. Je dovoleno mít pole struktur?


Řešení


16. Struktury II