6.1. Výrazový příkaz
6.2. Prázdný příkaz
6.3. Bloky.
6.4. Oblast platnosti identifikátoru
6.5. Podmíněný příkaz
if-else.
6.6. Přepínač
6.7. Cykly
6.8. Příkaz skoku
V dosavadním výkladu jsme se dozvěděli, že se program skládá
z funkce main()
a z příkazů, které tato funkce
obsahuje. Své intuitivní představy o programu rozšíříme
nejen o případné další funkce, ale detailněji1 se podíváme
i na obsah funkcí. Tělo funkce obsahuje řadu příkazů. Naším
cílem je provádět právě ty příkazy, které odpovídají
zvolenému záměru. Výběr z příkazů je určen stavem
dosavadního běhu programu, vstupními údaji a řídícími
strukturami, které jsme použili.
Program, provádějící příkazy v pevném a neměnném pořadí, které odpovídá jejich umístění ve zdrojovém textu a navíc bez možnosti jejich výběru, jistě není naším ideálem. A to bez ohledu na zvolený vyšší programovací jazyk. Cílem této kapitoly je proto seznámení s řídícími strukturami.
Před podrobným přístupem nejprve uveďme přehledně příkazy, které máme v C k dispozici:
Výraz známe z předchozího textu. Výrazem je nejen
aritmetický výraz (například a + b
, či 5 + 1.23 * a
),
prostý výskyt konstanty (literálu) či proměnné, ale i
funkční volání a přiřazení. Jestliže výraz ukončíme
symbolem ;
(středník), získáme výrazový příkaz.
Prázdný příkaz je výrazový příkaz, v němž není výrazová
část. Tato konstrukce není tak nesmyslná, jak se na první
pohled může zdát. Dává nám v některých případech
možnost umístit nadbytečný středník ;
do
zdrojového textu. Například i za vnořený blok. Protože se o
prázdném příkazu můžeme těžko dozvědět něco dalšího,
podívejme se raději na další příkazy jazyka C.
Všude v C, kde se může vyskytovat příkaz, se může
vyskytovat i složený příkaz. Složený příkaz
je posloupností příkazů2. Konstrukce, která složený příkaz vymezuje,
začíná levou a končí pravou složenou závorkou { }
,
a nazývá se blok. V bloku můžeme, kromě již zmíněné
realizace složeného příkazu, provádět lokální
deklarace a definice. Ty ovšem pouze na začátku bloku.
Jejich platnost je omezena na blok a případné další vnořené
bloky. Vnořený blok nemusí být ukončen středníkem. Představuje
složený příkaz a jeho konec je jasně určen. Není na škodu
si uvědomit, že tělo každé funkce je blokem. Proto jsme
mohli v těle funkce main()
definovat a používat
lokální proměnné. Syntakticky můžeme blok popsat následovně:
{
[declaration_1[; declaration_2 ... ];]
[statement_1 [; statement_2 ... ] ]
}
Blok tedy může obsahovat žádnou, jednu či více deklarací.
Pokud deklaraci obsahuje, musí být od další části bloku
oddělena středníkem. Dále blok může obsahovat jednotlivé
příkazy, rovněž oddělené středníkem. Povšimněme si, že
poslední z příkazů nemusí být od uzavírací složené závorky
bloku středníkem oddělen.
Identifikátor, který deklarujeme či definujeme, si ponechává svou platnost v programu, v němž je deklarován či definován. Jeho jméno je v tomto rozsahu viditelné, není-li maskováno:
Jméno makra je platné od jeho definice (direktivou define
)
až do místa, kdy je definice odstraněna (direktivou undef
, pokud
vůbec odstraněna je). Jméno makra nemůže být maskováno3.
if-else
. Operátor podmíněného výrazu ? :
používáme
pro výběr části výrazu. Pro výběr z příkazů máme k
dispozici podmíněný příkaz. Mohli bychom říci, že se jedná
o příkazy dva. Jejich syntaktický zápis je následující
if ( <expression> ) <statement1>;
if ( <expression> ) <statement1>;
else <statement2>;
Význam příkazu if
je následující. Po
vyhodnocení výrazu expression
(musí být v závorkách)
se v případě jeho nenulové hodnoty provede příkaz statement1
.
Po jeho provedení pokračuje program za tímto příkazem. V případě
nulového výsledku výrazu se řízení programu předá
bezprostředně za podmíněný příkaz. Jinak řečeno se příkaz statement1
přeskočí.
Příkaz if
můžeme použít i s variantou else
.
Sémantika takového příkazu if-else
je v první
části totožná se samotným if
. Je-li výslednou
hodnotou výrazu expression
jedna (nenulová
hodnota), provede se příkaz statement1
. V opačném
případě, kdy výsledkem je nula, se provede příkaz statement2
.
V obou případech se řízení programu po provedení prvního,
respektive druhého, příkazu předá za celý podmíněný výraz.
Někdy se výklad sémantiky předkládá způsobem, kdy se
nulové hodnotě říká nepravda a nenulové (jedničce) pravda.
Jak ostatně známe z logických výrazů. Pak lze ve druhé
variantě říci, že je-li podmínka splněna, vykoná se první
příkaz statement1
, jinak příkaz druhý statement2
.
Zdůrazněme, že oba příkazy jsou ukončeny středníkem4.
Z předchozích odstavců víme, že místo příkazu může být
umístěn blok. V takovém případě je jasně příkaz vymezen
a středník za blokem před else
nepíšeme!
Příklad nám ukáže použití podmíněného příkazu if-else
.
Máme vypočíst a zobrazit podíl dvou zadaných racionálních
čísel. Protože je známo, že nulou dělit nelze, využijeme
podmíněný příkaz k ošetření tohoto omezení.
/**********************/ /* soubor
if-else1.c
*/ /**********************/ #include <stdio.h> int main(void) { float a, b; puts("Zadej dve racionalni cisla:"); scanf("%f %f", &a, &b); if (b == 0.0) puts("\b\nNulou delit nelze!\n"); else { float podil; podil = a / b; printf("Jejich podil je: %10.2f\n", podil); } return 0; }
Jako první příkaz po testu if
je jednoduchý výstup
řetězce puts()
. Je ukončen středníkem a následuje
klíčové slovo else
. Příkaz v této části je
tvořen blokem. Za blokem středník není. Pokud by tam byl, byl
by chápán jako prázdný příkaz. Tak je interpretován i
středník za posledním příkazem v bloku.
V úvodu této kapitoly jsme si shrnuli příkazy jazyka C.
Nepřekvapí nás tedy umístění podmíněného příkazu if
jako jednoho z příkazů if-else
. Zpravidla se
umisťuje na místo druhého příkazu. Výsledná konstrukce bývá
často nazývána if-else-if
5:
if ( <expression1> ) <statement1>;
else if ( <expression2> ) <statement2>;
else if ( <expression3> ) <statement3>;
...
else if ( <expressionN> ) <statementN>;
else <statementN+1>;
Její často využívanou vlastností je skutečnost, že se
provede právě jeden z příkazů. Pokud není poslední příkaz
bez podmínky statementN+1
uveden, nemusí se provést
žádný. Jinak řečeno, provede se nejvýše jeden.
Zapamatujme si dobře tuto konstrukci. Nejen pro její
užitečnost. Po příkladu ji budeme moci porovnat s konstrukcí
zvanou přepínač.
Naším úkolem je programově ošetřit, jaký alfanumerický
znak byl zadán. Případně vydat zprávu o zadání znaku jiného. Protože
je jisté, že zadaný znak patří právě do jedné z tříd
malá písmena, velká písmena, číslice a jiné, použijeme
konstrukci podmíněného příkazu. Při použití if-else
by pro každou třídu byla znovu testována příslušnost
načteného znaku. Bez ohledu, zdali znak již některou z
předchozích podmínek splnil. Použitá konstrukce if-else-if
případné nadbytečné testy odstraní. Vždy bude vybrán právě
jednen z příkazů. Připomeňme si rovněž logický výraz,
který tvoří podmínku
if ((znak >= 'a') && (znak <= 'z'))
Vnější závorky jsou nezbytné, neboť ohraničují podmínku
příkazu if
. Vnitřní závorky naopak uvést nemusíme.
Priorita operátoru &&
je nižší než
relačních operátorů <=
a >=
.
Závorky jsme přesto uvedli, neboť zvyšují čitelnost. Celý
výpis zdrojového textu následuje.
/**********************/ /* soubor
if-else2.c
*/ /**********************/ #include <stdio.h> int main(void) { int znak; printf("Zadej alfanumericky znak:"); scanf("%c", &znak); printf("\nZadal jsi "); if ((znak >= 'a') && (znak <= 'z')) printf("male pismeno\n"); else if ((znak >= 'A') && (znak <= 'Z')) printf("velke pismeno\n"); else if ((znak >= '0') && (znak <= '9')) printf("cislici\n"); else printf("\nNezadal jsi alfanumericky znak!\n"); return 0; }
Přepínač slouží k rozdělení posloupnosti příkazů na části, následné vybrání a provedení některé, či některých z nich. Pokud nám tato formulace přepínač příliš nepřiblížila, pokusme se jinak.
Přepínač slouží k větvení výpočtu podle hodnoty celočíselného výrazu.
Syntakticky zapsaný příkaz přepínač má tento tvar:
switch ( <expression> ) <statement>
case <constant expression> :
default :
Syntaktickou definici přepínače ovšem musíme upřesnit.
Po klíčovém slově switch
následuje celočíselný
výraz expression
uzavřený v závorkách. Za ním
je příkaz statement
, zpravidla tvořený blokem.
Blok představuje posloupnost příkazů, v níž mohou být umístěna
návěští, jejichž syntaxi vidíme na druhé řádce definice.
Řídící příkaz tvoří celočíselný konstantní výraz6 constant
expression
uvozený klíčovým slovem case
a
ukončený dvoutečkou :
. Jedno z návěští může
být klíčovým slovem default
, přirozeně
ukončeným dvoutečkou :
.
Sémantika přepínače je poměrně složitá. Popíšeme si
jednotlivá pravidla, jimiž se řídí:
Program vyhodnotí konstantní výraz a jeho hodnotu porovnává
s každým z case
návěští přepínače. Návěští case
může být obsaženo uvnitř jiných příkazů (v rámci přepínače),
kromě případného vnořeného přepínače.
V jednom přepínači se nesmí používat dvě návěští se stejnou hodnotou.
Nastane-li shoda hodnoty case
návěští s
hodnotou switch
výrazu expression
, je
přeneseno řízení programu na toto návěští. Jinak je řízení
přeneseno na návěští default
v rámci příslušného
přepínače. Pro návěští default
platí stejné
zásady jako pro jiná návěští.
Pokud nenapíšeme default
návěští a hodnota
výrazu switch
se nebude shodovat s žádným z návěští,
bude řízení přeneseno na příkaz následující za přepínačem.
Pokud program při provádění prěpínače vykoná příkaz break
,
bude řízení přeneseno na příkaz následující za přepínačem.
Příkaz break
může být v rámci přepínače umístěn
v libovolných příkazech, kromě případných vnořených do
, for
, switch
nebo while
příkazech7.
Přepínač switch
může mít mnoho forem. Podívejme
se na příklad, v němž použijeme jednu z nich. Naším úkolem
je podat informaci o tom, jaká hodnota padla při simulovaném
hodu kostky. Místo kostky použijeme generátor pseudonáhodných
čísel (dále jim budeme říkat jen náhodná). Protože
takovou elektronickou kostku budeme používat i v příkladu v následujícím
odstavci, věnovaném cyklům, probereme si funkce s ní spojené
podrobněji.
Pomocí funkce srand()
8nastavíme posloupnost náhodných čísel. Jako
počáteční hodnotu nemůžeme zvolit konstantu, neboť pak by
byla generovaná posloupnost náhodných veličin vždy stejná.
Proto potřebujeme vhodnou hodnotu, která bude při každém
spuštění programu jiná. Takto vhodně se mění například
čas. Proto použijeme jako argument návratovou hodnotu funkce time()
9. Jiné záměry
s funkcí time()
nemáme, proto použijeme jako její
argument NULL
. Nesmíme jen zapomenout čas správně
přetypovat. A generátor máme připraven:
srand((unsigned) time(NULL) );
Teď musíme umět kostkou házet. Při volání funkce rand()
dostáváme náhodné celé číslo v rozsahu 0 až RAND_MAX
.
16-ti bitové BC31 definuje tuto hodnotu jako MAXINT
,
konkrétně 32767. Pro naši potřebu stačí číslo v rozsahu 0
až 5, k němuž přičteme jedničku. Tuto práci odvede operace
modulo šesti.
switch (rand() % 6 + 1)
Získaná hodnota 1 až 6 je výrazem přepínače switch
.
V závislosti na této hodnotě se řízení programu přenese na
konstantní návěští. Problém je v tom, že pokud bychom
takto označenou posloupnost příkazů neukončili příkazem break
,
pokračoval by od návěští program dále, až po konec přepínače.
I této vlastnosti se dá využít. Ukázku vidíme ve spojeném
hlášení pro hodnoty 2 a 3. Umístění návěští default
v přepínači je libovolné. Zpravidla se píše na konec, což
je poměrně zakořeněný zvyk. Budeme jej rovněž dodržovat.
/**********************/ /* soubor
switch-1.c
*/ /**********************/ #include <stdlib.h> #include <stdio.h> #include <time.h> int main(void) { char *s; printf("\nHazim kostkou...\n"); srand((unsigned) time(NULL) ); switch (rand() % 6 + 1) { case 1: s = "jednicka"; break; case 2: case 3: s = "dvojka nebo trojka"; break; case 4: s = "ctyrka"; break; case 5: s = "petka"; break; default: s = "sestka"; break; } printf("\nPadla %s.\n\n", s); return 0; }
Srovnáme-li přepínač s konstrukcí if-else-if
,
vidíme zásadní rozdíly:
if
může testovat
hodnoty jakéhokoliv typu10, zatímco rozhodovací výraz příkazu switch
musí být výhradně celočíselným výrazem. if-else-if
se provede nejvýše
(či podle použití právě) jeden z příkazů. I u
přepínače se nemusí provést žádný z příkazů.
Může jich být ovšem provedeno více. Konstantní návěští
určuje pouze první z nich. Pokud chceme, oddělíme následující
příkazy příkazem break
. default
může
vyskytovat kdekoliv. Odpovídající varianta v
konstrukci ifelseif
může být umístěna
pouze na konci11. Cyklus je část programu, která je v závislosti na podmínce prováděna opakovaně. U cyklu obvykle rozlišujeme řídící podmínku cyklu a tělo cyklu. Řídící podmínka cyklu určuje, bude-li provedeno tělo cyklu, či bude-li řízení předáno za příkaz cyklu. Tělo cyklu je příkaz, zpravidla v podobě bloku.
Cykly můžeme rozdělit podle toho, provede-li se tělo
alespoň jedenkrát, a cykly, kde tělo nemusí být provedeno
vůbec. Rozhodně můžeme říci, že i když v C existují
různé typy cyklů, je možné vystačit s jedním z nich.
Přesto si v této podkapitole povíme o všech. Jejich výběr
ponecháme na vhodnosti použití v dané situaci i na jejich
individuální oblibě. V části věnované příkazu while
si popíšeme některé vlastnosti společné všem cyklům.
Postupně tedy while
, for
a do
.
Příkaz while
, vykonává příkaz statement
(tělo cyklu) vícekrát, nebo vůbec, dokud má v daném
kontextu testovací výraz expression
nenulovou
hodnotu. Syntaxe příkazu while
je následující:
while ( <expression> ) <statement>
Příkaz je velmi často blokem. Zde se zejména začátečníci
mylně domnívají, že pokud se kontext kdykoliv během provádění
příkazů bloku těla cyklu změní, a podmínka tak přestane být
splněna, je cyklus opuštěn. To ovšem není pravda. Pravidlo
říká, že se příkaz statement
provede, je-li
podmínka expression
splněna. Je-li příkazem
blok, provede se tedy blok celý. Teprve poté je znovu proveden
test. Názornější bude, podívat se na vývojový diagram.
Ve vývojovém diagramu se vyskytují nepovinné příkazy break
a continue
. S prvním z nich jsme se již setkali u
přepínače. Druhý zatím neznáme. Jejich sémantiku,
zakreslenou ve vývojovém diagramu, si nyní popíšeme. Předem
poznamenejme, že oba jsou pokládány za prostředky
strukturovaného programování.
Příkaz break
má ve všech cyklech stejný význam.
Ukončí provádění příkazů těla cyklu a předá řízení
prvnímu příkazu za příkazem while
. Tímto
způsobem můžeme bezprostředně ukončit průběh cyklu bez
ohledu na hodnotu podmínky.
Příkaz continue
rovněž ukončí provádění
příkazů těla cyklu. Řízení ovšem předá těsně před
příkaz cyklu. Proběhne tedy vyhodnocení testovacího výrazu
a podle jeho hodnoty pokračuje program stejně, jako by bylo
tělo cyklu vykonáno do konce (tedy bez předčasného ukončení
vykonáním continue
). Podobně jako break
,
má příkaz continue
ve všech cyklech stejný význam.
Použití příkazu while
ukazuje příklad.
Opět v něm používáme kostku. S ní související funkce jsme
popsali v předchozím příkladu. Tentokrát je naším cílem
sečíst počet pokusů, potřebných k tomu, abychom hodili
šestku POCET
-krát. Současně s novou látkou si
připomeneme některé poznatky z předchozích kapitol.
Konstanta POCET
12, která nemá uveden typ má implicitně typ
int. Klíčovým slovem static
použitým při
deklaraci proměnných celkem
a pocet
(je to jiný identifikátor než POCET
), nejen
umisťujeme tyto proměnné do datového segmentu programu, ale zároveň
je jim při spuštění programu definována počáteční
hodnota nula. Díky tomu je dále nemusíme inicializovat.
Cyklus while
samotný probíhá tak dlouho, dokud
platí podmínka (pocet < POCET)
. Za blokem,
tvořícím příkaz cyklu, nemusíme psát ukončovací středník.
Následuje formátovaný standardní výstup výsledku a závěr
funkce main()
.
/**********************/ /* soubor
while-1.c
*/ /**********************/ #include <stdlib.h> #include <stdio.h> #include <time.h> const POCET = 10; int main(void) { static int celkem, pocet; printf("\nHazim kostkou dokud mi nepadne %d-krat sestka. ...\n", POCET); srand((unsigned) time(NULL) ); while (pocet < POCET) { celkem++; if ((rand() % 6 + 1) == 6) pocet++; } printf("\nA je to! Hodu bylo celkem %d.\n\n", celkem); return 0; }
Následující příklad ukazuje použití příkazu while
spolu s if-else-if
a příkazy break
a continue
.
Naším úkolem je porovnání dvou načtených řetězců a
zobrazení menšího z nich. Tento příklad používá
aritmetiku ukazatelů, probíranou v rámci jedné z dalších
kapitol. V tomto okamžiku přijměme skutečnost, že
prostřednictvím ukazatelů porovnáváme ASCII hodnoty jednotlivých
znaků odpovídajících řetězců. Každý řetězec je
ukončen znakem s kódem nula.
Zvolená mnemonika pojmenovává dva řetězce a
a b
, ukazatele na, respektive do, těchto řetězců pa
a pb
. Identifikátor pk
představuje
ukazatel na kratší z porovnávaných řetězců.
Algoritmus úlohy srovnává postupně znaky obou řetězců,
dokud jsou si rovny:
else if (*pa == *pb)
{
pa++; pb++;
continue;
}
Použití continue
není v našem případě
nezbytné. Díky if-else-if
nemůže v této větvi
těla cyklu následovat jiný příkaz. Naopak break
v
obou zbývajících větvích opouští cyklus. Ukončuje tím
srovnávání řetězců a určuje kratší z nich. V prvním ze
zmíněných případů je
if (*pa < *pb)
{
pk = a;
break;
}
hodnota znaku v řetězci a
menší, než v
řetězci b
. a
je tudíž kratší.
Cyklus je ukončen. Dále bychom totiž opustili definovaný rozsah
řetězce a
. A protože je podmínka cyklu napsána
tak, že zajišťuje jeho opakování, dokud nenarazíme na konec alespoň
jednoho z řetězců:
while ((*pa != 0x0) && (*pb != 0x0)) /* '\0' 0
*/
Máme jistotu, že pokud nenastaly předchozí možnosti, musí
platit:
else
{
pk = b;
break;
}
Tedy, že kratší je druhý řetězec. Těsně za tělem
cyklu máme ošetřenu variantu, kdy skončí druhý z řetězců
dříve, než se jejich obsahy lišily. Pak je kratším z
řetězců. Nám nezbývá, než jej zobrazit a ukončit program.
Následuje nepřerušený výpis zdrojového textu řešení.
/************************************************/ /* soubor
cmp_str.c
- compare two strings */ /* porovna dva nactene retezce a zobrazi mensi */ /************************************************/ #include <stdio.h> #define DELKA 50 int main(void) { char a[DELKA], b[DELKA], *pa, *pb, *pk; /* pa[], pb[], pk[] */ pk = pa = gets(a); pb = gets(b); while ((*pa != 0x0) && (*pb != 0x0)) /* '\0' 0 0x0 - totez*/ { if (*pa < *pb) { pk = a; break; } else if (*pa == *pb) { pa++; pb++; continue; } else { pk = b; break; } } if ((*pa != 0x0) && (*pb == 0x0)) pk = b; puts("\nkratsi je:"); puts(pk); return 0; }
Příkaz for
provádí příkaz statement
vícekrát,
nebo vůbec, dokud je hodnota nepovinného testovacího výrazu expr2
nenulová.
V příkazu for
můžeme ještě napsat dva další
výrazy s vedlejším efektem, expr1
a expr3
.
Syntaxe for
:
for ( [<expr1>] ; [<expr2>] ;
[<expr3>] ) <statement>
Nepovinný výraz expr1
je proveden před prvním
vyhodnocením testu. Typicky se používá pro inicializaci
proměnných před cyklem. Po každém provedení těla cyklu statement
,
provede program nepovinný výraz expr3
. Typicky se
jedná o přípravu další iterace cyklu. Pokud neuvedeme
testovací výraz expr2
, použije překladač
hodnotu 1
, a tedy bude provádět nekonečný
cyklus. Naštěstí můžeme použít příkazy break
a continue
se stejným významem, jaký jsme popsali
u while
.
Vývojový diagram úplné varianty příkazu for
je na obrázku, v němž jsme ponechali značení odpovídající
výše uvedené syntaxi:
Pro tisk ASCII tabulky znaků s kódy 32 až 127 použijeme
příkaz for
v úplné variantě:
for (znak = ' '; znak < 128; znak++)
V tomto případě můžeme nazývat proměnnou znak
řídící
proměnnou cyklu. Před testem ji inicializujeme mezerou13, tedy
prvním zobrazitelným ASCII znakem. Následuje test na hodnotu
128. Provádí se před každým průchodem tělem cyklu. Není-li
podmínka splněna, pokračuje se za cyklem.
Po každém průchodu tělem cyklu je řídící proměnná
cyklu znak
zvýšena o jedničku. Tak je připraven
další průchod cyklem s hodnotou následného ASCII znaku.
Samotné tělo cyklu vlastně jen zobrazuje jednotlivý znak.
Je-li jeho ASCII hodnota dělitelná 16 beze zbytku, zajistí
vysláním konce řádku tvar tabulky.
/**********************/ /* soubor
for-1.c
*/ /**********************/ #include <stdio.h> int main(void) { int znak; putchar('\n'); for (znak = ' '; znak < 128; znak++) { if (znak % 16 == 0) putchar('\n'); putchar(znak); } putchar('\n'); return 0; }
/*
!"#$%&'()*+,-./
0123456789:;<=>?
@ABCDEFGHIJKLMNO
PQRSTUVWXYZ[\]^_
`abcdefghijklmno
pqrstuvwxyz{|}~&127
*/
Příkaz do
je jediným z cyklů, který
zajišťuje alespoň jedno provedení těla cyklu. Jinak
řečeno, jeho testovací příkaz statement
je
testován až po průchodu tělem cyklu. Pokud je test splněn,
provádí se tělo cyklu. Po syntaktické stránce tvoří tělo
cyklu opět výraz expression
:
do <statement> while ( <expression> );
Vývojový diagram příkazu do
tuto vlastnost
ukazuje ještě názorněji:
Příkazy break
a continue
v těle
cyklu se chovají stejně, jaako v cyklech ostatních. Po break
je cyklus opuštěn, zatímco po continue
je
proveden výraz expression
a podle jeho výsledku se
pokračuje dále.
Časté použití příkazu do
nalezneme například
v těch numerických výpočtech, kdy je alespoň jedna iterace
nezbytná. V našem případě se jedná o výpočet přibližné
hodnoty Eulerova čísla. V prvním přiblížení položíme
hodnotu e
rovnu jedné stejně, jako hodnotu přírůstku epsilon
.
Za upozornění stojí datový typ long double
, a
tedy i odpovídající vhodné určení typů číselných
konstant. I ve formátovaném výstupu jsme museli specifikovat
příslušný datový typ. Operátory přiřazení spojené s
operací nad svou levou stranou jsou použity spíše pro
připomenutí jejich existence.
/**********************/ /* soubor
dowhile2.c
*/ /**********************/ #include <stdio.h> #include <math.h> #define chyba 1.0e-15L int main(void) { long double e = 1.0L, epsilon = 1.0L; unsigned long n = 0L; printf("\n"); do { epsilon /= ++n; e += epsilon; } while (epsilon > chyba); printf("e=%21.18Lf\tpocet diteraci:%ld", e, n); return 0; }
Příkaz skoku patří k zatracovaným příkazům
strukturovaného programování. Skutečně s jeho pomocí dokáže
méně zkušený programátor vytvořit zdrojový text, pro
nějž se vžilo označení špagetový.
Skutečnost, že jsme si příkaz skoku nezatajili má tři příčiny:
break
, continue
a return
15 jsou označovány jako strukturované
skoky. Jejich použití teorie (ani praxe) programování
neodmítá. Zůstává nám tedy jen příkaz skoku goto
.
Jeho syntaxe je jednoduchá:
identifier: <statement> ;
goto <identifier> ;
Uvedli jsme si nejen syntaxi goto
samotného, ale
i souvisejícího návěští identifier
. Návěští
neprovádí žádnou akci a nemá jiný vliv na řízení běhu.
Jeho identifikátor jen označuje nějaké místo ve zdrojovém
textu. Příkaz goto
přenáší řízení na příkaz, označený
návěštím. V rámci jedné funkce nesmí být dvě stejná návěští.
Výsvětlivky:
1 V tomto skriptu věnujeme
funkcím celou kapitolu.
2 Nezapomeňme, jednotlivé příkazy
jsou ukončeny středníky.
3 To je jasné, uvědomíme-li
si, že makra zpracovává preprocesor. Teprve takto zpracovaný
text s expandovanými makry je vstupem pro samotný překladač.
4 Jinak by se o příkazy
nejednalo.
5 Některé programovací jazyky
kvůli ní dokonce zavádí klíčové slovo elif.
6 Tedy výraz vyčíslitelný
během překladu. K celočíselným výrazům patří i znakové
výrazy.
7 Tyto příkazy mohou break
obsahovat. Jeho význam pak ovšem bude spojen s nimi, nikoliv s
vnějším příkazem case
.
8 Její prototyp je umístěn v
hlavičkovém souboru stdlib.h
.
9 Její prototyp je umístěn v
hlavičkovém souboru time.h
.
10 Je vhodné, aby výsledkem
testu byla celočíselná hodnota, nejlépe 0 a 1. Jinak
automaticky proběhne konverze.
11 Případně jen na začátku.
To bychom museli neobvykle negovat podmínky.
12 Díky tomu, že je definována
mimo tělo funkce je rozsahem její platnosti celý soubor (počínaje
místem definice).
13 ASCII kód mezery je 32.
14 Přeložený tvar našich
"pěkných strukturovaných programů" skoky ostatně
stejně obsahuje.
15 První dva jsme již popsali
dříve v této kapitole. Příkazu return
se
věnujeme v souvislosti s funkcemi.
Název: | Programování v jazyce C |
Autor: | Petr Šaloun |
Do HTML převedl: | Kristian Wiglasz |
Poslední úprava: | 19.11.1996 |