Aritmetika ukazatelů a pole
C++ 11

V tomto článku si vysvětlíme, co je aritmetika ukazatelů. Ukážeme si význam a aplikaci dalších operátorů vztahujících se k ukazatelům a popíšeme si jejich vzájemné vztahy k polím různých datových typů.

První si vysvětlíme, co to znamená, když uvedeme ve zdrojovém kódu identifikátor reprezentující pole bez operátoru indexace. V takovém případě se daný identifikátor v podstatě stává ukazatelem na nultou položku pole, tedy jinak řečeno, je to ukazatel na počátek pole. Na následujícím příkladu je třeba vidět, že lze adresu počátku pole přiřadit i do skutečného ukazatele, se kterým pak můžeme různě pracovat za pomoci aritmetických operátorů, jak si ukážeme dále v tomto článku.

int main() {
    int arr[10];
    int* ukazatel = arr; // Proměnná "ukazatel" je nyní inicializována adresou počátku pole jménem "arr"

    return 0;
}

Na takto inicializovaný ukazatel pak lze aplikovat operace sčítání a odčítání pomocí celých čísel. Význam těchto operací je posouvání ukazatele o daný počet položek pole dopředu nebo dozadu. Jinými slovy můžeme říci, že chceme pracovat s některým z předchůdců či následovníků položky pole, na něž ukazatel uchovává adresu nyní. Jedná se vlastně o nástroj pro relativní indexování v nějakém poli. Ukažme si vše na příkladu.

int main() {
    int pole[10];

    int* p = pole; // Ukazatel má adresu 0. položky
    p = p + 5;     // Ukazatel má adresu 5. položky
    p = p - 2;     // Ukazatel má adresu 3. položky

    *(p - 1) = 12;  // Pozor!!! Zde zapíšeme na 2. položku pole hodnotu 12

    return 0; 
}

První je ukazatel p inicializován na začátek deklarovaného pole, odkazuje tedy na položku s indexem 0. Po té je mu přičteno číslo 5 a jeho adresa bude odkazovat na 5. položku pole. Po odečtení čísla 2 v následujícím příkazu bude ukazatel nasměrován na 3. položku.

Poslední příkaz probereme trochu podrobněji. První se vyhodnotí výraz v závorce. Ukazatel má adresu 3. položky a dále se od ukazatele odečítá číslo 1, čili hodnota výrazu v závorce bude adresa na 2. položku pole. Po té se na tuto adresu aplikuje operátor dereference, který znamená, že chceme zapisovat do dané adresy. Nakonec je přiřazeno číslo 12 na adresu vypočítanou v závorce, tedy do 2. položky pole.

Tak jako na číselné datový typy, tak i na ukazatele můžeme aplikovat operátory inkrementace a dekrementace. Už je asi logicky jasné, že operátor dekrementace posouvá adresu na nejbližšího předchůdce pole, kdežto operátor inkrementace na nejbližšího následovníka. Operátory se vyskytují opět jak v prefixové, tak i postfixové podobě. Ukažme si aplikaci těchto operátorů na následujícím příkladu.

int main() {
    const int velikost = 5;
    int pole1[velikost] = {1, 2, 3, 4, 5};
    int pole2[velikost];

    int *pZdroj = pole1;
    int *pCil = pole2;
    for(int i = 0; i < velikost; i++) {
        *pZdroj = *pCil;
        pZdroj++;
        pCil++;
    }

    return 0;
}

Program na posledním příkladu okopíruje hodnoty pole1 do pole jménem pole2.

Závěrem by asi čtenáři mělo být jasné, že pokud přičtu k ukazateli číslo jedna, tak adresa, kterou uchovává, se nezvedne o číslo 1, tedy o 1 byte, ale o počet bytů, které zabírá v paměti datový typ, pro který je ukazatel deklarován. TODO – DOPLNIT NÁZORNÝ DIAGRAM INDEXACE A VZTAH K ARITMETICE ADRES, TROCHU ROZVÉST.