004 ‐ výpis řady - zizanek/github-tz-is-2026-sk1 GitHub Wiki

Úvod: Základní skladba programu

Než začneme psát konkrétní řádky kódu, je důležité pochopit, jak je většina programů (od nejjednodušších konzolových úloh až po rozsáhlé systémy) vnitřně strukturována.

Téměř každý algoritmus se v zásadě skládá ze tří až čtyř navazujících fází:

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────────┐
│     VSTUP       │ ──> │     LOGIKA      │ ──> │     VÝSTUP          │
│ (Input / Data)  │     │  (Algoritmus)   │     │ (Output / Zobrazení)│
└─────────────────┘     └─────────────────┘     └─────────────────────┘
         ▲                                               │
         └──────────── [ŘÍDICÍ SMYČKA / OPAKOVÁNÍ] ──────┘
  1. Příprava a Vstup (Input):

    • Získání dat potřebných pro běh programu (od uživatele z klávesnice, ze souboru nebo ze sítě).
    • V této fázi je klíčová validace – program musí data zkontrolovat dříve, než s nimi začne cokoliv dělat.
    • U začátečnických programů tato část často zabírá nejvíce řádků kódu, protože ošetřujeme překlepy a neplatné zadání uživatele.
  2. Logika / Výpočet (Processing):

    • Samotné „jádro“ algoritmu (výpočty, cykly, podmínky, transformace dat).
    • U jednoduchých úloh bývá tato část překvapivě krátká – často jen 3 až 5 řádků čisté matematiky nebo logiky.
    • Zde se řeší podstata problému odděleně od toho, jak se data načetla nebo jak se budou zobrazovat.
  3. Výstup (Output):

    • Prezentace výsledků uživateli (výpis do konzole, uložení do souboru, zobrazení v grafickém rozhraní).
    • Správný výstup by měl být přehledný, srozumitelný a měl by obsahovat i kontext (např. rekapitulaci vstupních hodnot, aby uživatel věděl, k čemu výsledek patří).
  4. Řídicí smyčka (Application Lifecycle):

    • Zajišťuje, aby program po jednom výpočtu hned neskončil, ale umožnil uživateli celou akci zopakovat nebo program korektně ukončit.

Při čtení i psaní kódu je dobré si všímat, kde jedna fáze končí a druhá začíná. Tento návyk vám později výrazně usnadní rozdělování programů do samostatných funkcí a metod.



Program: Výpis aritmetické řady čísel

Tento program slouží k procvičení základních stavebních kamenů jazyka C#:

  • cyklus s podmínkou na začátku (while),
  • bezpečné načítání číselného vstupu od uživatele (int.TryParse),
  • samostatná deklarace proměnných v paměti (int),
  • formátovaný výstup do konzole pomocí interpolace řetězců ($"").

1. Kompletní zdrojový kód programu

string again = "a";

// Řídicí cyklus aplikace:
// .ToLower() převede vstup na malá písmena, takže program pokračuje při zadání 'a' i 'A'.
// Jakýkoliv jiný vstup program ukončí.
while (again.ToLower() == "a")
{
    Console.Clear();
    Console.WriteLine("****************************");
    Console.WriteLine("***** Výpis řady čísel *****");
    Console.WriteLine("****************************");
    Console.WriteLine("******* Tomáš Žižka ********");
    Console.WriteLine("****************************");
    Console.WriteLine();

    // 1. Vstup počáteční hodnoty
    Console.Write("Zadejte první číslo řady (celé číslo): ");
    int first;
    while (!int.TryParse(Console.ReadLine(), out first))
    {
        Console.Write("Nezadali jste celé číslo. Zadejte první číslo znovu: ");
    }

    // 2. Vstup koncové hodnoty
    Console.Write("Zadejte poslední číslo řady (celé číslo): ");
    int last;
    while (!int.TryParse(Console.ReadLine(), out last))
    {
        Console.Write("Nezadali jste celé číslo. Zadejte poslední číslo znovu: ");
    }

    // 3. Vstup diference s kontrolou na kladnou hodnotu
    Console.Write("Zadejte diferenci (kladné celé číslo): ");
    int step;
    while (!int.TryParse(Console.ReadLine(), out step) || step <= 0)
    {
        Console.Write("Diference musí být kladné celé číslo větší než 0. Zadejte znovu: ");
    }

    // 4. Rekapitulace zadaných hodnot
    Console.WriteLine();
    Console.WriteLine("====================================");
    Console.WriteLine($"První číslo: {first}; Poslední číslo: {last}; Diference: {step}");
    Console.WriteLine("====================================");
    Console.WriteLine();

    // 5. Výpis řady
    Console.WriteLine("Výpis číselné řady:");
    if (first <= last)
    {
        int current = first;
        while (current <= last)
        {
            Console.WriteLine(current);
            current += step;
        }
    }
    else
    {
        Console.WriteLine("První číslo je větší než poslední. Tento program umí vypsat pouze vzestupnou řadu (od menšího k většímu).");
    }

    // 6. Dotaz na opakování
    Console.WriteLine();
    Console.Write("Pro opakování programu stiskněte 'a' a potvrďte klávesou Enter: ");
    again = Console.ReadLine() ?? "";
}

