Week 02

dynamická alokácia pamäte, pravouhlé pole, zubaté pole, pole smerníkov

Oznamy

  • prvé zadanie už o týždeň

  • Namakaný deň 2019

Previously In Programovanie

  • Naposledy sme sa pozreli na to, ako a hlavne kde sú údaje uložené v pamäti. Zoznámili sme sa s operátormi referencie a dereferencie.

  • Celý čas sme sa ale hrali s jednoduchými údajovými typmi. Na konci sme sa pozreli, ako je to s jednorozmernými poliami. Dnes na túto tému nadviažeme.

Copy Strings

Memory leak

  • Existuje niekoľko problémov, s ktorými sa dá stretnúť pri dynamickej práci s pamäťou, ako napr.:

    • čítanie z miesta, ktoré mi nepatrí
    • zápis na miesto, ktoré mi nepatrí
    • stratenie referencie na oblasť pamäti, ktorú som si vyhradil
    • neupratanie si pamäte po skončení funkcie alebo programu
  • Tieto problémy sa odhaľujú ťažko a častokrát dokonca si ani nevšimnete, že k tomuto problému došlo. Proste - ste mali šťastie. Rovnako aj v predchádzajúcom príklade - všimli ste si, že je v ňom chyba? Veď predsa vrátil presne to, čo mal.

  • Odhaliť úniky v pamäti je možné pomocou vhodných nástrojov. Jedným z nich je aj nástroj s názvom Valgrind (slide). Jeho použitie vyzerá nasledovne: valgrind ./spustitelny_subor
  • V našom prípade ho teda spustím s preloženou binárkou programu copy.c:

    valgrind ./copy
    
  • Na obrazovke sa objaví výpis podobný tomuto:

    ==19071== Invalid read of size 1
    ==19071==    at 0x4C30BC4: strlen (vg_replace_strmem.c:454)
    ==19071==    by 0x5192AD0: vfprintf (in /usr/lib64/libc-2.24.so)
    ==19071==    by 0x5199718: printf (in /usr/lib64/libc-2.24.so)
    ==19071==    by 0x4007FD: main (copy.c:27)
    ==19071==  Address 0x55098c4 is 0 bytes after a block of size 4 alloc'd
    ==19071==    at 0x4C2DB9D: malloc (vg_replace_malloc.c:299)
    ==19071==    by 0x400745: copy (copy.c:7)
    ==19071==    by 0x4007DF: main (copy.c:25)
  • Vo výstupe je možné vidieť, že došlo k neoprávnenému čítaniu o veľkosti 1B (Invalid read of size 1) priamo za alokovaným miestom v pamäti (Address 0x55098c4 is 0 bytes after a block of size 4 alloc’d).

  • Bližšie sa tomuto nástroju budete venovať na niektorom z nasledujúcich cvičení. Každopádne je to nástroj, ktorý vám občas môže zachrániť život.

Motivácia

  • Pri Hangmanovi ste mali jednoduchú funkciu getWord(), ktorá umožňovala načítať náhodné slovo zo súboru, ktorý obsahoval spolu 55900 slov. Čo ak by ale k tomuto súboru pristupovalo naraz niekoľko spustených programov (multipoužívateľský Linux)? Alebo čo ak by sa jednalo o sieťovú aplikáciu a zakaždým, keď by niekto chcel získať tajné slovo by tento súbor musel otvoriť? Výber náhodného slova zo súboru by sa veľmi rýchlo mohol stať úzkym hrdlom celej aplikácie.

  • Vyriešiť tento problém by sme mohli tak, že celý súbor načítame naraz do pamäte a pre získanie náhodného slova už nebudeme potrebovať pristupovať k súboru, ale priamo ho z tej pamäte dostaneme.

  • Pokúsme sa teda vytvoriť funkciu, ktorá tento súbor načíta a vráti nám ho v podobe dvojrozmerného poľa, kde počet riadkov bude zodpovedať počtu slov v súbore a na každom riadku sa bude nachádzať jedno slovo.

  • Tu však narazíme na problém, ktorý ilustruje nasledujúci fragment kódu (problem.c):

  • Ak sa program pokúsime preložiť, dostaneme hlášku: problem.c: In function ‘get_numbers’: problem.c:6:12: error: function returns address of local variable [-Werror=return-local-addr] return numbers; ^~~~~~~

  • Ako teda zabezpečiť, aby funkcia mohla vrátiť údaje uložené v poli? A v dvojrozmernom poli? Tento problém sa budeme snažiť vyrieši�� v rámci tejto prednáky.

Intermezzo

Square Array (Pravouhlé pole)

Jagged Array (Zubaté pole)

  • Pokúsime sa teda upraviť náš program tak, aby sme pre každý reťazec použili práve toľko miesta, koľko potrebuje.

Pole pointerov

Pointer na pointer

Parametre príkazového riadku

  • S týmto spôsobom zápisu ste sa stihli stretnúť už v zimnom semestri v rámci predmetu Základy algoritmizácie a programovania, keď ste hovorili o parametroch príkazového riadku. Deklarácia funkcie main vyzerá takto:

  • A tu si môžete všimnúť, akým spôsobom je reprezentovaný parameter argv - je to vlastne pole pointerov, o ktorom sme dnes rozprávali.

Zistenie počtu slov v súbore

Funkcia vracajúca zoznam načítaných slov zo súboru

Cleanup

Conclusion

  • Teraz už určite musíte rozumieť tomu, ako to v tej pamäti funguje. A ak nie, dajte šancu ešte nasledujúcemu videu ;)

  • (slide)

Additional Resources