Sunteți pe pagina 1din 30

C_POINTERIL l_2 Sda16 Tema Analiza

eficienei prelucrrii structurilor de date cu pointeri

Sarcina i obiectivele:
1. De studiat i nsuit materialul teoretic din lucrarea dat prin lansarea exerciiilor la execuie pentru analiza i
evidenierea esenialului prelucrrii structurilor de date cu pointeri n elaborarea modelelor soluiei prin
explicaii, argumentri i organigrame.
2. S se recapituleze materialul teoretic din lucrrile de lab. 5 (PC) din semestrul I i s se analiz eze algoritmii i
programele cu i fr pointeri (declarri i parcurgeri). Pentru aprofundarea nelegerii s se dezvolte algoritmii
i programele cu pointeri pentru condiiile problemelor din Anexe i s se elaboreze scenariile succinte de
soluionare prin pointeri cu calculele de verificare i explicaii. Rularea programelor n limbajul C cu afiarea
tuturor variabilor de intrare, intermediare i finale.
3. n raport s fie expuse toate programele i calculele efectuate. S se analizeze tehnica programrii eficiente cu
pointeri n baza exerciiilor i variantelor problemelor efectuate pentru diverse situaii cu argumentri.
Fiecare tem conine dou probleme care vor fi rezolvare cu mijloacele limbajului C (diferite modele de
date i obiecte). Temele se iau n conformitate compartimentele propuse.
Lucrarea se consider efecutat dup ce studenii demonstreaz profesorului funcionarea corect a
programelor la calculator i apoi prezint darea de seam cu analiza rezultatelor. Darea de seam include: foaia
de titlu i pentru fiecare lucrare s se descrie algoritmul de rezolvare a problemei, listingul programului, dotat cu
comentariile de rigoare, Datele de intrare i rezultatele s fie folosite n simularea numeric i s fie analizate n
comparaie cu rezultatele obinute, concluzia i bibliografia studiat.

Consideraii teoretice:
1. Noiuni, exemple i importana implementrii pointelor
Variabile statice i variabile dinamice. Variabilele pot fi statice sau dinamice. Cele statice au o zon de
memorie bine definit. Structura, locul, tipul acestei zone nu poate fi schimbat n procesul execuiei programului.
Accesul la variabilele statice se face direct, dup nume. Structurile statice de date au un numr fix de elemente, care
nu poate fi modificat. Alocarea memoriei se face ntr-un spaiu strict determinat al memoriei, care permite
adresarea direct.
O alt categorie de variabile, accesibile n limbaje este cea dinamic. Pentru acest tip de variabile poate fi
modificat volumul de memorie rezervat, ceea ce face mai flexibil alocarea memoriei n procesul de lucru al
programului. Structurile dinamice pot acumula elemente n procesul de funcionare al programului, sau pot lichida
elementele ce au devenit neutilizabile. Accesul la aceste variabile i declararea lor se face n mod diferit de cel al
variabilelor statice. Accesarea (definirea) este indirect, prin intermediul unui tip mediator de variabile tipul
referin.
Variabile de tip referin conin referiri (adresri indirecte) la variabilele dinamice. Referirea se realizeaz prin
memorarea n variabila referin a adresei unde e stocat variabila dinamic.
Pentru variabilele tip referin se aloc un spaiu de memorie de 4 octei, care conin adresa variabilei
dinamice. Memoria pentru variabilele dinamice se aloc dintr-o zon special, care folosete adresarea indirect,
numit heap. Aceast zon este diferit de zona pentru variabilele statice.
Variabilele dinamice ocup un spaiu de memorie n corespundere cu tipul lor: ntreg (int), float (real),
iruri de caractere (string) etc.
Memor
ia
program

zona
HEAP

variabila
dinamic referit

zona variabilelor statice


variabil tip referin (4
bytes) adresa variabilei
dinamice

Zona de memorie este o succesiune de 1 , 2 , 4 , 8 sau mai multe loca ii ( octei ) consecutive de
memorie. Adresa unei zone de memorie este numarul de ordine a primei locatii de memorie ( cea mai din
stinga ) . Sunt doua mari categorii de pointeri : pointeri catre variabile si pointeri catre functii .
Mulimea valorilor variabilelor tip referin este format dintr-o mulime de adrese, fiecare din ele identificnd o
variabil dinamic. Mulimea de valori mai e completat prin valoarea NULL, care nu conine nici o adres.
1.1. NOTIUNEA DE POINTER Un pointer este o variabila care are ca valoare adresa unei zone
de memorie.

Pointerii sunt variabile care contin adresa de memorie a unei alte variabile. Din aceste considerente, pointerii se
numesc si variabile de adresa.
Presupunem ca avem o variabila de tip ntreg numita entitate localizata la adresa de memorie 0x1000 (adresele
sunt automat asigante variabilelor de catre compilator). Daca dorim sa referim aceasta variabila prin intermediul
unui pointer entitate_ptr, atunci valoarea pointerului va fi 0x1000 (entitate_ptr = 0x1000), astfel spunem ca
entitate_ptr "arata" spre variabila entitate (Pentru a se evita confuziile, se recomanda ca numele pointerilor sa aiba
sufixul _ptr).
Pentru a ntelege mai bine mecanismul de functionare a pointerilor, introducem o analogie pointeri - adrese
postale, n care adresa de memorie este adresa postala, numele variabilei pointer este numele cladirii, iar entitatea
referita este cladirea propriu-zisa. Aceasta analogie este prezentata n tabelul 7.1. Se observa ca doi pointeri diferiti
(Fac_AC si Fac_ETC) au aceeasi valoare, indicnd spre aceeasi locatie, astfel referind aceeasi entitate.
Tabela 7.1: Analogie

pointeri Variabila (nume pointer)


Valoare adresa
Entitate

adrese postale
Fac_CIM
str. Studenilor 3
Cladire FCIM

Pointerii se utilizeaza pentru a face referine ( a avea acces ) . la valoarea unei variabile atunci cnd se
cunoaste adresa ei . Dar o variabila se memoreaza intr - o zona de memorie de o anumita lungime ,
functie de tipul ei . De exemplu, o variabila de tip int se memoreaza pe doi octeti, pe cnd una de tip float
pe 4 octeti . De aici urmeaza ca un pointer nu reprezinta numai adresa unei variabile ci mai mult decit
att, anume:
adresa unei zone de memorie;

tipul variabilei ( int , char , double etc . ) care este memorata in acea zona de memorie.
Notiunea de pointer face ca limbajul C sa fie un puternic instrument de programare , mai ales la
indemna programatorilor avansai . Recomandam ca utilizarea pointerilor sa se faca numai dupa intelegerea
clara a mecanismului de lucru cu adrese, intruct, folositi fara discernamint, ( pointerii neinitializati, distrugerea
unor zone de memorie etc.).
Totusi folosii cu economie si disciplina, ei dau nastere la programe clare si simple, si de cele mai multe ori
mai rapide decit in varianta fara pointeri.
1.2.
DECLARAREA POINTERILOR
Ca si in cazul oricaror tipuri de variabile si pointerii trebuie
declarati. Ei se declara la fel, cu deosebirea ca numele pointerului este precedat de caracterul *.
Declaraia de pointer este: tip *nume; si prin aceasta se precizeaza ca nume este un pointer catre o zona
de memorie care contine valoarea unei variabile de tipul tip.
In declaratia de mai sus tip poate fi : int, unsigned, char, float, double etc. sau un sablon de structura. Deci
constructia tip * introduce un nou tip de date anume pointer la tip.
In afara de tipul int, long, float etc., exista si un pointer special, anume de tip void (mai precis fara tip). care
se refera la o zona de memorie ce poate contine orice tip de variabila.
Exemple
long *pl ;
/* pointer la long; */
char *pc;
/* pointer la char;
*/
double *x;
/* pointer la double; */
void *v ;
/* pointer fara tip ; */
int *pi[ 8 ]; /* sir de 8 pointeri la int; */
unsigned *pm [ 5 ][ 2 ];
/*masiv bidimensional de pointer la unsigned. */
int *p; /* pointeri la int; */
*p++ operatorul ++ incrementeaza pointerul
(*p)++ operatorul ++ incrementeaza continutul pointerului
*++p operatorul ++ incrementeaza pointerul
++(*p) operatorul ++ incrementeaza continutul pointerului
1.3. OPERATORII unari: & si * Inainte de toate, pointerul este o variabila, ca orice variabila, el trebuie
initializat. O valoare valida pentru un pointer este fie o adresa, fie constanta 0 ( zero ), definita in fisierul antet stdio.h
prin NULL, si de aici urmeaza ca un pointer este initializat prin atribuirea unei adrese ( un alt pointer ) sau a constantei
simbolice NULL. Initializarea se poate face la declararea pointerului sau in decursul programului.
Adresa zonei de memorie, unde se pstreaz valoarea variabilei x se poate obine cu operatorul obinerii adresei &.
Rezultatul operaiei obinerii adresei este adresa locaiei de memorie ce a fost alocat pentru variabila respectiv. De exemplu:
presupunnd c x e nscris n memorie pe adresa 21650, atunci &x va fi egal cu 21650. Este important, c &x este constant
de tip indicator i valoarea sa nu se schimb n timpul execuiei programului.
Exemplul 1 Rulai, afiai i analizai:
# include <stdio.h>

void main (void) int x=5; float r=1.7; int *q; float *w; q=&x; w=&r;
printf (%f se afl pe adresa % d \n,r,w); printf (% d se afl pe adresa %d \n,x,q);}
Din exemplu uor se observ c adresa celulei de memorie se reprezint printr-o valoare de tip ntreg. n acelai timp
aceast valoare nu poate fi schimbat n program i expresia &x=55; este incorect.
Exista totusi cateva restrictii , astfel daca ptr1 si ptr2 sunt pointeri de tip1 respectiv de tip2, atunci o atribuire:

ptr 1 = ptr 2 ; este permisa numai daca:


- tip 1 si tip 2 reprezinta acelasi tip, sau
- tip 1 este void , sau
- se face o conversie explicita ( cast ) a lui tip2 catre tip1.
Analiznd toate aceste noiuni, apare ntrebarea: Cu ce scop se folosesc indicatori, dac valoarea variabilei i valoarea
adresei sale se poate pstra n variabile simple?.
Prioritatea folosirii indicatorului const n faptul, c la el se poate adresa n 2 moduri: q i *q. Astericsul * n acest caz
indic c se apeleaz la coninutul celulei de memorie, adresa creia este valoarea indicatorului. Adic valoarea variabilei x de
tip ntreg este 5; valoarea indicatorului q este 21650; iar valoarea lui *q este egal cu cifra de tip ntreg 5 nscris pe adresa de
memorie 21650. n aa mod:
1) Variabila q poate primi valori numai n form de adres q=&x i atribuirea de forma q=21650; este incorect din cauza
c aici se ncearc atribuirea unei valori ntregi unui indicator i nu a adresei.
2) Variabila *q poate primi valori de tip ntreg. De exemplu: *q=6; Aceast atribuire se descifreaz astfel: de amplasat
valoarea ntreag 6 n celula dememorie ce are adresa indicat n variabila q. Din cauza, c variabila q indic la celula cu
adresa 21650, valoarea variabilei ce-i pstreaz valoarea n celula de memorie cu aceast adres va fi egal cu 6.
Exemplul 2. Rulai, afiai i analizai:
#include <stdio.h>
main void (main){ int x=5; int *q; q=&x; printf (x=%d\n,x); // x=5;
*q=6; printf (x=%d\n,x) } // x= 6;
n rezultatul ndeplinirii exemplului vor fi afiate 2 expresii: x=5 i x=6. Prima valoare primit de variabila x este valoarea
5 atribuit la momentul iniializrii acesteia. A doua valoare primit de variabila x este valoarea 6 atribuit celulei de memorie
la care indic indicatorul q.
Desigur variabila x ar putea primi valoare nou prin simpla atribuire, x=6; dar efectul deplin de la folosirea indicatorilor se
poate observa la transmiterea lor n calitate de parametri unei funcii, la crearea unui fiier, etc.
Adresare si indirectare Operatorii specifici pointerilor sunt: operatorul de dereferentiere *, sau de indirectare
(pentru un pointer, returneaza entitatea referita de pointer) si operatorul de adresa & (pentru o entitate, returneaza adresa
entitatii). Exemplul urmator explica folosirea acestor operatori. Variabila pointer obiect_ptr primeste adresa variabilei obiect,
astfel obiect_ptr va indica spre zona de memorie unde este memorata variabila obiect. n ultima linie, se stocheaza valoarea 5
la zona de memorie spre care arata obiect_ptr, adica n variabila obiect.
Am vazut ca operatorul de adresa & se aplica unei variabile si intoarce valoarea adresei sale din memorie. Operatorul de
indirectare (sau de dereferentiere) se aplica unui pointer si returneaza valoarea scrisa in memorie la adresa data de pointer. Intrun anumit sens, acesti doi operatori sunt inversi unul altuia. Pentru a intelege mai bine aceste notiuni, sa vedem pe un exemplu
ce se intampla in memorie: Exemplu: Presupunem ca avem declaratiile:
int obiect;
/* variabila de tip intreg */
int * obiect_ptr; /* pointer la un intreg */
obiect=4; obiect_ptr=&obiect;
/* obiect_ptr va indica spre obiect */
printf("%d\n", *obiect_ptr);
/* afiseaza valoarea spre care indica obiect_ptr */
*obiect_ptr=5;
/* atribuie lui obiect valoarea 5 */
Exemplu: Operatorii adres & i de indirectare * sunt unul inversul celuilalt:
*&x este chiar x, pentru orice obiect (variabil) x;
&*p are valoarea p, pentru orice variabil pointer p (dar p e o variabil i poate fi atribuit; &*p e
o expresie i nu poate).
Folosirea gresita a operatorilor poate duce la functionri incorecte a programului sau, n cazul fericit, la erori semnalate de
compilator: *variabila este ilegal, prin aceasta se solicita entitatea referita de o variabila care nu este un pointer;
&variabila_ptr este legal, dar "neobisnuit", se solicita adresa lui variabila_ptr, adica un pointer la un pointer.
Mai multi pointeri pot indica spre aceeasi zona de memorie:
int obiect; int *obiect_ptr1;int *obiect_ptr2; obiect = 1;
/* se atribuie valoarea 1 lui obiect */
obiect_ptr1 = &obiect;
obiect_ptr2 = obiect_ptr1;
/* obiect_ptr1 si obiect_ptr2 vor indica spre
aceasi locatie de memorie */
printf("%d %d\n", *obiect_ptr1, *obiect_ptr2);

Amintim! nainte de folosire, un pointer trebuie iniializat, de ex. cu adresa unei variabile de tipul potrivit:
int x, *p, **pp; p = &x; pp = &p; Situaia se poate reprezenta n urmtorul fel:

O referin *p poate fi folosit la stnga sau la dreapta unei atribuiri (n cazul de mai sus, *p se
folosete absolut la fel (sinonim) cu x): int x, y, z, *p;
p = &x; z = *p;
/* z = x */
*p =
y;
/* x = y */
Mentionam ca adresa unei variabile este dependenta de sistem (C aloca memorie acolo unde poate). Exemplu:
float x, y, *p;
p = &x;
y = *p;
Mai inti "p" se asigneaza cu adresa lui "x". Apoi, "y"
se asigneaza cu valoarea unui obiect la care pointeaza p (adica *p). Aceste doua instructiuni de asignare se pot scrie y = *&x;
care este echivalent cu
y = x;
Am vazut mai sus ca un pointer se poate initializa in timpul declararii sale. Trebuie sa avem totusi grija ca variabilele din
membrul drept sa fie deja declarate. Exemplu: Unde este greseala ? int *p = &a, a;
Tabelul de mai jos ilustreaza modul de evaluare a expresiilor cu pointeri.
Exemplul 3: Presupunem ca avem declaratiile:
int i = 3, j = 5, *p = &i, *q = &j, *r;
double x;

