Slevový týden - Srpen
30 % bodů zdarma na online výuku díky naší Slevové akci!
Pouze tento týden sleva až 80 % na e-learning týkající se Javy.

Lekce 12 - Cykly v C# .NET podruhé - do-while, break a continue

V minulé lekci, Podmínky v C# podruhé - Ternární výraz a propadávací switch, jsme se věnovali další syntaxi podmínek.

Na úvod by bylo dobré podotknout, že dnešní lekce obsahuje méně používané praktiky a slouží hlavně k tomu, aby vás nepřekvapily v cizím kódu. Není příliš důležité, abyste je sami uměli používat.

do...while

Cyklus while již dobře známe. Méně používaný do...while se liší pouze tím, že se vždy vykoná nejméně jednou. Jeho podmínka je totiž umístěna až za tělem cyklu. Vypadá tedy takto:

do
{
    // kód...
} while (podmínka)

I k zapsání tohoto cyklu můžeme využít snippet ve Visual Studio: Napíšeme do a dvakrát stiskněme Tabulator. Zbytek cyklu se sám dopíše.

Příklad

Použití do-while cyklu si ukažme na naší kalkulačce z lekce o cyklech. Pro zkrácení příkladu nebudeme používat verzi s ověřením uživatelských vstupů.

Varianta s while

V kalkulačce jsme použili cyklus while, který umožnil celý program opakovat a tak zadávat další a další příklady. Kód vypadal takto (jedná se o verzi s konstrukcí switch):

Console.WriteLine("Vítejte v kalkulačce");
string pokracovat = "ano";
while (pokracovat == "ano")
{
    Console.WriteLine("Zadejte první číslo:");
    float a = float.Parse(Console.ReadLine());
    Console.WriteLine("Zadejte druhé číslo:");
    float b = float.Parse(Console.ReadLine());
    Console.WriteLine("Zvolte si operaci:");
    Console.WriteLine("1 - sčítání");
    Console.WriteLine("2 - odčítání");
    Console.WriteLine("3 - násobení");
    Console.WriteLine("4 - dělení");
    int volba = int.Parse(Console.ReadLine());
    float vysledek = 0;
    switch (volba)
    {
        case 1:
            vysledek = a + b;
            break;
        case 2:
            vysledek = a - b;
            break;
        case 3:
            vysledek = a * b;
            break;
        case 4:
            vysledek = a / b;
            break;
    }
    if ((volba > 0) && (volba < 5))
        Console.WriteLine("Výsledek: {0}", vysledek);
    else
        Console.WriteLine("Neplatná volba");
    Console.WriteLine("Přejete si zadat další příklad? [ano/ne]");
    pokracovat = Console.ReadLine();
}
Console.WriteLine("Děkuji za použití kalkulačky, aplikaci ukončíte libovolnou klávesou.");
Console.ReadKey();

Všimněte si, že jsme se u této varianty s while museli zamyslet nad výchozí hodnotou proměnné pokracovat, které jsme nastavili hodnotu "ano", aby podmínka byla splněna pro první průchod cyklem. Vymyslet výchozí hodnotu může být ale někdy poměrně složité a třeba i vyžadovat pomocnou proměnnou.

Varianta s do-while

Když použijeme cyklus do-while, tak výchozí hodnotu dané proměnné nemusíme řešit:

Console.WriteLine("Vítejte v kalkulačce");
string pokracovat;
do
{
    Console.WriteLine("Zadejte první číslo:");
    float a = float.Parse(Console.ReadLine());
    Console.WriteLine("Zadejte druhé číslo:");
    float b = float.Parse(Console.ReadLine());
    Console.WriteLine("Zvolte si operaci:");
    Console.WriteLine("1 - sčítání");
    Console.WriteLine("2 - odčítání");
    Console.WriteLine("3 - násobení");
    Console.WriteLine("4 - dělení");
    int volba = int.Parse(Console.ReadLine());
    float vysledek = 0;
    switch (volba)
    {
        case 1:
            vysledek = a + b;
            break;
        case 2:
            vysledek = a - b;
            break;
        case 3:
            vysledek = a * b;
            break;
        case 4:
            vysledek = a / b;
            break;
    }
    if ((volba > 0) && (volba < 5))
        Console.WriteLine("Výsledek: {0}", vysledek);
    else
        Console.WriteLine("Neplatná volba");
    Console.WriteLine("Přejete si zadat další příklad? [ano/ne]");
    pokracovat = Console.ReadLine();
} while (pokracovat == "ano");

Console.WriteLine("Děkuji za použití kalkulačky, aplikaci ukončíte libovolnou klávesou.");
Console.ReadKey();

