Articolele sunt
structuri de date neomogene si continue. Ele au un numar fix de elemente numite
campuri, iar accesul la acestea se face direct.
Utilitatea
articolelor apare in manipularea datelor complexe (care presupun stocarea unui
numar de caracteristici pentru fiecare entitate) si in crearea structurilor de
date evoluate.
Reprezentarea
grafica a unui articol se poate face sub forma:
Campurile care
compun un articol pot avea orice tip de date, inclusiv articol. In acest fel se
pot defini structuri complexe de date.
Exemplu:
Persoana (articol):
·
Nume
·
Prenume
·
Adresa
(articol)
o
Strada
o
Oras
o
Judet
o
Tara
Reprezentarea
acestei structuri este:
Dimensiunea unui
articol se calculeaza recusiv ca suma dimensiunilor campurilor componente.
Sintaxa folosita
pentru definirea unui articol in C++ este:
struct nume_structura { declaratii campuri } lista_variabile;
unde:
· nume_structura: numele tipului de date definit;
· declaratii campuri: declaratiile de campuri (similara cu declaratiile de variabile;
· lista_variabile: lista de variabile de tipul definit.
nume_structura si lista_variabile pot lipsi, dar nu simultan. In cazul in care lipseste numele structurii nu se vor putea declara ulterior variabile si nu se vor putea transmite ca parametri. In cazul in care nu este specificata o lista de variabile, acestea se pot declara ulterior folosind sintaxa nume_structura lista_variabile.
Exemple de articole:
// declarare
structura 'Adresa'
struct Adresa
{
// declaratii campuri
char strada[100], oras[50],
int cod_judet;
};
// declarare
structura 'Student'
// si variabile
de tip student
struct Student
{
// campuri simple
char nume[50], prenume[50];
// camp de tip structura
Adresa adresa;
}
student1, student2;
// declarare
variabile de tip adresa
Adresa o_adresa, alta_adresa;
Definirea unui
articol este de fapt definirea unui nou tip de date in cadrul limbajului. Aceasta
nu presupune alocare de memorie, dar permite declararea ulterioara de variabile
din noul tip. Compilatorul va aloca memorie doar pentru variabilele declarate
pe baza definitiei articolului. Pentru determinarea dimensiunii efective de
memorie utilizate se recomanda folosirea operatorului sizeof, deoarece ea poate
fi diferita de suma dimensiunilor campurilor componente (datorita restrictiilor
de aliniere).
Variabilele de
tip articol se pot initializa la declarare folosind sintaxa:
nume_structura variabila = {lista
de initializare};
Exemplu:
// declarare si initializare
Student s = {
// valori campuri simple
"Popescu", "Ion",
// valori campuri de tip
structura
{"Str. Zambilelor 2",
"Buhusi", "
Limbajul C++
permite definirea unui tip special de campuri numite campuri de tip bit. Aceste
campuri permit o folosire mai eficenta a memoriei in cazul in care o
caracteristica are un set de valori foarte mic (ex: sex, an de studii). Aceste
campuri pot fi combinate cu campurile normale in cadrul unei structuri. Sintaxa
folosita este:
tip nume_camp:nr_biti;
Exemplu:
struct Elev
{
// clasa -> 1-12
unsigned short clasa : 4;
// 0 - M, 1 - F
unsigned short sex : 1;
char nume[100];
};
Campurilor de tip bit se comporta ca si cele normale, dar au o serie de particularitati:
· tipul campului trebuie sa fie de tip intreg
· un camp nu trebuie sa taie limita unui cuvant
· lungimea unui camp nu poate depasi lungimea unui cuvant
· numele campului poate lipsi, caz in care nu poate fi accesat, dar este folosit pentru aliniere
· nu se poate extrage adresa unui astfel de camp
Accesul la membrii structurii se face folosind sintaxa variabila.camp.
Exemple:
// extrage prima litera din nume
char a = s.nume[0];
// extrage codul din structura
imbricata
int cod = s.adresa.cod_judet;
// modifica codul judetului
s.adresa.cod_judet = 27;
Operatiile premise asupra datelor de tip articol sunt:
a) extragerea adresei folosind operatorul &:
Student *pStudent = &s;
Accesarea campurilor prin intermediul pointerului se poate
face folosind operatorul de indirectare * sau operatorul ->: (*pStudent).nume sau
pStudent->nume;
b) atribuirea la nivel global folosind operatorul = :
Student s1;
s1 = s;
Copierea structurilor se face bit cu bit. In cazul in care structura contine pointeri, zonele de memorie referite trebuie copiate manual de catre programator. Singura exceptie o constituie masivele, care sunt copiate automat de compilator.
c) transmiterea ca argument in functie si returnarea ca rezultat:
Student
PrelucrareStudent(Student s)
{
Student tmp;
....
return tmp;
}
Structurile de date, spre deosebire de massive, sunt trimise prin valoare. In cazul in care structura contine un masiv, acesta va fi copiat in intregime la momentul apelului.
Limbajul C++
permite definirea de campuri de lungime variabila numite uniuni. Uniunea
corespunde unei zone de memorie care la momente de timp diferite poate contine
elemente de tipuri si lungimi diferite.
Ca si
structurile, uniunile sunt formate dintr-un ansablu de campuri. In cazul
uniunilor, campurile sunt alocate in acelasi spatiu de memorie (ele sunt mutual
exclusive). Din acest motiv, uniunea se comporta ca o structura in care toate
elementele sunt aliniate la aceeasi adresa. Lungimea unei uniuni este data de
lungimea celui mai lung camp.
Sintaxa de
declarare este:
union nume {lista_campuri};
Exemplu de
utilizare:
// declarare uniune
// (poate contine un numar intreg
// sau un numar real)
union
numar
{
int
intreg;
double
real;
};
// declarare variabila
numar n;
// folosire ca intreg
n.intreg = 7;
int i = n.intreg;
// folosire ca real
n.real = 5.6;
double d =
n.real;
Interpretarea
continutului zonei cade in sarcina programatorului. In general, pentru a putea
retine usor tipul informatiilor prezente la un moment dat intr-o uniune,
aceasta se include impreuna cu o variabila care mentine tipul stocat intr-o
structura.
De exemplu,
pentru a mentine date despre elevi si studenti se poate crea o stuctura de
forma:
// declarare
uniune
union DatePersoana
{
Student student;
Elev elev;
};
// includere
uniune in articol
struct Persoana
{
// tipul persoanei: 0 - Student, 1 -
Elev;
int tip;
DatePersoana date;
};
La momentul
prelucrarilor se va verifica intai tipul stocat, iar dupa aceea se vor efectua
prelucrarile.
De exemplu,
functia de afisare poate avea forma:
void AfisarePersoana(Persoana
pers)
{
// determinare tip
if (pers.tip == 0)
{
// afisare student
cout << pers.date.student.nume << "
"
<< pers.date.student.prenume << endl;
}
else
{
// afisare elev
cout << pers.date.elev.nume << " "
<< pers.date.elev.clasa << endl;
}
}
Structurile pot
fi grupate in masive, la fel ca oricare tip de date. De asemenea, structurile
pot vectori.
Exemple:
a) vector in articol
struct Student
{
int cod;
int nr_note;
// vector in structura
int note[10];
};
b) vector de articole
// declarare si
initializare
// vector de
studenti
Student grupa[] =
{
{1, 3, {7, 10, 10}},
{2, 3, {10, 8, 9}},
{3, 2, {10, 10}}
};
1.
Pentru
o factura se dau urmatoarele date: informatii despre beneficiar si cumparator
si lista de produse (cantitate si pret unitar). Sa se defineasca o structura de
date potrivita pentru stocarea informatiilor referitoare la o factura si sa se
scrie o functie care calculeaza celelalte informatii prezente pe factura
(valoare totala si TVA pentru fiecare produs si per total).
2.
Scrieti
programul care realizeaza initializarea si referirea unei structuri de date de
tip uniune. Explicati rezultatele programului in urma executiei.
3.
Despre fiecare student dintr-o grupa se cunosc
numele acestuia, notele obtinute la seminar, numarul de prezente la seminar. Sa
se memoreze intr-o structura de date corespunzatoare toate aceste informatii si
sa se scrie functiile si procedurile pentru obtinerea urmatoarelor situatii::
a.
afisarea studentilor in ordine alfabetica
b.
afisarea informatiilor despre un anumit student
c.
inscrierea unui nou student in grupa
d.
stergerea unui student din grupa
4.
O
societate comerciala cu profil de productie mentine informatii de gestiune
referitoare la materiile prime folosite si la produsele finite realizate. Pentru
materiile prime se retin: codul materialului, grupa de produse (max. 16 grupe),
subgrupa de produse (max 16 subgrupe), daca este produs local sau importat,
daca necesita conditii speciale de depozitare sau nu, cantitatea disponibila in
stoc si pretul unitar. Datele asociate unui produs sunt: codul produsului,
cantitatea existenta in stoc, pretul unitar si consumurile specifice (max 10).
Se cere:
a.
Sa se
defineasca o structura unitara si eficienta pentru tinerea gestiunii.
b.
Sa se
scrie functii pentru:
i.
Afisarea
listei de gestiune (tip, cod, cantitate, valoare totala);
ii.
Determinarea
valorii stocurilor de materii prime, de produse finite si valoarea totala a
elementelor din gestiune;
iii.
Determinarea
valorii totale si pe subgrupe a stocurilor pentru o grupa de materii prime;
iv.
Determinarea
profitului obtinut in cazul vanzarii intregului stoc de produse finite;
v.
Determinarea
pentru un produs dat a numarului maxim de unitati ce pot fi produse pe baza
stocurilor existente.
Rezolvare:
struct mat_pr
{
int cod;
short grupa:4;
short subgrupa:4;
short local:1;
short cond_spec:1;
int cant, pret;
};
struct consum
{
int cod_mat, cant;
};
struct prod_fin
{
int cod;
int cant, pret;
int nr_mat;
consum consumuri[10];
};
union date_elem_gest
{
prod_fin prod;
mat_pr mat;
};
struct elem_gest
{
short tip;
date_elem_gest date;
};
void AfisareLista(elem_gest
gest[], int n)
{
for(int
i = 0; i < n; i++)
{
if (gest[i].tip == 0) // daca e material
cout << "mat " << gest[i].date.mat.cod
<< " " <<
gest[i].date.mat.cant
<< " " <<
gest[i].date.mat.cant * gest[i].date.mat.pret << endl;
else
cout << "prod " <<
gest[i].date.prod.cod
<< " " <<
gest[i].date.prod.cant
<< " " <<
gest[i].date.prod.cant * gest[i].date.prod.pret << endl;
}
}
void ValoareStocuri(elem_gest
gest[], int n)
{
int totalMat = 0, totalProd =
0;
for(int
i = 0; i < n; i++)
if (gest[i].tip == 0) // daca e material
totalMat += gest[i].date.mat.cant *
gest[i].date.mat.pret;
else
totalProd += gest[i].date.prod.cant *
gest[i].date.prod.pret;
cout << "Total materii prime: " <<
totalMat << endl;
cout << "Total produse: " << totalProd
<< endl;
cout << "Total general: " << totalMat +
totalProd << endl;
}
void ValoareStocuri(elem_gest
gest[], int n, int
grupa)
{
int i, totalSubGr[16], total =
0;
for (i = 0; i < 16; i++)
totalSubGr[i] = 0;
for(i = 0; i < n; i++)
if (gest[i].tip == 0
&& gest[i].date.mat.grupa == grupa)
{
totalSubGr[gest[i].date.mat.subgrupa] +=
gest[i].date.mat.cant * gest[i].date.mat.pret;
total += gest[i].date.mat.cant *
gest[i].date.mat.pret;
}
for (i = 0; i < 16; i++)
cout << "Total subgrupa " << i
<< ": " << totalSubGr[i] << endl;
cout << "Total grupa: " << total;
}
void DeterminareProfit(elem_gest
gest[], int n)
{
int profitTotal = 0;
for(int
i = 0; i < n; i++)
// pentru fiecare produs
if (gest[i].tip == 1)
{
// determinare cost
produs
int cost = 0;
prod_fin p
= gest[i].date.prod;
for (int j = 0; j < p.nr_mat; j++)
for(int k = 0; k < n; k++)
if
(gest[k].tip == 0 && gest[k].date.mat.cod == p.consumuri[j].cod_mat)
cost += p.consumuri[j].cant
* gest[k].date.mat.pret;
// adaugare profit
pentru produs la profitul total
profitTotal += p.cant * (p.pret - cost);
}
cout << "Profit total:" << profitTotal
<< endl;
}
void NumarMaximUnitati(elem_gest
gest[], int n, int
codProd)
{
// cautam produsul
prod_fin p;
for(int
i = 0; i < n; i++)
// pentru fiecare produs
if (gest[i].tip == 1
&& gest[i].date.prod.cod == codProd)
p = gest[i].date.prod;
int nrMax = -1;
// pentru fiecare materie prima
necesara
for (int
j = 0; j < p.nr_mat; j++)
for(int k = 0; k < n; k++)
if (gest[k].tip
== 0 && gest[k].date.mat.cod == p.consumuri[j].cod_mat)
{
int
prodRealizabile = gest[k].date.mat.cant / p.consumuri[j].cant;
// daca nu e
initializat sau daca numarul estimat
// pana acum
este prea mare
if (nrMax
== -1 || nrMax > prodRealizabile)
nrMax = prodRealizabile;
}
cout << "Numar maxim de produse realizabile: "
<< nrMax << endl;
}