----------------------------------------------------------------------

| Expresie

| Expresie echivalenta

| Valoare

---------------------------------------------------------------------p == & i
p == (& i)
1
p=i+7
p = (i + 7)
gresit
**&p
* (* (& p))
3
r=&x
r = (& x)
gresit
7**p/*q+7
(((7 * (* p))) / (* q)) + 7
11
*(r = & j) *= *p (* (r = (& j))) *= (* p)
15
--------------------------------------------------------------------Spre deosebire de C traditional, in ANSI C, singura valoare intreaga care poate fi asignata unui pointer este 0
(sau constanta NULL). Pentru asignarea oricarei alte valori, trebuie facuta o conversie explicita (cast). In cele ce
urmeaza, vom scrie un program care ilustreaza legatura dintre valoarea unui pointer si adresa lui.
Exemplul : Un pointer special definit n limbajul C este pointerul NULL, care nu indica spre nimic (adresa
spre care arata acest pointer este 0). Acest pointer este definit n stdio.h si n stdlib.h ca fiind (void *) 0, adica un
pointer spre o locatie de tip void si care arata spre locatia de memorie 0.
Pentru a atribui unui pointer o adresa exista operatorul & , numit si de adresa , care aplicat unei variabile , unui
element al unui masiv sau unei structuri furnizeaza adresa zonei de memorie unde este memorat respectivul obiect .
Operatorul & este unar , are aceeasi prioritate cu a altor operatori unari ++, -- , ! , - (dupa paranteze) si se asociaza de la dreapta
la stanga. Nu se aplica expresiilor intre paranteze , constantelor sau variabilelor de tip register si de aceea utilizarile:
& (a + 2 * b )
sau & 13 sunt eronate.
Totusi , la lucru cu pointeri, cel mai mult intereseaza aflarea valorii din zona de memorie care are ca adresa pointerul,
deci actiunea complementara celei de aflare a adresei .
Exemplu 4.
Rulai, afiai i analizai
int x, y, *px ; / * x, y intregi ; px pointer la int */
px = &x ;
/* px este initializat cu adresa lui x
*/
y = * px ;
/* valoarea aflata la adresa px se atribuie lui y
*/
Se observa ca secventa de mai sus este echivalenta cu atribuirea : y = x ;
Este permisa si notiunea de pointer la pointer.Astfel prin : int * * ppi ;
se declara ppi ca fiind un pointer la un pointer de tip int. altfel spus ppi contine adresa unei zone de memorie ce contine
un numar de tip int. In acest sens urmariti exemplul urmator.
Exemplu 5. Rulai, afiai i analizai
# include studio.h
main ( )
{
int i, *pi, **ppi; /* se declara un intreg , un pointer la int. si un pointer la pointer la int. */
pi = & i ;
/* initializarea pointerului pi cu adresa lui i */
ppi = & pi;
/* initializarea lui ppi cu adresa lui pi */
printf ( pi = %p ppi = %p \ n , pi, ppi) ;
*pi = 7;
/*Echivalent cu i = 7 */
printf ( i = %d \ n , i );
i = *pi 3 ;
/ * Echivalent cu i = i - 3 ; */
printf ( i = % d \ n , i) ;
*pi = **ppi*2;
/* Echivalent cu i = i* 2 ;
*/
printf ( i = % d \ n , i) ;
}
La executia programului pe ecranul calculatorului se va afisa :
pi = FFDE ppi = FFEO
i= 7
i= 4
i= 8
In programul precedent se observa ca operatorul * aplicat unui pointer poate sa apara in partea stanga a unei
atribuiri.
Deci constructia * pointer este o valoare- stanga.
Exemplu 6. Rulai, afiai i analizai
main()
{
int ivar, *iptr;
iptr = &ivar;
ivar = 421;
printf(" ivar: %p\n",&ivar);
printf(" Coninutul ivar: %d\n", ivar);
printf("Coninutul iptr: %p\n", iptr);
printf(" Valoarea adresat: %d\n",*iptr);
}
Exemplu 7. analizai
//Operatii indirecte asupra variabilelor
x
y x, y se adreseaz direct la variabila
#include<stdio.h>
cu valoarea 7
7
9

void main()
{int x = 7, y = 97, s = 0;

respectic 97.

int *px, *py;


//Luam adresa variabilelor x, y:

px = &x;
py = &y;
//Suma x + y
s = (*px) + (*py);

px

Fie ca variabila x se afla


pe adresa 6000, iar
5000 6
6000 7
variabila pointer pe
adresa 5000. px se
adreseaz indirect la variabila cu valoarea 7. Analog
py se adreseaz indirect la variabila cu valoarea 97.

Operatia *, returneaz valoarea obiectului la care


operandul (pointerul) pointeaz: s = 7 + 97

//Afisarea Sumei
printf("\nSuma=%d\ ",s,); }
Exemplu 8. Rulai, afiai i analizai
In acest exemplu se va utiliza pointer de tip void , pointer care nu se
poate dereferentia.
Urmariti situatiile cand un pointer void se poate utiliza ca atare si cand este obligatorie o
conversie explicita ( cast ) , spre exemplu ( int * ).
# include stdio.h
main ( )
{
int i, * pi ;
/* se declara un intreg si un pointer la int */
void * pv ;
/* se declara un pointer de tip void */
pi = & i;
/* initializarea pointerului pi cu adresa lui i */
pv = pi;
/* corect ! lui pv i se atribuie valoarea pointerului pi */
* pi = 10;
/* Echivalent cu i = 10;
*/
i = * pv + 5;
/* Gresit ! pv este pointer de tip nedeterminat (void) */
i = * (int *) pv + 5; /* corect ! pv este convertit explicit spre pointer la int
*/
/* si astfel instructiunea este echivalenta cu i = i + 5;
*/
}
1.4. POINTER SI TABLOURI UNIDIMENSIONALE In urmatorul exemplu de program se defineste un sir de
caractere de dimensiune maxima 8 elemente initializate cu : abc).
Exemplu 9. Rulai, afiai i analizai
main ( )
{
char s[ 8];
s[0] = a;
s[1] = b;
s[2] = c;
s[3] = ) ;
s[4] = \ o;
printf (sirul S este % s \ n, S);
}
La executie se va afisa : abc ) adica elementele sirului pana la caracterul NULL ( \0 ).
In exemplul de mai sus s s-a declarat ca masiv unidimensional (sir) de maxim 8 elemente , dar in program s-au
utilizat 5 elemente. Mai mult decat atat s se putea declara ca parametru la o functie ca tablou deschis :
char s[ ] ;
pentru ca in aceasta situatie alocarea spatiului de memorie necesar se face dinamic . Acest lucru este
permis deoarece in limbajul C numele s al sirului este automat convertit la un pointer catre primul element al sirului. Acest
pointer este constant in sensul ca este ilegal a se modifica ( prin atribuiri) in program, deci nu este o parte stanga.
Inseamna ca declaratiile:
char s[ ] ; si char *s ;
sunt echivalente, cu observatia ca in primul caz s
este un pointer constant, initializat cu adresa lui s[0], iar in al doilea caz este un pointer obisnuit si neinitializat.
Aceasta echivalenta ne permite sa transmitem ca parametri unei functii siruri, matrici etc. prin pointeri catre primul lor
element.
Deci o functie care prelucreaza elementele unui sir poate arata:
void f (char s[ ])
{
...
}
sau
In ambele exemple, sfarsitul sirului s va fi determinat de detectarea
void f (char * s) caracterului \ o .
{
...
}
Al doilea tip de functie foloseste ca argument o adresa si de aceea in acest caz se mai spune ca apelul este prin
referinta ( in engleza call by adress).
Totusi, in cazul masivelor multidimensionale care sunt parametrii unei functii numai prin dimensiune poate lipsi.
Ex. int f ( float a [ ] [10])
In acest exemplu parametrul functiei f este un pointer catre primul element a unei matrici cu 10 coloane.
Exemplu 10. Sa se scrie o functie care verifica daca un ir de caractere x este sau nu palindrom (citit
de la stnga la dreapta sau de la dreapta la stnga este acelasi lucru: ex. cojoc, capac, cuc ). Rulai,
afiai i analizai
int palindrom (char *x)
char *p,*q;
for (p=x,q=x+strlen(x)-1;p<q;p++,q--) // se testeaza daca perechile de caractere
egal

if (*p!=*q) return 0;
coincid

//departate de extremitatile irului

return 1;
Exemplu 11. Sa se analizeze modurile de realizare functiei strlen:
int strlen(s) char s[]; { int length = 0;
for(; s[length] != '\0'; length++);
return (length); }
int strlen(s) char *s; { int length;
for(length=0; *s; length++, s++);
return length; }
int strlen(register char *s) { register char *p = s; while(*p) p++; /* */ return (p - s); }
Organizai apelurile, afind toate valorile.
1.5. OPERATII ARITMETICE CU POINTERI
Deoarece pointerii contin ca valoare o adresa de memorie, operatiile aritmetice permise sunt: atribuirea, adunarea cu
un intreg, scaderea cu un intreg, scaderea a doi pointeri, comparatia unui pointer cu constanta simbolica NULL si compararea a
doi pointeri.
Adunarea unui pointer cu un intreg Rezultatul adunarii este un pointer de acelasi tip marit cu intregul de adunat
inmultit cu numarul de octeti necesari pentru a memora o valoare de tipul pointerului. Astfel daca :
tip * ptr;
atunci: ptr + i modifica ptr cu i * sizeof (tip).
Deci noua valoare a lui ptr este: ptr + i* sizeof (tip).
Daca intregul i este l atunci se poate folosi operatorul ++ prefixat sau postfixat: ++ ptr sau ptr ++. Noul ptr va fi :
ptr + sizeof (tip).
Ex. int * pi, i;
...
pi++; /* Aduna 2 la pi (sizeof (int) = 2) */
i = * (pi + 3); /* Aduna 2 * 3 la pi si intregul memorat la pi + 6 este atribuit lui i */
...
Daca avem de-a face cu un masiv unidimensional (sir) tip a [DIM]; atunci numele sirului neurmat de indici este
considerat pointer catre primul sau element, anume pointer constant ce contine intotdeauna adresa lui a[ 0]. .Altfel spus,
valoarea lui a este & a[0]. Deci inseamna ca adunarea unui intreg la acest tip de pointer este o constructie corecta si :
a + i este identic cu &a[ i ] iar
*(a+i) este identic cu a [ i ] .
1.5.1. Scaderea unui intreg dintr-un pointer
Efectul scaderii unui intreg dintr-un pointer este acela ca valoarea
pointerului se micsoreaza cu intregul de scazut inmultit cu numarul de octeti necesari pentru a memora o valoare de tipul
pointerului.
Daca:
tip *ptr; atunci noua valoare a pointerului dupa: ptr i este : ptr i * sizeof (tip).
Utilizand operatorul de decrementare -- ptr sau ptr noua valoare pentru ptr va fi ptr sizeof (tip).
Atat operatorul de incrementare ++, cat si cel de decrementare se pot utiliza in expresii cu pointeri impreuna cu
operatorul de dereferentiere *. Pentru corectitudine trebuie tinut cont ca operatorii ++ , -- si * sunt de aceeasi prioritate si se
asociaza de la dreapata la stanga, deci se vor folosi parantezele pentru a forta ca un operator sa se execute primul.
Astfel daca: tip *ptr; atunci:
*ptr ++ respectiv *ptr mai intai obtine valoarea de la adresa ptr si apoi incrementeaza , respectiv
decrementeaza pointerul;
(*ptr)++ respectiv (*ptr) obtine valoarea de la adresa ptr pe care o incrementeaza , respectiv o
decrementeaza;
*++ptr respectiv * -- ptr mai intai incrementeaza, respectiv decrementeaza pointerul si apoi obtine
valoarea de la noua adresa ptr;
++*ptr respectiv --*ptr obtine valoarea de la adresa ptr pe care o incrementeaza , respectiv o decrementeaza .
Expresiile cu pointeri de mai sus permit o scriere mai compacta a programului si in comparatie cu utilizarea indicilor
la un tablou duc la o executie a programului intr-un timp mai scurt. Un motiv in plus pentru utilizarea acestor expresii este ca:
*ptr++, *ptr --, *++ptr si *-- ptr, intrucat se refera la obiectul catre care indica adresa din ptr, sunt valori-stanga (L value) si
deci pot fi utilizate la stanga operatorului de atribuire =. In acest caz operatorul = va modifica obiectul referit.
1.5.2. Scaderea a doi pointeri In general scaderea a doi pointeri este o operatie ilegala, cu cateva exceptii.
Astfel, daca pointerii sunt de acelasi tip , in sensul ca se refera la obiecte de acelasi tip, ei se pot scade si rezultatul
scaderii este un intreg int sau long ( functie de modelul de memorie) egal cu numarul de locatii de memorie capabile sa
memoreze o valoare de tipul comun al pointerilor existente intre adresa primului si adresa celui de-al doilea. Rezultatul este
pozitiv daca primul pointer este o adresa aflata la dreapta adresei din cel de-al doilea pointer si negativ in caz contrar.
Fie pointerii ptrl si ptr2:
tip *ptrl , *ptr2;
atunci: ptr l ptr 2 va fi egal cu (ptr l ptr 2)/ sizeof (tip).
Alta scadere corecta este aceea cand cei doi pointeri indica spre elementele aceluiasi tablou si in aceasta situatie
rezultatul este egal cu numarul de elemente dintre cei doi indici: pozitiv daca indicele l > indicele 2 si negativ in caz contrar.
# include stdio.h
main ( )
{int * pl, *p2; /* se declara doi pointer de tip int */
int x [ ] = { 0,1,2,3,4,5,6,7};
/* se declara un sir de 8 intregi care se initializeaza */
pl = & x [ 2 ];
/* Pointerul pl se initializeaza cu adresa lui x [2] . Echivalent cu : pl = x + 2 ; */
p2 = x + 7; /*Pointerul p2 se initializeaza cu adresa de inceput a lui x plus inca 7 locatii a cate
2 octeti adica cu adresa lui x [7].
Echivalent cu : p2 = & x [ 7];
printf (x = %u pl = %u p2= %u \n, x,pl,p2);

*/

printf (Diferente: pl x = %u p2 x = %u p2- p1 = %u \n,


pl x, p2 x, p2 pl); }
La executia programului se va afisa:
x = 65494 pl = 65498 p2= 65508
Diferente: pl x = 2 p2 x = 7 p2 p1 = 5
1.5.3. Compararea a doi pointeri.
Pentru ca operatia de comparare sa fie valida, cei doi pointeri trebuie sa indice
catre doua elemente ale aceluiasi tablou si rezultatul comparatiei este egal cu rezultatul comparatiei celor doi indici.
Daca pointerul pl indica pe a [i], iar pointerul p2 indica pe a [j] atunci:
pl < p2 = 1 (adevarata) daca i < j;
= 0 (falsa) daca i > j;
pl > = p2 =l (adevarata) daca i > j;
= O (falsa) daca i < j;
pl = = p2 = l (adevarata) daca i = j; i
= 0 (falsa) daca i j
Siruri cu index negativ sau mai mare decat dimensiunea maxima
La adunarea unui intreg la un pointer spunem ca daca a este un sir:
tip a[ DIM]; atunci:
a + i este identic cu &a[ i ], iar

*(a + i ) este identic cu a [i].

Intregul i care se aduna la pointerul constant a poate fi mai mare sau egal cu dimensiunea maxima a
sirului.Compilatorul C nu face verificarea depasirii dimensiunii maxime.
De asemenea ,din pointerul a se poate scade orice intreg si compilatorul C nu verifica depasirea limitei din stanga a
sirului.Intr-adevar la fel ca si la adunare cu intrgi :
a j este identic cu &a[-j], iar

(a-j) este identic cu a[-j].