break a continue

Běh cyklu je potřeba někdy přerušit, k tomu máme následující 2 klíčová slova.

break

Příkaz break ukončuje aktuální cyklus. Používá se nejčastěji pokud pomocí cyklu nalezneme nějakou položku v kolekci a dále již v jejím procházení nechceme pokračovat. Nebudeme tak dále zbytečně prohledávat zbytek kolekce, když již máme to, co jsme hledali.

Příklad

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Představme si, že máme pole položek a chceme v nich nějakou najít. Že můžeme použít metodu IndexOf() nebo Contains()? Pokud půjde o pole, tak ano, ale některé kolekce ji nemají a/nebo chceme hledat pomocí nějaké jiné vlastnosti, než kterou tyto metody zohledňují. Pak si vyhledávání musíme napsat hezky ručně cyklem nebo použít výrazně pokročilejší konstrukce, než nyní ovládáme.

Představme si, že máme velké a malé štítky na sklenice a chceme použít na všechny sklenice buď jedny nebo druhé. Zajímá nás tedy, zda se text všech popisek vejde na malé štítky. Napíšeme program, který zjistí, zda je v poli slovo delší než 6 znaků. Pokud ano, musíme použít větší štítky.

Začneme cyklem procházet jednotlivá slova a jakmile najdeme slovo delší než 6 znaků, tak si uložíme jeho index. Zatím stále nic nového pod sluncem. V tu samou chvíli ovšem pomocí break cyklus ukončíme.

Ukázka použití break:

string[] seznamOvoce = {"Jablka", "Hrušky", "Švestky", "Meruňky", "Jahody", "Třešně"};
int hledanyIndex = -1;

for (int i = 0; i < seznamOvoce.Length; i++)
{
    if (seznamOvoce[i].Length > 6)
    {
        hledanyIndex = i;
        break;
    }
}

if (hledanyIndex >= 0)
    Console.WriteLine("První slovo delší než 6 znaků: " + seznamOvoce[hledanyIndex]);

Výstup:

Konzolová aplikace
První slovo delší než 6 znaků: Švestky

Příkaz break se v praxi často nahrazuje příkazem return za předpokladu, že je kód v naší vlastní metodě. Vlastní metody se ale naučíme deklarovat až v navazujícím kurzu Základy objektově orientovaného programování v C#. Potom break doporučuji spíše nepoužívat, správnější varianta je kód pro práci s kolekcí vyčlenit do samostatné funkce.

continue

Příkaz continue je podobný break. Používá se však k ukončení pouze aktuální iterace (průběhu) cyklu a ne celého cyklu. Cyklus poté rovnou přechází na další iteraci. Použití continue můžeme najít např. při validování položek při procházení nějaké kolekce.

Příklad

Představme si, že máme od uživatele zadaná čísla a tato čísla chceme sečíst. Uživatel tato čísla zadá jako jeden řetězec, kde každé číslo je oddělené čárkou. Bohužel musíme počítat i s tím, že uživatel zadá místo čísla nějaký nesmysl. Řešení by mohlo vypadat následovně:

string cislaRetezec = "10,50,abcd,30,9";
// rozložení řetězce do pole
string[] cislaPole = cislaRetezec.Split(',');
int soucet = 0;
foreach (string cislo in cislaPole)
{
    // převedení řetězce na celé číslo
    int celeCislo;

    if(!int.TryParse(cislo, out celeCislo))
        continue;

    soucet += celeCislo;
}
Console.WriteLine("Součet je: " + soucet);

Výstup:

Konzolová aplikace
Součet je: 99

Program sečte všechny správně zadané hodnoty, tedy ty, u kterých metoda TryParse() vrátila hodnotu true. U nesprávně zadaných hodnot je aktuální iterace ukončena. Místo continue bychom samozřejmě mohli použít jen příkaz if, kód bychom tím ovšem zbytečně zanořili.

Zkrácený zápis cyklu for

Následující konstrukce jsou zde pro ukázku co vše je možné potkat v cizích kódech a není dobrý důvod je používat!

Cyklus for je možné zapsat takto zkráceně, bez těla cyklu:

for (int i = 0; i < 10; Console.Write(i++));

Výstup:

Konzolová aplikace
0123456789

Psát logiku průběhu běhu cyklu i logiku v cyklu na jeden řádek ovšem není intuitivní. Navíc se tak může snadno zapomenout na inkrementaci proměnné nebo ji inkrementovat vícekrát. 

Dokonce není nutné v hlavičce cyklu for uvádět jakýkoliv příkaz:

for (;;)
{
    // nekonečný cyklus
}

Tento zápis je stejný jako:

while (true)
{
    // nekonečný cyklus
}

Oba výše deklarované cykly běží do nekonečna a můžete je potkat ve špatně napsaných zdrojových kódech spolu s příkazy break, které z nich potom za nějakých podmínek vyskakují.

Jakmile podmínka není přímo v deklaraci cyklu, je poměrně nepřehledné zjistit kdy cyklus vůbec skončí a snadné udělat z takového cyklu nechtěně nekonečný. To platí zvláště, když z cyklu vyskakujeme více podmínkami a nepokryjeme všechny možné případy.

Ač dnešní lekce obsahovala standardní gramatiku C# .NET pro cykly, z nových konstrukcí používejte pouze do-while a continue. Přechodně ještě můžete používat break, než se dostaneme k objektům :)

V příští lekci, Vícerozměrná pole v C# .NET, si uvedeme díl o vícerozměrných polích.


 

Předchozí článek
Podmínky v C# podruhé - Ternární výraz a propadávací switch
Všechny články v sekci
Základní konstrukce jazyka C# .NET
Článek pro vás napsal Radek Vymětalík
Avatar
Jak se ti líbí článek?
3 hlasů
...
Aktivity (6)

 

 

Komentáře

Avatar
David Holohlavský:20. března 17:38

Ahoj, díky za článek. ;-) Skvěle napsaný, jen jsem našel překlep v části continue for (string cislo in cislaPole), tak by mělo být foreach (string cislo in cislaPole). :-)

 
Odpovědět
20. března 17:38
Avatar
Radek Vymětalík
Super redaktor
Avatar
Odpovídá na David Holohlavský
Radek Vymětalík:20. března 19:22

Díky za upozornění, koukneme na to. :-)

 
Odpovědět
20. března 19:22
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovědět
24. března 17:06
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Marek Vajčner:30. března 11:31

Zajímavý článek. Zdá se, že věta "všeho moc, škodí" (v daném případě přílišné zkracování kódu) platí také v programování.

 
Odpovědět
30. března 11:31
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Pratos Zesporaku:24. dubna 16:43

Zkoušel jsem DO_WHILE. S vašim stringem to funguje, ale když jsem používal bool, tak to nejde - teda jde, ale musí se ten bool nejdřív nadefinovat (true/false) což tedy pak ztrácí smysl použít DO_WHILE, proč - dělám něco špatně?

//DO_WHILE
string pismeno;
bool VolbaC;
bool PlatnaVolbaC;

// Tady ho musim nadefinovat, jinak mi dole za WHILE hlásí error
VolbaC = false;
do
{
    Console.WriteLine("Napište písmeno:");
    pismeno = Console.ReadLine();
    Console.WriteLine("Napsali jste písmeno: {0}", pismeno);
    Console.WriteLine("Chcete napsat další písmeno A/N?");

    // Tady ho musim nadefinovat, jinak mi dole za WHILE hlásí error
    PlatnaVolbaC = false;
    do
    {
        switch (Console.ReadKey().KeyChar.ToString().ToLower())
        {
            case "a":
                VolbaC = true;
                PlatnaVolbaC = true;
                Console.WriteLine();
                break;
            case "n":
                VolbaC = false;
                PlatnaVolbaC = true;
                break;
            default:
                Console.WriteLine();
                Console.WriteLine("Zadali jste neplatnou volbu, stiskněte klávesu [a] nebo [n]!");
                break;
        }
    } while (!PlatnaVolbaC);
} while (VolbaC);
 
Odpovědět
24. dubna 16:43
Avatar
Radek Vymětalík
Super redaktor
Avatar
Odpovídá na Pratos Zesporaku
Radek Vymětalík:24. dubna 18:01

Nic špatně neděláš. :) V C# musí mít proměnná před jejím použitím nadefinovanou nějakou hodnotu, jinak se kód nemůže zkompilovat. Je to vlastnost jazyka C#.

 
Odpovědět
24. dubna 18:01
Avatar
Odpovídá na Pratos Zesporaku
Martin Olejník:7. června 7:36

Nefunguje ti to, protože nemáš pokryté přiřazení true/false v defaultu u switche, tzn. když uživatel zadá něco, co neodpovídá case 1,2 tvoje řešení volá znovu vnitřní cyklus aniž by proměnná PlatnaVolbaC měla přiřazenou nějakou hodnotu, to samé platí pro vnější cyklus.

 
Odpovědět
7. června 7:36
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 7 zpráv z 7.