» Utilizator
Salut, vizitatorule!

SkullBox este o comunitate formata din programatori si administratori de sisteme sau retele care iti sta la dispozitie cand ai o problema legata de calculatoare. Daca esti un utilizator existent, autentifica-te.

Daca nu te-ai inregistrat inca pe forum, alatura-te noua astfel marind comunitatea si ajutandu-i pe cei care au nevoie de informatii.

Daca te-ai inregistrat dar inca nu ai primit codul de activare, il poti cere aici.




Autentifica-te cu numele de utilizator si parola pentru a putea posta pe forum sau pentru a accesa ariile disponibile doar utilizatorilor inregistrati.
 » Concurs
GameDev
 » Statistici
  • 46950 de mesaje.
  • 5871 de topicuri.
  • 825 de utilizatori.
  •  
  • cdoryn74 e ultimul utilizator inregistrat.
[Detalii]

 » Parteneri » Sponsori

 » Recomandăm
HostVision

» Avem un concurs pentru bloggeri si forumisti. Participi? «
Pagini: [1]
Print
[Curs C] Lectia 08 - Pointeri [1363 afisari]
Agkelos
*


Mesaje: 6023
OnlineOnline

WWW

Am cam ramas in urma cu lectiile din curs. Azi mi-am facut putin timp sa fac o scurta introducere in pointeri. Veti vedea ca este intr-adevar o introducere scurta. Nu am avut suficient timp (si nici dispozitia necesara) sa explic toate aplicatiile pointerilor dar e suficient sa va prindeti despre ce si cum fac pointerii. Deci, here it goes:

Unul termen foarte greu de inteles pentru incepatorii in C este pointerul. Ce este
un pointer ? La ce este bun ? De ce sa folosim pointeri cand tot ce fac e sa ne
ingreuneze munca ? Incerc sa explic chestia asta mai jos.


Incepem cu prima intrebare, si anume "Ce este un pointer ?"

In lectiile anterioare ati vazut ca exista diferite tipuri de date in C. Exista int
si long pentru numere intregi, char pentru caractere, float si double pentru numere
reale. Pointerul este un tip nou de data dar care spre deosebire de celelalte tipuri
memoreaza doar adrese.
Ce inseamna asta ? Ca sa intelegeti ce inseamna trebuie sa va familiarizati cu cativa
termeni intalniti in programare. Cand concepeti un program folositi, bineinteles,
variabile. La definirea unei variabile stiti ca e important sa cunoasteti doua
lucruri: tipul si numele acesteia. In timpul rularii unui program apare un nou termen
de care trebuie tinut cont si anume adresa variabilei. Un pointer este o variabila
care tine minte acest al treilea termen, adica adresa unei variabile.


Cum se declara un pointer ?

Inainte de a folosi un pointer trebuie sa stim spre ce fel de resursa va pointa, adica
sa stim ce tip de variabila se gaseste la adresa care o memoreaza. In functie de tipul
de variabila care se gaseste la adresa respectiva, se declara pointerul. Adica, daca
avem nevoie, de exemplu, de un pointer care sa pointeze catre o variabila de tip int
il vom declara in felul urmator:

Code:
int *pInt;

Dupa cum vedeti un pointer se declara ca si o variabila normala, in cazul nostru de tip
int, cu diferenta ca numele variabilei are un asterisc ( * ) in fata ceea ce ne spune
ca este un pointer, adica este o variabila care pastreaza o adresa a unei variabile de
tip int, nu este o variabila de tip int. Ca o conventie de nume majoritatea
programatoril prefera ca atunci cand se creaza un pointer sa i se dea un nume care incepe
cu litera p (de la pointer). Astfel de fiecare data cand folositi variabila respectiva
va amintit ca e pointer, nu o variabila normala.
Prin analogie va puteti da seama cum se declara pointeri pentru alte tipuri de date:

char *pCh; // un pointer catre un caracter
int *float; // un pointer catre un numar intreg


Ok. E usor de declarat un pointer, dar cum ii spun sa memoreze o adresa ?

Ei, daca tot am declarat un pointer e bine sa si memoreze ceva si ca sa fie util trebuie
sa memoreze o adresa. De fapt, asta e primul lucru care trebuie sa-l faceti dupa ce ati
declarat un pointer: sa-i dati o valoare, sa-l faceti sa pointeze spre ceva.
Pentru a-i spune unui pointer adresa care trebuie sa o memoreze se foloseste semnul egal
ca in atribuirile normale cu diferenta ca inaintea variabilei a carei adrese trebuie
memorate se pune semnul '&' care ii spune compilatorului ca acolo NU valoarea variabilei
trebuie data ca rvalue, ci adresa acesteia.
OK, am invatat sa asociem o adresa trebuie sa vedem si cum se poate citi (afisa)
valoarea care se gaseste la adresa respectiva. Asta se face ca si cum s-ar citi o
valoare normala doar ca numele pointerului este prefixat de un asterisc ( * ). Asta spune
compilatorului sa NU se citeasca/afiseze continutul pointerului si ceea ce se gaseste
la adresa care este tinuta in pointer.
Sa vedem si un exemplu concret care va ajuta sa intelegeti mai bine functionarea
pointerilor:

