Predchozi kapitola

Obsah

Konec

Nasledujici kapitola

6. Rizeni chodu programu

6.1. Vyrazovy prikaz
6.2.
Prazdny prikaz
6.3.
Bloky.
6.4.
Oblast platnosti identifikatoru
6.5.
Podmineny prikaz if-else.
6.6.
Prepinac
6.7.
Cykly

Cyklus while
Cyklus for
Cyklus do

6.8. Prikaz skoku


V dosavadnim vykladu jsme se dozvedeli, ze se program sklada z funkce main() a z prikazu, ktere tato funkce obsahuje. Sve intuitivni predstavy o programu rozsirime nejen o pripadne dalsi funkce, ale detailneji1 se podivame i na obsah funkci. Telo funkce obsahuje radu prikazu. Nasim cilem je provadet prave ty prikazy, ktere odpovidaji zvolenemu zameru. Vyber z prikazu je urcen stavem dosavadniho behu programu, vstupnimi udaji a ridicimi strukturami, ktere jsme pouzili.

Program, provadejici prikazy v pevnem a nemennem poradi, ktere odpovida jejich umisteni ve zdrojovem textu a navic bez moznosti jejich vyberu, jiste neni nasim idealem. A to bez ohledu na zvoleny vyssi programovaci jazyk. Cilem teto kapitoly je proto seznameni s ridicimi strukturami.

Pred podrobnym pristupem nejprve uvedme prehledne prikazy, ktere mame v C k dispozici:

6.1. Vyrazovy prikazzpet

Vyraz zname z predchoziho textu. Vyrazem je nejen aritmeticky vyraz (napriklad a+b, ci 5+1.23*a), prosty vyskyt konstanty (literalu) ci promenne, ale i funkcni volani a prirazeni. Jestlize vyraz ukoncime symbolem ; (strednik), ziskame vyrazovy prikaz.

6.2. Prazdny prikazzpet

Prazdny prikaz je vyrazovy prikaz, v nemz neni vyrazova cast. Tato konstrukce neni tak nesmyslna, jak se na prvni pohled muze zdat. Dava nam v nekterych pripadech moznost umistit nadbytecny strednik; do zdrojoveho textu. Napriklad i za vnoreny blok. Protoze se o prazdnem prikazu muzeme tezko dozvedet neco dalsiho, podivejme se radeji na dalsi prikazy jazyka C.

6.3. Bloky.zpet

Vsude v C, kde se muze vyskytovat prikaz, se muze vyskytovat i slozeny prikaz. Slozeny prikaz je posloupnosti prikazu2. Konstrukce, ktera slozeny prikaz vymezuje, zacina levou a konci pravou slozenou zavorkou {}, a nazyva se blok. V bloku muzeme, krome jiz zminene realizace slozeneho prikazu, provadet lokalni deklarace a definice. Ty ovsem pouze na zacatku bloku. Jejich platnost je omezena na blok a pripadne dalsi vnorene bloky. Vnoreny blok nemusi byt ukoncen strednikem. Predstavuje slozeny prikaz a jeho konec je jasne urcen. Neni na skodu si uvedomit, ze telo kazde funkce je blokem. Proto jsme mohli v tele funkce main() definovat a pouzivat lokalni promenne. Syntakticky muzeme blok popsat nasledovne:

{
 [declaration_1[; declaration_2 ... ];]
 [statement_1 [; statement_2 ... ] ]
}

Blok tedy muze obsahovat zadnou, jednu ci vice deklaraci. Pokud deklaraci obsahuje, musi byt od dalsi casti bloku oddelena strednikem. Dale blok muze obsahovat jednotlive prikazy, rovnez oddelene strednikem. Povsimneme si, ze posledni z prikazu nemusi byt od uzaviraci slozene zavorky bloku strednikem oddelen.

6.4. Oblast platnosti identifikatoruzpet

Identifikator, ktery deklarujeme ci definujeme, si ponechava svou platnost v programu, v nemz je deklarovan ci definovan. Jeho jmeno je v tomto rozsahu viditelne, neni-li maskovano:

Jmeno makra je platne od jeho definice (direktivou define) az do mista, kdy je definice odstranena (direktivou undef, pokud vubec odstranena je). Jmeno makra nemuze byt maskovano3.

6.5. Podmineny prikaz if-else. zpet

Operator podmineneho vyrazu ? : pouzivame pro vyber casti vyrazu. Pro vyber z prikazu mame k dispozici podmineny prikaz. Mohli bychom rici, ze se jedna o prikazy dva. Jejich syntakticky zapis je nasledujici

