Týždeň 1

štruktúrované údajové typy, používateľom definované údajové typy, zoznamy údajov, vyhľadávanie v zozname údajov

Úvod

  • Predmet sa volá Programovanie a naším cieľom je z vás vychovať programátorov. Slovo programovanie vyjadruje činnosť a preto aj tento kurz bude veľmi praktický.

  • Motivačne: na konci kurzu sa budete môcť pochváliť svojou (možno) druhou (alebo už treťou?) hrou, ktorú vytvoríte (keďže Hangmana a nejakú prvotinu v Scratch-i ste spáchali už v rámci predmetu Základy algoritmizácie a programovania)

  • Stránka celého predmetu sa nachádza na http://it4kt.cnl.sk/c/pvjc - tu nájdete cvičenia, prednášky, príklady použité na prednáškach aj všetko potrebné pre úspešné absolvovanie tohto kurzu.

  • Ak hľadáte literatúru pre tento predmet, môžete použiť titul Učebnice jazyka C od Pavla Herouta (slide) alebo Programovací jazyk C do tvorcov jazyka C Kernighan-a a Ritchie-ho (slide).

  • Ďalšie odporúčanie pre zvládnutie tohto predmetu je portál codewars (slide). Jedná sa o jeden z mnohých portálov/stránok, ktoré sa dnes snažia popularizovať progarmovanie herným spôsobom. Máte k dispozícii riešenie podobné našej Aréne, kde môžete voľne riešiť rozličné úlohy, za ktoré dostávate body a samozrejme s vyšším počtom bodov stúpate v rebríčku hodnotení. Veľmi dobrý spôsob, ako začať deň s cvičením v jazyku C na stránke codewars.

  • Za predmet môžete získať spolu 20 bodov (slide), ktoré získate vypracovaním niekoľkých zadaní. Našou snahou je, aby tých zadaní bolo čo najviac, aj keď tohto roku skončíme pri čísle 4. Aj preto pristupujte ku každému jednému zadaniu a k jeho riešeniu čo najsvedomitejšie.

  • Hodnotenie každého jedného zadania bude rovnaké, takže sa nespoliehajte na to, že stačí zamakať až na poslednom zadaní, lebo zaň získate najviac bodov. Tie najjednoduchšie zadania zo začiatku budú stáť rovnaký počet bodov ako tie najťažšie na konci.

  • Ak ste opakujúci, môžete si nechať uznať zápočet z minulého roku v jeho minimálnej podobe - 11 bodov. Odporúčame ho ale absolvovať znova (vyššia šanca predmet absolvovať úspešne a lepšie).

  • Pri absolvovaní predmetu budeme dbať na to, aby ste postupovali podľa etického kódexu (slide) a to hlavne pri práci na vašich zadaniach. Včas vás naň budeme opätovne upozorňovať.

  • V závere semestra sa pozrieme na úvod do programovania mikrokontroléra Arduino (slide).
  • Na stránke nájdete aj zoznam komponentov, ktoré si kúpte. Ak chcete ušetriť, odporúčame vám minimálne samotný mikrokontrolér spolu s prepájacím poľom objednávať z Číny už teraz. Ostatné súčiastky si už môžete kúpiť aj v lokálnych rádioamatérskych obchodoch. Po dobrej spolupráci z minulého roku sa aj tento rok pokúsime pripraviť hotové balíčky, ktoré si prídete len kúpiť.

  • Ak hľadáte literatúru pre programovanie mikrokontroléra Arduino v domácom jazyku, siahnite po knižke Arduino - Uživatelská příručka (slide).

  • V tejto súvislosti sa chceme aj tento rok zúčastniť celosvetého dňa s názvom Arduino Day (slide). Oficiálny dátum ešte nebol zverejnený, ale bude to zrejme niekedy začiatkom apríla. Akciu spravíme pravdepodobne v stredu, pretože chceme, aby sa jej zúčastnilo čo najviac z vás. Jednu stredu teda prednáška a cvičenia nebudú, ale miestno nej budete mať možnosť sa zúčastniť prednášok, workshopov a sprievodných aktivít počas tejto akcie.

  • Podmienky pre opakujúcich študentov - viď info stránka predmetu (slide).

Štruktúrovaný údajový typ

