Warning
This page is located in archive. Go to the latest version of this course pages. Go the latest version of this page.

Přednášky

Podklady přednášek pro aktuální akademický rok 2018/2019. 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 Stephen G. Kochan: Programming in C (3rd Edition), Sams Publishing, 2005. Před přednáškou je doporučeno pročíst si odkazované kapitoly.

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.

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

Harmonogram přednášek

#VTýden Týden Téma Středa 16:15 (Místnost T2:D3-309)
01 40. Přednáška 01 - Informace o předmětu, Úvod do programování
S. G. Kochan: kapitoly 2 a 3
03.10. - lec01
02 41. Přednáška 02 - Základy programování v C
S. G. Kochan: kapitoly 2 a 3
10.10. - lec02
03 42. Přednáška 03 - Zápis programu v C a základní řídicí struktury
S. G. Kochan: kapitoly 3, 4, 5 a část 6
17.10. - lec03
04 43. Přednáška 04 - Řídicí struktury, výrazy a funkce
S. G. Kochan: kapitoly 4, 5, 6 a 12
24.10. - lec04
05 44. Přednáška 05 - Pole, ukazatel, textový řetězec
S. G. Kochan: kapitoly 7, 10 a 11
31.10. - lec05
06 45. Přednáška 06 - Ukazatele, paměťové třídy a volání funkcí
S. G. Kochan: kapitoly 8 a 11
07.11. - lec06
07 46. Přednáška 07 - Struktury a uniony, přesnost výpočtů a vnitřní reprezentace číselných typů
S. G. Kochan: kapitoly 9, 14, 17 a Appendix B
14.11. - lec07
08 47. Přednáška 08 - Standardní knihovny C. Rekurze.
S. G. Kochan: kapitola 16 a Appendix B
15.11. - lec08
09 48. Přednáška 09 - Spojové struktury 16.11. - lec09
10 49. Přednáška 10 - Stromy 05.12. - lec10
11 50. Přednáška 11 - Abstraktní datový typ (ADT) - zásobník, fronta, prioritní fronta 12.12. - lec11
12 51. Přednáška 12 - Prioritní fronta, halda. Příklad použití při hledání nejkratší cesty v grafu 19.12. - lec12
52. Zimní prázdniny
13 01. Přednáška 13 - Rezerva
Dokončení přednášky Přednáška 10 - Stromy
Přehled zdrojových souborů k implementační zkoušce.
Dotazy a upřesnění náročnějších pasáží předchozích přednášek a domácích úkolů
02.01. - lec13
14 02. Přednáška 14 - Přednáška na vyzvané téma - Systémy pro správu verzí Zkouškový test 09.01. - lec14

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

Jan Faigl 2018/09/22 23:59

2. Základy programování v C

Jan Faigl 2018/10/10 21:39

Dotazy z přednášky

Q: Proč je návratový typ programu (funkce main) int, když maximální hodnota předaná interpretu příkazu pouze 255?

Je to dáno historicky. Cčko nelimituje rozsah a definuje int, nicméně zaleží na procesu, který program spouští. V našem případě interpret příkazů. Dokonce je to tak, že GNU bash limituje rozsah na 7-bitů, POSIX shell na 8 bitů a třeba Windows na 32-bit unsigned int. V tomto kontextu stojí za zmínku speciální návratové hodnoty.

Q: Jaká je vnitřní reprezentace typu _Bool?

Norma standardu C uvádí, že dostatečná pro uložení hodnot 0 a 1. Prakticky je to char, tj. jeden byte, viz příklad lec02/bool.c.

Q: Jak vytisknu znak '%' nebo '\' ve funkci printf()?

Jako dvojici znaků, tj.

printf("%% a \\ a následně nový řádek \n");

Jan Faigl 2017/10/20 08:21 Aktualizace: Oprava překlepů, doplnění informace o unárním operátoru přetypování.

3. Zápis programu v C a základní řídicí struktury

Jan Faigl 2017/10/26 09:42 Aktualizace: Oprava překlepů a diagramu pro do..while()Jan Faigl 2018/09/22 23:59

