Sunteți pe pagina 1din 31

Curs 02

RECAPITULARE (CONT.)
Pointeri, masive, transmiterea parametrilor
Pointerii

● Variabile responsabile cu salvarea unor adrese de memorie


● De cele mai multe ori sunt salvați în stack și pointează către zone din heap
(acesta este cel mai întâlnit scenariu, dar nu înseamnă că nu pot pointa către
zone din stack sau că nu pot fi definiți în heap)
● Ocupă 4 bytes indiferent de tipul de pointer (ce se regăsește la adresa de
memorie către care pointează) pentru un procesor/compilator pe 32 de biți

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Definire

//la definire de obicei valoarea este una arbitrara


//nu este recomandat ca un pointer sa ramana neinitializat
tip_data* nume_pointer;

tip_data* nume_pointer = nullptr;

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Inițializare

//pointerul poate salva doar adrese unde se gaseste


//tipul de data specificat
//operatorul & extrage adresa de memorie a unei variabile
tip_data nume_variabila = valoare;
tip_data* nume_pointer = &nume_variabila;

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Utilizare

//va afisa o adresa de memorie


cout << nume_pointer;

//va afisa continutul de la acea adresa de memorie


cout << *nume_pointer;

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Operații cu pointeri

● Definire
● Inițializare
● Dereferențiere
● Incrementare/decrementare
● Diferența a doi pointeri

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Incrementare/decrementare

int* nume_pointer = nullptr;


nume_pointer++;
//ce va afisa?
cout << nume_pointer;
//dar acum?
nume_pointer--;
cout << nume_pointer;

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Incrementare/decrementare

● Incrementarea unui pointer de tip T* va duce la mărirea adresei cu sizeof(T) sau,


cu alte cuvinte, deplasarea în memorie înainte către adresa următoarei variabile
de tip T
● Decrementarea unui pointer de tip T* va duce la scăderea adresei cu sizeof(T)
sau, cu alte cuvinte, deplasarea în memorie înapoi către adresa precedentei
variabile de tip T

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Caz particular: adunarea unui întreg

● Cum expresia variabilă++ este echivalentă cu variabilă = variabilă + 1, deducem că


putem aduna sau scădea orice întreg la/dintr-un pointer
● Deci expresia:

nume_pointer = nume_pointer + 3;

● Va duce la incrementarea adresei salvate în nume_pointer cu 3 * sizeof(T), unde T


este tipul de dată utilizat la definire

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Scăderea a doi pointeri
● Așa cum am văzut expresia de mai jos este una validă

nume_pointer2 = nume_pointer + 3;

● Asta înseamnă că și expresia de mai jos este una validă

nume_pointer2 - nume_pointer = 3;

● Deci scăderea a doi pointeri este posibilă, iar rezultatul este diferența efectivă
dintre adrese împărțită la sizeof(T) sau, cu alte cuvinte, câte variabile de tip T
încap între cei doi pointeri
© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Atenție!

Adunarea a doi pointeri nu este posibilă pentru că nu ar avea sens


(suma a două adrese nu este neapărat o adresă validă)!

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Identificatorul const în cazul pointerilor

● Pointerii făcând referire la adresa unei variabile există 3 situații posibile de folosire
a identificatorului const:
○ pointeri constanți: odată salvată o adresă, nu mai poate fi modificată

○ pointeri la o zonă de memorie constantă: valoarea de la adresa către care pointează nu


poate fi modificată prin intermediul lor
○ pointeri constanți la o zonă de memorie constantă: combinație între cele două situații
de mai sus

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Identificatorul const în cazul pointerilor
int x = 5; int y = 10;

//Pointer constant la intreg


int* const p = &x;
//adresa catre care pointeaza nu poate fi schimbata
//p = &y;

//Pointer la o zona de memorie constanta (pointer la int constant)


const int* q = &x;
//valoarea lui x nu poate fi modificat prin intermediul lui q
//*q = 4;

//Pointer constant la o zona de memorie constanta


const int* const w = &x;
//nu se poate schimba nici adresa, nici valoarea

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Vectorii

● Tipuri de date ce folosesc o zonă de memorie contiguă pentru a salva mai multe
valori de același tip
● Pot fi alocați static sau dinamic
● Cei alocați static sunt salvați în stack și trebuie să aibă un număr de elemente
cunoscut în momentul compilării
● Cei alocați dinamic se alocă și se dezalocă în heap și pot avea un număr de
elemente cunoscut la momentul execuției

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Definire

int array1[5];
float array2[4];

int* array3 = (int*)malloc(5 * sizeof(int));


float* array4 = new float[4];
free(array3); delete[] array4;

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Matricele

● Masive bidimensionale ce permit accesul elementelor pe linii și coloane


● Memoria fiind liniară (unidimensională) pentru a putea fi salvate sunt liniarizate
● Cele alocate static sunt salvate în memorie ca vectori consecutivi ce conțin
elementele de pe fiecare linie
● Cele alocate dinamic sunt salvate ca vectori de vectori (un vector ce conține
adresele de memorie ale fiecărui vector corespunzător fiecărei linii)

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Definire

