5. Operátor čárka , - slouží k jistému určení pořadí vykonání dvou příkazů - oddělím-li čárkou dva příkazy, je jisté, že ten první bude vykonán dříve než příkaz druhý. Např.: i = 5; j = 8; - po překladu nemusí jít tato dvě přiřazení takto za sebou – záleží to na překladači. Příkazy spolu nesouvisí, překladač je umístí dle potřeby. Jistotu má pouze při zápisu: i = 5, j = 8; - napřed půjde i = 5, potom j = 8. int i, j; // zde nejde o operátor čárka, // ale oddělení deklarací proměnných i = 2; j = 4; j = (i++, i - j); // chci napřed i++ pak i - j - závorky jsou zde povinné !!!! for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }
Bitové operátory - slouží k operacím nad jednotlivými bity & - bitový součin AND – součin bit po bitu | - bitový součet OR – součet bit po bitu ^ - bitový exkluzivní součet XOR – exsoučet bit po bitu BAA⊕B 0 0 0 0 1 1 1 1 0 1 1 0
<< - bitový posun doleva >> - bitový posun doprava ~ - negace bit po bitu (jednotlivých bitů) – dvojkový doplněk - operandy nesmí být typu float, double, long double !!! pouze celočíselné !!! - doporučeno je používat tyto operace s typy unsigned Např.: Test na liché cislo: (použijeme tzv. vymaskování (maskou)) unsigned int cislo; ... nejake prikazy ... if (1 & cislo) { // 1 = ...00000001B ...prikazy... // cislo = ...XXXXXXX?B } provedu součin bit po bitu & ...0000000? a = a >> 2 – posune bity v a o 2 doprava (a >>= 2) 00110110 po posunu 00001101
Priorita operátorů - pořadí vyhodnocování jednotlivých operátorů - nejsem-li si jist, závorkuji Priorita Operátor(y) potkají-li se stejné 1 () [] -> . zleva doprava 2 ! ~ ++ -- + - (typ) zprava doleva * & sizeof 3 * / % zleva doprava 4 + zleva doprava 5 << >> zleva doprava 6 < <= > => zleva doprava 7 == != zleva doprava 8 zleva doprava & and bitový 9 zleva doprava ^ xor bitový 10 zleva doprava | or bitový 11 && zleva doprava 12 || zleva doprava 13 ?: ternární operátor zprava doleva 14 = += -= *= /= %= >>= <<= zprava doleva &= |= ^= 15 , operátor čárka zleva doprava
Řídící struktury Podmínky a logické výrazy - poznámka - pozor, logický typ v C není, používá celočíselný (viz začátek přednášky) => může vést k omylů, např. při špatném závorkování j = j || (i / 2) int i = 1, j = 1; j = !j && (i = i + 1); – spíše odstrašující 0 (nepravda) 2 (pravda) Celkově: 0 (nepravda) Časté chyby: int i = 5; /* nejaky vypocet */ if (i == 1) // toto je v pořádku /* prikaz */ - totéž, ale spletu si == s = 1 if (i = 1) /* asi chyba – i bude 1 místo 5 a podmínka je pravdiva */ /* prikaz */ int c; if (c = getchar() == 'A') { /* chyba - v c bude 0 nebo 1 */ /* nejake operace vyuzivajici prom. c */ - načte se znak z klávesnice, porovná se s 'A', protože porovnání má vyšší prioritu než přiřazení) výsledek porovnání se uloží do c (bude 0 nebo 1)
Správný postup: if ((c = getchar()) == 'A') { /* OK-v c bude znak z klávesnice */ /* nejake operace vyuzivajici prom. c */ Podmínky u ternárního operátoru podmínka ? je-li pravdivá : je-li nepravdivá; (a < 5) ? a++ : a--; b = (a < 5) ? a : (a – 5); Jednoduchý převod malých písmen na velká pomocí ternárního operátoru: int c; c = getchar(); c = ((c >= 'a') && (c <= 'z')) ? c - ('a'-'A') : c; Operátor , a = 3, b = 6; /* a = 3 se provede před b = 6 - vždy int i = 2, j = 4; j = (i++, i – j);
// jako: j = ++i – j;
j = ++i - (i = 3); /* chybné - nevím co se provede dříve*/
Řídící struktury - pokračování if if-else if (podminka) prikaz;
/* nejsou nutné složené závorky */
if (podminka) { /* zde jsou složené závorky povinné */ prikaz1; prikaz2; prikaz3; } if (podminka) /* nejsou nutné složené závorky */ prikaz_pravda; else /* nejsou nutné složené závorky */ prikaz_nepravda; if (podminka) {/* zde jsou složené závorky povinné */ prikaz1; prikaz2; prikaz3; } else { /* zde jsou složené závorky povinné */ prikaz4; prikaz5; prikaz6; }
Porovnání na nulové hodnoty: Pro celá čísla: int i; if (i != 0) neco; Pro desetinná čísla: double d; if (d != 0.0) neco; Pro znaky: int c; if (c == '\0') /* porovnání s prázdným znakem \0 */ Pro pointery (ukazatele) - adresy do paměti int *p_i; nějaké příkazy if (p_i == NULL) /* NULL – nulová adresa, "nikam" */
Cykly while while (podminka) prikaz;
/* nejsou nutné složené závorky */
while (podminka) {/*zde jsou složené závorky povinné */ prikaz1; prikaz2; prikaz3; }
do - while do /* nejsou nutné složené závorky */ prikaz; while (podminka); do { /*zde jsou složené závorky povinné */ prikaz1; prikaz2; prikaz3; } while (podminka); Rozdíl mezi while a do-while - while – tělo příkazu nemusí proběhnout ani jednou (podmínka je hned nepravda) - do-while - tělo příkazu proběhnout vždy alespoň jednou Zvláštní případ – v těle while pouze prázdný příkaz while (podminka) ; /* pro přehlednost je lepší ; na novém řádku */ - k čemu je to dobré: např. "požrání" znaků z klávesnice až do konce řádku printf("Chces pokracovat ? (A/N)"); if ((c = getchar()) == 'A') { / nějaké příkazy s tím c */ } /* nyní se zbavíme všech znaků, které uživatel zadal navíc */ while (getchar() != '\n') ; Totéž, ale složitěji: int c; do {
c = getchar(); } while (c != '\n');
Další užití a prázdným příkazem: - čekání na stisk libovolné klávesy while(!kbhit()) // kbhit() je z knihovny conio ; - často se před toto čekání umisťuje cyklus pro vyprázdnění klávesnicového bufferu (požrání přebytečných znaků) while (getchar() != '\n') ; while(!kbhit()) ;
Kompletní ukázka: #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int c; printf("Chces pokracovat ? (A/N)"); if ((c = getchar()) == 'A') { printf("\nANO - Bylo stisknuto %c\n", c); } else { printf("\nNE - Bylo stisknuto %c\n", c); } /* nyní se zbavíme všech znaků, které uživatel zadal navíc */ while (getchar() != '\n') ; printf("Chces pokracovat podruhe ? (A/N)"); if ((c = getchar()) == 'A') { printf("\nANO - Bylo stisknuto %c\n", c); } else { printf("\nNE - Bylo stisknuto %c\n", c); } /* nyní se zbavíme všech znaků, které uživatel zadal navíc */ while (getchar() != '\n') ; printf("\nPro ukonceni racte stisknout klavesu...\n"); while(!kbhit()) ;
return 0; } Další možnosti: /* preskocit mezery */ while (getchar() == ' ') ; /* prázdný příkaz */ Pozor, v uvedeném případě přijdu o první významný znak: aaaaaaaahoj - přečte vše co je zeleně a zahodí to, nikam to neukládám, zbyde mi ke čtení jen hoj - jak tento problém odstranit: while ((c = getchar()) == ' ') ; /* prázdný příkaz */ - a tak mi po skončení cyklu zbyde v c první znak a - nejlépe ale: while ((c = getchar()) == ' ') ; /* prázdný příkaz */ ungetc(c); /* vrátí znak zpět do bufferu klávesnice */ /* preskocit vsechny bile znaky */ int c; while ((c = getchar()) == ' ' || c == '\t' || c == '\n') ; /* prázdný příkaz */ while (1) /* nekonečný cyklus */ prikaz; Ukončit jej lze příkazem break;
for for (start; běh_podminka; iterace) prikaz; for (start; běh_podminka; iterace) { prikaz1; prikaz2; prikaz3; } - totéž jako for pomocí cyklu while: start; while (běh_podminka) { prikaz1; prikaz2; prikaz3; iterace; } Typický vzhled příkazu: int i; for (i = 1; i <= 100; i++) { prikaz1; prikaz2; prikaz3; } nebo velmi často: for (int i = 1; i <= 100; i++) { prikaz1; prikaz2; prikaz3; } i = 9; /* chyba, zde už i není deklarována */ - pozor v předchozím případě existuje proměnná i pouze uvnitř bloku, tj. těla cyklu !!!!
for (;;) prikaz;
/* nekonečný cyklus */
Nevhodné užití: int i = 2; for ( ; i < 10; i++) prikaz; int i = 2; for ( ; i < 10; ) { prikaz1; i = 3 * y; prikaz3; prikaz4; }
Co lze: for (i = 0; i < 10; printf("%d", i), i++) vhodné */ ;
/* méně
int i, sum; for (i = 1, sum = 0; i <= 10; i++) sum += i; Jinak, méně přehledně: for (i = 1, sum = 0; i <= 10; sum += i, i++) ; Jiný krok pro for: for (i = 100; i >= 0; i--) prikaz;
/* krok -1 */
for (i = 0; i <= 100; i += 10) prikaz;
/* krok 10 */
for (i = 0; i <= 100; i = i + 10) prikaz; for (i = 100; i >= 0; i -= 5) prikaz;
/* krok -5 */
for (i = 100; i >= 0; i = i - 5) prikaz;
Příkazy continue; a break; continue for (i = 1; i <= 100; i++) { prikaz1; prikaz2; if (podminka) continue;
/* krok 10 */
/* krok -5 */
prikaz3; } for (i = 1; i <= 100; i++) { prikaz1; prikaz2; if ((i % 10) != 0) continue; /*pro i dělitelné 10 prikaz3 proběhne*/ prikaz3; } - stejně tak pro cyklus while a do-while
break int i, a; /* a zadano z klavesnice */ for (i = 1; i < 100; i++) { prikaz1; prikaz2; if ((a - i) == 5) break; /* pro a-i rovno 5 cyklus skončí */ prikaz3; } - stejně tak pro cyklus while a do-while
Příkaz switch-case – podmínka, nahradí několik příkazů if výraz je tzv. řídící proměnná switch (výraz) { /* výraz musí být typu celé číslo */ case hodnota1 : prikaz1a; prikaz1b; break; case hodnota2 : prikaz2; break; case hodnota3 : prikaz3; break; default : prikaz_jiny; break; } switch (výraz) { /* výraz musí být typu int */ case hodnota1 : case hodnota2 : prikaz2; /* prikaz2 bude vykonan pro */ break; /* hodnotu1 i hodnotu2 case hodnota3 : prikaz3; break; default : prikaz_jiny; break; }
*/
Nebo: switch (výraz) { /* výraz musí být typu int */ case hodnota1 : /* pro hodnotu 1 bude vykonán prikaz1 i prikaz2 prikaz1; case hodnota2 : prikaz2; /* prikaz2 bude vykonan pro */ break; /* hodnotu1 i hodnotu2 case hodnota3 : prikaz3; break; default : prikaz_jiny; break; }
Vsuvka: Pokud použiji: #include
- převod malých písmen na velká (typ int) jinak než ternárním operátorem: velke = toupper(male);
- převod velkých písmen na malá (typ int): male = tolower(velke);
*/
*/
Nepodmíněný skok: goto - používat málo a s rozvahou - velmi nevhodné užití: prikaz1; goto navesti; prikaz2; prikaz3; navesti: prikaz4; prikaz5; prikaz6; goto navesti;
- jedna z mála výjimek, kdy je vhodný – mnohonásobně vnořené cykly – když vyskočit z nejvnitřnějšího úplně mimo cykly: for neco for neco for neco for neco for neco /* chci predcasne ze vsech cyklu ven */ if (nejaka_podminka) goto ven; } } } } } ven: dalsi prikazy;
Příkaz return - ukončuje funkci v níž je volán - popř. vrací výsledek funkce (návratovou hodnotu) - u funkcí bez návratové hodnoty: return;
- s návratovou hodnotou return vysledek; return (vysledek); return (prom * 3 - y);