Sunteți pe pagina 1din 11

POINTERI ŞI TABLOURI

MULTIDIMENSIONALE
Elementele unui tablou bidimensional sunt păstrate tot într-o zonă continuă de
memorie, dar inconvenientul constă în faptul că ne gândim la aceste elemente
în termeni de rânduri (linii) .
Un tablou bidimensional este tratat ca un tablou unidimensional ale cărui
elemente sunt tablouri unidimensionale.
int M[4][3]={ {10, 5, -3}, {9, 18, 0}, {32, 20, 1}, {-1, 0, 8} };
Compilatorul tratează atât M, cât şi M[0], ca tablouri de mărimi diferite. Astfel:
cout<<”Marime M:”<<sizeof(M)<<endl; // 24 = 2octeţi 12elemente
cout<<”Marime M[0]”<<sizeof(M[0])<<endl;// 6 = 2octeţi 3elemente
cout<<”Marime M[0][0]”<<sizeof(M[0][0])<<endl; // 4 octeţi (sizeof(int))
Pointeri si tablouri
bidimensionale
M[0] 10 5 -3
Matricea M are 4 linii şi 3 coloane.
Numele tabloului bidimensional, M, referă M[1] 9 18 0
întregul tablou; M{2] 32 20 1
M[0] referă prima linie din tablou; M[3] -1 0 8
M[0][0] referă primul element al tabloului.
Aşa cum compilatorul evaluează referinţa către un tablou unidimensional ca un pointer, un tablou
bidimensional este referit într-o manieră similară. Numele tabloului bidimensional, M, reprezintă adresa
(pointer) către primul element din tabloul bidimensional, acesta fiind prima linie, M[0] (tablou
unidimensional). M[0] este adresa primului element (M[0][0]) din linie (tablou unidimensional), deci
M[0] este un pointer către int: M = M[0] = &M[0][0]. Astfel, M şi M[linie] sunt pointeri constanţi.

Putem concluziona:
 M este un pointer către un tablou unidimensional (de întregi, în exemplul anterior).
 M este pointer către int (pentru că M[0] este pointer către int), şi M = (M + 0) M[0].
 M este întreg; deoarece M[0][0] este int, M= ( M) (M[0])= (M[0]+0) M[0][0].
Exerciţiu: Să se testeze programul următor,
urmărind cu atenţie rezultatele obţinute
#include <iostream.h>
#include <conio.h>
Int main()
{int a[3][3]={{5,6,7}, {55,66,77}, {555,666,777}};
cout<<"a="<<a<<" &a="<<&a<<" &a[0]="<<&a[0]<<endl;
cout<<"Pointeri catre vectorii linii\n";
for (int i=0; i<3; i++){
cout<<" *(a+"<<i<<")="<<*(a+i);
cout<<" a["<<i<<"]="<<a[i]<<endl;
}
// afişarea matricii
for (i=0; i<3; i++){
for (int j=0; j<3; j++)
cout<<*(*(a+i)+j)<<“ ”; //sau:
cout<<*(a[i]+j)<<“ ”;
cout<<endl;
}
}
5.4. TABLOURI DE POINTERI
Un tablou de pointeri este un tablou ale cărui elemente sunt pointeri. Modul general de declarare a unui tablou
de pointeri:
tip  nume_tablou[dim];

Să considerăm exemplul în care se declară şi se iniţializează tabloul de pointeri s_p (figura 5.4.):
char  s_p[3] = { ”Programarea”, ”este”, ”frumoasă!” };
s_p
Deoarece operatorul de indexare [ ] are
s_p[0] prioritate mai mare decât operatorul de
”Programarea”
s_p[1] deferenţiere  , declaraţia char  s_p[3] este
”este” echivalentă cu char  (s_p[3]), care precizează
s_p[2] că s_p este un vector de trei elemente, fiecare
”frumoasă! ” element este pointer către caracter.

Figura 5.4. Tabloul de pointeri s_p


Observatii

• În ceea ce priveşte declaraţia: char *(s_p[3]), se poate