2. Řídicí cyklus programu (Event / Repeat Loop)

string again = "a";
while (again.ToLower() == "a")
{
    // ... tělo programu ...

    Console.Write("Pro opakování programu stiskněte 'a' a potvrďte Enterem: ");
    again = Console.ReadLine() ?? "";
}

Princip:

  • Proměnná again uchovává text zadaný uživatelem.
  • Cyklus while testuje podmínku před každým průchodem. Protože je na začátku hodnota nastavena na "a", tělo proběhne minimálně jednou.
  • Metoda .ToLower() převádí text na malá písmena, takže program pokračuje i při zadání velkého písmene A.

3. Bezpečné načítání celočíselného vstupu

Proč nepoužívat int.Parse u uživatelských vstupů?

// NEVHODNÉ ŘEŠENÍ:
int first = int.Parse(Console.ReadLine());

Pokud uživatel zadá text (např. "ahoj") nebo stiskne pouze Enter, metoda int.Parse vyvolá neošetřenou výjimku (FormatException) a celá aplikace okamžitě spadne.

Správné řešení s oddělenou deklarací proměnné:

Console.Write("Zadejte první číslo řady (celé číslo): ");
int first;
while (!int.TryParse(Console.ReadLine(), out first))
{
    Console.Write("Nezadali jste celé číslo. Zadejte první číslo znovu: ");
}

Jak to funguje:

  1. int first; nejprve vyhradí místo v paměti pro celé číslo.
  2. Console.ReadLine() přečte řádek textu od uživatele.
  3. int.TryParse(...) se pokusí text převést:
    • Pokud se převod podaří: uloží hodnotu přes parametr out first a vrátí true.
    • Pokud se převod nezdaří: vrátí false a program nespadne.
  4. Operátor negace ! otočí logickou hodnotu: pokud převod selhal (!false je true), cyklus while se zopakuje a požádá o vstup znovu.

4. Ošetření logických mezí (Diference nesmí být nulová)

Console.Write("Zadejte diferenci (kladné celé číslo): ");
int step;
while (!int.TryParse(Console.ReadLine(), out step) || step <= 0)
{
    Console.Write("Diference musí být kladné celé číslo větší než 0. Zadejte znovu: ");
}

Algoritmické riziko:

Pokud by diference (step) byla rovna 0, hodnota proměnné current by se nikdy nezvýšila a cyklus výpisu by skončil nekonečnou smyčkou. Podmínka step <= 0 brání zacyklení a vynucuje smysluplnou hodnotu.


5. Generování a výpis číselné řady

int current = first;
while (current <= last)
{
    Console.WriteLine(current);
    current += step; // ekvivalent zápisu: current = current + step;
}

Kroky algoritmu:

  1. Řídicí proměnná current se nastaví na počáteční hodnotu first.
  2. Podmínka current <= last hlídá, zda jsme nepřekročili horní mez.
  3. Po vypsání se hodnota current zvětší o diferenci step.
  4. Jakmile hodnota přesáhne last, cyklus se přirozeně zastaví.

6. Otázky k zamyšlení a obhajobě kódu

  1. Co se stane, pokud uživatel zadá first = 20 a last = 5? Proč je před výpisem zařazena podmínka if (first <= last)?
  2. Jaké klíčové slovo v metodě int.TryParse umožňuje předat proměnnou tak, aby do ní metoda mohla zapsat výsledek?
  3. Jak by bylo potřeba upravit podmínku a přičítání v cyklu, kdybychom chtěli vytvořit sestupnou řadu (např. od 100 do 0)?

7. Dobré programátorské návyky (Best Practices)

Na tomto prvním programu si můžeme ukázat několik základních pravidel profesionálního vývoje, která odlišují kvalitní software od narychlo sepsaného skriptu.


7.1. Uživatel nesmí tápat (Informativní UI)

Program běží v textové konzoli, kde uživatel nevidí žádná tlačítka ani nápovědu. O to důležitější je jasná komunikace:

  • Přesné výzvy: Místo vágního textu Zadejte číslo: uveďte Zadejte první číslo řady (celé číslo):. Uživatel musí předem vědět, jaký formát program očekává.
  • Konstruktivní chybové hlášky: Nestačí napsat Chyba!. Řekněte, v čem problém spočívá a co má uživatel udělat pro nápravu (Nezadali jste celé číslo. Zadejte hodnotu znovu:).
  • Zpětná vazba (rekapitulace): Před spuštěním samotného výpočtu program zopakuje zadané hodnoty. Uživatel si tak okamžitě ověří, s jakými daty aplikace reálně pracuje.

7.2. Předpokládejte neplatný vstup (Defenzivní programování)

