Pointeri (& și *) în C

Pointeri C89

O variabilă care păstrează adresa altei variabile; cu * citești sau modifici valoarea de la acea adresă.

Sintaxă
tip *p;          // p păstrează adresa unui tip
p = &variabila;  // & = adresa lui
*p = valoare;    // * = valoarea de la adresa din p

Ce face Pointeri (& și *)

Fiecare variabilă stă la o adresă în memorie. Operatorul & îți dă această adresă, iar un pointer este o variabilă în care o păstrezi: int *p = &x; se citește „p este un pointer la int și arată spre x”.

Operatorul * aplicat unui pointer (dereferențiere) înseamnă „valoarea de la adresa asta”. *p = 5; schimbă chiar variabila x.

În C, argumentele sunt trimise funcțiilor prin valoare (ca o copie). Dacă vrei ca o funcție să modifice o variabilă a apelantului, îi trimiți adresa variabilei, iar funcția lucrează prin pointer. Un pointer care nu arată spre nimic primește valoarea NULL (sau nullptr în C23).

Exemple

Exemplul 1: Adresa și valoarea

După *p = 1500, variabila salariu are noua valoare, pentru că p arată spre ea. Adresele diferă la fiecare rulare, așa că aici comparăm doar că sunt egale.

#include <stdio.h>

int main(void) {
    int salariu = 1200;
    int *p = &salariu;
    printf("salariu = %d, *p = %d\n", salariu, *p);
    *p = 1500;
    printf("după *p = 1500: salariu = %d\n", salariu);
    printf("p arată spre salariu? %s\n", p == &salariu ? "da" : "nu");
    return 0;
}

Rezultat

salariu = 1200, *p = 1200
după *p = 1500: salariu = 1500
p arată spre salariu? da

Exemplul 2: Funcția swap: modificare prin pointer

Funcția primește adresele, deci schimbă chiar variabilele din main. Cu parametri int a, int b ar fi schimbat doar copiile.

#include <stdio.h>

void schimba(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main(void) {
    int x = 3, y = 8;
    schimba(&x, &y);
    printf("x = %d, y = %d\n", x, y);
    return 0;
}

Rezultat

x = 8, y = 3

Exemplul 3: Mai multe rezultate dintr-o funcție

Funcția returnează un cod de succes și scrie rezultatele prin pointeri. Verifică NULL înainte să scrie, ca apelantul să poată sări peste un rezultat.

#include <stdio.h>
#include <stddef.h>

int min_max(const int *v, size_t n, int *min, int *max) {
    if (n == 0) return 0;
    int mic = v[0], mare = v[0];
    for (size_t i = 1; i < n; i++) {
        if (v[i] < mic) mic = v[i];
        if (v[i] > mare) mare = v[i];
    }
    if (min != NULL) *min = mic;
    if (max != NULL) *max = mare;
    return 1;
}

int main(void) {
    int temperaturi[] = {12, -3, 7, 21, 4};
    int mic, mare;
    if (min_max(temperaturi, 5, &mic, &mare)) {
        printf("minim %d, maxim %d\n", mic, mare);
    }
    return 0;
}

Rezultat

minim -3, maxim 21

Greșeli frecvente

  • Folosești un pointer neinițializat: int *p; *p = 5;. p conține o adresă la întâmplare, iar scrierea acolo este comportament nedefinit. Inițializează-l cu o adresă validă sau cu NULL.
  • Dereferențiezi NULL. Verifică pointerul înainte de *p dacă poate fi nul (de exemplu rezultatul lui malloc sau fopen).
  • Scrii int* a, b; crezând că ai doi pointeri. Doar a este pointer; b este int. Scrie int *a, *b;.
  • Returnezi adresa unei variabile locale. Variabila dispare la ieșirea din funcție, iar pointerul rămâne „atârnat” (dangling).

Comenzi înrudite

  • Aritmetica pointerilor: Adunarea și scăderea pe pointeri se fac în elemente, nu în octeți: p + 1 arată spre următorul element din tablou.
  • Pointer la pointer (**): Un pointer care păstrează adresa altui pointer: util când o funcție trebuie să schimbe un pointer sau pentru tablouri de șiruri.
  • void * (pointer generic): Un pointer care poate păstra adresa oricărui tip de date, dar care trebuie convertit la un tip concret înainte de folosire.
  • Funcții și prototipuri: Cum definești și declari funcții în C: tipul rezultatului, parametrii, prototipul și transmiterea argumentelor prin valoare.
  • nullptr: Constanta C23 pentru pointerul nul, cu tip propriu (nullptr_t), mai sigură decât NULL sau 0.
  • malloc: Cere sistemului un bloc de memorie de mărimea dată, în timpul rulării, și returnează adresa lui sau NULL dacă nu reușește.