//matrice alocata static de 3 linii si 4 coloane


int matrice[3][4];

//matrice alocata dinamic de 3 linii si 4 coloane


int** m = (int**) malloc(3 * sizeof(int*));
for(int i=0; i<3; i++)
{
m[i] = (int*) malloc(4 * sizeof(int));
}

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Dezalocare

for(int i=0; i<3; i++)


{
free(m[i]);
}
free(m);

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Definire cu și dezalocare cu new și delete

int** m = new int*[3];


for(int i=0; i<3; i++)
{
m[i] = new int[4];
}
//...
for(int i=0; i<3; i++)
{
delete[] m[i];
}
delete[] m;

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Legătura dintre pointeri și operatorul []

● Operatorul [] se folosește de aritmetica pointerilor pentru a accesa elementele


dintr-un masiv
● Așadar:
○ vector[i] ⇔ *(vector + i)

○ matrice[i][j] ⇔ *(*(matrice + i) + j)

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Vectorii de caractere

● În limbajul C nu există un tip de dată special definit pentru șiruri de caractere


● Pentru a salva totuși astfel de șiruri se folosește o convenție: se utilizează un
vector de caractere (vector de char) ce are drept ultim element ‘\0’ (cod ASCII 0)
pentru a ști când vectorul de caractere se sfârșește
● Vectorii de caractere pot fi prelucrați ca orice alt vector sau, profitând de faptul că
putem ști când ajungem la ultimul element, prin utilizarea de funcții specifice

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Utilizare vectori de caractere

char sir[20];
char* sir_dinamic = new char[10];

strlen(sir); //returneaza numarul de caractere al sirului (fara a numara \0)


strcpy(sir, "ceva"); //copiaza sirul din dreapta in variabila din stanga
strcpy_s(sir, 5, "ceva"); //varianta safe
strcmp(sir, sir_dinamic); //compara doua siruri de caractere si returneaza -1, 0 sau 1
strcat(sir, sir_dinamic); //concateneaza sir_dinamic la sfarsitul lui sir
strcat_s(sir, sir_dinamic); //varianta safe
//...
delete[] sir_dinamic;

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Tipul string

● În limbajul C++ avem tip de dată special definit pentru șiruri de caractere - string
● string este o clasă în C++ (vom descoperi în curând ce este o clasă) așadar
prelucrările se fac în mod direct prin operatori sau metode (descoperim și ce
este o metodă mai târziu 😃)

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Tipul string

string sir1;
string sir2 = "ceva";

sir2.length(); //returneaza numarul de caractere al sirului (fara a numara \0)


sir1 = sir2; //copiaza sirul din dreapta in variabila din stanga
(sir1 == sir2) ? 1 : 0; //compararea a doua stringuri
sir1 + sir2; //concatenarea a doua stringuri

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Transmiterea parametrilor

● În mod implicit parametrii sunt transmiși prin valoare în funcții


● Asta înseamnă că aceștia se copiază în variabile locale ce sunt dezalocate la
ieșirea din funcție
● În C++ mai există două modalități adiționale de a transmite parametri:
○ prin adresă (pointer)

○ prin referință (doar în C++, nu și în C)

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Transmiterea parametrilor prin valoare

void suma(int a, int b) {


a = a + b;
}

int main() {
int x = 5;
int y = 3;
suma(x, y);
cout << x;
}

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Transmiterea parametrilor prin adresă

void suma(int* a, int b) {


(*a) = (*a) + b;
}

int main() {
int x = 5;
int y = 3;
suma(&x, y);
cout << x;
}

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Transmiterea parametrilor prin referință

void suma(int& a, int b) {


a = a + b;
}

int main() {
int x = 5;
int y = 3;
suma(x, y);
cout << x;
}

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Pointeri la funcții

● Atât în C, cât și în C++ putem utiliza pointeri care salvează adresa de memorie a
unor funcții
● Aceștia implementează o formă incipientă de polimorfism (un pointer la funcție
poate face diferite tipuri de prelucrări prin schimbarea adresei către care
pointează)

tip_returnat (* nume_pointer) (parametri);

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Exemplu

long (*pf)(int, int); //definire pointer la o functie ce returneaza long


//si are doi parametri de tip int

long suma(int a, int b) { return a + b; }


long diferenta(int a, int b} { return a-b; }
pf = suma;
pf(5, 3); //returneaza 8
pf = diferenta;
pf(5, 3); //returneaza 2

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.
Directive de preprocesare

#define NULL 0
#define BEGIN {
#define END }
//...
#undef NULL
//...
#if, #elif, #else, #endif, s.a.

© 2020-2023 Bogdan Iancu. Reproducere integrală sau parțială a acestor materiale fără acordul autorului este strict interzisă.

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