Dnes se naučíme pracovat s logickými hodnotami. Dojde i na jejich využití: podmínku a podmíněný výraz.
19.11.2004 16:00 | Jan Němec | přečteno 45445×
Pro logické hodnoty ano/ne není v C zvláštní typ. Místo něj se používá se int, nula znamená ne a jakákoli jiná hodnota ano. Jako ano se v praxi nejčastěji používá jednička, ale stejně dobře poslouží třeba minus sto dvacet pět.
Typ int chápaný jako logická hodnota vracejí porovnávací operátory <, <=, ==, >= a > s významem menší, menší nebo rovno, rovná se, větší nebo rovno a větší. Všimněte si, že rovnost se testuje operátorem == a nikoli prostým =, které je rezervováno pro přiřazení. Dělá to problémy mnoha začínajícím céčkařům zvyklým na jiný jazyk. Porovnávat můžeme celá i reálná čísla. Při práci s reálnými čísly se musíme smířit se zaokrouhlovací chybou a nepřesností některých aritmetických operátorů. Zejména test na rovnost nemusí dopadnout podle představ programátora, pokud porovnává čísla jako 1.0000000298023 a 0.99999997542, i když třeba vznikla výpočtem, který by v ideálním světě matematiky vedl přesně k 1.0.
Úlohu logických spojek mají v C operátory !, && a ||. Vykřičník je negace (not/ne), && má význam konjunkce (and/a) a || je alternativa (or/nebo). Logické xor C nemá, nicméně je možné vyxorovat dvě čísla bit po bitu, ukážeme si to v některém z dalších dílů. Nejvyšší prioritu má negace, potom konjunkce a nakonec alternativa.
muze_ridit = !pil && ma_ridicak || ma_poslaneckou_imunitu;
Operátory && a || zaručují pořadí vyhodnocování. Nejprve se vyhodnotí levý operand a vyhodnocení pravého následuje pouze pokud je to nezbytné pro vypočtení hodnoty výrazu. V našem případě by tak u abstinenta s řidičákem již nedošlo na test imunity. Je proto zcela korektní psát kód jako
muzeme_lyzovat = lyzaru > 0 && hulek / lyzaru >= 2; /* neboli muzeme_lyzovat = ((lyzaru > 0) && ((hulek / lyzaru) >= 2))); */
V jazykách s úplným (nebo nespecifikovaným) vyhodnocováním výrazů by nám mohl obdobný příklad spadnout na dělení nulou, pokud je lyzaru nula, ale v Céčku vše projde.
Přirozeným využitím logických hodnot je podmíněný příkaz.
unsigned synacku = 5, jablicek = 11; if (synacku > 0) printf("Každý synáček dostane %u jablíček " "a %u jich zbude na tatínka.\n", jablicek / synacku, jablicek % synacku); else { puts("Tatínek má 0 synů."); puts("Raději nebudeme dělit nulou."); }
Podmínka má syntaxi
if (výraz) příkaz1 nebo blok1 [ else příkaz2 nebo blok2 ]
Nejprve se vyhodnotí podmínka, je-li splněna vykoná se příkaz1/blok1, v opačném případě se přeskočí a pokud následuje nepovinná větev else vykoná se příkaz2/blok2. Podmínit lze jen jeden příkaz, pokud chceme podmíněně vykonat příkazů více, je třeba je pomocí složených závorek seskupit do bloku, jako v případě else větve z příkladu se synáčky a jablíčky. Po vykonání podmínky (ať už byla splněna nebo ne) program pokračuje následujícím příkazem. Podmínky lze podobně jako jiné konstrukce v C do sebe zanořovat.
if (hotovost > cena) if (ucet > cena) puts("Můžeš platit kartou i hotovostí."); else puts("Zaplať hotovostí."); else if (ucet > cena) puts("Zaplať kartou."); else puts("Ten nový počítač nepotřebuješ.");
Nejasnost by mohla vzniknout v případě
if (výraz1) if (výraz2) příkaz1 else příkaz2 příkaz3 nebo konec bloku
Není totiž jasné ke které podmínce se váže else větev. Norma C to vyřešila jednoznačně, v podobných případech else větev patří ke vnitřní podmínce, vykoná se tedy pokud výraz1 && !výraz2, ovšem z důvodu čitelnosti programu je lepší celou vnitřní podmínku od druhého if až po příkaz2 uzavřít pomocí složených závorek do bloku.
Kromě klíčového slova if a podmíněného příkazu, nabízí C i ternární operátor ?: - podmíněný výraz.
a ? b : c
Nejprve se vyhodnotí logická hodnota a. Je-li splněna, je výsledkem výrazu b, v opačném případu c. V čistém C (narozdíl od C++) nikdy není výsledkem podmíněného výrazu l-hodnota. Není tedy možné mít podmíněný výraz na levé straně přiřazení a podmínku použít na určení proměnné, do které se má přiřadit. Ačkoli některé překladače toto omezení nemají, není dobré toho využívat.
/* Tohle v C nemusí projít */ (c > 0 ? a : b) = c;
Podmíněný výraz naopak můžeme s úspěchem použít na ošetření dělení nulou.
vysledek = i ? 128 / i : 0;
Někteří programátoři se podmíněnému výrazu systematicky vyhýbají a rozepisují jej pomocí if a else.
V dalším dílu probereme cykly.