c pointeri ll1sda16

Upload: dani-lungu

Post on 08-Mar-2016

19 views

Category:

Documents


1 download

TRANSCRIPT

POINTERI din C Standard

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 analizeze 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 pointelorVariabile 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.

Zona de memorie este o succesiune de 1 , 2 , 4 , 8 sau mai multe locaii ( 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 - adrese postale

Variabila (nume pointer) Fac_CIM

Valoare adresa str. Studenilor 3

Entitate 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

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

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. Intr-un 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

cu valoarea 7

void main()

respectic 97.

{int x = 7, y = 97, s = 0;

int *px, *py; px x Fie ca variabila x se afla

pe adresa 6000, iar

5000 6000 variabila pointer pe

//Luam adresa variabilelor x, y: adresa 5000. px se

px = &x; adreseaz indirect la variabila cu valoarea 7. Analog

py = &y; py se adreseaz indirect la variabila cu valoarea 97.

//Suma x + y

s = (*px) + (*py); Operatia *, returneaz valoarea obiectului la care

operandul (pointerul) pointeaz: s = 7 + 97

//Afisarea Sumei

printf("\nSuma=%d\ ",s,); }

Exemplu 8. Rulai, afiai i analizaiIn 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 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