Cykly alebo opakovanie

Ako by ste 10 krát vypísali "ahoj"? Spravili by ste to takto?

printf("ahoj\n");
printf("ahoj\n");
printf("ahoj\n");
printf("ahoj\n");
printf("ahoj\n");
printf("ahoj\n");
printf("ahoj\n");
printf("ahoj\n");
printf("ahoj\n");
printf("ahoj\n");

A čo keby ste chceli vypísať "ahoj" tisíckrát, alebo milionkrát?

Nebojte sa, aj na toto programátori mysleli a vymysleli cykly. Najjednoduchší cyklus je while cyklus. Jeho syntax je while (<podmienka>) <príkaz> prípadne namiesto <príkazu> môžeme napísať viacero príkazov zabalených v {}.

Tento cyklus funguje veľmi jednoducho - dokým je podmienka splnená, opakuje príkaz. Vysvetlíme si to na príklade.

int i = 0;
while (i < 10) {
    printf("ahoj\n");
    i = i + 1;
}

Najprv nastavíme i na 1. Následne budeme vykonávať vnútro {} pokiaľ i < 10. Keďže vo vnútri {} zväčšíme i vždy o 1, celý cyklus sa zopakuje 10 krát, až kým sa nestane, že i == 10 a teda !(i < 10) a teda cyklus skončí. Preto aj tento program vypíše "ahoj" 10 krát. Prerobiť ho, aby vypísal "ahoj" tisíckrát by nám nerobilo žiaden problém však?

Ešte poznamenajme, že miesto i = i+1 vieme písať i += 1 alebo dokonca i++, či ++i.

Vyššie uvedená konštrukcia ­— nainicializujeme premennú, pokým premenná nie je nejaká, robíme niečo je natoľko častá, že jej programátori vymysleli nový názov.

for (<príkaz1>; <podmienka>; <príkaz2>)
    <príkaz-telo-cyklu>

Najprv vykoná <príkaz1>, následne kým platí podmienka vykonáva <príkaz-telo-cyklu> a <príkaz2>.

Vyššie uvedený program s whileom teda vieme prepísať na

for (int i = 0; i < 10; ++i)
    printf("ahoj\n");

Samozrejme, premennú i môžeme využiť aj v tele cyklu. Nasledovný program vypíše čísla 0 až 7, každé na zvlášť riadku.

for (int i = 0; i < 8; ++i)
    printf("%d\n", i);

Cvičenie: Napíšte program, ktorý vypíše prvých 50 nepárnych čísel (1, 3, 5 \dots) Zvyšok po delení dvoma (paritu) vieme zistiť napríklad operátorom %. a % b vráti zvyšok a po delení b. Napríklad 47 % 10 == 7, 10 % 2 == 0. Pozor treba dávať na záporné čísla, -13 % 5 == -3.

Riešenie Predvedieme si tri spôsoby.
for (int i = 0; i < 100; ++i)
    if (i % 2 == 1)
        printf("%d\n", i);

for (int i = 0; i < 50; ++i)
    printf("%d\n", 2 * i + 1);

for (int i = 1; i < 100; i += 2)
    printf("%d\n", i);

Pri cykloch si treba dávať pozor, keďže sa môžu zacykliť a potom váš program bude bežať donekonečna (kým ho nezabijete). Príklady nekonečných cyklov sú napr. while (true); for (int i = 10; i > 0; ++i); ale aj while (a < 7); (lebo premenná a sa v cykle nemení).

Cykly a podmienky sa samozrejme dajú do seba ľubovoľne veľakrát vkladať, napríklad ako v nasledujúcom nezmyselnom programe.

int a = 7;
while (a < 70) {
    if (a == 2) {
        a = 31;
    } else {
        for (int i = 0; i < a; ++i) {
            while (i < a) ++i;
        }
    }
}

Keď už teda ľahkovážne pcháme všelikam zátvorky {}, zíde sa nám vedieť jedna vec o premenných ­— majú obmedzenú platnosť. Každá premenná existuje len v rámci {} v ktorých bola vyrobená. Potom proste zanikne.

int a = 0; // toto je globalna premenna, ta existuje stale a vsade

int main(){
    int b = 0; // tato premenna existuje iba vnutri main()

    if (true) {
        int c = 1;
    }
    c = 7; // !! chyba !! c prestalo existovat na predoslom riadku
    if (true) {
        c = 7; // !! stale chyba !!
    }
    int c = 1;
    if (true) {
        c = 7; // OK
        int b = 3; /*
         Vyrobit novu premennu b vam sice kompilator dovoli
         ale fakt to nerobte (nenazyvajte dve premenne
         vo vnorenych blokoch rovnako). Niekedy sa to moze spravat
         cudne.
        */
    }

    for (int i; i < a; ++i){
        i += 1; // OK
    }
    i = 7; // !! zasa chyba !! premenna i existovala len v ramci for-cyklu
}