Uživatelé dělají chyby, překlepy nebo program testují nečekanými vstupy:

  • Nikdy se nespoléhejte na metody, které při chybě spadnou (int.Parse).
  • Používejte bezpečné parsování (int.TryParse) v kombinaci s cyklem, který aplikaci udrží v chodu, dokud nezíská korektní data.
  • Aplikace nesmí za žádných okolností skončit neošetřenou výjimkou (červeným chybovým výpisem v konzoli).

7.3. Kontrola logických mezí, nejen datových typů

To, že uživatel zadá platné číslo typu int, ještě neznamená, že dává v kontextu úlohy smysl:

  • Diference step = 0 je formálně platné celé číslo, ale pro cyklus while (current <= last) znamená okamžité zamrznutí v nekonečné smyčce.
  • Vždy hlídejte logické podmínky domény problému (např. step > 0).

7.4. Anglické názvy identifikátorů (Clean Code)

Ačkoliv texty vypisované uživateli jsou v češtině, zdrojový kód píšeme podle mezinárodních standardů:

  • Proměnné (first, last, step, current, again) i názvy metod volíme v angličtině.
  • V praxi se software vyvíjí v mezinárodních týmech, s mezinárodními knihovnami a verzovacími nástroji. Míchání češtiny do kódu zhoršuje čitelnost a profesionalitu projektu.

7.5. Ochrana před hodnotami null

Moderní C# klade velký důraz na bezpečnost práce s pamětí:

  • Metoda Console.ReadLine() může za určitých okolností vrátit prázdný odkaz (null).
  • Použitím operátoru sloučení s hodnotou null (?? "") předcházíme pádům na NullReferenceException a zbavujeme kód varování kompilátoru.

8. Jak přemýšlet jako programátor: Jak sestavit algoritmus cyklu

Pro začátečníka bývá nejtěžší přejít od zadání úlohy k funkčnímu kódu. Když se podíváte na samotné jádro výpisu, má pouhých 6 řádků (včetně složených závorek):

int current = first;
while (current <= last)
{
    Console.WriteLine(current);
    current += step; // ekvivalent zápisu: current = current + step;
}

Jak na tuto konstrukci přijít z hlavy? Stačí si položit 4 základní otázky, které fungují pro jakýkoliv cyklus v programování:


Krok 1: Kde začínám? (Inicializace)

Než se cyklus rozběhne, musíme si připravit výchozí stav.

  • Otázka: „Jaká je hodnota úplně prvního čísla, které chci zpracovat?“
  • Odpověď: Hodnota, kterou uživatel uložil do proměnné first.
  • Kód: Vytvoříme si pracovní proměnnou (kurzor / počítadlo):
    int current = first;
    
    (Poznámka: Neupravujeme přímo proměnnou first, abychom si nezničili původní zadanou hodnotu pro případný další výpis).

Krok 2: Dokdy má cyklus pokračovat? (Podmínka běhu)

V C# klíčové slovo while znamená „DOKUD PLATÍ, ŽE...“, nikoliv „AŽ NASTANE...“.

  • Otázka: „Za jaké podmínky má program ještě vypsat další číslo?“
  • Častá chyba začátečníků: Přemýšlí nad tím, kdy má cyklus skončit („skonči, až bude current větší než last“ $\rightarrow$ current > last).
  • Správný postup: Podmínku musíme formulovat pro stav, kdy má cyklus ještě běžet: „Běž, dokud je aktuální číslo menší nebo rovno cíli.“
  • Kód:
    while (current <= last)
    

Krok 3: Co se má stát v jednom kroku? (Tělo cyklu)

Soustřeďte se vždy pouze na jeden jediný okamžik, jako by program dělal jen jeden krok:

  • Otázka: „Co mám s aktuálním číslem udělat teď a tady?“
  • Odpověď: Zobrazit ho uživateli na obrazovce.
  • Kód:
    Console.WriteLine(current);
    

Krok 4: Jak se posunu dál? (Krokování / Posun)

Každý cyklus se musí posouvat směrem k ukončovací podmínce, jinak vznikne nekonečná smyčka (program zamrzne).

  • Otázka: „Jak se dostanu k následujícímu číslu v řadě?“
  • Odpověď: K aktuální hodnotě přičtu zadanou diferenci step.
  • Kód:
    current += step;
    

Shrnutí postupu na mentálním modelu:

Kdykoliv stojíte před prázdným monitorem a potřebujete navrhnout cyklus, vezměte si tužku a papír a projděte si tuto tabulku:

Fáze návrhu Otázka pro vás Konkrétní kód v C#
1. Start Z jakého čísla vycházím? int current = first;
2. Podmínka Dokud platí co, má program pokračovat? while (current <= last)
3. Akce Co přesně chci v tomto jednom kroku provést? Console.WriteLine(current);
4. Krok vpřed Co musím změnit, abych se přiblížil ke konci? current += step;

Pokud si tyto 4 otázky zautomatizujete, dokážete bezpečně sestavit jakýkoliv cyklus – ať už půjde o počítání splátek, rozklad čísla na cifry nebo vykreslování herní grafiky.