Kurz C++ (7.)


Struktury

Zßklady

K vysv∞tlenφ struktur si zase vezmu na pomoc p°φklad adresß°e osob. Ukßzali jsme si, ₧e pomocφ pole m∙₧eme jednoduÜe uklßdat do jednΘ prom∞nnΘ vφc ·daj∙ stejnΘho druhu. Nap°φklad do pole °et∞zc∙ bychom mohli uklßdat jmΘna. Ale my pot°ebujeme uklßdat i adresy, data narozenφ, prost∞ spoustu ·daj∙. M∙₧eme si poradit dalÜφmi poli, ale sami asi uznßte, ₧e to nenφ p°φliÜ elegantnφ. Mnohem lepÜφ °eÜenφ je pou₧itφ tzv. struktur. Jsou to "slo₧enΘ prom∞nnΘ", tedy takovΘ prom∞nnΘ, kterΘ obsahujφ jinΘ prom∞nnΘ (slo₧ky). Struktury se deklarujφ klφΦov²m slovem struct:

struct Clovek {
  char jmeno[30];
  char adresa[50];
  unsigned vek;
};

Deklarovali jsme nov² datov² typ: strukturu, kterß se naz²vß Clovek, a mß 3 slo₧ky: dva °et∞zce (jmeno a adresa) a jednu celoΦφselnou prom∞nnou (vek). Pozor na to, ₧e deklarace struktury musφ konΦit st°ednφkem.


Poznßmka: je zvykem deklarovat struktury mimo t∞la funkcφ. Deklarujte tedy strukturu Clovek mimo funkci main().

Proto₧e se jednß o datov² typ, deklaraci prom∞nn²ch provedeme tak, jak jsme zvyklφ:

Clovek osoba1; // deklarace prom∞nnΘ novΘho datovΘho typu
Clovek osoba2;
Clovek osoba3;

strcpy(osoba1.jmeno, "Jan Novßk"); // p°istupujeme k slo₧kßm struktury
strcpy(osoba1.adresa, "Kocourkov");
osoba1.vek = 30;

strcpy(osoba2.jmeno, "Petr Nejedl²");
*osoba2.adresa = 0; // adresu neznßme, osoba2.adresa je prßzdn² °et∞zec
osoba2.vek = 35;

osoba3 = osoba2;

Deklarovali jsme t°i prom∞nnΘ datovΘho typu Clovek, kterΘ jsme dßle inicializovali. VÜimn∞te si, ₧e p°istup k slo₧kßm struktur se provßdφ operßtorem "." (teΦka). Dßle je na poslednφm °ßdku vid∞t, ₧e struktury je mo₧nΘ vzßjemn∞ p°i°azovat.


Poznßmka: na °ßdku *osoba2.adresa = 0; pou₧φvßme dva operßtory: "*" a ".". ZvφdavΘho Φtenß°e mo₧nß napadne, ₧e na takovou konstrukci je mo₧nΘ se dφvat dv∞ma zp∙soby:

*(osoba2.adresa) = 0;

tzn. vyhodnotφ se osoba2.adresa a na v²slednΘ adrese se ulo₧φ 0, nebo

(*osoba2).adresa = 0;

tzn. provede se dereference osoba2 (aΦkoli to nenφ ukazatel, ale co kdyby byl?) a pak se na prvnφ mφsto slo₧ky adresa v²sledku dereference ulo₧φ 0. Jinak polo₧ena otßzka by mohla znφt: mß v∞tÜφ prioritu operßtor "." (co₧ odpovφdß prvnφ mo₧nosti), nebo operßtor "*"? Sprßvnß je ovÜem prvnφ mo₧nost, co₧ ale znamenß, ₧e kdyby prom∞nnß osoba2 skuteΦn∞ byla ukazatelem, museli bychom k jejφm slo₧kßm p°istupovat pon∞kud t∞₧kopßdnou konstrukcφ se zßvorkami: (*osoba2).adresa). OvÜem, jak uvidφme dßle, existuje zvlßÜtnφ operßtor pro p°φstup k slo₧kßm ukazatele na strukturu.

Struktury je mo₧nΘ vno°ovat (n∞jakß slo₧ka struktury je jinß struktura), ale nenφ mo₧nΘ, aby slo₧ka struktury byla prßv∞ deklarovanß struktura. Jin²mi slovy, nenφ mo₧n² takov² zßpis:

struct Clovek {
  char jmeno[30];
  char adresa[50];
  unsigned vek;
  Clovek otec;
};

Ukßzali jsme si, ₧e datov² typ struktura deklarujeme klφΦov²m slovem struct. Existuje jeÜt∞ jeden zp∙sob deklarace, kter² je dokonce o n∞co mocn∞jÜφ (umo₧≥uje deklarovat nap°. datov² typ "ukazatel na strukturu"): je jφm klφΦovΘ slovo typedef. Jeho prost°ednictvφm je mo₧nΘ nap°φklad p°ejmenovat datov² typ na jin² (pro v∞tÜφ p°ehlednost):

typedef unsigned int uint;

Tφmto p°φkazem jsme deklarovali nov² datov² typ uint (v tomto okam₧iku uint znamenß to samΘ, co unsigned int). TakΘ m∙₧eme deklarovat nap°φklad datov² typ ukazatel na int:

typedef int *pint;

Pou₧itφ takovΘho datovΘho typu by bylo nap°φklad takovΘ:

int i;
pint p; // to samΘ jako int *p

p = &i;

┌pln∞ stejn∞ lze deklarovat nov² datov² typ struktura:

typedef struct Clovek {
  char jmeno[30];
  char adresa[50];
  unsigned vek;
} NovyClovek;

Nynφ lze deklarovat prom∞nnou jak datovΘho typu Clovek, tak i NovyClovek (datov² typ Clovek jsme deklarovali klφΦov²m slovem struct, datov² typ NovyClovek zase klφΦov²m slovem typedef) – v²Üe uveden² zßpis je to samΘ jako:

struct Clovek {
  char jmeno[30];
  char adresa[50];
  unsigned vek;
};

typedef Clovek NovyClovek;

Uvedenφ n∞jakΘho nßzvu jak pro struct, tak i pro typedef je zbyteΦnΘ, tak₧e se v∞tÜinou nßzev za struct neuvßdφ. JeÜt∞ bych cht∞l podotknout, ₧e deklarace struktur klφΦov²m slovem typedef je spφÜe zßle₧itost jazyka C, v C++ si a₧ na jednu v²jimku, kterou si ukß₧eme dßle, vystaΦφme s klφΦov²m slovem struct.


Poznßmka: deklarace prom∞nnΘ datovΘho typu struktura se provßdφ v C uvedenφm klφΦovΘho slova struct:

struct Clovek {
    ...
}

struct Clovek osoba;                    // uvedenφ struct je povinnΘ


Proto₧e to je nepohodlnΘ, v C se pou₧φvß prßv∞ typedef, kter² tuto nev²hodu odstra≥uje.

P°i deklaraci prom∞nn²ch odvozen²ch od struktur je mo₧nΘ je i inicializovat:

Clovek osoba = {"Jan Novßk", "Kocourkov", 30};

Musφme dodr₧et po°adφ slo₧ek ve struktu°e, a takΘ musφme dbßt, abychom neinicializovali vφc slo₧ek, ne₧ mß struktura (to by skonΦilo chybou). Ale nemusφme inicializovat vÜechny slo₧ky a pak ty, kterΘ neinicializujeme, budou mφt nulovou hodnotu:

Clovek osoba = {"Jan Novßk", "Kocourkov"};       // vynechßvßme slo₧ku vek
cout << osoba.vek;                               // vypφÜe se 0


Ukazatele na struktury

Jako i u zßkladnφch datov²ch typu, je mo₧nΘ se strukturami pracovat pomocφ ukazatel∙. Deklarace se provßdφ naprosto stejn∞:

Clovek osoba;
Clovek *p;

p = &osoba;

Jak jsme si °ekli v²Üe, p°φstup k slo₧kßm nebudeme provßd∞t operßtorem ".", ale operßtorem Üipka ("->"):

Clovek osoba1;

strcpy(osoba1->jmeno, "Jan Novßk");       
strcpy(osoba1->adresa, "Kocourkov");
osoba1->vek = 30;


Poznßmka: pφÜete-li Φeskou klßvesnicφ, m∙₧e b²t problΘm psanφ znaku "v∞tÜφtko". Nemusφte kv∙li tomu p°epφnat klßvesnici, zkuste klßvesovou zkratku Alt + > (jednß se o prav² Alt).

