Sunteți pe pagina 1din 49

CURS 7

Pointeri

CUPRINS
1.
2.
3.

4.
5.
6.
7.
8.
9.
10.
11.
12.
13.

Noiuni introductive
Operatori specifici pentru pointeri
Operaii cu pointeri
Apelul prin adres utiliznd pointeri
Pointeri i referine
Indirectarea multipl
Pointeri constani i pointeri ctre constante
Tablouri i pointeri
Funcii pentru lucrul cu iruri de caractere
Pointeri spre funcii
Transferarea de argumente ctre funcia main( )
Alocarea dinamic a memoriei
Funcii pentru manipularea zonelor de memorie

1. NOIUNI INTRODUCTIVE

Tipul pointer (indicator) reprezint adresa unei


locaii de memorie

adresele sunt valori numerice ntregi fr semn

Tipuri de pointeri:
pointeri de date:

pointeri de funcii:

conin adresa codului executabil din funcii

pointeri de obiecte:

conin adresa unor variabile sau constante din


memorie

conin adresa unui obiect

pointeri generici sau pointeri void:

conin adresa unui obiect oarecare

NOIUNI INTRODUCTIVE

Pointerii de date se declar astfel:


tip *nume_pointer;
Pointerii generici se declar astfel:
void *nume_pointer;
Exemplu:
int *nptr;
float *a, rezultat;
int *tabptr[10];
void *pgen;

2. OPERATORI SPECIFICI PENTRU POINTERI

Operatorul & (adresare sau refereniere):


permite aflarea adresei unei variabile oarecare:
&nume_var
rezultatul este un pointer la tipul variabilei

Operatorul * (indirectare sau derefereniere):

se folosete pentru a afla ce se gsete la o adres:


*nume_pointer <-> ... la adresa nume_pointer ...

OPERATORI SPECIFICI PENTRU POINTERI

expresia *nume_pointer poate fi folosit att pentru a


obine valoarea obiectului ct i pentru a o modifica:
var = *nume_pointer ;
*nume_pointer = expr;

Orice variabil pointer trebuie definit cu o valoare


valid (0 sau NULL, nu e valid, deci cu adresa unei
date) nainte de a fi utilizat:
int *p;
...
*p = 10; // eroare, pentru ca lui p nu i s-a asignat o
valoare
6

OPERATORI SPECIFICI PENTRU POINTERI