Deci, in limbajul C utilizarea indexului negativ sau a indexului mai mare decat dimensiunea maxima este permisa asa cum
se ilustreaza in urmatorul exemplu.
Exemplu 12. Rulai, afiai i analizai
# include stdio.h
main ( ) {

int i, a [8];

for (i = -3; i<=12; i++) /* se initializeaza : */


a[i] = i;

/* a [-3] = -3; a [-2] =-2; */


/* .. a[0]=0; a[1]=1;

*/

/* a[7]=7;; a [12]=12; */
printf (a[-3]= %d a [2] = %d a [12] = %d \n,

*(a-3), *(a+2), a [12] );

printf ( zona neinitializata a[-4] = %d, a[-4] ); }


La executia programului se va afisa:
a[-3]= -3 a[2] = 2 a[12] = 12
zona neinitializata a[-4] = 65224
1..5.4. Legatura dintre tablouri si pointeri. Numele unui tablou este un pointer constant spre primul sau element.
Un tablou cu mai multe dimensiuni se definete prin:
tip nume[d1][d2][dn];
Referirile la elemente unui tablou cu mai multe dimensiuni se fac folosind variabile indexate de forma: nume[i1][i2]
[in], n care 0<=ik<=dk-1
Un tablou cu n dimensiuni poate fi considerat ca un tablou cu o dimensiune avnd ca elemente tablouri cu n-1
dimensiuni.
Elementele tabloului ocup o zon continu de memorie de:
d1 x d2 xx dn x sizeof(T) octei.
Adresa n memorie a unui element a[i1][i2][in] este dat de funcia de alocare:
&a[i1][i2][in]=a+sizeof(T)*[i1*d2**dn+i2*d3**dn++in]
n cazul vectorilor: &a[i]=a+sizeof(T)*i
aceasta ne permite ca la declararea unui parametru vector s nu specificm dimensiunea tabloului.
n cazul matricilor, compilatorul le transform n vectori:
&a[i][j]=a+sizeof(T)*(i*C+j)
i n cazul matricelor, ca i la vectori putem nlocui indexarea prin operaii cu indici i avem:
a[i][j] = (*(a+i)[j]=*(*(a+i)+j)
La transmiterea unui tablou multidimensional ca parametru al unei funcii vom omite numai prima dimensiune,
celelalte trebuind s fie specificate.

Prin urmare, prototipul unei funcii de afiare a unei matrici avnd l linii i c coloane nu poate fi scris ca:
void matprint(int a[][], int l, int c);
ci: void matprint(int a[][DMAX], int l, int c);
n care DMAX este numrul de coloane al matricii din apel, ceeace ne limiteaz utilizarea funciei numai pentru matrici cu
DMAX coloane!
Vom reda generalitate funciei de afiare a matricilor, declarnd matricea parametru ca un vector de pointeri:
void matprint(int (*a)[], int l, int c)
{ int i,j;
for(i=0;i<l;i++) { for (j=0;j<c;j++)

printf(%d,((int*)a)[i*n+j];

printf(\n); } }

Problema transmiterii matricilor ca parametri poate fi evitat, dac le linearizm, transformndu-le n vectori. n acest
caz, n locul folosirii a doi indici i i j vom folosi un singur indice: k=i*C+j
Expresiile de mai jos sunt deci echivalente:
nume_tablou
&nume_tablou
&nume_tablou[0] *nume_tablou
nume_tablou[0]
La declaraiile: int a[3][3]={ { 11,12,13 }, { 21,22,23 }, { 31,32,33 } }; int *pa[3]={ a,a[1],a[2] }; int *p=a[0]; se
obine schema urmtoare:

Conform schemei de mai sus se obin urmtoarele echivalene:


a[0][0], *a, **a[0], *p, **pa, *p[0].
[i][j][k] poate avea urmtoarele construcii: *(*(*(B + i ) + j ) + k )
sau
*(B[i][j] + k ).
Exemplul 13. Organizai programul cu instruciunile de mai jos. Da-i la execuie i analizai echivalena lor a, afind
toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
a[ i ] /= k+m
i
a[ i ] = a[ i ]/k+m
a[ i ] /= k+m
i
a[ i ] = a[ i ]/(k+m)
a[ i++]+=3
i
a[i++] = a[ i++]+3
a[ i++]+=3
i
a[ i ] = a[ i++]+3
a[ i++]+=3
i
a[ i++ ] = a[ i ]+3
a[ i++]+=3
i
a[ i ] = a[ i ]+3; i++;
Exemplu 14. Rulai, afiai toate valorile intermediare i finale, apoi analizai
main ()
{ long ***a; int n,m,l,i,j;
scanf("%d %d %d",&n,&m,&l); /* ---- */
a=(long ***)calloc(m,sizeof(long **));
for (i=0; i<=m; i++) { a[i]="(long" **)calloc(n,sizeof(long *)); for (j="0;" i<="l;" j++) a[i][j]="(long"
*)calloc(l,sizeof(long)); }
for (i="0;" i<="m;" i++) { for (j="0;" j<="l;" j++) free (a[i][j]); free (a[i]); } free (a); }
Exemplu 15.: Programul de mai jos citeste si afiseaza elementele a doua tablouri, la primul accesul se face
indexat, la al doilea prin pointeri. Rulai, afiai i analizai
#include <stdio.h>
#include <conio.h>
#define N 5
int tab1[N],tab2[N];
void citire1(void){ /* citeste elementele lui tab1 prin accesarea indexata a elementelor */
int i; puts("Introduceti elementele lui tab1:");
for(i=0;i<N;i++){ putchar(':');scanf("%d",&tab1[i]); } /*for i*/ } /* citire1 */
void tiparire1(void){ /* tipareste elementele lui tab1 prin accesarea indexata a elementelor */
int i; puts("Elementele lui tab1:");
for(i=0;i<N;i++) printf("%d ",tab1[i]); putchar('\n'); } /* tiparire1 */
void citire2(void){ /* citeste elementele lui tab2 - accesarea fiecarui element se face printr-un pointer la el */
int *pi; puts("Introduceti elementele lui tab2:");
for(pi=tab2;pi<tab2+N;pi++){ /* initializari echivalente sunt pi=&tab2
sau pi=&tab[0]; conditie echivalenta pi<=&tab2[N-1] */
putchar(':');scanf("%d",pi); }
/*for pi*/ } /* citire2 */
void tiparire2(void){
/* tipareste elementele lui tab2 prin accesare la pointeri */
int *pi; puts("Elementele lui tab2:");
for(pi=tab2;pi<tab2+N;pi++) printf("%d ", *pi); putchar('\n'); } /* tiparire2 */
void main(void){ clrscr(); citire1(); tiparire1(); citire2(); tiparire2(); getche(); }
Programul acesta demonstreaz dou posibiliti de prelucrare a elementelelor tabloului, unde accesul prin pointeri este
mai eficient.
Stilul adecvat de prelucrare a elementelelor tabloului prin pointeri const n declararea pointerilor suplimentari pentru a
stabili legturile cu tablourile prin pointeri. i parcurgerea, accesul, elementelelor tabloului se face numai prin pointeri, care
se mai numete stilul prelucrrii cu pointeri.

Exemplu 16.: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
void main() { clrscr(); int i,j; int t[2][3], int t[2][3],*ptr[2] ,**pp;
for(i=0;i<2;i++) ptr[i]=&t[i][0];
for(i=0;i<2;i++) for(j=0;j<3;j++) t[i][j]=i+j;
for(i=0;i<2;i++) for(j=0;j<3;j++) printf(" %d ", *(*(ptr + i)+j) ); printf("\n\n");
for(i=0;i<2;i++) for(j=0;j<3;j++) printf(" %d ", *(ptr[i]+j) );
printf("\n\n");
for(i=0;i<2;i++) for(j=0;j<3;j++) printf(" %d ",ptr[i][j]); getch();
for(i=0;i<2;i++) ptr[i]=&t[i][0]; //pp[i]=&t[i][0];
pp=ptr;
for(i=0;i<2;i++) for(j=0;j<3;j++) printf(" %d ", *(*(pp + i)+j) ); printf("\n\n");
for(i=0;i<2;i++) for(j=0;j<3;j++) printf(" %d ",*(pp[i]+j) );
printf("\n\n");
for(i=0;i<2;i++) for(j=0;j<3;j++) printf(" %d ", pp[i][j]); printf("\n\n"); }
Exemplu 17 cu pointeri la tablouri bidimensionale: Programul de mai jos determin numrul de zerouri pe liniile
matricei. ntruct pointerii la primul element este pointerul la ir i e mai bine s prelucrm matricea pe rnduri ca linie
aparte, de aceea, se prvede elaborarea funciei cnt(int x[], int *n, int m), creia i se transmite ca pointeri la primele elemente
a rndurilor matricei. Rulai, afiai i analizai
#include <stdio.h>
#include <conio.h>
void cnt(int*, int*, int);
#define LIN 2
#define COL 3
void main() {
int a[LIN][COL], b[LIN], *p, *q, *t, k;
clrscr();
q = a[0];
t = b;
for (q = a[0]; q < a[0] + LIN * COL;) {
puts("citeste elementele liniei %d", i + 1);
for (p = q; p < q + COL; p++) scanf("%d",p); cnt(q,&k,COL); *(t++) = k; q = p; }
printf("Numrul de zerouri pe liniile matricei \n");
for (t = b; t < b + LIN; t++) printf(" %4d\n",*t); }
void cnt(int x[], int *n, int m) { int *p; *n = 0;
for(p = x; p <x + m; p++) if (*p == 0) ++(*n); }
1.6. POINTERI CA ARGUMENTE LA FUNCTII. APEL PRIN REFERINTA
Am precizat in capitolul precedent ca
la apelul prin valoare functia apelata prelucreaza o copie a valorilor parametrilor, valori care au fost puse pe stiva. Inseamna ca
functia apelata are efect asupra functiei apelante doar printr-o singura valoare returnata. Dar ce posibilitati are programatorul
cand doreste ca functia apelata sa modifice mai multe variabile din functie apelanta? In aceste situatii programatorul va
transmite functiei apelate adresele variabilelor ce urmeaza sa fie modificate. Avand la dispozitie aceste adrese, functia apelata
va putea lucra direct asupra valorilor aflate la aceste adrese. Deci programul apelant va trebui sa transmita functiei apelate
pointeri catre variabilele ce vor fi modificate.
n limbajul C se pot transmite parametri si returna prin adres, intr-un mod indirect, folosind pointeri care ne permit s
utilizm funciile ca proceduri, adic s returnm mai multe rezultate i, chiar, structuri complexe (tablourilor uni- i multidimensionale etc.).
n cazul pointerilor, funcia apelant trebuie s furnizeze adresa variabilei de modificat (tehnic printr-un pointer la aceast
variabil), iar funcia apelat trebuie s declare argumentul corespunztor ca fiind un pointer. Referirea la variabila de
modificat se face prin adresare indirect.
Printre argumentele funciei pot aprea i nume de tablouri. n acest caz valoarea transmis funciei este n realitate adresa
de nceput a masivului (elementele masivului nu snt copiate). Prin indexarea acestei valori funcia poate avea acces i poate
modifica orice element din tablou.
Urmeaza ca parametrii formali ai functiei apelate vor fi declarati ca pointeri.
Acest tip de apel de functie se numeste apel prin referinta sau prin adresa (in engleza: call by adress).
Exemplu 18. Mai jos sunt doua variante pentru o functie care interschimba doua numere intregi.
/* Varianta 1 Gresit */

/* Varianta 2 Corect */

void swap (int x, int y)


void swap (int *px, int *py)
{
{
int temp;
int temp;
temp = x;
temp = *px ;
x=y;
*px = *py;
y = temp;
*py = temp;
}
}
/* Gresit */
/* Corect */
Functia din varianta 1 (apel prin valoare) este gresita, deoarece se interschimba intre ele variabilele x si y locale functiei
swap si nu parametrii efectivi de la apel, asa cum ar dori programatorul.
Functia din varinta 2 lucreaza direct cu variabilele de interschimbat din functia apelanta,intrucat are ca parametrii formali
pointeri la acestea. O modalitate de apel ar fi: swap (&x, &y );
ceea ce constituie de fapt apelul prin referinta . Doar in
acest fel x si y sunt efectiv interschimbate intre ele.

Exemplul 19.
tradiional) este :

