Linux E X P R E S

Facebook

Programovanie v jazyku C++: Pointery – Tipy a triky (4)

cplusplus.png

Máme niekoľko možností kombinácie pointerovej aritmetiky a dereferenčného operátora. Okrem ukážok si o každej možností niečo povieme, napr. ako sa vyvarovať potencionálnych chýb s pamäťou.


Tipy a triky pri pointerovej aritmetike

Ukážme si príklady, kedy pointerová aritmetika môže zmiasť a programátor nedopatrením urobí chybu, ktorá sa mu môže vypomstiť. Uvidíme tri rôzne možností, ako môžete využiť nakombinovať pointerovú aritmetiku.

V prvom príklade využijeme tento tvár: *ptr++.

#include <iostream>
using namespace std;
 
int main()
{
    int pole[] = {55,22,78,91,27,187,155};
    int *ptr = pole;
 
    for(int i = 0; i < 3; i++)
    {
        cout << *ptr++ << " ";
    }
    cout << "\nUkazovatel ukazuje: " << *ptr;
    return 0;
}

Výstup programu:

55 22 78
Ukazovatel ukazuje: 91

Použitím *ptr++ dôjde najprv k inkrementácii adresy a potom a teraz pozor, dereferencia sa týka predošlej adresy, nie aktuálnej po inkrementácii!. Prečo to funguje takto podivné? Pretože postfix ++ má prednosť pred prefixom, ktorý predstavuje znak dereferencie *. Avšak pri tomto definovaní sa tiež môžete ľahko dostať do problému s pamäťou. Ak by ste chceli vypísať celé pole, tak pri poslednej iterácii dôjde k tomu, že pointer bude ukazovať mimo vašu vyhradenú pamäť a môže dôjsť v tom lepšom prípade len k pádu programu. Ako sa brániť proti tomuto druhu potencionálnej chyby? Napr. pridaním podmienky if/else.



#include <iostream>
using namespace std; 
int main()
{
    int pole[] = {55,22,78,91,27,187,155};
    int *ptr = pole; 

    for(int i = 0; i < 7; i++)
    {
        if(i != 6)
            cout << *ptr++ << " ";
        else cout << *ptr << " ";
    }
    cout << "\nUkazovatel ukazuje: " << *ptr;
    return 0; }

Výstup programu:

55 22 78 91 27 187 155
Ukazovatel ukazuje: 155

Druha možnosť využitia pointerovej aritmetiky je v tváre  *++p.

#include <iostream>
using namespace std; 

int main()
{
    int pole[] = {55,22,78,91,27,187,155};
    int *ptr = pole; 

    for(int i = 0; i < 3; i++)
    {
        cout << *++ptr << " ";
    }
    cout << "\nUkazovatel ukazuje: " << *ptr;
    return 0;
}

Výstup programu:

22 78 91 Ukazovatel ukazuje: 91

Ak sú oba operátory prefixové, čiže majú rovnakú prioritu a vtedy sa vykonávajú operátory sprava do ľavá. Najprv sa inkrementuje adresa pointera a následne sa aplikuje dereferenčný operátor.

Problémy s pamäťou sa iste objavia, ak si neustriehnete pridelený blok pamäte. Skúsme sa pozrieť na alternatívne riešenie odlišné od prvého riešenia tak, aby sme skúsili viacero možností v tomto dieli.

#include <iostream>
using namespace std; 
int main()

{
    int pole[] = {55,22,78,91,27,187,155};
    int *ptr = pole; 
    for(int i = 0; i < 7-1; i++)
    {
        cout << *++ptr << " ";
    }
    cout << "\nUkazovatel ukazuje: " << *ptr;
    return 0;
}

Výsledok programu:

22 78 91 27 187 155 Ukazovatel ukazuje: 155

Vyriešili sme to tak, že sme počet iterácii obmedzili podmienkou i < 7-1, kde 7 je počet prvkov v polí a od toho odčítame práve tu poslednú problematickú iteráciu. Ako z pointera zistiť veľkosť poľa sa dozviete v jednom z ďalších dieloch. Zatiaľ sme to definovali takto provizórne.

A teraz sa pozrime na poslednú tretiu možnosť pointerovej aritmetiky.

#include <iostream>
using namespace std; 
int main()
{
    int pole[] = {55,22,78,91,27,187,155};
    int *ptr = pole; 
    for(int i = 0; i < 3; i++)
    {
        cout << ++*ptr << " ";
    }
    cout << "\nUkazovatel ukazuje: " << *ptr;
    return 0;
}

Výsledok programu:

56 57 58 Ukazovatel ukazuje: 58 

Pri tretej možností kombinácie pointerovej aritmetiky s dereferenčným operátorom ++*ptr, opäť nastáva to, že oba operátory sú prefixy, čiže majú rovnakú prioritu. Vykonaním sprava do ľavá najprv sa aplikuje dereferenčný operátor a následne sa inkrementuje hodnota prvku, ktorú sme získali dereferenčným operátorom a nie adresa! Nikdy nedôjde k zmene adresy! Taktiež nehrozí žiadny problém s pamäťou, pretože stále bude pointer ukazovať na ten istý prvok. Presvedčme sa.

#include <iostream>
using namespace std; 
int main()
{
    int pole[] = {55,22,78,91,27,187,155};
    int *ptr = pole; 
    for(int i = 0; i < 25; i++)
    {
        cout << ++*ptr << " ";
    }
    cout << "\nUkazovatel ukazuje: " << *ptr;
    return 0;
}

Výsledok programu:

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
Ukazovatel ukazuje: 80 

Námet na tento článok poslúžili tieto zdroje:

Difference between ++*p, *p++ and *++p, geeksforgeeks.org, dostupné online

Can you explain the difference between *ptr++ and *(++ptr)? [duplicate], stackoverflow.com, dostupné online






Diskuze (1) Nahoru