Opakující se kód
Pokud jsou v programu úseky kódu, které se liší jen některými proměnnými, je často vhodné je nahradit jedním podprogramem.
Typické situace:
- čtení vstupní hodnoty,
- úloha se stejným algoritmem zpracovávající jiná data, například
- vypsání tabulky odepisování dlouhodobého hmotného majetku pro určitou odpisovou skupinu - Odpisová skupina se svojí dobou odepisování má být parametrem podprogramu s algoritmem společným pro výpis tabulky.
- algoritmus hry pro určitého hráče hry se střídajícími se hráči - Hráč a jeho vlastnosti má být parametrem podprogramu s algoritmem hry společným pro všechny hráče.
- hra s určitou obtížností - Stupeň obtížnosti a jeho vlastnosti (například rozsah hádaných čísel, odměna) má být parametrem podprogramu s algoritmem hry společným pro všechny obtížnosti.
Pokud jsou v programu proměnné, které spolu souvisí, například stupeň obtížnosti hry a jeho vlastnosti, měly by být zabaleny v poli struktur, například ve hře pro procvičování počtů je vhodná struktura
#define MAX_POCET_OPERATORU 4
typedef struct { /* Definice vlastního datového typu, která se umisťuje globálně. */
char* operatory;
int max_hodnota[MAX_POCET_OPERATORU]; /* Pro každý operátor se může stanovit jiný rozsah operandů. */
} OBTIZNOST;
Potom se deklaruje lokální proměnná obtiznost jako pole s položkou typu struktura a přiřadí se jí konkrétní hodnoty nebo se později načtou z konfiguračního souboru.
OBTIZNOST obtiznost[] = {
{"+-", {20, 20}},
{"+-*", {500, 500, 20}},
{"+-*/", {1000, 1000, 20, 200}}
};
Možnosti použití takového pole s položkou typu struktura:
- Pole je definováno v podprogramu s algoritmem hry společným pro všechny obtížnosti, protože je to jediné místo, kde se toto pole používá.
- Pole je definováno v programu volajícím podprogram s algoritmem hry společným pro všechny obtížnosti, protože s ním pracuje více podprogramů.
- Předá se celé jako adresa, na které pole začíná, jako datový typ OBTIZNOST pole[] nebo ekvivalentně OBTIZNOST *pole.
- Předá se jeho určitá položka jako adresa, na které celé pole začíná, a index položky.
- Předá se jeho určitá položka jako datový typ OBTIZNOST pole[index]. Je to méně efektivní než předchozí způsoby, protože se musí kopírovat do parametrů volaného podprogramu celá struktura.
Komunikace s uživatelem
Když chceme po uživateli, aby něco zadal, tak se musí vypsat výzva k zadání, například:
Vase volba:
Za výzvou je dvojtečka a za dvojtečkou je mezera. Za mezerou na stejném řádku se objevuje to, co uživatel zadává.
Typicky se na toto zapomíná po výpisu hlavního menu a po spočítání nějaké úlohy, po které program nemá ještě končit.
Pokud vybíráme pomocí písmenek, tak nemá záležet na jejich velikosti, tedy například program zareaguje stejně, když zadáme 'a' i 'A'.
Pokud má uživatel zadat několik hodnot, tak pro každou hodnotu se musí volat funkce pro čtení této jediné hodnoty s jejím ověřením zvlášť. Například místo "Zadejte výšku, šířku, hloubku: " musí být výzva "Zadejte výšku: ", potom se případné chyby uživatele řeší ve funkci pro zadání čísla, po úspěšném zadání výšky se objeví výzva "Zadejte šířku: " a tak dále.
Soubory
Otevírání a uzavírání souborů ověřujte na úspěch standardním způsobem dle Učebnice jazyka C Pavla Herouta.
Soubor, který jste otevřeli, také zavřete.
Pokud pro to není zvláštní důvod, neotevírejte a nezavírejte soubory více než jednou nebo vícekrát než na jediném místě programu.
Například u kalkulaček všech druhů je vhodné mít výstupní soubor, který zaznamenává úlohy se všemi vstupními hodnotami a jejich výsledky.
Program typu kalkulačka zpravidla zapisuje výsledky do souboru v podprogramech. V takových případech je nejlepší otevřít soubor pro zápis ve funkci volající jednotlivé podprogramy pro funkce kalkulačky, předávat do podprogramů pointer na otevřený soubor a na konci funkce volající jednotlivé podprogramy pro funkce kalkulačky soubor pro zápis zase zavřít.
Nechtějte po uživateli, aby musel vždy zadat do programu velké množství dat, například matici nebo dlouhý text. Místo toho bude takový vstup připraven ve vstupním souboru. Čtení ze souboru zařiďte během vývoje programu co nejdříve, abyste si ušetřili práci při ladění programu. Zadávání toho, co je v souboru, pomocí klávesnice může být nepovinně jako jedna z možností, kterou si uživatel může zvolit.
Pokud program zpracovává nebo dokáže jako jednu ze svých možností zpracovat vstupní soubor, k projektu přiložte soubor s vhodným vstupem.
Programy, které čtou vstup ze souboru, je možné udělat tak, že čtou celou množinu souborů a výstupy zapisují do jednoho nebo více výstupních souborů, pomocí argumentů funkce main() nebo redirekce spolu se spustitelným souborem s příkazy pro vícenásobné spuštění programu s parametry se jmény vstupních a výstupních souborů. Spustitelný soubor a vstupní soubory musí být dodány spolu s projektem. Program tohoto typu nemá opakovací menu.
Pointery
Alokaci paměti ověřujte na úspěch standardním způsobem dle Učebnice jazyka C Pavla Herouta.
Je-li v programu použita funkce malloc() nebo calloc(), musí být použita i funkce free(), aby nedošlo k úniku paměti, kdyby se paměť alokovala v cyklu.
Řídící struktury
Pro standardní, tedy často se opakující, typické úlohy používejte standardní učebnicová řešení.
Například opakovací menu řešte vždy pomocí struktury
do {
kód pro zadávání volby
switch (volba) {
case VOLBA1:
...
default:
kód pro špatnou volbu
}
} while (podmínka, za které se znovu vrátíme do menu);
Strukturu switch při programování funkcí menu preferujte před strukturou if...else, protože je přehlednější.
Kód v rámci struktury switch nebo if...else by měl být krátký, aby byl přehledný, což se řeší tím, že je členěn na podprogramy.
Skoky
Skoky všeho druhu používejte jen, pokud jsou součástí standardních způsobů řešení typických úloh probíraných v Učebnici jazyka C Pavla Herouta, například ověření správnosti otevření souboru:
if ((fr = fopen(VSTUPNI_SOUBOR, "r")) == NULL) {
printf("Soubor %s se nepodarilo otevrit.\n", VSTUPNI_SOUBOR);
return 1; /* Skok, který je vhodný. */
}
kód (zpravidla mnoho řádků), který se provede, když se soubor podařilo otevřít.
Kód
if ((fr = fopen(VSTUPNI_SOUBOR, "r")) == NULL) {
printf("Soubor %s se nepodarilo otevrit.\n", VSTUPNI_SOUBOR);
} else {
kód (zpravidla mnoho řádků), který se provede, když se soubor podařilo otevřít.
}
neobsahuje skok a proto je lepší z hlediska zásad strukturovaného programování, ale má nevýhodu v tom, že celý kód, který se provede, když se soubor podařilo otevřít, což je zpravidla spousta kódu, je v rámci struktury, což snižuje kvalitu kódu, protože v kódu by neměla být zbytečná vnoření.
Typický druh skoku, který by se měl ve většině případů nahradit cykly a podmínkami, je goto.
Dodržení těchto zásad může mírně zlepšit hodnocení programu.
Deklarace proměnných a konstant
V rámci funkce nejdříve deklarujte vlastní konstanty (modifikátor const), potom proměnné a teprve po nich pište příkazy.
Vlastní datové typy (klíčové slovo typedef) je většinou nejvhodnější definovat globálně za konstantami definovanými pomocí direktivy #define.
Datové typy proměnných by měly odpovídat oboru hodnot dané úlohy. Například počítání obvodu a obsahu by nemělo být pouze celočíselné, hádání čísla od MIN do MAX naopak musí být celočíselné. Používáme-li knihovnu math.h, je vhodné mít proměnné, které se stanou argumenty funkcí z této knihovny, typu double namísto float.
Komentáře
Komentujte kód, aby se vám lépe obhajoval. Neřešte komentování kódu nějakým odděleným souborem s dokumentací, ale mějte komentáře v kódu, protože současné SW inženýrství má workflow ve stylu, že se nejdříve vytvoří kód s komentáři a potom se nějakým programem může z komentovaného kódu vytvořit zvláštní soubor s dokumentací.
Délka řádků kódu
Špatně:
printf("Zadejte\n'p' pokud chcete hadat pismeno, nebo\n'c' pokud chcete hadat cislo.\n(pokud chcete ukoncit program, zadejte jakykoliv jiny znak)\n\nPOZOR - pismena se hadaji od 'a' do 'z', a cisla od 1 do 100.\n");
Dobře:
printf("Zadejte\n");
printf("'p' pokud chcete hadat pismeno, nebo\n");
printf("'c' pokud chcete hadat cislo.\n");
printf("(pokud chcete ukoncit program, zadejte jakykoliv jiny znak)\n\n");
printf("POZOR - pismena se hadaji od 'a' do 'z', a cisla od 1 do 100.\n");
Přehledné menu na obrazovce
Špatně:
Zadejte 'p' pokud chcete hadat pismeno, nebo 'c' pokud chcete hadat cislo. (pokud chcete ukoncit program, zadejte jakykoliv jiny znak) POZOR - pismena se hadaji od 'a' do 'z', a cisla od 1 do 100.