Code:
#include <stdio.h>

int main(){
  int i; // o variabila de tip int
  int *pInt // un pointer catre un int

  pInt = &i; // pInt citeste adresa lui i

  // afisam valoarea lui i si valoarea spre care pointeaza
  // pointerul pInt
  printf("n%d - %d\n",i,*pInt);

}

Rezultatul ar trebui sa fie: 10 - 10
Primul 10 este valoarea atribuita variabilei i. Al doilea 10 este valoarea care se gaseste
la adresa care este memorata de pointerul pInt. Cum pInt memoreaza adresa lui i, *pInt
va fi 10 adica valoarea lui i.

Haideti sa ne mai jucam putin cu pointerii. Incercati urmatorul program:

Code:
#include <stdio.h>

int main(){
  int i, j;
  int *pInt;

  i = 5;
  j = 2;

  pInt = &i;
  printf("*pInt are valoarea %d\n",*pInt);
  
  pInt = &j;
  printf("*pInt are valoarea %d\n",*pInt);

}

Dupa ce compilati si rulati codul de mai sus va trebui sa vedeti doua linii. Pe prima
linie ne spune ca *pInt are valoarea 5 iar pe cea de-a doua linie afisata ne spune
ca *pInt are valoarea 2.
De ce ? Simplu... i ia valoarea 5 si j ia valoarea 2. Inainte de primul printf() pInt
memoreaza adresa variabilei i, adica *pInt va afisa valoarea variabilei i care este 5.
Inainte de al doilea printf() pInt memoreaza adresa variabilei j iar la afisare pe
ecran apare 2, adica valoarea variabilei j la care pointeaza acum pInt.


Haideti sa intram la chestii ceva mai avansate cum ar fi folosirea pointerilor in
lucrul cu sirurile de caractere. Daca lucrati cu un singur caracter, utilizarea
pointerilor nu se deosebeste de utilizarea lor in numerele intregi. In schimb daca
folositi siruri de caractere apare o functionalitate in plus si anume posibilitatea
de a incrementa sau decrementa un pointer.
Sa vedem un exemplu:

Code:
int main(){
  int i;
  char sir[] = "abcdefghi";
  char *pChar;
  
  pChar = sir;
  
  for( i = 0 ; i < strlen(sir) ; i++ )
     printf("%c",*(pChar + i));

}

Codul de mai sus declara variabila sir si o initializeaza cu sirul de caractere
"abcdefghi". Mai jos declaram un pointer, pChar, care memoreaza date de tip char.
Mai jos punem in pChar adresa sirului de caractere declarat mai sus ( sir ).
Bun, avem un sir de caractere, un pointer catre un sir de caractere... now what ?
Afisam sirul de caractere afisand fiecare caracter in parte. Probabil va puneti
intrebarea "Cum sa afisam un sir daca pChar pointeaza spre un caracter ?". Ei bine,
intr-adevar pointerul pointeaza spre un caracter dar in cazul sirurilor de caractere,
care in memorie sunt reprezentate ca un sir lung de adrese consecutive, pointerul
pointeaza catre primul caracter din acel sir. Adica, pChar = &sir s-ar traduce ca
"Memoreaza primul caracter din sirul sir." Dupa cum am spus mai sus, toate caracterele
sunt reprezentate ca zone consecutive din memorie iar pointerul il putem incrementa
pentru a afisa continutul de la fiecare zona in parte.
In cazul de fata am preferat sa nu incrementez pointerul si sa-i adaug un numar. Dupa
cum vedeti am folosit o bucla for in care i este initializat cu valoarea 0 iar conditia
de oprire e ca i sa fie mai mic decat lungimea sirului de caractere.
La fiecare iteratie se va afisa caracterul care se gaseste la adresa pointata de pChar
la care se adauga valoarea lui i. Ce inseamna asta ? Se va afisa din sir "a i-a"
valoare. La prima trecere prin bucla i este 0, deci valoarea afisata va fi pChar + 0,
adica va afisa primul caracter din sir pentru ca, dupa cum am spus mai sus, cand unui
pointer ii atribuim adresa unui sir de fapt ii dam adresa primului caracter din sir.
La a doua iteratie se va afisa valoarea de la adresa pChar + 1, adica de la inceputul
sirului se "merge" distanta de 1 caracter si este afisat. La fel si mai departe.

Acelasi lucru putea fi scris si de forma:

Code:
int main(){
  int i;
  char sir[] = "abcdefghi";
  char *pChar;
  
  pChar = sir;
  
  for( i = 0 ; i < strlen(sir) ; i++ ){
     printf("%c",*pChar++);
  }
  
}