V²Üe jsme si °ekli, ₧e slo₧kou struktury nem∙₧e b²t prßv∞ deklarovanß struktura. Slo₧kou struktury ale m∙₧e b²t ukazatel na prßv∞ deklarovanou strukturu.

struct Uzel {
    int hodnota;
    Uzel *dalsi;
};

Takov² datov² typ se pou₧φvß ve spojov²ch seznamech, o kter²ch si budeme vφce povφdat v jednom z dalÜφch dφl∙, prozatφm prosφm berte uveden² p°φklad jako teoretick².

V p°φpad∞, ₧e strukturu deklarujeme klφΦov²m slovem typedef, pot°ebujeme ve struktu°e slo₧ku ukazatel na prßv∞ deklarovanou strukturu, je t°eba uvΘst n∞jak² nßzev i za struct, je to toti₧ jedin² zp∙sob jak se na odkazovat na strukturu, kterou prßv∞ deklarujeme:

typedef struct Uzel {
    int hodnota;
    Uzel *dalsi;
} Uzel;

A koneΦn∞ si m∙₧eme ukßzat i p°φpad, na kter² samotnΘ klφΦovΘ slovo struct nestaΦφ: chceme-li deklarovat datov² typ "ukazatel na strukturu" musφme pou₧φt typedef:

typedef struct {
    char jmeno[30];
    char adresa[50];
    unsigned vek;
} *PClovek;

Struktury jako parametry funkcφ

V jednom z minul²ch dφl∙ jsme si °ekli, ₧e nejΦast∞ji se parametry funkcφ p°edßvajφ hodnotou, co₧ p°edstavuje zkopφrovßnφ parametr∙ do funkce. Struktury se takΘ kopφrujφ, ale zde m∙₧e nastat problΘm: zkopφrovßnφ v∞tÜφch struktur nenφ p°φliÜ efektivnφ. Mnohem lepÜφm °eÜenφm je p°edßvßnφ struktur operßtorem reference:

void vypisOsobu(Clovek &osoba) {
    cout << "JmΘno: " << osoba.jmeno << "\n";
    cout << "P°φjmenφ: " << osoba.adresa << "\n";
    cout << "V∞k: " << osoba.vek << "\n";
}


╪ekli jsme si, ₧e reference je ukazatel, kter² se syntakticky chovß jako prom∞nnß danΘho datovΘho typu, tak₧e p°i zavolßnφ funkce vypisOsobu() dojde ke zkopφrovßnφ pouze 4 byt∙.


Poznßmka: dalÜφ zp∙sob p°edßvßnφ struktur je ukazatelem, ale to je praktika pou₧φvanß spφÜe v jazyce C. Setkßte se s tφm nap°φklad budete-li psßt programy pro Windows.

P°φklad

Dnes si ukß₧eme n∞jak² v∞tÜφ p°φklad, bude to adresß° osob, do kterΘho budeme moci uklßdat jmΘno a p°φjmenφ, ulici, m∞sto a telefonnφ Φφslo. Adresß° mß umo₧≥ovat p°idßvßnφ osoby, jejφ vymazßnφ, a hledßnφ podle jmΘna. Uklßdat do souboru adresß° nebude um∞t, to ani my jeÜt∞ neumφme, ale p°idßme to p°φÜt∞.

ZaΦneme nßÜ program rozhodnutφm, jak dlouhΘ budou °et∞zce do kter²ch budeme uklßdat data, a deklarovßnφm p°φsluÜnΘ struktury:

const unsigned DELKA_JMENO = 30;
const unsigned DELKA_ULICE = 40;
const unsigned DELKA_MESTO = 30;
const unsigned DELKA_TELEFON = 20;

struct Osoba {
    char jmeno[DELKA_JMENO];
    char ulice[DELKA_ULICE];
    char mesto[DELKA_MESTO];
    char telefon[DELKA_TELEFON];
};

Dßle bychom si m∞li rozmyslet jak budeme uklßdat vφce osob. Pravd∞podobn∞ do pole, ale pole nßm ne°ekne, kolik osob v n∞m mßme ulo₧eno, to si musφme pamatovat v dalÜφ prom∞nnΘ, nazv∞me ji pocet. Tyto dva ·daje blφzce souvisφ, tak₧e je m∙₧eme takΘ dat do n∞jakΘ struktury, kterß se bude naz²vat nap°. Osoby. V souvislosti s polem musφme jeÜt∞ rozhodnout, jakß bude jeho velikost (poΦet prvk∙). Abychom mohli tento poΦet lehce zm∞nit pokud to budeme n∞kdy pot°ebovat, deklarujeme si k tomu konstantu:

