5. seminář - Vícerozměrná pole

TEACHINGZPC2

Statická vícerozměrná pole

V programovacím jazyce C můžeme definovat i vícerozměrné pole. Zde je obecná forma deklarace vícerozměrného pole.

Deklarace


    type name[size1][size2]...[sizeN];

Příklad

Níže uvedený kód deklaruje 3-rozměrné pole s dimenzemi 5, 10 a 4


    int threedim[5][10][4];

Dvourozměrná pole

Asi nejpoužívanějším typem vícerozměrných polí je dvourožměrné pole které deklarujeme následovně:


    type array_name[x][y];

Uvažujme následující příkaz v jazyce C který deklaruje dvourozměrné pole s dimenzemi x = 3 a y = 4 obsahující hodnty typu int.


    int array[3][4];

Výše uvedené pole si můžeme přestavit jako tabulku, Kde x udává počet řádků a y udává počet sloupců.

Inicializace

Dvourozměrné pole můžeme podobně jako jednorozměrné inicializovat již konkrétními s hodnotami:


    int a[3][4] = {  
       {0, 1, 2, 3} ,
       {4, 5, 6, 7} ,
       {8, 9, 10, 11} 
    };

Přístup k prvkům

Přístup k prvkům pole provádíme standardně pomocí indexů u v hranatých závorkách. Příkazem níže získáme hodnotu na řádku číslo 2 a sloupci číslo 3. Řádky i sloupce jsou číslovány od 0.


    int array_value = a[2][3];

Tabulka níže ukazuje jak indexovat jednotlivé hodnoty u dvourozměrného pole se 3 řádky a 4 sloupci.

Two Dimensional array

Příklad


    #include <stdio.h>
    #define ROWS 5
    #define COLS 2
    
    int main () {
       int a[ROWS][COLS] = {
            {0,0}, 
            {1,2}, 
            {2,4}, 
            {3,6},
            {4,8}
       };
     
       for (int row = 0; row < ROWS; row += 1) {
           for (int col = 0; col < COLS; col += 1) {
               printf("a[%d][%d] = %d\n", row, col, a[row][col]);
           }
       }
       return 0;
    }

Dynamická vícerozměrná pole

Dvourozměrné pole můžeme vidět jako "pole ukazatelů". Deklarujeme tedy pole, které bude uchovávat ukazatele na int (v podstatě jde o pole polí). Každý řádek tedy může obsahovat jiný počet hodnot, což se nám může hodit u polí obsahující řetězce.


    const char* texts[] = {"aaa", "bb", "c"};
    printf("%s\n", texts[0]); // aaa
    printf("%c\n", texts[1][0]); // b

Dynamická alokace řádků


    int* array[3]; // Musime udat pocet radku (3)
    array[0] = (int*) malloc(sizeof(int) * 2);
    array[1] = (int*) malloc(sizeof(int) * 4);
    array[2] = (int*) malloc(sizeof(int) * 6);
    // Prvni radek ma dva 2 sloupce, druhy 4, treti 6
    
    array[0][0] = 4; // V poradku
    array[1][2] = 4; // V poradku
    array[0][2] = 4; // Spatne!
    array[2][3] = 4; // V poradku
    array[1][4] = 4; // Spatne!
    array[1] = 4; // Spatne, pole[1] je ukazatel na int, ne int

Dynamická alokace celého pole

Jedná se o nejdynamičtější variantu, kdy velikost dvourozměrného pole určíme až v při běhu programu. Než si ukážeme jak na to, tak si připomeňme jak alokovat pole čísel typu int.


    int* array = (int *) malloc(sizeof(int) * x);

Pokud chceme alokovat pole ukazatelů, tak to uděláme velice podobně jako kdybychom alokovali paměť pro čísla, jen místo sizeof(int) použijeme sizeof(int *) a místo uložení ukazatele si uložíme ukazatatel na ukazatel.


    int** matrix = (int**) malloc(sizeof(int*) * 2);
    matrix[0] = (int*) malloc(sizeof(int) * 4);
    matrix[1] = (int*) malloc(sizeof(int) * 69);

Funkce vracející vícerozměrné pole (výuková verze)

Pokud chceme vytvořit funkci vracející vícerozměrné pole, tak tato funkce musí vracet ukazatel na ukazatel.


    int** alloc_2d_array(size_t rows, size_t cols) {
        int **array = (int **) malloc(rows * sizeof(int *));
        
        for (int row = 0; row < rows; row += 1) {
            array[row] = (int *) calloc(cols, sizeof(int));
        }
        
        return array;
    }

Reprezentace vícerozměrného pole jednorozměrným

Alokace a dealokace je u vícerozměrných polí je složitější jako u jednorozměrných. Je tedy někdy vhodné reprezentovat vícerozměrné pole jednorozměrným. Princip spočívá v tom, že jednolivé řádky naskládáme za sebe do jendorozměrného pole. Výhodou je, že alokujeme pouze jednorozměrné pole ale nevýhodou je složitejěí přístup k prvkům pole (viz. obrázek).

Row major index

Úkoly

Napište funkci pro dealokaci dvourozměrného pole.
Do funkce alloc_2d_array přidejte kontrolu alokace. Pokud alokace selže funkce musí vracet NULL.
Vytvořte funkci, beroucí celočíselné argumenty m a n, která alokuje a vrátí dvourozměrné pole o velikosti m×n. Prvky pole budou reprezentovat násobky. Tedy prvek pole na indexu i, j bude roven i · j. Ve funkci main vypište toto pole.
Přepište předchozí funkci s použitím reprezentace jednorozměrným polem.