Kurz jazyka C - 4. dílPavel Čížek
Vítám Vás u další části kurzu, kterou můžeme nazvat "poslední úvodní". Dnes
dokončíme rychlý průřez jazykem C, od příště začínáme hezky od začátku (skoro),
tentokrát pomalu a podrobně. To je příležitost, aby se k nám připojili ti, kteří
tak ještě neučinili. A kdo to umožnil? Měsíčník AMIGA Review, který Vám bude
přinášet informace dvakrát častěji a poskytne nám tak více prostoru a času i pro
náš seriál.
Úvodní průřez berte jako seznámení se s Céčkem přehled, který nám bude
užitečný právě v dalších částech kurzu, kdy budeme postupovat pomalu a od
základů, vše budeme demonstrovat na vývoji nějaké konkrétní menší aplikace. Tyto
úvodní kapitoly nám umožní postupovat dále, aniž bychom stále škobrtali (jistou
představu o jazyce jste snad získali).
Řídící struktury
V této části (poslední přehledové, jak jsme ji již v úvodu nazvali) na nás
zaútočí řídící struktury Céčka (příkazy). Samozřejmě si na závěr vše ukážeme na
příkladech. Minule jsme se probrali spoustou nejrůznějších operátorů; s nimi
úzce souvisí výrazy, neboť operátory slouží právě k vytváření složitějších
výrazů. Základem výrazů (primárním výrazem) jsou např. identifikátory
proměnných, konstanty, řetězce, indexový výraz (což je primární výraz
následovaný výrazem v hranatých závorkách, který slouží například k odkazu na
položku pole, a[i]), volání funkce a také výběr položek struktur či unionů.
Složitější výrazy lze vytvářet z těchto základních pomocí operátorů, klasickým
příkladem je např. součet dvou proměnných a + b či násobení konstantou 3 *
a[5]. Chtěl bych upozornit na jednu podstatnou věc z tohoto vyplývající:
přiřazení je také operátor, a proto a = b + 3 je také výraz!
Ve výrazech samozřejmě nelze kombinovat náhodně cokoli, příslušné části musí být
stejných typů (lze např. sčítat dvě celá čísla ale těžko sečtete strukturu a
položku pole). Samozřejmě proměnné typu long a short nejsou téhož typu, ale
sčítat je chceme; proto Céčko provádí automaticky některé konverze. Pokud není
konverze prováděna automaticky, můžeme ji přikázat (to si musíte ovšem dobře
rozmyslet!). Implicitní konverze vypadá například tak, že vyskytne-li se ve
výrazu proměnná typu long int, je i druhá proměnná konvertována na tento typ.
Podrobněji o konverzích a podobných záležitostech pojednáme později.
Příkazy:
Výrazový příkaz se tvoří z výrazu připojením znaku ; (středník) za výraz.
Středník (jak už víme) se používá pro ukončení řídících konstrukcí Céčka. Takže
připojíme-li ho za výraz b + 5, dostaneme výrazový příkaz
b+5;
Nejčastěji samozřejmě použijete výrazový příkaz ve spojení s operátorem
přiřazení; to je obdoba přiřazovacího příkazu z jiných programovacích jazyků.
Nezapomeňme ani na volání funkce - se středníkem také tvoří samostatný příkaz,
například
a = funkce f(x, 2);
printf("Ahoj!
");
Další konstrukcí je blok. Blok umožňuje vytvářet z jednoduchých příkazů příkazy
složené. V nejjednodušší podobě se jedná o prostou posloupnost příkazů uzavřenou
ve složených závorkách:
{ příkaz_1, příkaz_2, ..., příkaz_n }
V Céčku máte navíc možnost připojit na počátek posloupnosti příkazů posloupnost
deklarací. Obecný tvar bloku tedy je
{ #deklarace_1 #... #deklarace_n # #příkaz_1 #... #příkaz_n }
Každá deklarace je samozřejmě ukončena středníkem, příkazy končí středníkem nebo
koncovou } jedná-li se o vnořeny blok. Poznáváte ho? Ano, jak je vidět, tělo
každé funkce není tvořeno ničím jiným než jedním blokem. Poznamenejme, že
proměnné deklarované na počátku bloku jsou v tomto bloku lokální, lze je tedy
využívat pouze v rámci tohoto bloku. Asi jste si už všimli také toho, že blok,
resp. jeho ukončovací závorka nemusí být následována středníkem.
Dalším důležitým příkazem je podmíněný příkaz. Jak název napovídá, slouží k
podmíněnému vykonávání příkazu. Podmíněný příkaz může mít dva tvary, vždy je
uvozen klíčovým slovem if:
kratší varianta: if (výraz) příkaz_1;
delší varianta: if (výraz) příkaz_1;
else příkaz_2;
Podmínkou je výraz, který musí být uzavřen v závorkách a který je vyhodnocen
před provedením příkazu; je-li jeho hodnota nenulová (TRUE, jak již víme), bude
vykonán příkaz_1, v opačném případě bude vykonán případný příkaz_2 (je-li
uveden). Pomocí tohoto příkazu lze pak již snadno napsat např. funkci pro výběr
maxima ze dvou čísel:
int max(int x, int y)
{
if (x < y) return(y);
else return(x);
}
Pozor! Jsou li příkazy if vložen do sebe, vztahuje se else vždy k
nejbližšímu předchozímu.
Užitečnou konstrukcí je také přepínač, který slouží pro větvení výpočtu podle
hodnoty celočíselného výrazu. Obecný tvar přepínače vypadá následovně:
switch (výraz)
{
case hodnota_1: příkaz_1;
...
case hodnota_n: příkaz_n;
default: příkaz;
}
Přepínač vyhodnotí celočíselný výraz uvedený na jeho počátku (opět v závorkách)
za klíčovým slovem switch. Pak se výsledek postupně srovnává s hodnotami za
klíčovými slovy case; dojde-li ke shodě, provede se příslušný příkaz. Pokud
výraz není roven žádné hodnotě za slovem case a je uvedena i část s klíčovým
slovem default (není povinná), provede se příkaz za tímto klíčovým slovem.
Důležité upozornění: po zpracování příkazu u case se provádí vykonávání
příkazů také následujících case větví až do vyčerpání seznamu přepínače nebo
zpracování příkazu break! Chceme-li tedy, aby se přepínač choval podobně jako
v ostatních jazycích, tj. aby se vykonal vždy právě a pouze příkaz uvedený za
nalezeným case, použijeme přepínač tvaru:
switch (výraz)
{
case hodnota_1: příkaz_1; break;
...
case hodnota_n: příkaz_n; break;
default: příkaz;
}
Ukažme si jednoduchý příklad demonstrující možnosti uvedených příkazů. K zadané
známce vypíšeme slovní hodnocení.
#include <stdio.h>
/*funkce vrací ukazatel na znak - takto se předávají řetězce v C; posíláme si
ukazovátko na první písmeno, konec je označen znakem */
char *Hodnoceni(int znamka)
{
char *text;
/*sem uložíme hodnocení */
/*otestujeme, je-li známka ve známém rozsahu, || je logický OR - "nebo" */
if ((znamka < 1) || (znamka > 5))
text= "Známka mimo rozsah 1 .. 5"
else /* jinak použijeme přepínač podle známky dáme do text hodnocení */
switch (znamka)
{
case 1: /*případy 1, 2 hodnotíme společně */
case 2: /* u case 1 není žádný příkaz, pokračuje se příkazem pro case 2*/
text = "Výborný výsledek";
break; /* zde se ukončí zpracování case 1 i 2 */
case 3: text = "Není to nejhorší ";
break; /*konec zpracování case 3 */
case 4; /*jako u case 1 a 2 - společně 4 */
case 5:
text= "S tím se asi chlubit nebudeš";
break; /*zde se ukončí zpracování case 4 a 5 */
}
/* vrátíme ukazatel na hodnocení */
return(text);
}
void main()
{
int znamka;
/*načteme známku do proměnné znamka; scanf už známe */
printf "
Zadejte známku: ");
scanf("%d", &znamka);
/* a vytiskneme hodnocení; znak %s říká, že parametr je řetězec */
printf("Hodnoceni: %s
", Hodnoceni(znamka));
}
Příklad je poměrně jednoduchý, ale využili jsme if i switch. Pomocí
podmíněného příkazu vyloučíme nesmyslné případy, přepínač nám pak umožní určit
hodnocení v závislosti na hodnotě známky. Zde jsou dobře patrné výše popsané
vlastnosti přepínače - bude-li známka 1 nebo 2, pak (protože u case 1 není
uveden žádný příkaz, pokračuje se tedy příkazy u následujících návěští, zde tedy
u case 2) se vykoná přiřazení téhož textu "Výborný výsledek" a vykonávání
skončí, neboť narazíme na break. Podobné je to u ostatních známek, u case 3
je za přiřazovacím příkazem uveden hned break, nebudou se tedy příkazy dalších
větví provádět.
Cykly
Cyklus slouží pro řízené opakování nějaké činnosti, výpočtu. V jazyce C
existují tři typy cyklů: while, do .. while a for. Hned se s nimi seznámíme.
Cyklus while (while je klíčové slovo, znamená dokud) má tvar: while (výraz)
příkaz;
V této konstrukci tvoří výraz podmínku provedení příkazu příkaz. Dokud má
vyhodnocený výraz nenulovou hodnotu (TRUE), provádí se příkaz; při nulové
hodnotě (FALSE) se cyklus ukončí. Podmínka se tedy testuje před provedením cyklu
cyklus nemusí být proveden ani jednou. Cyklus můžeme číst jako "dokud je splněna
podmínka, prováděj příkaz".
Cyklus do .. while (do je také klíčové slovo) má tvar do #příkaz while
(výraz);
I zde výraz určuje podmínku provádění cyklu. Tato podmínka se však vyhodnocuje
až po provedení těla cyklu (a opět, je-li podmínka splněna, opakuje se provádění
těla cyklu, má-li nulovou hodnotu provádění cyklu je ukončeno). Tělo cyklu se
proto provede alespoň jednou. Použití tohoto cyklu si můžeme demonstrovat na
předchozím příkladě se známkami a hodnocením pokud bychom chtěli hodnocení pro
více známek, museli bychom vždy program znovu spustit. To lze snadno vyřešit
použitím cyklu do .. while. Stačí tělo funkce main() upravit následovně:
do
{ /* načteme známku do proměnné mamka */
printf("
Zadejte známku:);
scanf("%d"; &znamka);
/* a vytiskneme hodnocení; znak %s říká, že parametr je řetězec */
printf("Hodnoceni: %s
, Hodnoceni(znamka));
} while (znamka !=0);
Pak se bude dotaz na známku a výpis příslušného hodnocení opakovat, dokud
nezadáme známku 0. Po té se program ukončí.
Posledním, velice výkonným, je cyklus for, který se na rozdíl od předchozích
nepodobá příliš cyklům v jiných programovacích jazycích. Tento cyklus má obecně
tvar
for (výraz_1; výraz_2; výraz_3) příkaz;
Přitom výraz_1 se vyhodnotí jen jednou, před vlastním započetím provádění
cyklu; obvykle slouží pro nastavení počátečních hodnot. výraz_2 se vyhodnotí
před každým provedením těla cyklu; má-li hodnotu TRUE, provádí se příkaz, je-li
nulový (FALSE), cyklus se ukončí. Je to tedy podmínka se stejným významem jako
podmínka u while cyklu. výraz_3 se vyhodnotí po provedení těla cyklu; slouží
obvykle pro změnu řídící proměnné cyklu. Význam cyklu for lze ekvivalentně
zapsat pomocí cyklu while takto:
výraz_1;
while (výraz_2)
{
příkaz;
výraz 3;
}
Jak je patrné, je cyklus for velice obecný a lze ho tedy použít téměř všude.
Jeho praktické využití si můžeme ukázat např. na vytvoření funkcestrlen() to
je standardní Céčkovská funkce pro určení délky zadaného řetězce.
int strlen(char *retezec)
{ int delka;
for(delka = 0; *retezec != ; retezec++)
delka++;
}
Jak je vidět, inicializační výraz_1 používáme pro nastavení délky na nulu,
podmínka vykonávání cyklu platí, dokud nenarazíme na znak (což značí konec
řetězce), a na konci každého cyklu posuneme ukazatel na řetězec o 1 znak dále
(příkaz retezec++). Vlastní tělo cyklu pak obsahuje jediný příkaz delka++
který při každém opakování cyklu zvýší hodnotu delka o 1.
Pro porovnání jednotlivých cyklů si uveďme funkci faktorial(), která spočte
pro zadané přirozené číslo výraz n!=1*2*...*n.
Příkazy skoku
Příkazy skoku slouží pro řešení výjimečných situací v programu, kdy se
nevyplatí jiné řešení. V jazyce C existuje několik typů skoků. Strukturované
skoky slouží pro řádné opuštění posloupnosti příkazů ve strukturovaných
příkazech - jedná se o příkazy break, continue a return . S příkazem
break sme se již setkali u přepínače. Obecně slouží přerušení nejblíže
nadřazené konstrukce a jejímu ukončení. Uvedete-li break v některém z již
zmíněných cyklů, bude tento přerušen a program bude pokračovat příkazem, který
následuje za cyklem. Příkaz continue také přeruší provádění nejblíže nadřazené
konstrukce (cyklu) a způsobí přechod na nový cyklus, aniž se dokončil předchozí
průběh (bude tedy znovu vyhodnocena podmínka cyklu a dle její hodnoty se bude
dále pokračovat). Posledním skokem, se kterým jsme se již často setkali, je
příkaz return, který má jednu z následujících podob:
return výraz; return(výraz); return;
Tento příkaz způsobí opuštění těla funkce a pokud obsahuje výraz, stane se
hodnota tohoto výrazu funkční hodnotou. Pokud je funkce typu void, musí být
použit příkaz return bez výrazu.
Kromě strukturovaných skoků existuje v Céčku také nestrukturovaný skok goto.
Jeho použití je omezeno v rámci jedné funkce (nelze skákat z jedné funkce do
druhé, ale nemusíme se řídit blokovou strukturou, lze skákat ven z bloku i
dovnitř bloku. Po skoku do těla bloku je ovšem hodnota všech lokálních
proměnných tohoto bloku nedefinována! Abychom mohli provést příkaz goto ,
musíme určit, kam se má skočit. Příkaz, na který chceme skočit, musíme označit
pomocí návěští, což je libovolný identifikátor ukončený dvojtečkou. Tento
identifikátor se pak stane parametrem goto, jak hned uvidíme. Zpočátku je však
nejlepší dodržovat zásadu, že goto není vhodné používat.
Ukažme si realizaci strukturovaných skoků break a continue v cyklu while
pomocí skoku goto
/* příkaz break */
while (...)
{
/*nějaké příkazy */
/*zde je goto místo break */
goto break_navesti;
/*nějaké příkazy */
} /*konec cyklu */
break_navesti:
/* další příkazy */
/* příkaz continue */
while (...)
{
/*nějaké příkazy */
/*zde je goto místo continue */
goto continue_navesti;
/* nějaké příkazy */
continue_navesti: ;
} /*konec cyklu */
Jak jste si jistě povšimli, návěští musí být před nějakým příkazem. Na konci
cyklu (při realizaci continue) jsme napsali pouze středník - to je tzv. prázdný
příkaz, je tvořen samotným znakem ;. Příkazy jsou samozřejmě tvořeny také
voláním funkcí, jejichž účel může být velice rozmanitý.
Tím jsme ukončili náš průřez jazykem C, o němž jste snad získali alespoň jakousi
povrchní představu. Příště (jak jsem zmínil již na začátku) začneme tvořit
nějakou menší aplikaci (od primitivní verze spouštěné z příkazové řádky až po
program s mnoha vymoženostmi, uživatelským rozhraním apod.), na níž si ukážeme
všechny zde popsané vlastnosti jazyka C, podrobně si vše ještě jednou vyložíme
(tak aby se i naprostý laik nemusel obávat nepochopení) a navíc uvidíme letos z
toho, co "v manuálu nenajdete". Je to zároveň příležitost pro ty, kteří by
chtěli začít sledovat náš kurz, nebol právě v příštím pokračování mají možnost
ještě naskočit do rozjetého vlaku. Jakékoliv dotazy, nápady, návrhy a připomínky
adresujte redakci Amiga Review.
/* faktoriál pomocí cyklu while */
unsigned faktorial(unsigned n)
{
/* proměnná obsahující výsledek */
unsigned fact= 1;
/* dokud nedojdeme až k nule, provádíme tělo cyklu = blok */
while (n != 0)
{
fact *= n;
/* vynásobení n */
n--;
/* snížíme n o 1 */
}
/* vrátíme získaný výsledek */
return(fact);
}
/* faktoriál pomocí cyklu do .. while */
unsigned faktorial(unsigned n)
{
/* proměnná obsahující výsledek */
unsigned fact= 1;
/* nula se musí ošetřit zvlášť, cyklus alespoň jednou proběhne, což se pro n = 0
státi nemá */
if (n == 0) return(fact);
/* dokud nedojdeme až k nule, provádíme tělo cyklu = blok */
do
{
fact *= n;
/* vynásobení n */
n--;
/* snížíme n o 1 */
}
while (n != 0);
/* vrátíme získaný výsledek */
return(fact);
}
/* faktoriál pomocí cyklu for */
unsigned faktorial(unsigned n)
{
/* proměnná obsahující výsledek */
unsigned fact;
/* dokud nedojdeme až k nule, provádíme tělo cyklu = blok; podmínka n != 0 je
totožná s podmínkou n */
for(fact = 1; n; n--) fact *= n;
/* vrátíme získaný výsledek */
return(fact);
} Vytlačiť článok
Pozn.: články boli naskenované ako text a preto obsahujú aj zopár chýb. Taktiež neručíme za zdrojové kódy (Asm, C, Arexx, AmigaGuide, Html) a odkazy na web. Dúfame, že napriek tomu vám táto databáza dobre poslúži.
Žiadna časť nesmie byť reprodukovaná alebo inak šírená bez písomného povolenia vydavatela © ATLANTIDA Publishing
none
|