Documente Academic
Documente Profesional
Documente Cultură
Modul 2, partea 4
Cuprins
1. Sistemul de intrări-ieşiri din C++
• Introducere
• Clasa ios
• Operaţii de I/E cu format
• Utilizarea funcţiilor width(), precision() şi fill()
• Verificarea stării sistemului de I/E
• Funcţiile de I/E de tip “manipulator”
• Funcţiile de I/E de tip “manipulator”
• Crearea propriilor funcţii de tip manipulator
• Clasa ostream
• Clasa istream
• Funcţiile de tip inserter şi extractor
• Redefinirea operatorului de ieşire
• Redefinirea operatorului de intrare
• Operaţii de intrare-ieşire pe fişiere
• Operaţii de intrare-ieşire pe şiruri de caractere
2
1. Sistemul de intrări-ieşiri din C++
Introducere
3
• Sistemul de I/E din C++ operează prin conceptul de flux
(stream)
• Un stream (flux) este un dispozitiv logic, care fie
produce, fie consumă informaţie şi este cuplat la un
dispozitiv fizic prin intermediul sistemului de I/E din C++
• Altfel spus, reprezintă totalitatea modalităţilor de
realizare a unor operaţii de citire sau scriere
4
• La execuţia unui program în C++ se deschid în mod
automat următoarele fluxuri predefinite (ca urmare nu
trebuie declarate) :
– cin Intrarea standard Tastatura
– cout Ieşirea standard Ecranul
– cerr Eroarea standard Ecranul
– clog Versiunea “tampon” a lui cerr Ecranul
5
• C++ defineşte sistemul său de I/E în mai multe fişiere
antet (atenție la extensie !):
– iostream.h: conţine o ierarhie de clase, pentru operaţii de nivel
scăzut (fluxuri de caractere) sau de nivel înalt (obiecte specifice,
predefinite sau definite de utilizator);
• aici sunt definite clasele ios, istream, ostream, iostream;
6
7
• Operaţiile de I/E se bazează pe un model pe două nivele:
– nivelul superior asigură operaţii de I/E formatate pentru obiecte
specifice (predefinite sau definite de utilizator)
– nivelul inferior se ocupă cu operaţii de I/E neformatate, pentru
fluxuri de octeți:
• acest nivel se bazează pe obiecte de tipul streambuf (flux cu zonă
tampon) şi permite ascunderea detaliilor fizice de operare a DP
8
Clasa ios
10
skipws determină citirea/ignorarea caracterele de tip
whitespace (spaţiu, tab, newline) la citire
left determină alinierea rezultatului la stânga
right determină alinierea rezultatului la dreapta (implicit)
internal o valoare numerică se va extinde astfel încât
să se completeze câmpul, prin inserarea de
spaţii între caracterele de bază; pentru valoare
nenumerică este echivalent cu flagul right
dec (implicit) afişare în zecimal
oct trebuie poziţionat când se doreşte afişarea
rezultatului în octal
hex se afişează rezultatul în hexazecimal
boolalpha citește/scrie elementele booleene ca șiruri de
caractere (true și false)
11
showbase determină afişarea ieşirii în baza de numeraţie
corespunzătoare
showpoint determină afişarea tuturor zerourilor şi a
punctului zecimal ale unei valori în format de
virgulă mobilă
showpos determină afişarea semnului înaintea valorilor
zecimale pozitive
scientific generează afişarea numerelor în format de virgulă
mobilă, folosindu-se notaţia ştiinţifică (1.23e+003)
fixed când este poziţionat, valorile în format de virgulă
mobilă sunt afişate folosind notaţia normală
(123.456789)
unitbuf fiecare stream este eliberat după o operaţie de
ieşire, ceea ce determină scrierea în dispozitivul
fizic cuplat la stream
12
uppercase determină afișarea cu majusculă a caracterelor
generate de stream ( de ex. 0X pentru afișarea
unei valori în hexazecimal)
13
• Pentru a seta un flag de format, se pot utiliza metodele
setf( ), membre ale clasei ios:
• Exemplu:
cout.setf( ios::showbase | ios::hex);
14
fmtflags setf (fmtflags flags, fmtflags mask);
• Exemplu:
cout.setf(ios::hex, ios::basefield);
cout << 27 << endl;
15
• Metoda unsetf( ), membră a clasei ios, şterge unul sau
mai mulţi indicatori de format:
void unsetf (fmtflags flags);
Exemplu:
cout.setf ( ios::hex, ios::basefield );
cout.setf ( ios::showbase );
cout << 200 << '\n';
cout.unsetf ( ios::showbase );
cout << 200 << '\n';
16
• Metoda flags( ), membră a clasei ios înapoiază starea
curentă a fiecărui indicator de format, codificat într-o
variabilă de tip fmtflags
• Prototipuri :
fmtflags flags( );
fmtflags flags( fmtflags f);
17
#include <iostream>
using namespace std;
void main( )
{
// afişarea valorilor folosind poziţionările implicite
cout<< 123.33 << " salut! " << 100 <<'\n';
cout<< 10 << ' ' << -10 <<'\n';
cout << 100.0 <<'\n';
// schimbăm formatul
cout.unsetf(ios::dec);
cout.setf ( ios::hex | ios::scientific);
cout << 123.33 << " salut! " << 100 <<'\n';
cout.setf(ios::dec);
cout.setf (ios::showpos);
cout <<10 << ' ' << -10 << '\n';
cout.setf (ios::showpoint);
cout << 100.0 << '\n';
cin.get( ); 18
}
Utilizarea metodelor width( ), precision( ) şi fill( )
21
#include <iostream>
using namespace std;
void main(void)
{
cout.width(10); // lătimea minima a campului
cout<<“salut”<<“\n”; // implicit, alinierea se face la dreapta
cout.fill(‘%’); // stabilirea caracterului de completare
cout.width(10);
cout<<”salut”<<“\n”; // alinierea la dreapta
cout.setf(ios::left); // alinierea la stanga
cout.width(10);
cout<<”salut”<<“\n”; // alinierea se face la stanga
cout.width(10);
cout<<123.234567<< “\n”; // se utilizeaza formatul implicit
cout.width(10); // se stabileste latimea
cout.precision(3); // se stabileste precizia (nr. total de cifre)
cout<<123.234567<<“\n”;
cin.get( );
22
}
Verificarea stării sistemului de I/E
Nume Semnificaţie
goodbit Are valoare 0, dacă nu există erori
Are valoare 1, dacă se semnalează o eroare
eofbit Are valoare 1 când se întâlneşte EOF
Are valoare 0 în caz contrar
failbit Are valoare 1, când s-a produs o eroare nefatală; în caz
contrar are valoare 0
badbit Are valoare 1, în caz de eroare fatală şi 0 în caz contrar
23
• Există două moduri prin care putem obţine informaţii
despre starea sistemului de I/E:
– în primul caz, se poate apela metoda membră iostate
rdstate( );
• returnează starea curentă a indicatorilor de eroare
24
void clear (iostate state = goodbit);
– permite stabilirea unor noi valori pentru indicatorii de eroare
– pentru valoarea implicită, se șterg toți indicatorii de eroare
Functii
Val.
indica
iostate good() eof() fail() bad() rdstate()
S-a atins
eofbit false true false false eofbit
EOF
Eroare de
badbit false false true true badbit
citire/scriere 25
while (!IN.eof( ))
{
IN.get (car) ;
// verifică eroarea
if ((! IN.good()) && (! IN.eof( ) ))
{
cout << ”Eroare de I/E …..se termina programul\n” ;
return 1;
}
}
…
26
Funcţiile de I/E de tip “manipulator”
27
• Manipulatorii pot să apară în lanţul de operaţii de I/E şi
afectează doar fluxul (stream) asociat, nu şi alte fluxuri
deschise în mod curent
• Principalul avantaj al manipulatorilor constă în faptul că
sunt mai uşor de utilizat şi permit scrierea mai
compactă a codului
• Mulţi manipulatori se aseamănă cu metodele membre
ale clasei ios
28
Manipulator Scop Intrare/ Ieşire
void main(void)
{
cout << hex << 100 << endl;
cout << oct << 100 << endl;
cout << setfill( ‘X’) << setw (10);
cout << 10 << endl << endl;
cin.get( );
}
30
Crearea propriilor funcţii de tip manipulator
31
• Forma generală a manipulatorilor de ieşire, fără
parametri, este:
ostream& nume-manipulator (ostream& stream)
{
// cod
return stream;
}
32
• Sintaxa funcţiilor manipulator de intrare, fără parametri,
este dată mai jos:
istream& nume manipulator (istream& stream)
{
// cod
return stream;
}
33
Exemplu:
# include <iostream>
#include <iomanip>
void main(void)
{
cout<< init << 123.123456 << endl << endl;
cin.get( );
}
34
Clasa ostream
35
• Metode membre:
– ostream& put (char);
– ostream& write (const char *s, int n);
– ostream& flush ( ); // goleste zona tampon asociata
– long tellp ( ); // returneaza pozitia curenta in flux
– ostream& seekp (long, seek_dir = ios::beg);
– enum seek_dir {beg, cur, end};
36
• Supraîncărcări ale operatorului de inserție:
– ostream& operator<< (bool val);
– ostream& operator<< (short val);
– ostream& operator<< (unsigned short val);
– ostream& operator<< (int val);
– ostream& operator<< (unsigned int val);
– ostream& operator<< (long val);
– ostream& operator<< (unsigned long val);
– ostream& operator<< (float val);
– ostream& operator<< (double val);
– ostream& operator<< (long double val);
– ostream& operator<< (void* val);
37
Clasa istream
38
• Metode membre :
– int get ( );
• extrage următorul caracter (inclusiv EOF)
– istream& get (char &c );
• extrage următorul caracter și îl depune la adresa dată
– istream& get (char *s, streamsize n, char delim = '\n');
• extrage și depune la adresa dată cel mult (n-1) caractere, până la
întâlnirea caracterului delimitator (implicit ‘\n’);
• caracterul delimitator nu este extras;
• dacă n>0, se adaugă automat caracterul null (‘\n’) la sfârșitul lui
s (chiar dacă nu se extrag caractere din flux)
– int peek ( );
• returnează următorul caracter din flux fără a-l extrage
• caracterul respectiv rămâne în flux pentru următoarea operație de
extracție
39
– istream& putback (char);
• pune înapoi în flux un caracter extras anterior
– istream& read (char *s, int n);
• extrage până la n caractere dar se oprește la întâlnirea EOF
• nu se adaugă caracterul null (‘\n’) la sfârșitul lui s
– istream& getline (char *s, int n, char = '\n’);
• extrage și depune la adresa dată cel mult n-1 caractere;
• extragerea se oprește la întâlnirea caracterului specificat sau la
întâlnirea EOF; caracterul delimitator este extras dar este neglijat
(nu este depus în s);
• se pune automat delimitatorul de șir (‘\0’) la coada lui s;
– int gcount ( );
• returnează numărul de caractere extrase la ultima operație de
intrare (cu metodele get, getline, ignore, read)
40
– istream& ignore (int n = 1, int delimi = EOF);
• extrage și ignoră caractere până când au fost extrase n caractere
sau a fost întâlnit caracterul delimitator specificat; extragerea se
oprește la întalnirea EOF (cu setarea bitului eofbit);
– long tellg ( );
• returnează poziția curentă în fluxul de intrare
– istream& seekg (long, seek_dir = ios::cur);
• mută poziția curentă în fluxul de intrare, în raport cu poziția de
început, de sfârșit sau în raport cu poziția curentă
41
Supraîncărcări ale operatorului de extracție:
– istream& operator>> (bool& val);
– istream& operator>> (short& val);
– istream& operator>> (unsigned short& val);
– istream& operator>> (int& val);
– istream& operator>> (unsigned int& val);
– istream& operator>> (long& val);
– istream& operator>> (unsigned long& val);
– istream& operator>> (float& val);
– istream& operator>> (double& val);
– istream& operator>> (long double& val);
– istream& operator>> (void*& val);
42
Funcţiile de tip “inserter” şi “extractor”
43
Redefinirea operatorului de ieşire
45
Exemplu:
# include <iostream>
#include <iomanip>
class COORD {
int x, y;
public:
COORD( ) {
x=0; y=0;
}
COORD(int i, int j) {
x=i; y=j;
}
friend ostream &operator<< (ostream& , COORD OB);
friend istream &operator>> (istream& , COORD &OB);
};
46
// inserter pentru clasa COORD
ostream& operator<<(ostream& STREAM, COORD OB)
{
STREAM << "abscisa: " << OB.x << ", ordonata: " << OB.y << '\n';
return STREAM;
}
47
// functia main
void main (void)
{
COORD A(1,1), B(10,24);
cout << "Obiecte cu coordonate predefinite: " <<endl;
cout<< "\tObiect1: “ <<A << "\tObiect2: “ <<B;
cout<< "\nCoordonate noi: ";
cin >> A;
cout << "Afisare coordonate noi:"<<endl<<'\t';
cout << A;
cin.get( );
}
48
• In C++ toate stream-urile sunt identice, de aceea un
operator redefinit de tip inserter (de exemplu), poate fi
folosit pentru a trimite rezultatele pe ecran sau într-un
fişier
• Supraîncărcarea operatorilor de I/E oferă simplitate şi
elimină necesitatea memorării denumirilor unor funcţii
de I/E supraîncărcate pentru fiecare tip de date
49
Operaţii de I/E cu fişiere
• Pentru a realiza operaţii de I/E cu fişiere, trebuie să
includem în program fişierul antet fstream.h, care
defineşte mai multe clase:
– ifstream, ofstream şi fstream
50
• In C++, un fişier este deschis prin cuplarea lui la un flux
(stream)
• Inainte de deschiderea fişierului trebuie să declarăm
mai întâi un flux (stream)
• Pentru a crea un flux (stream) de intrare, el trebuie
declarat ca fiind de tip ifstream, iar pentru a crea unul
de ieşire, streamul trebuie declarat de tip ofstream
• Fluxurile care realizează ambele tipuri de operaţii
trebuie declarate de tip iofstream
• Exemple:
ifstream in;
ofstream out;
iofstream io;
51
Deschiderea/închiderea unui fişier
52
• Lista valorilor posibile pentru al doilea parametru este
definită în clasa “ios” astfel:
in (input) fişier de intrare
out (iutput) fişier de ieşire
ate (at end) după deschidere, poziţia curentă va fi
chiar sfârşitul fişierului
app (append) deschis pentru adăugare (scriere la
sfârşit de fişier)
trunc (trucate) dacă fişierul există îi şterge conţinutul
(opţiune implicită în caz că e vorba de un fişier de
ieşire şi nu apare una dintre opţiunile “ios::app”
sau “ios::ate”)
binary deschidere în mod binar
53
• Sunt permise înlănţuiri ale specificatorilor modului de
deschidere prin “SAU LOGIC” la nivel de bit
• Majoritatea modurilor de deschidere corespund modului
text de lucru cu fișierele; modul binar trebuie precizat
explicit
• Parametrul mod are valori implicite:
– pentru un obiect de tip ifstream : ios::in
– pentru un obiect de tip ofstream : ios::out
– pentru un obiect de tip fstream : ios::in | ios::out
• Metoda open() poate fi apelată explicit (după declararea
obiectului flux) sau implicit (în momentul declarării):
ifstream in;
in.open(“Text.txt”);
sau
ifstream f1(“Text.txt”);
54
• Dacă operaţia de deschidere a fişierului eşuează fluxul
va avea valoarea zero
• Inainte de utilizarea unui fişier trebuie să verificăm dacă
operaţia de deschidere a reuşit, folosind o secvenţă de
genul:
if (!stream_propriu)
{
cout<< “Nu se poate deschide fişierul…\n”;
// trateaza eroarea
}
55
– Cuplarea unui flux la un fisier (sau deschiderea unui
fisier) poate fi verificată și cu metoda:
bool is_open();
ifstream f1(“Test.txt”);
if (! f1.is_open())
{
cout<< “Nu se poate deschide fişierul…\n”;
// trateaza eroarea
}
56
• Pentru a închide un fişier cuplat la un stream se
foloseşte metoda:
stream_propriu.close( );
57
Fișiere text vs Fișiere binare
• Un fișier text conține caractere ce pot fi vizualizate și
interpretate, fiecare caracter având asociat un cod
reprezentat (uzual) pe 1 octet. Un fișier binar conține
octeți cu conținut binar (biți cu valori 0 și 1), mai mulți
octeți pot corespunde unei valori într-un anumit format
• Pentru fișiere binare, caracterul newline sau LF (\n) este
convertit automat în secvența de două caractere CR-LF.
Pentru fișiere binare acest lucru nu este valabil
• Intr-un fișier text, sfărșitul de fișier este marcat de fiecare
dată cu un caracter special având codul ASCII 26. Un
astfel de caracter nu este prezent într-un fișier binar
58
#include <iostream>
#include <fstream>
using namespace std;
void main(void)
{
ofstream FOUT (“test”); // creaza un fisier de iesire
if (!FOUT) {
cout<<”Nu se poate deschide fisierul de iesire\n”;
exit(0);
}
FOUT<< ”Salut!\n”;
FOUT<< 100 << ’ ‘ << hex << 100 << endl;
FOUT.close( );
59
ifstream FIN(“test”); // deschide un fisier de intrare
if (!FIN) {
cout<<”Nu se poate deschide fisierul de intrare\n”;
exit(0);
}
char sir[80];
int i;
FIN>>sir>>i;
cout << sir << ’ ‘ << i << endl;
FIN.close( );
}
60
Citirea/scrierea datelor în fişiere
61
Exemplul 1:
#include <iostream>
using namespace std;
#include <fstream>
void main(void)
{
int numar=12;
char sir[20];
IN.getline(sir, 19);
IN.read ((char*) &numar, sizeof(int));
cout << sir << ' ' << numar << endl;
IN.close( ) ;
}
63
Exemplul 2:
#include <iostream>
using namespace std;
#include <fstream>
void main( )
{
char infname[101];
char outfname[101];
char buffer[101];
cout << ”File to copy from: ";
cin >> infname;
ifstream in(infname);
if (!in) {
cout << "Unable to open " << infname << endl;
exit(0);
} 64
cout << "File to copy to: ";
cin >> outfname;
ofstream out(outfname);
if (!out) {
cout << "Unable to open " << outfname << " -- already exists!" <<
endl;
exit(0);
}
in.getline(buffer,100);
while (!in.eof( )) {
out << buffer << endl;
in.getline(buffer,100);
}
in.close( );
out.close( );
}
65
Exemplul 3:
#include <iostream>
#include <string>
#include <fstream>
class Student
{
int marca;
string nume;
double media;
void display()
{
cout << "\n\tMarca\tNume\tMedia";
cout << "\n\t" << marca << "\t" << nume << "\t" << media << "\n";
}
66
public:
Student()
{
marca = 0;
nume = "";
media = 0;
}
67
static void AddRecord(string fis, Student Stu)
{
fstream f;
f.open(fis, ios::app | ios::binary);
if (f) {
f.write((char *)&Stu, sizeof(Stu));
f.close();
}
}
68
static void Display(string fis)
{
Student Stu;
fstream f(fis, ios::in | ios::binary);
if (f) {
while ((f.read((char*)&Stu, sizeof(Stu)))) {
Stu.display();
}
f.close();
}
}
};
69
void main()
{
int n = 4;
Student tab[4];
Student::Display("Student.dat");
cin.get();
}
70
Operaţii de I/E pe şiruri de caractere
71
• Clasele specificate sunt similare cu cele destinate
lucrului pe fişiere, fiind derivate din clasele iostream
corespondente şi ca urmare moştenesc metodele
membre ale acestora
• De exemplu pentru operaţii de intrare se pot folosi
metodele membre ale clasei istream (get( ), read( ),
getline( )) iar pentru operaţii de ieşire se pot folosi
metodele clasei ostream (put( ), write( )) dar și operatorii
de inserție și extracție
• Un obiect ostringstream poate fi folosit pentru a scrie
într-un șir de caractere (similar cu funcția sprintf())
• Un obiect istringstream poate fi folosit pentru a citi dintr-
un șir de caractere (similar cu funcția sscanf())
• Un obiect stringstream poate fi folosit atât pentru a citi
cât și pentru a scrie din/într-un șir de caractere
72
Constructori de tipul StringStream
• stringstream( )
• stringstream( openmode mode )
• stringstream( string s, openmode mode )
• ostringstream( )
• ostringstream( openmode mode )
• ostringstream( string s, openmode mode )
• istringstream( )
• istringstream( openmode mode )
• istringstream( string s, openmode mode )
Supraîncărcări
• operator<<
• operator>>
73
Alte metode:
• void str( string s );
– Permite obținerea unei copii a șirului asociat unui obiect
cout << stream1.str();
• string str();
– Permite copierea unui șir într-un obiect
stream1.str(string1);
74
Exemple:
ostringstream s1;
int i = 22;
s1 << “i = " << i << endl;
string s2 = s1.str();
cout << s2;
istringstream stream1;
string string1 = "25";
stream1.str(string1); // istringstream stream1 (string1);
int i;
stream1 >> i;
cout << i << endl;
75
// conversii intre un tip predefinit si tipul string
…
double d = 123.45;
ostringstream os;
os << d;
string s = “d = " + os.str();
cout << s << endl;
76
// conversii intre baze de numeratie
int decimal = 61;
stringstream sstr;
sstr << hex << decimal;
cout << “Valoarea in baza 16: " << sstr.str();
77