Documente Academic
Documente Profesional
Documente Cultură
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 90
Cuprins
• Pointeri şi operaţii cu pointeri
• Calificatorul const aplicat variabilelor de tip
pointer
• Pointeri şi tablouri
• Utilizarea variabilelor tablou ca parametri ai
funcţiilor
• Pointeri la funcţii
• Funcţii care returnează pointeri
• Alocarea dinamică a memoriei
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 90
Pointeri şi operaţii cu pointeri
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 90
char * p; /*variabilă pointer ce poate memora adresa unei variabile de tip
caracter*/
char c, d; /*variabile de tip caracter*/
c = 'Q'; /*atribuire de valoare de tip caracter*/
p = &c; /*în p se memorează adresa de început a zonei de memorie
alocată variabilei c*/
adresa… conţinutul de la adresa…
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 91
Adunare/scădere de constante la o valoare pointer
Rezultatul expresiei p+1 este adresa valorii de tip întreg ce se află în memorie
imediat după cea indicată de p. Deoarece p este un pointer „la int”, pentru
efectuarea calculelor compilatorul utilizează în rolul constantei 1 valoarea
1*sizeof(int).
Observaţii:
p+1 → pointer la următorul element de acelaşi tip (adresa elementului
situat în memorie imediat după cel indicat de p)
*(p+1) → întregul (valoarea lui) aflat în memorie imediat după cel de la
adresa p
p+2 → se poate aduna orice valoare constantă, nu doar valoarea 1!
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 92
Incrementarea/decrementarea valorilor pointer
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 92
Pointer_brev_15_16_cap7.c
#include <stdio.h>
int main()
{ int m=12, k=400, *p;
char b='t', a='V', *q;
p=&k;
q=&a;
printf("Adresa pt. q: %p\tValoarea lui q: %p\n\t\t\tValoarea de la adresa q:%c\n",&q,q,*q);
printf("---------------------------------------------------\n");
printf("Adresa pt. a: %p\tValoarea lui a: %c\n",&a,a); Desen pe tabla…
printf("Adresa pt. b: %p\tValoarea lui b: %c\n",&b,b);
printf("---------------------------------------------------\n");
printf("Adresa pt. p: %p\tValoarea lui p: %p\n\t\t\tValoarea de la adresa p:%d\n",&p,p,*p);
printf("---------------------------------------------------\n");
printf("Adresa pt. k: %p\tValoarea lui k: %d\n",&k,k);
printf("Adresa pt. m: %p\tValoarea lui m: %d\n",&m,m);
printf("---------------------------------------------------\n");
p=p+1; /*sau p++; */
q=q+1; /*sau q++; */
printf("Adresa pt. q: %p\tValoarea lui q: %p\n\t\t\tValoarea de la adresa q:%c\n",&q,q,*q);
printf("Adresa pt. p: %p\tValoarea lui p: %p\n\t\t\tValoarea de la adresa p:%d\n",&p,p,*p);
return 0;
}
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 92-1
Pointer NULL
char *p;
p = 0;
sau p= NULL; /*NULL este o constantă predefinită descrisă, de exemplu, in
stddef.h*/
Observaţie: indiferent de tipul variabilei pointer, valoarea atribuită în acest mod
este întotdeauna 0 (zero).
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 93
Pointer void *
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 93
Scăderea a doi pointeri de acelaşi tip
•Două variabile de acelaşi tip pointer - adresează obiecte de
acelaşi tip
•Rezultatul operaţiei de scădere - valoare întreagă =
numărul de obiecte situate între cele două adrese
•Prelucrări asupra variabilelor de tip tablou (vom vedea!)
•Tipul predefinit ptrdiff_t descris în fişierul stddef.h
#include <stddef.h>
ptrdiff_t d, i; /* 2 variabile ce pot memora diferenţa a 2 pointeri */
int *p1,*p2, m, n; /* 2 variabile de tip pointer „la int” şi 2 variabile de tip int */
float *p, *q, x, y; /* 2 variabile de tip pointer „la float” şi 2 variabile de tip float */
p1=&m;
p2=&n;
d=p2-p1; /*corect: p1 şi p2 sunt de acelaşi tip */
p=&x;
q=&y;
i = q – p; /*corect: p şi q sunt de acelaşi tip */
i = p2 – q; /*greşit: p2 şi q nu sunt de acelaşi tip; se va genera eroare în
faza de compilare */
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 94
Atribuirea de valori pointer
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 94
#include <stdio.h>
#include <stdlib.h> Pointeri_1.c eventual…
int main(void)
{ int *p, *q, a=1, b=2, t[3]={10,20,30};
float x=23.5, *adr;
adr=&x;
p=&a;
q=&x; /*eroare la compilare: q este pointer la int iar x este de tip float*/
p=&t[0]; /* p= 0022FF50 */
printf("Valoarea lui t[1] este: %d, identic cu %d\n", t[1], *(p+1));
q=&t[2]; /* q= 0022FF58 */
printf("Între adresele de memorie %p si %p există %d numere întregi\n", p, q,
q-p); /* pe ecran apare valoarea 2 */
q=q-2; /* q==p */
a=adr-p; /*eroare la compilare: cei 2 pointeri nu sunt de acelaşi tip*/
return 0; 0022FF48 adr
} 0022FF4C 23.5 x
0022FF50 10 t[0]
Ca urmare a lansării în execuţie a exemplului de program anterior, pe ecran apare 0022FF54 20 t[1]
următorul text: 0022FF58 30 t[2]
0022FF5C
Valoarea lui t[1] este: 20, identic cu 20 0022FF60 2 b
Între adresele de memorie 0022FF50 şi 0022FF58 există 2 numere întregi 0022FF64 1 a
0022FF68 q
0022FF6C p
Dev C++ 5 - dimensiunea în octeţi pentru câteva tipuri reprezentative este:
char=1, int=4, short int=2, long int=4, pointer=4, float=4, double=8.
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 95
Compararea valorilor pointer
Caracteristici:
se efectuează în aceleaşi condiţii ca scăderea (valorile pointer trebuie să fie de
acelaşi tip);
permite utilizarea tuturor celor 6 operatori de comparaţie:
< <= > >= == !=
utilizează regula: p>q este „adevărat” (valoare 1) atunci când se poate calcula
diferenţa p-q şi valoarea rezultată este strict pozitivă (>0);
orice valoare pointer poate fi comparată cu valoarea 0 (NULL).
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 95
Calificatorul const aplicat variabilelor de tip pointer
const int m=5;
m++; /*eroare la compilare: valoarea lui m nu poate fi modificata */
adr t
short t[3]; t[0]
short *adr; t[1]
adr = &t[0];
adr+2
t[2]
Particularitate:
Indicele
--- deplasare faţă de adresa de început
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 96
Particularitate:
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 97
Utilizarea variabilelor tablou unidimensional ca
parametri ai funcţiilor
Nume tablou ≡ pointer constant --- adresa I element al tabloului
Particularitate:
Folosirea unui tablou unidimensional ca parametru al unei funcţii
se va face întotdeauna, implicit, prin referinţă (adresă) şi nu prin
valoare, indiferent de forma în care este scris parametrul formal la
definirea funcţiei.
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 97
Exemple
folosind ca parametri:
tabloul
si numărul său de elemente
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 98
/*scrierea „clasică” a parametrilor şi accesarea elementelor tabloului prin index
(poziţie)*/ se poate omite specificarea dimensiunii maxime; se
poate scrie şi float x[100] !!!
float suma (float x[ ], int nr)
{ int i; specifică numărul efectiv de elemente din tablou
float s = 0.0;
for(i = 0; i < nr; i++)
s += x[i];
return s;
}
/*exemplificarea modului de apelare a funcţiei*/
int main (void)
{ int i, n;
float a[100], rez;
/*...aici pot fi scrise instrucţiunile pentru citirea de la tastatură a numărului de
elemente din tablou şi a valorilor ce fac parte din acesta
...............
*/
rez = suma (a, n); /* apelarea funcţiei suma() */
numele tabloului (care este şi pointer la primul element)
*/ ...aici pot să apară alte instrucţiuni ce aparţin funcţiei main()*/
} TABL73.c
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 98
/* scrierea explicită a parametrului tablou ca pointer şi accesarea elementelor prin
pointer (adresă) */
parametru de tip pointer la element de tipul celor din tablou
float suma (float *x, int nr)
{ float *final = x + nr; /* adresa finală a tabloului în memorie*/
float s = 0.0, *p;
for(p = x; p < final; ++p)
s += *p; /* echivalent cu: s=s+ *p; */
return s; se putea scrie p<x+nr şi se renunţa la declararea şi
} utilizarea variabilei final, dar timpul de execuţie este mai
bun aşa !
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 99
Observaţie: deoarece x, de tip „pointer la float”, este un parametru trimis prin
valoare, o eventuală modificare a sa în interiorul funcţiei nu se va reflecta în
exteriorul acesteia, ceea ce permite scrierea unei variante simplificate:
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 99
Particularitate:
…Consecinţă…
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 100
Exemplu:
Un program C care interschimbă valorile de tip întreg din două tablouri
unidimensionale citite de la tastatură, putând afişa pe ecran, de exemplu,
următorul text:
Introduceţi informaţii despre tabloul A
Tastaţi nr. de elemente: 3
Tastaţi valorile elementelor:
A[0]=1
A[1]=2
A[2]=3
Introduceţi informaţii despre tabloul B
Tastaţi nr. de elemente: 3
Tastaţi valorile elementelor:
B[0]=4
B[1]=5
B[2]=6
Valorile iniţiale sunt:
A[0]=1 A[1]=2 A[2]=3
B[0]=4 B[1]=5 B[2]=6
După interschimbare, valorile sunt:
A[0]=4 A[1]=5 A[2]=6
B[0]=1 B[1]=2 B[2]=3
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 100
TABL73M.c
/* Programul principal */ Tablou_7_3.c
#include <stdlib.h> /*pentru exit() */
#include <stdio.h>
void CiteşteTablouDeLaTastatură (int t[ ], int * nr, char nume);
void Afişează (int t[ ], int nr, char nume);
void Interschimbă (int x[ ], int y[ ],int nr);
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 101
/* Functie pentru citirea de la tastatură a:
- numărului de elemente ce fac parte dintr-un tablou unidimensional cu
elemente de tip întreg;
- tuturor valorilor ce fac parte din tablou;
Valorile citite pot fi folosite, după încheierea execuţiei funcţiei, de către funcţia
apelantă.*/
void CiteşteTablouDeLaTastatură (int t[ ], int * nr, char nume)
{int i;
(int *t, int * nr, char nume)
printf("Tastaţi nr. de elemente:");
scanf("%d", nr); /* NU se scrie &nr, nu ar fi corect în acest caz! */
printf("Tastaţi valorile elementelor:\n");
for(i = 0; i < *nr; i++)
{printf("%c[%d]=", nume, i);
scanf("%d", &t[i]); scanf("%d", (t+i));
} sau scanf("%d", t++);
}
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 101
/* Funcţie pentru afişarea pe ecran a valorilor tabloului */
void Afişează (int t[ ], int nr, char nume) void Afişează (int *t, int nr, char nume)
{int i; {int i;
for(i = 0; i < nr; i++) for(i = 0; i < nr; i++)
printf("%c[%d]=%d ", nume, i,t[i]); printf("%c[%d]=%d ", nume, i,*(t+i));
printf("\n"); printf("\n");
} }
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 102
Pointeri către tablouri unidimensionale
Reamintire:
char *s ; /* pointer la char – poate adresa o zonă de 1 octet */
float *r; /* pointer la float – poate adresa o zonă de 4 octeţi */
Exemplu:
int a[10]; /* tablou cu 10 elemente de tip int */
int * p_int; /* pointer la int */
int (* p_tab)[10]; /* pointer la tablou cu 10 elemente de tip int */
p_int = a;
p_tab = &a; /* p_int şi p_tab sunt pointeri de tipuri diferite !!! */
int a [10]
p_int p_int +1
p_tab p_tab+1
a[1][0]
a[3][2] a[1]
a[1][1]
a+2
a[2][0]
a[2]
a[2][1]
*a == a[0]
=> *a[0] == a[0][0] => **a == a[0][0]
a[0] == &a[0][0]
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 103
Accesarea elementelor tabloului bidimensional:
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 103
Utilizarea variabilelor tablou multidimensional ca
parametri ai funcţiilor
Similară celei prezentate pentru tablouri unidimensionale.
DAR…
La declararea parametrului se poate omite doar specificarea
primei dimensiuni.
Se pot specifica drept parametri:
un pointer (adresa primului element din tablou) si
dimensiunile tabloului
!!! Ultima variantă trebuie folosită cu multă atenţie --- poate genera
dificultăţi utilizatorilor ne-experimentaţi.
Exemplu: Afişarea elementelor unui tablou bidimensional, int x[3][4]
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 104
trebuie să apară; se poate omite doar prima dimensiune
void AfisMatr (int a[ ][4], int m, int n)
{ int i, j; numărul de coloane din tablou
for( i = 0; i < m; i++)
numărul de linii din tablou
{ for( j = 0; j < n; j++)
printf(“%6d”, a[i][j]);
printf(“\n”);
}
}
/*exemplificarea modului de apelare a funcţiei*/
int main (void)
{ int i, j, l, c;
int x[3][4];
/*...aici pot fi scrise instrucţiunile pentru citirea de la tastatură a numărului de
elemente din tablou şi a valorilor ce fac parte din acesta
...............
*/
AfisMatr (x, l, c); /* apelarea funcţiei AfisMat() */
Numele tabloului, urmat de dimensiunile acestuia. Pentru
corectitudinea funcţionării programului, este important ca,
în acest caz, c să aibă valoarea 4.
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 104
Nu poate fi omisă !!!
INCORECT: void matprint (int a[ ][ ], int m, int n)
Două posibile (…) soluţii CORECTE:
/*Prima soluţie*/
void AfisMatr (int (*a)[4], int m, int n) /*detalii live, la curs*/
{ int i, j;
for( i = 0; i < m; i++)
{ for( j = 0; j < n; j++)
printf(“%6d”, *(a[i]+j));
printf(“\n”);
}
}
TABL741_mod17.c
/*A doua soluţie*/
#include<stddef.h> /* necesar pt. folosirea tipului ptrdiff_t */
void matprint (void *a, int m, int n)
{ int *v = (int*)a;
int nr = m * n; /*numărul total de elemente din tablou*/
ptrdiff_t d; /*pentru diferenţa dintre două valori pointer*/
while((d = v – (int*)a) < nr)
printf( (d%n == n-1) ? “%6d\n” : “%6d”, * v ++ );
/*pentru afişarea sub formă de matrice*/
/*nu functioneaza corect in anumite situatii – detalii live, la curs*/
}
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 105
Particularitate:
…Consecinţă…
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 105
EXEMPLU
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 106
Câte linii au matricele? 2
Câte coloane au matricele? 3
Tastaţi valori pentru matricea A:
Dorim ca A[0][0]=3
lansarea în A[0][1]=1
A[0][2]=1
execuţie a A[1][0]=2
programului sa A[1][1]=5
produca, de A[1][2]=6
Tastaţi valori pentru matricea B:
exemplu, B[0][0]=0
afisarea acestor B[0][1]=3
B[0][2]=0
informatii pe B[1][0]=5
ecranul B[1][1]=4
sistemului de B[1][2]=-1
Iniţial, valorile celor 2 matrice sunt:
calcul: Matricea A:
311
256
Matricea B:
030
5 4 -1
După interschimbare, valorile celor 2 matrice sunt:
Matricea A:
301
-1 5 6
Matricea B:
130
542
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 106
TEST2742.c
TABL742.c – modif. …
#include <stdio.h>
/* Functie pentru citirea de la tastatură a valorilor ce fac parte dintr-un tablou
bidimensional cu elemente de tip întreg.
Valorile citite pot fi folosite, după încheierea execuţiei funcţiei, de către funcţia
apelantă.*/
void creare_matrice(int a[][10], int l, int c, char nume)
{ int i,j;
printf ("Tastati valori pentru matricea %c:\n",nume);
for(i=0;i<l;i++)
for(j=0;j<c;j++)
{printf("%c[%d][%d]=",nume,i,j);
scanf ("%d",&(a[i][j]));
}
}
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 107
/* Funcţie pentru afişarea pe ecran a valorilor tabloului */
void afisare_matrice(int a[][10] , int l, int c, char nume)
{ int i,j;
printf("Matricea %c:\n",nume);
for(i=0;i<l;i++)
{ for(j=0;j<c;j++) printf ("%d ",a[i][j]);
printf ("\n");
}
}
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 107
/* Programul principal */
int main ()
{ int i,j,p1,p2,aux,m,n,a[10][10],b[10][10];
printf("Cate linii au matricele? ");
scanf("%d",&m);
printf("Cate coloane au matricele? ");
scanf("%d",&n);
creare_matrice(a,m,n,'A');
creare_matrice(b,m,n,'B');
printf("Initial, valorile celor 2 matrice sunt:\n");
afisare_matrice(a,m,n,'A');
afisare_matrice(b,m,n,'B');
for(i=0;i<m;i++) /* interschimbarea elementelor cu valoare minimă*/
{ p1=poz_min(a[i],n);
p2=poz_min(b[i],n);
aux=a[i][p1];
a[i][p1]=b[i][p2];
b[i][p2]=aux;
}
printf("Dupa interschimbare, valorile celor 2 matrice sunt:\n");
afisare_matrice(a,m,n,'A');
afisare_matrice(b,m,n,'B');
return 0;
}
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 108
Tabl_7_nov_15.c
2 3 10 15 17
1 5 4 6 12
8 -3 -1 5 7
2 10 0
4 6 12
8 0 0
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 108-1