3. cvičení

Přehled základních datových typů

Paměť počítače je lineární a rozdělená na bajty (1 bajt = 8 bitů). Každý bajt v paměti má svou jedinečnou adresu. Interpretace jednotlivých dat uložených v paměti počítače závisí na datovém typu příslušné proměnné.

Typ Velikost (bits) Minimální hodnota Maximální hodnota Poznámky
bool 8 0 1 Pro použití typu bool je třeba #include <stdbool.h>.
char 8 -128 127 7-bitové kódování znaků pomocí ASCII tabulky.
unsigned char 8 0 255
short 16 -32768 32767 Typ pro reprezentaci celých čísel.
unsigned short 16 0 65535 Typ pro reprezentaci nezáporných celých čísel.
int 32 -2147483648 2147483647 Typ pro reprezentaci celých čísel.
unsigned int 32 0 4294967295 Typ pro reprezentaci nezáporných celých čísel.
long 64 -9223372036854775808 9223372036854775807 Typ pro reprezentaci celých čísel.
unsigned long 64 0 18446744073709551615 Typ pro reprezentaci nezáporných celých čísel.
float 32 \(\approx 1.175 \times 10^{-38}\) \(\approx 3.402 \times 10^{38}\) Typ pro reprezentaci racionálních čísel.
double 64 \(\approx 2.225 \times 10^{-308}\) \(\approx 1.797 \times 10^{308}\) Typ pro reprezentaci racionálních čísel.

Při vyhodnocování aritmetických operací obsahujících proměnné různých typů dochází k implicitní konverzi proměnných na „ten větší“ ze zúčastněných typů. Tedy např. součet proměnné typu short a proměnné typu int proběhne tak, že se hodnota proměnné typu short převede na typ int a součet se provede pro typ int. Při výpočtech může dojít k chybám způsobeným přetečením nebo podtečením maximálního rozsahu hodnot pro daný typ.

Pozor: Celočíselné proměnné lze dělit pouze celočíselně. Pokud je potřeba neceločíselný výsledek, je třeba explicitně provést přetypování, např. (float) x / y.

Pozor: Konverze na typ bool funguje jinak než konverze na ostatní celočíselné typy. Výraz (bool) 0.5 dává 1, kdežto (int) 0.5 dává 0.

Pozor: Hodnoty typu char (znaky) je třeba ve zdrojovém kódu zapisovat pomocí jednoduchých uvozovek, tedy 'a', 'b', 'c' apod. Pomocí dvojitých uvozovek se zapisují textové řetězce, kterými se budeme zabývat později.

Důležité pojmy

Probrané příklady

  1. Program demonstrující deklaraci proměnných celočíselného typu int a neceločíselného typu float, provedení operace sčítání a výpis výsledku pomocí funkce printf.

    #include <stdio.h>
    
    int main()
    {
        float a = 1.5;
        int b = 2;
        float c = a + b;
        printf("%f + %d = %f\n", a, b, c);
        return 0;
    }
    

    Proměnné jsou vypisovány pomocí speciálního symbolu pro daný datový typ (%d pro typ int a %f pro typ float). Přehled všech možností funkce printf bude ukázán později.

  2. Program pro výpočet obvodu a obsahu kruhu.

  3. Výpočet faktoriálu pomocí rekurzivní funkce. Pro příliš vysoké hodnoty proměnné n dojde při výpočtu k tzv. přetečení rozsahu pro daný typ (zde long) a program vrátí špatný výsledek.

    #include <stdio.h>
    
    long factorial(int n)
    {
        if (n == 1)
            return 1;
        else
            return n * factorial(n - 1);
    }
    
    int main()
    {
        int n = 10;
        long f = factorial(n);
        printf("%d! = %ld\n", n, f);
        return 0;
    }
    

    Nerekurzivní funkci pro výpočet faktoriálu lze zapsat např. pomocí cyklu for:

    long factorial(int n)
    {
        long vysledek = 1;
        for (int i = 2; i <= n; i++)
            vysledek *= i;
        return vysledek;
    }
    

    Nebo pomocí cyklu while:

    long factorial(int n)
    {
        long vysledek = 1;
        while (n > 1) {
            vysledek *= n;
            n--;
        }
        return vysledek;
    }
    
  4. Výpočet členů Fibonacciho posloupnosti. Rekurzivní verze je jednoduchá, ale velmi pomalá (i výpočet prvních 200 členů trvá dlouho):

    #include <stdio.h>
    
    int fibonacci(int n)
    {
        if (n == 1)
            return 1;
        else if (n == 2)
            return 1;
        else
            return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    int main()
    {
        for (int i = 1; i <= 200; i++)
            printf("fibonacci(%d) = %d\n", i, fibonacci(i));
        return 0;
    }
    

    Nerekurzivní verze je komplikovanější, ale mnohem rychlejší. Efektivitu výpočtu zdůvodňovat nebudeme, to bude náplní předmětu ZALG v letním semestru.

    int fibonacci(int n)
    {
        // dve pomocne promenne pro predchozi cleny posloupnosti
        int f_i_minus_1 = 1;
        int f_i_minus_2 = 1;
    
        for (int i = 3; i <= n; i++) {
            // vypocet aktualniho clenu
            int f_i = f_i_minus_1 + f_i_minus_2;
            // posun promennych pro dalsi iteraci
            f_i_minus_2 = f_i_minus_1;
            f_i_minus_1 = f_i;
        }
    
        // vysledek (clen f_n) je v promenne f_i_minus_1
        return f_i_minus_1;
    }