Calculul lungimii unui sir de caractere terminat cu \ O in varianta cu pointeri (vezi si : Exemplul

unsigned strlen (char * a)


{
char * b = a ;
/* Pointerul b se initializeaza cu adresa de inceput a sirului
*/
while ( * b ! = \ O ) /* Cat timp nu s-a ajuns la sf.
*/
b++;
/* sirului incrementeaza l la b (adica treci la caracterul urmator)
*/
return n a;
/* Diferenta b a ne furnizeaza numarul de caractere peste */
/* care s-a trecut, de fapt lungimea sirului.
*/
}
OBSERVATIE
Instructiunea while ( * b! = 0 ) se putea scrie mai concis: while (*b ), deoarece expresiile : *b ! =
\0 , respectiv * b sunt sau ambele adevarate, sau ambele false.
Exemplul 20.
varianta cu pointeri .

In exemplul tradiional s-a prezentat o functie care copie sirul s ( sursa) in sirul d (destinatie). Iata

void strcpy (char * d, char * s)


{ while ( ( * d = * s)! = \ O ) {
/ * Copie caracterul
*/
s++;
/* curent din s in d pana cand s-a copiat si O . */
d++;
/* Avansarea la urmatorul caracter se face cu s++; d++; */
} }
Expresiile cu pointeri ne permit o scriere mult mai compacta :
void strcpy (char * d, char * s)
{

while ( * d++ =*s++)

/* */

}
OBSERVATIE:
Instructiunea: while ( * d++ = * s++); cuprinde urmatoarele operatii:
-la adresa curenta data de pointerul d atribuie caracterul curent aflat la adresa data de pointerul s;
-incrementeaza l atat la d, cat si la s ( se trece la caracterul urmator);
-daca ultimul caracter atribuit este = \ O atunci repeta observatiile de mai sus; altfel iese din ciclul while.
In concluzie , cele trei operatii de la prima varianta :
1.

* d = * s;

2.

s++; si d++;

3.

*d!=\O?

se executa intr-a doua varianta cu o singura instructiune.


Exemplul 21
In exemplul tradiional se compara lexicografic doua siruri de caractere a cu b. Comparati varianta
de acolo cu varianta cu pointeri de mai jos :
int strcmp (char *a, char * b )
{
for ( ; * a = = * b ; a + +, b+ + )
/* cat timp caracterul
*/
if (* a = = \ 0 )
/* curent din a este egal
*/
return 0 ;
/* cu cel din b si nu s-a
*/
return *a - *b;
/* ajuns la sfarsitul lui a
*/
} /* trece la caracterul urmator. Daca s-a ajuns la sfarsitul lui a si cum *a = = *b
*/
/* inseamna ca sirurile sunt egale si returneaza 0
*/
/* Daca *a ! = *b atunci returneaza *a - *b (dif. carecterelor curente). */
/* Daca diferenta este negativa, atunci a < b, altfel a > b
*/
Exemplu 22. Functia urmatoare utilizeaza pointerii pentru a sorta crescator un sir de numere prin metoda bulelor (vezi cel
tradiional). Rulai, afiai i analizai
void sortbule ( float *a, unsigned n )
{
unsigned i, m = n 1; float temp;
int ind = 1;
while ( ind >= 0) { ind = - 1;
for ( i = 0 ; i < m ; i++)
if ( *(a + i) > * ( a +i +1)) { temp = *( a + i ) ; *( a + i ) = *( a + i + 1) ; *( a +i +1) = temp ; ind = i ; }
m = ind ; }
}
Prin aceasta metoda sirul a [ 0 ] , a [ 1 ] , , a [ n 1 ] se parcurge de la inceput spre dreapta, astfel incat daca a [ i ]
> a [ i + 1 ] atunci se face interschimbarea lui a [ i] cu a [ i + 1] . Indicele i pentru care s-a facut interschimbarea se retine in
ind care il va schimba pe m. Intrucat de la ultimul indice i retinut in ind si pana la sfarsitul sirului este ordonat crescator la

urmatoarea parcurgere se analizeaza sirul doar pana la ultimul indice ind minus l . Se continua astfel pana nu se mai fac
interschimbari ( ind = -l ) si deci sirul este ordonat.
Exemplul 23.
Functia urmatoare sorteaza crescator un sir de numere utilizand metoda insertiei directe. In ce
consta metoda ? Se presupune ca subsirul:
a[0], a[1],,a[i-1] este deja ordonat crescator si se cauta locul lui a[i] in acest sir. Cautarea se face spre stanga, adica
de la i - 1 spre 0. Daca j este indicele pentru care (j = -1, i; a[-1] = -);
a[ j ] a[ i ] < a [ j + 1] atunci toate elementele a [ j + 1], a [j + 2],,a[ i - 1] se deplaseaza la dreapta cu o pozitie, iar
in pozitia j + 1 devenita libera se insereaza elementul a [ i ]. Se aplica procedeul de mai sus pentru i de la 1 la n - 1 si astfel
sirul este ordonat crescator.
void sortinsdir (float * a, unsigned n)
{
int i, j ;
float temp ;
for (i = 1 ; i < n ; i ++) { temp = * (a + i);
for ( j = i - 1 ; j > =0 ; j --)
/* cauta inapoi locul */
if (* (a + j) > temp)
/* elementului a j
*/
*(a+j+1) = *(a+j);
/* deplasare spre dreapta */
else { *(a+j+1) = temp; go to sf;
/* In locul lui */
}
/* a [ j + 1 ] vine a [ i ]
*/
*a = temp;
/* Locul lui a [ i ] este cel mai */
/* din stanga
*/
sf : ;
/* Instructiune vida etichetata
*/
}
}
Exemplu 24. Rulai, afiai i analizai
O alta metoda de sortare este metoda Shell cea prezentata in functia de mai jos. Principiul metodei :
- se fixeaza un pas ; la inceput n/2 ;
- se sorteaza subsirurile avand elementele aflate la distanta pas intre ele:
a [ 0] cu a [pas] , a [1] cu a [pas+1],
- se injumatateste pasul ; pas=pas/2 si se sorteaza subsirurile :
a [0] , a [pas], a [2 * pas],
a [1] , a [pas + 1], a [2 * pas + 1], s.a.m.d.
- cand pas = 0 algoritmul se termina : sirul este ordonat crescator.
Subsirurile se ordoneaza prin metoda insertiei directe prezentata anterior.
Metoda are avantajul ca aranjeaza inca de la inceput elementele aflate departe de locul lor final. Astfel, in etapele
urmatoare (cu pasul injumatatit) ramane mai putin de facut.
void sort Shell (float *a, unsigned n)
{ int i , j , pas ; float temp ;
pas = n/2 ;
/* Pasul initial
*/
while (pas >0)
{
for (i = pas ; i < n ; i++) {
/* sortarea subsirurilor */
j = i - pas ;
while ( j > =0 && a [ j ] > a [ j + pas ] ) {
temp = a [ j ] ;
a [ j ] = a [ j + pas] ;
a [ j + pas] = temp ;
j = j - pas ;
}
}
pas = pas/2 ;
/* Injumatatirea pasului. Cand
*/
}
/* acesta devine 0 programul
*/
}
/* se termina
*/
Observatie
Daca ar fi sa facem o comparatie intre cele trei metode de sortare prezentate anterior, cea mai rapida
este metoda Shell, urmeaza metoda insertiei directe si ultima, mai putin rapida, este metoda bulelor.
1.7 FUNCTII CARE RETURNEAZA POINTERI
Sunt situatii cand nu este suficient ca functia apelanta
sa intoarca o singura valoare catre apelanta. De multe ori apelanta ar trebui sa returneze un sir de valori, o structura sau o
uniune, un sir de caractere, o matrice etc.
Toate aceste alternative sunt rezolvate in limbajul C prin intermediul functiilor care returneaza pointeri. Anume
pointeri la siruri, la structuri, la uniuni, la matrice etc.
O functie care returneaza pointer se declara astfel :
[tip] nume-functie (lista-declaratori-parametri) ;
In aceasta constructie caracterul asterisc * este cel care indica faptul ca va returna un pointer. Tip-ul din fata este
de fapt tipul pointerului returnat de functie.
Exemplu 25
Urmatoarea functie concateneaza sirul S la sfarsitul lui D si returneaza pointer catre noul sir D. Se
presupune ca in D este suficient loc pentru ambele siruri.
char *strcat (char *D, char *S)
{ char *M = D ;
while ( *D)
/* cat timp caracterul curent din D 0
*/

++D ;
while ( *D++ = *S++)
;

/* avanseaza la urmatorul caracter


*/
/* Copie caracterul curent
*/
/* din S in caracterul curent de la sf.
*/
/* lui D si trece la caracterul urmator
*/
return M ;
/* Returneaza adresa de inceput a sirului rezultat */
Exemplu 26
Functia ce urmeaza determina daca S 1 este subsir al sirului S 2 si returneaza pointer la elementul
din S 2 de unde incepe subsirul S 1, respectiv NULL daca S 1 nu este subsir al sirului S 2.
# include stdio.h
char *strstr (char *S 1, char *S 2)
{
unsigned i ;
char *SA = S 1, *SB = S 2, *SC = S 2 ;
while ( *SB ! = \0 ) {
i=1;
while ( *SA ! = \0)
/* Verifica daca S 1 este
*/
if ( *SA == *SB) { /* subsir incepand din
*/
SA ++; SB++;} /* pozitia SB
*/
else {
i = 0 ; break ; }
if (i == 1)
/* Daca este subsir atunci */
return SC ;
/* returneaza SC
*/
SA = S 1 ; SC++ ; SB = SC ; /* Trece la urmatoarea */
}
/* pozitie in S 2
*/
return NULL ;
/* Nu este subsir */
}
1.8. POINTERI LA FUNCTII Daca intr-o functie este nevoie sa se apeleze alta functie, atunci metoda comoda de
lucru este ca aceasta din urma sa fie declarata ca parametru pentru prima functie. In limbajul C, o functie poate apare ca
parametru numai ca pointer la acea functie.
Un pointer la o functie se declara prin :
tip ( * nume-functie) (lista-declaratii-parametri) ;
unde tip este tipul valorii returnate de functie (poate fi si void), iar lista-declaratii-parametri este o lista de declaratori
pentru parametri separati prin virgule. Specificarea acestei liste nu este obligatorie.
Dei o funcie nu este o variabila, aceasta are o adres fizic precis de lansare n execuie, numit i punct de intrare n
funcie. Aceast adres poate, deci, fi atribuit unei variabile de tip pointer, ceea ce poate duce la posibilitatea apelrii funciei
folosind un pointer ctre funcie. In orice limbaj de programare, deci i n LC, apelarea pentru execuie a unei funcii presupune
lansarea execuiei programului n cod main, obinut dup compilare i link-editare, de la adresa punctului de intrare n
funcie. Acest lucru permite ca apelarea i lansarea n execuie a unei funcii s se fac prin intermediul unui pointer ctre
funcia respectiv. Ca i n cazul obinerii adreselor tablourilor (prin folosirea numelor acestora fr utilizarea indicilor)
adresele funciilor se obin prin folosirea numelor acestora fr paranteze si argumente.
Exemplu
float ( *func) (unsigned, char) ;
Mai sus se declara func ca fiind un pointer spre o functie care are doi parametri, primul unsigned si al doilea char si
returneaza o valoare de tip float.
Un pointer catre o functie are ca valoare adresa de memorie unde incepe partea de instructiuni executabile a functiei
in cauza. In ceea ce priveste obtinerea facem precizarea ca numele unei functii neurmat de paranteze rotunde este pointer catre
functie.
Daca de exemplu avem functie cu prototipul:
long test (int, float) ;
atunci test este pointer la aceasta functie.
Observatie
Parantezele rotunde de la declaratia de pointer la functie : ( *nume-functie) sunt necesare, deoarece
fara ele :
tip *nume-functie ( ) ; obtinem o declaratie corecta, dar de functie ce returneaza pointer (vezi
paragraful precedent) si nu de pointer la functie. Aceasta pentru ca ( ) sunt mai prioritare decat *.
int (*arr[])() = {f,g,h};
int n = 3;
main () { int i;
for(i=0; i<n; i++)
printf("%d\n",*arr[i]);
getch(); return 0;
}
Este posibil s creem un tablou de pointeri la funcii; apelarea funciilor, n acest caz, se face prin referirea la componentele
tabloului.
De exemplu, iniializarea unui tablou cu pointeri cu funciile matematice uzuale se face prin:
double (*tabfun[])(double) = {sin, cos, tan, exp, log};
Pentru a calcula rdcina de ordinul 5 din e este suficient atribuirea:
y = (*tabfun[3])(0.2);
Numele unei funcii fiind un pointer ctre funcie, poate fi folosit ca parametru n apeluri de funcii.
n acest mod putem transmite n lista de parametri a unei funcii numele altei funcii.

De exemplu, o funcie care calculeaz integrala definit: I

f(x) dx

va avea prototipul:

double integrala(double, double, double(*)(double));


Exemplu 27. Rulai, afiai i analizai. Definii o funcie pentru calculul unei integrale definite prin metoda
b

f(a) f(b)

f(x)dx h
a

n1

f(a ih)
i1

cu

ba
n

trapezelor,cu un numr fixat n de puncte de diviziune:


Folosii apoi aceast funcie pentru calculul unei integrale definite cu o precizie dat . Aceast precizie este atins
n momentul n care diferena ntre dou integrale, calculate cu n, respectiv 2n puncte de diviziune este inferioar lui
#include <math.h>
double sinxp();
double trapez(double,double,int,double(*)());
double a=0.0, b=1.0, eps=1E-6; int N=10;
void main(void) { int n=N; double In,I2n,vabs; In=trapez(a,b,n,sinxp);
do { n*=2;
I2n=trapez(a,b,n,sinxp);
if((vabs=In-I2n)<0) vabs=-vabs; In=I2n;
printf(%6.2lf\n, I2n); }
double trapez(double a,double b,int n,double(*f)())

} while(vabs > eps);

{ double h,s; int i; h=(b-a)/n;


for(s=0.0,i=1;i<n;i++) s+=(*f)(a+i*h); s+=((*f)(a)+(*f)(b))/2.0; s*=h; return s; }
Exemplu 28.
Fie de calculat valoarea aproximativa a integralei definite dintr-o functie f. O metoda suficient de
rapid convergenta este metoda Simpson (vezi [ ] pag. ). Formula lui Simpson este:
I h/3 * [f(a)+2(f(a+2h)+f(a+4h)++f(a+(2n-2)h) )+4 *(f(a+h)+f(a+3h)++f(a+(2n-1)h) ) ]
unde h = (b-a)/2n. Rulai, afiai i analizai
Vom scrie o functie Simpson care calculeaza expresia de mai sus si in care va fi apelata functia f transmisa primeia ca
un pointer la functie.
# include stdio.h
# include math.h.
double f (double) ;
double Simpson (double a, double b, unsigned n, double ( *f) ( ) ) ;
/* Ultimul parametru al functiei Simpson este pointer la functia f */
main ( )
{
int n ;
double i 1, i 2, eps, a, b ;
printf (Calculul integralei prin metoda Simpson \ n) ;
do {
printf (Introduceti a, b, eps : ) ;
scanf (%1f, %1f, %1f, &a, &b, &eps) ;
}
while (a > = b || eps < = 0) ;
n=4;
i 2 = Simpson (a, b, n, f) ;
/* Ultimul parametru este pointer la fc. f
*/
do {
i1 = i2 ;
n = n*2 ;
i2 = Simpson (a, b, n, f) ;
}
while (fabs (i1 - i2) / 15 > = eps) ;
/* Criteriul de oprire este i1 - i2 / 15 eps unde
*/
/* i2 este urmatoarea aprox. obtinuta dubland nr. de intervale */
printf (Valoarea integralei = %f \ n, i2) ;
}
double Simpson (double a, double b, unsigned n, double ( *pf) ( ) )
{
unsigned i ;
double S, h ;
h = (b - a) / n ;
S = (*pf) (a) + ( *pf) (h) ; /* Calculul sumelor
*/
for (i = 1 ; i < n ; i = i + 2) /* ce intervin
*/
S = S + ( *pf) (a + i*h) * 4 ; /* in formula lui Simpson
*/
for ( i=2 ; i < n ; i = i+2)
S = S+( *pf) (a+i*h) *2 ;
return h/3 *S ;
/* Returneaza urmatoarea aproximatie */

}
double f (double x) { return exp (-x *x) ;
/* Functia de integrat
*/ }
Exemplu 29 Da-i la execuie pentru a nelege principiile principale. Analizai definiiile funciilor, modul de
organizare a apelurilor i obinere a rezultatelor prin antetul funciilor. Face-i mbuntiri i rulai din nou. Comparai.
#include <math.h>
double sinxp();
double trapez(double,double,int,double(*)());
double a=0.0, b=1.0, eps=1E-6;
int N=10;
void main(void) { int n=N; double In,I2n,vabs; In=trapez(a,b,n,sinxp);
do { n*=2; I2n=trapez(a,b,n,sinxp); if((vabs=In-I2n)<0) vabs=-vabs; In=I2n; } while(vabs > eps);
printf(%6.2lfn, I2n); }
double trapez(double a,double b,int n,double(*f)())
{ double h,s; int i; h=(b-a)/n;
for(s=0.0,i=1;i<n;i++) s+=(*f)(a+i*h); s+=((*f)(a)+(*f)(b))/2.0; s*=h; return s; }
1.9. TABLOURI DE POINTERI. INITIALIZAREA TABLOURILOR DE POINTERI
Sa presupunem ca
avem de scris o functie care sa returneze un sir de caractere cu numele zilei a n-a din saptamana. O functie nu poate intoarce un
sir de caractere asa ca este clar ca trebuie sa revina cu un pointer la numele zilei a n-a. Deci, in cadrul functiei trebuie sa se
creeze un sir de nume de zile si un sir de pointeri spre aceste nume. Clasa de memorie pentru acest sir de nume trebuie sa fie
static interna, asa fel incat sa nu se distruga la fiecare revenire din functie.
Exemplu 30
char *nume-zi (int n)
{
static char *zi [ ] = { /* Declaratie de sir de
*/
zi ilegala,
/* pointeri si
*/
Luni,
/* initializarea
*/
Marti,
/* acestuia
*/
Miercuri
Joi
Vineri
Sambata
Duminica } ;
if (n > = 1 && n < = 7) return zi [ n ] ;
else return zi [ 0 ] ;
}
Exemplu 31. Un alt exemplu clasic de utilizare de siruri de pointeri este transmiterea matricilor ca parametri ai unei
functii. Deoarece accesul la un element al matricei se face prin dubla referinta la linie si coloana, modalitatea de transmitere a
matricelor la functii difera de cea de la siruri. In acest caz trebuie transmis un pointer la un sir de pointeri, fiecare element al
sirului pointand la liniile matricei.
Mai jos se prezinta programul care inmulteste doua matrice. Catre functia care efectueaza inmultirea se transmit
pointeri la siruri de pointeri pentru matricele A [ M ] [ N ] , B [N] [P] respectiv spre matricea rezultat C [ M ] [ P ], de fapt
pointeri la pointeri. Rulai, afiai i analizai
# include stdio.h
# define M 4
# define N 2
# define P 3
void inm-matr (float **, float **, float **, unsigned, unsigned, unsigned) ;
main ( )
{
unsigned i, j ;
float *pa [M], *pb [N], *pc [M], **ppa, **ppb, **ppc ;
float a [M] [N] = h
{ 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }
};
float b [N] [P] = h
{1, 2, 3},
{4, 5, 6} } ;
float c [M] [P] ;
for (i = 0 ; i < M ; i++ )
pa[ i ] = a [ i ] ; /* pa [ i ] = adresa liniei i in matricea a
*/
for ( i = 0 ; i < N ; i++ )
pb [ i ] = b [ i ] ;/* pb [ i ] = adresa liniei i in matricea b
*/
for ( i = 0 ; i < M; i++)
pc [ i ] = c [ i ] ; /* pc [ i ] = adresa liniei i in matricea c
*/
ppa = pa ;
ppb = pb ;
ppc = pc ;
inm-matr (ppa, ppb, ppc, M, N, P) ;
printf (Matricea rezultat = \ n) ;
for ( i = 0 ; i < M ; i++) {
for ( j = o ; j < P ; j++)
printf (?) ; } }
O situatie n care pointerii sunt mai utili este declararea structurilor recursive. n C nu se permite ca o structura sa
contina cmpuri de tipul aceleiasi structuri. Aceasta restrictie poate fi evitata folosind pointeri la structuri, dupa cum se arata n
exemplul urmator:
typedef struct pers { char nume[20]; int varsta; struct pers * urmator; } persoana;
persoana *p;

