|
(directa sau indirecta) a datelor arhivate.Exersati cat mai multe exemple
|
səhifə | 8/55 | tarix | 07.05.2018 | ölçüsü | 4,6 Mb. | | #50260 |
| (directa sau indirecta) a datelor arhivate.Exersati cat mai multe exemple
de declarare si apelare a datelor,atat prin metode directe,cat si prin
metode indirecte(prin pointeri).
POINTERI:-sunt variabile care contin o adresa de memorie(locatia unui
obiect declarat anterior).Cel mai frecvent este adresa unei alte variabile
motiv pentru care se spune ca o variabila o indica pe cealalta(de unde si
denumirea de pointer-in engleza point=a arata,a tinti).Se declara la fel
ca orice variabila dar se va adauga si caracterul *(asterix) in fata iden-
tificatorului,pentru a specifica faptul ca este o variabila pointer.
-51-
Sintaxa generala este de tipul:
SPECIFICATOR DE TIP * Identificator
EXEMPLU: char *Pointer1
Pointeri nu sunt date structurate dar se pot utiliza pentru a forma
structuri,uniuni,enumerari sau tablouri de pointeri.In plus,fata de
variabilele simple contin si abilitatea de a accesa memoria,fapt ce
permite prezentarea lor impreuna cu structurile de date.
Specificatorul de tip se utilizeaza pentru a desemna tipul de baza al
pointerului,adica tipul de date asupra carora va actiona.
Pentru atribuirea adresei de memorie se utilizeaza operatorul &.
EXEMPLU: int *m; //declara pointerul
m=&x; //m primeste adresa variabilei x
q=*m //q primeste valoarea lui x
Pentru atribuirea valorii arhivate la adresa respectiva se va utiliza
operatorul *(asterix) care este complementar lui &.
Aceste notatii se preteaza la numeroase confuzii,deoarece caracterul
* poate fi utilizat si pentru operatiile de multiplicare iar & este si
operator AND binar.Semnificatia lor este generata de contextul in care
apar,iar in situatiile in care apar in aceeasi expresie operatorii de
pointer au precedenta fata de cei aritmetici.Este preferabil totusi ca
declararea pointerilor si operatiile cu pointeri sa se faca prin expre-
sii distincte(sau sa se adauge comentarii explicative la program).
Orice variabila(inclusiv pointerii) se caracterizeaza printr-o va-
loare(nula sau nenula) si o adresa de memorie unde este arhivata valoa-
rea respectiva.Pointerii permit accesarea ambelor tipuri de informatie
despre o variabila oarecare.Locatia de memorie este denumita uneori si
l-valoare iar valoarea obiectului respectiv este denumita uneori si
r-valoare,dupa pozitia din ecuatia adresa=valoare.Toate datele de tip
r-valoare sunt si l-valoare(toate valorile au o adresa in memorie) dar
nu toate datele l-valoare sunt si r-valoare(nu toate adresele de memorie
contin valori).In diverse manuale,apar aceste denumiri(si altele).
Expresiile care contin pointeri se formuleaza la fel ca celelalte.
Unui pointer i se poate atribui si valoarea unui alt pointer.
EXEMPLU: int x;
int *p1,*p2;
p1= &x;
p2=p1; //p2 primeste valoarea lui p1
Operatiile permise cu poinerii sunt adunarea si scaderea.Prin increment-
are cu unu,pointerul va contine adresa elementului urmator din tablou,
iar prin scadere va contine adresa elementului precedent.
Trebuie remercat faptul ca la nivel de memorie operatiile sunt deter-
minate de tipul datelor.Astfel,in cazul datelor de tip double long la
care fiecare element este reprezentat pe 10 octeti,incrementarea unui
pointer cu un element determina un salt in memorie de 10 octeti(pana la
elementul urmator).
Doi pointeri pot fi comparati prin expresii relationale.Comparatia se
va referi in acest caz la adresa de memorie continuta.Astfel o expresie
de genul p
p este inferioara celei din q(anterioara in cazul memoriei stiva).
Un tablou poate fi reprezentat numai din pointeri.
EXEMPLU: int *x[10] //un tablou de 10 pointeri de tip int
-52-
Un pointer poate contine adresa unui alt pointer,care contine adresa
unui alt poiner etc.Aceasta situatie poarta numele de adresare indirecta.
Pentru a declara un pointer catre un alt pointer se va adauga inca un
asterix.EXEMPLU: float **bilant; //este un pointer spre un alt pointer
Daca este nevoie de mai multi pointeri (rar) se pot utiliza paranteze,
pentru a declara explicit acest lucru. EXEMPLU float *(*(*bilant));
Este posibil sa declarati un pointer,iar in cursul programului,acesta
sa-si schimbe adresa de memorie accidental.Pentru a depista nivelul de
program la care a intervenit eroarea,se poate fixa un "nivel de intreru-
pere" pe pointerul respectiv.In acest fel,la derularea programului,se va
face pauza in punctul in care pointerul primeste o valoare.In cazul in
care pointerul este orientat corect dar in aria de memorie este o valoare
incorecta,se poate fixa un "nivel de intrerupere"(breakpoint) pe valoarea
pointerului respectiv,caz in care programul se va intrerupe in momentul
in care aria pointata isi schimba valoarea.In acest sens,selectati din
meniul Edit optiunea Breakpoints,alegeti Data iar in caseta de dialog
introduceti identificatorul(p) sau valoarea (*p) pointerului respectiv.
Un pointer catre date de tip void poate fi convertit in orice alt tip
de pointer,dar numai prin o declaratie explicita a tipului.Un pointer
catre orice tip poate fi convertit implicit in pointer catre void.
In situatii speciale,se poate crea un pointer spre obiecte care exista
doar in timpul executiei programului,fara a avea o adresa fixa de memorie.
Acest gen de pointeri se numesc "Pointer moniker" se se realizeaza utili-
zand functia CreatePointerMoniker.
EXEMPLU: WINOLEAPI CreatePointerMoniker(
LPUNKNOWN punk,
LPMONIKER FAR *ppmk
);
Pentru operatii intre membrii unei clase si pointeri se pot utiliza
operatorii .* si ->* (vezi operatorii).Operatiile cu pointeri au sens
doar atunci cand acestia pointeaza arii formate din mai multe elemente.
Pointerii spre un element unic,nu participa la operatii aritmetice sau
relationale.
Pointerii pot fi convertiti dintr-un tip de date in altul,cu conditia
ca tipul de date final sa ocupe tot atata spatiu de memorie,sau mai putin.
Pointerii pot fi declarati si in mod automat,dinamic,utilizand functia
DYNAMIC_DOWNCAST care declara si verifica pointerul de clasa declarat.
Pointerii sunt un instrument de lucru extrem de util al limbajului C si
C++,dar trebuie manevrati cu foarte multa atentie,deoarece pot modifica
datele din adresele de memorie (accidental sau intentionat) de asa maniera
incat sa defecteze sistemul de operare(sunt instrumentul preferat al cre-
atorilor de "virusi informatici").Orice program care contine pointeri ce
produc programe defective prin alterarea memoriei va fi considerat si
tratat juridic ca si un "virus informatic" premeditat,autorul nu va putea
utiliza scuza unei "greseli accidentale" sau a necunoasterii implicatiilor
rezultate.
Pointerii pot fi utilizati si in medii de programare complexe care
contin rutine scrise in limbaje diferite.Astfel,de exemplu,in limbajul
Fortran,pentru a extrage adresa unei variabile se utilizeaza functia LOC.
Pentru a transfera o astfel de adresa,dintr-o rutina scrisa in Fortran in
aplicatia de baza scrisa in limbaj C sau C++ se va utiliza un pointer.
-53-
STRUCTURI
Reprezinta un set de mai multe elemente de acelasi tip de data,sau de
tipuri diferite.In alte limbaje de programare poarta numele de "records"
(inregistrari) sau "procedure"(proceduri) etc.Se utilizeaza pentru a
putea grupa functii si date,pentru a putea fi accesate in bloc.Definitia
unei structuri poate fi utilizata si ca sablon pentru formarea unor alte
structuri similare.In general,functiile si datele grupate intr-o struc-
tura au o legatura logica intre ele.Identificatorul,denumit si "tag",este
facultativ dar este foarte util pentru a face referinta la structura de-
clarata.Declararea se face utilizand cuvantul cheie "struct"
Sintaxa generala este: struct [identificator]
{
[]
...
}[]
Numele precizat prin identificator(tag-ul),poate fi utilizat pentru refe-
rirea la o structura definita in alta zona a programului.Daca o structura
a fost deja definita,iar definitia este "vizibila"(adica este incarcata
in memoria de lucru a programului),atunci lista de declaratii din struc-
tura nu poate fi redeclarata.Tag-ul se poate utiliza si pentru declararea
pointerilor spre structura respectiva.Mai mult,in cazul pointerilor se
poate utiliza tag-ul(numele) viitor al unei structuri ce nu a fost inca
declarata.Structura nu poate fi utilizata insa decat dupa declarare.
Fiecare variabila declarata in lista de declaratii va reprezenta un
membru al structurii.Membrii unei structuri pot fi de orice tip,cu ex-
ceptia tipului void si a tipului incomplet.
Numele unei structuri(identificatorul),trebuie sa fie unic in cadrul
aceleasi zone de vizibilitate(zona de lucru a programului).
Fiecare declaratie din lista de declaratii trebuie sa fie unica.In
interiorul structurii,se pot utiliza si denumiri(identificatori) care
apar si in interiorul unei alte structuri(deoarece nu sunt in aceeasi
zona de vizibilitate a programului) dar nu pot fi repetate denumirile
pentru variabilele declarate externe(globale).
Declaratiile vor contine si tipul de date,pentru fiecare membru.
EXEMPLU: struct Adresa
{
char nume[30];
char strada[40];
char oras[20];
char stat[10];
unsigned long int cod_postal;
};
Declaratia unei structuri se termina cu punct si virgula,deoarece este
considerata ca si o instructiune si trebuie returnat controlul la nivelul
de baza(functia main()).
Optional,structura poate fi si initializata in momentul declararii prin
.
Structurile pot fi intricate("imbricate"),una in cealalta ,caz in care
structura din interiorul celeilalte se va comporta ca si un membru al
structurii respective.
-54-
Daca o structura a fost declarata fara o lista de variabile(nu a fost
initializata),atunci declaratia doar descrie structura dar nu poate fi
utilizata(nu are memorie alocata).
Dupa declarare,referirea la un membru al structurii se face utilizand
operatorul punct.
EXEMPLU: struct numar{
float real;
float imaginar;
}a
Pentru a accesa cei doi membri ai numarului complex se vor utiliza for-
mulele a.real si a.imaginar.
Un membru al unei structuri poate fi accesat si indirect,printr-un
pointer,utilizand operatorul ->*
EXEMPLU: struct numar{
float real;
float imaginar;
}a,ptr*=&a;
Pentru a desemna pointerul spre fiecare membru al structurii se va
utiliza prt->*real sau ptr->* imaginar
O structura poate si sa se autorefere,adica sa contina un pointer care se
orienteaza spre propria structura.
EXEMPLU: struct pair
{
int a;
int b;
struct pair *sp;
} item,list[10];
Prin item.sp=&item pointerul va aloca adresa de memorie a propriei struc-
turi.in mod similar se poate atribui unui pointer adresa de memorie a
oricarui membru din structura.Observati ca in cazul membrilor formati din
tipuri de data diferite,si adresele de memorie alocate pentru fiecare
membru vor fi diferite ca lungime in octeti.
Informatia continuta intr-o structura poate fi atribuita unei alte
structuri,cu conditia sa fie definita la fel.
EXEMPLU: struct numere {
int a;
int b;
} x,y;
x.a=10; //membrul a este initializat 10
y=x; //structura x se atribuie lui y
In urma operatiei,elementul y.a va fi gata initializat la valoarea 10.
Sutucturile pot fi grupate in tablouri,pentru a forma diverse instru-
mente de calcul tabelar de genul conoscutului program "Excel" sau "Lotus".
In acest caz,fiecare element al tabloului va fi format din cate o struc-
tura care contine la randul sau un numar de elemente.Rezulta un complex
bidimensional de date structurate,foarte util pentru calcul tabelar.
EXEMPLU: struct calcul{
char ch;
int i;
float c;
} tab[2][3] // tablou bidimensional
-55-
Tabloul de structuri va putea fi initializat prin:
{ //initializarea tabloului
{ //initializarea liniei
{'nume1',1,1.2} //initializarea primei structuri
{'nume2',2,3.4}
{'nume3',3,5.6}
}
{ //initializarea liniei urmatoare
{'nume4',4,7.8} //initializare prima structura din linia 2
{'nume5',5,9.9}
}
};
Datele arhivate vor fi de forma:
[0][0] nume1 1 1.2
[0][1] nume2 2 3.4
[0][2] nume3 3 5.6
[1][0] nume4 4 7.8
[1][1] nume5 5 9.9
[1][2] 0 0
Elementele unei structuri pot fi transmise unei functii,adica se va
transfera valoarea unui membru al structurii,valoare ce va fi apoi uti-
lizata in cadrul functiei pentru efectuarea operatiilor.
EXEMPLE: struct date
{
char x;
int y;
float z;
char s[10];
} adrese;
Pentru a transfera valoarea unui membru catre o functie se vor utiliza:
func(adrese.x); //transmite valoarea lui x (de tip caracter)
func(adrese.y) //transmite valoarea lui y (de tip int)
func(adrese.s[2] //transmite valoarea membrului 3 din tabloul s
Este posibila transferarea intregii structuri ca argument al unei functii,
caz in care atat argumentul cat si parametrul functiei trebuie sa fie de
acelasi tip.In versiunile vechi de C,acest transfer integral nu este
posibil structurile fiind tratate la fel ca si tablourile.
EXEMPLU: struc date1 {
int a,b;
char ch;
};
void f1(struct date1); //se transfera structura
Intr-o structura este importanta ordinea in care se declara fiecare
membru,deoarece se vor arhiva in memorie in ordinea declararii.Primul
membru declarat va avea adresa de memorie cea mai mica iar ultimul decla
rat va avea adresa de memorie cea mai mare.Eventual se poate utiliza
pachetul #pragma pack,pentru a controla modul de arhivare in memorie a
datelor in forme cat mai compacte(valoarea implicita este cea de 8 bytes).
O structura din limbajul C este echivalenta cu RECORD din FORTRAN sau
cu class din limbajul C++(class contine si atribute suplimentare).
-56-
UNIUNI
Sunt structuri in care toti membrii utilizeaza aceeasi adresa de me-
morie si se substitue reciproc(se suprascriu reciproc).Adresa de memorie
are dimensiunea adaptata pentru tipul de date al membrului care ocupa cel
mai mult spatiu.O uniune poate contine variabile de tipuri diferite,un
identificator denumit tag(eticheta) si este la fal ca si structura,echi-
valenta cu RECORD din limbajul Fortran,sau PROCEDURE din FoxPro.
Declararea se face la fel ca si pentru structuri(respecta aceleasi reguli
fundamentale).Fata de structuri,ocupa mai putin spatiu de memorie,permit
tratarea mai multor tipuri de date in aceeasi arie de memorie,permit
diverse conversii ale tipurilor de date,contin o singura variabila la
un anumit moment dat.Uniunile pot include si campuri de biti.Membrii unei
uniuni nu pot fi de tip void sau incomplet.
EXEMPLU: union sign
{
int svar;
unsigned uvar;
} numar;
Declara o uniune de tip sing,formata din doi membri si salvata in varia-
bila numar.
Daca se salveaza o variabila de un anumit tip,iar apoi uniunea este
accesata cu un alt tip de data,rezultatul poate fi imprevizibil(Exemplu:
numerele int vor putea fi reprezentate intr-o variabila float,dar nu si
viceversa).Rezervarea de memorie pentru o uniune se face doar in momentul
declararii variabilei.Tipul de data al reuniunii este ultimul tip de
data atribuit.Utilizatorul este responsabil de pastrarea evidentei pentru
tipul curent de data(daca nu exista o rutina special destinata) si respec-
tiv pentru apelarea corecta a datelor curente.
Pointerii catre uniuni se realizeaza la fel ca si cei spre structuri.
Valoarea unei uniuni poate fi atribuita unei functii.Se pot forma tablouri
din uniuni,pentru a realiza tabele multifunctionale(afiseaza succesiv,nu-
mele,adresa,telefonul,contul curent etc.).Uniunile pot fi intricate una
in alta,ca si cand ar fi membri simpli,sau pot fi incluse in structuri.
Nu pot fi utilizati ca membri ai uniunii,clasele de date automate(cu con-
structor si destructor),clasele de date care contin operatori artizanali(
cu definitie precizata de catre utilizator) sau datele declarate static(
mai multi membri trebuie sa poata utiliza adresa de memorie).
Pentru declarare se utilizeaza cuvantul cheie union.Sintaxa generala este:
typedef [atribute] union [tag] {
declaratii membrii
......
} numeuniune;
Atributele acceptate sunt:helpstring,helpcontext,uuid,hidden si version.
EXEMPLU: union nume1
{
char ch;
int i;
long l;
float f;
} parola; // poate fi utilizata pentru arhivarea parolei
-57-
In limbaj C++,o uniune este considerata ca si o clasa de date,dar cu
unele limitari.Poate avea specificatori de acces de tipul public,private
sau protected,membri formati din date sau din functii (inclusiv construc-
tori si destructori),dar nu poate contine functii virtuale sau membri
declarati statici.Nu poate avea clasa de baza si nici nu poate fi clasa
de baza pentru alte clase.Accesul implicit este cel de tip public.
Operatiile asupra uniunii sunt la fel ca pentru structuri.
EXEMPLU: union cod1
{
int i;
double d;
} var1;
var1.i=6 //va arhiva valoarea 6 (tip int)
var1.d=5.327 //va suprascrie valoarea 5.327(double)
CAMPURI DE BITI (bit fields)
Se utilizeaza in cadrul declaratiilor de membri ai unei structuri sau
uniuni,pentru a preciza explicit,bit cu bit,modul in care vor fi arhivate
datele in memorie.Dimensiunea campului de date in care trebuie incadrata
declaratia depinde de formatul suportului de memorie(Exemplu: in cazul
versiunii MS-DOS pe 16 biti,dimensiunea maxima a campului de biti va fi
de 15,iar in cazul versiunii Windows pe 32 de biti va fi de 31 de biti).
Sintaxa generala este:
struct-numele(tag-ul){
declarator
specificator de tip declarator:constanta
unde constanta specifica largimea in biti a campului de biti.Specifica-
torul de tip trebuie sa fie unsigned int,signed int sau int,iar constanta
trebuie sa fie o marime intreaga pozitiva.Nu se pot declara tablouri de
tip camp de date,dar se pot forma tablouri din structuri ce contin campuri
de date.
EXEMPLU: struct imagine
{
unsigned short icon : 8;
unsigned short color : 4;
unsigned short underline : 1;
unsigned short blink : 1;
Dostları ilə paylaş: |
|
|