{{indexmenu_n>3}} ====== 3 - Řídicí struktury a cykly ====== * pro vyučující: [[courses:b0b36prp:internal:tutorialinstruction:03|]] ===== Cíle cvičení ===== - Podmínky a cykly ([[courses:b0b36prp:tutorials:coding:control|řídicí struktury]]), [[https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B|operátory]]. - [[courses:b0b36prp:tutorials:testing|Testování HW programů před odevzdáním]] ===== Úkoly na cykly ===== * Vypište čísla od 1 do 10 s využitím cyklů ''for'', ''while'' a ''do-while''. * Nahraďte terminační podmínku příkazem ''break''. * Vypište všechna sudá čísla od 1 do $n$, kde $n$ zadá uživatel na standardním vstupu * Vypište součin všech čísel vypsaných v předchozím kroku * Vypište řadu $n$ čísel ve tvaru: 1, -1, 1, -1, 1, -1, ... ===== Úkoly na testování HW programů před odevzdáním ===== * Seznamte se s testování programu před odevzdáním [[https://cw.fel.cvut.cz/b221/courses/b0b36prp/tutorials/testing]]. * Prozkoumejte adresářovou strukturu výchozích souboru pro [[courses:b0b36prp:hw:hw01|HW 01 - Načítání vstupu, výpočet a výstup]]. * Stáhněte soubor {{:courses:b0b36prp:hw:b0b36prp-hw01.zip|}}, který rozbalte ve svém pracovním adresáři cvičení např. ''~/ctu-fee/prp/lab03''. * Zip archív rozbalte v terminálu příkazem ''unzip b0b36prp-hw01.zip'' unzip b0b36prp-hw01.zip Archive: b0b36prp-hw01.zip creating: b0b36prp-hw01/ extracting: b0b36prp-hw01/generate_solutions.sh creating: b0b36prp-hw01/data/ extracting: b0b36prp-hw01/data/pub03.in extracting: b0b36prp-hw01/data/pub01.out extracting: b0b36prp-hw01/data/pub01.in extracting: b0b36prp-hw01/data/pub03.out extracting: b0b36prp-hw01/data/pub04.in extracting: b0b36prp-hw01/data/pub02.in extracting: b0b36prp-hw01/data/pub02.out extracting: b0b36prp-hw01/data/pub04.out extracting: b0b36prp-hw01/b0b36prp-hw01-genref-osx extracting: b0b36prp-hw01/b0b36prp-hw01-genref extracting: b0b36prp-hw01/main.c extracting: b0b36prp-hw01/Makefile * Vypište adresářovou strukturu příkazem ''tree''. tree b0b36prp-hw01 b0b36prp-hw01 ├── Makefile ├── b0b36prp-hw01-genref ├── b0b36prp-hw01-genref-osx ├── data │   ├── pub01.in │   ├── pub01.out │   ├── pub02.in │   ├── pub02.out │   ├── pub03.in │   ├── pub03.out │   ├── pub04.in │   └── pub04.out ├── generate_solutions.sh └── main.c 1 directory, 13 file * Vyzkoušejte si spuštění referenčního řešení ''b0b36prp-hw01-genref'' na přiložených vstupech. * Vyzkoušejte si přesměrování vstupu a výstupu a porovnání nově vygenerovaných souborů například příkazem ''diff'' nebo ''vimdiff'', či jiným porovnávačem/rozdílovačem. Můžete např. ručně upravit obsah výstupního souboru, aby záměrně obsahoval chybu. * Seznamte se s požitím nástroje ''hexdump'' a vyzkoušejte si zobrazení souborů s různými [[https://en.wikipedia.org/wiki/Whitespace_character|bílými znaky]]. ===== Další úkoly (na doma) ===== ==== Výpisy cykly ==== * Vypište: * ** *** **** ***** * Vypište: ***** **** *** ** * * Vypište následující tabulku (využijte formátovaného výstupu např. "%3d" nebo si napište vlastní funkci s využitím pouze ''putchar''): 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 * Jak to naprogramujete s využitím pouze jediného cyklu? Jak s dvěma vnořenými cykly? Co se vám zdá lepší a proč? * Nyní zkuste vypsat pouze diagonálu: 0 11 22 33 44 55 66 77 88 99 * Nyní tu druhou: 9 18 27 36 45 54 63 72 81 90 * A co obě zároveň? 0 9 11 18 22 27 33 36 44 45 54 55 63 66 72 77 81 88 90 99 * Parametrizujte svuj kód. Dokážete pouhou změnou parametru vypsat totéž pro tabulku 5x5? ==== Výpis čísla v dec/hex/bin soustavě ==== * Vypište v dekadické, hexadecimální a binární reprezentaci znaku zapsanéh na standardním vstupu uživatelem * Výpis v binárním tvaru můžete realizovat bitovými operátory, např. bitový posun a součin. * Výpis dekadické a hexadecimální reprezentaci lze použít ''printf()''. * Binární výpis můžete realizovat funkcí, ve které realizujte postupný bitový posun, např. doleva (operátor ''v << 1'') a součin s 128 (b10000000) a tisknutí znaku '0' nebo '1' (např. funkcí ''putchar'') v závislosti na vyhodnocení výrazu jako logická nepravda (''FALSE'') nebo pravda (''TRUE''). V programu kontrolujete návratovou hodnotu funkce ''getchar'' viz ''man getchar'' a v případě ''EOF'' program vrátí hodnotu ''100'', jinak indikuje očekávané chování hodnotou ''0''. ^ Standardní vstup ^ Standardní výstup ^ | a | 97\\ 0x61 \\ b01100001 | * Příklad použití clang main.c && echo 'a' | ./a.out 97 61 b01100001 ==== Jednoduchý automat na mince ==== * Napište program, který pro zadanou částku (v celých korunách) vypíše nejmenší počet mincí (20, 10, 5, 2, 1), ze kterých se dá daná částka složit. * Rozšiřte program tak, aby vypisoval pouze použité mince. * Nechte program vypsat vloženou částku i v jiných měnách. ==== Kalendář ==== * Naprogramujte zjednodušenou verzi programu ''cal''. * Nejdříve zkuste vypsat: Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 * Pak zkuste kalendář pro mesíc září: September Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 * nebo rovnou kalendář pro tři po sobě jdoucí měsíce: September Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 October Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 November Mo Tu We Th Fr Sa Su 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 * Parametrizujte kód, pokud tak již nemáte a zkuste vypsat kalendář pro různý rozsah měsícu. * Následující vám může pomoci: static char *day_of_week[] = {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su" }; static char *name_of_month[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static int days_in_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static int first_day_in_september = 2; // 1. 9. 2021 is Wednesday static int first_day_in_year = 4; // 1. 1. 2021 is Friday ==== Výpočet Ludolfova čísla ==== * Napiště program který umožní výpočet Ludolfova čísla jako součtu Leibnizovy řady $$ \qquad\pi = 4 \sum_{k=0}^\infty\dfrac{(-1)^k}{2k+1} = \dfrac{4}{1}-\dfrac{4}{3}+\dfrac{4}{5}-\dfrac{4}{7}+\dfrac{4}{9}-\dfrac{4}{11}+\cdots $$ * Vytvořte funkci pro výpočet Ludolfova čísla pomocí $n$ prvků Leibnizovy řady * Zjistěte kolik členů řady je potřeba zahrnout, abychom dostali Ludolfovo číslo s přesností na $10^{-6}$. /* ===== Vnořené podmínky ===== - Zopakování if a doplnění ... TBD příklad (možná přesunout do lab02) ===== Cykly - syntaxe ===== ==== For cyklus ==== for (inicializace; podmínka; změna) { tělo cyklu } * //Inicializace// u ''for'' cyklu se provede pouze před prvním provedením těla cyklu. * //Podmínka// je ověřována před každým provedením těla cyklu. * //Tělo cyklu// se provede pouze, pokud je podmínka splněna. * //Změna// se provede vždy až po provedení těla cyklu. Použití preinkrementu či postinkrementu tuto vlastnost neovlivní. * U for cyklu lze vynechat libovolnou část příkazu for. Cyklus for(;;) bude nekonečný. === Příklad === Výpis čísel od 1 do 10. for (int i = 1; i <= 10; i = i + 1) { printf("%d, ", i); } ==== While cyklus ==== while(podmínka) { tělo cyklu } Nejprve se otestuje platnost podmínky. Je-li splněna, provede se tělo cyklu a poté se opět otestuje platnost podmínky. V případě nesplnění podmínky při prvním testování, neproběhne tělo cyklu ani jednou. === while cyklus - příklad === Výpis čísel od 1 do 10. int i = 1; while (i <= 10) { printf("%d, ", i); i = i + 1; // nebo i++; } ==== Do - while cyklus ==== do { tělo cyklu } while (podmínka); * Nejprve se provede //tělo cyklu// a teprve po jeho prvním provedení se otestuje podmínka. Znovu se tělo cyklu provede pouze v případě platnosti podmínky. * Narozdíl od while cyklu se tělo do - while cyklu provede alespoň jednou. === do - while cyklus - příklad === Jaký je rozdíl mezi while a do-while? int i = 1;; do { printf("%d, ", i); i++; } while ( i <= 10 ); */ /* ==== Speciální příkazy pro cykly ==== * Příkaz **''break''** ukončí provádění cyklu a pokračuje zpracováním kódu za tělem cyklu. * Příkaz **''continue''** ukončí provádění těla cyklu a v případě splnění podmínky znovu zahájí zpracování těla cyklu. */