AMIGA REVIEW online
  Uvodná stránka     Software     Hry     Obaly     Download     Amiga na PC     Amiga Forever  

Kurz jazyka C - 4. díl

Pavel Číž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


© ATLANTIDA Publishing Všechna práva vyhrazena.
Žádna část nesmí být reprodukována nebo jinak šířena bez písemného svolení vydavatele.



Amiga na Vašem PC rychle, snadno a zdarma!


none

AMIGA REVIEW

57 ( 11-12 / 2000 )
56 ( 9-10 / 2000 )
55 ( 7-8 / 2000 )
54 ( 5-6 / 2000 )
53 ( 3-4 / 2000 )
52 ( 1-2 / 2000 )
 
51 ( 12 / 1999 )
50 ( 11 / 1999 )
49 ( 10 / 1999 )
48 ( 9 / 1999 )
46-47 ( 7-8 / 1999 )
45 ( 6 / 1999 )
44 ( 5 / 1999 )
43 ( 4 / 1999 )
42 ( 3 / 1999 )
41 ( 2 / 1999 )
40 ( 1 / 1999 )
 
39 ( 12 / 1998 )
38 ( 11 / 1998 )
37 ( 10 / 1998 )
36 ( 9 / 1998 )
35 ( x / 1998 )
34 ( x / 1998 )
33 ( 1-2 / 1998 )
 
32 ( 11-12 / 1997 )
31 ( 9-10 / 1997 )
30 ( 7-8 / 1997 )
29 ( 6 / 1997 )
28 ( 5 / 1997 )
27 ( 4 / 1997 )
26 ( 3 / 1997 )
25 ( 2 / 1997 )
24 ( 1 / 1997 )
 
23 ( 12 / 1996 )
22 ( 11 / 1996 )
21 ( 10 / 1996 )
20 ( 9 / 1996 )
18-19 ( 7-8 / 1996 )
17 ( 6 / 1996 )
16 ( 5 / 1996 )
15 ( 4 / 1996 )
14 ( 3 / 1996 )
13 ( 2 / 1996 )
12 ( 1 / 1996 )
 
11 ( 12 / 1995 )
10 ( 11 / 1995 )
9 ( 10 / 1995 )
8 ( 9 / 1995 )
7 ( 7 / 1995 )
6 ( 5 / 1995 )

ATLANTIDA NEWS

5 ( 3 / 1995 )
4 ( 1 / 1995 )
 
3 ( 11 / 1994 )
2 ( 9 / 1994 )
1 ( 7 / 1994 )
0 ( 5 / 1994 )