if ( <expression> ) <statement1>;

if ( <expression> ) <statement1>;
else <statement2>;

Vyznam prikazu if je nasledujici. Po vyhodnoceni vyrazu expression (musi byt v zavorkach) se v pripade jeho nenulove hodnoty provede prikaz statement1. Po jeho provedeni pokracuje program za timto prikazem. V pripade nuloveho vysledku vyrazu se rizeni programu preda bezprostredne za podmineny prikaz. Jinak receno se prikaz statement1 preskoci.

Prikaz if muzeme pouzit i s variantou else. Semantika takoveho prikazu if-else je v prvni casti totozna se samotnym if. Je-li vyslednou hodnotou vyrazu expression jedna (nenulova hodnota), provede se prikaz statement1. V opacnem pripade, kdy vysledkem je nula, se provede prikaz statement2. V obou pripadech se rizeni programu po provedeni prvniho, respektive druheho, prikazu preda za cely podmineny vyraz.

if

if-else

Nekdy se vyklad semantiky predklada zpusobem, kdy se nulove hodnote rika nepravda a nenulove (jednicce) pravda. Jak ostatne zname z logickych vyrazu. Pak lze ve druhe variante rici, ze je-li podminka splnena, vykona se prvni prikaz statement1, jinak prikaz druhy statement2.

Zdurazneme, ze oba prikazy jsou ukonceny strednikem4.

Z predchozich odstavcu vime, ze misto prikazu muze byt umisten blok. V takovem pripade je jasne prikaz vymezen a strednik za blokem pred else nepiseme!

Priklad nam ukaze pouziti podmineneho prikazu if-else. Mame vypocist a zobrazit podil dvou zadanych racionalnich cisel. Protoze je znamo, ze nulou delit nelze, vyuzijeme podmineny prikaz k osetreni tohoto omezeni.

