Ce face Pointer la pointer (**)
Un pointer este tot o variabilă, deci are și el o adresă. int **pp = &p; păstrează adresa pointerului p. *pp este p, iar **pp este valoarea spre care arată p.
Cel mai des îl folosești în două situații: când o funcție trebuie să modifice un pointer al apelantului (de exemplu să-i aloce memorie) și pentru tablouri de șiruri, cum este char **argv din main sau un const char *nume[] trimis unei funcții.
Se poate merge și mai departe (***), dar codul devine greu de citit; de obicei un struct sau un typedef ajută mai mult.
Exemple
Exemplul 1: Două niveluri de adrese
Prin pp poți ajunge la x (cu **pp) sau poți schimba spre ce arată p (cu *pp).
#include <stdio.h>
int main(void) {
int x = 10, y = 20;
int *p = &x;
int **pp = &p;
printf("**pp = %d\n", **pp);
*pp = &y; // acum p arată spre y
printf("*p = %d\n", *p);
**pp = 25; // modifică y
printf("y = %d\n", y);
return 0;
}
Rezultat
**pp = 10
*p = 20
y = 25
Exemplul 2: O funcție care alocă memorie pentru apelant
Funcția primește adresa pointerului din main și scrie în el adresa memoriei alocate. Cu un simplu int * ar fi schimbat doar copia locală.
#include <stdio.h>
#include <stdlib.h>
int creeaza_note(int **rezultat, size_t n) {
int *v = malloc(n * sizeof *v);
if (v == NULL) return 0;
for (size_t i = 0; i < n; i++) v[i] = 10 - (int)i;
*rezultat = v;
return 1;
}
int main(void) {
int *note = NULL;
if (creeaza_note(¬e, 4)) {
for (size_t i = 0; i < 4; i++) printf("%d ", note[i]);
printf("\n");
free(note);
}
return 0;
}
Rezultat
10 9 8 7
Exemplul 3: Un tablou de șiruri trimis unei funcții
Parametrul const char **orase primește tabloul de pointeri. Fiecare orase[i] este un const char *.
#include <stdio.h>
void afiseaza(const char **orase, size_t n) {
for (size_t i = 0; i < n; i++) {
printf("%zu. %s\n", i + 1, orase[i]);
}
}
int main(void) {
const char *orase[] = {"Iași", "Cluj-Napoca", "Timișoara"};
afiseaza(orase, sizeof orase / sizeof orase[0]);
return 0;
}
Rezultat
1. Iași
2. Cluj-Napoca
3. Timișoara
Greșeli frecvente
- Trimiți unei funcții care alocă memorie un
int *în loc deint **. Alocarea se face, dar pointerul din apelant rămâne neschimbat, iar memoria se pierde. - Crezi că
int m[3][4]este unint **. Matricea este un bloc continuu deint; unint **este un tablou de pointeri. Nu le poți schimba între ele. - Uiți un nivel de
*:*pp = 5pune 5 în pointer (ca adresă), nu în valoarea finală. Compilatorul avertizează, iar cu-Werrorcodul nu se compilează.
Comenzi înrudite
Pointeri (& și *): O variabilă care păstrează adresa altei variabile; cu * citești sau modifici valoarea de la acea adresă.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.Tablouri bidimensionale (matrice): Un tablou de tablouri: date așezate pe rânduri și coloane, accesate cu doi indici, m[rând][coloană].main: Funcția cu care începe orice program C: sistemul o apelează la pornire, iar valoarea returnată spune dacă programul a reușit.Șiruri de caractere (char[]): În C, un șir de caractere este un tablou de char terminat cu caracterul nul ‘\0’, care marchează sfârșitul textului.