Pentru a referi un cmp folosind un pointer spre o structura, se foloseste operatorul de dereferentiere: (*p).nume.
Echivalent cu acest operator exista n C un alt operator pentru accesarea cmpurilor din structurile indicate de pointeri: p>nume.
Folosirea neadecvata a operatiilor cu pointeri. O greseala des ntlnita este referirea pointerilor spre alte locatii de
memorie:
int obiect=5; int *obiect_ptr;
obiect_ptr = obiect;
Lipsa operatorului de adresa & face ca obiect_ptr sa indice spre locatia de memorie aflata la adresa 5.
Urmatorul exemplu ilustreaza un stil de programare "daunator", care strica lizibilitatea codului. Limbajul C este foarte
flexibil, fapt ce poate duce, n special n cazul pointerilor, la rezultate imprevizibile:
void copy_string(char * p, char *q) { /* copiaza sirul q in p */
while (*p++ = *q++); }
Chiar daca aceasta implementare este mult mai compacta, urmarirea codului este foarte dificila, iar folosirea combinata a
operatorilor de incrementare si pointerilor poate duce la efecte necontrolate. Urmatoarea varianta de implementare a aceleiasi
functii copy_string prezinta un stil adecvat programarii cu pointeri:
void copy_string(char * dest, char * sursa)
{ *dest = *sursa;
while (*dest!='\0') { ++dest; ++sursa; *dest = *sursa; } }
1.10. Alocarea dinamic a memoriei. Alocarea dinamica a memoriei este deosebit de utila atta timp ct
programatorul foloseste structuri de date pentru care nu tie dimensiunea la scrierea programului. In cursul executiei programul
poate aloca memorie in limitele impuse de sistem. n C, deoarece limbajul ofera o mare libertate de exprimare, este foarte usor
pentru un programator neatent sa faca erori care nu sunt semnalate la compilare, dar care duc la comportari neasteptate ale
programului, adic, iari, folosirea neadecvata a operatiilor cu pointeri O eroare tipica este atribuirea de valori pointerilor
neinitializati:
int *un_pointer; *un_pointer=5;
n aceasta situatie, deoarece un_pointer este neinitializat, valoarea 5 este scrisa n memorie la o locatie aleatoare, poate
chiar rezervata altei variabile.
Alocarea dinamic este un mijloc folosit, n programarea n LC, pentru alocarea de memorie pentru diversele variabile pe
parcursul executrii programului. Alocarea dinamica de memorie se face cu ajutorul unor funcii speciale numite funcii de
alocare dinamic. Prin aceste funcii pot fi alocate zone de memorie dinamice n zona speciala de memorie heap care se afl
ntotdeauna intercalata ntre programul utilizatorului mpreuna cu zona de memorare permanenta i memoria stiva.
Dimensiunea zonei heap este necunoscut utilizatorului dar dispune de o cantitate relativ mare de memorie.
Pentru alocarea dinamica n LC se folosesc, n mod uzual, funciile malloc() si free(), prima pentru alocarea dinamic
propriu-zis i cea de-a doua pentru eliberarea zonei de memorie ocupat prin funcia malloc(). Aceste funcii se gsesc n
fiierul antet (header) stdlib.h.
Alocarea dinamica de memorie se face cu sintaxa:
*malloc (size_t numar_de_bytes)
unde:
- size_t este un tip definit n fiierul stdlib.h ca un intreg far semn;
- numar_de_octeti reprezint numrul de bytes (octei) pe care programatorul dorete s-i aloce prin funcia malloc.
Dup o alocare reuita functia malloc returneaza un pointer de tip void, (ceea ce precizeaz ca poate fi atribuit oricarui tip
de pointer), al primului octet liber din zona de memorie heap, iar dac alocarea eueaza ca urmare a inexistenei lungimii de
memorie cerut din zona heap atunci funcia malloc returneaz valoarea zero.
n cazul n care un pointer nu arata spre o zona de memorie rezervata, trebuie alocata o zona de memorie n mod explicit,
folosind functia malloc:
un_pointer=(int *)malloc(sizeof(int));
Functia malloc rezerva spatiu de memorie si returneaza adresa spatiului rezervat; zona de memorie referita de un pointer
poate fi eliberata folosind functia free. Ambele functii sunt definite n stdlib.h.
n C nu exista un mecanism de garbage collection, astfel ca programatorul trebuie sa aiba grija ca zonele de memorie
alocate dinamic si care nu mai sunt utile sa fie dealocate (folosind functia free). Faptul ca unui pointer i se atribuie o noua
valoare nu nseamna ca zona de memorie spre care arata s-a eliberat si n acest mod programul poate ajunge sa tina alocata
toata memoria disponibila.
Astfel utilizatorul poate solicita n timpul execuiei programului alocarea unei zone de memorie.
Aceast zon de memorie poate fi eliberat, n momentul n care nu mai este necesar.
Alocarea i eliberarea de memorie la execuie permite gestionarea optim a memoriei.
int **a, n, m, i;
scanf("%d%d", &n, &m);
a = (int **) malloc(n *sizeof(int *));
for (i = 0 ; i < n; i++) a [i] = (int *) malloc(m *sizeof(int));
eliberarea de memorie se efectueaz n ordinea invers crerii:
for (i = 0 ; i < n; i++) free(a[i]); free(a);
Biblioteca standard ofer 4 funcii, avnd prototipurile n <alloc.h> i <stdlib.h>. Acestea sunt:
/1/

void *malloc(unsigned n);

Funcia aloc un bloc de memorie de n octei. Funcia ntoarce un pointer la nceputul zonei alocate. n caz c cererea
de alocare nu poate fi satisfcut, funcia returneaz NULL.
Exemple a)- secventa de program:
char *ptrsir;

ptrsir = malloc(200); /* se aloca 200 octeti */


