. O serie de constante utilizate de aceste clase sunt definite în clasa ios. Pentru prelucrarea unui fişier se crează un obiect instanţă a uneia din clasele de mai sus care este denumit stream.
-
clasele definesc un constructor fără parametri.
Funcţiile membre importante ale claselor sunt
-
funcţia open() cu prototipul
open(char * filename, int mode);
asociază obiectul cu fişierul. Parametrul filename este un şir de caractere cu numele fişierului. Al doilea parametru este opţional şi dă modul de deschidere. El poate avea valorile
ios::in - deschidere în citire
ios::out – deschidere în scriere
ios::binary – fişier binary
Aceşti parametri se pot combina folosind operatorul | . De exemplu, pentru un fişier binar deschis în scriere vom avea
ios::binary | ios:out
iar pentru deschiderea unui fişier binar în citire
ios::binary | ios::în
Acest al doilea parametru este opţional pentru obiecte de tipul ifstream şi ofstream, care sunt automat deschise în citire şi respectiv scriere.
-
clasele definesc şi un constructor cu parametrii funcţiei open(). Acest constructor crează un obiect şi apoi deschide fişierul.
void close();
închide un fişier.
bool eof();
are valoarea adevărat dacă s-a detectat sfârşitul fişierului
bool is_open();
are valoarea adevărat dacă fişierul este deschis.
11.1 Fişiere text
Există două tipuri de operaţii intrare/ ieşire pentru fişiere tip text
-
funcţii pentru intrări / ieşiri cu format
-
funcţii ce scriu / citesc caractere
Funcţii intrare / ieşire cu format
Fişierele tip text se prelucrează în acelaşi mod ca fişierele standard de intrare şi ieşire, cin şi cout. Operatorii de citire şi scriere sunt >> şi <<.
Funcţii intrare / ieşire tip caracter
Clasele istream şi ifstream au următoarele funcţii membre pentru citirea caracterelor. Funcţia
get(char&);
citeşte un character.
Funcţia
getline(char * bloc, int size);
citeşte cel mult size caractere în vectorul bloc.
Funcţia clasei istream
getline(char * bloc, int size, char delim);
citeşte cel mult size caractere în vectorul bloc sau până la întâlnirea caracterului delim.
Funcţia globală
istream& getline(istream& file, string str, char delim) ;
citeşte caractere din obiectul file de tip istream în obiectul str de tip string până la întâlnirea caracterului delim. Valoarea implicită a caracterului delim este ‘\n’, în care caz funcţia are forma
istream& getline(istream& file, string str);
Clasele ostream şi ofstream au funcţia membră
put(char);
ce scrie un caracter.
Probleme rezolvate
Problema 1. Să se scrie un program care să calculeze valoarea unei expresii într-un anumit număr de puncte. Rezultatele calculelor se vor scrie într-un fişier text după care acest fişier va fi citit şi afişat pe ecran. Programul de rezolvare a problemei este cel de mai jos.
# include
# include
# include
using namespace std;
int main()
{
char * filename = "rez.txt";
ofstream fil1;
char separator='\t';
fil1.open(filename);
if(!fil1.is_open())
{ cout << " Nu se poate crea fisierul " << filename << endl;
return 0;
}
// calculeaza expresia
double x, e;
for(int i = 0; i < 11; i++)
{
x = i * 0.2;
e = (cos(x) * cos(x) + x) / (1.0 + fabs(x)) + sin(x);
fil1 << x << " " << e << endl;
}
fil1.close();
// citeste fisierul creat si afisaza rezulatele
ifstream fil2;
fil2.open(filename);
if(!fil2.is_open())
{ cout << " nu se poate deschide fisierul " << filename << endl;
return 0; }
cout << "x" << '\t' << "e" << endl;
fil2 >> x >> e;
while(!fil2.eof())
{ cout << x << separator << e << endl;
fil2 >> x >> e; }
fil2.close();
return 0;
}
Rezultatele rulării programului sunt cele de mai jos.
Problema 2. Să se facă un program care să copieze un fişier text. Programul va citi de la tastatură numele fişierului iniţial şi al noului fişier. Copierea se va face citind câte un octet din primul fişier şi scriindu-l în al doilea fişier. Se vor număra şi afişa octeţii citiţi. Programul de rezolvare a problemei este cel de mai jos.
# include
# include
using namespace std;
int main()
{
char filename [24];
cout << “Introduceti numele fisierului de copiat” << endl;
cin >> filename;
ifstream fila(filename);
if(!fila.is_open())
{
cout << endl << “Fisierul “ << filename << “ nu exista “ << endl;
return 0;
}
cout << endl << “Introduceti numele noului fisier” << endl;
cin >> filename;
ofstream filb(filename);
if(!filb.is_open())
{
cout << “Fisierul “ << filename << “ nu se poate crea” << endl;
return 0;
}
char car;
int nl = 0;
fila.get(car);
while(!fila.eof())
{
filb.put(car);
nl++;
fila.get(car);
}
fila.close();
filb.close();
cout << "lungimea fisierului " << nl << " caractere" << endl;
return 0;
}
Rezultatele rulării programului pentru un exemplu concret sunt cele de mai jos.
11.2Fişiere binare
Scrierea şi citirea datelor din fişierele binare se face cu funcţiile
write(char * block, int size);
read(char * block, int size);
Primul parametru este adresa unui vector de caractere de unde sunt scrise datele sau unde sunt citite datele. Al doilea parametru dă numărul de caractere de citit sau de scris.
Fişierele au indicatori interni care dau adresa următorului octet de citit sau de scris. Valoarea acestor indicatori este dată de funcţiile
tellg();
pentru indicatorul următorului octet de citit şi
tellp();
pentru indicatorul următorului octet de scris.
Indicatorii de poziţie sunt modificaţi de funcţiile
seekg(int offset, int direction);
pentru indicatorul de citire şi respectiv
seekp(int offset, int direction);
pentru indicatorul de scriere. Parametrul offset dă valoarea cu care se modifică indicatorul. Parametrul direction are valorile
ios::beg – relativă la începutul fişierului
ios::end – relativă la sfarşitul fişierului
ios::cur – relativă la poziţia curentă
Probleme rezolvate
Problema 1. Se va crea un fişier binar cu 10 blocuri cu şiruri de 10 caractere. Se va citi apoi fişierul şi se va afişa pe ecran. Programul de rezolvare a problemei este cel de mai jos.
# include
# include
using namespace std;
int main()
{
char filename[] = “fis.txt”;
char x[11];
ofstream fila;
// creaza fisierul
fila.open(filename, ios::out | ios::binary);
if(!fila.is_open())
{
cout << “ Nu se poate crea fisierul “ << filename << endl;
return 0;
}
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++)
x[j] = ‘0’ + i;
x[10] = 0;
fila.write(x, 11);
}
fila.close();
ifstream filb;
// citeste si afisaza fisierul
filb.open(filename, ios::binary | ios::in);
if(!filb.is_open())
{
cout << “Nu se poate citi fisierul “ << filename << endl;
return 0;
}
filb.read(x, 11);
while(!filb.eof())
{
cout << x << endl;
filb.read(x, 11);
}
filb.close();
return 0;
}
Rezultatele rulării programului sunt cele de mai jos.
11.3Probleme propuse
Problema 1. Să se facă un program care să calculeze dimensiunea în octeţi a unui fişier text. Lungimea se va calcula citind câte un octet din fişier.
Problema 2. Se va rezolva problema anterioară modificând indicatorul de poziţie al fişierului.
Problema 3. Să se facă un program care să calculeze numărul de linii dintr-un fişier text. Numărul de linii se va calcula citind toate liniile fişierului.
12Biblioteca de şabloane standard
12.1Clase generice
Clasele din biblioteca de şabloane standard sunt clase generice în care tipurile datelor şi funcţiilor sunt parametri. O clasă generică se defineşte cu instrucţiunea template cu forma
template
class nume_clasa
{
// definitia clasei
};
În această definiţie T1, T2, …, Tn sunt tipuri ce se pot utiliza la declararea de obiecte de tipul clasei generice. Un obiect de tipul unei clase generice se declară cu următoarea diagramă sintactică
nume_clasa nume_obiect;
Problema 1. Să definim o clasă generică X ce poate calcula pătratul unui număr întreg sau real. O reprezentare a clasei este cea de mai jos. În această reprezentare tipul T este parametrul clasei X. Definiţia clasei este cea de mai jos.
# include
using namespace std;
template
class X
{
private:
T a;
public:
X(T b) {a = b;}
T square() {return a * a;}
T geta() {return a;}
};
Să definim obiecte de tipul X ce conţin elemente de tip int sau double utilizând clasa generică X. Programul de rezolvare a problemei este cel de mai jos.
int main()
{
// crează un obiect cu şablonul
X n(2);
cout << "patratul valorii" << n.geta() << " este " << n.square() << endl;
// crează un obiect cu şablonul
X d(3.14);
cout << "patratul valorii" << d.geta() << " este " << d.square() << endl;
return 0;
}
12.2Vectori
Clasa generică vector implementează vectori cu elemente de un anumit tip. Un obiect de tip vector are un număr iniţial de componente şi dimensiunea lui creşte dacă este nevoie. Clasa vector are ca parametru tipul componentelor vectorului.
Clasa defineşte următorii constructori
-
constructorul implicit (fără parametri)
vector();
crează un vector vid
vector(vector p);
crează un vector în care copiază elementele vectorului p care este parametru
Fie T tipul componentelor vectorului (parametrul clasei generice). Clasa defineşte următoarele funcţii
-
void push_back(T&); adaugă un element la sfârşitul vectorului
-
void pop_back(); ştrege ultimul element al vectorului
-
int size(); dă numărul de componente ale vectorului
-
bool empty(); are valoarea true dacă vectorul este vid
-
operatorul [] şi funcţia T& at(int) selectează un element al vectorului
-
T& front(); are ca rezultat primul component al vectorului
-
T& back();are ca rezultat ultimul component al vectorului
Menţionăm că un vector poate avea două sau mai multe elemente egale. Clasa vector este definită în biblioteca .
Problema 2. Să creăm şi să listăm un vector cu componente întregi. Programul este următorul.
# include
# include
using namespace std;
int main()
{
// definim un vector cu componente intregi
vector v;
// adauga 4 elemente
v.push_back(12);
v.push_back(-5);
v.push_back(7);
v.push_back(13);
// afiseaza componentele vectorului
int k;
for(k = 0; k < v.size(); k++)
cout << v[k] << endl;
return 0; }
Rezultatele rulării programului sunt cele de mai jos.
12.3Liste
Clasa generică list implementează o listă dublu înlănţuită, adică o listă ce poate fi parcursă în ambele sensuri. Lista poate avea oricâte elemente de acelaşi tip. Prototipul clasei este definit în biblioteca . Clasa defineşte următorii constructori
list();
defineşte o listă vidă
list(list p);
crează o listă în care copiază elementele listei p
Fie T tipul elementelor listei. Funcţiile definite de clasa list sunt următoarele.
-
void push_back(T&); adaugă un element la sfârşitul listei
-
void push_front(T&); adaugă un element la începutul listei
-
void pop_front(); şterge primul element din listă
-
void pop_back(); şterge ultimul element din listă
-
T& front(); are ca rezultat primul element din listă
-
T& back(); are ca rezultat ultimul element din listă
Parcurgerea listelor
Pentru parcurgerea componetelor unei liste se pot utiliza iteratori. Un iterator este asemenea unui pointer la un element al listei. O listă poate fi parcursă în sens direct sau în sens invers.
Parcurgerea listelor în ordine directă
Pentru parcurgerea unei liste în ordine directă se utilizează clasa iterator care este o clasă internă a clasei list. Un obiect de tipul acestei clase se defineşte astfel
list::iterator nume_obiect;
Operatorii implementaţi de clasa iterator sunt ++, -- şi *. Pentru parcurgerea directă a listelor clasa list defineşte funcţiile
begin();
end();
ce au ca rezultat un iterator ce indică primul element al listei şi respectiv ultimul element al listei.
Parcurgerea listelor în ordine inversă
Pentru parcurgerea inversă a listelor se utilizează clasa reverse_iterator care este tot o clasă internă a clasei list. Un obiect de tipul acestei clase se defineşte ca
list::reverse_iterator nume_obiect;
Operatorii implementaţi de clasa iterator sunt ++, -- şi *. Clasa list defineşte funcţiile
rbegin();
rend();
ce au ca rezultat un iterator pentru parcurgerea în sens invers a listei ce indică ultimul element al listei şi respectiv primul element al listei.
Sortarea listelor
Pentru sortarea în ordine directă şi inversă a listelor clasa list defineşte funcţiile
void sort();
void reverse();
ce sorteză elementele listei în ordine directă şi inversă.
Problema 3. Vom crea o listă cu elemente întregi, o vom sorta ascendent şi descendent şi vom afişa elementele listei. Programul este următorul.
# include
# include
using namespace std;
int main()
{
list ls;
// adauga elemente la sfarsitul şi inceputul listei
ls.push_back(11);
ls.push_back(7);
ls.push_front(4);
ls.push_front(12);
// parcurgerea listei
cout << "lista initiala\n";
list::iterator iter;
for(iter = ls.begin(); iter != ls.end(); iter++)
cout << *iter << endl;
// sortarea elementelor listei în ordine crescatoare
ls.sort();
// parcurgerea listei sortate
cout << "lista sortata\n";
for(iter = ls.begin(); iter != ls.end(); iter++)
cout << *iter << endl;
// sortarea elementelor liste în ordine descrescatoare
ls.reverse();
// parcurgerea listei sortate
cout << "lista sortata în ordine inversa\n";
for(iter = ls.begin(); iter != ls.end(); iter++)
cout << *iter << endl;
// parcurgerea listei
cout << "parcurgerea listei în ordine inversa\n";
list::reverse_iterator iter1;
for(iter1 = ls.rbegin(); iter1 != ls.rend(); iter1++)
cout << *iter1 << endl;
return 0;
}
Rezultatele rulării programului sunt cele de mai jos.
12.4Numere complexe
Biblioteca de şabloane standard defineşte clasa complex pentru lucrul cu numere complexe. Prototipul acestei clase este definit în biblioteca . Clasa are ca parametru T, tipul double sau float al perechii de numere reale ce definesc numărul complex. Clasa defineşte următorii constructori
-
Constructorul implicit fără parametri
complex();
ce crează numărul complex 0 + i 0
complex(const complex&);
Biblioteca defineşte următorii operatori
-
cei patru operatori aritmetici +, - * , /
-
operatorii relaţionali = = şi !=
-
operatorul de scriere <<. Numărul complex u + i v este scris de operatorul << ca
(u, v)
-
operatorul de citire >>. Pentru citirea cu operatorul >> numărul complex u + i v este introdus ca
(u, v)
Clasa defineşte următorii operatori de atribuire
Biblioteca defineşte următoarele funcţii matematice standard care au ca argumente numere complexe
asin sin exp pow
acos cos log sqrt
atan tan log10
Biblioteca defineşte următoarele funcţii
-
T real();
-
T real(const complex&);
dau partea reală a numărului complex, prima este funcţie membră a clasei
-
T imag();
-
T imag(const complex&);
dau partea imaginară a numărului complex, prima este funcţie membră a clasei
are ca rezultat conjugatul numărului complex
dă valoarea absolută (norma) a numărului complex
dă pătratul valoarii absolute (normei) a numărului complex
12.5Probleme propuse
Problema 1. Să se definească o listă de şiruri de caractere. Se va parcurge lista în ambele sensuri şi se vor sorta componentele în ordine crescătoare.
Problema 2. Se va crea un vector cu elementele şiruri de caractere. Se vor lista componentele vectorului în ordine directă şi în ordine inversă.
Problema 3. Fie numerele complexe 1.2 + 3i şi -2.1 + 6.3i. Să se facă un program care să calculeze suma, diferenţa, produsul şi câtul numereleor complexe.
Problema 4. Fie functia
Să se calculeze valorile funcţiei pentru s luând valori de la 0i la 100i cu pasul 5i.