const unsigned MAX_POCET_OSOB = 100;

struct Osoby {
    Osoba pole[MAX_POCET_OSOB];
    int pocet;
};

DatovΘ typy ji₧ mßme, poj∩me si nynφ napsat n∞jakΘ funkce pro prßci s nimi. P°edn∞ budeme pot°ebovat n∞jakou funkci, kterß bude inicializovat prom∞nnou odvozenou od datovΘho typu Osoby, a to nastavenφm slo₧ky pocet na nulu (na zaΦßtku programu je adresß° prßzdn², nejsou v n∞m ₧ßdnΘ osoby). Tato funkce dostane jako parametr prom∞nnou, kterou chceme inicializovat (samoz°ejm∞ referencφ):

void osobyInit(Osoby &osoby) {
    osoby.pocet = 0;
}

Dßle budeme pot°ebovat n∞jakou funkci pro ulo₧enφ novΘ osoby. Jako parametry dostane prom∞nnou typu Osoby a prom∞nnou typu Osoba, a bude vracet hodnotu bool podle toho, zda se ulo₧enφ poda°ilo Φi ne:

bool osobyPridej(Osoby &osoby, Osoba &osoba) {
    if (osoby.pocet < MAX_POCET_OSOB) {
        osoby.pole[osoby.pocet] = osoba;
        osoby.pocet++;
        return true;
    }
    else
        return false;
}

Ulo₧enφ prob∞hne zkopφrovßnφm novΘ osoby do pole na mφsto, kterΘ udßvß prßv∞ prom∞nnß osoby.pocet (je-li nap°φklad pocet = 3, jsou v poli obsazenΘ polohy 0, 1 a 2, dalÜφ volnß poloha je tedy prßv∞ 3). Prom∞nnou pocet nßsledn∞ zv∞tÜφme o jedna. Samoz°ejm∞ jeÜt∞ p°ed zkopφrovßnφm musφme zkontrolovat, zda pole nenφ nßhodnou plnΘ, v tomto p°φpad∞ nenφ kam uklßdat a funkce vracφ hodnotu false. V p°φpad∞ ·sp∞chu vracφme true.

Dßle budeme pot°ebovat funkci, kterß ve struktu°e Osoby vyhledß osobu se zadan²m jmΘnem. Tato funkce dostane jako parametry prom∞nnou typu Osoby, ve kterΘ se vyhledß, a takΘ °et∞zec obsahujφcφ jmΘno, kterΘ se mß vyhledat. Prochßzφme pole osob a porovnßvßme jmΘna se zadan²m jmΘnem. K porovnßvßnφ pou₧ijeme funkci strnicmp(), kterß porovnßvß n∞jak² zadan² poΦet znak∙ v °et∞zcφch bez ohledu na velkß/malß pφsmena. Funkce vracφ polohu v poli v p°φpad∞ nalezenφ, a -1 jinak (proto₧e -1 nenφ platn² index do pole):

int osobyHledej(Osoby &osoby, char *jmeno) {
    int i;

    for (i = 0; i < osoby.pocet; i++) {
        if (!strnicmp(osoby.pole[i].jmeno, jmeno, DELKA_JMENO)) {
            return i;
        }
    }

    return -1;
}

Pot°ebujeme jeÜt∞ funkci na vymazßnφ osoby, co₧ je mo₧nß nejslo₧it∞jÜφ akce. Nenφ-li vymazanß osoba poslednφ v poli, bude pot°eba veÜkerΘ osoby za nφ p°esunout o jednu polohu doleva, jak je vid∞t na obrßzku (ma₧e se osoba na poloze 1):

