Moje poznámka: Vlastní zkoumání jazyka C++, když jsem byl ještě začátečník... Stáhněte si archiv.
Poznámka: Cílem této html stránky je podat základní "kurs" o programování v C++, protože některá literatura je příliš drahá a také velice rychle zestárne.
Poznámka: Informace a výklad je tedy veden podle přednášek Programování v C++ na FJFI (to je Fakulta Jaderná a Fyzikálně Inženýrská - to je zde, kde si nyní prohlížíte tuto WWW stránku), patřící pod ČVUT. Přednášky přednáší ing. M.Virius, Csc.
Žádost: Pokud uvidíte jakoukoliv chybu, dejte mi prosím vědět. Chybička totiž pravděpodobně vznikla přepisem prográmků do WWW stránky, na přednášce se chyby vyskytují jen zřídka.
Obsah:
Moje poznámka: Vlastní zkoumání jazyka C++, když jsem byl ještě začátečník... Stáhněte si archiv.
Důvodem rozdělení WWW stránky na části byl, že editor WWW stránek (sharewarová verze Golden HTML Editor) neumožnil pracovat s delšími stránkami. Takže k referencích - zopakujeme a doplníme, k čemu jsou vlastně dobré:
Příklad na použití reference jako předávání parametrů odkazem:
void swap(int &a, int &b) { int c=a; a=b; b=c; } int a=11, b=55; double c=9.9; swap(a,b); swap(a,c);
Volání funkce swap(a,b) provede správný výsledek, protože "a" i "b" jsou proměnné typu int, takže je to bez problému. Zatímco volání funkce swap(a,c) provede špatnou akci, protože se druhá proměnná "c" typu double konvertuje na typ int do pomocné proměnné, která se použije jako parametr funkce swap, takže ve vlastním volání se pracuje s pomocnou proměnnou, takže výsledek je chybný. V dnešní normě je však něco takového již zakázáno. Všeobecně platí zásada, že bychom měli dávat proměnné správného typu, jinak se může i přemazat část paměti, např. když dáme jako parametr např. proměnnou, která je kratší (zabírá méně B v paměti), takže zcela jistě se přemažou nějaká jiná data, která jsou za tou proměnnou v paměti.
Deklarace pro konstantní parametry se provede takto:
void swap(const int &a, const int &b) { }
Přehození proměnných "a" a "b" proběhne v pořádku. V případě proměnných "a" a "c" je to však blbost, protože se skutečně přehazují nesmysly.
Shrneme důvody předávání proměnné odkazem: změna parametrů - předávání jako výstup z funkce; práce s rozsáhlými proměnnými; v objektech - destruktory a konstruktory (blíže v objektovém programování) a někdy je nutné pro vynucení, pokud chceme používat knihovní funkce.
Vstupy a výstupy, hlavičkový soubor stdio.h:
Příkladem přesměrovatelných vstupů je práce s proudy cin a cout, které lze přesměrovat, jako se přesměrovává data pro filtr DOSu sort: SORT <D >E kde D je vstupní soubor a E je výstupní soubor. Je tu taková mnemotechnická pomůcka jak si to zapamatovat, < je jako šipka, která v případě SORT <D vychází z D a jde do SORT, takže D je zdroj a jde to do filtru SORT, SORT >E výchází ze SORT a vchází do E, takže v E je výstup, protože je to také jako šipka směřující do E, což podle směřující "šipky" musí být výstup. Analogicky si můžete odvodit, že operátor >> v C++ je vstupní, protože se zapisuje např. >> x, takže je to také šipka a z toho proudu to jde do proměnné x, takže ta se změní, takže je to musí být vstupní operátor a analogickou úvahou << x je výstupní operátor.
Rozlišíme několik způsobů podle různých překladačů a verzí jazyka:
Takže začneme od standartních vstupů a výstupů v C:
stdin a stdout jsou standartní vstupní a výstupní zařízení, známe, že se používají při printf (výstup) a scanf (vstup)
Z Pascalu známe skoro tajný pojem - proměnná typu soubor, zde v C jasně více, co to je. V C se s ní pracuje pomocí ukazatele ukazující na strukturu (asi něco podobného je také v Pascalu), která se jmenuje FILE (velkými písmeny, neboť víme, že C rozlišuje malé a velké písmena), musíme definovat ukazatel na FILE, abychom mohli vůbec nějak se soubory pracovat:
FILE *f;
FILE *fopen(char *jmeno,char *mod); jmeno a mod jsou tedy řetězce definované jako char * a jmeno je normální jméno souboru, lze uvést disk, adrářovou cestu a jméno souboru i s koncovkou, mod je speciální řetězec (r - read = čtení, w - write = zápis, a - append = přidávání na konec souboru a za ním lze přidat: t - text - otevřít jako textový soubor, b - binary - otevřít jako binární soubor). Funkce fopen vrací ukazatel na stukturu FILE, pokud je tento ukazatel nenulový, potom se otevření zdařilo, pokud je nula, nastala chyba. V žádném případě se zde neobjevují zprávy typu Runtime Error ??? at ????:???? známé z Pascalu (ikdyž to lze direktivou vypnout). Nezapomeňte zdvojovat znak \ v adresářové cestě.
Ještě existují režimy r+, slouží to pro otevření pro čtení, však je možný i zápis do souboru, w+ znamená otevři pro zápis, ale umožni i číst, a+ znamená otevřít jako append (pro zápis na konec souboru), ale umožnit i čtení.
Do textový souboru se zapisují jednotlivé řádky, jako části souboru, v binárním lze zapsat cokoliv, proto bych měl při čtení vědět, co vlastně číst. Jak už jsem upozornit, lze do binárního souboru psát textové řetězce (ikdyž to není obvyklé), a opačně do textového souboru lze zapsat něco binárně (i to je dost neobvyklé, protože potom se uživatel zhrozí, co se mu stalo s jeho přehledným textem, co jsou ty hrozné znaky, kterým nerozumí... Snad se to hodí jen v případě tiskárny, když chceme posílat řídící znaky. To ovšem vyžaduje znát, jaká tiskárna je připojená, jinak se může tisk ještě více znepřehlednit, než kdyby se řídící znaky neposílaly, např. tiskárně HP posílat řídící znaky tiskárny EPSON.
Výhodou a také nevýhodou proti Pascalu je, že do textového souboru lze číst i zapisovat jak textově (např. fprintf - je jako printf, pouze 1. parametr má navíc jméno souboru a fscanf - je jako scanf, pouze 1. parametr má navíc jméno souboru), ale také i binárně (to není chyba a výmysl!!!) a to příkazy např. fread a fwrite. Také do souboru otevřeného binárně, lze zapisovat resp. číst nejen binárně, ale i textově. Neboť v C a C++ platí zásada a předpokládá se, že "Programátor ví, co dělá." a proto zde není omezován, tak jako v Pascalu - toho na jednu stranu výhodou - taková svoboda, ale nevýhodou, pokud programátor není, co dělá, zkrátka není na to upozorněn a potom musí dlouho ladit svůj program, až zjistí, v čem je ten problém...
Pro zavření souboru slouží funkce i=fclose(FILE *f); "f" je ukazatel na FILE a "i" je typu int. V případě, že soubor je úspěšně zavřen, potom vrátí 0, jinak EOF (to je předdefinovaná konstanta), například když byste se pokoušeli zavřít již jednou uzavřený soubor nebo soubor, který se nepodařilo úspěšně otevřít.
fprintf provádí formátovaný zápis (i do binárního souboru)
fscanf provádí formátované čtení (i z binárního souboru)
fread provádí neformátované čtení (i z textového souboru)
fwrite provádí neformátovaný zápis (i do textového souboru)
Použití si ukážeme na příkladech, předpokládejme, že soubor již byl úspěšně otevřet pro zápis (v 1. případě) a proměnná x je typu double resp. pro čtení (v 2. případě), dále předpokládáme, že na aktuální pozici v souboru je teď proměnná typu double a y je typu double a dále v obou případech předpokládáme, že v "f" je platný ukazatel na strukturu FILE.
fprintf(f,"%d",x);
fscanf(f,"%d",&y);
Neformátované čtení si také ukážeme na příkladě. Předpokládejme, že v "f" je platný ukazatel na strukturu FILE, tj. f je nenulový ukazatel (soubor se podařilo otevřít), v 1. případě pro čtení, v 2. případě pro zápis. Dále budeme potřebovat do něčeho proměnnou přečíst (měli bychom číst proměnnou správného typu, která je skutečně v souboru) v prvním případě budeme do ní číst, takže se její obsah změní, v druhém případě budeme její obsah ukládat do souboru - zapisovat, takže by měl zůstat její obsah nezměněn.
fread(&x,sizeof(x),1,f); //proměnnou x předáváme odkazem, protože v 1. parametru je vyžadován ukazatel na proměnnou, sizeof(x) vrací její velikost v B, 1 je počet proměnných (my chceme číst 1 proměnnou), f je předpokládaný ukazatel na FILE, fread vrátí 0 v případě chyby nebo nenulovou hodnotu, odpovídající počtu přečtených položek (ne Bytů)
fwrite(&x,sizeof(x),1,f); //proměnnou x předáváme odkazem, protože v 1. parametru je vyžadován ukazatel na proměnnou, sizeof(x) vrací její velikost v B, 1 je počet proměnných (my chceme číst 1 proměnnou), f je předpokládaný ukazatel na FILE, fwrite vrátí 0 v případě chyby nebo nenulovou hodnotu, odpovídající počtu zapsaných položek (ne Bytů)
Pokud máme číst a zapisovat pole, potom nepíšeme &pole, ale pouze pole jako 1. parametr, protože pole, jak již víme, se automaticky konvertuje na ukazatel na 1. prvek. Funkce fread vrací počet úspěšně přečtených položek (ne Bytů), fwrite počet úspěšně zapsaných položek.
Funkce feof(f) vyžaduje ukazatel na FILE a vrací hodnotu podle otázky: Narazil jsem před předcházejícím čtením na konec souboru? Pokud ano, vrací nenulovou hodnotu, pokud narazil na konec souboru, vrací 0.
Znak \n se vlastně v DOSu přemění na dva znaky s ASCII kódem 13 a 10. Znak \r znamená return (návrat vozu - ikdyž při tisku na obrazovku nemá smysl mluvit o nějakém vozu...) a znak \n je new line, takže DOS musí mít oba znaky (zároveň přechod na 1. znak \r a zároveň odřádkování \n). Pokud tedy soubor otevřeme jako textový, potom se bude počítač starat o správné kládání těchto znaků, pokud otevřeme soubor jako binárně a budeme s ním pracovat jako s binárním, potom se tyto vkládání neprovádí. Proto binární soubory zásadně kopírujte v módu binary - f=fopen("a.com","rb"); a čtěte příkazem fread(buffer,sizeof(buffer),1,f); Podobnou situaci asi jste zažili na Internetu, pokud stahujete pomocí programu "ftp" hodně dlouhý binární soubor a zapomněli jste zapnout přepnutí do režimu binary, protože se provádí konverze znaků \n a \r podle směru převodu v řežimu ASCII.
Nastavení pozice v souboru se provede příkazem i=fseek(f,o co,odkud);, kde se předpokládá, že "f" je ukazatel na strukturu FILE, "o co" je offset typu long a "odkud" je proměnná typu int nabývající jedné ze 3 hodnot:
SEEK_SET (=0) offset se bude počítat od začátku souboru
SEEK_CUR (=1) offset se počítá od aktuální pozice
SEEK_END (=2) offset od konce souboru
Doporučuji používat symbolické jména
Funkce fseek vrací 0 v případě, že byl úspěšně ukazatel přemístěn, jinak vrací nenulovou hodnotu.
i=fclose(f) zavře soubor, kde f je ukazatel na FILE a vrací 0 v případě úspěšného zavření souboru nebo hodnotu EOF (-1), v případě chyby při zavření (třeba pokud soubor nebyl otevřen nebo již byl zavřen). Zavřením souboru byl se měl vyrovnávací buffer již zapsat skutečně na disk, pokud v DOSu není smartdrv s nastaveným opožděným zápisem, v tom případě se to uloží do bufferu smartdrv a zapíše se to vše najednou. Představuje to jisté nebezpečí, že se počítač zasekne nebo vypne a data se nezapíšou, ale to jsou již podrobnosti, které s programováním nemají nic společného. Dokud neprovedeme zavření souboru, data se nezapíšou. Do vyrovnávací paměti přibývají data a až je vyrovnávací paměť plná, tak se zapíše a vyprázdní. Určitě se zapíše uzavřením souboru.
Pokud chceme zapsat data v určitém okamžiku, tak aby se z vyrovnávací paměti zapsali na disk, potom použijeme funkci i=fflush(f) a jako vždy (f je ukazatel na FILE, i je typu int), pokud se to provede OK, tak se vrátí 0 v proměnné "i" typu int, ale v případě chyby vrátí předdefinovanou hodnotu EOF (-1). V případě, že není smartdrv, data jsou již zapsaná na disku, jinak se předají programu smartdrv a ten je buď zapíše hned a nebo až se zpožděním.
stderr je výstup chyb, stdout je standartní přesměrovatelný výstup (implicitně na obrazovku) a stdin je standartní přesměrovatelný vstup (implicitně z klávesnice).
i=fputc(znak,f) zapíše jeden znak "znak" (typu int !!!) do souboru s ukazatelem f na FILE. V případě úspěchu vrátí (int) kód znaku, jinak EOF.
i=fgetc(f) přečte jeden znak ze souboru (int), v případě úspěchu platný kód přečteného znaku, jinak i=EOF (což znamená chybu při čtení).
První příklad, jednoduché otevření a zavření souboru.
Druhý příklad pro práci se soubory.
Poznámka: Pokud pracujeme v režimu čtení i zápis současně v jednom souboru (režimy r+, w+, a+ zadaných v řetězci jako 2. parametr ve funkci fopen), potom mezi fread a fwrite musíte použít funkci fseek, jinak nefunguje.
Poznámka: fcanf(f,"%i",&i); Toto volání funkce přečte číslo ze souboru v libovolné soustavě (z C, C++ jsou k dispozici desítková, osmičková a šestnáctková). Jak bychom měli vědět z úvodu, desítková čísla se zapisují normárně, s nenulovým znakem na prvním místě (nulu samozřejmě nelze zapsat jinak než jako 0). Čísla v osmičkové soustavě se zapisují s 0 na prvním místě, musí samozřejmě obsahovat pouze cifry do 7 včetně. Číslo v šestnáctkové soustavě začíná znaky 0x. Toto volání funkce fcanf by mělo za příznivých okolností rozeznat všechny 3 číselné soustavy. Binární není podporována, na což jsem se zeptal a prý si to má programátor naprogramovat sám, pokud to bude potřebovat. Důvod předávání "i" jako reference &i je jednak, že do proměnné se bude předávat výstup, což nelze hodnotou jako parametr předat a za druhé, že fscanf je funkce z C, které jak víme nezná předávání parametru odkazem, tak se musí předat odkazem.
Formátovaný výstup u reálných čísel:
Výhody a nevýhody printf, scanf:
Výhoda efektivnost, více programátorů používá programovací jazyk C než C++, C má delší dobu existence, tedy existuje více knihoven a již naprogramovaných algoritmů, proto zde uvádíme příkazy printf a scanf.
Nevýhodou je menší přehlednost, scanf a printf totiž používají výpustku, což bývá nebezpečné a někdy zdrojem chyb. V C++ je cout a cin mnohem bezpečnější.
i=getchar(); - přečte znak ze standartního vstupu, který je na řadě. Vrací kód znaku v proměnné typu int, důvod je ten, aby funkce mohla vrátit i EOF (-1) jako chyba, ASCII kód znaku (0..255).
i=fgetc(f); - čte jeden znak ze souboru, f je ukazatel na strukturu FILE. I zde vrací int, aby bylo možné signalizovat případnou chybu.
Varování: Proč ukládat kód klávesy do int? Protože EOF (-1) je v šestnáctkové soustavě jako FFFFH, ale když by se výsledek uložil do char, potom by se z FFFFH stalo FFH, což je také kód znaku. Z toho vyplývá, že bychom nebyli schopni rozpoznat konec souboru a pletli si ho se znakem s ASCII kódem 255. Taktéž znak, který není koncem souboru, by se stal koncem souboru a např. cyklus vyhodnocující konec souboru, by skolnčil předčasně.
putchar(int); Zapíše jeden znak na standartní výstupní zařízení.
fputc(int c,FILE *f); Zapíše jeden znak do souboru, který byl otevřen pro zápis, f je ukazatel na FILE.
fgets(FILE *f); Přečte řetězec ze souboru, daným ukazatelem na FILE.
fputs(FILE *f); Zapíše řetězec "s" do souboru, daného ukazatelem na FILE.
gets();
puts();
sscanf(); - slouží pro formátované čtení ze řetězce
sprintf(); - slouží pro formátované psaní do řetězce
Většina z těchto funkcí jsou z hlavičkového souboru stdio.h.
Funkce z hlavičkového souboru conio.h.
Obsahuje podobné funkce jako stdio.h, ale zce tyto funkce pracují přímo s konzolí, vynechávají tedy volání operačního systému, čímž obecně jsou rychlejší. Uvedeme jen takový přehled, parametry a vracené hodnoty najdete v Helpu v Borland C++ 3.1. Upozorníme pouze, že funkce pro čtení klávesy, vrací int a ne char. Důvodem je, že funkce musí vrátit také někdy chybu (EOF = -1).
cprinft - přímý výstup na obrazovku
cscanf - přímý vstup z klávesnice
getch - čtení 1 znaku z klávesnice - kódu klávesy, v případě, že se přečte 0, potom to znamená rozšířený kód a mělo by následovat ještě jednou getch, aby se zjistil rozšířený kód skutečné klávesy (např. klávesy se šipkami dávají kódy 0,77 a 0,75)
getche - totéž jako getch, navíc vypíše znak na obrazovku, pokud je zobrazitelný, "e" na konci znamená echo.
ungetch vrátí 1 znak do vstupního proudu
cscanf přečte data z konzole, co se má přečíst, zadává se jako parametr u scanf.
cputs zapíše řetězec do textového okna na obrazovce
cgets přečte řetězec z konzole
kbhit je obdobou Pascalovské funkce KeyPressed a vrací nenulovou hodnotu v případě stisklé klávesy, jinak 0. Používá se, aby program nečekal v nekonečné smyčce na stisk klávesy, touto funkcí je možno otestovat, zda je v klávesnicové frontě nějaký znak a v případě, že je, číst klávesu, jinak dělat jinou užitečnější práci, než čekat na stisk klávesy. Funkce je podporována v Borland překladači. Následující funkce jsou také v Borland překladači na PC. Uvedu taktéž odpovídající funkce v grafickém režimu, jejichž hlavičky jsou v hlavičkovém souboru graphics.h.
textattr zjištění barvy pozadí a písma v textovém módu.
textbackground nastavení barvy pozadí v textovém módu. (V grafickém módu je to na nastavení barvy pozadí setbkcolor a pro zjištění barvy pozadí getbkcolor - je to vlastně změna barvy 0 v paletě).
textcolor nastavení barvy textu v textovém módu. (V grafickém módu se nastaví barva kreslení bodů, úseček, kružnic, atd. setcolor a zjištění barvy kreslení funkcí getcolor).
window nastaví oblast v textovém režimu, do kterého bude proveden tisk funkcí z conio.h. Souřadnice levého horního rohu je 1,1 a dolního rohu 80,25. V grafickém režimu se oblast nastaví funkcí setviewport.
clrscr mazání oblasti nastavené pomocí funkce window. Implicitně, pokud není nastaveno jinak), potom se maže celá obrazovka v textovém režimu. V grafickém režimu se část obrazovky smaže funkcí clearviewport.
gotoxy nastavení pozice textového kurzoru v textovém režimu (v grafickém režimu se nastaví pozice grafického kurzoru funkcí moveto).
wherex, wherey zjištění pozice textového kurzoru v textovém režimu (v grafickém režimu se zjišťuje pozice grafického režimu getx a gety).
insline, delline provádí vložení a smazání řádku v textovém módu. V grafickém módu si to asi musíte naprogramovat sami... Odrolování se provádí přímou adresací videopaměti začínající na adrese B800:0 H, což je jen u PC. Všechny funkce pracující s barvami je možné použít jak v reálném, tak i v chráněném módu.
inportb, outportb je v DOS.H a slouží pro čtení bytu resp. zapsání bytu na port. Hodí se například pro čtení hesla v paměti C MOS. Přišel jste náhodou někdo na způsob, jak je tam to heslo zakódované? Rád se dozvím jak...
Objektová struktura vstupů a výstupů v C++:
Vstupy a výstupy jsou naprogramovány objektově. Je to typově bezpečné (C++ má zabudovánu přísnější typovou kontrolu než C), výhodou je pohodlnější práce.
Moje poznámma: Tak nyní jsem si z tabule na přednášce překreslil hierarchii objektových typů, přece to není zase tak složité... :-) Nezalekněte se toho a klidně dál programujte, ikdyž tu hierarchii neznáte...
Nejdůležitější je si zapamatovat proudy cin a cout, které se v C++ používají nejčastěji. Upozorňuji, že jsou v C++, ne v C, protože v hlavičkovém souboru iostream.h je test, zda se překládá kompilátorem C nebo C++ (testuje se existence makra _cplusplus, které je definováné, pokud se překládá kompilátorem C++, v C není známé). V C tyto proudy cin a cout nejsou podporovány. Jak vidíme z obrázku, iostream je odvozen od tříd istream a ostream. Zatímco Pascal dovolil, aby měl jeden objekt maximálně jednoho předka, v C++ toto omezení neexistuje, v C++ může mít objekt více předků, vznikají tak někdy složité hiearchie. Běžně vystačíme s třídami: ifstream, fstream, ofstream, istream, ofstream, fstrstream.
io.h obsahuje zastaralé funkce práce se vstupy a výstupy v Unixu a v DOSu. V dnešní době existuje v C++ iostream, takže tyto staré volací konvence se už vidí jen zřídka, však pro zachování kompatibility, by měly funkce z io.h existovat i na nejnovějších překladačích.
stdio.h obsahuje ještě funkce vprintf(ap); a vscanf(ap);, funkce s "v" označují proměnný počet parametrů, tedy, že se bude používat výpustka. Musíme tedy mít někde proměnnou, která zpřístupní parametry výpustky, které předáme do vprintf nebo vscanf.
va_list ap; //deklarace proměnné, která zpřístupní parametry výpustky
ap je tedy proměnná, podle této deklarace. Měla by být inicializovaná.
Známe již funkce fread, fwrite, fscanf, fprintf, getche (vrací int - 2B, nutné ukládat do int, funkce: přečte znak a zobrazí je na obrazovku).
iostream.h, jak víme, obsahuje proudy cin a cout, což jsou vlastně třídy. Jsou pro ně přetížené operátory << (výstupní operátor) a >> (vstupní operátor), které se normálně používají pro bitové posuny.
Zápis cout << a; si kompilátor převede na: cout.operator<<(a);. Operátory jsou chápány jako funkce. Operátory, stejně jako funkce, lze přetížit, skoro pro každý typ.
Manipulátory v iostream.h:
Manipulátory s parametry v iomanip.h:
setw(n) - nastavení šířky výstupu, je účinný jen na následující výstup, potom se opět nastaví na původní šírku. Udává šířku pole výstupu, pokud je výstup kratší, zleva se doplní mezerami.
setprecision(n) - nastavení počtu desetinných míst reálného čísla. Tento manipulátor a následující dva mají trvalý účinek, tj. dokud se jinak nezmění.
setiosflags(n) - n (jako skupina bitů) určuje, které bity příznaku se nastaví. V ios jsou příznaky - bity bity lze nastavit, pokud na odpovídající místo v "n" zapíšu logickou 1. Pokud je na odpovídajícím místě v "n" logická 0, odpovídající příznak v ios zůstane nezměněn.
resetiosflags(n) - n (jako skupina bitů) určuje, které bity příznaku se vynulují. V ios jsou příznaky - bity lze vynulovat, pokud na odpovídající místo v "n" zapíšu logickou 1. Pokud je na odpovídajícím místě v "n" logická 0, odpovídající příznak v ios zůstane nezměněn.
Nyní si konečně ukážeme příklad na použití manipulátorů.
Dále si uvedeme spíše takové drobnosti, přesnou syntaxi objevíte v nápovědě, my si pouze řekneme, že něco takového existuje. Ještě něco k příznakům ve třídě ios.
Příznak ios::showpoint přísluší k třídě ios. Nastavení tohoto příznaku se provede mapříklad cout << setiosflags(ios::showpoint);
setfill(znak) slouží pro nastavení vyplňovacího znaku (jak už název napovídá), který se píše, pokud je výstup kratší, než je nastavo např. manipulátorem setw.
int ios::width(); přečte šířku
int ios::width(n); přečte šířku a nastaví novou
ios::clear nastaví resp. schození bitu chyby. Když vznikne chyba, odmítá spolupracovat, až dokud se neshodí příznak chyby, který je jako chráněný atribut ios::state ve třídě ios. Nejčastěji se používá vynulování, takže se zapíše ios::clear.
ios::rdbuf vrací ukazatel na bufferu (tedy jeho adresu).
Poznámky k tvorbě programů:
Deklarace a otevření souboru se provede deklarací a zavoláním konstruktoru, který by již měl (za příznivých okolností) provést otevření souboru.
Studenti FJFI si budou moci prohlédnout příklady, které naprogramoval ing. M.Virius, CSc, které jsou k dispozici v Trojance na serveru katedry matematiky v adresáři ...VYUKA\CPP\#ZAKL\10 příklady pro práci se soubory. Vy, kteří tam nemáte uživatelské konto, tak si ho zařiďte.
ofstream f(cesta,ios::out | ios::binary); cesta je vlastně řetězec s názvem disku, s cestou, se jménem souboru a s koncovkou. Druhým parametrem konstruktoru třídy ofstream je režim otevření, ios::out je příznak pro otevření pro výstup a ios::binary, jak již název napovídá, otevření jako binární.
Lze testovat, zda se povedlo otevření souboru: if (!f) příkaz; //pokud se nepovedlo se otevřít, provede se příkaz, jinak se pokračuje za příkazem if
f je odkaz na proud, !f vrací negaci proudu
Lze volat i konstruktor bez parametrů: ifstream f; //jako vstupní proud, ale konstruktor zde neprovede otevření souboru, protože jste nezadali jméno souboru a režim (ten by si sice mohl odvodit - čtení z ifstream, ale musíte ještě zadat režim: binární nebo textový)
Proto otevření provedete voláním metody třídy přístupné pomocí f: f.open(cesta,ios::in|ios::binary)
Nápovědu o tomto otevření souboru v BC 3.1 získáte napsáním "fstream" a Ctrl+F1, zvolit Constructors: fstream::fstream Form2, See also: File Open. Jednodušší způsob je najít v indexu (Shift+F1) "open,fstream" a dále See also: File open. Jako příznak pro otevření lze použít: ios::binary(otevření jako binární soubor), ios::in (otevření jako vstupní - čtení), ios::out (otevření pro výstup - zápis), ios::nocreate (pro ty, kteří neumí anglicky - nocreate znamená nevytvářet, je to v případě, že soubor neexistuje, tak se nevytvoří, ale pokud existuje, potom se přepíše.
Prohlédněte si přiložený prográmek v C++.
Vysvětlíme si, proč lze testovat proměnnou typu f, zda nastala chyba. Vysvětlení je poměrně jednoduché: Většina funkcí f.read, f.get, f.open, atd. vrací proud a takže i chybu, neboť pokud se něco nepodaří (nastala chyba) - vrací se 0, jinak (povedlo se) - vrací se skutečná adresa proudu, což lze ovšem použít pro test, zda se vše povedlo. Pokud bychom chtěli funkcí f.read číst na konci souboru, tak se vrátí v f bude obsahovat 0 (je to vlastně ukazatel neukazující nikam - nulový ukazatel), což indikuje chybu.
Ještě si v rychlosti řekneme přesun v souboru (je to pro rozlišení, zda pracujeme se souborem otevřeným pro čtení nebo pro zápis, podle toho se dělí i funkce pro posun ukazatele v souboru):
seekp p=put, tedy ukazatel v souboru otevřeném pro zápis
seekg g=get, tedy ukazatel v souboru otevřeném pro čtení
Nápovědu získáte najitím seekp nebo seekg v indexu.