pointer - limbajul c

Upload: andrei-luca

Post on 06-Apr-2018

223 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/3/2019 Pointer - limbajul C

    1/13

    Curs 7 Pointeri

    1

    PointeriPointerii sunt tipuri speciale variabile sau constante care au ca valori adrese ale unor alte

    variabile sau constante, adic adrese ale unor locaii de memorie. Ei permit calcule cu adrese,calcule care sunt specifice limbajelor de asamblare i sunt folosii n scopul scrierii unor programemai eficiente att din punctul de vedere al timpului de execuie ct i din punctul de vedere alutilizrii resurselor hard, n mod concret al utilizrii memoriei computerelor.Pointerii sunt n mod special utili la alocarea dinamic a memoriei [Beu99] i la apelul prin

    referin.Pentru a nelege mai uor pointerii este convenabil ca acetia s fie discutai prin

    comparaie cu variabilele normale.O variabil "normal" este o locaie de memorie care pstreaz o anumit valoare. Am vzut ncapitolele precedente c la declararea unei variabile, acesteia i se aloc un anumit numr de octei,iar referirea la valoarea stocat n acei octei se face prin numele respectivei variabile. La nivelmain, respectiva locaie are o adres de memorie. Dac de exemplu, variabila declarat este sdetip float, cei 4 octei care ncep la adresa locaiei respective sunt cunoscui programatorului ca i si pe aceti 4 octei pot fi stocate valori reale n simpl precizie.

    Pointerii nu pstreaz o valoare n sens tradiional ci adresa nceputului locaiei n care estestocat o anumit valoare. Deoarece pointerii pstreaz adrese i nu valori "tradiionale", ei pot fivzui ca un pachet compus din dou pri: pointerul nsui, care are ca valoare adresaprimului octet al locaiei de memorie n care este stocat o variabil (sau constant) i tipul valoriistocate n locaia de memorie la nceputul creia pointeaz. Acest tip spune computerului ctmemorie s citeasc dup adresa la care pointeazi cum s o interpreteze.

    Limbajul C folosete pointerii n trei moduri:a) pentru a crea structuri dinamice de date construite din blocuri de memorieb) pentru a opera cu parametrii pasai funciilor la apelul acestorac) pentru a accesa informaia stocat n tablouri.

    In C, exist o legtur intim ntre tablouri i pointeri.

    n cazul unui pointer la o funcie, tipul pointerului va fi tipul de dat returnat de ctre funcie, iarvaloarea sa va fi adresa la care ncepe codul funciei respective.Pentru lucrul cu pointeri, limbajul C ofer doi operatori: &i * care se folosesc n faa numelui uneivariabile sau constante. Astfel, &x nseamn adresa variabilei x (de fapt adresa primului octet allocaiei de memorie n care este stocat variabila x), iar *p1 valoarea stocat n locaie de memoriela care pointeaz pointerul p1.

    Declararea i iniializarea pointerilorPointerii se declar ca orice variabil, deosebirea constnd doar n faptul c numele lor este

    precedat de caracterul * care reprezeint operatorul unar de indirectare sau de derefereniere.

    Exemple de locaii de memorie, adrese, pointer

  • 8/3/2019 Pointer - limbajul C

    2/13

    Curs 7 Pointeri

    2

    Pentru iniializarea pointerilor se poate folosi operatorul unar &, numit operator de refereniere icare returneaz adresa argumentului su.

    Declararea pointerilor se face n modul urmtor:tip*nume_pointer; sau tip* nume_pointer;

    unde tipeste un tip de date de baz sau tip utilizator, iar nume_pointereste un identificator folositpentru pointerul care se declar.

    Exemple

    1.float *pf;//pf poate conine adrese la care se afl memorate date de tipfloatint *pi; //pi poate conine adrese la care se afl memorate date de tipintchar* pc; //pc poate conine adrese la care se afl memorate date de tipchar

    2.struct agenda{

    char nume[20];

    char tel[15];

    };

    struct agenda *psa;//psa este un pointer la date de tip structur agenda.

    Iniializarea pointerilor const n precizarea adresei unui obiect definit n memorie. Dac p estenumele unui pointer, atunci *p reprezint valoarea de la adresa la care "pointeaz" pointerul p.

    Exemple1.double a, *pd;

    a=8.406;

    pd=&a;

    2. int n=1, m=2, s[10];

    int *pi; // pi este un pointer la tipul ntregpi = &n; // pi pointeaz acum la nm = *pi; // m are valoarea de la adresa lui n, adic 1*pi = 0; // n are acum valoarea 0pi = &s[0]; // pi pointeaz acum la s[0], adic are ca

    // valoare adresa elementului s[0]*pi=5*m; // s[0] are acum valoarea 5*1=5

    3. float pi, *p;

    p=*p=3.14159;

    Prin ultima instruciune i se atribuie de fapt lui pi valoarea 3.14159.La declarea i iniializarea pointerilor constani se va ine cont de faptul c printr-o construcie deforma:

    const int* pi=&i;

    se declar un pointer neconstant la o constant ntreag, iar printr-o construcie de forma:int* const pi=&i;

    se declar un pointer constant la un ntreg.

  • 8/3/2019 Pointer - limbajul C

    3/13

    Curs 7 Pointeri

    3

    n primul caz pointerul pi poate lua diferite valori n timp ce i va fi o constant. n al doilea caz,ntregul i poate fi modificat prin intermediul pointerului dar nu poate fi modificat pointerul pentru apointa la altceva.De asemenea, la declararea pointerilor ntr-o singur declaraie se va ine cont de faptul c printr-odeclaraie de forma:

    int* p1, p2, p3;

    numai p1 este pointer, n timp ce p2 i p3 sunt ntregi. Astfel dac se dorete declararea tuturor

    celor trei pointeri se poate proceda fie sub forma:int *p1, *p2, *p3;

    fie sub forma:int* p1;

    int* p2;

    int* p3;

    Prin declaraia urmtoare:float *pf1, fact(int *);

    se declar pointerul pf1 la tipulfloat i o funcie factcare returneaz o valoare de tip float icare are ca argument un pointer la tipulint.Un pointer este constrns s pointeze la un anumit tip de date. Astfel, dac a fost declarat unpointer la tipul float, ca i n declaraia de mai sus, atunci el nu va putea avea ca valori adrese

    ale unor locaii de memorie unde sunt stocate date de tip ntreg.

    Program exemplu

    #include

    #include

    void main()

    {

    float a,b;

    float* p;

    p = &a;

    *p=4*atan(1.0);

    b=2*a;printf("a=%f b=%f",a,b);

    printf("\nValoarea din locatia de memorie la care pointeaza p este %f

    \nAdresa lui a: %X", *p, p);

    }

    Output-ul acestui program este:

    i rezult dup parcurgerea etapelor schiate n figura urmtoare:

    Dup seciunea de declaraii, variabilele a i b au valori arbitrare, iar pointerul p, nefiind iniializat,poate pointa oriunde.Dup instruciuneap=&a; p va pointa la locaia de memorie rezervat variabilei a i va avea cavaloare adresa primului octet al acestei locaii.Dup instruciunea*p=4*atan(1.0); coninutul locaiei de memorie la care pointeaz p, adicvaloarea lui a, va fi de 4 ori arcul al crui tangent este 1 (n radiani), adic 3.141593, iar dupinstruciunea b=2*a;, valoarea variabilei b va fi 6.283185.

  • 8/3/2019 Pointer - limbajul C

    4/13

    Curs 7 Pointeri

    4

    Etapele execuiei programului precedent

    ExerciiuAnalizai output-ul generat de urmtoareasecven de program:int *i;

    printf("%X\n",i);

    printf("introduceti o valoare

    intreaga: ");

    scanf("%d",i);printf("%d\n",*i);

    printf("%X\t\n",i);

    printf("%X",++i);

    Care este numele variabilei a crei valoare setiprete n urma celui de-al treilea apel alfunciei scanf?

    O atenie special va fi acordatiniializrii pointerilor deoarece pointeriineiniializai indic adrese nevalide. Astfel, nurma unei declaraii i iniializri de forma:

    int *p;

    *p = 4;

    pointerul neiniializat p pointeaz la o locaie aleatoare de memorie care poate fi una din zonavariabilelor globale sau n spaiul programului obiect sau chiar n zona sistemului de operare. Prinatribuirea*p=4;programul va ncerca s scrie valoarea 4 n locaia arbitrar la care pointeaz pceea ce poate duce la ieirea din execuie sau la blocarea programului sau chiar la coruperea unordate ale sistemului de operare i blocarea acestuia. Aadar, nainte de dereferenierea pointeriloracetia trebuie s fie iniializai cu adrese valide.

    O alt eroare care se poate face cu pointerii este o referina nevalid care poate fi produsprintr-o atribuire de forma p1=p2;, unde p1 i p2 sunt pointeri, iar p2 este neiniializat. Oricereferin la *p1 va produce o referin nevalid.

    Un alt tip de eroare cu pointeri este referina la pointeri nuli. O astfel de eroare se producecnd un pointer care pointeaz la zero, respectiv la pointerul NULL este folosit pentru a facereferin la un bloc de date. Astfel, dac p este un pointer la tipul ntreg, secvena de cod

    p = 0;

    *p = 12;

    este nevalid deoarece nu exist nici un bloc de date la care s pointeze p. In consecin,ncercarea de a citi sau scrie acel bloc de date conduce la o referin nevalid.Menionm c exist cazuri n care un pointer poate pointa la zero, doar dereferenierea unui astfelde pointer fiind nevalid.Un program poate testa dac un pointer va pointa la o adres legal sau nu.

    Exemplu

    int* pi=0;

    ...

    if(pi!=0)n=*pi; //se folosete pointerul dac pointeaz la o adres legal (valid)

    n loc de valoarea 0 (zero) se poate folosi macroul NULL, aceast valoare pentru un pointerindicnd de asemenea o adres nevalid. Astfel, exemplul precedent poate fi rescris sub forma:

    #include

    #include

    void main()

    {

  • 8/3/2019 Pointer - limbajul C

    5/13

    Curs 7 Pointeri

    5

    int* pi=NULL;

    int n;

    scanf("%d",&n);

    if(n

  • 8/3/2019 Pointer - limbajul C

    6/13

    Curs 7 Pointeri

    6

    i=&a;

    printf("%X\n",i);

    for(j=0;j

  • 8/3/2019 Pointer - limbajul C

    7/13

    Curs 7 Pointeri

    7

    while(*p)

    putchar(*p++); //se va tipri sirul BorlandC

    3.double a[15],t;t=*(a+3); //este echivalent cu t=a[3];

    Program exemplu: adunarea elementelor unuiir folosind pointeri

    #include #include

    #include

    void main()

    {

    float x[100], *y,v;

    double s=0.0,med;

    int i;

    //genereaza aleator elementele sirului x

    randomize();

    for(i=0;i

  • 8/3/2019 Pointer - limbajul C

    8/13

    Curs 7 Pointeri

    8

    Apelul prin referin utiliznd parametri de tip pointer

    Apelul funciilor poate fi fcut n dou moduri i anumeprin valoare, caz n care funciei ise transmite valoarea argumentului i respectiv prin referin, caz n care funciei i se transmiteadresa argumentului.

    Astfel, un apel de forma:f(x)

    este un apel prin valoare deoarece funciei f i se transmite valoarea argumentului x, iar un apel deforma:

    g(&x)este un apel prin referin deoarece funciei g i se transmite adresa variabilei x.

    Antetele celor dou funcii vor fi de forma:void f(int x)

    respectiv:void g(int *pi)

    Un tablou poate fi transferat unei funcii n dou moduri.S presupunem c vrem s construim o funcie care tiprete elementele unui ir la ieireastandard. O versiune a acestei funcii ar putea fi de forma:

    void printsir(float sir[],int dim)

    {

    int i;

    for (i=0; i

  • 8/3/2019 Pointer - limbajul C

    9/13

    Curs 7 Pointeri

    9

    Program exemplu: ordonarea unuiir folosind pointerii funcie care returneazun pointer lairulordonat

    #include

    void printsir(float *p, int dim)

    {

    int i;

    for (i=0; i

  • 8/3/2019 Pointer - limbajul C

    10/13

    Curs 7 Pointeri

    10

    void sc2(double *i, double *j)

    {

    double t;

    t=*i;*i=*j;*j=t;

    }

    void main()

    {double a,b;

    printf("Adresa la care incepe codul functiei sc1 este: %X\n",sc1);

    scanf("%lf%lf",&a,&b);

    sc1(a,b);

    printf("\nApelul functiei sc1:\na= %lg\tb=%lg",a,b);

    sc2(&a,&b);

    printf("\nApelul functiei sc2:\na= %lg\tb=%lg",a,b);

    }

    Un exemplu de output al acestui program este:

    Dup cum se vede, funcia sc1 nu interschimb valorile variabilelor din funcia apelant ci numaicopii ale acestora. Pe de alt parte, funcia sc2, al crui apel se face prin referin, realizeazinterschimbarea celor dou valori. Aadar, argumentele de tip pointer permit funciilor s accesezei s modifice valorile variabilelor funciei apelante.

    ExerciiuS se scrie o funcie care s returneze 1 dac se citete un numr de la tastaturi s returneze 0

    n caz contrar. Vezi funcia getint din B.W. Kernighan and D.M. Ritchie, The C ProgrammingLanguage, pag. 81,http://madison-project.wdfiles.com/local--files/tutorials/The_C_Programming_Language.pdf].

    Pointeri la funciiLa fel ca i numele unui tablou i numele unei funcii este un pointer la funcia respectiv,

    adic numele funciei este o reprezentare n mod intern a adresei la care ncepe codul funciei.Pointerii la funcii se utilizeaz pentru transmiterea funciilor ca parametri ai altor funcii.

    Exemplu

    Dac dorim ca funcia f s apeleze funcia g sub forma f(g), funcia g avnd antetul:float g(int x)

    atunci antetul lui f trebuie s fie de forma:double f (float (*) (int))

    Exemplu//Funcia bisect are ca parametru o alt funcie f

    //======================= Functia f =========================

    double f(double x)

    {

    return x-sqrt(2);

  • 8/3/2019 Pointer - limbajul C

    11/13

    Curs 7 Pointeri

    11

    }

    //======================Functia bisect =======================

    double bisect(double inf, double sup, double (*pf)(double))

    {

    double c,sol;

    if((*pf)(inf)==0) return inf;

    if((*pf)(sup)==0) return sup;

    if((*pf)(inf)*(*pf)(sup)>0){

    printf("\n\a\aNu exista sol sau exista sol. multiple");

    getch();

    exit(1);

    }

    do

    {

    c=(inf+sup)/2.0;

    if((*pf)(c)==0) return c;

    if((*pf)(inf)*(*pf)(c)= eps);

    return c;

    }

    //=================Apelul functiei bisect=======================

    s=bisect(A,B,f);

    Tablouri de pointeri; pointeri la pointeriDeoarece pointerii sunt variabile i ei pot fi stocai n tablouri. Un astfel de tablou de

    pointeri ar putea fi util la scrierea unui program care s sorteze ntr-o anumit ordine liniile unuitext de input (vezi [Ker88], pag.91).Un tablou de pointeri se declar la fel ca orice tablou, diferena constnd n faptul c elementeletabloului sunt pointeri.

    Exemple

    char *pr[1000];//tablou cu maxim 1000 de elemente; elementele sunt pointeri la tipul charint *ptr[100]; //tablou cu maxim 100 de elemente; elementele sunt pointeri la tipulint

    Structuri de date dinamice n CStructurile de date dinamice sunt structuri care i modific dimensiunea prin alocarea i

    eliberarea (dealocarea) memoriei dintr-o zon special de memorie numit "heap". Acestea suntextrem de importante n C deoarece permit programatorului s controleze exact consumul dememorie al unui program.Structurile dinamice aloc blocuri de memorie din heapn funcie de necesiti, iar managementulacestor blocuri se face folosind pointeri. Cnd anumite structuri de date nu mai sunt folosite, elevor returna blocurile corepunztoare memoriei heap, pentru a fi refolosite de ctre orice program,realizndu-se astfel o utilizare eficient a memoriei.Memoria heap este o zon aparte de memorie corespunztoare unui program, folosit pentrucrearea i distrugerea structurilor de date care au timp de via limitat.Dup cum este schematizat n Figura 1, conceptual, memoria alocat unui program este mprit

    n patru segmente: segmentul corespunztor codului executabil, segmentul corespunztorvariabilelor globale, segmentul de memorie stivi segmentul memoriei heap.

  • 8/3/2019 Pointer - limbajul C

    12/13

    Curs 7 Pointeri

    12

    Segmentul cod conine biii corespunztori instruciunilor programului i acest segment dememorie este determinat de ctre compilator i link-editor. Tot aici sunt incluse funciile debibliotec ce sunt adugate programului. In general, aceast memorie este de tip "read-only".

    Segmentul de memorie corespunztor variabilelor globale ale programului, numit isegment de date statice, este folosit pentru stocarea variabilelor globale.

    Segmentul memoriei stiv pstreaz variabilele locale i parametrii unei funcii. Un cadrustiv este creat la apelul unei funcii i este eliberat la ncetarea execuiei funciei respective. Lafiecare apel al unei funcii, variabilele sale locale i parametrii si sunt mpinse n memoria stiv. Laieirea din funcie, aceste variabile i parametri sunt eliminai din stiv. Din aceast cauz,mrimea memoriei stiv a unui program, chiar dac are o valoare maxim, se modific continuu ntimpul execuiei programului.

    Memoria heapeste o zon de memorie complet separat, controlat de ctre un managerde memorie de tip "run-time", care face managementul memoriei n timpul execuiei programului.De fapt acest manager de memorie este o funcie de bibliotec adugat programului aflat nexecuie.

    Dac un program folosete structuri dinamice n memoria heap, atunci cnd aceste structurinu mai sunt folosite, managerul de memorie va marca blocurile de memorie corespunztoareacestora ca fiind libere. Atunci cnd un program de aplicaii i ncheie execuia, sistemul deoperare va descrca acel program din memorie, precum i variabilele sale globale i stiva sa, astfel

    nct un alt program va putea folosi spaiul corespunztor de memorie. n acest fel, memoriacomputerelor este n permanen reciclati refolosit de ctre programe pe msur ce acestea seafl n execuie i se ncheie.

    Memoria heapeste disponibil programelor de aplicaii n timpul execuiei acestora folosindfunciile malloc i free. Acestea permit ca unui program s i se aloce memorie, pentru operioad determinat, exact atunci cnd este nevoie n timpul execuiei programului.

    FunciilemallocifreeS presupunem c dorim alocarea unei anumite zone de memorie n timpul execuiei unui

    program. Acest lucru se face cu ajutorul funciei malloc, care va aloca un bloc de memorie dinheap. Sistemul de operare va rezerva acel bloc de memorie pentru program, bloc care va putea fifolosit n orice fel n programul respectiv. Cnd acel bloc nu mai este necesar, el va fi returnatsistemului de operare pentru a fi folosit de ctre alte aplicaii. Eliberarea (dealocarea) unui bloc dememorie se face folosind funciafree.

    Funciamalloci are prototipul ni n, aloc o zon contigude memorie i este de forma:

    (void *) malloc(dimensiune)

    unde dimensiune reprezint mrimea blocului de memorie alocat n octei. Funcia returneaz unpointer void, adic un pointer la o zon de tip necunoscut de date. La o iniializare ulterioarpointerul va fi convertit la un pointer specific unui anumit tip de date (vezi exemplul de mai jos).

    Fig.1

  • 8/3/2019 Pointer - limbajul C

    13/13

    Curs 7 Pointeri

    13

    n caz de succes, funciamalloc returneaz un pointer la primul octet al primei locaii a bloculuide memorie alocat, iar n caz de eroare returneaz pointerul NULL. Tot pointerul NULL estereturnat i cnd dimensiuneeste egal cu zero.

    Funcia freeelibereaz un bloc de memorie alocat cu funcia malloci apelul acesteia seface cu un parametru care reprezint pointerul la originea blocului de memorie care se elibereaz.Mai jos este prezentat un program exemplu n care se folosesc funciilemallocifree.Pn acum, cnd am lucrat cu tablouri, acestea au fost declarate de o anumit dimensiune maximDIM, iar programul putea folosi tablouri avnd maxim DIM elemente. De cele mai multe ori ns,programul cere numrul de elemente al tabloului, n, care este de obicei mai mic dect DIM.n programul exemplu de mai jos, memoria necesar tabloului va fi alocat dup citirea numruluisu de elemente i va fi exact ct este necesar.

    Program exemplu: folosirea funciilor malloci free

    //Se aloca dinamic un tablou de n elemente;

    #include

    #include

    void main()

    {

    int n,i;float *p,*p0;

    printf("Introduceti dimensiunea tabloului: ");

    scanf("%d",&n);

    p=(float *)malloc(n*sizeof(float));

    //(float *) converteste pointerul void

    //returnat de catre malloc intr-un pointer la tipul float

    p0=p;

    if (p==NULL)

    {

    printf("Eroare: Memorie nedisponibila\n");

    exit(1);

    }

    for(i=0;i