aloca 200 de octeti , iar adresa primului octet se va gasi in pointerul ptrsir
b)- secventa de program:
int *ptrint;
ptrint = malloc(75*sizeof(int); /* se aloca memorie pentru 75 nr. intregi */
aloca memorie pentru 75 de numere intregi (75*ziseof(int)=75*2 octeti), iar adresa primului numar se va gasi in pointerul
ptrint.
/2/
void *calloc(unsigned nelem, unsigned dim);
Aloc nelem*dim octei de memorie (nelem blocuri formate din dim octei fiecare). ntoarce un pointer la nceputul
zonei alocate sau NULL.Memoria alocat este iniializat cu zerouri.
void free(void *p);
/3/

Funcia realloc elibereaz o zon de memorie indicat de p, alocat n prealabil prin malloc() sau calloc().
void *realloc(void *p, unsigned dim);

Modific dimensiunea spaiului alocat prin pointerul p, la dim. Funcia ntoarce adresa zonei de memorie realocate,
iar pointerul p va adresa zona realocat.

dac dimensiunea blocului realocat este mai mic dect a blocului iniial, p nu se modific, iar funcia va ntoarce valoarea
lui p.

dac dim==0 zona adresat de p va fi eliberat i funcia ntoarce NULL.

dac p==NULL, funcia aloc o zon de dim octei (echivalent cu malloc()).

Eliberarea zonei memorie alocat printr-o funcie malloc se face cu funcia free() avnd sintaxa urmtoare:
free(nume_pointer);
unde nume_pointer este variabil de tip pointer care conine adresa de memorie a zonei alocate i utilizate anterior i care
urmeaz sa fie disponibilizat pentru alte alocri dinamice viitoare.
Tehnica alocrii dinamice n LC este folosit alturi de pointeri pentru crearea, actualizarea i exploatarea unor structuri de
date importante cum ar fi: listele simplu si dublu nlnuite, arborii binari i tablourile alocate dinamic.
Tablouri alocate dinamic Deoarece oricrui pointer i se poate aplica un indice, asemntor unui tablou unidimensional,
atunci se poate lucra cu zona de memorie indicata de un pointer ca i cum ar fi un tablou unidimensional.
/4/

Funciile de alocare ntorc pointeri generici (void*) la zone de memorie, n timp ce utilizatorul aloc memorie ce
pstreaz informaii de un anumit tip. Pentru a putea accesa memoria alocat, indirect, prin intermediul pointerului, acesta va
trebui s fie un pointer cu tip, ceea ce impune conversia explicit (prin cast) a pointerului ntors de funcia de alocare ntr-un
pointer cu tip.
De exemplu, pentru a aloca un vector de ntregi, avnd n elemente vom folosi:
int *p:
if (p=(int*)malloc(n*sizeof(int))==NULL) {
printf(Memorie insuficienta\n); exit(1); }
Funciile care ntorc pointeri sunt utile n alocarea de spaiu pentru variabile dinamice.
Deoarece zona heap de memorie nu este infinit (ci limitat), la fiecare alocare dinamic de memorie, trebuie s se verifice
valoarea returnat de funcia malloc pentru a fi siguri c alocarea s-a fcut cu succes, ca n exemplul de mai jos:
int *ptrint;
ptrint = malloc(75*sizeof(int); /* se aloca memorie pentru 75 nr. intregi */
if(ptrint){ printf(\n memorie insuficienta, eroare de alocare);
exit(1); }
sau
if (!(ptrint =malloc(100))) { printf(\n memorie insuficienta, eroare de alocare); exit(1); }
Functia exit() este cea care se foloseste la iesirea din rutina in momentul cand nu este suficienta memorie.
Variabilele dinamice sunt alocate n momentul execuiei, nu au nume i sunt accesate prin pointeri.
Un constructor este o funcie care aloc spaiu n mod dinamic pentru o variabil i ntoarce un pointer la spaiul
rezervat.
Un destructor este o funcie care primete un pointer la o zon alocat dinamic i elibereaz aceast zon.
O funcie util, strdup() salveaz un ir de caractere ntr-o zon alocat dinamic i ntoarce un pointer la acea
zon sau NULL.
char *strdup(char *s) {
char *p;
p=(char*) malloc(strlen(s)+1);
if (p!=NULL) strcpy(p,s);
return p;
}
int main() { int n,i; int * a; // adresa vector alocat dinamic
printf ("n="); scanf ("%d", &n); // dimensiune vector
a=(int *) calloc (n,sizeof(int)); // a=(int*) malloc (n*sizeof(int));
printf ("componente vector: \n");

for (i=0;i<n;i++)
scanf ("%d", &a[i]); // sau scanf (%d, a+i);
for (i=0;i<n;i++) // afisare vector printf ("%d ",a[i]);
return 0; }
Exista si cazuri in care datele memorate intr-un vector rezulta din anumite prelucrari, iar numarul lor nu poate fi cunoscut
de la inceputul executiei. Un exemplu poate fi un vector cu toate numerele prime mai mici ca o valoare data. In acest caz se
poate recurge la o realocare dinamica a memoriei. In exemplul urmator se citeste un numar necunoscut de valori intregi intr-un
vector extensibil:
#define INCR 100 // cu cat creste vectorul la fiecare realocare
int main() {
int n,i,m ;
float x, * v; // v = adresa vector
n=INCR;
i=0;
v = (float *)malloc (n*sizeof(float)); // dimensiune initiala vector
while ( scanf("%f",&x) != EOF) {
if (++i == n) { // daca este necesar
n= n+ INCR; // creste dimensiune vector
v=(float *) realloc (vector,n*sizeof(float));
v[i]=x; // memorare in vector numar citit
}
for (i=0;i<n;i++) // afisare vector
printf ("%f ",v[i]);
return 0;
}

Din exemplele anterioare lipseste eliberarea memoriei alocate pentru vectori, dar fiind vorba de un singur vector alocat in
functia main si necesar pe toata durata de executie, o eliberare finala este inutila. Inainte de executia unui nou program
memoria heap este reinitializata (se anuleaza automat toate alocarile facute de programul anterior). Eliberarea explicita poate
fi necesara pentru vectori de lucru, folositi numai in anumite secvente de program (sau functii). Realocarea repetata de
memorie poate conduce la fragmentarea memoriei heap, adica la crearea unor blocuri de memorie libere dar neadiacente si
prea mici pentru a mai fi reutilizate ulterior. De aceea, politica de realocare pentru un vector este uneori dublarea capacitatiii
sale anterioare.
Matrice alocate dinamic Alocarea dinamica pentru o matrice este importanta deoarece:
-Foloseste economic memoria si evita alocari acoperitoare, estimative.
-Permite matrice cu linii de lungimi diferite.
-Reprezinta o solutie buna la problema argumentelor de functii de tip matrice.
Daca programul poate afla numarul efectiv de linii si de coloane al unei matrice (cu dimensiuni diferite de la o executie la
alta), atunci se va aloca memorie pentru un vector de pointeri (functie de numarul liniilor) si apoi se va aloca memorie pentru
fiecare linie (functie de numarul coloanelor) cu memorarea adreselor liniilor in vectorul de pointeri. O astfel de matrice se
poate folosi la fel ca o matrice declarata cu dimensiuni constante. Exemplu:
int main () {
int ** a; int i,j,nl,nc;
printf (nr. linii=); scanf (%d,&nl);
printf (nr. col. =); scanf (%d,&nc);
a = (int**) malloc (nl*sizeof(int*)); // alocare ptr vector de pointeri
for (i=0; i<n;i++)
a[i] = (int*) calloc (nc, sizeof(int)); // alocare pentru o linie si initializare
// completare diagonala matrice unitate
for (i=0;i<nl;i++)
a[i][i]=1; // a[i][j]=0 pentru i != j
// afisare matrice<
printmat (a,nl,nc); return 0;
}
Functia de afisare a matricei se poate defini astfel :
void printmat (int ** a, int nl,int nc) {
for (i=0;i<nl;i++) { for (j=0;j<nc;j++) printf (%2d, a[i][j]); printf(\n);
}

Notatia a[i][j] este interpretata astfel pentru o matrice alocata dinamic:


-a[i] contine un pointer (o adresa b)
-b[j] sau b+j contine intregul din pozitia j a vectorului cu adresa b.
Functia printmat data anterior nu poate fi apelata dintr-un program care declara argumentul efectiv ca o matrice cu
dimensiuni constante. Exemplul urmator este corect sintactic dar nu se executa corect:
int main () {
int x [2][2]={{1,2},{3,4}}; // o matrice patratica cu 2 linii si 2 coloane
printmat ( (int**)x, 2, 2); return 0;}

Explicatia este interpretarea diferita a continutului zonei de la adresa aflata in primul argument: functia
printmat considera ca este adresa unui vector de pointeri ( int * a[]). iar programul principal considera

ca este adresa unui vector de vectori (.int x[][2]). Se poate defini si o functie pentru alocarea de memorie
la executie pentru o matrice. Exemplu:
int **newmat(int nl, int nc) { // rezultat adresa matrice
int i; int ** p=(int **) malloc (nl*sizeof (int*));
for (i=0;i<n;i++) p[i] =(int*) calloc (nc,sizeof (int)); return p; }
Exemplul 32.: Rulai, afiai i analizai. Citii de la intrarea standard un ir de caractere de lungime necunoscut
ntr-un vector alocat dinamic. Alocarea de memorie se va face progresiv, n incremente de lungime INC, dup citirea a INC
caractere se face o realocare.
char *citire()
{ char *p, *q;
int n; unsigned dim=INC; p=q=(char*)malloc(dim);
for(n=1; (*p=getchar())!=\n &&*p!=EOF; n++) {
if(n%INC==0) { dim+=INC;
p=q=realloc(q,dim);
p+=n; continue; }
p++;
} *p=\0; return realloc(q,n);
Not. n C++, alocarea dinamic se face mai simplu i mai sigur, folosind operatorii new i delete.
permite alocarea de memorie n heap. El se folosete ntr-una din formele:
tip *p, *q, *r;
p=new tip;
//rezerva in heap o zona de sizeof(tip) octeti
q=new tip(expresie);//acelasi efect cu initializare cu val.expresiei
r=new tip[expint]; //rezerva o zona neinitializata de expint*sizeof(tip) octeti
Eliberarea memoriei alocate se face prin: delete p: delete [] r;

}
Operatorul

new

//elibereaza memoria alocata pentru tablou

Exemplul 33: Rulai, afiai i analizai. Definii o funcie care aloc dinamic memorie pentru o matrice avnd l linii i c
coloane conform organigramei urmtoare:

plin

pelem
plin[0]
plin[1]
plin[2]

pelem[0][0]
pelem[0][1]
pelem[1][0]
pelem[1][1]
pelem[2][1] pelem[2][0]

double **alocmat(int lin, int col)


{ double **plin; double *pelem; int i;
pelem=(double*)calloc(lin*col, sizeof(double));
if(pelem==(double*)NULL){ printf(spatiu insuficient\n); exit(1);}
plin=(double**)calloc(lin, sizeof(double*);
if(plin==(double**)NULL){ printf(spatiu insuficient\n); exit(1); }
for (i=0; i< lin; i++) { plin[i]=pelem;
pelem+=col; } return plin; }
Pointeri la pointeri (indirectare multipla). Limbajul C permite realizarea indirectarii multiple prin faptul ca un pointer
poate fi pointat de un alt pointer. Indirectarea multipla este limitata la pointer catre pointer si se utilizeaza cu precautie.

Figura 11.1. Pointerul catre pointer retine adresa pointerului la o variabila


Daca pointer1 pointeaza catre pointer2 atunci acesta contine adresa lui pointer2. Pointer2 contine adresa variabilei.
Declararea unui pointer la pointer se face cu un * suplimentar fata de declararea pointerului. De exemplu:
int k; /* declararea variabilei */
int *p; /* declarare pointer */
int **plap; /* declarare pointer la pointer */
float v,*p,**pp; p=&v;
pp=&p;
**pp=1.2 /* v=1,2 */
Exemplul 34: Rulai, afiai i analizai
#include<stdlib.h>
#include<stdio.h>
#include<string.h>

int main() { int n, i; char (*cuvinte_u)[20] = NULL, (*cuvinte)[20]; // un pointer la un sir de 20 caractere
int *aparitii;
scanf("%d\n", &n); cuvinte = (char (*)[20]) malloc(n * sizeof(char[20]));
i = 0;
while (i < n) { scanf("%s", cuvinte[i]); i++; }
int dim = 4, unice = 0, k;
cuvinte_u = (char (*)[20]) malloc(dim * sizeof(char[20]));

aparitii = (int *) malloc(dim * sizeof(int));


for (i = 0; i < n; i++) { int found = 0; // variabila care va indica daca am gasit cuvantul in vectorul de aparitii unice
for (k = 0; k < unice; k++) { if (strcmp(cuvinte_u[k], cuvinte[i]) == 0) { aparitii[k]++; found = 1;} }
if (found != 1) {
//in cazul in care vucantul nu a fost gasit in vectorul de valori unice
if (unice >= dim) { //in cazul in care dimensiunea vectorului unic nu a ajuns la limita
dim *= 2; aparitii = (int *) realloc(aparitii, dim * sizeof(int));
cuvinte_u = (char (*)[20]) realloc(cuvinte_u, dim * sizeof(char[20]));
}
strcpy(cuvinte_u[unice], cuvinte[i]); aparitii[unice] = 1; unice++; } }
for (i = 0; i < unice; i++) { //afisarea rezultatelor
printf("%s %d\n", cuvinte_u[i], aparitii[i]);
}
//dealocare de memorie
free(aparitii);
free(cuvinte_u);
free(cuvinte);
return 0; }
Rulai, afiai i analizai /* Citirea unui sir prin indirectare multipla */
#include<stdio.h>
void main (void)
{ char sir[80],*p_sir,**p_p_sir;
p=sir; p_p_sir=&p; printf("\n Introduceti numele Dvs.: "); gets(*p_p_sir); printf("\n Salut %s ", *p_p_sir); }
Pentru a declara un pointer ctre un alt pointer, trebuie plasat un asterix suplimentar n faa numelui pointerului.
De exemplu:
char ** pp; pp este un pointer ctre un alt pointer de tip char, i nu un pointer ctre un caracter.
Accesarea valorii printr-un pointer ctre un alt pointer, cere ca operatorul asterix s fie aplicat de dou ori. De
exemplu:
p = &ch; // asigneaz lui p adresa lui ch
pp = &p; //asigneaz lui pp adresa lui p
**pp = c; // asigneaz lui ch valoarea c folosind indirectare multipl
Observaie. Pointeri ctre pointeri pot produce confuzii. De aceea, indirectarea excesiv este derutant i surs de erori
conceptuale.
#include <stdio.h>
void main(void)
{float a,s=0,*pa,**ppa; int i;
i=1;
while(i<=10) {printf(\n a=); scanf(%f,&a);
pa=&a; ppa=&pa;
s=s + **ppa; i++; }
printf(\n media=%f,s/(i-1)); }
Exemplul .35: Da-i la execuie pentru a nelege principiile principale. Analizai definiiile funciilor, modul de organizare a
apelurilor i obinere a rezultatelor prin antetul funciilor. Face-i mbuntiri i rulai din nou. Comparai.
#include <stdio.h>
#include <string.h>
#include <conio.h>
void SimetricPare(char*);
void SimetricImpare(char*);
void Transpune(char*);
char* Trim(char*);
void EnterProp(char*);
void SimetricImpare(char*);
void Calculate(char*);
int countPare=-1, countImpare=50, index, probels=0, len;
char *cMaiLung, *cMaiScurt, *cuvintele[10];
bool bPar=false, bImpar=false, entered=false;
int main(void)
{ char cPropozitia[125]; int i=0, j, mi;
printf("Menu:\n----------\n");
printf("1. Introducerea propozitiei\n");
printf("2. Calcule\n");
printf("3. Simetric lung pe poz.pare\n");
printf("4. Simetric scurt pe poz.impare\n");
printf("5. Transpusa\n");
printf("6. Iesire\n");
printf("\n-=Alegeti un punct al meniului=-:\n");
mi = getch();
while(mi!=(int)'6')
{
switch(mi)
{
case (int)'1': EnterProp(cPropozitia); break;
case (int)'2': if(!entered){printf("Introd. propozitia!"); break;}Calculate(cPropozitia); break;
case (int)'3': if(!entered){printf("Introd. propozitia!"); break;}if(bPar)printf("\nSimetric Lung de pe
pare: %s\n", cMaiLung);else printf("\n\nSimetric Lung pe pare nu a fost gasit\n"); break;
case (int)'4': if(!entered){printf("Introd. propozitia!"); break;}if(bImpar)printf("\nSimetric Scurt de
pe impare: %s\n", cMaiScurt);else printf("\n\nSimetric Scurt pe impare nu a fost gasit\n"); break;
case (int)'5':

if(!entered){printf("Introd. propozitia!"); break;}


for(i=0; i<probels+1; i+=2)
{
Transpune(cuvintele[i]);
}
if(!bPar || !bImpar)
{
puts("Propozitia transpusa: ");
for(int i=0; i<len; i++) printf("%c", cPropozitia[i]);
}
else printf("Cuvinte transpuse nu sunt\n");

}
break;
default: printf("Comanda necunoscuta\n"); break;
}
mi = getch();
}
return 0;
}
void EnterProp(char* c)
{ printf("Introduceti propozitia: ");
gets(c);
c = Trim(c);
entered = true;
return;
}
void Calculate(char* c)
{
int i, j;
len = strlen(c);
for(i=0; i<strlen(c); i++)
if(c[i]==' ')probels++;
/* SPLIT */
cuvintele[0] = strtok(c, " ");
for(i=0; i<probels; i++)
cuvintele[i+1] = strtok(NULL, " ");
/* *** */
for(i=0, j=1; i<probels+1; i+=2, j+=2) //j-pare, i-impare
{
SimetricImpare(cuvintele[i]);
if(j<probels+1)SimetricPare(cuvintele[j]);
}
printf("\nCalcule si operatii cu propozitia au fost efectuate\n");
return;
}
void SimetricPare(char* c)
{
int j=strlen(c)-1, i;
for(i=0; i<strlen(c)/2; i++, j--)
if(c[i]!=c[j])return;
bPar = true;
if(countPare<(int)strlen(c))
{
cMaiLung = c;
countPare = strlen(c);
}
return;
}
void SimetricImpare(char* c)
{
int j=strlen(c)-1, i;
for(i=0; i<strlen(c)/2; i++, j--)
if(c[i]!=c[j])return;
bImpar = true;
if(countImpare>(int)strlen(c))
{
cMaiScurt = c;
countImpare = strlen(c);
}
return;
}
void Transpune(char* cuvintul)
{ int i, j=strlen(cuvintul)-1;

char c;
for(i=0; i<strlen(cuvintul)/2; i++, j--)
{
c = cuvintul[i];
cuvintul[i] = cuvintul[j];
cuvintul[j] = c;
}
return;
}
char* Trim(char* c)
{
int index, i, j;
char* str2trim;
str2trim = c;
index = strlen(str2trim);
for(i=0, j=0; i<strlen(str2trim); i++)
{
if(str2trim[i]==' ' && str2trim[i+1]==' '){ index--; continue; }
str2trim[j] = str2trim[i];
j++;
}
str2trim[index] = '\0';
while(*str2trim==' ')*str2trim++;
index = strlen(str2trim);
while(str2trim[index-1]==' ') index--;
str2trim[index] = '\0';
return str2trim;
}
Exemplul 36: Da-i la execuie i analizai modul de organizare a apelurilor i obinere a rezultatelor prin antetul
funciilor. Face-i mbuntiri i rulai din nou. Comparai.
#include <stdio.h>;
int cmp_cresc ( const int x, const int y )
{
if ( x == y ) return 0; return x > y ? 1 : -1; }
int cmp_desc ( const int x, const int y ) { if ( x == y ) return 0; return x > y ? -1 : 1; }
void swap ( int *x, int *y) { int aux; aux = *x; *x = *y; *y = aux; }
void sort(int v[], int n, int (*cmp) ( const int x, const int y) ) { int i, j;
for ( i = 0; i < n - 1; i++ ) for ( j = i + 1; j < n; j++ ) if ( cmp ( v[i], v[j] ) == 1 ) swap( &v[i], &v[j] ); }
int main() { int v[100], n, ord;
int (*cmps[2]) ( const int, const int ) = { cmp_cresc, cmp_desc }; // citire n si vector ...
printf("Alegeti tipul de sortare: 0 - crescator; 1 - descrescator.\n"); scanf("%d", &ord);
sort(v, n, cmps[ord]); // afisare vector sortat ...
return 0; }
Exemplul 37: Da-i la execuie i analizai modul de organizare a apelurilor i obinere a rezultatelor prin antetul
funciilor. Face-i mbuntiri i rulai din nou. Comparai.
#include<stdio.h>
#include<conio.h>
int a; int *pa;
int **ppa;
int ***pppa;
int ****ppppa;
int *****pppppa;
int (*v[3])[3][3]; int (*(*ppp)[3])[3][3]; int(*(*(*ph))[3])[3][3];
int s[3],m[3][3]={{1,2,8},{4,6,7},{6,7,5}};
void main(){clrscr();
a=33; pa=&a;
ppa=&pa;
pppa=&ppa;
ppppa=&pppa; pppppa=&ppppa;
printf("\n%d %d %d ",*pa , ***pppa, *****pppppa); getch();
clrscr();
for(int i=0;i<3;i++) v[i]=&m; ppp=&v; ph=&ppp;
for(i=0;i<3;i++){s[i]=0; for(int j=0;j<3;j++) s[i]+=(*(*(*ph))[i])[i][j]; }for(i=0;i<3;i++) printf(" %d ",s[i]); getch(); }
Exemplul 38: Da-i la execuie i analizai modul de organizare a apelurilor i obinere a rezultatelor prin antetul funciilor.
Face-i mbuntiri i rulai din nou. Comparai.
#include<stdio.h>
#include<conio.h>
#include<alloc.h>

int ***ppp_int; int **pp_int; int *p_int; int intreg=44;


void main(){ clrscr(); p_int=(int *)malloc(sizeof(int)); pp_int=(int **)malloc(sizeof(int*));
ppp_int=(int ***)malloc(sizeof(int**)); p_int=&intreg; pp_int=&p_int; ppp_int=&pp_int;
printf(" %d %d ", *p_int ,***ppp_int); getch(); }
Exemplul 39: Da-i la execuie i analizai modul de organizare a apelurilor i obinere a rezultatelor prin antetul
funciilor. Face-i mbuntiri i rulai din nou. Comparai.
#include<conio.h>
#include<stdio.h>
int (*v[3])[3][3]; int (*(*ppp)[3])[3][3]; int(*(*(*ph))[3])[3][3];
int s[3],m[3][3]={{1,2,8},{4,6,7},{6,7,5}};
void main(){ clrscr();
for(int i=0;i<3;i++) v[i]=&m; ppp=&v; ph=&ppp;

for(i=0;i<3;i++){s[i]=0; for(int j=0;j<3;j++) s[i]+=(*(*(*ph))[i])[i][j]; }


for(i=0;i<3;i++) printf(" %d ",s[i]); getch();}
Exemplul40: Da-i la execuie i analizai modul de organizare a apelurilor i obinere a rezultatelor prin antetul funciilor.
Face-i mbuntiri i rulai din nou. Comparai.
#include<stdio.h>
#include<conio.h>
float y[100]; int f[100],n; float xmed[3]; float (*functii[3])(float x[100],int f[100],int n);
float med1(float x[100],int f[100],int n){ float a=0,b;
for(int i=0;i<n;i++){ f[i]=1; a+=x[i]*f[i]; } return a/n; }
float med2(float x[100],int f[100],int n){ float a,b; a=b=0;
for(int i=0;i<n;i++){ b+=f[i]; a+=x[i]*f[i]; } return a/b; }
float med3(float x[100],int f[100],int n){ float a,b; a=b=0;
for(int i=0;i<n;i++){ b+=f[i]; a+=f[i]/x[i]; } return b/a; }
void main(){ functii[0]=med1; functii[1]=med2; functii[2]=med3;
printf("\nNr de elemente: ");fflush(stdin); scanf("%d",&n);
for(int i=0;i<n;i++){ printf("\n y[%d]= ",i+1); scanf("%f",&y[i]); }
for(i=0;i<3;i++){ xmed[i]=functii[i](y,f,n); printf("\n%12.10f",xmed[i]); } getch(); }
Exemplul 41. Da-i la execuie i analizai modul de organizare a apelurilor i obinere a rezultatelor prin antetul funciilor.
Face-i mbuntiri i rulai din nou. Comparai.
#include<stdio.h>
#include<conio.h>
typedef char* f();
f *a[2][2];
//o matrice de pointeri spre functii
char *s;
char *f1(){ return "functia1"; } char* f2(){ return "functia2"; }
char* f3(){ return "functia3"; } char* f4(){ return "functia4"; }
void main(){ clrscr(); a[0][0]=f1;
a[0][1]=f2;
a[1][0]=f3;
a[1][1]=f4;
for(unsigned char i=0;i<2;i++) for(unsigned char j=0;j<2;j++){ s=a[i][j](); printf("\n %s",s); } getch(); }
Exemplul 42: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
int main() { float *q, **b;
int i, j, k, n, m;
scanf("%d %d",&n,&m);
q=(float *)calloc(m,sizeof(float));
q[0]=22.3;
q-=5;
q[5]=1.5; /* num. elem.?*/
q[6]=2.5; /* num. elem.?- */
q[7]=3.5; /* num. elem.? - */
q+=5; /* */
q+=2; /* */
q[-2]=8.2;
q[-1]=4.5;
q-=2; /* */
q--; /* */
free(++q); /* */
b=(float **)calloc(m,sizeof(float *));
for (i=0; i < m; i++) b[i]=(float *)calloc(n,sizeof(float));
for (i=0; i < m ; i++) --b[i]; b--;
for (i=1; i<=m; i++) for (j="1;" j<="n;" j++) b[i][j]="(float)(i+j);"
for (i="1;" i<="m;" i++) ++b[i]; b++; /* */
for (i="0;" i < m; i++) free(b[i]); free(b); ... ... return 0; }
Exemplul 43: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
main() { int vvod(double ***, long **);
double **a; /* a[n][m] */
long *b;
/* b[n]
*/
vvod (&a,&b); /* */ }
int vvod(double ***a, long **b) { int n,m,i,j;
scanf (" %d %d ",&n,&m); *a=(double **)calloc(n,sizeof(double *));
*b=(long *)calloc(n,sizeof(long));
for (i=0; i<=n; i++) *a[i]="(double" *)calloc(m,sizeof(double)); }
Exemplul 44: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
#include . #include ..
double cos(double); double sin(double); double tan(double);
int main() { double (*(*masfun))(double);
double x=0.5, y; int i;
masfun=(double(*(*))(double)) calloc(3,sizeof(double(*(*))(double)));
masfun[0]=cos; masfun[1]=sin; masfun[2]=tan;
for (i=0; i<3; i++); { y="masfun[i](x);" printf("\n x="%g" y="%g",x,y);" }
return 0; }

Exemplul 45: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
#define n 3
int a[n][n],b[n][n];
void linii(int **a,int i,int j)
// cerina a)
{
int *p,*q,aux;
for(p=*(a+i),q=*(a+j);p<=*(a+i)+n-1;p++,q++)
{
aux=*p;*p=*q;
*q=aux;
}
}
void coloane(int **a,int i,int j)
// cerina b)
{
int *p,*q,aux;
for(p=*a+i,q=*a+j;p<=*(a+n-1)+i;p+=n,q+=n)
{
aux=*p;
*p=*q;
*q=aux;
}
}
int suma(int **a)
// cerina
c)
{
int *p,s=0; for(p=*a;p<=*(a+n-1)+n-1;p+=n+1)
s+=*p;
return s; }
int produs(int **a)
// cerina d)
{
int *p,pr=1; for(p=*a+n-1;p<=*(a+n-1);p+=n-1)
pr*=*p;
return pr;
}
void transpusa(int **a,int **b)
// cerina e)
{
int *p,*q,*r;
for(int i=0;i<n;i++)
for(p=*(a+i),q=p+n-1,r=*b+i;p<=q;p++,r+=n)
*r=*p;
}
Exemplul 46: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
#include <alloc.h>
main() {
#define NUMINTS 3
int *list,i;
list = (int *) calloc(NUMINTS,sizeof(int));
*list = 421;
*(list+1) = 53; *(list+2) = 1806; printf(":");
for (i=0; i<NUMINTS; i++) printf("%4p ",(list+i));
printf("\ :");
for (i=0; i<NUMINTS; i++) printf("%4p ",*(list+i));
printf("\n"); }
Exemplul47: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
#define n 3
int a[n][n],b[n][n];
void linii(int **a,int i,int j) // cerin]a a)
{
int *p,*q,aux;
for(p=*(a+i),q=*(a+j);p<=*(a+i)+n-1;p++,q++)
{
aux=*p;
*p=*q;
*q=aux;
}
}
//***********************
void coloane(int **a,int i,int j) // cerin]a b)
{ int *p,*q,aux;
for(p=*a+i,q=*a+j;p<=*(a+n-1)+i;p+=n,q+=n)
{
aux=*p;
*p=*q;
*q=aux;
}
}
//***********************
int suma(int **a) // cerin]a c)
{
int *p,s=0;
for(p=*a;p<=*(a+n-1)+n-1;p+=n+1)
s+=*p;
return s;
}
//***********************
int produs(int **a) // cerin]a d)
{
int *p,pr=1;
for(p=*a+n-1;p<=*(a+n-1);p+=n-1)
pr*=*p;
return pr;
}
//***********************
void transpusa(int **a,int **b) // cerin]a e)
{
int *p,*q,*r;
for(int i=0;i<n;i++)
for(p=*(a+i),q=p+n-1,r=*b+i;p<=q;p++,r+=n)
*r=*p;
}
Exemplul 48: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
#include <alloc.h>
main()
{
#define NUMINTS 3
int *list,i;
list = (int *) calloc(NUMINTS,sizeof(int));
*list = 421;
*(list+1) = 53; *(list+2) = 1806;
printf("Lista adreselor:");

for (i=0; i<NUMINTS; i++)


printf("%4p ",(list+i)); printf("\n Lista valorilor:");
for (i=0; i<NUMINTS; i++)
printf("%4p ",*(list+i)); printf("\n");
}
Exemplul 49: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
main()
{
int a[3][4] = {{ 5, 3, -21, 42},
{44, 15, 0, 6},
{97 , 6, 81, 2}};
int b[4][2] = {{22, 7},
{97, -53},
{45, 0},
{72, 1} };
int c[3][2],i,j,k;
for (i=0; i<3; i++) {
for (j=0; j<2; j++) {
c[i][j] = 0;
for (k=0; k<4; k++)
c[i][j] += a[i][k] * b[k][j];
}
}
for (i=0; i<3; i++) {
for (j=0; j<2; j++) printf("c[%d][%d] = %d ",i,j,c[i][j]);
printf("\n");
}
}
Exemplul 50: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Face-i mbuntiri i rulai din nou. Comparai.
#include<stdlib.h>
#include<stdio.h>
#include<conio.h>
#include<string.h>

char *mesaj, alegere;


main(){ while (1) { puts ("\nIntroducetsi 1,2 say 3; esc pentru a iesi din program"); alegere= getch();
switch(alegere) {
case 49: { if(mesaj = malloc(14)!=NULL) { strcpy(mesaj, "ati apasat 1"); break; }
else { puts("Insuficienta memorie, nu se poate de continuat"); exit(1); }
}
case 50: { if (mesaj=malloc(26)!=NULL) { strcpy(mesaj, "Ati apasat tasta 2"); break; }
else { puts("Insuficienta memorie, nu se poate de continuat"); exit(1);
}
}
case 51: { if (mesaj = malloc(24)!=NULL) { strcpy(mesaj, "De data asta atsi tastat 3"); break; }
else { puts("Insuficienta de memorie, nu se poate de continuat"); exit(1); } }
case 27: {
exit (0);
}
default:
{ ;
} } puts (mesaj); } }
Exemplul 51.: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
a).
...
int i, p, j, q;
p = &i;
q = &p;
j = p = 1;
q = p-1; p += 1;
i = ++q + p; q -= 1;
i = q ++ + q;
printf("i=%d, j=%d, p=%d, q=%d \n", i, j, p, q);
b)
...
int x = 1, y; char c = a;
int pi, qi; char pc;
pi = &x;pi = 3; y = pi; pi = c; qi = pi;
pc = qi; qi+=1; pi++;
(- - pi) = 5;
y = qi+1;
pc = &c;
++pc; (pc)++;
pc++; pc+=1;
x = (int)pi;
pi=(int)pc;
pi=(int)x;
x = 1+ pi;
pc=(char)pi;
c = pc; pc = &y;
x = qi pi;
qi = 0;
qi+=pi;
y = &pi;y = (int)&pi;
pi = pi +5;
(pi+1)=0;
pi=&(x+0);
Exemplul 52: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
a) int i = 2; const int j = 5;
int pi;
const int pci;
int const cpi;
const int const cpci;
pi = &i;
pci = &j;
cpi = &i;
cpci = &j;
pci = &i;
pi = (int)&j;
i = pci + pi;
pci = 3;

pi = 3;
i=pci++;
(cpi++)=5;
cpi++;
b) int f(const int i, int j) { j++; return i+j; }
main()
{ int a, b; const int c = 5;
scanf("%d", &a);
b = f(c,a); printf("a=%d, b=%d, c=%d \n", a, b, c);
b = f(c,c); printf("a=%d, b=%d, c=%d \n", a, b, c);
b = f(a,a); printf("a=%d, b=%d, c=%d \n", a, b, c);
b = f(a,c); printf("a=%d, b=%d, c=%d \n", a, b, c);
}
Exemplul53: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
a) int a[100], sum, i;
sum = 0;
for ( i = 0; i < 100; ++i ) sum += a[i];
b) int a[100], p, sum;
sum = 0;
for ( p = a; p < &a[100]; ++p ) sum = sum + p;
c) int a[100], p, sum;
sum = 0;
for ( p = &a[0]; p < &a[100]; p++ ) sum += p;
d) int a[100], sum, i;
sum = 0;
for ( i = 0; i < 100; ++i ) sum += (a+i);
e) int a[100], sum, i;
sum = 0;
for ( i = 0; i < 100; ++a, ++i ) sum += a;
f) int a[100], p, sum, i;
sum = 0;
for ( i = 0, p = a; i < 100; ++i ) sum += p[i];
g) int a[100], p, sum, i;
sum = 0;
for ( i = 0, p = a; i < 100; ++i ) sum += (p+i);
Exemplul54: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
a) . . .
int a[5] = { 1, 2, 3, 4, 5 };
int p, x, q , i;
p = a + 2;
(p+2) = 7;
a += 3;q=&p-1;
x = ++ p - q ++; x += ++ p;
x=p-- + p++;
for (i = 0; i < 5; i++) printf("a [%d]=%d", i, a[ i ] ); printf("\n");
printf("x=%d, p=%d, q=%d \n", x, p, q);
b) . . .
char str = "abcdef";
char p, q, r; int k;
p = str; q = 0;
p++;
k = p - str;
r = p+k;
if ( k && p || q ) q = str + 6;
p = q ? r : q;
(p-1) = a;
r = x;
printf("str: %s\n", str);
c)
...
char s[ ] = "0123456";
int pi; char pc1, pc2;
pc2 = s;
pc1 = s + (s+strlen(s) - 1) - 0;
pi = ( int ) pc2; pc1-- = 8;
if ( pc1 - pc2 < 3 ) pc1 = pc2 = pi; else pc1 = ( pc1+pc2 )/2;
if ( s == pc2 ) pc1 = pc2 + 1; else pc1 = 9;
printf("s: %s\n", s);
d) . . .
int i; char c; int pi;
i = a;
pi = &i; c = (char)pi + 3;
printf("c1=%c", c);