Parametry funkce budou prom∞nnß typu Osoby a polohu v poli, udßvajφcφ osobu, kterß se mß vymazat. Samoz°ejm∞ je t°eba zkontrolovat platnost polohy (musφ to b²t vetÜφ nebo rovna nule, a nesmφ b²t v∞tÜφ nebo rovno existujφcφmu poΦtu osob. Nakonec je t°eba snφ₧it poΦet osob.

bool osobyVymaz(Osoby &osoby, int poloha) {
    int i;

    if (poloha < 0 || poloha >= osoby.pocet)
        return false;

    for (i = poloha + 1; i < osoby.pocet; i++)
        osoby.pole[i - 1] = osoby.pole[i];
    osoby.pocet--;
    return true;
}

Poslednφ funkci pro prßci se strukturou Osoby je funkce, kterß vracφ true je-li v poli mφsto pro novou osobu, a false jinak:

bool osobyJeMisto(Osoby &osoby) {
    return osoby.pocet < MAX_POCET_OSOB;
}

Nynφ je pot°eba si napsat funkce pro u₧ivatelskΘ rozhranφ (funkci, kterß p°eΦte ·daje o osob∞ z klßvesnice a z nich vytvo°φ novou prom∞nnou typu Osoba kterou p°idß do seznamu osob, dßle funkci pro vyhledßnφ a vymazßnφ osoby). K tomu je pot°eba vstup z klßvesnice a tak si vytvo°φme n∞jakou obecnou funkci prßv∞ pro tento ·Φel. V jednom z prvnφch dφl∙ jsme si °ekli, ₧e vstup z klßvesnice lze p°eΦφst funkcφ scanf(). Nap°φklad chceme-li p°eΦφst °et∞zec, pou₧ijeme:

scanf("%s", retezec);

Takov² p°φstup mß ale jednu velkou chybu a to je ₧e funkce scanf() by mohla ulo₧it do prom∞nnΘ rezetec vφc znak∙, ne₧ by se tam mohlo vejφt (velikost prom∞nnΘ neznß a ulo₧φ tolik znak∙, kolik zadß u₧ivatel). Pou₧ijeme tedy trochu jin² formßt, kter²m lze udßvat nejvyÜÜφ poΦet, kter² lze do v²sledku (prom∞nnΘ retezec) ulo₧it:

scanf("%30s", retezec);

V tomto p°φpad∞ je tedy nejvyÜÜφ poΦet znak∙ 30. OvÜem zapφÜe-li se do v²sledku maximßlnφ poΦet znak∙, pak se nezapφÜe nulov² ukonΦovacφ znak, kter² musφme doplnit sami.

DalÜφm problΘmem funkce scanf() je, ₧e chßpe mezeru jako odd∞lovaΦ polφ. To mß za nßsledek ulo₧enφ do v²sledu pouze znak∙ do prvnφ mezery. Ale to lze takΘ vy°eÜit: mφsto formßtu %s lze zadat seznam platn²ch znak∙, nebo naopak seznam neplatn²ch znak∙. To se provßdφ uvedenφm seznam platn²ch znak∙ do hranat²ch zßvorek:

scanf("%[abc]", retezec);
scanf("%[a-z]", retezec);

V prvnφm p°φpad∞ jsou platnΘ znaky a, b a c, v druhΘm znaky a a₧ z. Seznam neplatn²ch znak∙ zase zadßme uvedenφm st°φÜky hned po otevφracφ hranatΘ zßvorce:

scanf("%[^abc]", retezec);

To znamenß, ₧e platnΘ znaky jsou vÜechny a₧ na a, b a c. My pou₧ijeme formßt "%30[^\n]", kter² udßvß, ₧e platnΘ znaky jsou vÜechny a₧ na znak konec °ßdku, a ₧e se mß ulo₧it nejv²Üe 30 znak∙

DalÜφ zßdrhel souvisφ s nejvyÜÜφm poΦtem znak∙ v²sledku. Znaky, kterΘ u₧ivatel zadß navφc, se neztrßcejφ, n²br₧ z∙stanou ulo₧eny ve vyrovnßvacφ pam∞ti, a funkce scanf() je bude zpracovßvat p°i dalÜφm zavolßnφ. P°ed ka₧d²m zavolßnφm musφme tedy tuto vyrovnßvacφ pam∞¥ vyprßzdnit, co₧ provedeme funkcφ fflush(), jejφ₧ p°esn² v²znam si vysv∞tlφme p°φÜt∞:

fflush(stdin);

┌pln∞ poslednφ v∞c na kterou musφme dßt pozor je, ₧e kdy₧ u₧ivatel nezadß nic, funkce scanf() neulo₧φ do v²sledku nic, tedy ani nulov² ukonΦovacφ znak. Ten si musφme doplnit sami na zßklad∞ nßvratovΘ hodnoty scanf(). Nßvratovß hodnota uvßdφ kolik polφ bylo zpracovßno (podle naÜeho formßtovacφho °et∞zce "%30[^\n]" jedno pole), nebo 0 pokud nebylo zpracovßno nic. Nynφ si m∙₧eme napsat funkcφ, kterß p°eΦte z klßvesnice °et∞zec za podmφnek, kterΘ jsme uvedli. Funkce dostane jako parametr °et∞zec, kam se mß v²sledek ulo₧it, a nejvyÜÜφ poΦet znak∙, kter² se mß do v²sledku ulo₧it. Z tohoto d∙vodu musφme vytvo°it formßtovacφ °et∞zec, pomocφ funkce sprintf(), kterß funguje jako printf(), ale v²sledek ulo₧φ do °et∞zce:

const char *strFmt = "%%%u[^\n]";              // %% znamenß znak procento, dßle %u se nahradφ n∞jak²m cel²m Φφslem                                                     // v²sledek je nap°. "%30[^\n]"

const unsigned MAX_FORMAT = 32;                     // dΘlka pro °et∞zec, do kterΘho vytvß°φme formßtovacφ °et∞zec

void precti(char *vysledek, unsigned maxDelka) {
    char fmt[MAX_FORMAT];                           // format. °et∞zec
    sprintf(fmt, strFmt, maxDelka);                 // vytvß°φme formßtovacφ °et∞zec
    fflush(stdin);                                  // vyprßzdn∞nφ vyrovnßvacφ pam∞ti
    if (scanf(fmt, vysledek))                       // Φtenφ
        vysledek[maxDelka - 1] = 0;                 // scanf vrßtilo 1, tak₧e pro jistotu dopl≥ujeme nulov² ukonΦovacφ znak
    else
        *vysledek = 0;                             // scanf vrßtilo 0, ta₧e dopl≥ujeme na zßΦßtek °et∞zce nulov² ukonΦovacφ znak                                                     // vysledek je tedy p°ßzdn² °et∞zec
}

Nynφ si m∙₧eme napsat funkce pridej(), hledej() a vymaz(), jejich v²pis najdete p°ilo₧en². Funkce hledej() a vymaz() pou₧φvajφ funkci hledejPolohu(), kterß p°eΦte z klßvesnice jmΘno, kterΘ se mß vyhledat, pop°. vymazat, a vracφ nalezenΘ osoby v poli nebo -1.

Ve funkci main() je pouze k≤d, kter² vytvß°φ jednoduchΘ menu. U₧ivatel volφ z menu pomocφ jednoznakov²ch zkratek. K p°eΦtenφ znaku z klßvesnice pou₧ijeme funkci getche() z hlaviΦkovΘho souboru conio.h. TakΘ je na zaΦßtku pot°eba vypnout vyrovnßvacφ pam∞¥ objektu cout, jinak by se vypsanΘ °et∞zce nezobrazovaly na obrazovce hned, ale jen "jednou za Φas" (po napln∞nφ vyrovnßvacφ pam∞ti). Vyrovnßvacφ pam∞¥ se vypφnß volßnφm funkce objektu cout, ale tomu zatφm nemusφte rozum∞t, vÜechno si to povφme a₧ si vysv∞tlφme t°φdy a objekty.

void main() {
    Osoby osoby;
    char volba = -1;

    cout.setf(ios::unitbuf);                       // nastavujeme v²pis na obrazovce po ka₧dΘ v²pis do objektu cout

    osobyInit(osoby);

    while (volba != 'k' && volba != 'K') {
        cout << strZadejVolbu;
        volba = getche();
        cout << endl;
       
        switch (volba) {
        case 'p':
        case 'P':
            if (!pridej(osoby))
                cout << errAdrPlny;
            break;

        case 'h':
        case 'H':
            if (!hledej(osoby))
                cout << errNenalezeno;
            break;

        case 'v':
        case 'V':
            if (!vymaz(osoby))
                cout << errNenalezeno;
        }

        cout << endl;
    }
}

P°φklad rozhodn∞ nenφ p°φliÜ jednoduch². Zp∙sobujφ to r∙znΘ kontroly zda vÜechno prob∞hlo v po°ßdku, a takΘ komplikace kolem funkce scanf(). Ale programovßnφ u₧ je takovΘ, musφte dßvat pozor na vÜechno. D∞kuji za pozornost a t∞Üφm se p°φÜtφ m∞sφc nashledanou.
 

Andrei Badea