Table of Contents

Přednášky

Podklady přednášek pro aktuální akademický rok 2019/2020. Podklady se skládají z promítaných slidů, které jsou také k dispozici ve zkrácených verzích šetrnějších k případnému tisku, bez přechodů mezi snímky a ve formátu čtyř a devíti snímků na stránku.

Podklady tvoří podpůrný materiál a jejich učelem není nahradit vlastní zápisky z přednášky, které slouží také jako prostředek osvojení si studované problematiky.

Tématicky je náplň přednášek pokryta v knize K.N. King: C Programming A Modern Approach, Second Edition. W. W. Norton & Company, Inc., 2008/. Před přednáškou je doporučeno pročíst si odkazované kapitoly.

On-line otázky na přednášce

#VTýden Týden Téma Úterý 14:30 (Místnost T2:D3-209)
01 08. Přednáška 01 - Informace o předmětu, Úvod do programování v C
K. N. King: kapitoly 1, 2 a 3
18.02. - lec01
02 09. Přednáška 02 - Výrazy, řídicí struktury a funkce
K. N. King: kapitoly 4, 5, 6 a 20
25.02. - lec02
03 10. Přednáška 03 - Datové typy: pole a ukazatele. Paměťové třídy. Volání funkcí
K. N. King: kapitoly 7, 8, 9, 10, 11 a 18
03.03. - lec03
04 11. Přednáška 04 - Pole, řetězce a ukazatele
K. N. King: kapitoly 8, 11, 12, 13 a 17
10.03. - lec04
05 12. Přednáška 05 - Datové typy: Složený typ, výčtový typ a bitová pole. Preprocesor a sestavení programu
K. N. King: kapitoly 10, 14, 15, 16 a 20
17.03. - lec05
06 13. Přednáška 06 - Vstup / výstup a standarní knihovny C
K. N. King: kapitoly 21, 22, 23, 24, 26 a 27
24.03. - lec06
07 14. Přednáška 07 - Paralení programování, paralelní výpočty a synchronizační primitiva (semafory, zprávy a sdílená paměť ) 31.03. - lec07
08 15. Přednáška 08 - Vícevláknové programování, modely aplikací, POSIX vlákna C11 vlákna 07.04 - lec08
09 15. Přednáška 09 - Praktická ukázka a ladění programu 14.04. - lec09
10 17. Přednáška 10 - ANSI C, C99, C11 a rozdíly mezi C a C++. Úvod do C++ 21.04. - lec10
11 18. Přednáška 11 - Stručný úvod do C++ Objektově orientované programování v C++: třídy, objekty, dědičnost a polymorfismus 28.04. - lec 11
12 19. - 05.05. páteční rozvrh
13 20. Přednáška 12 - C++ konstrukty v příkladech Systémy pro správu verzí 12.05.
14 21. Přednáška 13 - Zkouškový písemný test Objekty v C++ 19.05. - lec 13

V přednáškách uvedené zdrojové kódy jsou přiloženy v příslušném .zip archivu. Kromě vyzkoušení programů je též vřele doporučeno si složitější úlohy samostatně naprogramovat a přednáškové příklady využít pro inspiraci.

Podklady budou průběžně aktualizovány.

1. Informace o předmětu, základy programování v C

Jan Faigl 2020/03/05 23:31

2. Výrazy, řídicí struktury a funkce

Jan Faigl 2020/02/12 15:35

3. Datové typy: pole a ukazatele. Paměťové třídy. Volání funkcí

Na přednášce zmíněná funkce fgets() pro řešení HW 03 nemusí být zas až tak výhodná a mnohem výhodnější může být využití funkce getline(), která však pracuje pouze s dynamicky alokovanou pamětí.

Jan Faigl 2020/02/12 15:35

4. Pole, řetězce a ukazatele

Jan Faigl 2020/02/12 15:35

Příklad z přednášky

Příklad na přednášce demonstrující použití kompilace s debug, např. clang -g a valgrind pro rychlé nalezení problémového místa nám pomohl ukázat na zápis mimo přidělenou paměť na řádku 13, tj. sieve[i*j] = 0;

 10 for (int i = 2; i < 1000000; ++i) {
 11       if (sieve[i]) {
 12          for (int j = i; i*j < 1000000; ++j) {
 13             sieve[i*j] = 0;
 14          }
 15       }
 16    }

