[Přednáška 1] [Obsah] [Přednáška 3]

Přednáška 2


Témata


Načtení znaku z klávesnice a výpis znaku na obrazovku

Pro načtení jednoho znaku ze standarního vstupu (klávesnice, terminál) slouží funkce int getchar(), pro výstup jednoho znaku na standardní výstup (obrazovku, terminál) slouží funkce int putchar(int c) z knihovny stdio.h. Tzv. hlavičku funkce, tj. jak funkce vypadá, čteme následovně: funkce getchar vrací číslo typu int a nemá žádné parametry (prázdné závorky, upřesnění a detaily si povíme později). Funkce putchar vrací číslo typu int a má jeden parametr typu int. Funkce getchar() nevrací překvapivě hodnotu typu char, ale hodnotu typu int. Původ této skutečnosti je ve funkcích sloužící ke čtení znaků ze souboru, resp. k zápisu znaků do souboru. Návratové hodnoty mimo rozsah 0 až 255 (tedy rozsah odpovídající znakům) dovolují programu signalizovat, že došlo k nějaké chybě (např. konec souboru atd.). Ve funkci putchar(int c) je c znak vystupující na terminál. Samozřejmě, skutečným parametrem funkce putchar(int c) může být proměnná typu char, dojde k automatické konverzi. V případě, že návratová hodnotá funkce getchar() je přiřazena do proměnné typu char, překladač většinou hlásí varování typu „Conversion may lose significant digits“.

Příklad:

putchar('A'); putchar(65);

Podmíněný výraz

Podmíněný výraz je ternární operátor, jehož operandy jsou tři výrazy. Je další ukázkou toho, jak lze psát v jazyce C efektivní a úsporný kód. Syntaxe podmíněného výrazu je následující:

výraz1 ? výraz2 : výraz3

Hodnota podmíněného výrazu je výraz2, pokud má výraz1 nenulovou hodnotu (neboli je pravdivý, true); v opačném případě má hodnotu výraz3.

Příklady:

(a==3) ? 1 : 0 // je-li hodnota proměnné a rovna 3, podmíněný výraz má hodnotu 1, jinak 0

Podmíněný výraz lze s výhodou využít např. při přiřazení:

x = (a==3) ? 1 : 0 // je-li hodnota proměnné a rovna 3, do proměnné x se přiřadí hodnota 1

Pomocí podmínky bychom zapsali přiřazení takto: if (a==3) x = 1; else x = 0;

Poznámka: První výraz není nutné uzavírat do závorky, ale často se uzavírá kvůli čitelnosti kódu. Uvědomte se, že podmíněným výrazem nelze nahradit jakoukoliv podmínku if !


Operátor „ , “ (čárka)

Operátor čárka představuje jednu ze specialit jazyka C. Oddělují se jím jednotlivé výrazy ve výrazu (dovoluje napsat jakýsi vícenásobný výraz) a použití může nalézt tam, kde syntaxe jazyka dovoluje zapsat pouze jeden výraz. Tedy:

výraz1, výraz2, výraz3

Zapsaná trojice výrazů je považována za jeden výraz. Význam je následující: nejprve se vyhodnotí výraz1, pak výraz2 a naposledy výraz3. Hodnotou celého výrazu je hodnota posledního vyhodnoceného výrazu. Vše vysvětlí malý příklad, i když poněkud nesmyslný:

Příklad:

x = a=1, 3, a+b;

Nejprve se vyhodnotí přiřazovací výraz, tedy do proměnné a se přiřadí hodnota 1; hodnota výrazu a=1 je 1, ale tato hodnota se „zahodí“. Vyhodnotí se další výraz, tedy 3, tato hodnota se opět „zapomene“. Nakonec se sečtou hodnoty proměnných a a b. Součet je hodnotou celého výrazu a je přiřazen do proměnné x.

Z příkladu je viditelné, že operátor čárka není příliš přehledný z hlediska čitelnosti kódu, čtenář možná pochybuje o jeho smyslu (a v tomto případě má pravdu). Proto je také doporučeno omezit jeho používání pouze v případě cyklu typu for.

Cyklus for

Cyklus for má v jazyku C poněkud odlišnou syntaxi i sémantiku než v jazycích typu Pascal nebo Basic. Jeho možnosti jsou mnohem bohatší oproti zmíněným jazykům. Obecný zápis cyklu vypadá takto:

for(výraz1;výraz2;výraz3) příkaz;

Chování cyklu for je ekvivaletní cyklu typu while s tímto zápisem:

výraz1;
while(výraz2)
{
  příkaz;
  výraz3;
}
Nejprve se vyhodnotí výraz1 (pouze jednou, před vstupem do cyklu!). Pak se provádí tělo cyklu, dokud je splněn výraz2. Na konci každého provedení těla cyklu je vždy ještě vyhodnocen výraz3. Typické využití cyklu for je ve tvaru cyklu s pevným počtem opakování, např.

for(i=1;i<=n;i++) příkaz;, resp. for(i=n;i>=1;i--) příkaz;

Na místě výrazů mohou být skutečně libovolné výrazy, tedy na místě výraz2 může být libovolně složitá podmínka, zvětšit hodnotu proměnné na konci cyklu je možné např. o 2 aj.

Poznámka: Proměnná i se nazývá řídicí proměnná cyklu.
Ekvivalence obou cyklů je ukázána na jednoduchém příkladě, který vypíše násobilku 3, viz tabulka 1.

Cyklus forCyklus while
int i;

for(i=1;i<=10;i++)
  printf("%d",3*i);
int i;

i=1;
while(i<=10)
{
  printf("%d",3*i);
  i++;
}  

Tabulka 1: Ekvivalence cyklů

