Documente Academic
Documente Profesional
Documente Cultură
Marius Minea
Pointeri: recapitulare
O variabil x de tipul tip are o adres &x de tipul tip * a a Variabila x ocup sizeof(x) (sau: sizeof(tip )) octeti pornind de la &x a Adresele sunt nenule. Valoarea NULL (adres 0) indic o adres invalid. a a a a tip t[5]; numele t e adresa tabloului (elem. [0]) i are tipul tip * In s Functiile au ca parametri nu continutul tabloului, ci adresa tabloului. void f(tip t[8]); e la fel ca void f(tip t[]) i ca void f(tip *t); s Functia care primete adresa unei variabile o poate modica (i citi). s s Ex: scanf (atribuie valori citite de la intrare), functii cu tablouri (modic continutul tabloului, dar nu adresa, transmis prin valoare!) a a O constant ir de caractere "sir" are tipul char * a s Valoarea constantei "sir" este adresa de memorie unde se a irul. a s ATENTIE Nu putem compara un char (a) cu un ir (adres) "a" ! s a Comparm iruri cu str(n)cmp, nu cu == (compar adrese, nu continut) a s a Pointerii sunt variabile normale: au tip, valoare, loc memorie, adres, n a pot declarati, atribuiti, tipriti, dati parametri, au operatii specice. a
Programarea calculatoarelor. Curs 9 Marius Minea
Pointer = o variabil care contine adresa altei variabile a Declararea pointerilor tip *nume var ; // nume var e pointer la o valoare de tip
Operatorul adres & a operator prex operand: o variabil (ex. x); rezultat: adresa variabilei a &x folosit doar pt. variabile (i elem. tablou), nu constante, expresii, etc. s se poate atribui unui pointer la acel tip: int x; int *p; p = &x; Operatorul de dereferentiere (indirectare) * operator prex operand: pointer; rezultat: obiectul (variabila) indicat de pointer *p e un lvalue, poate folosit la stnga unei atribuiri, ca i variabilele a s sau elem. tablou; (orice expresie poate la dreapta lui =) dac p e &x, atunci *p e obiectul de la adresa p (a lui x), deci x a int x, y, *p; p = &x; y = *p; /* y = x */ *p = y; // x = y Operatorul * e inversul lui &: *&x e chiar x (obiectul de la adresa lui x) &*p e p (p: pointer cu valoare valid): adresa obiectului de la adresa p a
Programarea calculatoarelor. Curs 9 Marius Minea
Declaratii i referinte s
Putem citi declaratia tip * p; tip * p; p are tipul tip * tip *p; *p e un caracter char **s; // adres de adr.de char a char *t[8]; // tab.de 8 adr.de char Valoare Adres a 5 0x408 ... int *p=&x; 0x408 0x51C ... int **pp=&p; 0x51C 0x9D0 ATENTIE O declaratie cu initializare NU este o atribuire ! int t[2] = { 3, 5 }; initializeaz t. NU are sens: t[2] = { 3, 5 }; a int x, *p = &x; este int x; int *p = &x; sau int x; int *p; p = &x; (e initializat/atribuit p, NU *p). *p = &x e incorect ca tip! char *p = "sir"; e char *p; p = "sir"; dar *p = "sir;" e greit! s * i & au precedenta mai ridicat dect operatorii aritmetici: s a a y = *px + 1; // cu 1 mai mult dec^t valoarea indicat de px */ a a dar *px++ d valoarea indicat de px, i incrementeaz pointerul px a a s a (nu valoarea), pentru c ++ i * se evalueaz de la dreapta la stnga ! a s a a
Programarea calculatoarelor. Curs 9 Marius Minea
Variabil a int x = 5;
Tablouri i pointeri s
limbajul C notiunile de pointer i nume de tablou sunt asemntoare. In s a a declararea unui tablou aloc un bloc de memorie pt. elementele sale a numele tabloului e adresa blocului respectiv (= a primului element) declarnd a tip a[LEN], *pa; putem atribui pa = a; &a[0] e echivalent cu a iar a[0] e echivalent cu *a Diferenta: adresa a e o constant (tabloul e alocat la o adres x) a a a nu putem atribui a = adres, dar putem atribui pa = adres a a pa e o variabil ocup spatiu de memorie i are o adres &pa a a s a
a a[0] a[1] a[2] a[3] a[4] a[5] R @ pa
R @
...
adresa (hex)
6
5C0 5E0
6
5C0
5D0
Aritmetica cu pointeri
O variabil v de un anumit tip ocup sizeof(tip) octeti a a &v + 1 reprezint adresa la care s-ar putea memora urmtoarea a a variabil de acelai tip (adresa cu sizeof(tip) mai mare dect &v). a s a 1. Adunarea unui ntreg la un pointer: poate parcurs un tablou a + i e echivalent cu &a[i] iar *(a + i) e echivalent cu a[i] char *endptr(char *s) { /* returneaz pointer la sf^ritul lui s */ a a s char *p = s; /* sau: char *p; p = s; */ while (*p) p++; /* adic la pozitia marcat cu \0 */ a a return p; } 2. Diferenta: doar ntre doi pointeri de acelai tip s tip *p, *q; = numrul (trunchiat) de obiecte de tip care a ncap ntre cele 2 adrese diferenta numeric octeti: se convertesc ambii pointeri la char * a n p - q == ((char *)p - (char *)q) / sizeof(tip) Nu sunt denite nici un fel de alte operatii aritmetice pentru pointeri ! Se pot a efectua operatii logice de comparatie (==, !=, <, etc.) ns
Programarea calculatoarelor. Curs 9 Marius Minea
Pointeri i indici s
10
Termenul pointer provine de la to point (to) (a indica) CAnd identicm un element de tablou a[i] folosim doua variabile: a tabloul i indicele, i implicit o adunare (indicele la adresa de baz) s s a Mai simplu: folosind direct un pointer la adresa elementului &a[i]==a+i la parcurgere, loc s avansm indicele, incrementm pointerul n a a a char *strchr_i(const char *s, int c) { // caut caracter n ir a ^ s for (int i = 0; s[i]; ++i) // parcurge s cu indice i p^n la \0 a a if (s[i] == c) return &s[i]; // s-a gsit: returneaz adreasa a a return NULL; // nu s-a gsit: returneaz NULL (adres invalid) a a a a } char *strchr_p(const char *s, int c) { // scris folosind pointer a for ( ;*s; ++s) // folosim chiar parametrul pentru parcurgere if (*s == c) return s; // s indic caracterul curent a return NULL; // nu s-a gsit a }
Programarea calculatoarelor. Curs 9 Marius Minea
11
Fie un tablou bidimensional (matrice) declarat tip a[DIM1][DIM2]; a[i] e adresa (constant tip *) a unui tablou (linii) de DIM2 elemente a a[i][j] e al j-lea element din tabloul de DIM2 elemente a[i] ; adresa &a[i][j] == a[i]+j e cu DIM2*i+j elemente dup adresa tabloului a a o functie cu parametri tablou trebuie s cunoasc toate dimensiunile a a afar de prima trebuie declarat n a a tip-f f(tip-t t[][DIM2]); char t[12][4]={"ian",...,"dec"}; i char *p[12]={"ian",...,"dec"}; s t e un tablou 2-D de caractere p e un tablou de pointeri i a n \0 0x460 i a n \0 f e b \0 0x5C4 f e b \0 ... ... 0x9FC d e c \0 d e c \0
t ocup 12 * 4 octeti a p ocup 12*sizeof(char *) octeti a (+ 12*4 octeti pt. constantele ir) s
12
Pe linia de comand, dup numele programului rulat, pot urma argua a mente (parametri): optiuni, nume de iere ... Exemple: s gcc -Wall -o prog prog.c ls director cp sier1 sier2 C, avem acces la linia de comand declarnd main cu 2 parametri: In a a int argc : nr. de cuvinte din linia de comand (nr. argumente + 1) a char *argv[] : tablou cu adresele argumentelor (iruri de caractere) s #include <stdio.h> int main(int argc, char *argv[]) { printf("Numele programului: %s\n", argv[0]); if (argc == 1) printf("Program apelat fr parametri\n"); a a else for (int i = 1; i < argc; i++) printf("Parametrul %d: %s\n", i, argv[i]); return 0; /* codul returnat de program */ } argv[0] (primul cuvnt) e numele programului, deci sigur argc >= 1 a tabloul argv[] e ncheiat cu un element NULL (argv[argc])
Programarea calculatoarelor. Curs 9 Marius Minea
13
Alocarea dinamic a
Folosim adrese pentru a lucra de fapt cu obiectele indicate prin adres a ATENTIE! declarnd un pointer tip *p avem loc doar pentru o adres, a a NU i pentru un obiect (variabil) de tip. s a Declararea lui char *s; NU nseam i loc pentru a citi/memora un ir! as s Pn acum am indicat prin pointeri doar variabile deja declarate: a a int x; int *p; p = &x; char a[20]; char *s; s = a+5; // s = &a[5]; Am declarat static doar tablouri de dimensiuni cunoscute i xe s ( C99 se permit dimensiuni variabile, evaluate la rulare) n Nu putem crea i returna dintr-o functie un tablou: el trebuie declarat s afara functiei, i adresa transmis la functie care completeaz n s a l a (ex. scanf, strcpy, functiile scrise pentru lucrul cu vectori/matrici) Functiile de alocare dinamic (stdlib.h) permit s creem variabile noi a a de dimensiuni necesare aprute la rularea programului a
Programarea calculatoarelor. Curs 9 Marius Minea
14
15
#include <stdio.h> #include <stdlib.h> #define BLOCK 16 char *getline(void) { char *p, *s = NULL; // s initializat pentru realloc int c, lim = -1, size = 0; // pastram un loc pentru \0 while ((c = getchar()) != EOF) { if (size >= lim) // s-a umplut zona alocata if (!(p = realloc(s, (lim+=BLOCK)+1))) { // mai aloca 16 ungetc(c, stdin); break; // termina daca nu mai e loc } else s = p; // tine minte noua adresa alocata s[size++] = c; // adauga ultimul caracter if (c == \n) break; // iese la linie noua } // termina cu \0, realoca doar cat e nevoie if (s) { s[size++] = \0; s = realloc(s, size); } return s; }
Programarea calculatoarelor. Curs 9 Marius Minea
16
NU e necesar cnd tim dinainte de ct memorie e nevoie a a s a a NU: int *px; px = malloc(sizeof(int)); scanf("%d", px); Mai simplu: int x; scanf("%d", &x); DA, cnd nu tim de la compilare ct memorie e necesar a s a a a (tablouri cu dimensiuni aate la rulare, liste, arbori, etc.) DA, cnd trebuie s returnm un obiect nou creat dintr-o functie a a a (NU putem returna adres de var. local, memoria dispare la revenire!) a a char *strdup(const char *s) { // creeaza copie a lui s char *d = malloc(strlen(s) + 1); // loc pentru sir si \0 return d ? strcpy(d, s) : NULL; // fa copia, returneaza d } DA, cnd trebuie pstrat un obiect citit a a ntr-un loc temporar char *tab[10], buf[81]; while (i < 10 && fgets(buf, 81, stdin)) tab[i++] = strdup(buf); // salveaza adresa copiei
Programarea calculatoarelor. Curs 9 Marius Minea
Pointeri la functii
17
Parametrii i variabilele ne permit mai mult dect calcule cu valori xe s a uneori dorim s variem functia apelat a a ntr-un punct de program Exemplu: parcurgerea unui tablou pentru diverse prelucrri a for (int i = 0; i < len; ++i) f(tab[i]); (pt. diverse functii f) se poate, folosind variabile pointeri la functii Numele unei functii reprezint chiar adresa functiei. a Declaratii: de functie: tip rez fct (tip1, . . . , tipn); de pointer la functie (de acelai tip): tip rez (*pfct) (tip1, . . . , tipn); s se poate atribui pfct = fct; (numele functiei reprezint adresa ei) a Exemplu: int fct(void); declar o functie ce returneaz un a a ntreg int (*fct)(void); declar un pointer la o functie ce returneaz a a ntreg ATENTIE! int *fct(void); e o functie ce returneaz pointer la a ntreg Sintaxa pointerilor de functii e complicat e util s declarm un tip: a a a typedef void (*funptr)(void); // tip pointer la functie void funptr funtab[10]; // tablou de pointeri de functie void
Programarea calculatoarelor. Curs 9 Marius Minea
18
void mul3(int *p) { *p *= 3; } void tip(int *p) { printf("%d ", *p); } void prel(int tab[], int len, void (*fp)(int *p)) { for (int i = 0; i < len; ++i) fp(&tab[i]); } // apoi in main putem scrie: int t[LEN] = { 2, 3, 5, 7, 11 }; // tabloul de prelucrat prel(t, LEN, mul3); /*inmulteste*/ prel(t, LEN, tip); //afiseaza Exemplu: functia standard de sortare qsort (stdlib.h)
void qsort(void *base, size t num, size t size, int (*compar)(void *, void *));
adresa tabloului de sortat, numrul i dimensiunea elementelor a s adresa functiei care compar 2 elemente (returneaz <, = sau > 0) a a folosete argumente void * ind compatibile cu pointeri la orice tip s typedef int (*comp_t)(const void *, const void *);//tip ptr.fct.cmp int intcmp(int *p1, int *p2) { return *p1 - *p2; }//fct.cmp.intregi int tab[5] = { -6, 3, 2, -4, 0 }; // tabloul de sortat qsort(tab, 5, sizeof(int), (comp_t)intcmp); // sorteaza crescator
Programarea calculatoarelor. Curs 9 Marius Minea