Motivácia

  • Na predmete Základy algoritmizácie a programovania ste sa venovali najmä tzv. jednoduchým alebo ináč nazývaným aj primitívnym údajovým typom (slide). Výlučne s nimi si však do konca života nevystačíme, pretože svet a problémy, ktoré budete riešiť, nebudú vždy také jednoduché. A dnes si ukážeme prečo.
  • Predstavte si napríklad, že vo svojom programe potrebujete opísať vlastnosti nejakého auta alebo osoby. Čo všetko by vás zaujímalo? (nechať študentov menovať jednotlivé vlastnosti a zapisovať si ich do súboru)
  • Ak by sme tieto vlastnosti mali reprezentovať v jazyku C, aké údajové typy by mali? (k vymenovaným vlastnostiam začať písať údajové typy)
  • Máme k dispozícii niekoľko vlastností, pomocou ktorých vieme opísať nejakú osobu. Čo ak by sme však potrebovali opísať viac ako jednu osobu? Čo ak by sme potrebovali vytvoriť informačný systém, ktorý bude pracovať s tisíckami takýchto osôb? Čo ak budeme potrebovať funkciu, ktorá spracuje informácie o konkrétnej osobe?
  • Jazyk C umožňuje pracovať s tzv. štruktúrovanými typmi údajov, resp. štruktúrami (slide). Význam je podobný ako tomu bolo v jazyku Pascal, kde sa na tento účel používal údajový typ record.
  • Podobný prístup je možné vidieť napr. aj v relačných databázach, kde entita (tabuľka) reprezentuje štruktúrovaný údajový typ a konkrétny riadok v tabuľke hovorí o konkrétnom objekte, resp. zázname.