observa:
• 1. s_p[3] este de tipul char * (fiecare dintre cele trei
elemente ale vectorului s_p[3] este de tipul pointer către
char);
• 2. * (s_p[3]) este de tip char (conţinutul locaţiei adresate de
un element din s_p[3] este de tip char).
• Fiecare element (pointer) din s_p este iniţializat să pointeze
către un şir de caractere constant. Fiecare dintre aceste şiruri
de caractere se găsesc în memorie la adresele memorate în
elementele vectorului s_p: s_p[0], s_p[1], etc.
Alcarea dinamica a memoriei
Operatorii new şi delete.
În limbajul C alocarea dinamică a memoriei poate fi facută numai cu funcţii din biblioteci
specializate în gestionarea memoriei, cele mai utilizate fiind funcţiile malloc(), calloc(), free(),
realloc(),toate din <malloc.h>.
În C++ au fost introduşi, special pentru alocarea dinamică, operatorii new şi delete, care fac parte
integrantă din limbaj (şi deci nu necesită apelarea vreunei biblioteci).
Operatorul new poate fi utilizat în două moduri:
• pentru a rezerva spaţiu de memorie pentru un singur obiect, caz în care new întoarce adresa
obiectului alocat;
• pentru a rezerva spaţiu pentru un tablou cu un numar variabil de obiecte (dar bine
determinat în momentul evaluării expresiei, la rulare), caz în care new întoarce adresa
primului element din tablou. Un tablou alocat astfel este numit tablou dinamic.
Prin “obiecte” înţelegem în acest context: date de tip scalar (tipuri aritmetice sau pointeri), structuri
sau chiar tablouri. Nu putem aloca funcţii dar putem aloca pointeri şi tablouri dinamice de pointeri
către funcţii.
Sintaxa operatorului new
Sintaxa operatorului new este următoarea: cuvântul cheie new urmat
de declaratorul abstract al tipului pe care vrem să-l alocăm.
int *p ; p=new int;
Rezultatul operaţiei este adresa variabilei alocate sau, dacă tipul
alocat este un tablou, adresa primului element al tabloului.
Adresa returnată de comanda new trebuie reţinută într-un pointer
adecvat.
Dacă sistemul de operare nu găseşte spaţiul de memorie necesar,
operatorul new returnează pointerul nul.
Alocarea unei variabie simple si a
unui tablou
double *p; pentru un tablou dinamic cu n caractere:
p = new double; int n = 12;
*p = 13.13; char *q;
q = new char[n];
if (q == NULL)
{ cout << "nu mai este loc in memorie" << endl;
return 0;
}
q[0]= 'a';
q[1]= 'b';
alocarea şi dealocarea unei variabile simple
#include<iostream>
using namespace std;
Expresia delete p nu are ca efect ştergerea din memorie
int main(){
int *p; a variabilei p (ce ar însemna aceasta?), ci
p = new int; dealocarea zonei ţintite de p, ceea ce înseamnă că zona
*p = 1; de memorie respectivă este pusă la dispoziţia
cout << "p=" << p << endl; sistemului de operare care, în principiu, o poate aloca
cout << "*p=" << *p << endl; unui alt program care rulează concomitent cu al
delete p; nostru. Variabilele alocate dinamic sunt anonime, nu au
cout << "p=" << p << endl; un identificator asociat, nu au un nume
cout << "*p=" << *p << endl; propriu-zis.
p = new int;
Astfel, variabila alocată cu
*p = 6;
cout << "p=" << p << endl; int *p = new int;
cout << "*p=" << *p << endl; sau, echivalent, cu
delete p; int *p; p = new int;
return 0; se numește “ţinta lui p” , *p.
}
Alocarea unui vector cu un număr variabil de elemente
##include<iostream> int main(){ Se va afisa
100
using namespace std; int i, dim = 5; 200
int* aloca(int n) int* vector; 300
{ vector = aloca(dim); 400
500
int* p; for(i = 0; i < dim; i++) -572662307
p = new int[n]; cout << vector[i] << endl; -572662307
for(int i = 0; i < n; i++) dealoca(vector); -572662307
-572662307
p[i] = 100*(i+1); for(i = 0; i < dim; i++) -572662307
return p; cout << vector[i] << endl;
} return 0;
void dealoca(int* p) }
{
delete [] p;
}
Referirea prin pointeri a structuri
Referirea membrilor unei structuri se poate face si prin intermediul unui
pointer la variabila structura. In acest caz operatorul de referentiere este -
> (minus, mai mare)
• struct Complex {
    double real;
    double imag;
} z, *pz=&z;
// ...
pz->real=2.;
pz->imag=-3.;
cout<< z.real<<“ ”<<(*pz).imag);
• Expresiile pz->imag si (*pz).imag sunt echivalente (in exemplul de mai sus
referind ambele membrul z.imag).
Aocarea meorie pentru pz se poate face si dinamic.

S-ar putea să vă placă și