Exemplu:
void main(void)
{
int i=10, *ptri;
ptri = &i;
printf("Valoare var : %d \nLa adresa var : %d" , i, *ptri);
*ptri = 20;
printf("Valoare var : %d \nLa adresa var : %d" , i, *ptri);

OPERATORI SPECIFICI PENTRU POINTERI

In C/C++ se permite ca orice tip de pointer s pointeze


oriunde n memorie, tipul pointerului determinnd
modul n care va fi tratat obiectul pointat:
Un pointer de un anumit tip nu va fi folosit s pointeze
o dat de alt tip:
int q;
double *dp;
dp = &q;
*dp = 20.5;//voi scrie 8 octei

OPERATORI SPECIFICI PENTRU POINTERI

sau
int *p;
double q, temp;
temp=20.5;
p=&temp;
q=*p;
//iau doar cat e specific unui int
printf (\nprin pointer int luat de la un
double: %lf,q);

OPERATORI SPECIFICI PENTRU POINTERI

Pointerii generici (void *) nu sunt asociai unui anumit


tip de date:
dimensiunea zonei de memorie adresate i
interpretarea datelor din acea zon nu sunt definite
Aceti pointeri pot fi utilizai cu mai multe tipuri de
date, ns numai cu operatorul de conversie explicit
(cast):

10

OPERATORI SPECIFICI PENTRU POINTERI

int x;
float y;
void *p;
...
p=&x;
// lui p i se atribuie adresa de memorie
unde pot fi intregi
*(int*)p = 10;
p=&y;

// lui p i se atribuie adresa de memorie


unde pot fi flotanti
*(float *)p = 20.5;
11

OPERATORI SPECIFICI PENTRU POINTERI

Operatorul cast poate modifica semnificaia pointerilor:


int *pi;
float *pf;
...
*((char*)pf) -> primul octet al unei variabile de tip float
*((char*)pf+1) -> al doilea octet al unei variabile de tip float

Construcia (char*) este folosit pentru accesul pe octet la


zone de memorie de mrimi diferite

12

3. OPERAII CU POINTERI

Cu ajutorul pointerilor se pot efectua operaii de:


atribuire
comparare
adunare
scdere
incrementare
decrementare
In operaii se ine cont de faptul c adresele care
reprezint pointerii au valori numerice ntregi fr
semn
13

OPERAII CU POINTERI

Atribuirea

Dac:
tip1 *id_ptr1;
tip2 *id_ptr2;
id_ptr1 = id_ptr2;

Avem urmtoarele cazuri:


tip1 este void, atunci tip2 poate fi oarecare
tip2 este void, atunci tip1 poate fi oarecare (la
asignare se foloseste cast)
tip1 si tip2 sunt identice, atribuirea este corect
tip1 si tip2 difer, atunci compilatorul genereaz
14
un avertisment sau o eroare

OPERAII CU POINTERI

#include <iostream>
using namespace std;
#include <conio.h>
void main(){
void *pg;
int *pi;
double *pd;
int nota=10;
double media=9.97;
pi=&nota;
pg=pi;
15
cout <<"\nNota prin pointer generic e:"<<*(int*)pg<<endl;//10

OPERAII CU POINTERI

pd=&media;
pg=pd;
cout <<"\nMedia prin pointer generic
e:"<<*(double*)pg<<endl;//9.97
pi=(int*)pg;
cout <<"\nMedia prin pointer intreg e:"<<*pi<<endl;
//valoarea nu e corecta:-687194767
pd=(double*)pg;
cout <<"\nMedia prin pointer double
e:"<<*pd<<endl;//valoarea e corecta:9.97
getch();
}

16

OPERAII CU POINTERI

Compararea a doi pointeri

Se face cu operatorii relaionali, dar numai n cazul


n care pointerii pointeaz pe obiecte de acelai
tip

Exemplu:
int *p1, *p2, i, j;
...
p1=&i;
p2=&j;
if (p1 < p2)
printf ("p1= %n p2 = %n\n", p1, p2);
17

OPERAII CU POINTERI

Operatorii == i != pot fi folosii pentru a compara


pointeri cu o constant special NULL definit de
obicei n stdio.h prin:
#define NULL 0

Pentru un pointer generic (void *p) se pot face


comparaiile:
p == NULL i p != NULL

In C++ este recomandabil a folosi:


if (p == 0)
<=>
if (!p)
if (p != 0)
<=>
if (p)
18

OPERAII CU POINTERI

Adunare, scdere i incrementare, decrementare

Pot fi adugate sau sczute doar cantiti ntregi


Operaiile se efectueaz relativ la tipul pointerului
(int, float, char, etc.)
Fie declaraia:
Operaiile:

tip *id_ptr;
id_ptr + n, id_ptr - n

corespund adugrii/scderii la adresa obinut n


cadrul variabilei id_ptr a valorii: n * sizeof(tip)
19

OPERAII CU POINTERI

Analog se efectueaz i operaiile de


incrementare/decrementare doar c n este= 1/-1

Rezultatul este corect doar atunci cnd pointerul


adreseaz un tablou i prin opearatia aritmetic
se produce o deplasare n interiorul limitelor
tabloului

20

OPERAII CU POINTERI

Exemplu:
float *fp1, *fp2, tf[10];
// sizeof (float) = 4
double *dp, td[10[;
// sizeof (double) = 8
...
fp1 = &tf[0];
//tf
dp = &td[9];
// adresa celui de-al 10-lea element
fp2 = fp1+5;
dp = dp-2;
fp1++;
dp--;

// fp2 va contine : adresa lui tf + 5*4


// dp va contine : adresa lui dp - 2*8
// fp1 va contine : adresa lui fp1 + 1*4
// dp va contine : adresa lui dp - 1*8

21

OPERAII CU POINTERI

Operaia de incrementare/decrementare se poate aplica:


asupra pointerului nsui
asupra obiectului pe care l pointeaz

Dac se folosete varianta:


int *p, q=17, v;
p=&q;
v=*p++;
// nti se aplica * i apoi ++ asupra
pointerului

Dac se folosete varianta:


v = (*p)++;

// se obine nti coninutul de la adresa p


// care apoi se incrementeaz cu 1

22

OPERAII CU POINTERI
. (programul de la slide-ul 15)

res=(*pd)++;
cout <<"\nMedia prin res e:"<<res<<endl;
//valoarea e corecta:9.97
//dupa, *pd se va incrementa ca si valoare double
cout<<"\nAdresa pd e = "<<pd<<endl;//0077FC08
res=*pd++;//res incrementat anterior:10.97, adresa se
va incrementa
cout <<"\nMedia prin res incrementata
e:"<<res<<endl;//valoarea e corecta:10.97
cout<<"\nAdresa pd incrementata e =
"<<pd<<endl;//0077FC10

23

OPERAII CU POINTERI

#include <iostream>
using namespace std;
#include <conio.h>
void main(){
int l=1, j=5,k, *p;
p=&l;
*p=2;//modific l, operatie asupra continut
cout << "\nl= "<< l << " j= " << j << " Pointer adresa lui l (e p) = "
<< p << " Adresa lui j = " << &j << endl;
k=*(p=&j)++;
//modific in final pointerul p de la adresa lui j
cout << "\nk (j)= "<< k << " Valoarea lui j = " << j << " Adresa lui
j = " << &j << " Adresa lui p (oper. pointer) = " << p<<endl;
24

OPERAII CU POINTERI
p=&l;
cout << "*p=l = " <<l <<" adresa data de p e: " << p << endl;
k=(*p)++;
//oper continut
cout << "k=l = " <<k <<" adresa data de p e aceiasi: " << p
<< endl;
cout <<"l se va incrementa: " <<l << endl;
k=*p++;
cout << "k=l = " <<k <<" adresa data de p e: (incrementata)
" << p << endl;
const int const kk=7;
int k_var= *(int*)&kk;
k_var++;
cout <<"\n const kk = " << kk <<" k_var = " << k_var;
getch(); }//main
25

26

OPERAII CU POINTERI

Scderea a doi pointeri


Este permis numai pentru pointeri de acelai
tip ce refer un tablou, rezultatul fiind o valoare
care reprezint diferena de adrese divizat la
dimensiunea tipului de baz
Adunarea pointerilor nu este permis !
Exemplu:
float l,ft[9];
float *p1=&ft[4], *p2=&ft[2];
...
l = p2-p1; // l = (adresa p2- adresa p1)/4

Datorit rolului tipului la adunare i scdere,


operanzii nu pot fi pointeri void sau pointeri spre
funcii

27

4. APELUL PRIN ADRES UTILIZND


POINTERI

Transferul parametrilor prin valoare (implicit):


const n ncrcarea valorii parametrilor efectivi n zona
de memorie a parametrilor formali
dac parametrul efectiv este o variabil, orice operaie
efectuat n funcie asupra parametrului formal nu
afecteaz variabila
spunem c se lucreaz cu copii ale parametrilor efectivi

Dac vrem ca o funcie s modifice o variabil


parametru efectiv, atunci trebuie s transmitem
funciei, la apel, adresa variabilei:
ca i parametri formali se pot folosi pointeri unde se
vor copia aceste adrese

28

APELUL PRIN ADRES UTILIZND POINTERI


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

void schimba2(int *a, int *b)


{
int temp;
temp=*a;
*a=*b;
*b=temp;
}

Apel:

Apelul:
schimba1(x, y);

schimba2(&x, &y);

29

APELUL PRIN ADRES UTILIZND POINTERI

Dac la apelul unei funcii se folosete ca i argument


un tablou, funcia va primi doar adresa acelui tablou,
adic adresa primului element din tablou

Variante:

parametrul formal este declarat ca un tablou fr


dimensiune
int cauta(int p[ ], int n, int x );

parametrul formal este declarat ca un pointer ctre


tipul tabloului, argumentul folosit ca i parametru
efectiv fiind adresa tabloului asupra cruia se fac
operaii n funcie
int cauta(int *p, int n, int x );
30

APELUL PRIN ADRES UTILIZND POINTERI


// cautare pe un tablou
int cauta(int *p, int n, int x );

int cauta(int *p, int n, int x)


{
int i;
for(i=0; i<n; i++)
{
if(x == p[i])
return i;
}
return 1;
}
Apel: cauta(tab, MAX, val);

31

5. POINTERI I REFERINE

Referinele, ca i pointerii, conin adrese de memorie


Se declar cu ajutorul operatorului de adresare ("&) i
se iniializeaz obligatoriu la inceput cu o adres
(a unei variabile sau a unei constante), fiind un alias al
ei:
int i;
int &r = i; //alias

32

POINTERI I REFERINE

Accesul la o variabil prin intermediul unei referine se


face simplu fr a mai folosi operatorul de indirectare ca
n cazul pointerilor:
int i;
int *p;
...
p = &i;
*p = 100; // i = 100

int i;
int &r = i;

r = 1000; // i = 1000

33

POINTERI I REFERINE

Diferene ntre pointeri i referine:


dup modul de declarare:
* pentru pointeri
& pentru referine

dup modul de utilizare:


pointerii:
se asociaz unei variabile cu operatorul &, pentru
accesul la valoare se utilizeaz operatorul *
pot fi asociai mai multor variabile la momente diferite
de timp i deci pot conine adrese diferite
referinele:
se asociaz unei variabile i numai uneia la definire
conin tot timpul adresa aceleiai variabile fiind de fapt
o redenumire (alias) a variabilei
34
li se asociaz valori pe baza unei atribuiri simple

POINTERI I REFERINE

Restricii:
nu sunt permise referine la referine, pointeri la
referine, referine la cmpuri de bii, tablouri de
referine, dar putem avea referine la pointeri
o referin nu poate avea valoarea NULL
o referin nu poate fi asociat unei alte variabile
Utilizare:
se folosesc rar variabile referine simple
uzual se folosesc la transmiterea parametrilor prin
referin, caz n care indirectarea este ascuns i nu
este necesar dereferenierea n funcie (utilizarea
operatorului *)
35

POINTERI I REFERINE

// varianta cu pointeri
void schimba2(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}

apelul :
schimba2(&i, &j);

// varianta cu referine
void schimba3(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}

apelul :
schimba3(i, j);

36

POINTERI I REFERINE

Rezultatul unei funcii se poate transfera prin referin


astfel:
int& func(...)
{
static int var;
...
return (&var);
}
Trebuie evitat returnarea adresei (prin pointer sau
referin) unui obiect automatic, obiect care se distruge
la ieirea din funcie
37

6. INDIRECTAREA MULTIPL

Cnd un pointer pointeaz alt pointer avem un proces


de indirectare multipl:
Pointer ctre pointer -----> Pointer -----> Obiect

Primul pointer conine adresa celui de-al doilea


pointer, pointer care pointeaz locaia care va conine
obiectul,...
Declararea se face utiliznd un asterisc suplimentar n
faa numelui pointerului:

char **pm, *p, ch;


...
p = &ch;
pm = &p;
**pm = 'A';
// lui ch i s-a asignat valoarea A
prin 2 pointeri

38

7. POINTERI CONSTANI I POINTERI


CTRE CONSTANTE

Exist pointeri ctre constante i pointeri constani


(care nu pot fi modificai):
pointeri ctre constante
const char *str1 = "pointer catre constanta";
//str1[0] = 'P';
str1 = "ptr la const";

// incorect
// ok

pointeri constani
char *const str2 = "pointer constant ";
//str2 = "ptr const";
str2[0] = 'P';

// incorect
// ok
39

POINTERI CONSTANI I POINTERI CTRE CONSTANTE

pointeri constani ctre constante

const char *const str3 = "pointer constant la constanta";


//str3 = "ptr const la const";
// incorect
//str3[0] = 'C';
// incorect

un pointer poate, indirect, modifica totui o


variabil declarat cu modificatorul const astfel:
*(tip *)&var;

int const kk=7;//const int const kk=7;


int k_var= *(int*)&kk; // val lui kk se depune in k_var
cout <<"\n const kk = " << kk <<" k_var = " << k_var+1; 40

POINTERI CONSTANI I POINTERI CTRE CONSTANTE

O funcie care are ca parametri formali pointeri, dar


nu are voie s modifice datele pointate de parametru
efectiv arat astfel:
void cifru(const char *src, char *dest)
{
while(*src)
{
*dest = *src + 5;
dest++;
src++;
}
}

41

ALTE CONSIDERAII REFERITOARE LA POINTERI

In limbajul C/C++ se folosesc des funcii care


returneaz pointeri
Exemplu:
char *strcpy(char *dest, const char *src);
Astfel de funcii se mai folosesc i pentru alocarea
dinamic a memoriei, prelucrarea listelor, arborilor, ...

42

Exemplul 1:
#include <stdio.h>
void main(void)
{
int n, *pn;
float r, *pr;

printf("\nIntroduceti un numar intreg: ");


scanf("%d", &n);
pn = &n;
printf("\nReprezentarea in memorie a lui %d este:
0x%02x%02x%02x%02x\n", n,
*((unsigned char *)pn+3),
*((unsigned char *)pn+2),
*((unsigned char *)pn+1),
*((unsigned char *)pn));
43

printf("\nIntroduceti un numar real: ");


scanf("%f", &r);
pr = &r;
printf("\nReprezentarea in memorie a lui %f este:
0x%02x%02x%02x%02x\n", r,
*((unsigned char *)pr+3),
*((unsigned char *)pr+2),
*((unsigned char *)pr+1),
*((unsigned char *)pr));
}

44

Exemplul 2:
#include <stdio.h>

void schimba1(int a, int b);


void schimba2(int *a, int *b);
void schimba3(int &a, int &b);
void main(void)
{
int x, y;
int *px, *py;
int &rx=x, &ry=y;
printf("\nIntroduceti valoarea lui x: ");
scanf("%d", &x);
printf("\nIntroduceti valoarea lui y: ");
scanf("%d", &y);
45

schimba1(x, y);
printf("\nNoile valori sunt: x = %d, y = %d", x, y);
schimba2(&x, &y);
printf("\nNoile valori sunt: x = %d, y = %d", x, y);
schimba3(x, y);
printf("\nNoile valori sunt: x = %d, y = %d\n", x, y);
}

46

void schimba1(int a, int b){


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

void schimba3(int &a, int &b){


int temp;
temp = a;
a = b;
b = temp;
}

47

Exemplul 3:
#include <stdio.h>
#include <conio.h>
void main(void){
int n, *p;
int tab[ ] = {1, 3, 5, 7, 9};
n = sizeof(tab)/sizeof(int);

p = &tab[0];
printf("\nElementele tabloului cu ++ de la inceput sunt: ");
for(int i=0; i<n; i++)
printf("\t%d", *p++);
p = &tab[n-1];
printf("\nElementele tabloului cu -- de la sfarsit sunt: ");
for(int i=0; i<n; i++)
printf("\t%d", *p--);

48

p = &tab[0];
printf("\nElementele tabloului de la inceput sunt: ");
for(int i=0; i<n; i++)
printf("\t%d", *(p+i));
p = &tab[n-1];
printf("\nElementele tabloului de la sfarsit sunt: ");
for(int i=0; i<n; i++)
printf("\t%d", *(p-i));
int *p1, *p2;
p1 = &tab[0]; p2 = p;
printf("\n\nDistanta intre ultimul si primul element: %d\n", p2-p1);
printf("\n\nCompararea pointerilor: ");
for(int i=0; i<n; i++){
if(p1 == p2)
printf("\n\tPentru i=%d, pointerii indica acelasi element\n", i);
p1++;
p2--;
}
49
getch();
}

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