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 B A A B 0 0 0 0 1 1 1 0 1 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 =...00000001 B...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 & and bitový zleva doprava 9 ^ xor bitový zleva doprava 10 or bitový zleva doprava 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) /* nejsou nutné složené závorky */ if (podminka) { /* zde jsou složené závorky povinné */ 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é */ 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) /* nejsou nutné složené závorky */ while (podminka) {/*zde jsou složené závorky povinné */
do - while do /* nejsou nutné složené závorky */ while (podminka); do { /*zde jsou složené závorky povinné */ 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 */ Ukončit jej lze příkazem break;
for for (start; běh_podminka; iterace) for (start; běh_podminka; iterace) { - totéž jako for pomocí cyklu while: start; while (běh_podminka) { iterace; Typický vzhled příkazu: int i; for (i = 1; i <= 100; i++) { nebo velmi často: for (int i = 1; i <= 100; i++) { 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 (;;) /* nekonečný cyklus */ Nevhodné užití: int i = 2; for ( ; i < 10; i++) int i = 2; for ( ; i < 10; ) { i = 3 * y; prikaz4;
Co lze: for (i = 0; i < 10; printf("%d", i), i++) /* méně vhodné */ ; 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--) /* krok -1 */ for (i = 0; i <= 100; i += 10) /* krok 10 */ for (i = 0; i <= 100; i = i + 10) /* krok 10 */ for (i = 100; i >= 0; i -= 5) /* krok -5 */ for (i = 100; i >= 0; i = i - 5) /* krok -5 */ Příkazy continue; a break; continue for (i = 1; i <= 100; i++) { if (podminka) continue;
for (i = 1; i <= 100; i++) { if ((i % 10)!= 0) continue; /*pro i dělitelné 10 prikaz3 proběhne*/ - stejně tak pro cyklus while a do-while break int i, a; /* a zadano z klavesnice */ for (i = 1; i < 100; i++) { if ((a - i) == 5) break; /* pro a-i rovno 5 cyklus skončí */ - 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 : break; case hodnota3 : break; default : prikaz_jiny; break; switch (výraz) { /* výraz musí být typu int */ case hodnota1 : case hodnota2 : /* prikaz2 bude vykonan pro */ break; /* hodnotu1 i hodnotu2 */ case hodnota3 : 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 */ case hodnota2 : /* prikaz2 bude vykonan pro */ break; /* hodnotu1 i hodnotu2 */ case hodnota3 : break; default : prikaz_jiny; break; Vsuvka: Pokud použiji: #include <ctype.h> - 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í: goto navesti; 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);