i <<= 8; c--;
printf("c2=%c\n", c);
e)
...
char c1, c2; short i;
char pc; short ps;
c1 = 1;c2 = 2;ps =&i;
pc = (char)ps; pc = c1;
pc++;
pc = c2;
printf("i = %hd\n", i);
Exemplul55: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
#include <stdio.h>
char str[ ] = "ABCDIREWIEWRHOWEHOWL5";
main()
{ int i, c;
for ( i = 2; ( c = str [ i ] ) != \0; i++) {
switch (c) {
case a: putchar(i); continue;
case 1: break;
case 1: while ( ( c = str [++ i ] ) != \1 && c != \0);
case 9: putchar(S);
case E: case L: continue;
default: putchar(c); continue; }
putchar( ); } putchar(\n); }
Exemplul56: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
#include <stdio.h>
int a[ ] = { 0, 1, 2, 3, 4 };
main()
{ int i, p;
for ( i = 0; i <= 4; i++ ) printf("a[ i ]=%d ", a[ i ]); printf("\n");
for ( p = &a[0]; p <= &a[4]; p++ ) printf("p=%d ", p); printf("\n");
for ( p = &a[0], i = 0 ; i <= 4; i++ ) printf("p[ i ]=%d ", p[ i ]); printf("\n");
for ( p = a, i = 0; p+i <= a+4; i++ ) printf(" (p+i)=%d ", (p+i));
printf("\n"); for ( p = a+4; p >= a; p-- ) printf("p=%d ", p ); printf("\n");
for ( p = a+4, i=0; i <= 4; i++ ) printf("p[ -i ]=%d ", p[ -i ]);
printf("\n"); for ( p = a+4; p >= a; p -- ) printf("a[ p - a ]=%d ", a[ p - a ]);
printf("\n");
}
Exemplul 57: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
#include <stdio.h>
int a[ ] = { 8, 7, 6, 5, 4 };
int p[ ] = { a, a+1, a+2, a+3, a+4 };
int pp = p;
main()
{ printf("a=%d p=%d pp=%d\n", a, p, pp );
pp++;
printf("pp-p=%d pp-a=%d pp=%d\n", pp-p, pp-a, pp );
++pp;
printf("pp-p=%d pp-a=%d pp=%d\n", pp-p, pp-a, pp );
pp = p;
++pp;
printf("pp-p=%d pp-a=%d pp=%d\n", pp-p, pp-a, pp );
}
Exemplul58: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
#include <stdio.h>
int a[ 3 ][ 3 ] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
int pa[ 3 ] = { a[ 0 ], a[ 1 ], a[ 2 ] };
int p = a[ 0 ];
main()
{ int i;
for ( i = 0; i < 3; i ++ )
printf(" a[ i ][ 2 i ]=%d a[ i ]=%d ((a+i)+i)=%d\n",
a[ i ][ 2 i ], a[ i ], ((a+i)+i));
for ( i = 0; i < 3; i ++ )
printf("pa[ i ]=%d p[ i ]=%d \n", pa[ i ], p[ i ] ); }
Exemplul 59: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.

