Ulazno-izlazna biblioteka
Standardna ulazno izlazna biblioteka brine o prijenosu podataka između programa, datoteka te standardnog ulaza (tastature) i standardnog izlaza (ekrana). Prijenos podataka je konceptualiziran kao tok podataka (eng. stream) između programa i vanjskog medija.
Ulazno izazni tipovi su definirani u tri datoteke zaglavlja:
<iostream> |
<fstream> |
<sstream> |
Pojedini tipovi su u sljedećoj tabeli raspoređeni prema datotekama zaglavlja.
Zaglavlje | Tipovi |
---|---|
<iostream> |
istream čita iz streama |
ostream piše u stream |
|
iostream čita iz i piše u stream |
|
<fstream> |
ifstream čita iz datoteke |
ofstream piše u datoteku |
|
fstream čita iz i piše u datoteku |
|
<sstream> |
istringstream čita iz stringa |
ostringstream piše u string |
|
stringstream čita iz i piše u string |
Standardni ulaz i izlaz
Za unos podataka koristimo istream objekt cin kojeg obično nazivamo standardni ulaz.
Za ispis podataka na standardni izlaz koristimo ostream objekt cout. Pored njega prisutna su još dva ostreama objekta, cerr i clog koji služe za ispis grešaka i logova (standardni izlazi za greške i logove).
Standardni ulazno-izlazni tokovi vezani su za terminal u kojem se program izvršava, no na većini operacijskih sustava mogu se preusmjeriti.
Primjer:
#include <iostream>
int main()
{
int v1, v2;
std::cout << "Unesite dva broja:"<<std::endl;
std::cin >> v1 >> v2;
std::cout << "Suma brojeva " << v1 << " i " << v2
<< " je jednaka " << v1+v2 << "." << std::endl;
return 0;
}
Ispis
Za ispis podataka na izlazni tok koristimo operator <<. Taj se operator u primjeru
std::cout << "Unesite dva broja:"<< std::endl;
koristi dva puta. Operator na lijevoj strani mora biti ostream objekt, dok je na desnoj strani operand koji se ispisuje.
To je ekvivalentno naredbama
std::cout << "Unesite dva broja:";
std::cout << std::endl;
endl je jedan od tzv. manipulatora i definiran je u imeniku std. Njegov efekt pri ispisu na izlazni tok je ispis znaka za prijelaz u novi red i slanje međuspremnika na izlaz (flushing) što osigurava trenutni ispis čitavog međuspremnika koji čuva podatke koji su poslani na izlazni tok ali još nisu ispisani.
Operator <<
vrši formatirano ispisivanje. U kojem formatu će podatak biti ispisan
ovisi o tipu podatka koji se ispisuje.
Unos
Čitanje podataka s ulaznog toka vrši se pomoću operatora >>. Lijevi operand je ulazni tok, a desni je varijabla u koju se podatak upisuje. Operacije čitanja možemo ulančavati. Izraz
std::cin >> v1 >> v2;
je ekvivalentan s
std::cin >> v1;
std::cin >> v2;
Operator >>
služi za formatirano učitavanje. U kojem formatu će podatak biti
učitan ovisi o tipu varijable u koju se učitavanje vrši.
Testiranje toka
Podatke sa standardnog ulaza možemo sekvencijalno čitati se dok ne
naiđemo na kraj ulaz tako da ispitujemo stanje toka u while
petlji ili
if
naredbi. U sljedećem primjeru sumiramo sve učitane brojeve, ne znajući
unaprijed koliko će ih biti.
#include <iostream>
int main()
{
int v, suma= 0;
while(std::cin >> v)
suma += v;
std::cout << "Suma = " << suma << std::endl;
return 0;
}
Čitanje podatka sa standardnog ulaza dešava se u while petlji:
while(std::cin >> v)
Nakon što je podatak pročitan izraz vraća ulazni tok koji se testira u
while
naredbi. Prilikom testiranja toka vraća se njegovo stanje
koje može biti ispravno ili neispravno. Stanje ulaznog toka je ispravno
ako je moguće pročitati sljedeći podatak iz toka. U suprotnom je neispravno i tada će while
petlja završiti.
Ulazni tok dolazi u neispravno stanje u slučaju pogreške ili nailaska na kraj toka (end-of-file marker). Stoga u ovakvom kodu ta dva događaja nije moguće razlikovati. U oba slučaja petlja će se zaustaviti.
Pri čitanju sa standardnug ulaza, da bismo zaustavili čitanje, trebamo unijeti end-of-file marker. Na Linux i Mac OS-X sustavima to je obično Enter i Ctrl-d, a pod Windowsima Enter i Ctrl-z.
Funkcije za čitanje - getline
Stringove možemo čitati sa standardnog ulaza kao i sve druge podatke pomoću operatora >>
. Pri tome treba
znati da se kao delimiter između različitih stringova koriste bjeline (koje pored bjelina
uključuju tabulatore i znak za prijelaz u novi red). Dakle, pri upisu bit će preskočene
prethodne bjeline i čitanje će biti zaustavljeno nailaskom na prvu bjelinu. To
ilustrira sljedeći primjer:
#include <iostream>
#include <string>
int main()
{
std::string word;
while(std::cin >> word)
std::cout << word<< std::endl;
return 0;
}
Ukoliko želimo pročitati čitavu liniju sa svim eventualnim bjelinama trebamo koristiti
globalnu funkciju getline
istream& std::getline ( istream& is, string& str );
koja je deklarirana u zaglavlju <string>. Ona čita do znaka za prijelaz u novi red, koji pročita i odbaci. Vraća ulazni tok koji se može testirati kao u sljedećem primjeru u kojem učitavom ulaz liniju po liniju sve do kraja ulaznog toka.
#include <iostream>
#include <string>
int main()
{
std::string line;
while(std::getline(std::cin, line))
std::cout << line << std::endl;
return 0;
}
Da li je učitavanje uspjelo saznajemo testiranjem ulaznog toka.
Napomena. std::getline()
pročita znak za prijelaz u novi red ali ga ne dodaje u
string.
Napomena. Ulazni tokovi imaju metodu članicu getline()
istog imena i
iste funkcionalnosti, ali ona radi
sa C-stringovima (nizovima znakova završenim nul znakom).
Fukcija getline()
ima i treći parametar koji ima predodređenu vrijednost.
Taj parametar je separator i ako se ne zada ima vrijednost prijelaza u novi red (\n).
istream& std::getline ( istream& is, string& str, char separator );
Zadavanjem bjeline kao separatora moguće je ulazni tekst čitati riječ po riječ.
Funkcije za čitanje - get
U nekim situacijama zgodnije je čitanje vršiti znak po znak. Tome služi funkcija
std::istream & std::istream::get(char & c)
koja će učitati sljedeći znak u varijablu c te vratiti ulazni tok na kome možemo provjeriti je li upis uspio. Sljedeći primjer ilustrira takav način učitavanja:
#include <iostream>
#include <string>
using namespace std;
int main()
{
char c{'\0'};
string text;
// Funkcija get će učitati svaki znak. Zaustavljanje
// unosa se postiže sa enter i Ctrl-D (linux)
// ili sa enter i Ctrl-Z (windows).
while( cin.get(c) )
text.push_back(c);
cout << text << endl;
return 0;
}
Isti efekt se postiže ako na cin
uklonimo zastavicu skipws
koja određuje
da se bjeline preskaču ako je postavljena, odnosno ne preskaču ako nije.
char c{'\0'};
std::string text;
cin.unsetf(ios::skipws); // ukloni zastavicu
while(cin >> c)
text.push_back(c);
cin.setf(ios::skipws); // vrati zastavicu
cout << text << endl;
Stanje streama
Kod učitavanja podatak greške se redovito dešavaju. IO biblioteka ima stoga niz metoda koje indiciraju u kakvom je stanju stream (ulazni kao i izlazni).
Stanje streama je određeno variablom tipa std::iostate
definiranoj u klasi std::ios_base
. Predefinirano je nekoliko konstanti tipa iostate
koje su dane u sljedećoj tabeli:
Konstanta | Značenje |
---|---|
|
Sve je uredu. |
|
Došlo se do kraja datoteke (nađen end-of-file). |
|
Greška; operacija neuspješna. |
|
Fatalna greška. |
Razlika između situacija koje signaliziraju failbit
i badbit
je sljedeća: badbit
signalizira da je stream korumpiran i podaci su eventualno
izgubljeni. Čitanje stoga nije moguće nastaviti. failbit
, s druge strane, kaže da je
zadnje čitanje neuspjelo
no stream je u konzistentnom stanju i čitanje se može nastaviti.
eofbit
se postavlja kada se pokuša čitati iza EOF znaka. Istovremeno s njim se postavlja i
failbit
.
Funkcije koje daju stanje streama
Biblioteka definira niz funkcija za manipuliranjem sa stanjem streama. Kada želimo saznati stanje neke zastavice trebamo
koristiti te funkcije budući da one vraćaju true
ili false
, dok je tip zastavice određen sustavom.
Poziv funkcije | Povratna vrijednost |
---|---|
|
true ako je |
|
true iako je |
|
true ako je |
|
true ako je stream u ispravnom stanju. |
|
Postavi sve vrijednosti stanja na "ispravno" na streamu |
|
Stavi specifičnu zastavicu stanja na vrijednost flag, a druge poništi. Tip varijable |
|
Postavljanje dodatnih zastavica. |
|
Vrati tekuće stanje streama kao varijablu tipa |
Primjer
int main(int argc, char ** argv)
{
int ival;
// čitaj cin i testiraj samo na EOF;
while (!std::cin.eof()) {
std::cin >> ival; // Čitaj podatak
std::cout << "ival = " << ival << std::endl;
if (std::cin.bad()) // input stream korumpiran; izađi
throw std::runtime_error("IO stream defektan" );
if (std::cin.fail()) // loš ulaz
{
std::cin.clear(); // resetiraj stream
std::string t;
//čitaj podatak koji nije mogao biti konvertiran u int
std::cin >> t;
std::cout << "Pogresan podatak na ulazu (procitao "
<< t << "). Pokusajte ponovo." << std::endl;
continue; // idi na novi ulaz
}
// ok, procesiraj ival
// ...
}
return (EXIT_SUCCESS );
}
Datoteke
Datoteka zaglavlja <fstream> definira tri tipa:
-
ifstream, koji proširuje istream i služi čitanju iz datoteke;
-
ofstream, koji proširuje ostream i služi pisanju u datoteku;
-
fstream, koji proširuje iostream i služi čitanju i pisanju u/iz iste datoteke.
Iz činjenice da su klase za rad s datotekama nastale proširenjem klasa za rad sa standardnim
ulazom/izlazom proizlazi da one dijele isto sučelje, odnosno da formatirano pisanje i čitanje vršimo
pomoću operatora <<
i >>
, te da stanje streama ispitujemo na isti način.
Otvaranje streama
File stream možemo otvoriti tako da konstruktoru damo ime datoteke.
// Ime datoteke koju želimo čitati
std::string file_name("datoteka.txt" );
// Otvori ulazni stream prema datoteci "datoteka.txt"
std::ifstream infile(file_name);
// Otvori izlazni stream prema datoteci "output.txt"
std::ofstream outfile("output.txt" );
Nakon ovih operacija možemo koristiti stream infile
za čitanje iz datoteke datoteka.txt, a stream
outfile
za pisanje u datoteku output.txt.
Druga mogućnostje iskoristiti defaultne konstruktore i metodu open:
// Otvori stream prema datoteci "datoteka.txt"
std::ifstream infile; // Defaultni konstruktor ifstream klase
infile.open(file_name);
std::ofstream outfile; // Defaultni konstruktor ofstream klase
outfile.open("output.txt" );
Oba načina povezivanja streama s datotekom su ekvivalentna.
Zatvaranje streama
Nakon otvaranja datoteke treba provjeriti je li operacija uspjela. To se čini
ispitivanjem streama u if
naredbi.
if (!infile)
{
std::cerr << "Greška: ne mogu otvoriti ulaznu datoteku: "
<< file_name << std::endl;
return EXIT_FAILURE ;
}
Nakon što smo koristili stream moramo ga zatvoriti metodom close. Jednom zatvoreni stream može se ponovo otvoriti pomoću open i povezati s nekom drugom datotekom.
infile.close(); // Zatvori ulazni stream.
infile.clear();
infile.open("neka_druga_datoteka"); // Ponovo otvori isti stream.
Prije ponovnog otvaranje streama treba pozvati metodu clear
radi eliminacije grešaka koje su se eventualno pojavile u prethodnom procesiranju.
Primjer
Ovdje imamo potpun primjer čitanja cijelih brojeva iz jedne datoteke i njihovog prepisivanja u drugu.
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::string file_name("datoteka.txt" );
std::ifstream infile;
infile.open(file_name.c_str());
if (!infile)
{
std::cerr << "Greška: ne mogu otvoriti ulaznu datoteku: "
<< file_name << std::endl;
return EXIT_FAILURE ;
}
std::ofstream outfile;
outfile.open("output.txt" );
if (!outfile)
{
std::cerr << "Greška: ne mogu otvoriti izlaznu datoteku: "
<< "output.txt" << std::endl;
return EXIT_FAILURE ;
}
int tmp;
// Čitaj cijele brojeve is datoteke datotek.txt
// i ispiši ih u datoteku output.txt
while (infile >> tmp)
outfile << tmp << std::endl;
infile.close();
outfile.close();
return EXIT_SUCCESS ;
}
Načini otvaranja datoteke
Kada otvaramo neku datoteku za čitanje ili pisanje automatski se postavljaju neke zastavice u ovisnosti o tipu streama. Popis tih zastavica dan je u sljedećoj tabeli.
Zastavica | Značenje |
---|---|
|
Otvori za čitanje |
|
Otvori za pisanje |
|
Prije svakog pisanja idi na kraj datoteka |
|
Idi na kraj datoteke odmah nakon otvaranja |
|
"truncate" postojeći stream pri otvaranju |
|
Operacije vrši binarno |
Nisu sve zastavice kompatibilne sa svakim streamom. Na primjer, in
zastavica se može postaviti samo na
ulaznom streamu, ali tamo je postavljena implicitno tako da ju ne moramo sami postavljati. Slično je i s
out
zastavicom.
Korisna može biti app
zastavica koju možemo postaviti na izlaznom streamu. Ako želimo pisati u datoteku koja nije
prazna ona će biti prije prvog pisanja obrisana (trunc
je implicitno postavljen). Ako želimo nadopisivati
u datoteku treba postaviti app
zastavicu kao u ovom primjeru:
std::ofstream out;
out.open( "A.txt" );
out << "Linija 1 \n" ;
out.close();
std::ofstream out1;
// Ako otvorimo bez zastavice app file će biti obrisan.
out1.open( "A.txt" , std::ofstream::app);
out1 << "Linija 2 \n" ;
out1.close();
Datoteku je moguće otvoriti i u binarnom modu i tada za ulaz i izlaz treba koristiti posebne funkcije.
Korištenjem fstream
-a moguće je datoteku otvoriti za istovremeno pisanje i čitanje.
Formatiranje ulaza/izlaza
Stanje streama i manipulatori
Ulazno-izlazni streamovi pamte određen broj parametara koji određuju način formatiranja ispisa, odnosno format ulaznih podataka.
Korisnik može mijenjati te unutarnje parametre streamova pomoću manipulatora. Manipulatori su objekti ili funkcije koji se mogu koristiti kao operandi ulaznog/izlaznog streama s ciljem da promjene njegovo stanje. Oni vraćaju stream objekt tako da se mogu ubacivati u niz čitanja i pisanja.
Jedan primjer manipulatora je endl
. Kada ispiše u izlazni stream
std::cout << std::endl;
On ispiše znak za prijelaz u novi red i šalje međuspremnik streama na izlaz. Na sličan način funkcioniraju i drugi manipulatori. Oni se prividno ispisuju i učitavaju, dok ustvari vrše neke druge operacije na streamu.
Format logičkog tipa
bool
varijabla se po defaultu ispisuje kao 0 ili 1. true i false dobivamo primjenom boolalpha
manipulatora. To ilustrira ovaj program:
#include <iostream>
#include <cstdlib>
using namespace std;
int main ( int argc, char *argv[] )
{
cout << "defaultni ispisbool vrijednosti: "
<< true << " " << false
<< " \n Nakon boolalpha: "
<< boolalpha
<< true << " " << false
<< endl;
return EXIT_SUCCESS ;
}
Izlaz programa je ovaj:
defaultni ispis bool vrijednosti: 1 0
Nakon boolalpha: true false
Nakon što smo "ispisali" boolalpha
svako daljnje ispisivanje logičkih vrijednosti
koristi true
i false
. To ponašanje poništavamo s noboolalpha
:
bool x = true;
cout << "Ispis nakon boolalpha: x = " << x
<< noboolalpha << endl
<< "Ispis nakon noboolalpha: x = " << x << endl;
Nakon noboolalpha
, true
i false
se ponovo ispisuju kao 1 i 0.
Baza cjelobrojnih tipova
Svi se cijeli brojevi ispisuju u bazi 10. To se mijenja pomoću manipulatora
hex
, oct
i dec
. hex
daje heksadecimalni ispis, oct
oktalni,
a dec
služi za povratak na
decimalni.
const int val = 15;
cout << "defaultni ispis: val = " << val << endl;
cout << "oktalno: val = " << oct << val << endl;
cout << "heksadecimalno: val = " << hex << val << endl;
cout << "decimalno: val = " << dec << val << endl;
Ispis:
defaultni ispis: val = 15
oktalno: val = 17
heksadecimalno: val = f
decimalno: val = 15
Promjena koju vrše ovi manipulatori je trajna.
Oznaka baze na izlazu
Općenito se ne ispisuje. To se mijenja s manipulatorima showbase
i noshowbase
.
Pri tome u ispisu imamo sljedeće pravilo:
-
Vodeći
0x
indicira heksadecimalan broj; -
Vodeća
0
indicira oktalan broj; -
Odsutnost oznake indicira decimalan broj.
const int val = 15;
cout << showbase; // Prikaži bazu
cout << "defaultni ispis: val = " << val << endl;
cout << "oktalno: val = " << oct << val << endl;
cout << "heksadecimalno: val = " << hex << val << endl;
cout << "decimalno: val = " << dec << val << endl;
cout << noshowbase; // Vrati staro stanje
Ispis:
defaultni ispis: val = 15
oktalno: val = 017
heksadecimalno: val = 0xf
decimalno: val = 15
noshowbase
manipulator poništava showbase
.
Heksadecimalni brojevi se ispisuju s malim slovima. Želimo li velika slova koristimo uppercase
/nouppercase
:
cout << uppercase << showbase << hex
<< "Hexadecimalno: val = " << val << endl;
Ispis:
Hexadecimalno: val = 0XF
nouppercase
manipulator poništava akciju uppercase
manipulatora.
Kontrola ispisa fp-brojeva
Sljedeći su aspekti formatiranja fp-brojeva:
-
Preciznost: broj ispisanih znamenaka;
-
Notacija: s eksponentom ili bez njega;
-
Decimalna točka kod cjelobrojnih vrijednosti.
Normalno se koristi 6 znamenki u ispisu. Ako je broj cijeli ne ispisuje se decimalna točka. Hoće li biti ispisan s eksponentom ili ne ovisi o veličini broja.
Promjena preciznosti
Preciznost ispisa (broj znamenki u ispisu) postavlja se pomoću funkcije precision
ili pomoću setprecision
manipulatora.
Funkcija precision
uzima nula ili jedan argument. Kad uzima argument onda
postavlja preciznost, dok bez argumenta vraća trenutnu preciznost. Manipulator setprecision
uzima jedan argument i postavlja preciznost.
Primjer:
#include <iomanip>
// cout.precision daje trenutnu preciznost
cout << "Preciznost: " << cout.precision()
<< ", Vrijednost: " << sqrt(2.0) << endl;
// cout.precision(12) postavlja preciznost na 12 znamenaka
cout.precision(12);
cout << "Preciznost: " << cout.precision()
<< ", Vrijednost: " << sqrt(2.0) << endl;
// možemo upotrijebiti i setprecision manipulator
cout << setprecision(4);
cout << "Preciznost: " << cout.precision()
<< ", Vrijednost: " << sqrt(2.0) << endl;
Ispis:
Preciznost: 6, Vrijednost: 1.41421
Preciznost: 12, Vrijednost: 1.41421356237
Preciznost: 4, Vrijednost: 1.414
setprecision
manipulatori i drugi manipulatori koji uzimaju argumente definirani su u
iomanip headeru.
Eksponencijalni ili pozicijski ispis
Ovdje su nam na raspolaganju manipulatori scientific
i fixed
.
Oni trajno mijenjaju formatiranje fp-brojeva, ali ne postoje
negativni manipulatori koji bi vratili prethodno stanje.
Zato smo dužni manipulirati sa zastavicama, što opisujemo niže, odnosno, u ovom slučaju
je dovoljno zvati unsetf
metodu kojoj dajemo vrijednost iz biblioteke
nazvanu ios::floatfield
:
// postavi defaulne vrijednosti - poništi eventualne prethodne promjene
cout.unsetf(ios::floatfield);
cout << "\nDefaultni prikaz: " << 100*sqrt(2.0) << endl;
cout << "Eksponencijalni prikaz: " << scientific << 100*sqrt(2.0) << "\n"
<< "Pozicijski prikaz: " << fixed << 100*sqrt(2.0) << "\n";
// vrati defaultne vrijednosti
cout.unsetf(ios::floatfield);
cout << "Nakon brisanja zastavica: " << 100*sqrt(2.0) << endl;
Ispis:
Defaultni prikaz: 141.421
Eksponencijalni prikaz: 1.414214e+02
Pozicijski prikaz: 141.421356
Nakon brisanja zastavica: 141.421
Ispis decimalne točke
Manipulatori showpoint
i noshowpoint
kontroliraju ispis decimalne
točke kod cjelobrojnih floating point brojeva. Po defaultu točka se ne ispisuje-
cout << 10.0 << endl; // ispisuje 10
cout << showpoint << 10.0 // ispisuje 10.0000
<< noshowpoint << endl; // povrat na defaultnu vrijednost
Kontrola dopunjavanja bjelinama (padding)
Imamo ove manipulatore:
-
setw
postavlja minimalnu širinu za sljedeći numerički ili znakovni podatak; -
left
lijevo pozicionira izlaz; -
right
desno pozicionira izlaz (default); -
internal
kontrolira predznak kod negativnog broja. Znak stavi lijevo, a vrijednost desno; -
setfill
specificira alternativan znak za popunjavanje (umjesto bjeline).
setw
, kao endl
, ne mijenja stanje streama, i vrijedi samo za sljedeći ispis.
setw
predstavlja samo minimalni broj znakova, što znači da će podatak biti ispisan s
većim brojem znakova ako je to potrebno.
Primjer
// minimum 12 znakova za izlaz
cout << "1 i: " << setw(12) << i << "::" << '\n'
<< "1 d: " << setw(12) << d << "::" << '\n';
// pozicioniraj lijevo
cout << left
<< "2 i: " << setw(12) << i << "::" << '\n'
<< "2 d: " << setw(12) << d << "::" << '\n';
// vrati desno pozicioniranje
cout << right
<< "3 i: " << setw(12) << i << "::" << '\n'
<< "3 d: " << setw(12) << d << "::" << '\n';
// unutrašnje pozicioniranje; prikaži pozitivan broj sa znakom +
cout << internal << showpos
<< "4 i: " << setw(12) << i << "::" << '\n'
<< "4 d: " << setw(12) << d << "::" << '\n';
// promijeni znak za popunjavanje u _
cout << setfill('_')
<< "5 i: " << setw(12) << i << "::" << '\n'
<< "5 d: " << setw(12) << d << "::" << '\n'
<< setfill(' ') // vrati bjelinu kao znak za popunjavanje
<< right // vrati defaultno pozicioniranje
<< noshowpos; // ne prikazuj + kod nenegativnog broja (default))
Ispis:
1 i: -1024::
1 d: 3.14159::
2 i: -1024 ::
2 d: 3.14159 ::
3 i: -1024::
3 d: 3.14159::
4 i: - 1024::
4 d: + 3.14159::
5 i: -_______1024::
5 d: +____3.14159::
Kontrola ulaznog formatiranja
Standardno ulazna operacija ignorira bjeline
(blank
, tab
, newline
, formfeed
, carriage return
).
Na primjer, petlja:
char ch;
while (cin >> ch && ch != 'x')
cout << ch;
cout << endl;
na podacima
w e rx
izvrši se 3 puta čitajući svaki znak posebno, preskakanjem bjelina (bjelina je delimiter). Izlaz programa je:
wer
Manipulator noskipws
čini da ulazni operator čita i bjeline, umjesto da ih preskače.
Pomoću skipws
manipulatora vraćamo se na normalno učitavanje s preskakanjem bjelina.
cin >> noskipws; // neka cin ne preskače bjeline
while (cin >> ch && ch != 'x')
cout << ch;
cout << endl;
cin >> skipws; // vrati staro stanje
Zadamo li ulaz:
e r t zx
dobivamo izlaz
e r t z
Mijenjanje stanja streama pomoću zastavica
Formatiranje ulaza i izlaza pomoću manipulatora je vrlo praktično, no postoji i drugi način da se
postignu isti efekti.
Način formatiranja ulaza/izlaza određen je varijablama u klasi ios
, tipa
ios::fmtflags
, koje nazivamo zastavicama (flags) i koje određuju način ispisa
cijelih brojeva, bool vrijednosti, floating-point brojeva itd.
Postavljanje pojedine zastavice odgovara primjeni ogovarajućeg manipulatora, dok brisanje zastavice odgovara primjeni suprotnog (poništavajućeg) manipulatora.
Neke od zastavica tvore grupe i posebne maske su definirane da olakšaju rad s njima. Funkcije koje manipuliraju sa zastavicama dane su u sljedećoj tabeli.
Funkcija | Značenje |
---|---|
|
Postavi |
|
Postavi |
|
Obriši sve zastavice formatiranja |
|
Vrati skup zastavica formatiranja |
|
Postavi zatavice formatiranja na vrijednost flags i vrati prethodno stanje zastavica formatiranja |
|
Kopiraj sve zastavice formatiranja od |
Vraćanje početnog stanja pomoću zastavica
Metoda flags()
omogućava da uzmemo stanje streama prije
primjene manipulatora i da ga vrtimo kad smo gotovi. Imamo dvije preopterećene
verzije:
-
flags()
bez argumenata vraća tekuće stanje formatiranja streama. Vrijednost je tipafmtflags
. -
flags(arg)
uzimafmtflags
argument i postavlja stanje stream na ono indicirano argumentom.
Na primjer,
void display(ostream & os)
{
// Zapamti trenutno stanje streama
ostream::fmtflags curr_fmt = os.flags();
// Rad sa streamom ... manipulacije
os.flags(curr_fmt); // vrati originalno stanje
}
Funkcije
setf()
i unsetf()
postavljaju ili uklanjaju jednu ili više zastavica.
Pri tome je moguće manipulirati s više zastavica kombiniranjem njihovih simboličkih imena pomoću
operatora binarno ili (|).
Funkcija setf()
može uzeti drugi argument kako bi uklonila sve zastavice iz grupe određene drugim
argumentom prije no što postavi zastavice određene prvim argumentom, koje moraju pripadati istoj grupi.
Na primjer,
// postavi zastavice showpos, showbase i uppercase što je ekvivalentno upotrebi istih manipulatora
cout.setf(ios::showpos | ios::showbase | ios::uppercase);
cout << hex << 11 << endl;
// Postavi samo zastavicu hex u grupi basefield (koja sadrži hex, oct, dec)
cout.setf(ios::hex, ios::basefield);
cout << 12 << endl;
// očisti zastavicu uppercase
cout.unsetf(ios::uppercase);
cout << 12 << endl;
Ispis:
0XB
0XC
0xc
Funkcijom copyfmt()
možemo kopirati informacije o formatu iz jednog streama u drugi.
IO klase
Sljedeća slika pokazuje lanac nasljeđivanja za klase streamova.
Prikazane klase su ustvari aliasi za parametrizirane klase koje u svom imenu imaju "basic_", a parametrizirane su tipom znaka na kojem je string sagrađen. Na primjer,
typedef basic_ios<char> ios;
typedef basic_istream<char> istream;
typedef basic_ostream<char> ostream;
typedef basic_iostream<char> iostream;
typedef basic_ifstream<char> ifstream;
typedef basic_ofstream<char> ofstream;
typedef basic_fstream<char> fstream;
Kada se za template parametar uzme široki znak (tip wchar_t
) dobiva se posve isti sustav klasa
čijim imenima prethodi znak "w". Na primjer
typedef basic_ios<wchar_t> wios;
typedef basic_istream<wchar_t> wistream;
typedef basic_ostream<wchar_t> wostream;
typedef basic_iostream<wchar_t> wiostream;
typedef basic_ifstream<wchar_t> wifstream;
typedef basic_ofstream<wchar_t> wofstream;
typedef basic_fstream<wchar_t> wfstream;
Uočimo da klasa ios_base
nije parametrizirana jer sadrži samo dio sustava vezan uz formatiranje
i stanje izlazno ulaznih tokova. Pored ovih klasa sustav čini još i parametrizirana klasa
basic_streambuf<>
koja vrši stvarni transfer podataka između programa i ulaza/izlaza. Sve klase
koju proširuju ios_base
vrše samo formatiranje podataka. Kao i kod ostalih klasa imamo dva
simbolička imena:
typedef basic_streambuf<char> streambuf;
typedef basic_streambuf<wchar_t> wstreambuf;