Doplnění načítání vstupu

Při načítání vstupu funkcí scanf() lze rozlišit tři případy - úspěšné načtení požadované hodnoty, detekce ukončení vstupu a vstup neodpovídající načítané hodnotě, více viz man scanf.

#include <stdio.h>
 
int main(void)
{
   int v;
   int r;
   int c = 0;
   while ((r = scanf("%d", &v)) > 0) {
      c += 1;
   }
   if (r == EOF) {
      printf("End of file detected, no. of parsed values %i\n", c);
   } else {
      printf("Error occur during parsing value no. %i\n", c + 1);
   }
   return 0;
}

4. Řídicí struktury, výrazy a funkce

Jan Faigl 2017/10/26 09:42 Aktualizace: Doplnění kódů pro příklady nedefinovaného chování

Jan Faigl 2018/09/22 23:59

Dotazy z přednášky

Q: Je možné umístit návěští pro příkaz goto před cyklus?

V zásadě ano, jediným omezením je použití pouze v rámci jedné funkce a dále pak otvírá rozsah platnosti (scope) proměnných konkretního bloku. To souvisí s paměťovou třídou lokálních proměnných (viz přednáška 6). V podstatě nelze příkazem goto skočit na místo, kde ještě není proměnná deklarována (v rámci jednoho bloku).

Návěští před začátkem cyklu Návěští před začátkem cyklu, ale před deklarací proměnné (nelze)
int a; // začátek platnosti a
outer: 
for (int i = 0; i < 3; ++i) {
    goto outer;
}
outer: // proměnná a (bloku) není deklarována, návěští nelze uvést
int a; 
for (int i = 0; i < 3; ++i) {
    goto outer;
}
 

Další podstatnou nevýhodou umístění návěští před cyklus je horší čitelnost a tím také vyšší náchylnost k chybě a zacyklení.

5. Pole, ukazatel, textový řetězec

Jan Faigl 2018/10/31 06:41

Dotazy z přednášky

Q: Proč uvedený příklad načítání skončil v nekonečné smyčce?

Načítání hodnot celých čísel funkcí scanf() ve smyčce while:

#include <stdio.h>
 
int main(void)
{
   int v;
   int i = 0;
   while (scanf("%d", &v) > 0) {
      printf("%d %d\n", ++i, v); 
   }
   printf("No. of read values %d\n", i);
   return 0;
}

Skončil v nekonečné smyčce, neboť původní podmínka cyklu

 while (scanf("%d", &v)) { ... } 
je vyhodnocena jako logická pravda i v případě neúspěšného načtení nové celočíselné hodnoty. V proměnné zůstane původní hodnota. Při opravě jsem, jak někdo na přednášce zmínil, zapomněl soubor uložit.

6. Ukazatele, paměťové třídy a volání funkcí

Jan Faigl 2017/11/09 21:56 Aktualizace: Oprava překlepů a přidání snímku 26 s příkladem na extern.

Jan Faigl 2018/11/07 22:06 Aktualizace: Oprava překlepu na snímku 25.

Dotazy z přednášky

Q: Snažím se načíst celé číslo do typu unsigned int funkcí scanf() a když dám na vstup celé záporné číslo, např. -10, nejen, že se hodnota načte, ale hodnota je veliká. Jak je to možné?

Minimální kód programu read_unsigned.c může být například:

#include <stdio.h>
 
int main(void)
{
   unsigned int i;
   int r = scanf("%+u", &i);
   printf("Return value %i read value %u\n", r, i);
   return 0;
}

Výstup pak například

clang read_unsigned.c && echo "-10" | ./a.out
Return value 1 read value 4294967286
Hodnota 4294967286 odpovídající maximálním hodnotě typu unsigned int bez 10 vyplývá z použití doplňkového kódu. Program nemá zřejmé očekávané chování. Při bližším pohledu na chování funkce scanf(), např. man scanf

NAME
     scanf, fscanf, sscanf, vscanf, vsscanf, vfscanf — input format conversion

LIBRARY
     Standard C Library (libc, -lc)