#include <stdio.h>
char c[ ] = { "FIRST", "FOR", "WHILE", "DO" };
char cp[ ] = { c+3, c+2, c+1, c };
char cpp=cp;
main()
{ printf("%s", ++cpp );
printf("%s ", -- ++cpp+3 );
printf("%s", cpp[ -2 ]+3 );
printf("%s\n", cpp[ -1 ][ -1 ]+1 );
}
Exemplul 60: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Se introduc de la tastatur dou iruri de caractere oarecare. Utilizndu-se o funcie (de
comparare a celor dou iruri) apelat prin intermediul unui pointer la aceast functie s se afieze dac cele dou iruri sunt
sau nu identice oricare ar fi cele doua siruri.
#include <stdio.h>
#include <string.h>
//-------------------------------------------------------------// definirea functiei de verificare a doua siruri oarecare
void comparare_siruri (char *x, char *y, int ( *comp) (const char *,const char *))
{printf(\n verificarea egalitatii sirurilor);
if((*comp)(x,y)) /* apelarea functiei comp prin pointer catre aceasta */
printf(\n sirul %s nu este egal cu sirul %s,a,b);
else printf(\n sirul %s este egal cu sirul %s,a,b);
}
//-------------------------------------------------------------// functia principala
void main(void) {char sir1[50],sir2[50],raspuns=d;
int (*ptrfunctie) ();
// memorarea in ptrfunctie a adresei punctului de intrare in functia de comparare a doua siruri strcmp
ptrfunctie = strcmp;
while(raspuns == d) {gets(sir1); gets(sir2);
// apelarea functiei de comparare siruri
compara_siruri(sir1,sir2,ptrfunctie);
printf(\n continuati ?(d/n):);
raspuns = getchar();
}
}
//-------------------------------------------------------------Exemplul 61: Evaluai n programul dat expresia : **(*(*x)[i]).y[j]) Explicai modul de rezolvare i rezultatul obinut:
#include<stdio.h>
#include<conio.h>
typedef int a; typedef a *pa; typedef pa *ppa;
typedef ppa v1[2];
struct r1 { v1 y; }; typedef struct r1 *pr1; typedef pr1 v2[2]; typedef v2 *pv2; a n1,n2,m1,m2;
pa pn1,pn2,pm1,pm2; ppa ppn1,ppn2,ppm1,ppm2; struct r1 art1,art2; v2 vec; pv2 x;
void main() { clrscr(); n1=100; n2=101; pn1=&n1; pn2=&n2; ppn1=&pn1; ppn2=&pn2; art1.y[0]=ppn1;
art1.y[1]=ppn2; m1=200; m2=201; pm1=&m1; pm2=&m2; ppm1=&pm1; ppm2=&pm2;
art2.y[0]=ppm1; art2.y[1]=ppm2; vec[0]=&art1; vec[1]=&art2; x=&vec;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) printf("\n **(*(*x)[i]).y[j]=== %d ",i,j,**(*(*x)[i]).y[j]); getch(); }
Exemplul 62: Evaluai programul dat i explicai modul de rezolvare i rezultatul obinut:
#include<dos.h>
#include<stdio.h>
unsigned int aaa, bbb; int a[3][3][3]; int *vp[3]; int *pp; int j,k; char rasp=1;
void main(){ clrscr();
for(int i=0;i<3;i++) for(j=1;j<3;j++) for(k=0;k<3;k++) a[i][k][j]=0;
for(i=0;i<3;i++) vp[i]=&a[i][0][0];
while(rasp!= ){ printf("\nintroduceti coordonatele:\n "); printf("\ncoordonata i : ");scanf("%d",&i);i--;
printf("coordonata j : ");scanf("%d",&j);j--; printf("coordonata k : ");scanf("%d",&k);k--;
aaa=FP_SEG(vp[i]); bbb=FP_OFF(vp[i]); aaa+=(j*3+k)*2; bbb+=(j*3+k)*2;
pp=(int *)MK_FP(aaa,bbb); printf("\ndati elementul: "); scanf("%d",pp);
printf("\nContinuati introducerea? [pentru nu,tastati spatiu]: "); fflush(stdin);scanf("%c",&rasp); }
for(i=0;i<3;i++){ for(j=0;j<3;j++){ for(k=0;k<3;k++) printf(" %d ",a[i][j][k]); printf("\n"); }
printf("\n*******\n"); } getch(); }
Exemplul 63: Rulai, afiai i analizai
#include <stdio.h>
#include <string.h>
// definirea functiei de verificare a doua siruri oarecare
void comparare_siruri (char *x, char *y, int ( *comp) (const char *,const char *))
{printf(\n verificarea egalitatii sirurilor);
if((*comp)(x,y)) /* apelarea functiei comp prin pointer catre aceasta */
printf(\n sirul %s nu este egal cu sirul %s,a,b);
else printf(\n sirul %s este egal cu sirul %s,a,b); }

// functia principala
void main(void) {char sir1[50],sir2[50],raspuns=d;
int (*ptrfunctie) (); // memorarea in ptrfunctie a adresei punctului de intrare in functia de comparare a doua siruri strcmp
ptrfunctie = strcmp;
while(raspuns == d) {gets(sir1); gets(sir2);
// apelarea functiei de comparare siruri
compara_siruri(sir1,sir2,ptrfunctie);
printf(\n continuati ?(d/n):); raspuns = getchar(); } }
Exemplul 64: Rulai, afiai i analizai. Matrice alocata dinamic (cu dimensiuni cunoscute la executie)
#include <stdio.h>
#include <stdlib.h>
int main () {int n,i,j;

int ** mat; // adresa matrice


// citire dimensiuni matrice<
printf("n="); scanf("%d",&n);
// alocare memorie ptr matrice
mat=(int **) malloc (n*sizeof (int*));
for (i=0;i<n;i++)
mat[i] =(int*) calloc (n,sizeof (int));
// completare matrice
for (i=0;i<n;i++)
for (j=0;j<n;j++) mat[i][j]= n*i+j+1;
// afisare matrice
for (i=0;i<n;i++) {
for (j=0;j<n;j++)
printf ("%6d ",mat[i][j]);
printf ("\n");
} return 0; }
Exemplul 65: Rulai, afiai i analizai. Pointeri la pointeri (indirectare multipla). Limbajul C permite realizarea indirectarii
multiple prin faptul ca un pointer poate fi pointat de un alt pointer.
#include<stdio.h>
char *m[]= {"ianurie", "februarie", "martie",
"aprilie","mai","iunie","iulie","august","septembrie","octombrie","noiembrie","decembrie"}; // initializare poiterilor la masiv
char **mp[]= {m+11,m+10,m+9,m+8,m+7,m+6,m+5,m+4,m+3,m+2,m+1,m};/*initializare poiterilor
catre m*/
char ***mpp[]= {mp, mp+9,mp+6,mp+3};//initializarea poiterilor catre mp
char ****mppp=mpp; //atribuirea pointerului mppp la masivul mpp
main() {
int i;
printf("%s \n\n", ***++mppp); // va afisa martie
printf("%s \n\n", ***--mppp);// va afisa decemrie
for(i=0;i<12;i++)
printf("%s %c",mppp[0][0][i-11],(i==6)?'\n':' '); //va afisa lunile in ordine normala
printf("\n\n");
for(i=0;i<12;i++)
printf("%s %c",mppp[1][2][11-i],(i==5)?'\n':' '); va afisa lunile in ordine inversa
printf("\n\n");
printf(" %s \n",*mppp[3][1]);// va afisa cuvintul august
printf(" %s \n",**mppp[1]+5);// va afisa literea e din cuvintul martie
printf("%s \n",mppp[2][-1][3]+2);//va afisa o parte tombire din octomrie
for(i=0;i<9;i++) printf("%s \t",mppp[3][-2][-9]+i); /*stergerea pe rind a primei litere din cuvintul februarie pina la ultima litera */
}
Exemplul 66: Modificai programul prin parcurgeri de pointeri i cu pointeri la pointeri (indirectare multipla). Apoi Rulai,
afiai i analizai
#include <conio.h>;
#include <stdio.h>;
#include <stdlib.h>;
void main() { int *p,*a,i,j,n,k,s,l; char ch; clrscr(); printf("Indicati dimensiunea matricei:"); scanf("%d",&n);
a=(int *) malloc(n*n); //Alocarea dinamica a memoriei
p=a; // pointu p se initializeaza cu pointu a
for(i=0;i<n;i++)
for(j=0;j<n;j++) { printf("a[%d,%d]=",i+1,j+1);
scanf("%d",p++); } //Se introduce valori in pointu p si pointu p intorudce valorile in pointu a
while(1) { clrscr();
printf("1 - afisarea elementelor prime\n");
printf("2 - suma elementelor impare\n");
printf("3 - frecventa elementului indicat\n");
printf("4 - iesire\n");
ch=getche();
switch (ch) {
case '1' : clrscr(); printf("Elementele matricei sunt:\n"); p=a; //initializarea pointurului p cu a
for(i=0;i<n;i++) {
for(j=0;j<n;j++)
printf(" %d",*p++); printf("\n"); } // afisharea valorilor din point
printf("Elementele prime ale liniilor impare sunt:\n");
p=a; // Initializam pointu p cu pointu a
for(i=0;i<n;i+=2) {
for(j=0;j<n;j++) {
k=1;s=0;

case '2' : clrscr();

while(k<=*p && *p!=0)


{ if(*p%k==0) s++; //daca valoarea pointului p la impartire cu k =0
k++; }
if(s==2 || *p==1) //daca cointu p =1
printf(" %d",*p); p++; } // afisharea valoarea pointului p
p+=n; } getch();break;
printf("Elementele maricei sunt:\n");
p=a; //initializam pointu p cu pointu a
for(i=0;i<n;i++) {
for(j=0;j<n;j++)
printf(" %d",*p++); printf("\n"); } // afisham valorile pointului p
printf("Suma elementele impare ale coloanelor pare sunt:\n");
s=0; p=a; //Initializam pointu cu poinru a
for(i=0;i<n;i++)
for(j=1;j<n;j+=2)
if(*(p+i*n+j)%2==1) //daca valoarea p[i][j]/2==1
s+=*(p+i*n+j); //la s se adauga valoarea p[i][j]
printf("s=%d",s); getch(); break;

case '3' : clrscr(); printf("Elementele maricei sunt:\n");


p=a;
for(i=0;i<n;i++) {
for(j=0;j<n;j++)
printf(" %d",*p++); printf("\n");}//afisez valoarea pointului
printf("Indicati numarul la care doriti sa aflati frecventa: ");
scanf("%d",&k);
s=0; p=a; // initializarea pointului p cu poitu a
if(n%2==0)
l=n/2-1;
else l=n/2;
for(i=0;i<l;i++)
for(j=i+1;j<n-i-1;j++)
if(*(p+i*n+j)==k) s++; //daca pointu p[i][j]=k
printf("\n Frecventa in cadranul 1 este: %d",s);
s=0;
for(i=n/2+1;i<n;i++)
for(j=i-1;j>=n-i;j--)
if(*(p+i*n+j)==k) s++; //daca pointu p[i][j]=k
printf("\n Frecventa in cadranul 3 este: %d",s); getch(); break;
case '4' : getch(); exit(1); break;
default: printf("\nTastati intre 1 si 3 !\n");
getch();
}
}
}
Exemplul 67: Analizati efectele utilizarii pointerilor la pointeri de caractere prin precizarea valorilor care se afiseaza pe
ecran la executia programului:
#include<stdio.h>
void main(void) {
char *psir[]={"unu","doi","trei","patru"};
char **ppsir[]={psir+3,psir+2,psir+1,psir};
char ***pppsir=ppsir;
printf("\n%s",**++pppsir); printf("\n%s",*--*++pppsir+3); printf("\n%s",*pppsir[-2]+3); printf("\n%s",pppsir[-1][-1]+1);
int a[10]={1,10,20,30,40,50,60,70,80,90} int b[10]={100,200,300,400,500,600,700,800,900,1000}; int *pa=a,*pb=b;
printf("\n *pa+*pb=%d",*pa+*pb); printf("\n *pa++ +*pa++=%d",*pa++ + *pb++);
printf("\n ++*pa + *pb++=%d",++*pa + *pb++); printf("\n *pa++ + ++*pb=%d",*pa++ + ++*pb);
printf("\n *pa++ + *pb++=%d",*pa++ + *pb++); }
Exemplul 68: Analizati efectele utilizarii funciilor de caractere prin precizarea valorilor care se afiseaza pe ecran la executia
programului:
#include <stdio.h>
int a[5][5; int b[25]; int i,j;
void f1(void) {
int q=0,w=0; printf("introduceti vectorul");
while(i<25){scanf("%d",&b[i]);i++;}
for(i=0;i<25;i++)
{
a[q][w]=b[i];
if(w<4){w++;}
else
if(q<4){q++;w=0;}
}
printf("matricea obinut din vector este:");

for(i=0;i<5;i++){printf("\n"); for(j=0;j<5;j++) printf(" %d ",a[i][j]);} exit(); }


void f2(void) {
int k=0; char t=0;
for(i=0;i<5;i++) for(j=0;j<5;j++) { scanf("%d",&a[i][j]);}
for(i=0;i<5;i++) for(j=0;j<5;j++)
{
b[k]=a[i][j];
k++;
}
printf("vectorul primit din matrice e:");
for(i=0;i<k;i++) printf(" %d \n",b[i]); }
main()
{printf("1:matrice->vector\t2:vector->matrice\n");
if(getchar()=='2') {f1();} else f2(); }
Exemplul 69: Rulai, afiai i analizai.
void main()
{ int *pi, i=10; float *pf, f=12.5; double *pd, d=0.001; char *pc, c=a;
*pi=i; *pf=f; *pd=d; *pc=c;
printf(pi=%p, pf=%p, pd=%p, pc=%p, pi, pf, pd, pc);
printf(*pi=%i, *pf=%f, *pd=%e, *pc=%c, *pi, *pf, *pd, *pc);
printf(pi++ =%p, pf++ =%p, pd++ =%p, pc++=%p, pi++, pf++, pd++, pc++);
printf((*pi)++ =%p, (*pf)++ =%p, (*pd)++ =%p, (*pc)++ = %p, (*pi)++ , (*pf)++, (*pd)++, (*pc)++);
}
Exemplul 70: Da-i la execuie i analizai modul de organizare a parcurgerii i obinere a rezultatelor prin pointeri i
indeci, afind toate valorile. Dac sunt construcii inadmesibile, face-i corectri cu explicaii i rulai din nou. Comparai.
#include <stdio.h>
int a[ ] = { 8, 7, 6, 5, 4 };
int p[ ] = { a, a+1, a+2, a+3, a+4 };
int pp = p;
main() { printf("a=%d p=%d pp=%d\n", a, p, pp );
pp++;
printf("pp-p=%d pp-a=%d pp=%d\n", pp-p, pp-a, pp );
++pp; printf("pp-p=%d pp-a=%d pp=%d\n", pp-p, pp-a, pp );
pp = p; ++pp; printf("pp-p=%d pp-a=%d pp=%d\n", pp-p, pp-a, pp ); }
Exemplul 71: Da-i la execuie i analizai modul de organizare a apelurilor i obinere a rezultatelor prin antetul
funciilor. Face-i mbuntiri i rulai din nou. Comparai.
#include<stdio.h>
#include<conio.h>
#include<alloc.h>

int intreg=22;

int *p_int;
//pointer spre intreg
int **pp_int; //pointer spre pointer
void main(){ clrscr(); p_int=(int *)malloc(sizeof(int)); p_int=&intreg; pp_int=(int **)malloc(sizeof(int*));
pp_int=&p_int; printf(" %d %d ",*p_int ,**pp_int); getch(); }
Bibliografie:
1. ."Limbajul de programare C". Brian W.Kernighan. Dennis M.Ritchie.
2. Liviu Negrescu. Limbajul de programare C i C++ V.1-4. Buc. 1999
3. Knuth, D. E. - "Arta programarii calculatoarelor, vol. 1: Algoritmi fundamentali", Ed. Teora, 1999.
4. Knuth, D. E. - "Arta programarii calculatoarelor, vol. 2: Algoritmi seminumerici", Ed. Teora, 2000.
5. Knuth, D. E. - "Arta programarii calculatoarelor, vol. 3: Sortare si cautare", Ed. Teora, 2001.
6. Bacivarov, A.; Nastac, I. - "Limbajul C. Indrumar de laborator", Tipografia UPB, Bucuresti, 1997.
7. Bates, J; Tompkins, T. - "Utilizare C++", Ed. Teora 2001.
8. Ionescu Texe, C.; Zsako, I. - "Structuri arborescente si aplicatiile lor", Ed. Tehnica, 1990.
9. Andonie, R.; Gabarcea, I. - "Algoritmi fundamentali. O perspectiva C++", Ed. Libris, 1995.
10.
Help din Turbo C ++IDE ,versiunea 3.0. 1999
11.
CORMEN, T. LEISERSON, CH. RIVEST, R.: Introducere in algoritmi, Ed. Comp Libris.
Agora, Cluj, 2000.
12.
D. Lucanu: Bazele proiectarii programelor si algoritmilor, Universitatea A.I.Cuza Iasi, 1996
13.
L. Livovschi, H. Georgescu: Sinteza si analiza algoritmilor, Ed. Stiintifica si enciclopedica, 1986
14.
Cristea Valentin. Tehnici de programare. Ed.: Bucur., Teora, 1993. /681.3; T29/
15.
Odagescu Ioan, Copos Cristina s.a. Metode si Tehnici de programare./enunuri, solutii, probleme propuse/
Ed.:Bucur.: INTACT, 1994 /681.3; O23/
16.
Tudor Blnescu. Corectudinea agoritmilor.Bucur.:Ed. Tehn.1995
17. Conspectele la PC 2015 i SDA-2016