8. týždeň

2D Arrays

Viacrozmerné polia

Video (14.11.2023)

Prezentácia

Zdrojový kód

Poznámky k prednáške

Deklarácia 2D poľa

char array[5][4];
  • Avšak pozor, toto pole nebude prázdne!

Inicializácia 2D poľa

  • 2D pole je možné inicializovať podobne, ako tomu bolo pri inicializácii 1D polí, teda priamym vymenovaním hodnôt poľa. To je možné dosiahnuť dvoma spôsobmi.
  • Prvý spôsob vyžaduje uviesť oba rozmery poľa. Inicializácia 2D poľa potom vyzerá nasledovne:
char array[5][4] = {
    {' ', '-', '-', ' '},
    {'|', ' ', ' ', '|'},
    {' ', '-', '-', ' '},
    {'|', ' ', ' ', '|'},
    {' ', '-', '-', ' '}
};
  • Druhý spôsob nevyžaduje uviesť prvý rozmer podobne, ako tomu bolo v prípade 1D polí. Ten bude zistený automaticky. Druhý rozmer je však povinný. Inicializácia 2D poľa potom vyzerá nasledovne:
char array[][4] = {
    {' ', '-', '-', ' '},
    {'|', ' ', ' ', '|'},
    {' ', '-', '-', ' '},
    {'|', ' ', ' ', '|'},
    {' ', '-', '-', ' '}
};

Prístup k prvkom poľa

  • Ako sme spomínali v prípade 1D polí, pole sa indexuje od 0. Podobne je tomu tak aj v 2D poliach, teda oba rozmery poľa sa indexujú od hodnoty 0.
  • Pri pristupovaní k prvkom poľa nezabudnite na to, že je dôležité nepomýliť si poradie súradníc!

Prechod 2D poľom

  • Vytvoríme si funkciu draw(), pomocou ktorej zabezpečíme vykreslenie 2D poľa na obrazovku.
  • Podobne ako v prípade odovzdávania poľa ako parameter funkcie, budeme postupovať aj v prípade 2D polí, teda okrem adresy samotného poľa odovzdáme v rámci parametrov aj jeho šírku a výšku.
  • Avšak podobne ako pri inicializácii poľa musí byť jedna jeho súradnica známa už v časti deklarácie funkcie. Od verzie jazyka C99 je možné použiť takýto zápis (záleží na poradí parametrov):
void draw(const int rows, const int cols, char array[][cols]);
  • Funkcia draw() bude potom vyzerať nasledovne:
void draw(const int rows, const int cols, char array[][cols]){
    for(int y = 0; y < rows; y++){
        for(int x = 0; x < cols; x++){
            printf("%c", array[y][x]);
        }
        printf("\n");
    }
}
  • Príklad vykreslí na obrazovku 7-segmentovku (seven-1.c):
 --
|  |
 --
|  |
 --

Hranice 2D polí

  • S hranicami 2D polí je to úplne rovnaké, ako v prípade 1D polí: Prekladač v dobe prekladu nevie odhaliť, či s nimi budete pracovať správne a počas behu programu môže dôjsť k indexovaniu poľa mimo jeho rozsah.
  • Pozor na Off-by-one Problem alebo Fence-post Problem, lebo je veľmi jednoduché pomýliť sa práve o hodnotu 1.
  • Sledovať, či náhodou nedochádza k zapisovaniu údajov mimo rozsahu polí, si musí sám programátor.

Reprezentácia 2D poľa v pamäti

  • Pamäť počítača je lineárna. Ako je v nej však uložené 2D pole, ktoré má 2 rozmery a pozeráme sa na neho ako na tabuľku?
  • Keď sme do pamäte ukladali 1D pole, jednotlivé jeho prvky boli uložené v pamäti za sebou od nižších adries k vyšším, pričom veľkosť jednej obsadenej "bunky" závisela od veľkosti uloženého údajového typu.
  • Aj 2D pole je nakoniec v pamäti reprezentované lineárne, a do pamäte sa riadky údajov ukladajú postupne za sebou.
  • Pohľad používateľa na 2D pole je tabuľkový (2D ako tabuľka), ale v skutočnosti je toto pole uložené v pamäti ako 1D pole (lineárne, sekvenčne).

Viacrozmerné polia

  • Ako si predstavujete viacrozmerné polia? Ako môže vyzerať 3D pole? (3D priestor) Napr. to môže byť číslo strany v knihe, číslo stĺpca a poradové číslo slova (Sherlock Holmes - The Valey of Fear)
  • Ako je to však s ďalšími rozmermi? Ako vyzerá 4D pole? Je štvrtým rozmerom čas? 5D pole? Čo sú tie 3 zvyšné "rozmery" v 5D kine? Viac D viac Adidas?
  • Príkladom viacrozmerných polí môže byť napríklad aj adresa (pseudokód):
entry["state"]["city"]["street"]["person"];
  • Upravme náš príklad tak, aby na obrazovku vykreslil konkrétnu číslicu 7-segmentovky. Poľu najskôr pridáme tretí rozmer, ktorý nám povie, či sa má daný znak vykresliť na obrazovku alebo nie. Keďže na začiatku nevieme, ktorú číslicu budeme vykresľovať, znaky, ktoré nie sú biele, nastavíme na 'n'.
  • Nezabudnime upraviť funkciu draw() tak, aby vedela pracovať s týmto tretím rozmerom.
  • Ďalej od používateľa načítame číslicu z obrazovky (v main()).
  • Pred vykreslením číslice vytvoríme novú funkciu set_segments(), ktorá upraví tretí rozmer poľa array podľa príslušných segmentov (na 'y').
  • Nezabudnime, že v hlavnej funkcii main() je potrebné zavolať funkciu set_segments() ešte pred volaním funkcie draw().
  • Príklad vykreslí na obrazovku 7-segmentovku (seven-2.c):
Enter number to display: 5
 --
|
 --
   |
 --

Doplňujúce zdroje

  1. Seven-segment display
  2. C Multidimensional Arrays
  3. Multi-dimensional Arrays in C

Video