Codul de mai sus si codul anterior sunt echivalente cu diferenta ca nu se apeleaza
pChar + deplasament cum era in primul caz ci se afiseaza doar pChar care este
incrementat dupa fiecare afisare. Observati ca am folosit operatorul de incrementare
dupa valoarea variabilei, adica mai intai va fi afisat *pChar si apoi va fi incrementat.

Cam asta ar fi ideea de utilizare a pointerilor. Bineinteles, pointerii sunt mult mai
complecsi decat am prezentat eu aici. In randurile de mai sus am facut doar o prezentare
scurta a ceea ce se numeste pointer.

Pentru a va obisnui cu pointerii pun mai jos inca un exemplu care e util sa il studiati
si sa il intelegeti:

Transmiterea unui pointer ca parametru intr-o functie:

Code:
#include <stdio.h>

void afiseaza(int *pInt);

int main(){
  int i;

  i = 5;
  
  afiseaza(&i);

}

void afiseaza(int *pInt){
     printf("%d",*pInt);
}

In codul de mai sus se poate vedea cum transmitem ca parametru functiei afiseaza() o adresa
in locul unei valori. Cazul de fata este doar exemplificativ si nu are o valoare practica
deosebita dar in cadrul unui program complex este o tehnica utila dintr-un motiv simplu:
daca valoarea transmisa este foarte mare ( ex. o structura de 10MB ) nu este deloc util
sa apelam functia dand ca parametru variabila. In schimb putem transmite doar adresa
variabilei care urmeaza a fi prelucrate astfel evitand incarcarea memoriei.

Daca aveti nelamuriri, astept sa le postati aici Winking
Logged

Blog | Twitter

De nu va zice omul intru inima sa "Eu singur si Dumnezeu suntem in lume" nu va avea odihna. - Avva Alonie
15-12-2006, 23:16 
 
Zazu



Mesaje: 11
OfflineOffline


In primul rand doresc sa salut pe toata lumea pentru ca este primul meu post in acest forum,care-l gasesc interesant.
Nu in ultimul rand , ma inclin in fata lui OSHO care s-a muncit sa scrie articolul de mai sus.Dar....

Am dorit sa intervin pentru a face anumite corectii asupra acestei lecturi cu scopul de de a fi corect informati,  userii acestui forum.
1.Pointer-ul nu este un tip de data ci un mecanism prin care se poate accesa o locatie de memorie.
2.Memoria este intr-adevar o resursa dar tipul de data (char,int), nu este.De fapt trebuie specificat tipul de data al pointerul pentru a stii cati bytes(lungimea) se citesc/scriu in memorie :
Exemplu
tipul de data char ocupa 1 byte,un integer(int) ocupa 2 byte,un long 4 byte...etc.
3.Un pointer este alocat automat de catre SO in momentul in care este declarat.Numai daca-l initializam cu NULL este deferit din orice locatie de memorie.Asta in ideea ca-l vom aloca cand este intr-adevar nevoie de el, folosind functiile care fac acest lucru.
Este deosebit de periculos ca utilizatorul sa stabilieasca catre ce adresa de memorie trebuie sa pointeze o variabila.Iar asta se face foarte simplu prin urmatorul exemplu :
int *p;
*p=12; //sistemul crapa la o asemenea linie de cod, pentru ca la aceasta adresa , adica 12, sigur vom gasi vreun octet din boot sequence al SO.

in schimb, daca scriem :
p=12;
atunci, intr-adevar la adresa din memorie ,alocata de SO la declararea variabilei p, se va scrie valoarea 12;

Cred ca inainte de a aduce pointerii in discutie , ar trebui facuta o "lectie" despre moduri de reprezentare a datelor si bineinteles cate ceva despre
mecanismele prin care SO-urile (cele mai populare fiind Uindouz si linux) lucreaza cu memoria si nu numai.
Logged
18-12-2006, 21:30 
 
Agkelos
*


Mesaje: 6023
OnlineOnline

WWW

Salut si daca aici e primul tau post iti urez aici bun venit pe forum !
Mersi de completari. Intr-adevar am uitat sa mentionez ca e nasol sa se foloseasca pointeri neinitalizati, dar noroc ca ma completezi Winking
Sper sa-mi fac timp in curand pentru o continuare a lectiei ca despre pointeri e foarte mult de vorbit. Chiar daca am scris o lectie destul de lunga, nu am acoperit mai deloc pointerii ci doar am facut o mica introducere. Pana cand termin lectia sper sa se lamureasca userii macar cu ce am scris pana aici Smile
Logged

Blog | Twitter

De nu va zice omul intru inima sa "Eu singur si Dumnezeu suntem in lume" nu va avea odihna. - Avva Alonie
18-12-2006, 21:34 
 
Yeap



Mesaje: 3
OfflineOffline


Va rog ceva informatie despre utilizarea pointerilor in matrice. ms anticipat
Logged
23-01-2009, 11:06 
Pages: [1]
Print
SkullBox Forum  |  Development  |  Java / C / C++ / C# (Moderators: AnaKonD, astan)  |  Topic: [Curs C] Lectia 08 - Pointeri
Jump to: