KURZUS: Programozás alapjai
MODUL: IV. modul
12. lecke: Magas szintű bemenet, kimenet
Ebben a fejezetben a magas szintű ki- és bemenet kezelésével foglalkozunk, ami egységes szemléletben teszi lehetővé a billentyűzet, a képernyő és hasonló hardver elemek, illetve fájlok kezelését. Megismerkedünk a folyam fogalmával, azok használatával, a különféle típusú folyamok eltérő pufferezési módjával, a legkülönfélébb fájlkezelési műveletekkel, és időnként megtapasztaljuk majd a magas szintű megközelítés hátulütőit is. | |||||||||||||||||||||||||||||||||||||
A lecke végére a hallgatónak tisztában kell lennie | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A lecke kulcsfogalmai: folyam, fájlazonosító, FILE struktúra, szöveges és bináris fájl, transzláció, írás, olvasás, hozzáfűzés, felújítás, pufferezetlenség, sorpufferezettség, teljes pufferezettség, fájlmutató, cső, átirányítás. | |||||||||||||||||||||||||||||||||||||
Áttekintés | |||||||||||||||||||||||||||||||||||||
A magas szintű bemeneten és kimeneten olyan folyam, áram (stream) jellegű fájl, ill. eszköz (nyomtató, billentyűzet, képernyő stb.) kezelést értünk, ami a felhasználó szempontjából nézve szinte nincs tekintettel a mögöttes hardverre, s így a lehető legflexibilisebb kimenetet, bemenetet biztosítja. | |||||||||||||||||||||||||||||||||||||
A valóságban a folyamot egy FILE típusú struktúrára mutató mutatóval manipuláljuk. Ezt a struktúrát, a folyamkezelő függvények prototípusait stb. az stdio.h fejfájlban definiálták. A struktúra például legyen a következő! | |||||||||||||||||||||||||||||||||||||
typedef struct{ | |||||||||||||||||||||||||||||||||||||
A programunkban | |||||||||||||||||||||||||||||||||||||
FILE *fp; | |||||||||||||||||||||||||||||||||||||
deklarációs utasítással FILE típusú struktúrára mutató mutatót kell deklarálni, mely értéket a folyamot megnyitó fopen, freopen függvényektől kap. Tehát használat előtt a folyamot meg kell nyitni. Megnyitása a folyamot egy fájlhoz, vagy egy eszközhöz kapcsolja. Jelezni kell azt is ilyenkor, hogy a folyamot csak olvasásra, vagy írásra, vagy mind kettőre kívánjuk használni stb. Ezután elvégezhetjük a kívánt bemenetet, kimenetet a folyamon, majd legvégül le kell zárni. | |||||||||||||||||||||||||||||||||||||
Folyamok megnyitása | |||||||||||||||||||||||||||||||||||||
FILE *fopen(const char *fajlazonosito, const char *mod); | |||||||||||||||||||||||||||||||||||||
A függvény megnyitja a fajlazonositoval megnevezett fájlt, és folyamot kapcsol hozzá. Visszaadja a fájlinformációt tartalmazó FILE struktúrára mutató mutatót, mely a rákövetkező műveletekben azonosítani fogja a folyamot, ill. NULL mutatót kapunk tőle, ha a megnyitási kísérlet sikertelen volt. | |||||||||||||||||||||||||||||||||||||
A fajlazonosito természetesen tartalmazhat (esetleg meghajtó nevet) utat is, de a maximális összhossza FILENAME_MAX karakter lehet. | |||||||||||||||||||||||||||||||||||||
A második paraméter mod karakterlánc meghatározza a későbbi adatátvitel irányát, helyét és a folyam típusát. Nézzük a lehetőségeket! | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A folyam típusa szöveges (text), vagy bináris lehet. A szöveges folyam a bemenetet és a kimenetet sorokból állóknak képzeli el. A sorok végét egy '\n' (LF) karakter jelzi. Lemezre történő kimenet esetén bizonyos operációs rendszereken (pl. Windows) a folyam a sorlezáró '\n' karaktert "\r\n" karakter párral (CR-LF) helyettesíti. Megfordítva: lemezes bemenetnél a CR-LF karakter párból ismét LF karakter lesz. Ezt a manipulációt transzlációnak nevezzük. Bemenet esetén a folyam a 0x1A értékű karaktert fájlvégnek tekinti. Összegezve: a szöveges folyam bizonyos, kitüntetett karaktereket speciálisan kezel, míg a bináris folyam ilyent egyetlen karakterrel sem tesz. | |||||||||||||||||||||||||||||||||||||
A mod karakterláncban expliciten megadhatjuk a folyam típusát. A szövegest a 't', a binárist a 'b' jelöli. A folyamtípus karakter a karakterláncban az első betű után bárhol elhelyezhető, azaz megengedettek az rt+, r+t stb. Nem kötelező azonban a folyamtípust a mod karakterláncban expliciten megadni. Ha elhagyjuk, alapértelmezés a szöveges. | |||||||||||||||||||||||||||||||||||||
Ha a folyamot felújításra (update) nyitották meg, akkor megengedett mind a bemenet, mind a kimenet. A kimenetet azonban fflush, vagy pozícionáló (fseek, rewind stb.) függvény hívása nélkül nem követheti közvetlenül bemenet. A fordított adatirányváltás is csak fájlvégen, vagy e függvények hívásának közbeiktatásával valósítható meg. | |||||||||||||||||||||||||||||||||||||
Folyamok pufferezése | |||||||||||||||||||||||||||||||||||||
A fájlokhoz kapcsolt folyamok szokásosan pufferezettek, s a puffer lefoglalása megnyitáskor automatikusan megtörténik malloc hívással. Ez is megengedi azonban az "egy karakteres szintű" bemenetet, kimenetet (getc, putc), ami nagyon gyors. A pufferrel kapcsolatos információkat a FILE struktúra tagjai írják le: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
ahol buffer a puffer kezdőcíme és bsize a mérete. A curp a pufferbeli aktuális pozícióra mutat, s level pedig számlálja, hogy még hány karakter van hátra a pufferben. A teljes pufferezettség azt jelenti, hogy kiírás automatikusan csak akkor történik, ha a puffer teljesen feltelt, ill. olvasás csak akkor következik be, ha a puffer teljesen kiürült. Egy karakter írása, vagy olvasása a curp pozícióról, ill. pozícióra történik, s a művelet mellékhatásaként a curp eggyel nő, s a level eggyel csökken. | |||||||||||||||||||||||||||||||||||||
A pufferezetlenség azt jelenti, hogy a bájtok átvitele azonnal megtörténik a fájlba (fájlból), vagy az eszközre (eszközről). | |||||||||||||||||||||||||||||||||||||
A mai operációs rendszerek legtöbbje a kisebb fájlokat megnyitásuk után valamilyen rendszer területen (cache) tartja, s a pufferek is csak a memóriabeli fájllal vannak kapcsolatban. Célszerű tehát, a programfejlesztő rendszer segítségében utánanézni, hogy az azonnali fájlba írás, vagy olvasás pontosan hogyan valósítható meg, ha igazán szükség van rá. | |||||||||||||||||||||||||||||||||||||
Megjegyezzük, hogy a setbuf és a setvbuf függvényhívásokkal kijelölhetünk saját puffert, módosíthatjuk a használatos puffer méretét, vagy pufferezetlenné tehetjük a bemenetet és a kimenetet, használatuk részleteit azonban itt nem tárgyaljuk. | |||||||||||||||||||||||||||||||||||||
A szabvány bemenet (stdin) sorpufferezett és a szabvány kimenet (stdout) pufferezetlen, ha nincsenek az operációs rendszerben átirányítva, mert ekkor mindkettő teljesen pufferezett. A sorpufferezettség azt jelenti, hogy ha a puffer üres, a következő bemeneti művelet megkísérli a teljes puffer feltöltését. Kimenet esetén mindig kiürül a puffer, ha teljesen feltelik, ill. amikor '\n' karaktert írunk bele. | |||||||||||||||||||||||||||||||||||||
Eddig csak a pufferek automatikus ürítéséről beszéltünk. Lehetséges azonban a pufferek kézi ürítése is. Sőt, adatátviteli irányváltás előtt a kimeneti puffert ki is kell üríteni. Lássuk a függvényt! | |||||||||||||||||||||||||||||||||||||
int fflush(FILE *stream); | |||||||||||||||||||||||||||||||||||||
Kimenetre nyitott folyam esetén a rutin kiírja a puffer tartalmát a kapcsolt fájlba. | |||||||||||||||||||||||||||||||||||||
Bemeneti folyamnál a függvény eredménye nem definiálható, de többnyire törli a puffer tartalmát. | |||||||||||||||||||||||||||||||||||||
Mindkét esetben nyitva marad a folyam. | |||||||||||||||||||||||||||||||||||||
Pufferezetlen folyamnál e függvény hívásának nincs hatása. | |||||||||||||||||||||||||||||||||||||
Sikeres esetben zérust kapunk vissza. Hibás esetben a szolgáltatott érték EOF. | |||||||||||||||||||||||||||||||||||||
Az fflush(NULL) üríti az összes kimeneti folyamot. | |||||||||||||||||||||||||||||||||||||
Pozícionálás a folyamokban | |||||||||||||||||||||||||||||||||||||
A folyamokat rendszerint szekvenciális fájlok olvasására, írására használják. A magas szintű bemenet, kimenet a fájlt bájtfolyamnak tekinti, mely a fájl elejétől (0 pozíció) indul és a fájl végéig tart. A fájl utolsó pozíciója a fájlméret - 1. Az adatátvitel mindig az aktuális fájlpozíciótól kezdődik, megtörténte után a fájlpozíció a fájlban következő, át nem vitt bájtra mozdul. A fájlpozíciót fájlmutatónak is szokás nevezni. | |||||||||||||||||||||||||||||||||||||
Eszközhöz kapcsolt folyam mindig csak szekvenciálisan (zérustól induló, monoton növekvő fájlpozícióval) érhető el. Lemezes fájlhoz kapcsolt folyam bájtjai azonban direkt (random) módon is olvashatók és írhatók. | |||||||||||||||||||||||||||||||||||||
Lemezes fájlok esetén a fájlmutató adatátvitel előtti beállítását az | |||||||||||||||||||||||||||||||||||||
int fseek(FILE *stream, long offset, int ahonnet); | |||||||||||||||||||||||||||||||||||||
függvénnyel végezhetjük el, mely a stream folyam fájlmutatóját offset bájttal az ahonnet paraméterrel adott fájlpozíción túlra állítja be. Szöveges folyamokra az offset zérus lehet, vagy egy az ftell függvény által visszaadott érték. | |||||||||||||||||||||||||||||||||||||
Az ahonnet paraméter a következő értékeket veheti fel: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A függvény elvet minden a bemenetre ungetc-vel visszarakott karaktert. | |||||||||||||||||||||||||||||||||||||
Felújításra megnyitott fájl esetén az fseek után mind bemenet, mind kimenet következhet. | |||||||||||||||||||||||||||||||||||||
A függvény törli a fájlvég jelzőt. | |||||||||||||||||||||||||||||||||||||
A függvény zérust ad vissza, ha a fájlpozícionálás sikeres volt, ill. nem zérust kapunk hiba esetén. | |||||||||||||||||||||||||||||||||||||
Írjunk fájlméretet megállapító függvényt! | |||||||||||||||||||||||||||||||||||||
#include <stdio.h> | |||||||||||||||||||||||||||||||||||||
A fajlmeret elteszi a pillanatnyi pozíciót az aktpoz változóba, hogy a fájl végére állítás után helyre tudja hozni a fájlmutatót. A lekérdezett fájlvég pozíció éppen a fájlméret. | |||||||||||||||||||||||||||||||||||||
Nézzük a további fájlpozícióval foglalkozó függvényeket! | |||||||||||||||||||||||||||||||||||||
long int ftell(FILE *stream); | |||||||||||||||||||||||||||||||||||||
A rutin visszaadja a stream folyam aktuális fájlpozícióját sikeres esetben, máskülönben -1L-t kapunk tőle. A | |||||||||||||||||||||||||||||||||||||
void rewind(FILE *stream); | |||||||||||||||||||||||||||||||||||||
a stream folyam fájlmutatóját a fájl elejére állítja. | |||||||||||||||||||||||||||||||||||||
Felújításra megnyitott fájl esetén a rewind után mind bemenet, mind kimenet következhet. | |||||||||||||||||||||||||||||||||||||
A függvény törli a fájlvég és a hibajelző biteket. | |||||||||||||||||||||||||||||||||||||
A FILE struktúra flags szava bitjei (állapotjelzői) a következő jelentésűek lehetnek! | |||||||||||||||||||||||||||||||||||||
#define _F_RDWR 0x0003 /* olvasás és írásjelző */ | |||||||||||||||||||||||||||||||||||||
A megadott stream folyam aktuális fájlpozícióját helyezi el az | |||||||||||||||||||||||||||||||||||||
int fgetpos(FILE *stream, fpos_t *pos); | |||||||||||||||||||||||||||||||||||||
a pos paraméterrel adott címen. Ez az érték felhasználható az fsetpos-ban. A visszaadott érték zérus hibátlan, és nem zérus sikertelen esetben. Az | |||||||||||||||||||||||||||||||||||||
int fsetpos(FILE *stream, const fpos_t *pos); | |||||||||||||||||||||||||||||||||||||
a stream folyam fájlmutatóját állítja be a pos paraméterrel mutatott értékre. | |||||||||||||||||||||||||||||||||||||
Felújításra megnyitott fájl esetén az fsetpos után mind bemenet, mind kimenet következhet. | |||||||||||||||||||||||||||||||||||||
A függvény törli a fájlvég jelző bitet, és elvet minden, e fájlra vonatkozó ungetc karaktert. | |||||||||||||||||||||||||||||||||||||
A visszakapott érték egyezik az fgetpos-nál írottakkal. | |||||||||||||||||||||||||||||||||||||
Vegyük észre, hogy az fseek és az ftell long értékekkel dolgozik. A maximális fájlméret így 2GB lehet. Az fpos_t adattípus e korlát áttörését biztosítja, hisz mögötte akár 64 bites egész is lehet. | |||||||||||||||||||||||||||||||||||||
Bemeneti műveletek | |||||||||||||||||||||||||||||||||||||
int fgetc(FILE *stream); | |||||||||||||||||||||||||||||||||||||
A folyam következő unsigned char karakterét adja vissza előjel kiterjesztés nélkül int-té konvertáltan, s eggyel előbbre állítja a fájlpozíciót. Sikertelen esetben, ill. fájl végén EOF-ot kapunk. A | |||||||||||||||||||||||||||||||||||||
int getc(FILE *stream); | |||||||||||||||||||||||||||||||||||||
makró, mint ahogyan ez a lehetséges definíciójából is látszik, ugyanezt teszi: | |||||||||||||||||||||||||||||||||||||
#define getc(f) \ | |||||||||||||||||||||||||||||||||||||
int ungetc(int c, FILE *stream); | |||||||||||||||||||||||||||||||||||||
A függvény visszateszi a stream bemeneti folyamba a c paraméter unsigned char típusúvá konvertált értékét úgy, hogy a következő olvasással ez legyen az első elérhető karakter. A szabályos működés csak egyetlen karakter visszahelyezése esetén garantált, de a visszatett karakter nem lehet az EOF. | |||||||||||||||||||||||||||||||||||||
Két egymást követő ungetc hívás hatására már csak a másodiknak visszatett karakter érhető el, mondjuk, a következő getc-vel, azaz az első elveszik. Gondoljuk csak meg, hogyha nincs puffer, akkor a visszatételhez a FILE struktúra egyetlen hold tagja áll rendelkezésre! | |||||||||||||||||||||||||||||||||||||
Az fflush, az fseek, az fsetpos, vagy a rewind törli a bemenetre visszatett karaktert. | |||||||||||||||||||||||||||||||||||||
Sikeres híváskor az ungetc a visszatett karaktert adja vissza. Hiba esetén viszont EOF-ot kapunk tőle. Az | |||||||||||||||||||||||||||||||||||||
char *fgets(char *s, int n, FILE *stream); | |||||||||||||||||||||||||||||||||||||
karakterláncot hoz be a stream folyamból, melyet az s címtől kezdve helyez el a memóriában. Az átvitel leáll, ha a függvény n - 1 karaktert, vagy '\n'-t olvasott. A rutin a '\n' karaktert is kiteszi a láncba, és a végéhez még záró '\0'-t is illeszt. | |||||||||||||||||||||||||||||||||||||
Sikeres esetben az fgets az s karakterláncra mutató mutatóval tér vissza. Fájlvégen, vagy hiba esetén viszont NULL-t szolgáltat. | |||||||||||||||||||||||||||||||||||||
Vegyük észre, hogy a jegyzet eleje óta használt getline függvény csak annyiban tér el az fgets-től, hogy: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
size_t fread(void *ptr, size_t size, size_t n, FILE *stream); | |||||||||||||||||||||||||||||||||||||
A függvény n * size bájtot olvas a stream folyamból, melyet a ptr paraméterrel mutatott címen helyez el. Visszaadott értéke nem a beolvasott bájtok száma, hanem a | |||||||||||||||||||||||||||||||||||||
beolvasott bájtok száma / size | |||||||||||||||||||||||||||||||||||||
sikeres esetben. Hiba, vagy fájlvég esetén ez persze nem egyezik n-nel. | |||||||||||||||||||||||||||||||||||||
Az eddig ismertetett bemeneti függvények nem konvertálták a beolvasott karakter(lánco)t. Az | |||||||||||||||||||||||||||||||||||||
int fscanf(FILE *stream, const char *format<, cim, ...>); | |||||||||||||||||||||||||||||||||||||
viszont a stream folyamból karakterenként olvasva egy sor bemeneti mezőt vizsgál. Aztán minden mezőt a format karakterláncnak megfelelően konvertál, és letárol rendre a paraméter cimeken. A format karakterláncban ugyanannyi konverziót okozó formátumspecifikációnak kell lennie, mint ahány bemeneti mező van. | |||||||||||||||||||||||||||||||||||||
A jelölésben a <> az elhagyhatóságot, a ... a megelőző paraméter tetszőleges számú ismételhetőségét jelenti. A bemeneti mező definíciója, a formázás és a konvertálás részletei a scanf függvény leírásában találhatók meg! | |||||||||||||||||||||||||||||||||||||
Az fscanf a sikeresen vizsgált, konvertált és letárolt bemeneti mezők számával tér vissza. Ha a függvény az olvasást a fájl végén kísérelné meg, vagy valamilyen hiba történne, akkor EOF-ot kapunk tőle vissza. A rutin zérussal is visszatérhet, ami azt jelenti, hogy egyetlen vizsgált mezőt sem tárolt le. | |||||||||||||||||||||||||||||||||||||
Kimeneti műveletek | |||||||||||||||||||||||||||||||||||||
int fputc(int c, FILE *stream); | |||||||||||||||||||||||||||||||||||||
A függvény a c unsigned char típusúvá konvertált értékét írja ki a stream folyamba. Sikeres esetben a c karaktert kapjuk vissza tőle, hiba bekövetkeztekor viszont EOF-ot. A | |||||||||||||||||||||||||||||||||||||
int putc(int c, FILE *stream); | |||||||||||||||||||||||||||||||||||||
makró, mint ahogyan ez a lehetséges definíciójából is látszik, ugyanezt teszi: | |||||||||||||||||||||||||||||||||||||
#define putc(c,f) \ | |||||||||||||||||||||||||||||||||||||
int fputs(const char *s, FILE *stream); | |||||||||||||||||||||||||||||||||||||
A függvény az s karakterláncot kiírja a stream folyamba. Nem fűz hozzá '\n' karaktert, és a lezáró '\0' karakter sem kerül át. | |||||||||||||||||||||||||||||||||||||
Sikeres esetben nem negatív értékkel tér vissza. Hiba esetén viszont EOF-ot kapunk tőle. Az | |||||||||||||||||||||||||||||||||||||
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream); | |||||||||||||||||||||||||||||||||||||
a ptr címmel mutatott memória területről n * size bájtot ír ki a stream folyamba. Visszaadott értéke nem a kiírt bájtok száma, hanem a | |||||||||||||||||||||||||||||||||||||
kiírt bájtok száma / size | |||||||||||||||||||||||||||||||||||||
sikeres esetben. Hiba bekövetkeztekor ez nem egyezik n-nel. | |||||||||||||||||||||||||||||||||||||
Az eddigi kimeneti függvények nem végeztek konverziót. Az | |||||||||||||||||||||||||||||||||||||
int fprintf(FILE *stream, const char *format<, parameter, ...>); | |||||||||||||||||||||||||||||||||||||
fogad egy sor parametert, melyeket a format karakterláncnak megfelelően formáz (konvertál), és kivisz a stream folyamba. A format karakterláncban ugyanannyi konverziót okozó formátumspecifikációnak kell lennie, mint ahány parameter van. | |||||||||||||||||||||||||||||||||||||
A jelölésben a <> az elhagyhatóságot, a ... a megelőző paraméter tetszőleges számú ismételhetőségét jelenti. A formázás és a konvertálás részletei a printf függvény leírásában találhatók meg! | |||||||||||||||||||||||||||||||||||||
Az fprintf a folyamba kivitt karakterek számával tér vissza sikeres esetben, ill. EOF-ot kapunk tőle hiba bekövetkeztekor. | |||||||||||||||||||||||||||||||||||||
Folyamok lezárása | |||||||||||||||||||||||||||||||||||||
int fclose(FILE *stream); | |||||||||||||||||||||||||||||||||||||
A rutin lezárja a stream folyamot. Ez előtt azonban üríti a folyamhoz tartozó puffert, s a pufferhez automatikusan allokált memóriát fel is szabadítja. Ez utóbbi nem vonatkozik a setbuf, vagy a setvbuf függvényekkel hozzárendelt pufferekre. Ezek "ügyei" csak a felhasználóra tartoznak. | |||||||||||||||||||||||||||||||||||||
Sikeres esetben az fclose zérussal tér vissza. Hiba esetén viszont EOF-ot kapunk tőle. | |||||||||||||||||||||||||||||||||||||
Hibakezelés | |||||||||||||||||||||||||||||||||||||
Tudjuk, hogy a szabvány könyvtári függvények - így a magas szintű bemenetet, kimenetet kezelők is - a hibát, a kivételes esetet úgy jelzik, hogy valamilyen speciális értéket (EOF, NULL mutató, HUGE_VAL stb.) adnak vissza, és az errno globális hibaváltozóba beállítják a hiba kódját. A hibakódok az errno.h fejfájlban definiált, egész, nem zérusértékű szimbolikus állandók. | |||||||||||||||||||||||||||||||||||||
Programunk indulásakor a szabvány bemeneten (stdin) és kimeneten (stdout) túl a hibakimenet (stderr) is rendelkezésre áll, s a hibaüzeneteket ez utóbbin célszerű megjelentetni. Az stderr a képernyő (karakteres ablak) alapértelmezés szerint. | |||||||||||||||||||||||||||||||||||||
Mit jelentessünk meg hibaüzenetként az stderr-en? | |||||||||||||||||||||||||||||||||||||
Természetesen bármilyen szöveget kiírathatunk, de a hibakódokhoz programfejlesztő rendszertől függően hibaüzenet karakterláncok is tartoznak, s ezek is megjelentethetők. A hibakodhoz tartozó hibaüzenet karakterlánc kezdőcímét szolgáltatja a szabványos | |||||||||||||||||||||||||||||||||||||
#include <string.h > | |||||||||||||||||||||||||||||||||||||
char *strerror(int hibakod); | |||||||||||||||||||||||||||||||||||||
függvény, s az üzenet meg is jelentethető | |||||||||||||||||||||||||||||||||||||
fprintf(stderr, "Hiba: %s\n", strerror(hibakod)); | |||||||||||||||||||||||||||||||||||||
módon. A | |||||||||||||||||||||||||||||||||||||
voidperror(const char *s); | |||||||||||||||||||||||||||||||||||||
kiírja az stderr-re azt a hibaüzenetet, melyet a legutóbbi hibát okozó, könyvtári függvény hívása idézett elő. Először megjelenteti az s karakterláncot a rutin, aztán kettőspontot (:) tesz, majd az errno aktuális értékének megfelelő üzenet karakterláncot írja ki lezáró '\n'-nel. | |||||||||||||||||||||||||||||||||||||
Tehát például a perror("Hiba: ") megfelel a | |||||||||||||||||||||||||||||||||||||
fprintf(stderr, "Hiba: %s\n", strerror(errno)); | |||||||||||||||||||||||||||||||||||||
függvényhívásnak. | |||||||||||||||||||||||||||||||||||||
Vigyázat! Az errno értékét csak közvetlenül a hibát okozó rutin hívása után szabad felhasználni, mert a következő könyvtári függvény megidézése felülírhatja e globális változó értékét. Ha a hibakóddal mégis később kívánnánk foglalkozni, akkor tegyük el az errno értékét egy segédváltozóba! | |||||||||||||||||||||||||||||||||||||
Folyamokkal kapcsolatban a perror s paramétere a fájlazonosító szokott lenni. | |||||||||||||||||||||||||||||||||||||
Meg kell tárgyalnunk még három, csak a folyamok hibakezelésével foglalkozó függvényt! A | |||||||||||||||||||||||||||||||||||||
void clearerr(FILE *stream); | |||||||||||||||||||||||||||||||||||||
nullázza a stream folyam fájlvég és hibajelzőjét. Ha a folyam hibajelző bitje egyszer bebillent, akkor minden a folyamon végzett művelet hibával tér vissza mindaddig, míg a hibajelzőt e függvénnyel, vagy a rewind-dal nem törlik. | |||||||||||||||||||||||||||||||||||||
A fájlvég jelző bitet egyébként minden bemeneti művelet nullázza. Az | |||||||||||||||||||||||||||||||||||||
int feof(FILE *stream); | |||||||||||||||||||||||||||||||||||||
többnyire makró, mely a következő lehetséges | |||||||||||||||||||||||||||||||||||||
#define feof(f) ((f)->flags & _F_EOF) | |||||||||||||||||||||||||||||||||||||
definíciója miatt, visszaadja a fájlvég jelző bit állapotát, azaz választ ad a fájlvég van-e kérdésre. | |||||||||||||||||||||||||||||||||||||
Az egyszer bebillent fájlvég jelző bit a következő, e folyamra vonatkozó bemeneti, pozícionáló műveletig, vagy clearerr-ig 1 marad. Az | |||||||||||||||||||||||||||||||||||||
int ferror(FILE *stream); | |||||||||||||||||||||||||||||||||||||
makró ebben a szellemben | |||||||||||||||||||||||||||||||||||||
#define ferror(f) ((f)->flags & _F_ERR) | |||||||||||||||||||||||||||||||||||||
a hiba jelző bit állapotát adja vissza. | |||||||||||||||||||||||||||||||||||||
Az egyszer bebillent hiba jelző bitet csak a clearerr és a rewind függvények törlik. Ha a kérdéses folyammal kapcsolatban a bebillent hiba jelző bit törléséről nem gondoskodunk, akkor minden e folyamra meghívott további függvény hibát jelezve fog visszatérni. | |||||||||||||||||||||||||||||||||||||
Írjuk meg az fputc segítségével az fputs függvényt! | |||||||||||||||||||||||||||||||||||||
int fputs(const char *s, FILE *stream){ | |||||||||||||||||||||||||||||||||||||
Készítsünk szoftvert komplett hibakezeléssel, mely az első parancssori paramétere fájlt átmásolja a második paramétere azonosítójú fájlba! Ha a programot nem elég parancssori paraméterrel indítják, akkor ismertesse használatát! A másolási folyamat előrehaladásáról tájékoztasson feltétlenül! | |||||||||||||||||||||||||||||||||||||
/* PELDA30.C: Elso parameter fajl masolasa a masodikba. */ | |||||||||||||||||||||||||||||||||||||
A formátumspecifikációbeli * SZELES mezőszélességet eredményez. | |||||||||||||||||||||||||||||||||||||
while((c=fgetc(be))!=EOF) { | |||||||||||||||||||||||||||||||||||||
Az stdout-ra irányuló műveletek hibakezelésével azért nem foglalkoztunk, mert ahol az sem működik, ott az operációs rendszer sem megy. | |||||||||||||||||||||||||||||||||||||
Előre definiált folyamok | |||||||||||||||||||||||||||||||||||||
Egy időben legfeljebb FOPEN_MAX, vagy OPEN_MAX folyam (fájl) lehet megnyitva. Ennek megfelelő a globális FILE struktúratömb | |||||||||||||||||||||||||||||||||||||
extern FILE _streams[]; | |||||||||||||||||||||||||||||||||||||
mérete is, melyből ráadásul még az első három bizonyosan foglalt is: | |||||||||||||||||||||||||||||||||||||
#define stdin (&_streams[0]) | |||||||||||||||||||||||||||||||||||||
A globális FILE struktúratömb neve persze lehet ettől eltérő is. | |||||||||||||||||||||||||||||||||||||
Ezek az előre definiált folyamok, melyek programunk futásának megkezdésekor már megnyitva rendelkezésre állnak. | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Az stdin és az stdout átirányítható a programot indító parancssorban szövegfájlba. | |||||||||||||||||||||||||||||||||||||
program < bemenet.txt > kimenet.txt | |||||||||||||||||||||||||||||||||||||
Ha nincsenek átirányítva, akkor az stdin sorpufferezett, s az stdout pedig pufferezetlen. Ilyen az stderr is, tehát pufferezetlen. A legtöbb operációs rendszerben cső (pipe) is használható. Például: | |||||||||||||||||||||||||||||||||||||
program1 | program2 | program3 | |||||||||||||||||||||||||||||||||||||
program1 a rendszerben beállított szabvány bemenettel rendelkezik. Szabvány kimenete szabvány bemenete lesz program2-nek, aminek szabvány kimenete program3 szabvány bemenete. Végül program3 szabvány kimenete az, amit a rendszerben beállítottak. | |||||||||||||||||||||||||||||||||||||
Mindhárom előre definiált folyam átirányítható a programban is, azaz ha nem felelne meg az alapértelmezés szerint a folyamhoz kapcsolt eszköz, akkor ezt kicserélhetjük az | |||||||||||||||||||||||||||||||||||||
FILE *freopen(const char *fajlazonosito, const char *mod, FILE *stream); | |||||||||||||||||||||||||||||||||||||
függvénnyel a fajlazonositojú fájlra. A rutin első két paraméterének értelmezése és visszaadott értéke egyezik az fopen-ével. A harmadik viszont az előre definiált folyam: stdin, stdout vagy stderr. | |||||||||||||||||||||||||||||||||||||
Az freopen persze nem csak előre definiált folyamokra használható, hanem bármilyen mással is, de ez a legjellemzőbb alkalmazása. | |||||||||||||||||||||||||||||||||||||
Készítsünk programot, mely a szabvány bemenetről érkező karaktereket a parancssori paraméterként megadott szövegfájlba másolja! Ha indításkor nem adnak meg parancssori paramétert, akkor csak echózza a szoftver a bementet a kimeneten! | |||||||||||||||||||||||||||||||||||||
A feladatot az stdout átirányításával oldjuk meg. | |||||||||||||||||||||||||||||||||||||
/* PELDA31.C: Bemenet masolasa fajlba stdout-kent. */ | |||||||||||||||||||||||||||||||||||||
Az stdlib.h bekapcsolásával rendelkezésre álló | |||||||||||||||||||||||||||||||||||||
int system(const char *parancs); | |||||||||||||||||||||||||||||||||||||
rutin parancs paraméterét átadja végrehajtásra az operációs rendszernek (a parancsértelmezőnek), azaz végrehajtatja a rendszerrel a parancsot. A függvény visszatérési értéke a programfejlesztő rendszertől függ, de többnyire a parancsértelmező által szolgáltatott érték az. | |||||||||||||||||||||||||||||||||||||
Ha a parancs NULL, akkor a rutin a parancsértelmező létezéséről számol be, azaz ha van, nem zérussal tér vissza, és zérust szolgáltat, ha nincs. | |||||||||||||||||||||||||||||||||||||
Bemenet az stdin-ről | |||||||||||||||||||||||||||||||||||||
int getchar(void); | |||||||||||||||||||||||||||||||||||||
A függvény makró, azaz: | |||||||||||||||||||||||||||||||||||||
#define getchar() getc(stdin) | |||||||||||||||||||||||||||||||||||||
A | |||||||||||||||||||||||||||||||||||||
char *gets(char *s); | |||||||||||||||||||||||||||||||||||||
az fgets-hez hasonlóan karaktereket olvas az stdin-ről, melyeket rendre elhelyez a paraméter s karaktertömbben. A visszaadott értéke is egyezik az fgets-ével, azaz normál esetben s-t szolgáltatja, s fájlvég vagy hiba bekövetkeztekor NULL-t. Az stdin-ről való olvasás azonban az első '\n' karakterig tart. Magát az LF karaktert nem viszi át az s tömbbe, hanem helyette a karakterláncot záró '\0'-t ír oda. | |||||||||||||||||||||||||||||||||||||
A konverziót is végző | |||||||||||||||||||||||||||||||||||||
int scanf(const char *format<, cim, ...>); | |||||||||||||||||||||||||||||||||||||
függvény az fscanf-hez hasonlóan - de az stdin folyamból - olvasva egy sor bemeneti mezőt vizsgál. Aztán minden mezőt a format karakterláncnak megfelelően formáz (konvertál), és letárol rendre a paraméter címeken. | |||||||||||||||||||||||||||||||||||||
A jelölésben a <> az elhagyhatóságot, a ... a megelőző paraméter tetszőleges számú ismételhetőségét jelenti. A bemeneti mező definíciójára rögtön kitérünk! | |||||||||||||||||||||||||||||||||||||
A scanf a sikeresen vizsgált, konvertált és letárolt bemeneti mezők számával tér vissza. A vizsgált vagy akár konvertált, de le nem tárolt mezők ebbe a számba nem értendők bele. Ha a függvény az olvasást a fájl végén kísérelné meg, vagy valamilyen hiba következne be, akkor EOF-ot kapunk tőle vissza. A függvény zérussal is visszatérhet, ami azt jelenti, hogy egyetlen vizsgált mezőt sem tárolt le. | |||||||||||||||||||||||||||||||||||||
A format karakterláncban ugyanannyi formátumspecifikációnak kell lennie, mint ahány bemeneti mező van, és ahány cim paramétert megadtak a hívásban. Ha a formátumspecifikációk többen vannak, mint a cimek, akkor ez előre megjósolhatatlan hibához vezet. Ha a cim paraméterek száma több mint a formátumspecifikációké, akkor a felesleges cimeket egyszerűen elhagyja a scanf. | |||||||||||||||||||||||||||||||||||||
A format karakterlánc három féle objektumból áll: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Ha fehér karakter következik a format karakterláncban, akkor a scanf olvassa, de nem tárolja a bemenetről érkező fehér karaktereket egészen a következő nem fehér karakterig. | |||||||||||||||||||||||||||||||||||||
Nem fehér karakter minden más a '%' kivételével. Ha a format karakterláncban ilyen karakter következik, akkor a scanf olvas a bemenetről, de nem tárol, hanem elvárja, hogy a beolvasott karakter egyezzen a format karakterláncban levővel. | |||||||||||||||||||||||||||||||||||||
A formátumspecifikációk vezérlik a scanf függvényt az olvasásban, a bemeneti mezők konverziójában és a konverzió típusában. A konvertált értéket aztán a rutin elhelyezi a soron következő paraméterrel adott cím-en. A formátumspecifikáció általános alakja: | |||||||||||||||||||||||||||||||||||||
% <*> <szélesség> <h|l|L> típuskarakter | |||||||||||||||||||||||||||||||||||||
ahol a <> az elhagyhatóságot és a | a vagylagosságot jelöli. Nézzük a részleteket! | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A következő táblázatban felsoroljuk az aritmetikai konverziót okozó típuskaraktereket: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A mutató konverzió típuskarakterei: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A karakteres konverzió típuskarakterei: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Néhány programfejlesztő rendszer esetén a keresőkészletben tartomány is megadható, azaz például a %[0123456789]-et a %[0-9] teljes mértékben helyettesíti. A tartomány kezdő karaktere kódjának azonban kisebbnek kell lenni a tartomány vég karaktere kódjánál. Nézzünk néhány példát! | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Tisztázzuk végre a bemeneti mező fogalmát! | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A bemeneti mező második alternatívája miatt, nem javasoljuk a scanf függvény széleskörű használatát programokban. Helyette olvassuk be a bemeneti karakterláncot, végezzük el rajta az összes formai ellenőrzést! Ha aztán minden rendben volt, a konverzió megvalósítható egy menetben az | |||||||||||||||||||||||||||||||||||||
int sscanf(const char *puffer, const char *format<, cim, ...>); | |||||||||||||||||||||||||||||||||||||
függvénnyel, mely ugyanazt teszi, mint a scanf, de bemeneti mezőit nem az stdin-ről, hanem az első paraméterként kapott karakterláncból veszi. | |||||||||||||||||||||||||||||||||||||
Kimenet az stdout-ra | |||||||||||||||||||||||||||||||||||||
int putchar(int c); | |||||||||||||||||||||||||||||||||||||
A függvény makró, azaz: | |||||||||||||||||||||||||||||||||||||
#define putchar(c) putc((c), stdout) | |||||||||||||||||||||||||||||||||||||
A | |||||||||||||||||||||||||||||||||||||
int puts(const char *s); | |||||||||||||||||||||||||||||||||||||
függvény a '\0' lezárású s karakterláncot az stdout folyamba írja a '\0' nélkül, mely helyett viszont kitesz még egy '\n' karaktert. | |||||||||||||||||||||||||||||||||||||
Sikeres esetben nem negatív értékkel tér vissza. Hiba bekövetkeztekor viszont EOF-ot kapunk tőle. | |||||||||||||||||||||||||||||||||||||
A konverziót is végző | |||||||||||||||||||||||||||||||||||||
int printf(const char *format<, parameter, ...>); | |||||||||||||||||||||||||||||||||||||
rutin fogad egy sor parametert, melyek mindegyikéhez hozzárendel egy, a format karakterláncban lévő formátumspecifikációt, és az ezek szerint formázott (konvertált) adatokat kiviszi az stdout folyamba. | |||||||||||||||||||||||||||||||||||||
A jelölésben a <> az elhagyhatóságot, a ... a megelőző paraméter tetszőleges számú ismételhetőségét jelenti. | |||||||||||||||||||||||||||||||||||||
A format karakterláncban ugyanannyi formátumspecifikációnak kell lennie, mint ahány parameter van. Ha kevesebb a paraméter, mint a formátumspecifikáció, akkor ez előre megjósolhatatlan hibához vezet. Ha több a paraméter, mint a formátumspecifikáció, akkor a felesleges paramétereket egyszerűen elhagyja a printf. | |||||||||||||||||||||||||||||||||||||
A rutin a folyamba kivitt bájtok számával tér vissza sikeres esetben, ill. EOF-ot kapunk tőle hiba bekövetkeztekor. | |||||||||||||||||||||||||||||||||||||
A format karakterlánc kétféle objektumot tartalmaz: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A sima karaktereket változatlanul kiviszi az stdout-ra a printf. A formátumspecifikációhoz veszi a következő parameter értékét, konvertálja, és csak ezután teszi ki az stdout-ra. | |||||||||||||||||||||||||||||||||||||
A formátumspecifikáció általános alakja a következő: | |||||||||||||||||||||||||||||||||||||
% <jelzők> <szélesség> <.pontosság> <h|l|L> típuskarakter | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A következőkben leírjuk a típuskarakterek értelmezését arra az esetre, ha a formátumspecifikációban a % jelet csak a típuskarakter követi. Nézzük előbb az aritmetikai konverziót okozó típuskaraktereket: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
e vagy E típuskarakter esetén a vonatkozó paraméter értékét a printf | |||||||||||||||||||||||||||||||||||||
<->d.ddd...e<+|->ddd | |||||||||||||||||||||||||||||||||||||
alakúra konvertálja, ahol: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
f típuskarakternél a vonatkozó paraméter értékét a printf | |||||||||||||||||||||||||||||||||||||
<->ddd.ddd... | |||||||||||||||||||||||||||||||||||||
alakúra konvertálja, s a tizedes pont után kiírt számjegyek számát itt is a pontosság határozza meg. | |||||||||||||||||||||||||||||||||||||
g vagy G típuskarakter esetén a printf a vonatkozó paraméter értékét e, E, vagy f alakra konvertálja | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A karakteres konverzió típuskarakterei: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A mutató konverzió típuskarakterei: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Lássuk a jelzőket! | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Az alternatív formák a típuskaraktertől függnek: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A szélesség a kimeneti érték minimális mezőszélességét határozza meg, azaz a megjelenő eredmény legalább ilyen szélességű. A szélességet két módon adhatjuk meg: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Bármilyen szélességet is írunk elő, a printf a konverzió eredményét nem csonkítja! A lehetséges szélesség specifikációk: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
A pontosság specifikáció mindig ponttal (.) kezdődik. A szélességhez hasonlóan ez is megadható közvetlenül, vagy közvetve (*) a paraméter listában. Utóbbi esetben egy int típusú paraméternek meg kell előznie azt a paramétert a printf hívásban, amire az egész formátumspecifikáció vonatkozik. | |||||||||||||||||||||||||||||||||||||
Megemlítjük, hogy a szélességet és a pontosságot is megadhatjuk egyszerre közvetetten. Ilyenkor a formátumspecifikációban *.* van. A printf hívás paraméter listájában két int típusú paraméter előzi meg (az első a szélesség, a második a pontosság) azt a paramétert, amire az egész formátumspecifikáció vonatkozik. Lássunk egy példát! | |||||||||||||||||||||||||||||||||||||
printf("%*.*f", 6, 2, 6.2); | |||||||||||||||||||||||||||||||||||||
A 6.2-et f típuskarakterrel kívánjuk konvertáltatni úgy, hogy a mezőszélesség 6 és a pontosság 2 legyen. | |||||||||||||||||||||||||||||||||||||
A pontosság specifikációk a következők: | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Legvégül nézzük még a h, l és L méretmódosító karaktereket! A méretmódosítók annak a paraméternek a hosszát módosítják, melyre az egész formátumspecifikáció vonatkozik. | |||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
Jelentessük meg a 2003. március 2. dátumot ÉÉÉÉ-HH-NN alakban! | |||||||||||||||||||||||||||||||||||||
printf("%04d-%02d-%02d", 2003, 3, 2); | |||||||||||||||||||||||||||||||||||||
Mindkét hívás 2003-03-02-t szolgáltat. | |||||||||||||||||||||||||||||||||||||
Szemléltessük a 0, a #, a + és a - jelzők hatását d, o, x, e és f típuskarakterek esetén! | |||||||||||||||||||||||||||||||||||||
/* PELDA32.C: A printf jelzoinek szemleltetese nehany | |||||||||||||||||||||||||||||||||||||
Az i 15-ről indul, s zérusig csökken egyesével, azaz eközben leírja az összes lehetséges négybites bitkombinációt. A k felvett értékei 1, 2, 4 és 8, s a jelzok tömb épp ezen indexű elemeiben találhatók meg a jelző karakterek. | |||||||||||||||||||||||||||||||||||||
strcpy(format, "%5s |"); | |||||||||||||||||||||||||||||||||||||
A program futtatásakor megjelenő kimenet: | |||||||||||||||||||||||||||||||||||||
prefix 6d 6o 8x 10.2e 10.2f | |||||||||||||||||||||||||||||||||||||
int sprintf(char *puffer, const char *format<, parameter, ...>); | |||||||||||||||||||||||||||||||||||||
A függvény ugyanazt teszi, mint a printf, de a kimenetét nem az stdout-ra készíti, hanem az első paraméterként megkapott karaktertömbbe '\0'-lal lezárva. | |||||||||||||||||||||||||||||||||||||
Egyéb függvények | |||||||||||||||||||||||||||||||||||||
Csak lezárt fájlokkal foglalkozik a következő két függvény. A | |||||||||||||||||||||||||||||||||||||
int remove(const char *fajlnev); | |||||||||||||||||||||||||||||||||||||
törli az akár komplett úttal megadott azonosítójú fájlt. Sikeres esetben zérust, máskülönben -1-et szolgáltat a rutin. A | |||||||||||||||||||||||||||||||||||||
int rename(const char *reginev, const char *ujnev); | |||||||||||||||||||||||||||||||||||||
a reginev azonosítójú fájlt átnevezi ujnev-re. Ha az ujnev meghajtónevet is tartalmaz, akkor az nem térhet el attól, ahol a reginev azonosítójú fájl elhelyezkedik. Ha viszont az ujnev a fájl eredeti helyétől eltérő utat tartalmaz, akkor az átnevezésen túl megtörténik a fájl átmozgatása is. | |||||||||||||||||||||||||||||||||||||
A függvény egyik paramétere sem lehet globális fájlazonosító! | |||||||||||||||||||||||||||||||||||||
Sikeres esetben zérust szolgáltat a rutin. A problémát a -1 visszaadott érték jelzi. | |||||||||||||||||||||||||||||||||||||
FILE *tmpfile(void); | |||||||||||||||||||||||||||||||||||||
A rutin "wb+" móddal ideiglenes fájlt hoz létre, melyet lezárásakor, vagy normális programbefejeződéskor automatikusan töröl a rendszer. A visszaadott érték az ideiglenes fájl FILE struktúrájára mutat, ill. NULL jön létrehozási probléma esetén. | |||||||||||||||||||||||||||||||||||||
char *tmpnam(char s[L_tmpnam]); | |||||||||||||||||||||||||||||||||||||
tmpnam(NULL) módon hívva olyan fájlazonosítót kapunk, mely egyetlen létező fájl nevével sem egyezik. A szolgáltatott mutató belső, statikus karaktertömböt címez, ahol a fájlazonosító karakterlánc található. | |||||||||||||||||||||||||||||||||||||
A fájlazonosító karakterlánc nem marad ott örökké, mert a következő tmpnam hívás felülírja. | |||||||||||||||||||||||||||||||||||||
Nem NULL mutatóval hívva a rutin kimásolja a fájlazonosítót az s karaktertömbbe, s ezzel is tér vissza. Az s tömb legalább L_tmpnam méretű kell, legyen. Többszöri hívással legalább TMP_MAX darab, különböző fájlazonosító generálása garantált. |
Feladatok | |||||||||
1. Készítsen szoftvert, mely eldönti az indító parancssorban megadott azonosítójú fájl típusát, azaz hogy szöveges, vagy bináris! Ha parancssori paraméter nélkül futtatják a programot, akkor ismertesse a használatát! A fájltípus megállapítása a benne szereplő karakterek kódjain alapulhat; az ASCII kódtábla első 32 vezérlőjele többségének semmi értelme sincs egy szöveges fájlban. | |||||||||
#include <stdio.h> | |||||||||
2. Írjon szoftvert, mely az indító parancssorban megadott szövegfájlokat egyesíti a megadás sorrendjében a parancssorban utolsóként előírt azonosítójú szövegfájlba! Ha parancssori paraméter nélkül indítják a programot, akkor ismertesse a képernyőn, hogyan kell használni! Ha csak egy fájlazonosító van a parancssorban, akkor a szabvány bemenet másolandó bele. A fájlok egyesítése során a folyamat előrehaladásáról tájékoztatni kell a képernyőn! A szabvány bemenet másolása esetén végül közlendő még az eredményfájl mérete! | |||||||||
/* EGYESIT.C: Szovegfajlok egyesitese. */ | |||||||||
3. A kezdő programozó olyan függvényt próbált írni, ami helyben középre igazítja m szélességben a paraméter karakterláncot, majd visszaadja annak címét! | |||||||||
/*1*/char *kozepre(char *s,int m){ | |||||||||
Mivel a függvény nem tökéletes, jelölje meg azokat a sorokat, amelyekkel működőképessé tehető!
![]() | |||||||||
4. Kezdő programozónk azt a feladatot kapta, hogy készítsen egy függvényt, ami a paramétereként adott egyik folyam tartalmát a másikba másolja, és ehhez meret méretű belső puffert használ. A megoldás sajnos nem tökéletes. | |||||||||
/*1*/void masol(FILE* be, FILE* ki, int meret) { | |||||||||
Jelölje meg azokat a sorokat, amelyekkel helyes lesz a működése!
![]() |