Pro ověření, zda dobře rozumíte cyklu for, zkuste analyzovat následující příklad.

Úloha:

Napište program, který vypočte součet přirozených čísel od 1 do n, číslo n se zadává z klávesnice.

Řešení:

Na této úloze si ukážeme několik specialit, které cyklus for v jazyce C nabízí. V popisech řešení vynecháme pro stručnost deklaraci proměnných (všechny jsou typu int), načtení čísla n z klávesnice a výpis výsledku na obrazovku.
Přirozené řešení, odpovídající filozofii zápisu algoritmu i v jiných jazycích, uvedeme jako první:

s = 0;
for(i=1;i<=n;i++) s+=i;
Právě zde je rozumné využít operátor čárka a přidat inicializační výraz s = 0 do cyklu k inicializaci proměnné i:

for(s=0,i=1;i<=n;i++) s+=i;
Libovolný z výrazů je možné v cyklu vynechat. Pokud bychom chtěli zvýšení hodnoty proměnné i o jedničku provést v těle cyklu současně se sumací (využijeme operátor ++ v postfixové formě), můžeme napsat:

for(s=0,i=1;i<=n;) s+=i++;
V krajním případě bychom mohli celý výraz představující sumaci a následné zvýšení hodnoty proměnné i zahrnout do cyklu jako výraz3 a tělo ponechat prázdné:

for(s=0,i=1;i<=n;s+=i++); /* zde ma strednik vyznam prazdneho prikazu v tele cyklu */
Poslední dvě řešení se nedoporučuje příliš využívat, protože slučují příkazy těla cyklu a kód související s řídicí proměnnou cyklu, což ubírá na čitelnosti a přehlednosti kódu. Nicméně příklady poslouží jako vhodná ukázka, jaká „kouzla“ jazyk C dovoluje.

Poznámka: S cykly (se všemi typy) v jazyce C souvisejí dvě klíčová slova: break a continue. Příkaz break ukončuje předčasně cyklus (používá se v souvislosti s nějakou podmínkou). Příkaz continue ukončí přeruší pouze aktuální iteraci, provede se skok na testovací podmínku, je-li splněna, provádí se další iterace.

Napíšeme program, který přečte z klávesnice text (posloupnost znaků) zakončený stiskem klávey Enter a který převede velká písmena anglické abecedy na malá.

int main(int argc, char **argv)
{
  int c;
  while((c = getchar())!='\n')
    putchar((c >='A' && c <= 'Z') ? c+('a'-'A') : c);
  
  system("PAUSE");
  return 0;
}

Jako ukázku přepíšeme cyklus s využitím break a continue. Reálný kód by takto vypadat ale neměl.
while (1)
{
  c = getchar();
  if (c == '\n') break;
  if (c >= 'A' && c <= 'Z') { putchar(c+('a'-'A'));  continue; }
  putchar(c);
}

Příkaz switch

Příkaz switch představuje přepínač variant, je obdobou příkazu case v jazyce Pascal. Obecný tvar příkazu můžeme zapsat:
switch (výraz)
{
  case konstanta1: příkaz1;
  case konstanta2: příkaz2;
  atd.
  default: příkaz;
}
Výraz je libovolný výraz, který musí být celočíselného typu (nelze tedy použít přepínač např. s proměnnými typu float nebo double). Jednotlivé varianty, zapsané za klíčovým slovem case, mohou být pouze konstanty, není dovoleno psát proměnné ani např. intervaly ohraničené konstantami. Pokud je nutné zapsat k dané variantě více příkazů, nemusejí být tentokrát uzavřeny do bloku mezi znaky { ... }. Varianta uvedená za klíčovým slovem default je vykonána v případě, že hodnota výrazu neodpovídá ani jedné z uvedených variant. Varianta default je nepovinná, pokud není uvedena a hodnota výrazu neodpovídá žádné z variant, žádný příkaz se neprovede.

Příklad:

switch(getchar())
{
  case '1': printf("Zadal jste 1!");
  case '2': printf("Zadal jste 2!");
  case '3': printf("Zadal jste 3!");
}
Je pravděpodobné, že skutečné chování příkazu (jak jsme jej zapsali výše) se bude lišit od čtenářovy představy. Zadá-li uživatel programu znak 2, na obrazovce se vytiskne následující text:
Zadal jste 2!
Zadal jste 3!
Zadaný znak se nejprve porovná s konstantou '1', není-li shodný, pokračuje se v porovnání s konstantou '2' atd. Nastane-li shoda, provedou se příkazy u dané varianty a pokračuje se v provádění příkazů u dalších variant (příkaz switch je většinou přeložen do strojového kódu jako „rozskok“ pomocí tabulky a instrukce typu JMP). Abychom dosáhli výběru jediné varianty, je třeba doplnit jednotlivé větve klíčovým slovem break:
switch(getchar())
{
  case '1': printf("Zadal jste 1!"); break;
  case '2': printf("Zadal jste 2!"); break;
  case '3': printf("Zadal jste 3!"); break;
  default: printf("Zadal jste něco jiného");
}
Pak bude po zadání znaku 2 na obrazovce skutečně jedna věta:
Zadal jste 2!
Na uvedení příkazu break programátoři, kteří začínají s jazykem C, často zapomínají.

Vynechání příkazu break může být účelem, je dovoleno vynechat dokonce i příkaz. Tímto způsobem se zajistí obsloužení více variant jedním kódem:

switch(getchar())
{
  case '1': printf("Zadal jste 1!"); break;
  case '2':
  case '3': printf("Zadal jste 2 nebo 3!"); break;
  default: printf("Zadal jste něco jiného");
}
Upozornění: S konstrukcí switch souvisí pouze příkaz break, nikoliv continue.


[Přednáška 1] [Obsah] [Přednáška 3]