Přestože řádek vypadá relativně neškodně, je nutné uvažovat jakou hodnotu bude mít výraz i*j pokud jsou obě proměnné typu int. Zcela jistě se totiž hodnota výrazu, např. 47000 * 47000, do rozsahu typu int reprezentovaného 32-bity nevejde. Možných řešení je více, jedno z nich může být využít automatické typové konverze na větší z typů, např.

 10 for (int i = 2; i < 1000000; ++i) {
 11       if (sieve[i]) {
 12          for (long j = i; i*j < 1000000; ++j) {
 13             sieve[i*j] = 0;
 14          }
 15       }
 16    }

Rozdíl je na řádku 12 v použití typu long pro řídicí proměnnou j. V tomto případě je hodnota výrazu i*j typu long a problém je vyřešen.

Každopádně mnohonásobné použití magické konstanty 1000000 lze vhodně nahradit např.

#define SIEVE_SIZE 1000000

Dotazy z přednášky

Q: Co udělá realloc() při zmenšení velikost nebo nastavení velikosti na 0?

Zmenší alokované místo a v případě 0, např. realloc(ptr, 0); uvolní paměť a odpovídá tak volání free(ptr);.

Dotazy z přednášky

Q: Je nutné nebo vhodné explicitně typovat ukazatel návratové hodnoty z volání funkce malloc()?

Vyloženě nutné to v současných verzích Cčka není, přestože pro některé kompilátory (zvláště pak před standarem) to nutné bylo. V současné době je typ void* chápan jako generický ukazatel, jehož přetypování na konktrétní typ ukazatel na proměnné příslušné typu je zřejmé dle typu proměnné a není tak nutné explicitní přetypování uvádět. Jestli je vhodné explicitně přetypovat, tak na to se názory různí. Například v knize S.G.Kochan: Programming in C (3rd Edition), Sams Publishing, 2005 je uváděn malloc vždy s explicitním přetypováním:

int *a = (int*)malloc(10 * sizeof(int));

Naproti tomu v knize K.N. King: C Programming A Modern Approach, Second Edition. W. W. Norton & Company, Inc., 2008 je preferována varianta bez přetypování:

int *b = malloc(10 * sizeof(int));

Obě varianty jsou přípustné, argumenty proti explicitnímu přetypování jsou uváděny například: přehlednější kód a je to zbytečné, neboť dochází k přetypování automaticky. Na druhé straně relativně silné argumenty pro explicitní přetypování uvedené v diskusi http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc jsou například:

You do cast, because:

Je to tak spíše věc osobního vkusu, preferencí, případně používaného kódovacího stylu.

Jan Faigl 2019/03/05 13:27

5. Datové typy: Složený typ, výčtový typ a bitová pole. Preprocesor a sestavení programu

Jan Faigl 2020/02/12 15:35

Dotazy z přednášky

Q: Jakým způsobem mohou přetypovat dynamicky alokovaný souvislý blok paměti na dvourozměrné pole o cols sloupcích?

Předně je nutné zajistit, že ukazatel odkazuje na souvislý blok paměti o příslušné velikost. Následně lze definovat proměnnou se specifikací počtu sloupců např. int(*matrix)[cols] = (int(*)[cols])m;, kde m je ukazatel na souvislý blok int hodnot. V kontextu programu to může vypadat, následovně.

void *alloc(size_t size)
{
    void *ret = malloc(size);
    if (ret == NULL) {
        fprintf(stderr, "Malloc fail!");
        exit(-1);
    }
    return ret;
}
 
void print_matrix(int rows, int cols, int m[][cols])
{
    for (int r = 0; r < rows; ++r) {
        for (int c = 0; c < cols; ++c) {
            printf("%2d ", m[r][c]);
        }
        printf("\n");
    }
}
 
int rows = 2;
int cols = 3;
 
int *m = alloc(rows * cols * sizeof(int));
for (int i = 0; i < rows * cols; ++i) {
   m[i] = i + 1;
}
 
int(*matrix)[cols] = (int(*)[cols])m;
 
print_matrix(rows, cols, matrix);
 
free(m);

