uyu shirinu 0. Pri rabote s polyami imeetsya ryad momentov, na kotorye sleduet obratit' vnimanie. Po-vidimomu naibolee sushchestvennym yavlyaetsya to, chto otrazhaya prirodu razlichnyh apparatnyh sred- stv, raspredelenie polej na nekotoryh mashinah osushchestvlyaetsya sleva napravo, a na nekotoryh sprava nalevo. |to oznachaet, chto hotya polya ochen' polezny dlya raboty s vnutrenne oprede- lennymi strukturami dannyh, pri razdelenii vneshne opredelyae- myh dannyh sleduet tshchatel'no rassmatrivat' vopros o tom, ka- koj konec postupaet pervym. Drugie ogranicheniya, kotorye sleduet imet' v vidu: polya ne imeyut znaka; oni mogut hranit'sya tol'ko v peremennyh tipa INT (ili, chto ekvivalentno, tipa UNSIGNED); oni ne yavlyayutsya massivami; oni ne imeyut adresov, tak chto k nim ne primenima operaciya &. 6.8. Ob容dineniya Ob容dineniya - eto peremennaya, kotoraya v razlichnye momen- ty vremeni mozhet soderzhat' ob容kty raznyh tipov i razmerov, prichem kompilyator beret na sebya otslezhivanie razmera i tre- bovanij vyravnivaniya. Ob容dineniya predstavlyayut vozmozhnost' rabotat' s razlichnymi vidami dannyh v odnoj oblasti pamyati, ne vvodya v programmu nikakoj mashinno-zavisimoj informacii. V kachestve primera, snova iz simvol'noj tablicy kompilya- tora, predpolozhim, chto konstanty mogut byt' tipa INT , FLOAT ili byt' ukazatelyami na simvoly. znachenie kazhdoj konkretnoj konstanty dolzhno hranit'sya v peremennoj sootvestvuyushchego ti- pa, no vse zhe dlya upravleniya tablicej samym udobnym bylo by, esli eto znachenie zanimalo by odin i tot zhe ob容m pamyati i hranilos' v tom zhe samom meste nezavisimo ot ego tipa. eto i yavlyaetsya naznacheniem ob容dineniya - vydelit' otdel'nuyu pere- mennuyu, v kotoroj mozhno zakonno hranit' lyubuyu odnu iz pere- mennyh neskol'kih tipov. Kak i v sluchae polej, sintaksis os- novyvaetsya na strukturah. UNION U_TAG \( INT IVAL; FLOAT FVAL; CHAR *PVAL; \) UVAL; Peremennaya UVAL budet imet' dostatochno bol'shoj razmer,chtoby hranit' naibol'shij iz treh tipov, nezavisimo ot mashiny, na kotoroj osushchestvlyaetsya kompilyaciya, - programma ne budet za- visit' ot harakteristik apparatnyh sredstv. Lyuboj iz etih treh tipov mozhet byt' prisvoen UVAR i zatem ispol'zovan v vyrazheniyah, poka takoe ispol'zovanie sovmestimo: izvlekaemyj tip dolzhen sovpadat' s poslednim pomeshchennym tipom. Delo programmista - sledit' za tem, kakoj tip hranitsya v ob容di- nenii v dannyj moment; esli chto-libo hranitsya kak odin tip, a izvlekaetsya kak drugoj, to rezul'taty budut zaviset' ot ispol'zuemoj mashiny. Sintaksicheski dostup k chlenam ob容dineniya osushchestvlyaetsya sleduyushchim obrazom: imya ob容dineniya.chlen -------------------- ili ukazatel' ob容dineniya ->chlen ---------------------------- to est' tochno tak zhe, kak i v sluchae struktur. esli dlya ots- lezhivaniya tipa, hranimogo v dannyj moment v UVAL, ispol'zu- etsya peremennaya UTYPE, to mozhno vstretit' takoj uchastok programmy: IF (UTYPE == INT) PRINTF("%D\N", UVAL.IVAL); ELSE IF (UTYPE == FLOAT) PRINTF("%F\N", UVAL.FVAL); ELSE IF (UTYPE == STRING) PRINTF("%S\N", UVAL.PVAL); ELSE PRINTF("BAD TYPE %D IN UTYPE\N", UTYPE); Ob容dineniya mogut poyavlyat'sya vnutri struktur i massivov i naoborot. Zapis' dlya obrashcheniya k chlenu ob容dineniya v strukture (ili naoborot) sovershenno identichna toj, kotoraya ispol'zuetsya vo vlozhennyh strukturah. naprimer, v massive struktur, opredelennym sleduyushchim obrazom STRUCT \( CHAR *NAME; INT FLAGS; INT UTYPE; UNION \( INT IVAL; FLOAT FVAL; CHAR *PVAL; \) UVAL; \) SYMTAB[NSYM]; na peremennuyu IVAL mozhno soslat'sya kak SYMTAB[I].UVAL.IVAL a na pervyj simvol stroki PVAL kak *SYMTAB[I].UVAL.PVAL V sushchnosti ob容dinenie yavlyaetsya strukturoj, v kotoroj vse chleny imeyut nulevoe smeshchenie. Sama struktura dostatochno ve- lika, chtoby hranit' "samyj shirokij" chlen, i vyravnivanie prigodno dlya vseh tipov, vhodyashchih v ob容dinenie. Kak i v sluchae struktur, edinstvennymi operaciyami, kotorye v nastoya- shchee vremya mozhno provodit' s ob容dineniyami, yavlyayutsya dostup k chlenu i izvlechenie adresa; ob容dineniya ne mogut byt' prisvo- eny, peredany funkciyam ili vozvrashcheny imi. ukazateli ob容di- nenij mozhno ispol'zovat' v tochno takoj zhe manere, kak i uka- zateli struktur. Programma raspredeleniya pamyati, privodimaya v glave 8 , pokazyvaet, kak mozhno ispol'zovat' ob容dinenie, chtoby sde- lat' nekotoruyu peremennuyu vyrovnennoj po opredelennomu vidu granicy pamyati. 6.9. Opredelenie tipa V yazyke "C" predusmotrena vozmozhnost', nazyvaemaya TYPEDEF dlya vvedeniya novyh imen dlya tipov dannyh. Naprimer, opisanie TYPEDEF INT LENGTH; delaet imya LENGTH sinonimom dlya INT. "Tip" LENGTH mozhet byt' ispol'zovan v opisaniyah, perevodov tipov i t.d. Tochno takim zhe obrazom, kak i tip INT: LENGTH LEN, MAXLEN; LENGTH *LENGTHS[]; Analogichno opisaniyu TYPEDEF CHAR *STRING; delaet STRING sinonimom dlya CHAR*, to est' dlya ukazatelya na simvoly, chto zatem mozhno ispol'zovat' v opisaniyah vida STRING P, LINEPTR[LINES], ALLOC(); Obratite vnimanie, chto ob座avlyaemyj v konstrukcii TYPEDEF tip poyavlyaetsya v pozicii imeni peremennoj, a ne srazu za slovom TYPEDEF. Sintaksicheski konstrukciya TYPEDEF podobna opisaniyam klassa pamyati EXTERN, STATIC i t. D. my takzhe is- pol'zovali propisnye bukvy, chtoby yasnee vydelit' imena. V kachestve bolee slozhnogo primera my ispol'zuem konst- rukciyu TYPEDEF dlya opisaniya uzlov dereva, rassmotrennyh ra- nee v etoj glave: TYPEDEF STRUCT TNODE \( /* THE BASIC NODE */ CHAR *WORD; /* POINTS TO THE TEXT */ INT COUNT; /* NUMBER OF OCCURRENCES */ STRUCT TNODE *LEFT; /* LEFT CHILD */ STRUCT TNODE *RIGHT; /* RIGHT CHILD */ \) TREENODE, *TREEPTR; V rezul'tate poluchaem dva novyh klyuchevyh slova: TREENODE (struktura) i TREEPTR (ukazatel' na strukturu). Togda funk- ciyu TALLOC mozhno zapisat' v vide TREEPTR TALLOC() \( CHAR *ALLOC(); RETURN((TREEPTR) ALLOC(SIZEOF(TREENODE))); \) Neobhodimo podcherknut', chto opisanie TYPEDEF ne privodit k sozdaniyu novogo v kakom-libo smysle tipa; ono tol'ko do- bavlyaet novoe imya dlya nekotorogo sushchestvuyushchego tipa. pri etom ne voznikaet i nikakoj novoj semantiki: opisannye takim sposobom peremennye obladayut tochno temi zhe svojstvami, chto i peremennye, opisannye yavnym obrazom. Po sushchestvu konstrukciya TYPEDEF shodna s #DEFINE za isklyucheniem togo, chto ona inter- pretiruetsya kompilyatorom i potomu mozhet osushchestvlyat' podsta- novki teksta, kotorye vyhodyat za predely vozmozhnostej mak- roprocessora yazyka "C". Naprimer, TYPEDEF INT (*PFI) (); sozdaet tip PFI dlya "ukazatelya funkcii, vozvrashchayushchej znache- nie tipa INT", kotoryj zatem mozhno bylo by ispol'zovat' v programme sortirovki iz glavy 5 v kontekste vida PFI STRCMP, NUMCMP, SWAP; Imeyutsya dve osnovnye prichiny primeneniya opisanij TYPEDEF. Pervaya prichina svyazana s parametrizaciej programmy, chtoby oblegchit' reshenie problemy perenosimosti. Esli dlya ti- pov dannyh, kotorye mogut byt' mashinno-zavisimymi, ispol'zo- vat' opisanie TYPEDEF, to pri perenose programmy na druguyu mashinu pridetsya izmenit' tol'ko eti opisaniya. Odna iz tipich- nyh situacij sostoit v ispol'zovanii opredelyaemyh s pomoshch'yu TYPEDEF imen dlya razlichnyh celyh velichin i v posleduyushchem podhodyashchem vybore tipov SHORT, INT i LONG dlya kazhdoj imeyu- shchejsya mashiny. Vtoroe naznachenie TYPEDEF sostoit v obespechenii luchshej doku- mentacii dlya programmy - tip s imenem TREEPTR mozhet okazat'- sya bolee udobnym dlya vospriyatiya, chem tip, kotoryj opisan tol'ko kak ukazatel' slozhnoj struktury. I nakonec, vsegda sushchestvuet veroyatnost', chto v budushchem kom- pilyator ili nekotoraya drugaya programma, takaya kak LINT, smo- zhet ispol'zovat' soderzhashchuyusya v opisaniyah TYPEDEF informaciyu dlya provedeniya nekotoroj dopolnitel'noj proverki programmy.  * 7. Vvod i vyvod *  Sredstva vvoda/vyvoda ne yavlyayutsya sostavnoj chast'yu yazyka "s", tak chto my ne vydelyali ih v nashem predydushchem izlozhenii. Odnako real'nye programmy vzaimodejstvuyut so svoej okruzhayu- shchej sredoj gorazdo bolee slozhnym obrazom, chem my videli do sih por. V etoj glave budet opisana "standartnaya biblioteka vvoda/vyvoda", to est' nabor funkcij, razrabotannyh dlya obespecheniya standartnoj sistemy vvoda/vyvoda dlya "s"- prog- ramm. |ti funkcii prednaznacheny dlya udobstva programmnogo interfejsa, i vse zhe otrazhayut tol'ko te operacii, kotorye mogut byt' obespecheny na bol'shinstve sovremennyh operacion- nyh sistem. Procedury dostatochno effektivny dlya togo, chtoby pol'zovateli redko chuvstvovali neobhodimost' obojti ih "radi effektivnosti", kak by ni byla vazhna konkretnaya zadacha. I, nakonec, eti procedury zadumany byt' "perenosimymi" v tom smysle, chto oni dolzhny sushchestvovat' v sovmestimom vide na lyuboj sisteme, gde imeetsya yazyk "s", i chto programmy, koto- rye ogranichivayut svoi vzaimodejstviya s sistemoj vozmozhnostya- mi, predostavlyaemymi standartnoj bibliotekoj, mozhno budet perenosit' s odnoj sistemy na druguyu po sushchestvu bez izmene- nij. My zdes' ne budem pytat'sya opisat' vsyu biblioteku vvo- da/vyvoda; my bolee zainteresovany v tom, chtoby prodemonst- rirovat' sushchnost' napisaniya "s"-programm, kotorye vzaimodej- stvuyut so svoej operacionnoj sredoj. 7.1. Obrashchenie k standartnoj biblioteke Kazhdyj ishodnyj fajl, kotoryj obrashchaetsya k funkcii iz standartnoj biblioteki, dolzhen vblizi nachala soderzhat' stro- ku #INCLUDE <STDIO.H> v fajle STDIO.H opredelyayutsya nekotorye makrosy i peremennye, ispol'zuemye bibliotekoj vvoda/vyvoda. Ispol'zovanie uglovyh skobok vmesto obychnyh dvojnyh kavychek - ukazanie kompilyatoru iskat' etot fajl v spravochnike, soderzhashchem zagolovki stan- dartnoj informacii (na sisteme UNIX obychno LUSRLINELUDE). Krome togo, pri zagruzke programmy mozhet okazat'sya neob- hodimym ukazat' biblioteku yavno; na sisteme PDP-11 UNIX, naprimer, komanda kompilyacii programmy imela by vid: CC ishodnye fajly i t.d. -LS gde -LS ukazyvaet na zagruzku iz standartnoj biblioteki. 7.2. Standartnyj vvod i vyvod - funkcii GETCHAR i PUTCHAR Samyj prostoj mehanizm vvoda zaklyuchaetsya v chtenii po od- nomu simvolu za raz iz "standartnogo vvoda", obychno s termi- nala pol'zovatelya, s pomoshch'yu funkcii GETCHAR. Funkciya GETCHAR() pri kazhdom k nej obrashchenii vozvrashchaet sleduyushchij vvodimyj simvol. V bol'shinstve sred, kotorye podderzhivayut yazyk "s", terminal mozhet byt' zamenen nekotorym fajlom s po- moshch'yu oboznacheniya < : esli nekotoraya programma PROG ispol'- zuet funkciyu GETCHAR to komandnaya stroka PROG<INFILE privedet k tomu, chto PROG budet chitat' iz fajla INFILE, a ne s terminala. Pereklyuchenie vvoda delaetsya takim obrazom, chto sama programma PROG ne zamechaet izmeneniya; v chastnosti stro- ka"<INFILE" ne vklyuchaetsya v komandnuyu stroku argumentov v ARGV. Pereklyuchenie vvoda okazyvaetsya nezametnym i v tom slu- chae, kogda vyvod postupaet iz drugoj programmy posredstvom potochnogo (PIPE) mehanizma; komandnaya stroka OTHERPROG \! PROG progonyaet dve programmy, OTHERPROG i PROG, i organizuet tak, chto standartnym vvodom dlya PROG sluzhit standartnyj vyvod OTHERPROG. Funkciya GETCHAR vozvrashchaet znachenie EOF, kogda ona popa- daet na konec fajla, kakoj by vvod ona pri etom ne schityva- la. Standartnaya biblioteka polagaet simvolicheskuyu konstantu EOF ravnoj -1 (posredstvom #DEFINE v fajle STDIO.H), no pro- verki sleduet pisat' v terminah EOF, a ne -1, chtoby izbezhat' zavisimosti ot konkretnogo znacheniya. Vyvod mozhno osushchestvlyat' s pomoshch'yu funkcii PUTCHAR(C), pomeshchayushchej simvol 's' v "standartnyj vvod", kotoryj po umol- chaniyu yavlyaetsya terminalom. Vyvod mozhno napravit' v nekotoryj fajl s pomoshch'yu oboznacheniya > : esli PROG ispol'zuet PUTCHAR, to komandnaya stroka PROG>OUTFILE privedet k zapisi standartnogo vyvoda v fajl OUTFILE, a ne na terminal. Na sisteme UNIX mozhno takzhe ispol'zovat' potoch- nyj mehanizm. Stroka PROG \! ANOTHERPROG pomeshchaet standartnyj vyvod PROG v standartnyj vvod ANOTHERPROG. I opyat' PROG ne budet osvedomlena ob izmenenii napravleniya. Vyvod, osushchestvlyaemyj funkciej PRINTF, takzhe postupaet v standartnyj vyvod, i obrashcheniya k PUTCHAR i PRINTF mogut pe- remezhat'sya. Porazitel'noe kolichestvo programm chitaet tol'ko iz odno- go vhodnogo potoka i pishet tol'ko v odin vyhodnoj potok; dlya takih programm vvod i vyvod s pomoshch'yu funkcij GETCHAR, PUTCHAR i PRINTF mozhet okazat'sya vpolne adekvatnym i dlya na- chala opredelenno dostatochnym. |to osobenno spravedlivo tog- da, kogda imeetsya vozmozhnost' ukazaniya fajlov dlya vvoda i vyvoda i potochnyj mehanizm dlya svyazi vyvoda odnoj programmy s vvodom drugoj. Rassmotrim, naprimer, programmu LOWER, ko- toraya preobrazuet propisnye bukvy iz svoego vvoda v stroch- nye: #INCLUDE <STDIO.H> MAIN() /* CONVERT INPUT TO LOWER CASE */ \( INT C; WHILE ((C = GETCHAR()) != EOF) PUTCHAR(ISUPPER(C) ? TOLOWER(C) : C); \) "Funkcii" ISUPPER i TOLOWER na samom dele yavlyayutsya makrosa- mi, opredelennymi v STDIO.H . Makros ISUPPER proveryaet, yav- lyaetsya li ego argument bukvoj iz verhnego registra, i vozv- rashchaet nenulevoe znachenie, esli eto tak, i nul' v protivnom sluchae. Makros TOLOWER preobrazuet bukvu iz verhnego regist- ra v tu zhe bukvu nizhnego registra. Nezavisimo ot togo, kak eti funkcii realizovany na konkretnoj mashine, ih vneshnee po- vedenie sovershenno odinakovo, tak chto ispol'zuyushchie ih prog- rammy izbavleny ot znaniya simvol'nogo nabora. Esli trebuetsya preobrazovat' neskol'ko fajlov, to mozhno sobrat' eti fajly s pomoshch'yu programmy, podobnoj utilite CAT sistemy UNIX, CAT FILE1 FILE2 ... \! LOWER>OUTPUT i izbezhat' tem samym voprosa o tom, kak obratit'sya k etim fajlam iz programmy. (Programma CAT privoditsya pozzhe v etoj glave). Krome togo otmetim, chto v standartnoj biblioteke vvo- da/vyvoda "funkcii" GETCHAR i PUTCHAR na samom dele mogut byt' makrosami. |to pozvolyaet izbezhat' nakladnyh rashodov na obrashchenie k funkcii dlya obrabotki kazhdogo simvola. V glave 8 my prodemonstriruem, kak eto delaetsya. 7.3. Formatnyj vyvod - funkciya PRINTF Dve funkcii: PRINTF dlya vyvoda i SCANF dlya vvoda (sledu- yushchij razdel) pozvolyayut preobrazovyvat' chislennye velichiny v simvol'noe predstavlEnie i obratno. Oni takzhe pozvolyayut ge- nerirovat' i interpretirovat' formatnye stroki. My uzhe vsyudu v predydushchih glavah neformal'no ispol'zovali funkciyu PRINTF; zdes' privoditsya bolee polnoe i tochnoe opisanie. Funkciya PRINTF(CONTROL, ARG1, ARG2, ...) preobrazuet, opredelyaet format i pechataet svoi argumenty v standartnyj vyvod pod upravleniem stroki CONTROL. Upravlyayu- shchaya stroka soderzhit dva tipa ob容ktov: obychnye simvoly, ko- torye prosto kopiruyutsya v vyhodnoj potok, i specifikacii preobrazovanij, kazhdaya iz kotoryh vyzyvaet preobrazovanie i pechat' ocherednogo argumenta PRINTF. Kazhdaya specifikaciya preobrazovaniya nachinaetsya s simvola % i zakanchivaetsya simvolom preobrazovaniya. Mezhdu % i simvo- lom preobrazovaniya mogut nahodit'sya: - znak minus, kotoryj ukazyvaet o vyravnivanii preobrazovan- nogo argumenta po levomu krayu ego polya. - Stroka cifr, zadayushchaya minimal'nuyu shirinu polya. Preobrazo- vannoe chislo budet napechatano v pole po krajnej mere etoj shiriny, a esli neobhodimo, to i v bolee shirokom. Esli pre- obrazovannyj argument imeet men'she simvolov, chem ukazannaya shirina polya, to on budet dopolnen sleva (ili sprava, esli bylo ukazano vyravnivanie po levomu krayu)zapolnyayushchimi sim- volami do etoj shiriny. Zapolnyayushchim simvolom obychno yavlyaet- sya probel, a esli shirina polya ukazyvaetsya s lidiruyushchim nu- lem, to etim simvolom budet nul' (lidiruyushchij nul' v dannom sluchae ne oznachaet vos'merichnoj shiriny polya). - Tochka, kotoraya otdelyaet shirinu polya ot sleduyushchej stroki cifr. - Stroka cifr (tochnost'), kotoraya ukazyvaet maksimal'noe chislo simvolov stroki, kotorye dolzhny byt' napechatany, ili chislo pechataemyh sprava ot desyatichnoj tochki cifr dlya pere- mennyh tipa FLOAT ili DOUBLE. - Modifikator dliny L, kotoryj ukazyvaet, chto sootvetstvuyu- shchij element dannyh imeet tip LONG, a ne INT. Nizhe privodyatsya simvoly preobrazovaniya i ih smysl: D - argument preobrazuetsya k desyatichnomu vidu. O - Argument preobrazuetsya v bezznakovuyu vos'merichnuyu formu (bez lidiruyushchego nulya). X - Argument preobrazuetsya v bezznakovuyu shestnadcaterichnuyu formu (bez lidiruyushchih 0X). U - Argument preobrazuetsya v bezznakovuyu desyatichnuyu formu. C - Argument rassmatrivaetsya kak otdel'nyj simvol. S - Argument yavlyaetsya strokoj: simvoly stroki pechatayutsya do teh por, poka ne budet dostignut nulevoj simvol ili ne bu- det napechatano kolichestvo simvolov, ukazannoe v specifika- cii tochnosti. E - Argument, rassmatrivaemyj kak peremennaya tipa FLOAT ili DOUBLE, preobrazuetsya v desyatichnuyu formu v vide [-]M.NNNNNNE[+-]XX, gde dlina stroki iz N opredelyaetsya ukazannoj tochnost'yu. Tochnost' po umolchaniyu ravna 6. F - Argument, rassmatrivaemyj kak peremennaya tipa FLOAT ili DOUBLE, preobrazuetsya v desyatichnuyu formu v vide [-]MMM.NNNNN, gde dlina stroki iz N opredelyaetsya ukazannoj tochnost'yu. Tochnost' po umolchaniyu ravna 6. otmetim, chto eta tochnost' ne opredelyaet kolichestvo pechataemyh v formate F znachashchih cifr. G - Ispol'zuetsya ili format %E ili %F, kakoj koroche; nezna- chashchie nuli ne pechatayutsya. Esli idushchij za % simvol ne yavlyaetsya simvolom preobrazovaniya, to pechataetsya sam etot simvol; sledovatel'no,simvol % mozhno napechatat', ukazav %%. Bol'shinstvo iz formatnyh preobrazovanij ochevidno i bylo proillyustrirovano v predydushchih glavah. Edinstvennym isklyuche- niem yavlyaetsya to, kak tochnost' vzaimodejstvuet so strokami. Sleduyushchaya tablica demonstriruet vliyanie zadaniya razlichnyh specifikacij na pechat' "HELLO, WORLD" (12 simvolov). My po- mestili dvoetochiya vokrug kazhdogo polya dlya togo, chtoby vy mogli videt' ego protyazhennost'. :%10S: :HELLO, WORLD: :%10-S: :HELLO, WORLD: :%20S: : HELLO, WORLD: :%-20S: :HELLO, WORLD : :%20.10S: : HELLO, WOR: :%-20.10S: :HELLO, WOR : :%.10S: :HELLO, WOR: Predosterezhenie: PRINTF ispol'zuet svoj pervyj argument dlya opredeleniya chisla posleduyushchih argumentov i ih tipov. Es- li kolichestvo argumentov okazhetsya nedostatochnym ili oni bu- dut imet' nesootvetstvennye tipy, to vozniknet putanica i vy poluchite bessmyslennye rezul'taty. Uprazhnenie 7-1 -------------- Napishite programmu, kotoraya budet pechatat' razumnym ob- razom proizvol'nyj vvod. Kak minimum ona dolzhna pechatat' negraficheskie simvoly v vos'merichnom ili shestnadcaterichnom vide (v sootvetstvii s prinyatymi u vas obychayami) i sklady- vat' dlinnye stroki. 7.4. Formatnyj vvod - funkciya SCANF Osushchestvlyayushchaya vvod funkciya SCANF yavlyaetsya analogom PRINTF i pozvolyaet provodit' v obratnom napravlenii mnogie iz teh zhe samyh preobrazovanij. Funkciya SCANF(CONTROL, ARG1, ARG2, ...) chitaet simvoly iz standartnogo vvoda, interpretiruet ih v sootvetstvii s formatom, ukazannom v argumente CONTROL, i pomeshchaet rezul'taty v ostal'nye argumenty. Upravlyayushchij argu- ment opisyvaetsya nizhe; drugie argumenty, kazhdyj iz kotoryh dolzhen byt' ukazatelem, opredelyayut, kuda sleduet pomestit' sootvetstvuyushchim obrazom preobrazovannyj vvod. Upravlyayushchaya stroka obychno soderzhit specifikacii preobra- zovaniya, kotorye ispol'zuyutsya dlya neposredstvennoj interpre- tacii vhodnyh posledovatel'nostej. Upravlyayushchaya stroka mozhet soderzhat': - probely, tabulyacii ili simvoly novoj stroki ("simvoly pus- tyh promezhutkov"), kotorye ignoriruyutsya. - Obychnye simvoly (ne %), kotorye predpolagayutsya sovpadayushchi- mi so sleduyushchimi otlichnymi ot simvolov pustyh promezhutkov simvolami vhodnogo potoka. - Specifikacii preobrazovaniya, sostoyashchie iz simvola %, neo- byazatel'nogo simvola podavleniya prisvaivaniya *, neobyaza- tel'nogo chisla, zadayushchego maksimal'nuyu shirinu polya i sim- vola preobrazovaniya. Specifikaciya preobrazovaniya upravlyaet preobrazovaniem sleduyushchego polya vvoda. normal'no rezul'tat pomeshchaetsya v pe- remennuyu, kotoraya ukazyvaetsya sootvetstvuyushchim argumentom. Esli, odnako , s pomoshch'yu simvola * ukazano podavlenie pris- vaivaniya, to eto pole vvoda prosto propuskaetsya i nikakogo prisvaivaniya ne proizvoditsya. Pole vvoda opredelyaetsya kak stroka simvolov, kotorye otlichny ot simvolov prostyh prome- zhutkov; ono prodolzhaetsya libo do sleduyushchego simvola pustogo promezhutka, libo poka ne budet ischerpana shirina polya, esli ona ukazana. Otsyuda sleduet, chto pri poiske nuzhnogo ej vvo- da, funkciya SCANF budet peresekat' granicy strok, poskol'ku simvol novoj stroki vhodit v chislo pustyh promezhutkov. Simvol preobrazovaniya opredelyaet interpretaciyu polya vvo- da; soglasno trebovaniyam osnovannoj na vyzove po znacheniyu semantiki yazyka "s" sootvetstvuyushchij argument dolzhen byt' ukazatelem. Dopuskayutsya sleduyushchie simvoly preobrazovaniya: D - na vvode ozhidaetsya desyatichnoe celoe; sootvetstvuyushchij ar- gument dolzhen byt' ukazatelem na celoe. O - Na vvode ozhidaetsya vos'merichnoe celoe (s lidiruyushchim nu- lem ili bez nego); sootvetstvuyushchij argument dolzhen byt' ukazatelem na celoe. X - Na vvode ozhidaetsya shestnadcaterichnoe celoe (s lidiruyushchi- mi 0X ili bez nih); sootvetstvuyushchij argument dolzhen byt' ukazatelem na celoe. H - Na vvode ozhidaetsya celoe tipa SHORT; sootvetsvuyushchij ar- gument dolzhen byt' ukazatelem na celoe tipa SHORT. C - Ozhidaetsya otdel'nyj simvol; sootvetstvuyushchij argument dolzhen byt' ukazatelem na simvoly; sleduyushchij vvodimyj simvol pomeshchaetsya v ukazannoe mesto. Obychnyj propusk sim- volov pustyh promezhutkov v etom sluchae podavlyaetsya; dlya chteniya sleduyushchego simvola, kotoryj ne yavlyaetsya simvolom pustogo promezhutka, pol'zujtes' specifikaciej preobrazo- vaniya %1S. S - Ozhidaetsya simvol'naya stroka; sootvetstvuyushchij argument dolzhen byt' ukazatelem simvolov, kotoryj ukazyvaet na massiv simvolov, kotoryj dostatochno velik dlya prinyatiya stroki i dobavlyaemogo v konce simvola \0. F - Ozhidaetsya chislo s plavayushchej tochkoj; sootvetstvuyushchij ar- gument dolzhen byt' ukazatelem na peremennuyu tipa FLOAT. E - simvol preobrazovaniya E yavlyaetsya sinonimom dlya F. Format vvoda peremennoj tipa FLOAT vklyuchaet neobyazatel'nyj znak, stroku cifr, vozmozhno soderzhashchuyu desyatichnuyu tochku i neo- byazatel'noe pole eksponenty, sostoyashchee iz bukvy E, za ko- toroj sleduet celoe, vozmozhno imeyushchee znak. Pered simvolami preobrazovaniya D, O i X mozhet stoyat' L, kotoraya oznachaet , chto v spiske argumentov dolzhen nahodit'sya ukazatel' na peremennuyu tipa LONG, a ne tipa INT. Analogich- no, bukva L mozhet stoyat' pered simvolami preobrazovaniya E ili F, govorya o tom, chto v spiske argumentov dolzhen naho- dit'sya ukazatel' na peremennuyu tipa DOUBLE, a ne tipa FLOAT. Naprimer, obrashchenie INT I; FLOAT X; CHAR NAME[50]; SCANF("&D %F %S", &I, &X, NAME); so strokoj na vvode 25 54.32E-1 THOMPSON privodit k prisvaivaniyu I znacheniya 25,X - znacheniya 5.432 i NAME - stroki "THOMPSON", nadlezhashchim obrazom zakonchennoj simvolom \ 0. eti tri polya vvoda mozhno razdelit' stol'kimi probelami, tabulyaciyami i simvolami novyh strok, skol'ko vy pozhelaete. Obrashchenie INT I; FLOAT X; CHAR NAME[50]; SCANF("%2D %F %*D %2S", &I, &X, NAME); s vvodom 56789 0123 45A72 prisvoit I znachenie 56, X - 789.0, propustit 0123 i pomestit v NAME stroku "45". pri sleduyushchem obrashchenii k lyuboj procedu- re vvoda rassmotrenie nachnetsya s bukvy A. V etih dvuh prime- rah NAME yavlyaetsya ukazatelem i, sledovatel'no, pered nim ne nuzhno pomeshchat' znak &. V kachestve drugogo primera perepishem teper' elementarnyj kal'kulyator iz glavy 4, ispol'zuya dlya preobrazovaniya vvoda funkciyu SCANF: #INCLUDE <STDIO.H> MAIN() /* RUDIMENTARY DESK CALCULATOR */ \( DOUBLE SUM, V; SUM =0; WHILE (SCANF("%LF", &V) !=EOF) PRINTF("\T%.2F\N", SUM += V); \) vypolnenie funkcii SCANF zakanchivaetsya libo togda, kogda ona ischerpyvaet svoyu upravlyayushchuyu stroku, libo kogda nekotoryj element vvoda ne sovpadaet s upravlyayushchej specifikaciej. V kachestve svoego znacheniya ona vozvrashchaet chislo pravil'no sov- padayushchih i prisvoennyh elementov vvoda. |to chislo mozhet byt' ispol'zovano dlya opredeleniya kolichestva najdennyh elementov vvoda. pri vyhode na konec fajla vozvrashchaetsya EOF; podcherk- nem, chto eto znachenie otlichno ot 0, chto sleduyushchij vvodimyj simvol ne udovletvoryaet pervoj specifikacii v upravlyayushchej stroke. Pri sleduyushchem obrashchenii k SCANF poisk vozobnovlyaetsya neposredstvenno za poslednim vvedennym simvolom. Zaklyuchitel'noe predosterezhenie: argumenty funkcii SCANF dolzhny byt' ukazatelyami. Nesomnenno naibolee rasprostranen- naya oshibka sostoit v napisanii SCANF("%D", N); vmesto SCANF("%D", &N); 7.5. Formatnoe preobrazovanie v pamyati Ot funkcii SCANF i PRINTF proishodyat funkcii SSCANF i SPRINTF, kotorye osushchestvlyayut analogichnye preobrazovaniya, no operiruyut so strokoj, a ne s fajlom. Obrashcheniya k etim funk- ciyam imeyut vid: SPRINTF(STRING, CONTROL, ARG1, ARG2, ...) SSCANF(STRING, CONTROL, ARG1, ARG2, ...) Kak i ran'she , funkciya SPRINTF preobrazuet svoi argumenty ARG1, ARG2 i t.d. V sootvetstvii s formatom, ukazannym v CONTROL, no pomeshchaet rezul'taty v STRING, a ne v standartnyj vyvod. KOnechno, stroka STRING dolzhna byt' dostatochno velika, chtoby prinyat' rezul'tat. Naprimer, esli NAME - eto simvol'- nyj massiv, a N - celoe, to SPRINTF(NAME, "TEMP%D", N); sozdaet v NAME stroku vida TEMPNNN, gde NNN - znachenie N. Funkciya SSCANF vypolnyaet obratnye preobrazovaniya - ona prosmatrivaet stroku STRING v sootvetstvii s formatom v ar- gumente CONTROL i pomeshchaet rezul'tiruyushchie znacheniya v argu- menty ARG1, ARG2 i t.d.eti argumenty dolzhny byt' ukazatelya- mi. V rezul'tate obrashcheniya SSCANF(NAME, "TEMP%D", &N); peremennaya N poluchaet znachenie stroki cifr, sleduyushchih za TEMP v NAME. Uprazhnenie 7-2 -------------- Perepishite nastol'nyj kal'kulyator iz glavy 4, ispol'zuya dlya vvoda i preobrazovaniya chisel SCANF i/ili SSCANF. 7.6. Dostup k fajlam Vse do sih por napisannye programmy chitali iz standart- nogo vvoda i pisali v standartnyj vyvod, otnositel'no koto- ryh my predpolagali, chto oni magicheskim obrazom predostavle- ny programme mestnoj operacionnoj sistemoj. Sleduyushchim shagom v voprose vvoda-vyvoda yavlyaetsya napisa- nie programmy, rabotayushchej s fajlom, kotoryj ne svyazan zara- nee s programmoj. odnoj iz programm, kotoraya yavno demonstri- ruet potrebnost' v takih operaciyah, yavlyaetsya CAT, kotoraya ob容dinyaet nabor iz neskol'kih imenovannyh fajlov v standar- tnyj vyvod. Programma CAT ispol'zuetsya dlya vyvoda fajlov na terminal i v kachestve universal'nogo sborshchika vvoda dlya programm, kotorye ne imeyut vozmozhnosti obrashchat'sya k fajlam po imeni. Naprimer, komanda CAT X.C.Y.C pechataet soderzhimoe fajlov X.C i Y.C v standartnyj vyvod. Vopros sostoit v tom, kak organizovat' chtenie iz imeno- vannyh fajlov, t.e., kak svyazat' vneshnie imena, kotorymi myslit pol'zovatel', s fakticheski chitayushchimi dannye operato- rami. |ti pravila prosty. Prezhde chem mozhno schityvat' iz neko- torogo fajla ili zapisyvat' v nego, etot fajl dolzhen byt' otkryt s pomoshch'yu funkcii FOPEN iz standartnoj biblioteki. funkciya FOPEN beret vneshnee imya (podobnoe X.C ili Y.C), pro- vodit nekotorye obsluzhivayushchie dejstviya i peregovory s opera- cionnoj sistemoj (detali kotoryh ne dolzhny nas kasat'sya) i vozvrashchaet vnutrennee imya, kotoroe dolzhno ispol'zovat'sya pri posleduyushchih chteniyah iz fajla ili zapisyah v nego. |to vnutrennee imya, nazyvaemoe "ukazatelem fajla", fak- ticheski yavlyaetsya ukazatelem struktury, kotoraya soderzhit in- formaciyu o fajle, takuyu kak mesto razmeshcheniya bufera, tekushchaya poziciya simvola v bufere, proishodit li chtenie iz fajla ili zapis' v nego i tomu podobnoe. Pol'zovateli ne obyazany znat' eti detali, potomu chto sredi opredelenij dlya standartnogo vvoda-vyvoda, poluchaemyh iz fajla STDIO.H, soderzhitsya opre- delenie struktury s imenem FILE. Edinstvennoe neobhodimoe dlya ukazatelya fajla opisanie demonstriruetsya primerom: FILE *FOPEN(), *FP; Zdes' govoritsya, chto FP yavlyaetsya ukazatelem na FILE i FOPEN vozvrashchaet ukazatel' na FILE. Obratite vnimanie, chto FILE yavlyaetsya imenem tipa, podobnym INT, a ne yarlyku struk- tury; eto realizovano kak TYPEDEF. (Podrobnosti togo, kak vse eto rabotaet na sisteme UNIX, privedeny v glave 8). Fakticheskoe obrashchenie k funkcii FOPEN v programme imeet vid: FP=FOPEN(NAME,MODE); Pervym argumentom funkcii FOPEN yavlyaetsya "imya" fajla, koto- roe zadaetsya v vide simvol'noj stroki. Vtoroj argument MODE ("rezhim") takzhe yavlyaetsya simvol'noj strokoj, kotoraya ukazy- vaet, kak etot fajl budet ispol'zovat'sya. Dopustimymi rezhi- mami yavlyayutsya: chtenie ("R"), zapis' ("W") i dobavlenie ("A"). Esli vy otkroete fajl, kotoryj eshche ne sushchetvuet, dlya za- pisi ili dobavleniya, to takoj fajl budet sozdan (esli eto vozmozhno). Otkrytie sushchestvuyushchego fajla na zapis' privodit k otbrasyvaniyu ego starogo soderzhimogo. Popytka chteniya nesu- shchestvuyushchego fajla yavlyaetsya oshchibkoj. Oshibki mogut byt' obus- lovleny i drugimi prichinami (naprimer, popytkoj chteniya iz fajla, ne imeya na to razresheniya). Pri nalichii kakoj-libo oshibki funkciya vozvrashchaet nulevoe znachenie ukazatelya NULL (kotoroe dlya udobstva takzhe opredelyaetsya v fajle STDIO.H). Drugoj neobhodimoj veshch'yu yavlyaetsya sposob chteniya ili za- pisi, esli fajl uzhe otkryt. Zdes' imeetsya neskol'ko vozmozh- nostej, iz kotoryh GETC i PUTC yavlyayutsya prostejshimi.funkciya GETC vozvrashchaet sleduyushchij simvol iz fajla; ej neobhodim uka- zatel' fajla, chtoby znat', iz kakogo fajla chitat'. Takim ob- razom, C=GETC(FP) pomeshchaet v "C" sleduyushchij simvol iz fajla, ukazannogo posred- stvom FP, i EOF, esli dostignut konec fajla. Funkciya PUTC, yavlyayushchayasya obrashcheniem k funkcii GETC, PUTC(C,FP) pomeshchaet simvol "C" v fajl FP i vozvrashchaet "C". Podobno fun- kciyam GETCHAR i PUTCHAR, GETC i PUTC mogut byt' makrosami, a ne funkciyami. Pri zapuske programmy avtomaticheski otkryvayutsya tri faj- la, kotorye snabzheny opredelennymi ukazatelyami fajlov. |timi fajlami yavlyayutsya standartnyj vvod, standartnyj vyvod i stan- dartnyj vyvod oshibok; sootvetstvuyushchie ukazateli fajlov nazy- vayutsya STDIN, STDOUT i STDERR. Obychno vse eti ukazateli svya- zany s terminalom, no STDIN i STDOUT mogut byt' perenaprav- leny na fajly ili v potok (PIPE), kak opisyvalos' v razdele 7.2. Funkcii GETCHAR i PUTCHAR mogut byt' opredeleny v termi- nalah GETC, PUTC, STDIN i STDOUT sleduyushchim obrazom: #DEFINE GETCHAR() GETC(STDIN) #DEFINE PUTCHAR(C) PUTC(C, STDOUT) Pri rabote s fajlami dlya formatnogo vvoda i vyvoda mozhno is- pol'zovat' funkcii FSCANF i FPRINTF. Oni identichny funkciyam SCANF i PRINTF, za isklyucheniem togo, chto pervym argumentom yavlyaetsya ukazatel' fajla, opredelyayushchij tot fajl, kotoryj bu- det chitat'sya ili kuda budet vestis' zapis'; upravlyayushchaya stroka budet vtorym argumentom. Pokonchiv s predvaritel'nymi zamechaniyami, my teper' v sostoyanii napisat' programmu CAT dlya konkatenacii fajlov. Ispol'zuemaya zdes' osnovnaya shema okazyvaetsya udobnoj vo mnogih programmah: esli imeyutsya argumenty v komandnoj stro- ke, to oni obrabatyvayutsya posledovatel'no. Esli takie argu- menty otsutstvuyut, to obrabatyvaetsya standartnyj vvod. |to pozvolyaet ispol'zovat' programmu kak samostoyatel'no, tak i kak chast' bol'shej zadachi. #INCLUDE <STDIO.H> MAIN(ARGC, ARGV) /*CAT: CONCATENATE FILES*/ INT ARGC; CHAR *ARGV[]; \( FILE *FP, *FOPEN(); IF(ARGC==1) /*NO ARGS; COPY STANDARD INPUT*/ FILECOPY(STDIN); ELSE WHILE (--ARGC > 0) IF ((FP=FOPEN(*++ARGV,"R"))==NULL) \( PRINTF("CAT:CAN'T OPEN %\N",*ARGV); BREAK; \) ELSE \( FILECOPY(FP); FCLOSE(FP); \) \) FILECOPY(FP) /*COPY FILE FP TO STANDARD OUTPUT*/ FILE *FP; \( INT C; WHILE ((C=GETC(FP)) !=EOF) PUTC(C, STDOUT); \) Ukazateli fajlov STDIN i STDOUT zaranee opredeleny v biblio- teke vvoda-vyvoda kak standartnyj vvod i standartnyj vyvod; oni mogut byt' ispol'zovany v lyubom meste, gde mozhno ispol'- zovat' ob容kt tipa FILE*.oni odnako yavlyayutsya konstantami, a ne peremennymi, tak chto ne pytajtes' im chto-libo prisvai- vat'. Funkciya FCLOSE yavlyaetsya obratnoj po otnosheniyu k FOPEN; ona razryvaet svyaz' mezhdu ukazatelem fajla i vneshnim imenem, ustanovlennuyu funkciej FOPEN, i vysvobozhdaet ukazatel' fajla dlya drugogo fajla.bol'shinstvo operacionnyh sistem imeyut ne- kotorye ogranicheniya na chislo odnovremenno otkrytyh fajlov, kotorymi mozhet rasporyazhat'sya programma. Poetomu, to kak my postupili v CAT, osvobodiv ne nuzhnye nam bolee ob容kty, yav- lyaetsya horoshej ideej. Imeetsya i drugaya prichina dlya primene- niya funkcii FCLOSE k vyhodnomu fajlu - ona vyzyvaet vydachu informacii iz bufera, v kotorom PUTC sobiraet vyvod. (Pri normal'nom zavershenii raboty programmy funkciya FCLOSE vyzy- vaetsya avtomaticheski dlya kazhdogo otkrytogo fajla). 7.7. Obrabotka oshibok - STDERR i EXIT Obrabotka oshibok v CAT neideal'na. Neudobstvo zaklyuchaet- sya v tom, chto esli odin iz fajlov po nekotoroj prichine oka- zyvaetsya nedostupnym, diagnosticheskoe soobshchenie ob etom pe- chataetsya v konce ob容dinennogo vyvoda. |to priemlemo, esli vyvod postupaet na terminal, no ne goditsya, esli vyvod pos- tupaet v nekotoryj fajl ili cherez potochnyj (PIPELINE) meha- nizm v druguyu programmu. CHtoby luchshe obrabatyvat' takuyu situaciyu, k programme tochno takim zhe obrazom, kak STDIN i STDOUT, prisoedinyaetsya vtoroj vyhodnoj fajl, nazyvaemyj STDERR. Esli eto voobshche vozmozhno, vyvod, zapisannyj v fajle STDERR, poyavlyaetsya na terminale pol'zovatelya, dazhe esli standartnyj vyvod naprav- lyaetsya v drugoe mesto. Davajte peredelaem programmu CAT takim obrazom, chtoby soobshcheniya ob oshibkah pisalis' v standartnyj fajl oshibok. "INCLUDE <STDIO.H> MAIN(ARGC,ARGV) /*CAT: CONCATENATE FILES*/ INT ARGC; CHAR *ARGV[]; \( FILE *FP, *FOPEN(); IF(ARGC==1) /*NO ARGS; COPY STANDARD INPUT*/ FILECOPY(STDIN); ELSE WHILE (--ARGC > 0) IF((FP=FOPEN(*++ARGV,"R#))==NULL) \( PRINTF(STDERR, "CAT: CAN'T OPEN,%S\N", ARGV); EXIT(1); \) ELSE \( FILECOPY(FP); \) EXIT(0); \) Programma soobshchaet ob oshibkah dvumya sposobami. Diagnostiches- koe soobshchenie, vydavaemoe funkciej FPRINTF, postupaet v STDERR i, takim obrazom, okazyvaetsya na terminale pol'zova- telya, a ne ischezaet v potoke (PIPELINE) ili v vyhodnom faj- le. Programma takzhe ispol'zuet funkciyu EXIT iz standartnoj biblioteki, obrashchenie k kotoroj vyzyvaet zavershenie vypolne- niya programmy. Argument funkcii EXIT dostupen lyuboj program- me, obrashchayushchejsya k dannoj funkcii, tak chto uspeshnoe ili neu- dachnoe zavershenie dannoj programmy mozhet byt' provereno dru- goj programmoj, ispol'zuyushchej etu v kachestve podzadachi. Po soglasheniyu velichina 0 v kachetsve vozvrashchaemogo znacheniya svi- detel'stvuet o tom, chto vse v poryadke, a razlichnye nenulevye znacheniya yavlyayutsya priznakami normal'nyh situacij. Funkciya EXIT vyzyvaet funkciyu FCLOSE dlya kazhdogo otkry- togo vyhodnogo fajla, s tem chtoby vyvesti vsyu pomeshchennuyu v bufery vyhodnuyu informaciyu, a zatem vyzyvaet funkciyu _EXIT. Funkciya _EXIT privodit k nemedlennomu zaversheniyu bez ochistki kakih-libo buferov; konechno, pri zhelanii k etoj funkcii mozh- no obratit'sya neposredstvenno. 7.8. Vvod i vyvod strok Standartnaya biblioteka soderzhit funkciyu FGETS, sovershen- no analogichnuyu funkcii GETLINE, kotoruyu my ispol'zovali na vsem protyazhenii knigi. V rezul'tate obrashcheniya FGETS(LINE, MAXLINE, FP) sleduyushchaya stroka vvoda (vklyuchaya simvol novoj stroki) schity- vaetsya iz fajla FP v simvol'nyj massiv LINE; samoe bol'shoe MAXLINE_1 simvol budet prochitan. Rezul'tiruyushchaya stroka za- kanchivaetsya simvolom \ 0. Normal'no funkciya FGETS vozvrashchaet LINE; v konce fajla ona vozvrashchaet NULL. (Nasha funkciya GETLINE vozvrashchaet dlinu stroki, a pri vyhode na konec fajla - nul'). Prednaznachennaya dlya vyvoda funkciya FPUTS zapisyvaet stroku (kotoraya ne obyazana soderzhat' simvol novoj stroki) v fajl: FPUTS(LINE, FP) CHtoby pokazat', chto v funkciyah tipa FGETS i FPUTS net nichego tainstvennogo, my privodim ih nizhe, skopirovannymi neposredstvenno iz standartnoj biblioteki vvoda-vyvoda: #INCLUDE <STDIO.H> CHAR *FGETS(S,N,IOP) /*GET AT MOST N CHARS FROM IOP*/ CHAR *S; INT N; REGISTER FILE *IOP; \( REGISTER INT C; REGISTER CHAR *CS; CS = S; WHILE(--N>0&&(C=GETC(IOP)) !=EOF) IF ((*CS++ = C)=='\N') BREAK; *CS = '\0'; RETURN((C==EOF && CS==S) 7 NULL : S); \) FPUTS(S,IOP) /*PUT STRING S ON FILS IOP*/ REGISTER CHAR *S; REGISTER FILE *IOP; \( REGISTER INT C; WHILE (C = *S++) PUTC(C,IOP); \) Uprazhnenie 7-3 --------------- Napishite programmu sravneniya dvuh fajlov, kotoraya budet pechatat' pervuyu stroku i poziciyu simvola, gde oni razlichayut- sya. Uprazhnenie 7-4 --------------- Peredelajte programmu poiska zadannoj kombinacii simvo- lov iz glavy 5 takim obrazom, chtoby v kachestve vvoda ispol'- zovalsya nabor imenovannyh fajlov ili, esli nikakie fajly ne ukazany kak argumenty, standartnyj vvod. Sleduet li pechatat' imya fajla pri nahozhdenii podhodyashchej stroki? Uprazhnenie 7-5 -------------- Napishite programmu pechati nabora fajlov, kotoraya nachina- et kazhdyj novyj fajl s novoj stranicy i pechataet dlya kazhdogo fajla zagolovok i schetchik tekushchih stranic. 7.9. Neskol'ko raznoobraznyh funkcij Standartnaya biblioteka predostavlyaet mnozhestvo raznoob- raznyh funkcij, nekotorye iz kotoryh okazyvayutsya osobenno poleznymi. My uzhe upominali funkcii dlya raboty so strokami: STRLEN, STRCPY, STRCAT i STRCMP. Vot nekotorye drugie. 7.9.1. Proverka vida simvolov i preobrazovaniya Nekotorye makrosy vypolnyayut proverku simvolov i preobra- zovaniya: SALPHA(C) ne 0, esli "C" alfavitnyj simvol, 0 - esli net. SUPPER(C) Ne 0, esli "C" bukva verhnego registra, 0 - esli net. SLOWER(C) Ne 0, esli "C" bukva nizhnego registra, 0 - esli net. SDIGIT(C) Ne 0, esli "C" cifra, 0 - esli net. SSPACL(C) Ne 0, esli "C" probel, tabulyaciya ili novaya stroka, 0 - esli net. OUPPER(C) Preobrazuet "C" v bukvu verhnego registra. OLOWER(C) Preobrazuet "C" v bukvu nizhnego registra. 7.9.2. Funkciya UNGETC Standartnaya biblioteka soderzhit dovol'no ogranichennuyu versiyu funkcii UNGETCH, napisannoj nami v glave 4; ona nazy- vaetsya UNGETC. V rezul'tate obrashcheniya UNGETC(C,FP) simvol "C" vozvrashchaetsya v fajl FP. Pozvolyaetsya vozvrashchat' v kazhdyj fajl tol'ko odin simvol. Funkciya UNGETC mozhet byt' ispol'zovana v lyuboj iz funkcij vvoda i s makrosami tipa SCANF, GETC ili GETCHAR. 7.9.3. Obrashchenie k sisteme Funkciya SYSTEM(S) vypolnyaet komandu, soderzhashchuyusya v sim- vol'noj stroke S, i zatem vozobnovlyaet vypolnenie tekushchej programmy. Soderzhimoe S sil'no zavisit ot ispol'zuemoj ope- racionnoj sistemy. V kachestve trivial'nogo primera, ukazhem, chto na sisteme UNIX stroka SYSTEM("DATE"); privodit k vypolneniyu programmy DATE, kotoraya pechataet datu i vremya dnya. 7.9.4. Upravlenie pamyat'yu Funkciya CALLOC ves'ma shodna s funkciej ALLOC, ispol'zo- vannoj nami v predydushchih glavah. V rezul'tate obrashcheniya CALLOC(N, SIZEOF(OBJCCT)) vozvrashchaetsya libo ukazatel' prostranstva, dostatochnogo dlya razmeshcheniya N ob容ktov ukazannogo razmera, libo NULL, esli zapros ne mozhet byt' udvoletvoren. Otvodimaya pamyat' inicia- liziruetsya nulevymi znacheniyami. Ukazatel' obladaet nuzhnym dlya rassmatrivaemyh ob容ktov vyravnivaniem, no emu sleduet pripisyvat' sootvetstvuyushchij tip, kak v CHAR *CALLOC(); INT *IP; IP=(INT*) CALLOC(N,SIZEOF(INT)); Funkciya CFREE(P) osvobozhdaet prostranstvo, na kotoroe ukazyvaet "P", prichem ukazatel' "P" pevonachal'no dolzhen byt' poluchen v rezul'tate obrashcheniya k CALLOC. Zdes' net nikakih ogranichenij na poryadok osvobozhdeniya prostranstva, no budet nepriyatnejshej oshibkoj osvobodit' chto-nibud', chto ne bylo po- lucheno obrashcheniem k CALLOC. Realizaciya programmy raspredeleniya pamyati, podobnoj CALLOC, v kotoroj razmeshchennye bloki mogut osvobozhdat'sya v proizvol'nom poryadke, prodemonstrirovana v glave 8.  * 8. Interfejs sistemy UNIX *  Material etoj glavy otnositsya k interfejsu mezhdu s-prog- rammami i operacionnoj sistemoj UNIX. Tak kak bol'shinstvo pol'zovatelej yazyka "C" rabotayut na sisteme UNIX, eta glava okazhetsya poleznoj dlya bol'shinstva chitatelej. dazhe esli vy ispol'zuete s-kompilyator na drugoj mashine, izuchenie privodi- myh zdes' primerov dolzhno pomoch' vam glubzhe proniknut' v me- tody programmirovaniya na yazyke "C". |ta glava delitsya na tri osnovnye chasti: vvod/vyvod, sistema fajlov i raspredelenie pamyati. Pervye dve chasti predpolagayut nebol'shoe znakomstvo s vneshnimi harakteristika- mi sistemy UNIX. V glave 7 my imeli delo s sistemnym interfejsom, kotoryj odinakov dlya vsego mnogoobraziya operacionnyh sistem. Na kazh- doj konkretnoj sisteme funkcii standartnoj biblioteki dolzhny byt' napisany v terminah vvoda-vyvoda, dostupnyh na dannoj mashine. V sleduyushchih neskol'kih razdelah my opishem osnovnuyu sistemu svyazannyh s vvodom i vyvodom tochek vhoda operacion- noj sistemy UNIX i proillyustriruem, kak s ih pomoshch'yu mogut byt' realizovany razlichnye chasti standartnoj biblioteki. 8.1. Deskriptory fajlov V operacionnoj sisteme UNIX ves' vvod i vyvod osushchestv- lyaetsya posredstvom chteniya fajlov ili ih zapisi, potomu chto vse periferijnye ustrojstva, vklyuchaya dazhe terminal pol'zova- telya, yavlyayutsya fajlami