/**********************/
/* 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 prvni prikaz po testu if je jednoduchy vystup retezce puts(). Je ukoncen strednikem a nasleduje klicove slovo else. Prikaz v teto casti je tvoren blokem. Za blokem strednik neni. Pokud by tam byl, byl by chapan jako prazdny prikaz. Tak je interpretovan i strednik za poslednim prikazem v bloku.

V uvodu teto kapitoly jsme si shrnuli prikazy jazyka C. Neprekvapi nas tedy umisteni podmineneho prikazu if jako jednoho z prikazu if-else. Zpravidla se umistuje na misto druheho prikazu. Vysledna konstrukce byva casto nazyvana if-else-if5:

if ( <expression1> )  <statement1>;
else if ( <expression2> )  <statement2>;
else if ( <expression3> )  <statement3>;
...
else if ( <expressionN> )  <statementN>;
else <statementN+1>;

Jeji casto vyuzivanou vlastnosti je skutecnost, ze se provede prave jeden z prikazu. Pokud neni posledni prikaz bez podminky statementN+1 uveden, nemusi se provest zadny. Jinak receno, provede se nejvyse jeden.

Zapamatujme si dobre tuto konstrukci. Nejen pro jeji uzitecnost. Po prikladu ji budeme moci porovnat s konstrukci zvanou prepinac.

Nasim ukolem je programove osetrit, jaky alfanumericky znak byl zadan. Pripadne vydat zpravu o zadani znaku jineho. Protoze je jiste, ze zadany znak patri prave do jedne z trid mala pismena, velka pismena, cislice a jine, pouzijeme konstrukci podmineneho prikazu. Pri pouziti if-else by pro kazdou tridu byla znovu testovana prislusnost nacteneho znaku. Bez ohledu, zdali znak jiz nekterou z predchozich podminek splnil. Pouzita konstrukce if-else-if pripadne nadbytecne testy odstrani. Vzdy bude vybran prave jednen z prikazu. Pripomenme si rovnez logicky vyraz, ktery tvori podminku

if ((znak >= 'a') && (znak <= 'z'))

Vnejsi zavorky jsou nezbytne, nebot ohranicuji podminku prikazu if. Vnitrni zavorky naopak uvest nemusime. Priorita operatoru && je nizsi nez relacnich operatoru <= a >=. Zavorky jsme presto uvedli, nebot zvysuji citelnost. Cely vypis zdrojoveho textu nasleduje.

/**********************/
/* 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;
}

6.6. Prepinaczpet

Prepinac slouzi k rozdeleni posloupnosti prikazu na casti, nasledne vybrani a provedeni nektere, ci nekterych z nich. Pokud nam tato formulace prepinac prilis nepriblizila, pokusme se jinak.

Prepinac slouzi k vetveni vypoctu podle hodnoty celociselneho vyrazu.

Syntakticky zapsany prikaz prepinac ma tento tvar:

switch ( <expression> ) <statement>
case <constant expression> :
default :

Syntaktickou definici prepinace ovsem musime upresnit. Po klicovem slove switch nasleduje celociselny vyraz expression uzavreny v zavorkach. Za nim je prikaz statement, zpravidla tvoreny blokem. Blok predstavuje posloupnost prikazu, v niz mohou byt umistena navesti, jejichz syntaxi vidime na druhe radce definice.

Ridici prikaz tvori celociselny konstantni vyraz6 constant expression uvozeny klicovym slovem case a ukonceny dvouteckou :. Jedno z navesti muze byt klicovym slovem default, prirozene ukoncenym dvouteckou :.

Semantika prepinace je pomerne slozita. Popiseme si jednotliva pravidla, jimiz se ridi:

Program vyhodnoti konstantni vyraz a jeho hodnotu porovnava s kazdym z case navesti prepinace. Navesti case muze byt obsazeno uvnitr jinych prikazu (v ramci prepinace), krome pripadneho vnoreneho prepinace.

V jednom prepinaci se nesmi pouzivat dve navesti se stejnou hodnotou.

Nastane-li shoda hodnoty case navesti s hodnotou switch vyrazu expression, je preneseno rizeni programu na toto navesti. Jinak je rizeni preneseno na navesti default v ramci prislusneho prepinace. Pro navesti default plati stejne zasady jako pro jina navesti.

Pokud nenapiseme default navesti a hodnota vyrazu switch se nebude shodovat s zadnym z navesti, bude rizeni preneseno na prikaz nasledujici za prepinacem.

Pokud program pri provadeni prepinace vykona prikaz break, bude rizeni preneseno na prikaz nasledujici za prepinacem. Prikaz break muze byt v ramci prepinace umisten v libovolnych prikazech, krome pripadnych vnorenych do, for, switch nebo while prikazech7.

Prepinac switch muze mit mnoho forem. Podivejme se na priklad, v nemz pouzijeme jednu z nich. Nasim ukolem je podat informaci o tom, jaka hodnota padla pri simulovanem hodu kostky. Misto kostky pouzijeme generator pseudonahodnych cisel (dale jim budeme rikat jen nahodna). Protoze takovou elektronickou kostku budeme pouzivat i v prikladu v nasledujicim odstavci, venovanem cyklum, probereme si funkce s ni spojene podrobneji.

Pomoci funkce srand()8nastavime posloupnost nahodnych cisel. Jako pocatecni hodnotu nemuzeme zvolit konstantu, nebot pak by byla generovana posloupnost nahodnych velicin vzdy stejna. Proto potrebujeme vhodnou hodnotu, ktera bude pri kazdem spusteni programu jina. Takto vhodne se meni napriklad cas. Proto pouzijeme jako argument navratovou hodnotu funkce time()9. Jine zamery s funkci time() nemame, proto pouzijeme jako jeji argument NULL. Nesmime jen zapomenout cas spravne pretypovat. A generator mame pripraven:

srand((unsigned) time(NULL) );

Ted musime umet kostkou hazet. Pri volani funkce rand() dostavame nahodne cele cislo v rozsahu 0 az RAND_MAX. 16-ti bitove BC31 definuje tuto hodnotu jako MAXINT, konkretne 32767. Pro nasi potrebu staci cislo v rozsahu 0 az 5, k nemuz pricteme jednicku. Tuto praci odvede operace modulo sesti.

switch (rand() % 6 + 1)

Ziskana hodnota 1 az 6 je vyrazem prepinace switch. V zavislosti na teto hodnote se rizeni programu prenese na konstantni navesti. Problem je v tom, ze pokud bychom takto oznacenou posloupnost prikazu neukoncili prikazem break, pokracoval by od navesti program dale, az po konec prepinace. I teto vlastnosti se da vyuzit. Ukazku vidime ve spojenem hlaseni pro hodnoty 2 a 3. Umisteni navesti default v prepinaci je libovolne. Zpravidla se pise na konec, coz je pomerne zakoreneny zvyk. Budeme jej rovnez dodrzovat.

/**********************/
/* 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;
}

Srovname-li prepinac s konstrukci if-else-if, vidime zasadni rozdily:

  1. Rozhodovaci vyraz if muze testovat hodnoty jakehokoliv typu10, zatimco rozhodovaci vyraz prikazu switch musi byt vyhradne celociselnym vyrazem.
  2. V konstrukci if-else-if se provede nejvyse (ci podle pouziti prave) jeden z prikazu. I u prepinace se nemusi provest zadny z prikazu. Muze jich byt ovsem provedeno vice. Konstantni navesti urcuje pouze prvni z nich. Pokud chceme, oddelime nasledujici prikazy prikazem break.
  3. V prepinaci se navesti default muze vyskytovat kdekoliv. Odpovidajici varianta v konstrukci ifelseif muze byt umistena pouze na konci11.

6.7. Cyklyzpet

Cyklus je cast programu, ktera je v zavislosti na podmince provadena opakovane. U cyklu obvykle rozlisujeme ridici podminku cyklu a telo cyklu. Ridici podminka cyklu urcuje, bude-li provedeno telo cyklu, ci bude-li rizeni predano za prikaz cyklu. Telo cyklu je prikaz, zpravidla v podobe bloku.

Cykly muzeme rozdelit podle toho, provede-li se telo alespon jedenkrat, a cykly, kde telo nemusi byt provedeno vubec. Rozhodne muzeme rici, ze i kdyz v C existuji ruzne typy cyklu, je mozne vystacit s jednim z nich. Presto si v teto podkapitole povime o vsech. Jejich vyber ponechame na vhodnosti pouziti v dane situaci i na jejich individualni oblibe. V casti venovane prikazu while si popiseme nektere vlastnosti spolecne vsem cyklum. Postupne tedy while, for a do.

Cyklus whilezpet

Prikaz while, vykonava prikaz statement (telo cyklu) vicekrat, nebo vubec, dokud ma v danem kontextu testovaci vyraz expression nenulovou hodnotu. Syntaxe prikazu while je nasledujici:

while ( <expression> ) <statement>

Prikaz je velmi casto blokem. Zde se zejmena zacatecnici mylne domnivaji, ze pokud se kontext kdykoliv behem provadeni prikazu bloku tela cyklu zmeni, a podminka tak prestane byt splnena, je cyklus opusten. To ovsem neni pravda. Pravidlo rika, ze se prikaz statement provede, je-li podminka expression splnena. Je-li prikazem blok, provede se tedy blok cely. Teprve pote je znovu proveden test. Nazornejsi bude, podivat se na vyvojovy diagram.

cyklus while

Ve vyvojovem diagramu se vyskytuji nepovinne prikazy break a continue. S prvnim z nich jsme se jiz setkali u prepinace. Druhy zatim nezname. Jejich semantiku, zakreslenou ve vyvojovem diagramu, si nyni popiseme. Predem poznamenejme, ze oba jsou pokladany za prostredky strukturovaneho programovani.

Prikaz break ma ve vsech cyklech stejny vyznam. Ukonci provadeni prikazu tela cyklu a preda rizeni prvnimu prikazu za prikazem while. Timto zpusobem muzeme bezprostredne ukoncit prubeh cyklu bez ohledu na hodnotu podminky.

Prikaz continue rovnez ukonci provadeni prikazu tela cyklu. Rizeni ovsem preda tesne pred prikaz cyklu. Probehne tedy vyhodnoceni testovaciho vyrazu a podle jeho hodnoty pokracuje program stejne, jako by bylo telo cyklu vykonano do konce (tedy bez predcasneho ukonceni vykonanim continue). Podobne jako break, ma prikaz continue ve vsech cyklech stejny vyznam.

Pouziti prikazu while ukazuje priklad. Opet v nem pouzivame kostku. S ni souvisejici funkce jsme popsali v predchozim prikladu. Tentokrat je nasim cilem secist pocet pokusu, potrebnych k tomu, abychom hodili sestku POCET-krat. Soucasne s novou latkou si pripomeneme nektere poznatky z predchozich kapitol.

Konstanta POCET12, ktera nema uveden typ ma implicitne typ int. Klicovym slovem static pouzitym pri deklaraci promennych celkem a pocet (je to jiny identifikator nez POCET), nejen umistujeme tyto promenne do datoveho segmentu programu, ale zaroven je jim pri spusteni programu definovana pocatecni hodnota nula. Diky tomu je dale nemusime inicializovat.

Cyklus while samotny probiha tak dlouho, dokud plati podminka (pocet < POCET). Za blokem, tvoricim prikaz cyklu, nemusime psat ukoncovaci strednik. Nasleduje formatovany standardni vystup vysledku a zaver 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;
}

Nasledujici priklad ukazuje pouziti prikazu while spolu s if-else-if a prikazy break a continue. Nasim ukolem je porovnani dvou nactenych retezcu a zobrazeni mensiho z nich. Tento priklad pouziva aritmetiku ukazatelu, probiranou v ramci jedne z dalsich kapitol. V tomto okamziku prijmeme skutecnost, ze prostrednictvim ukazatelu porovnavame ASCII hodnoty jednotlivych znaku odpovidajicich retezcu. Kazdy retezec je ukoncen znakem s kodem nula.

Zvolena mnemonika pojmenovava dva retezce a a b, ukazatele na, respektive do, techto retezcu pa a pb. Identifikator pk predstavuje ukazatel na kratsi z porovnavanych retezcu.

Algoritmus ulohy srovnava postupne znaky obou retezcu, dokud jsou si rovny:

else if (*pa == *pb)
      {
       pa++; pb++;
       continue;
      }

Pouziti continue neni v nasem pripade nezbytne. Diky if-else-if nemuze v teto vetvi tela cyklu nasledovat jiny prikaz. Naopak break v obou zbyvajicich vetvich opousti cyklus. Ukoncuje tim srovnavani retezcu a urcuje kratsi z nich. V prvnim ze zminenych pripadu je

if (*pa < *pb)
      {
       pk = a;
       break;
      }

hodnota znaku v retezci a mensi, nez v retezci b. a je tudiz kratsi. Cyklus je ukoncen. Dale bychom totiz opustili definovany rozsah retezce a. A protoze je podminka cyklu napsana tak, ze zajistuje jeho opakovani, dokud nenarazime na konec alespon jednoho z retezcu:

while ((*pa != 0x0) && (*pb != 0x0)) /* '\0' 0 */

