Documente Academic
Documente Profesional
Documente Cultură
Cuprins
Tipul pointer (continuare)
Tablouri și pointeri
Aritmetica pointerilor
Alocare dinamica a memoriei
Pointeri la funcții
Bibliografie selectivă
Tipul pointer
Să ne amintim:
Orice variabilă are o adresă, la care se memorează valoarea ei.
Operatorul prefix & dă adresa operandului: &x e adresa variabilei x.
În cazul tablourilor, numele unui tablou este chiar adresa sa.
Tipul pointer
O adresă poate fi tipărită (în #include <stdio.h>
hexazecimal – baza 16) int main( void )
folosind formatul %p în {
apelul funcției printf: double d ; int a [ 6 ] ;
printf ("Adresa lu i d : %p\n" , &d ); // folosim operatorul &
printf ("Adresa lu i a : %p\n" , a ); // a e deja adresa , nu e nevoie de &
return 0;
}
Tipul pointer
Orice variabilă x are o adresă &x, unde se memorează valoarea ei.
Fiind o expresie &x are un tip: tipul pointer
Pentru o variabilă declarată:
Nume_tip x;
Adresa &x are tipul nume_tip * = pointer la nume_tip, adresa unui obiect de tip nume_tip
Tipul pointer
Numele unui tablou are tipul pointer la tipul elementelor:
int a[4]; ⇒ a are tipul int *
char s[8]; ⇒ s are tipul char *
Tipul unei constante șir de caractere ”sir” este char * = adresa unde se găsește
șirul în memorie
Valoarea specială NULL e folosită pentru a indica o adresă invalidă.
Tipul pointer
Pointer = o variabilă care conține adresa altei variabile.
Declararea unei variabile de tip pointer:
Nume_tip *nume_variabila
= nume_variabila e pointer la o valoare de tip nume_tip
= nume_valiabila conține adresa unei valori de tip nume_tip
int x; //variabila de tip int
int *p; //variabila pointer la int
p=&x; //lui p i se atribuie adresa lui x
Tipul pointer
Dereferențierea unui pointer
Operatorul de dereferențiere *
◦ Operator prefix: *nume_pointer
◦ Operand: pointer
◦ Rezultat: valoarea de la adresa conținută de pointer
Observație: dacă p este un pointer, *p este lvalue (locator value) - i se pot atribui valori
Operatorul * este inversul operatorului &
int x,*p;
*&x este chiar x (valoarea de la adresa lui x)
&*p este p (adresa valorii de la adresa p)
Tipul pointer #include <stdio.h>
#include <string.h>
O funcție care primește adresa unei /*functia calculeaza atat suma cat si diferenta a doua numere*/
variabile îi poate citi și modifica void sum_dif(int a, int b, int *sum, int *dif)
valoarea memorată. {
*sum = a + b;
Obs: În cazul parametrilor de tip *dif = a - b;
pointer valoarea transmisă este o }
adresă (adresa nu se modifică!) int main() {
int s, d;
Folosim parametri de tip pointer:
sum_dif(5, 3, &s, &d);
◦ când ne obligă limbajul (tablouri ca printf("5+3=%d\n5-3=%d\n", s, d);
parametri la funcții) return 0;
◦ când dorim să întoarcem mai multe }
rezultate (folosind return putem
întoarce doar un rezultat)
Tipul pointer #include <stdio.h>
#include <string.h>
Schimbarea valorilor de la două adrese: // schimba valorile de la 2 adrese
void swap(int * pa, int * pb)
{
int tmp; // variabila temporara
tmp = *pa;
*pa = *pb;
*pb = tmp;
}
int main()
{
int a = 5, b = 3;
Urmăriți cu ajutorul depanatorului de programe (debugger) swap(&a, &b);
modificarea valorilor variabilelor a și b! printf("a=%d,b=%d", a, b);
return 0;
}
Tablouri și pointeri
În C numele unui tablou este un pointer (adresa blocului de elemente/a primului element).
Dacă declarăm Diferența:
tip a[LEN], *pa;
Adresa a este o constantă, pa este o variabilă
Putem atribui pa=a;
&a[0] a iar a[0] *a Nu putem atribui a=adresă, dar putem atribui pa=adresă
... 5C0
Adresa(hex) 5C0
Tablouri și pointeri
Ca parametri la funcții, următoarele două scrieri înseamnă același lucru:
size_t strlen(char s[]); sau size_t strlen(char *s);
Totuși între tablouri și pointeri există unele diferențe:
char s [ ] = ”test” ; // adresa constanta
int main()
{
printf("%s\n", final("Programare"));
return 0;
}
Aritmetica pointerilor
Operația de scădere:
Se poate calcula doar diferența între doi pointeri de același tip
tip *p, *q;
p-q = numărul de valori de tip tip care încap între cele două adrese
Pentru a se obține diferența numerică în octeți:
a[0] a[1] a[2] a[3]
a
Se pot converti ambii pointeri la char *
sau se înmulțește rezultatul cu sizeof(tip) ...
Următoarele operații sunt echivalente:
p - q ((char *)p - (char *)q) / sizeof(tip) Adresa(hex) 5C0
Aritmetica pointerilor
Atenție: Nu sunt definite alte operații aritmetice pentru pointeri!
Dar se pot efectua operații logice de comparație (cu operatorii relaționali ==, !=, <, etc.)
Aritmetica pointerilor
PARCURGERE TABLOU FOLOSIND INDICI PARCURGERE TABLOU FOLOSIND POINTERI
Să ne amintim:
Organizarea memoriei unui program. …
Heap
Segmentul de date
Segmentul de cod
Zona rezervată
Segmentul de date
Segmentul de cod
Alocarea dinamică a memoriei
Funcțiile de alocare dinamică a memoriei (declarate în stdlib.h) ne permit să creăm variabile noi
de dimensiunile necesare, la rularea programului:
void *malloc (size_t size); - alocă size octeți de memorie
void *calloc (size_t num, size_t size); - allocă num x size octeți și îi inițializează cu 0
void *realloc(void*ptr, size_t size); - modifică la size dimensiunea unei zone
alocate cu c/malloc, mută blocul de
memorie dacă este necesar
Alocarea dinamică a memoriei
Funcțiile m/c/realloc returnează:
◦ adresa de început a blocului unde a fost alocat numărul de octeți cerut, dacă alocarea de
memorie a fost posibilă
◦ NULL în caz de eroare (memorie insuficientă).
Trebuie testat rezultatul returnat (!= NULL).
Memoria alocată dinamic trebuie eliberată când nu mai este necesară, folosim
tot o funcție din stdlib.h
void free(void *ptr);
Alocarea dinamică a memoriei
Citirea elementelor unui tablou a cărui
dimensiune o citim de la tastatură. int i, n, *t;
printf("Dati numarul de elemente ");
scanf("%d", &n);
t = (int*)malloc(n*sizeof(int));
//alocam spatiu pentru n elemente de tip int
if (t != NULL)
{
//daca alocarea memoriei nu a dat eroare
printf("Dati %d elemente\n",n);
//citim elementele tabloului
for ( i = 0; i < n; i++)
scanf("%d", &t[i]);
}
Alocarea dinamică a memoriei
Exemple de utilizare greșită a adresei unei variabile.
// Vector cu cifrele unui nr intreg
NU se poate returna adresa unei variabile locale! int * cifre(int n) {
De ce? int k, c[5]; // Vector local
for (k = 4; k >= 0; k--)
O variabila locală este stocată pe stivă și are o {
existenţă temporară, garantată numai pe durata c[k] = n % 10;
execuţiei funcţiei în care este definită (cu excepţia n = n / 10;
variabilelor locale statice) }
return c; // Aici este eroarea !
Una din soluții, în acest caz, este tot utilizarea }
alocării dinamice
#include <stdio.h>
Alocarea dinamică #include <string.h>
#include <stdlib.h>
a memoriei char * strd(const char * s) {
// creeaza o copie a lui s
char *d = (char *)malloc(strlen(s) + 1);
Alocarea dinamică a memoriei pentru un obiect // loc pentru sir si ’\0’
în funcție. if(d != NULL){ // alocare ok
// face copia , returneaza d
strcpy(d, s);
return d;
} else // eroare la alocare
return NULL;
}
int main()
{
char *s="Program",*d;
d = strd(s);
printf("%s\n", d);
return 0;
}
#include <stdio.h>
Alocarea dinamică #include <stdlib.h>
int* creare_tablou(int *dimensiune)
a memoriei {
int i, n, *t;
void afisare_tablou(int *t, int n) printf("Dati numarul de elemente ");
Un exemplu mai complex: scanf("%d", &n);
{ //afisarea tabloului folosind o parcurgere cu pointeri
int *p,i; t = (int*)malloc(n*sizeof(int));
p=t; //alocam spatiu pentru n elemente de tip int
for (i=0;i<n;i++) if (t != NULL)
{ {
printf("Valoarea %d la adresa %p\n",*(p),p); //daca alocarea memoriei nu a dat eroare
p++; printf("Dati %d elemente\n",n);
} //citim elementele tabloului
} for ( i = 0; i < n; i++)
int main() scanf("%d", &t[i]);
{ }
int *tab, n; *dimensiune=n;
tab=creare_tablou(&n); //valoarea dimensiunii citite in functie
afisare_tablou(tab,n); //se va transmite in afara functiei
free(tab); //prin intermediul parametrului int*
return 0; return t;
} }
Pointeri la funcții
Uneori dorim să variem funcția apelată într-un punct de program.
Exemplu:
parcurgerea unui tablou pentru diverse prelucrări:
for (int i = 0; i < len; ++i)
f(tab[i]); //(cu diverse funcții f)