ZPRO 2018

Předmět je vyučován s dotací 0+4, tzn. dvě cvičení týdně. Časy našich cvičení jsou v pondělí 9:30 (B-009) a ve středu 13:30 (T-115).

Podmínky pro zisk zápočtu

Materiály ke cvičení

1. a 2. cvičení

Důležité pojmy:

Probrané příklady:

  1. Hello, world! Nejjednodušší program v jazyce C, který na obrazovku vypíše text „Hello, world!“.

    #include <stdio.h>
    
    int main()
    {
        printf("Hello, world!\n");
        return 0;
    }
    
  2. 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.

  3. Výpis sudých čísel. Program ukazuje využití cyklu for a podmínky.

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

    Místo cyklu for lze ekvivalentně použít cyklus while:

    #include <stdio.h>
    
    int main()
    {
        int i = 0;
        while (i < 100) {
            if (i % 2 == 0)
                printf("%d\n", i);
            i++;
        }
        return 0;
    }
    

    Cyklus for je vhodné použít v případech, kdy předem známe počet opakování cyklu. Cyklus while je obecnější a hodí se pro situace, kdy dopředu neznáme počet opakování cyklu.

  4. Výpis prvočísel. Program ukazuje komplikovanější strukturu vnořených cyklů.

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

    O něco chytřejší verze využívá toho, že čísla j větší než polovina čísla i nemohou být děliteli čísla i. Stačí tedy procházet pouze čísla od 2 do i / 2.

    #include <stdio.h>
    
    int main()
    {
        for (int i = 1; i < 100; i++) {
            int pocet_delitelu = 1;
    
            for (int j = 2; j < i / 2; j++) {
                if (i % j == 0)
                    pocet_delitelu += 1;
            }
    
            if (pocet_delitelu == 1)
                printf("%d\n", i);
        }
        return 0;
    }
    

Stručný přehled jazyka C aneb základy jazyka C++

3. a 4. cvičení

Efektivní používání české klávesnice

Pro usnadnění programování a zrychlení psaní na české klávesnici doporučuji používat následující klávesové zkratky využívající klávesu AltGr:

V systému Linux navíc fungují následující zkratky využívající horní řadu znaků s diakritikou (speciální znaky jsou na těchto klávesách spolu s číslicemi nakresleny pro snazší zapamatování):

Pod ostatními klávesami se skrývají další, i když méně užitečné speciální znaky.

Dále velmi doporučuji procvičit si psaní všemi deseti, bude se vám to velmi hodit nejen při programování.

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

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

Čtení vstupních dat z konzole

Pro čtení vstupních dat z konzole budeme používat funkci scanf, která přečte vstupní řetězec zadaný v terminálu po stisknutí klávesy Enter, pokusí se ho převést na data odpovídajícího datového typu a výsledek uloží na zadanou adresu. Nejjednodušší vysvětlení na příkladu:

#include <stdio.h>

int main()
{
    // text pro uzivatele
    printf("Zadej cele cislo: ");

    // precteni vstupu
    int cislo;
    scanf("%d", &cislo);

    // vypis precteneho cisla
    printf("zadane cislo = %d\n", cislo);

    return 0;
}

Zkompilování a spuštění programu může dopadnout např. takto:

$ gcc -std=c99 -Wall scanf.c -o scanf
$ ./scanf
Zadej cele cislo: -4
zadane cislo = -4

Důležité poznámky:

Pomocí jednoho příkazu lze přečíst data pro libovolný pevný počet proměnných, např. příkaz scanf("%d %f %f", &cislo1, &cislo2, &cislo3); přečte jedno celé číslo a dvě desetinná čísla oddělená mezerami.

Probrané příklady

  1. 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;
    }
    
  2. 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;
    }
    
  3. Úprava předchozích příkladů, aby vstupní data (např. počet členů posloupnosti) četly z terminálu. Program pro výpočet obvodu a obsahu kruhu.

5. cvičení

Program pro výpočet řešení kvadratické rovnice. Pro výpočet odmocniny použijeme funkci sqrtf z hlavičkového souboru math.h.

#include <stdio.h>
#include <math.h>

int main()
{
    printf("Zadej parametry a, b, c kvadraticke rovnice a*x^2 + b*x + c = 0:\n");
    float a, b, c;
    scanf("%f %f %f", &a, &b, &c);

    float d = b*b - 4*a*c;
    if (d > 0) {
        float x1 = (-b - sqrtf(d)) / (2*a);
        float x2 = (-b + sqrtf(d)) / (2*a);
        printf("Reseni rovnice jsou x_1 = %g a x_2 = %g.\n", x1, x2);
    }
    else if (d == 0) {
        float x = -b / (2*a);
        printf("Reseni rovnice je x = %g.\n", x);
    }
    else {
        printf("Rovnice nema zadne realne reseni.\n");
    }

    return 0;
}

Při překladu pomocí kompilátoru gcc v systému Linux je potřeba přidat parametr -lm, tedy např:

gcc -std=c99 -Wall -lm rovnice.c -o rovnice

Last updated: Wed 10 October 2018