Mame jistotu, ze pokud nenastaly predchozi moznosti, musi platit:

else
{
pk = b;
break;
}

Tedy, ze kratsi je druhy retezec. Tesne za telem cyklu mame osetrenu variantu, kdy skonci druhy z retezcu drive, nez se jejich obsahy lisily. Pak je kratsim z retezcu. Nam nezbyva, nez jej zobrazit a ukoncit program. Nasleduje nepreruseny vypis zdrojoveho textu reseni.

/************************************************/
/* 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;
}

Cyklus forzpet

Prikaz for provadi prikaz statement vicekrat, nebo vubec, dokud je hodnota nepovinneho testovaciho vyrazu expr2 nenulova. V prikazu for muzeme jeste napsat dva dalsi vyrazy s vedlejsim efektem, expr1 a expr3. Syntaxe for:

for ( [<expr1>] ; [<expr2>] ; [<expr3>] ) <statement>

Nepovinny vyraz expr1 je proveden pred prvnim vyhodnocenim testu. Typicky se pouziva pro inicializaci promennych pred cyklem. Po kazdem provedeni tela cyklu statement, provede program nepovinny vyraz expr3. Typicky se jedna o pripravu dalsi iterace cyklu. Pokud neuvedeme testovaci vyraz expr2, pouzije prekladac hodnotu 1, a tedy bude provadet nekonecny cyklus. Nastesti muzeme pouzit prikazy break a continue se stejnym vyznamem, jaky jsme popsali u while.

Vyvojovy diagram uplne varianty prikazu for je na obrazku, v nemz jsme ponechali znaceni odpovidajici vyse uvedene syntaxi:

cyklus for

Pro tisk ASCII tabulky znaku s kody 32 az 127 pouzijeme prikaz for v uplne variante:

for (znak = ' '; znak < 128; znak++)

V tomto pripade muzeme nazyvat promennou znak ridici promennou cyklu. Pred testem ji inicializujeme mezerou13, tedy prvnim zobrazitelnym ASCII znakem. Nasleduje test na hodnotu 128. Provadi se pred kazdym pruchodem telem cyklu. Neni-li podminka splnena, pokracuje se za cyklem.

Po kazdem pruchodu telem cyklu je ridici promenna cyklu znak zvysena o jednicku. Tak je pripraven dalsi pruchod cyklem s hodnotou nasledneho ASCII znaku. Samotne telo cyklu vlastne jen zobrazuje jednotlivy znak. Je-li jeho ASCII hodnota delitelna 16 beze zbytku, zajisti vyslanim konce radku 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

*/