Vytvorenie štruktúrovaného údajového typu

  • Na vytvorenie štruktúrovaného údajového typu (štruktúry) sa používa kľúčové slovo struct nasledovne: c struct person{ char name[10]; char surname[20]; char sex; // M, F int age; };

  • Zamyslime sa však nad reprezentáciou veku osoby. Je dobré vek udržiavať ako celé číslo? Ak ho totiž budeme udržiavať v takejto forme, musíme ho v pravidelných intervaloch aktualizovať. A otázkou je, že kedy? Znie celkom logicky, že by to mohlo byť 1. januára, ale človek, ktorý má narodeniny až 31. decembra, bude o rok starší už podstatne skôr. Ak chceme mať teda presnú informáciu o veku, toto nie je správne riešenie, ako sa popasovať s týmto problémom. Keď budete mať v druhom ročníku databázové systémy, takéto riešenie pre reprezentáciu údajov budete považovať za porušnie tzv. 3. normálnej formy, pretože sa jedná o tzv. dopočítavaný údaj.

  • Ako teda reprezentovať v počítači dátum a čas?

  • Tento problém zatiaľ odložme bokom a uvažujme nad štruktúrou Person bez položky age: c struct person{ char name[10]; char surname[20]; char sex; // M, F // int age; };

  • Tým sme vytvorili štruktúru s názvom Person. Ak chceme vytvoriť premennú, ktorá bude daného údajového typu, zadeklarujeme ju v tvare: c struct person john;

typedef

  • V jazyku C sa môžete stretnúť s kľúčovým slovom typedef (slide), pomocou ktorého je možné zadefinovať nové meno pre niektorý už existujúci údajový typ. Jeho použitie si môžeme ilustrovať na nasledujúcom príklade: c typedef unsigned char BYTE;
  • Následne v kóde viem zadeklarovať premennú byte tak, že bude typu BYTE: c BYTE byte;
  • Tento zápis je ekvivalentný so zápisom: c unsigned char byte;
  • Ak by sme teda chceli vytvoriť nový údajový typ na základe práve vytvorenej štrukt��ry Person, mohol by vyzerať nasledovne: c typedef struct { char name[10]; char surname[20]; char sex; // M, F // int age; } PERSON;
  • Následne je možné zadeklarovať novú premennú, ktorá bude typu PERSON: c PERSON john;

  • Aj keď jazyk C tento spôsob podporuje, môžete sa stretnúť s rozličnými odporúčaniami ohľadom používania tohto spôsobu. Napríklad vývojári linuxového jadra to majú vyslovene zakázané a pokiaľ vytvárajú vlastné štruktúrované údajové typy, nepoužívajú kľúčové slovo typedef. Rovnako sa budeme správať aj my - v našich projektoch nebudeme používať kľúčové slovo typedef.

size_t

  • S niektorými údajovými typmi, ktoré boli vytvorené pomocou kľúčového slova typedef, sa je možné stretnúť bežne v knižniciach jazyka. Ak sa pozriete napr. na typ návratovej hodnoty funkcie strlen() z knižnice string.h (napr. pomocou man strlen), tak zistíte, že sa jedná o typ size_t a nie o typ int, ako sme si doteraz mysleli a aj používali. Čo za typ je teda size_t?

  • Tento údajový typ je zadefinovaný v hlavičkovom súbore stddef.h (man stddef.h). A je pri ňom uvedené, že:

    Unsigned integer type of the result of the sizeof operator.

  • Takže sa jedná o kladné celé číslo a jeho použitie je vhodné všade tam, kde sa pracuje s dĺžkou alebo indexom, napr. pri iterovaní pomocou cyklu for.

  • Použitie tohto údajového typu si ilustrujeme v rámci dnešných príkladov.

Size of Structured Type

  • Množstvo bytov, ktoré zaberá štruktúra v pamäti, je možné zistiť pomocou operátora sizeof(). Ak teda chcem zistiť, koľko bytov v pamäti zaberá štruktúra person, vložíme do programu tieto riadky: c size_t size = sizeof(struct person); printf("Size is: %lu\n", size);

  • Program vypíše na obrazovku číslo 31, ktoré vznikne súčtom veľkostí jednotlivých členov štruktúry: c printf("%ld + %ld + %ld = %ld\n", sizeof(john.name), sizeof(john.surname), sizeof(john.sex), sizeof(john));

Structure Initialization

  • Inicializácia premennej: c struct person john = { .name = "john", .surname = "smith", .sex = 'M' };

  • alebo c struct person john = { "john", "smith", 'M' };

Prístup ku položkám štruktúry

  • Pre prístup ku konkrétnym položkám štruktúry budeme používať operátor .. Ak teda chceme nastaviť premennej john typu struct person vek, zabezpečíme to zápisom: c john.sex = 'M';

  • Podobne môžeme pristupovať aj ku ostatným položkám štruktúry. Naplníme teda všetky prvky premennej john a vypíšeme ich na obrazovku (struct1.c): ```C #include <stdio.h> #include <string.h>

    struct person{ char name[10]; char surname[20]; char sex; // M, F // int age; };

    int main(){ struct person john;

      john.sex = 'M';
      strcpy(john.name,"John");
      sprintf(john.surname, "Doe");
    
      printf("%s %s is %cn",
          john.name, john.surname, john.sex);

    } ```

  • Keďže však chceme vypisovať obsah aj iných premenných, ktoré sú typu struct person, pripravíme si za týmto účelom funkciu s menom print_person(). Táto funkcia dostane jeden parameter typu tejto štruktúry a vypíše na obrazovku jej hodnoty: c void print_person(struct person person){ printf("%s %s is %cn", person.name, person.surname, person.sex); }

  • V kóde ju potom môžeme použiť nasledovne: c print_person(john);

List of People

  • Vráťme sa však k pôvodnému zámeru - chceme uchovávať informácie o viacerých ľuďoch - nie len o jednom človeku. Ak by sme teda chceli naraz uchovať informácie o viacerých ľuďoch, čo by sme za tým účelom vedeli s výhodou použiť?

  • Pre vytvorenie zoznamu osôb použijeme jednorozmerné pole typu struct person (struct2.c): ```c #include <stdio.h> #include <string.h>

    // structure representing a person struct person { char name[20]; char surname[30]; char sex; // int age; };

    void print_person(struct person person){ printf(“%s %s is %c.n”, person.name, person.surname, person.sex ); }

    int main(){ // read the nr of persons printf(“Enter the number of persons:”); int size; scanf(“%d”, &size);

      // declare list of persons
      struct person list[size];
    
      // populate list
      for(size_t i = 0; i < size; i++){
          printf("Enter %zu person: ", i);
          scanf("%s %s %c", list[i].name, list[i].surname, &list[i].sex);
      }
    
      // traverse the list
      for(size_t i = 0; i < size; i++){
          printf("%zu: ", i);
          print_person(list[i]);
      }

    } ```

  • Aby sme nemuseli stále dookola pridávať osoby znova a znova, môžeme si zoznam pripraviť bokom do súboru (list.txt) a následne presmerovať vstup do nášho programu: bash $ ./main < list.txt

Searching

Conclusion

  • Dnes sme sa teda pozreli na štruktúry a štruktúrované údajové typy v jazyku C. Ukázali sme si ich základné použitie a realizovali sme operáciu vyhľadávania nad poľom štruktúr.

  • Nabudúce budeme v téme pokračovať a pozrieme sa, ako triediť takéto údaje a ukladať ich do súboru.

Additional Resources