...
u     Matches an optionally signed decimal integer; the next pointer must
           be a pointer to unsigned int.
...
se dočteme, že konverze přes “%u” načítá znamenkový integer. Funkce se tak chová dle dokumentace. V případě, že bychom se chtěli vyhnout takovému chování můžeme buď použití větší datový typ, např. unsigned long, a kontroloval rozsah pro unsigned int nebo si napsat vlastní načítání pouze kladných hodnot a při výskytu znaku '-' na vstupu indikovat špatný vstup.

7. Struktury a uniony, přesnost výpočtů a vnitřní reprezentace číselných typů

Jan Faigl 2018/09/22 23:59

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:

  • It makes your code more portable between C and C++, and as SO experience shows, a great many programmers claim they are writing in C when they are really writing in C++ (or C plus local compiler extensions).
  • Failing to do so can hide an error: note all the SO examples of confusing when to write type * versus type **.
  • The idea that it keeps you from noticing you failed to #include an appropriate header file misses the forest for the trees. It's the same as saying “don't worry about the fact you failed to ask the compiler to complain about not seeing prototypes – that pesky stdlib.h is the REAL important thing to remember!”
  • It forces an extra cognitive cross-check. It puts the (alleged) desired type right next to the arithmetic you're doing for the raw size of that variable. I bet you could do an SO study that shows that malloc() bugs are caught much faster when there's a cast. As with assertions, annotations that reveal intent decrease bugs.
  • Repeating yourself in a way that the machine can check is often a great idea. In fact, that's what an assertion is, and this use of cast is an assertion. Assertions are still the most general technique we have for getting code correct, since Turing came up with the idea so many years ago.

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

Q: Jak funguje ukazatelová aritmetika v případě void*

Přičítá se hodnota jednoho bajtu, například pro hodnotu ukazatele void *a = 0x100; bude je hodnota (a+1) rovna 0x101.

8. Standardní knihovny C, rekurze

Jan Faigl 2018/09/22 23:59

9. Spojové struktury

Jan Faigl 2018/09/22 23:59

10. Stromy

Jan Faigl 2018/12/15 18:40 Aktualizace: Odstranění zbytečného volání feof()

 while (!feof(f) && !exit) {                               ->          while (!exit) {
      if (g->num_edges == g->capacity) {                                    if (g->num_edges == g->capacity) {
         enlarge_graph(g);                                                      enlarge_graph(g);
      }                                                                      }
      edge_t *e = g->edges + g->num_edges;                                   edge_t *e = g->edges + g->num_edges;
      while (!feof(f) && g->num_edges < g->capacity) {     ->                while (g->num_edges < g->capacity) {
Funkce feof() vrací logickou hodnotu TRUE pouze v případě dosažení konce souboru, což je detekováná až při pokusu o čtení. Vždy je proto nutné kontrolovat návratové hodnoty čtecích funkcí více např. viz https://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1046476070&id=1043284351

11. Abstraktní datový typ (ADT) - zásobník, fronta, prioritní fronta

Jan Faigl 2018/09/22 23:59

12. Prioritní fronta, halda. Příklad použití prioritní fronty při hledání nejkratší cesty v grafu

Jan Faigl 2017/12/23 08:09 Aktualizace: Zjednoušení návratové hodnoty funkce dijkstra_solve() a zpřehlednění podmínky v pq_down().

Jan Faigl 2018/01/08 08:48 Aktualizace: tdijkstra verze 2.3.6. - fix segfault při pokusu testovat řešení většího grafu než je vstupní graf

Jan Faigl 2018/12/28 20:43

13. Rezerva

14. Přednáška na vyzvané téma

Zkouškový test

Např. systémy pro správu verzí * prezentace: b0b36prp-lec14-slides.pdf * zkrácená verze: b0b36prp-lec14-handout.pdf * zkrácená verze 2×2: b0b36prp-lec14-handout-2x2.pdf * zkrácená verze 3×3: b0b36prp-lec14-handout-3x3.pdf

Jan Faigl 2018/09/22 23:59

courses/b0b36prp/lectures/start.txt · Last modified: 2018/12/28 20:43 by faiglj