Cyklus dozpet

Prikaz do je jedinym z cyklu, ktery zajistuje alespon jedno provedeni tela cyklu. Jinak receno, jeho testovaci prikaz statement je testovan az po pruchodu telem cyklu. Pokud je test splnen, provadi se telo cyklu. Po syntakticke strance tvori telo cyklu opet vyraz expression:

do <statement> while ( <expression> );

Vyvojovy diagram prikazu do tuto vlastnost ukazuje jeste nazorneji:

cyklus do

Prikazy break a continue v tele cyklu se chovaji stejne, jaako v cyklech ostatnich. Po break je cyklus opusten, zatimco po continue je proveden vyraz expression a podle jeho vysledku se pokracuje dale.

Caste pouziti prikazu do nalezneme napriklad v tech numerickych vypoctech, kdy je alespon jedna iterace nezbytna. V nasem pripade se jedna o vypocet priblizne hodnoty Eulerova cisla. V prvnim priblizeni polozime hodnotu e rovnu jedne stejne, jako hodnotu prirustku epsilon. Za upozorneni stoji datovy typ longdouble, a tedy i odpovidajici vhodne urceni typu ciselnych konstant. I ve formatovanem vystupu jsme museli specifikovat prislusny datovy typ. Operatory prirazeni spojene s operaci nad svou levou stranou jsou pouzity spise pro pripomenuti 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;
}