Můžeme toho například využít při řešení HW05, kdy si nejdříve odladíme funkce pro dvojrozměrné pole, které následně můžeme přímo využít pro rozšířenou implementaci s využitím dynamické alokace.

Q: Je nutné v případě dynamicky alokované matice, jako pole ukazatelů na pole hodnot, postupně paměť uvolňovat podobně jako při alokaci?

Ano je. Nejdříve je nutné postupně uvolnit dílčí pole reprezentující sloupce v jednotlivých řádcích a následně pak uvolnit pole ukazatelů (na řádky). S výhodou je možné si definovat funkce pro alokaci a uvolnění paměti, např.

void *alloc(size_t size)
{
    void *ret = malloc(size);
    if (ret == NULL) {
        fprintf(stderr, "Malloc fail!");
        exit(-1);
    }
    return ret;
}
 
int **matrix_alloc(int rows, int cols)
{
    int **matrix = alloc(rows * sizeof(int *));
    for (int r = 0; r < rows; ++r) {
        matrix[r] = alloc(cols * sizeof(int));
    }
    return matrix;
}
 
void matrix_free(int rows, int cols, int **matrix)
{
    if (matrix) {
        for (int r = 0; r < rows; ++r) {
            if (matrix[r]) {
                free(matrix[r]);
            }
        }
        free(matrix);
    }
}
které můžeme následně použít například
const int ROWS = 2;
const int COLS = 2;
 
int **matrix = matrix_alloc(ROWS, COLS);
matrix_free(ROWS, COLS, matrix);

Pragmatičtější však může být použití složeného typu struct.

Jan Faigl 2019/03/19 22:46

6. Vstup / výstup a standarní knihovny C

Jan Faigl 2020/02/12 15:35

Dotazy z přednášky

Q: Jakým funguje Quick-Sort?

Jedná se o algoritmus řazení na principu rozděl a panuj, který je například popsán na https://cs.wikipedia.org/wiki/Quicksort nebo znázorněn na Quick-sort with Hungarian (Küküllőmenti legényes) folk dance.

7. Paralení programování, paralelní výpočty a synchronizační primitiva

Jan Faigl 2020/02/12 15:35

8. Vícevláknové programování, modely aplikací, POSIX vlákna C11 vlákna

Jan Faigl 2018/05/16 07:54 CEST Aktualizace: Oprava output_thread() - zamčení/odemčení mutexu vně cyklu

Jan Faigl 2020/02/12 19:49

9. Praktická ukázka a ladění programu

Přednáška formou ukázek.

Jan Faigl 2018/02/19 16:00

Dotazy z přednášky

Q: Proč při nastavení terminálu do raw režimu nedochází k tisku nového řádku na začátku?

Při nastavení raw režimu cfmakeraw() je vypnuto zpracování výstupních znaků (output postprocessing), které automaticky nahrazuje konec řádku za “návrat vozíku a nový řádek” (NL na CR-NL). Vyřešit lze buď explicitním uvedením znaku '\r', což ale není příliš kompatibilní nebo povolením output processing (OPOST) např.

static struct termios tio;
tcgetattr(STDIN_FILENO, &tio);
cfmakeraw(&tio);   // nastavení raw režimu viz man termios
tio.c_oflag |= OPOST; //zapnutí output processing
tcsetattr(STDIN_FILENO, TCSANOW, &tio);

10. ANSI C, C99, C11 a rozdíly mezi C a C++. Úvod do objektově orientovaného programování v C++

Jan Faigl 2020/02/12 19:48

Dotazy / připomínky z přednášky

C: Při přepnutí terminálu do raw režimu příkazem stty raw stále dochází k tisku stisknuté klávesy

Pokud tomu tak je (např. v Linuxu), je nutné ještě vypnout echo například stty -noecho příkaz pro nastavení termínálu tak může být

stty raw -echo
a nastavit zpět pak lze např.
stty -raw echo

11. Stručný úvod do C++

Jan Faigl 2020/02/12 19:48

12. C++ konstrukty v příkladech

Jan Faigl 2020/02/12 19:48

Systémy pro správu verzí

Původní podklady pro obecný úvod do verzovacích systémů a to jak centralizovaných tak distribuovaných, s příkladem použití systémů RCS, SVN a Git.

Jan Faigl 2018/02/19 16:00