10. seminář - Strukturované datové typy

TEACHINGZPC1

Co kdybychom chtěli v našem programu definovat nový datový typ pro reprezentaci pravivostních hodnot a místo 1/0 používat TRUE/FALSE. Řešení tohoto problému si ukážeme na tomto semináři. Naším cílem bude implementovat funkci pro hledání nuly v poli následovně


    Bool contains_zero(int numbers[], int length) {
        for (int i = 0; i < length; i++) {
              if (numbers[i] == 0) {
                  return TRUE;
              }
        }
        return FALSE;
    }

Odvozené datové typy

Jako první začněme s definicí nového typu pro pravdivostní hodnoty a nazveme jej Bool. Pro tyto účely máme v jazyce C konstrukci typedef.


    typedef type_in_c new_type;

Příklady


    // přejmenování typu; nepoužívá se
    typedef int integer;
    // vytvoření typu pro pole 10 prvků typu int
    typedef int small_array[10];
    // přejmenování typu za účelem zkrácení zápisu; používá se zřídka
    typedef unsigned long ULong;
    // v definici typu je možné využít všechny dříve definované typy
    typedef const ULong CULong;


    // Deklarace pomocí definovaných typů
    small_array my_numbers;
    ULong large_number;

Pomocí typedef ale nezařídíme aby TRUE mělo hodnotu 1 a FALSE hodnotu 0. Tento problém vyřešíme pomocí výčtového typu.

Výčtový typ

Výčtový typ nám umožňuje definovat nový datový typ, tak i konstanty kterých může daný datový typ nabývat. Pro definici výčtového typu Bool použijeme konstrukci enum následovně.


    typedef enum{TRUE = 1, FALSE = 0} Bool;

Příklad dny v týdnu


    typedef enum{MO, TU, WE, TH, FR, SA, SU} Day;

    // Tento výraz je ekvivaletní s předchozím
    //typedef enum {MO = 0, TU = 1, WE = 2, TH = 3, FR = 4, SA = 5, SU = 6} Day;

    int main() {
        Day exam;
        Day seminar = TU;
        Day today = MO;

        if (today == MO) {
            do_homework();
        }
        printf("Den: %i\n", TU); // Den: 1
        return 0;
    }

Jak reprezentujeme například 30. 11. 2021?

Jak definujeme funkci která bere jako argument datum a má datum jako návratový typ?

Struktury

Jako jedno možné řešení se nabízí pole. Má to ale jednu vadu. Pole nemohou obsahovat hodnoty ruzných typů. Jelikož den může být maximálně 31, tak nemá smysl používat stejný datový typ jako pro rok, protože ten nabývá mnohem vyšších hodnot. Řešením jsou struktury které uchovávají více hodnot ale různých typů. Definice struktury je následující:


    typedef struct {
        char day;
        char month;
        short year;
    } Date;

    // Pouziti struktury
    int main() {
        Date birthday = {24, 3, 1972};
        birthday.year = 1986;
        birthday.month = narozen.month + 1;
        birthday.month++;
        printf("Den narozeni: %i", birthday.day);
    }

Zlomky

Struktury můžeme použít jako argument nebo návratovou hodnotu funkce. Struktury jsou předávány hodnotou takže při předání jako argument funkce se hodnoty překopírují.


    typedef struct {
        int numerator, denominator;
    } Fraction;

    Fraction fraction_multiply(Fraction f1, Fraction f2) {
        Fraction new_fraction;
        new_fraction.numerator = f1.numerator * f2.numerator;
        new_fraction.denominator = f1.denominator * f2.denominator;
        return new_fraction;
    }

    int main() {
        Fraction f1 = {2, 5}, f2 = {3, 7}, f3;
        f3.numerator = 0;
        f3.denominator = 45;
        print_fraction(f1); // Vytiskne: 2/5
        print_fraction(f2); // Vytiskne: 3/7
        print_fraction(f3); // Vytiskne: 0/45
    }

Složené zlomky


    typedef struct {
        Fraction compount_numerator;
        Fraction compount_denominator;
    } CompoundFraction;

    int main() {
        Fraction f1 = {2, 5}, f2 = {3, 7};
        CompoundFraction compound = {f1, f2};
        print_fraction(compound.compount_numerator); // Vytiskne: 2/5
        print_fraction(compound.compount_denominator); // Vytiskne: 3/7
        printf("%i\n", compound.compount_numerator.numerator); // 5
        printf("%i\n", compound.compount_denominator.denominator); // 3
        compound.compount_denominator.denominator = 10;
        print_fraction(compound.compount_denominator); // Vytiskne: 3/1
    }

Úkoly

Definujte strukturu pro obdélník rovnoběžný s osami(vhodné položky vymyslete sami). Naprogramujte:

  • funkci pro výpočet obsahu a obvodu obdélníku
  • funkci, která určí, zda se dva obdélníky protínají
  • funkci, která určí, zda je jeden obdélník uvnitř druhého obdélníku.

Naprogramujte funkce pro aritmetické operace se zlomky a pro převod zlomku do základního tvaru.

Definujte strukturu pro reprezentaci bodu na ploše. Naprogramujte funkci, která pro pole bodů vrátí nejkratší vzdálenost mezi mezi body z pole.