6.8. Prikaz skokuzpet

Prikaz skoku patri k zatracovanym prikazum strukturovaneho programovani. Skutecne s jeho pomoci dokaze mene zkuseny programator vytvorit zdrojovy text, pro nejz se vzilo oznaceni spagetovy. Skutecnost, ze jsme si prikaz skoku nezatajili ma tri priciny:

  1. Jazyk C proste prikaz skoku obsahuje. Jeho neuvedeni by nebylo fer.
  2. Jazyk C umoznuje jako systemovy prostredek psat programy na velmi nizke urovni. Casto velmi blizko strojovemu kodu. Pouziti skoku v takovem pripade muze byt velmi zadouci14.
  3. Skokove prikazy break, continue a return15 jsou oznacovany jako strukturovane skoky. Jejich pouziti teorie (ani praxe) programovani neodmita.

Zustava nam tedy jen prikaz skoku goto. Jeho syntaxe je jednoducha:

identifier: <statement> ;
goto <identifier> ;

Uvedli jsme si nejen syntaxi goto samotneho, ale i souvisejiciho navesti identifier. Navesti neprovadi zadnou akci a nema jiny vliv na rizeni behu. Jeho identifikator jen oznacuje nejake misto ve zdrojovem textu. Prikaz goto prenasi rizeni na prikaz, oznaceny navestim. V ramci jedne funkce nesmi byt dve stejna navesti.


Vysvetlivky:

1 V tomto skriptu venujeme funkcim celou kapitolu.
2 Nezapomenme, jednotlive prikazy jsou ukonceny stredniky.
3 To je jasne, uvedomime-li si, ze makra zpracovava preprocesor. Teprve takto zpracovany text s expandovanymi makry je vstupem pro samotny prekladac.
4 Jinak by se o prikazy nejednalo.
5 Nektere programovaci jazyky kvuli ni dokonce zavadi klicove slovo elif.
6 Tedy vyraz vycislitelny behem prekladu. K celociselnym vyrazum patri i znakove vyrazy.
7 Tyto prikazy mohou break obsahovat. Jeho vyznam pak ovsem bude spojen s nimi, nikoliv s vnejsim prikazem case.
8 Jeji prototyp je umisten v hlavickovem souboru stdlib.h.
9 Jeji prototyp je umisten v hlavickovem souboru time.h.
10 Je vhodne, aby vysledkem testu byla celociselna hodnota, nejlepe 0 a 1. Jinak automaticky probehne konverze.
11 Pripadne jen na zacatku. To bychom museli neobvykle negovat podminky.
12 Diky tomu, ze je definovana mimo telo funkce je rozsahem jeji platnosti cely soubor (pocinaje mistem definice).
13 ASCII kod mezery je 32.
14 Prelozeny tvar nasich "peknych strukturovanych programu" skoky ostatne stejne obsahuje.
15 Prvni dva jsme jiz popsali drive v teto kapitole. Prikazu return se venujeme v souvislosti s funkcemi.


Predchozi kapitola

Obsah

Zacatek

Nasledujici kapitola


Nazev: Programovani v jazyce C
Autor: Petr Saloun
Do HTML prevedl: Kristian Wiglasz
Posledni uprava: 29.11.1996