Documente Academic
Documente Profesional
Documente Cultură
1.1. Structuri
1.1.1. Definire
O structură este un tip de date nou. Atunci când definim o structură, trebuie să specificăm
numele structurii şi câmpurile ei:
struct student {
char* nume;
int nota;
};
Am introdus tipul struct student. Pentru a evita repetarea lui struct putem să
introducem un pseudonim pentru tipul struct student si anume Student astfel:
typedef struct {
char* nume;
int nota;
} Student ;
struct Student {
char* nume;
int nota;
};
1
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
poate fi denumit struct Student sau, doar simplu, Student. In continuare ne vom
folosi de această facilitate C++ care măreşte lizibilitatea programelor.
Am definit structura Student având CÂMPURILE "nume" (adresa unui sir de caractere)
si "nota" de tip int.
Student
┌─────────────────┐
nume nota
╔═════════╤══════╗
║ ■ │ 10 ║
╚════╪════╧══════╝
│ ╔═══╤═══╤═══╤═══╤════╗
└─────────────> ║'R'│'a'│'d'│'u'│'\0'║
╚═══╧═══╧═══╧═══╧════╝
Operatorul . cere in stânga sa o valoare stânga de tip structura iar in dreapta, numele
câmpului selectat, rezultatul fiind o valoare-stânga care se refera la câmpul selectat. De
exemplu, din declaraţiile de mai sus, câmpurile variabilei grupa[3] vor fi denumite:
grupa[3].nume si grupa[3].nota
grupa[3]
╔════════════════╤═══════════════╗
║ grupa[3].nume │ grupa[3].nota ║
╚════════════════╧═══════════════╝
grupa[3] . nota
└──┬───┘ └─┬┘
┌────┘ │
variabila_structura . câmp
2
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
Operatorul -> cere in stânga sa o expresie de tip "pointer la structura" iar in dreapta
numele câmpului selectat, rezultatul fiind o valoare-stânga care se refera la câmpul
selectat:
ps
╔═══════╗
║ ■ ║
╚═══╪═══╝ *ps
│ ╔════════════════╤═══════════════╗
└───────>║ ps->nume │ ps->nota ║
╚════════════════╧═══════════════╝
ps->nota
┌─────┘ │
pointer_la_structura -> câmp
1.2. Pointeri
1.2.1. Definire
Exemple:
1.2.2. Iniţializare
Prima operaţie care se face cu un pointer este iniţializarea. Un "pointer la T" poate fi
iniţializat cu:
pi = &i;
pi i
╔═══════╗ ╔═══════╗
║ ■───╫──────> ║ ║
╚═══════╝ ╚═══════╝
*pi
cap = 0; cap
╔═══════╗
║ 0 ║
╚═══════╝
c) valoarea altui "pointer la T". De exemplu: daca p si q sunt de tip T* si p conţine
adresa unei variabile de tip T (a fost iniţializat in prealabil), atribuirea q = p va face ca
ambii pointeri sa indice aceeaşi variabilă.
p
╔═══════╗ ╔═════════╗
║ ■───╫─────────>║ ║
╚═══════╝ ┌───>╚═════════╝
q │
╔═══════╗ │
║ ■───╫─────┘
╚═══════╝
d) adresa unui spaţiu de memorie alocat in zona de alocare dinamica. Spaţiul alocat poate
sa conţină un singur obiect de tip T, acesta se exprima:
p *p
╔═══════╗ ╔═══════╗
║ ■───╫──────> ║ ║
╚═══════╝ ╚═══════╝
Exprimările din C++ sunt in mod evident mult mai simple si le vom folosi pe acestea in
continuare.
Iată un exemplu:
4
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
Este operaţia prin care având un "pointer la T" (care conţine adresa unui T) obţinem o
valoare stânga care se refera la obiectul pointat (vezi operatorul *).
Numele unui "tablou de T" este convertit automat la tipul "pointer la T", deci poate fi
folosit pentru a iniţializa un "pointer la T". Valoarea acestui pointer este adresa primului
element al tabloului:
T tab[10];
T* ptrT = tab; // ptrT conţine adresa primului element
Un "pointer la T" este deseori folosit pentru a se referi pe rând la elementele unui tablou.
Daca un pointer a fost iniţializat cu adresa unui spaţiu din zona de alocare dinamică,
atunci când nu mai avem nevoie de spaţiul respectiv (adică nu mai avem nevoie de
obiectul din spaţiul respectiv) vom elibera spaţiul. El va putea fi astfel utilizat pentru
alocări ulterioare.
Daca p este un pointer care a fost iniţializat printr-o alocare de memorie, eliberarea
memoriei alocate se exprimă:
in C: free(p);
in C++: delete p;
5
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
!!!Atentie!!!
Nici free() nici delete nu modifică valoarea pointerului p, dar obiectul a cărui adresa
este conţinută de p nu trebuie sa fie referit după eliberare.
1.2.6. Observaţie
In laboratoarele următoare, vor exista cazuri in care anumiţi pointeri nu sunt variabile
simple, ci vor fi componente ale unor structuri de date complexe. Toate regulile de mai
sus se păstrează.
1.3. Referinţe
O referinta este un alt nume pentru o variabila, un pseudonim. In esenta, o referinta este
un pointer implicit.
1.3.1. Utilizare
Referinte independente
La crearea unei referinte independente, in fapt, se creeaza un alt nume pentru o variabila.
Toate referintele independente trebuie initializate la declarare. Ulterior nu se poate
modifica ce obiect refera o referinta.
int a;
int &ref = a; //referinta independenta (ref este un alt nume pt. a)
a = 10;
cout << a << " " << ref << endl;
ref = 100;
cout << a << " " << ref << endl;
int b = 19;
ref = b; //face ca a si ref sa ia valoarea lui b
//(ref nu devine o referinta pt. b)
cout << a << " " << ref << endl;
ref--; //decrementeaza pe a
cout << a << " " << ref << endl;
6
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
Transmiterea prin referinţă este utilizată atunci când dorim ca la revenirea din funcție
variabila transmisă să reţină modificarile aduse in functie.
În acest caz, parametrii actuali trebuie să fie referinţe la variabile. La transmitere,
subprogramul reţine în stivă adresa variabilei. La compilare, orice referinţa la o variabilă
este tradusă în subprogram ca adresare indirectă. Acesta este motivul pentru care în
subprogram putem adresa variabila normal (nu indirect), cu toate că, pentru o variabilă
transmisă, se reţine adresa ei.
Exemple:
Functia a lucrat cu variabila locala i care Functia a lucrat cu variabila locala i care
reprezinta o copie a variabilei x reprezinta adresa lui x
7
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
int main() {
int x = 10;
neg(x);
cout << "Dupa inversare: " << x << endl;
return 0;
}
Dupa inversare: -10
Functia a lucrat cu variabila locala i care reprezinta o referinta la x (un alt nume pentru
x)
8
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
int main() {
int x = 5;
int y = 10;
swap(x, y);
cout << "Dupa swap: x=" << x << " y=" << y << endl;
return 0;
}
Dupa swap: x=10 y=5
Variabilele a si b sunt variabile locale functiei swap care sunt initializate la momentul
apelului acestei functii ca referinte la variabilele cu care s-a realizat apelul.
Daca argumentele au tipuri mai complicate, atunci sintaxa din interiorul funcţiei devine
greoaie. Pentru a rezolva aceasta problema putem trimite ca argumente REFERINTE. Un
argument referinţa trebuie interpretat ca fiind un PSEUDONIM pentru argumentul pasat.
Orice modificare a referinţei se va face asupra argumentului pasat:
9
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
int a;
cin >> a;
cin >> a;
În mod similar, operatorul << are o semnificaţie specială pentru variabila cout.
Expresia:
semnifică faptul că variabila str este scrisă la consola. Variabilele scrise pot fi de
aceleaşi tipuri ca şi cele citite cu cin.
Observaţi că în exemplul de mai sus a fost scrisă la consolă o variabilă de tip
char[], tip care nu a fost menţionat în lista de tipuri suportate pentru operandul dreapta.
Totuşi, utilizarea lui a fost posibilă într-o expresie cu cout. De ce?
Variabilele cin şi cout sunt definite în header-ul <iostream>. Pentru a le putea
folosi, trebuie să includem la începutul programului următoarele linii:
10
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
#include <iostream>
using namespace std;
Aceste variabile speciale fac parte din categoria “obiecte”. Obiectele vor fi
studiate în detaliu la Programare orintată obiect (POO).
Iată un exemplu complet folosind noile facilităţi de scriere/citire:
int main()
{
int iVal;
char sVal[30];
Un aspect nou este cuvântul endl. Acesta este o variabilă globală tip şir de caractere cu
valoarea "\n" (sfârşit de linie).
Sintaxa:
cout << a;
11
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
Comparativ cu funcţiile printf / scanf din C, expresiile cu cin şi cout sunt mai simple şi
mai uşor de înţeles. Nu mai este nevoie de specificatori de format. Dezavantajul este că
nu putem face afişări formatate pe un anumit număr de caractere. O afişare de genul:
printf("%7.2f", f);
În C++, lucrul cu memoria dinamică este facilitat de doi operatori speciali - new şi delete.
Alocarea dinamică de memorie se face cu operatorul new. El returnează un pointer către
începutul blocului de memorie proaspăt alocat. Sintaxa operatorului este următoarea:
Atunci când nu mai avem nevoie de o variabilă alocată dinamic, aceasta trebuie
dealocată. Memoria dealocată devine disponibilă pentru noi cereri de alocare. Pentru
dealocari se folosesc operatorii delete – pentru variabile simple, şi delete[] – pentru
vectori. Exemplu:
delete vi;
delete[] psir;
12
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
2. APLICAŢII
1. Sa se scrie un program care citeste studentii dintr-o grupa si ii afiseaza. Programul va fi
impartit in trei module:
Modulul Student
#ifndef _STUDENT_
#define _STUDENT_
struct Student {
char* nume;
int nota;
};
#endif
Modulul Grupa
#ifndef _GRUPA_
#define _GRUPA_
#include "student.h"
struct Grupa {
Student* tab;
int nr;
int id; // numarul grupei, de exemplu 1105
};
13
Laborator de Structuri de Date si Algoritmi – Lucrarea nr. 1
#endif
■ InitGrupa citeste numarul grupei si numarul de studenti, dupa care va aloca spatiu cu
malloc pentru acestia. Fiecare student va fi apoi initializat cu InitStudent.
■ AfisGrupa afiseaza studentii.
■ StergeGrupa va elibera spatiul de memorie ocupat de cei nr studenti.
Modulul Program principal
#include <stdio.h>
#include "student.h"
#include "grupa.h"
void main()
{
Grupa g;
InitGrupa(g); // citeste studentii
AfisGrupa(g); // afiseaza grupa
StergeGrupa(g); // elibereaza spatiul
}
2. In cadrul programului anterior, adaugati o functie care cauta un student dupa nume si
afiseaza nota acestuia in cazul in care este gasit, sa un mesaj corespunzator daca nu este
gasit.
3. In cadrul programului anterior, adaugati o functie care afiseaza nota cea mai mica si
nota cea mai mare obtinute de studentii din cadrul unei grupe.
NOTARE
Problema 1 – 7p
Problema 2 – 3p
Problema 3 – 2p
14