Kezdőlap

|

Mi a kreditvadasz.hu Egy felsőoktatási közösségi oldal amely segít kapcsolatot tartani a hallgatók között, így segítséget nyújt a sikeres tanulmányokhoz...

C programozási feladatgyűjtemény - Poppe András – Kocsis Tamás

Országok listájaHungaryDebreceni EgyetemInformatikai KarProgramtervező informatikusBevezetés Az InformatikábaGyakorló FeladatokC programozási feladatgyűjtemény - Poppe András – Kocsis Tamás

2009.01.06 15:09:07
(10)
Szerző: Simintoo
Cimkék: c nyelv, programozás, feladatgyűjtemény, poppe andrás, kocsis tamás


Az alábbi szöveg egy formázás és képek nélküli előnézete a dokumentumnak. A tökéletes megjelenítéshez jelentkezz be, majd töltsd le a dokumentumot.

C programoz´si a feladatgyjtem´ny u e
Poppe Andr´s ­ Kocsis Tam´s a a BME M´rn¨ki Tov´bbk´pz Int´zet, 1992. e o a e o e

Tartalomjegyz´k e
Elsz´ o o 1. C alapok 1.1. Ciklusok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.1. Feladat: Fahrenheit-Celsius ´tsz´mol´ program . . . a a o 1.1.2. Feladat: Fahrenheit-Celsius ´tsz´mol´ for ciklussal a a o 1.2. Egykarakteres I/O . . . . . . . . . . . . . . . . . . . . . . . 1.2.1. Feladat: Karaktersz´ml´s . . . . . . . . . . . . . . . a a 1.3. El´gaz´s: if, switch . . . . . . . . . . . . . . . . . . . . . . a a 1.3.1. Feladat: Sorsz´ml´l´s . . . . . . . . . . . . . . . . . a aa ¨ a o 1.4. On´ll´ feladatok . . . . . . . . . . . . . . . . . . . . . . . . 1.4.1. Feladat: Blank-ek sz´ml´l´sa . . . . . . . . . . . . . a aa 1.4.2. Feladat: Blank-ek sz´ml´l´sa t´ a aa ipusonk´nt . . . . . . e 1.5. Az oper´torok gyakorl´sa . . . . . . . . . . . . . . . . . . . a a 1.5.1. Feladat: A sizeof egyszer haszn´lta . . . . . . . . u a 1.5.2. Feladat: A sizeof ´s 2-vel val´ szorz´s a shiftel´ssel e o a e 1.5.3. Feladatok: Aritmetikai mveletek int-ekkel . . . . . u 2. Bonyolultabb szerkezetek 2.1. Az elfeldolgoz´ haszn´lata . . . . . . . . . . . . . . . . . o o a 2.1.1. Szimb´lumok haszn´lata, felt´teles ford´ as . . . . o a e it´ 2.1.2. Feladat: Programford´ as k¨r¨lm´nyeinek kiirat´sa it´ o u e a 2.1.3. Feladat: Az #ifdef alkalmaz´sa . . . . . . . . . . a 2.1.4. Ford´ asi idben ´l szimb´lumok . . . . . . . . . . it´ o eo o ´ e e 2.1.5. Uj ´s r´gi st´ u f¨ggv´nydeklar´c´k . . . . . . . . ilus´ u e a o 2.1.6. Feladat: . . . . . . . . . . . . . . . . . . . . . . . . 2.1.7. Makr´definici´k . . . . . . . . . . . . . . . . . . . . o o 2.1.8. Feladatok: min, max, pow, toupper, tolower . . . 2.2. T¨mb-, pointer- ´s f¨ggv´nyt´ o e u e ipusok . . . . . . . . . . . . . 2.3. Karaktert¨mb¨k ´s pointerek . . . . . . . . . . . . . . . . o o e i iii 1 1 1 3 5 6 7 7 8 8 8 8 8 8 8 11 11 12 13 14 15 15 17 17 18 19 23

. . . . . . . . . . .

ii 2.3.1. Feladat: saj´t strcpy . . . . . . a 2.3.2. Feladat: saj´t strlen . . . . . . a 2.4. F¨ggv´nypointerek . . . . . . . . . . . . u e 2.5. T¨bb modulb´l ´ll´ programok k´sz´ ese o o a o e it´ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 25 25 30 33 33 35 39 39 40 40 41 41 43 43 43 46 47 47 55 75

3. A dinamikus t´rkezel´s alapjai a e 3.1. Dinamikus adatok . . . . . . . . . . . . . . . . . . . . . . . 3.1.1. Feladat: line´ris egyenletrendszer megold´sa . . . . . a a 4. Az oper´ci´s rendszerrel val´ kapcsolat a o o 4.1. Folyam jelleg I/O . . . . . . . . . . . . . . . . . . u 4.1.1. Feladatok: File-ok m´sol´sa . . . . . . . . . a a 4.1.2. File-nyit´si hib´k, azok kezel´se . . . . . . . a a e 4.2. A main argumentumai . . . . . . . . . . . . . . . . 4.2.1. Feladat: A copy parancs ­ saj´t kivitelben a 5. Fejlettebb technik´k a 5.1. Strukt´r´k ­ l´ncolt lista . . . . . . . . ua a 5.1.1. Fealadat: L´ncolt lista k´sz´ ese a e it´ 5.2. Men¨rendszer . . . . . . . . . . . . . . . u ¨ 5.3. Osszetett mintap´lda . . . . . . . . . . . e 5.3.1. A tervez´s egyes f´zisai . . . . . e a 5.3.2. A men¨kezel rendszer list´ja . . u o a Irodalomjegyz´k e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

Elsz´ o o
A C programoz´si nyelv az egyik legn´pszerbb programfejleszt´si eszk¨z a e u e o a vil´gon. Ez nagy r´szt a mikr´- ´s minisz´m´ og´pek, illetve az un. a e o e a it´ e ´ munka´llom´sok (worktstation-¨k) vil´gm´ret t´rnyer´s´nek k¨sz¨nhet. a a o a e u e ee o o o Ezen g´pkateg´ri´k Magyarorsz´gon, illetve sz¨kebben a Budapesti Mszae o a a u u ki Egyetemen elterjedt reprezent´nsain is (IBM PC/AT, VAX/MicroVAX, a SUN, stb.) hat´kony C fejleszti k¨rnyezeteket tal´lhatunk. e o o a A programfejlesztk sz´ o ivesen dolgoznak a C-vel, mert ´ltal´nos c´l´, ala a eu kalmas igen nagy l´legzet csoportmunk´kban val´ felhaszn´l´sra, nagyon e u a o aa j´ hat´sfok´ k´dot lehet vele el´ll´ o a u o oa itani, m´gis magas szinten strukt´r´lt, e ua a ´tfog´an szabv´nyos´ o a itott nyelv. Ez ut´bbi azt jelenti, hogy egy adott g´po e t´ ipus adott oper´ci´s rendszer´re kidolgozott ­ bizonyos program´ asi szaa o e ir´ b´lyokat figyelembe vev ­ program viszonylag kis munk´val, j´l meghaa o a o t´rozott helyeken val´ m´dos´ assal ´t´ a o o it´ a irhat´ m´s sz´m´ og´p tetszleges (a o a a it´ e o C nyelvet t´mogat´) oper´ci´s rendszere al´. Itt azonban r¨gt¨n meg kell a o a o a o o jegyezn¨nk azt is, hogy nagyon k¨nny C nyelven ´ttekinthetetlen, nehezen u o u a meg´rthet ´s m´dos´ e oe o ithat´ programokat k´sz´ o e iteni. Nagyon fontos teh´t a a fegyelmezett, k¨r¨ltekint programoz´si st´ alkalmaz´sa, aminek az elsaou o a ilus a j´t´ asa kb. annyi munk´t ig´nyelhet, mint maguknak a nyelvi elemeknek a it´ a e a megtanul´sa. a Tekintve, hogy a C n´pszers´ge n, egyre t¨bben szeretn´k a nyelvet ele ue o o e saj´t´ a itani. Ehhez egyre t¨bb, a C nyelvet ismertet k¨nyv ´ll rendelkez´sre, o o o a e de ezek k¨zt kev´s tartalmaz olyan mintaprogramot, illetve mintafeladatot, o e amelyek seg´ ek elm´ly´ iten´ e iteni a C nyelv ismert´t. Feladatgyjtem´ny¨nk e u e u ­ legal´bbis ugy hissz¨k ­ ezt a hi´nyt igyekszik p´tolni olym´don, hogy a ´ u a o o egyes C nyelvi elemekhez kapcsol´dva mintaprogramokat, illetve programo r´szleteket k¨z¨l, illetve feladatkitz´seket tartalmaz. e o o u e A hi´nyp´tl´son t´l, m´sik c´lunk az, hogy seg´ eget ny´jtsunk egy a o a u a e its´ u tiszta, a nyelvi elemeket j´l kihaszn´l´, port´bilis C programoz´si st´ elo ao a a ilus saj´t´ as´hoz. Azt is igyeksz¨nk bemutatni ­ egy, a BME Villamosm´rn¨ki a it´ a u e o Kar´nak nappali tagozat´n szok´sos programoz´si nagy h´zi feladat megola a a a a d´s´nak ismertet´s´vel ­ hogy milyen az un. ¨ndokument´l´ program, egy aa ee ´ o ao iii

iv

Elsz´ o o

k´sz, nagyobb l´legzet C programot hogy dokument´ljunk, ehhez milyen e e u a seg´dprogramokat vehet¨nk ig´nybe. e u e A sz¨vegben az IBM PC kompatibilis g´peken sz´les k¨rben elterjedt o e e o TURBO/BORLAND C(++) ford´ okkal, illetve a VAX t´ u sz´m´ oit´ ipus´ a it´ g´pek VMS oper´ci´s rendszere alatt el´rhet VAX-C ford´ oval egyar´nt e a o e o it´ a leford´ ithat´ programp´ld´kat szerepeltet¨nk. o e a u Felt´telezzk, hogy e feladatgyjtem´nyt forgat´ olvas´knak valamilyen e u u e o o m´s programoz´si nyelv ­ p´ld´ul a Pascal ­ haszn´lat´ban m´r van n´mi a a e a a a a e rutinjuk. A C nyelvet term´szetesen egy p´ldat´rb´l nem lehet megtae e a o nulni, ´ javasoljuk, hogy a mintaprogramok, illetve a kitz¨tt feladatok igy u o feldolgoz´s´t egy, a C nyelvet ismertet k¨nyv tanulm´nyoz´s´val p´rhuaa o o a aa a zamosan v´gezze az Olvas´. Feladatgyjtem´ny¨nk anyag´nak fel´p´ ese e o u e u a e it´ olyan, hogy t¨bb´-kev´sb´ k¨veti a BME M´rn¨ki Tov´bbk´pz Int´zete o e e e o e o a e o e a ´ltal kiadott Az IBM PC programoz´sa Turbo C 2.0 nyelven c. jegyzet [1], a illetve a ComputerBooks kiad´n´l 1991-ben megjelent Bevezet´s a BORo a e LAND C++ programoz´sba c. k¨nyv [2] anyag´t. A p´ldat´r sz¨veg´ben a o a e a o e ­ aja´nlott kieg´sz´ o olvasm´nyk´nt ­ ez ut´bbi munka fejezetsz´maira a e it´ a e o a fogunk hivatkozni. Haszonnal forgathatja az olvas´ Kerninghan ´s Ritchie A C programoo e z´si nyelv c´ u k¨nyv´t [3], illetve e k¨nyv m´sodik, csak angol nyelven a im o e o a hozz´f´rhet kiad´s´t [4] is: bizonyos feladatkitz´seket onnan vett¨nk ´t. ae o aa u e u a Az egyes C nyelvi implement´ci´kra vonatkoz´ r´szletes ismeretekre a o o e nincs sz¨ks´g e feladatgyjtem´ny haszn´lata sor´n, mindazon´ltal c´lszer u e u e a a a e u lehet ezek forgat´sa komolyabb programfejleszt´si munk´kn´l. a e a a

K¨sz¨netnyilv´n´ as o o a it´
Szeretn´nk megk¨sz¨nni Benk Tiborn´nak azt, hogy f´radhatatlanul b´ e o o o e a iztatott minket arra, hogy a BME Villamosm´rn¨ki Kar´nak nappali tagoe o a zatos 1. ´vfolyamos hallgat´inak oktat´sa sor´n ¨sszegyjt¨tt tapasztalae o a a o u o tainkat jelen p´ldat´r ¨ssze´ll´ as´val k¨zz´ tegy¨k. e a o a it´ a o e u K¨sz¨net illeti Verh´s P´tert is, aki HION nev programj´t rendelkez´o o a e u a e s¨nkre bocs´totta. Ez a program tette lehetv´, hogy a magyar nyelv, u a o e u ´kezetes sz¨vegfile-jainkat gond n´lk¨l haszn´lhassuk a TEXsz¨vegform´z´ e o e u a o a o A rendszer L TEXmakr´csomagj´val. o a Budapest, 1998. szeptember 6. A szerzk o

1. fejezet

C alapok
Jelen fejezet c´lja az, hogy meg´reztesse a C programoz´s ´ et. Mivel a tele e a iz´ jesen port´bilis programoz´si st´ a a ilust igyeksz¨nk bemutatni, az itt ismertett u p´ld´k, illetve a kitz¨tt feladatok ak´r TURBO C-vel, ak´r BORLAND e a u o a a C++-szal, ak´r VAX C-vel leford´ a ithat´k. Lehets´g szerint ANSI C ford´ o oe it´si opci´t haszn´ljunk, ha IBM PC-n dolgozunk. a o a A tov´bbiakban felt´telezz¨k, hogy az olvas´ alaposan ismer m´r egy a e u o a programoz´si nyelvet, p´ld´ul a Pascal-t. Elsz¨r egyszer p´ld´kat k¨za e a o o u e a o l¨nk mind Pascal, mind C nyelven ­ r´szben csak egyszer szintaxis v´lu e u a t´ssal, r´szben kihaszn´lva a C ny´jtotta t¨m¨r´ esi lehets´geket, majd a e a u o o it´ oe egyes probl´m´knak a C nyelv megval´s´ as´t k¨z¨lj¨k, v´g¨l pedig csak e a u o it´ a o o u e u feladatki´ asokat adunk meg, a C nyelvet tanul´kra b´ ir´ o izva az egyes feladatok konkr´t, C nyelv megval´s´ as´t. E fejezet feldolgoz´s´hoz javasolt e u o it´ a aa olvasm´ny [2]-b´l: 2.1, 2.2, 2.4.4, 2.4.5, 2.5, 2.7 fejezetek. a o

1.1.
1.1.1.

Ciklusok
Feladat: Fahrenheit-Celsius ´tsz´mol´ program a a o

K´sz´ unk olyan programot, amely egy adott tartom´nyon bel¨l, adott e its¨ a u l´p´sk¨zzel kilist´zza a Fahrenheit fokokban adott hm´rs´klet Celsius foe e o a o e e kokban sz´molt ´rt´k´t. a e e e Ezzel a mintaprogrammal kezddik Kerninghan ´s Ritchie k¨nyve is. o e o Mi elsz¨r a C-ben m´g j´ratlan olvas´ kedv´´rt Pascal nyelven k¨z¨lj¨k o o e a o ee o o u a megold´st, majd megadjuk ugyanezt a programot C-ben is. A C-re vaa l´ ´tt´r´st egyszer szintaxis-v´lt´ssal oldottuk meg. Igy a program egy o a ee u a a 1

2

1. FEJEZET. C ALAPOK

C ford´ ov´l m´r leford´ it´ a a ithat´, de m´g nem "C nyelv". Ezalatt azt ´rto e u e j¨k, hogy egy´ltal´n nem haszn´lja ki a C lehets´geit. A C-ben k´dolt u a a a oe o programv´ltozat fokozatos finom´ as´val jutunk el egy m´r C programnak a it´ a a nevezhet v´ltozathoz. o a A Pascal v´ltozat: a PROGRAM FAHRANHEIT(INPUT, OUTPUT); VAR FAHR, CELS: INTEGER; LOWER, UPPER, STEP: INTEGER; BEGIN LOWER:=0; UPPER:=300; STEP:=20; FAHR:=LOWER; WRITELN; WHILE(FAHR <= UPPER) DO BEGIN CELS:=5*(FAHR-32) DIV 9; WRITELN(FAHR,' ',CELS); FAHR:=FAHR+STEP; END; END. A C v´ltozat: a #include main() { int fahr, cels; int lower, upper, step; lower = 0; upper = 300; step = 20; fahr = lower; printf("\n"); while(fahr <= upper) {

1.1. CIKLUSOK cels = 5 * (fahr - 32) / 8; printf("%d\t%d\n",fahr,cels); fahr = fahr + step; } }

3

1.1.2.

Feladat: Fahrenheit-Celsius ´tsz´mol´ for cika a o lussal

Alak´ itsuk at a C v´ltozatot ugy, hogy a while ciklus helyett for ciklussal ´ a ´ mk¨dj¨n! (L´sd [2]-b´l a 2.7.3-as r´szt.) u o o a o e Gondoljuk v´gig, hogy mi az inicializ´l´ r´sz, amit lehet, azt a vesze ao e sz oper´tor seg´ eg´vel rakjuk a for ciklus inicializ´l´ kifejez´s r´sz´be! o a its´ e ao e e e Haszn´ljuk ki a C ny´jtotta t¨m¨r´ esi lehets´geket! a u o o it´ oe Megold´s: a #include main() { int fahr, cels; int lower, upper, step; printf("\n"); for (fhar = lower = 0, upper = 300, step = 20; fahr <= upper; fahr += step) { cels = 5 * (fahr- 32) / 8; printf("%d\t%d\n",fahr,cels); } } Tov´bbi lehets´g: a o e Az inicializ´l´st ´thelyezz¨k a deklar´ci´s r´szbe, azaz inicializ´lt v´ltoz´aa a u a o e a a o kat hozunk l´tre. Ekkor a for ciklus inicializ´l´ r´sze egy ures utas´ as e ao e ¨ it´ lesz: #include main() { int fahr = 0, cels;

4

1. FEJEZET. C ALAPOK int lower = 0, upper = 300, step = 20; printf("\n"); for ( ; /* initialization - empty statement */ fahr <= upper; /* condition */ fahr += step) /* stepping */ { cels = 5 * (fahr- 32) / 8; printf("%d\t%d\n",fahr,cels); }

}

Szimb´lumok haszn´lata: o a Haszn´ljunk szimb´likus konstansokat a konkr´t numerikus ´rt´kek helyett a o e e e a fprogramon bel¨l! (L´sd [2] 2.3-as, az un. elfeldolgoz´r´l sz´l´ fejezeo u a ´ o o o oo t´nt, azon bel¨l a 2.3.1-es szakaszt.) Az elz programv´ltozat szimb´likus e u o o a o konstansok felhaszn´l´s´val teh´t ´ n´z ki: aa a a igy e

#include #define LOWER 0 #define UPPER 300 #define STEP 20 main() { int fahr = LOWER, cels; int lower = LOWER, upper = UPPER, step = STEP; printf("\n"); for ( ; /* initialization - empty statement */ fahr <= upper; /* condition */ fahr += step) /* stepping */ { cels = 5 * (fahr- 32) / 8; printf("%d\t%d\n",fahr,cels); } }

1.2. EGYKARAKTERES I/O

5

1.2.

Egykarakteres I/O

Gyakoroljuk a szabv´nyos input/output egykarakteres kezel´s´t! Ehhez az a ee stdio.h k¨nyvt´r getchar (egy karakter beolvas´sa a billentyzetrl) ´s o a a u o e putchar (egy karakter nyomtat´sa a k´pernyre) rutinjait haszn´ljuk fel. a e o a (L´sd [2] 2.10.2 fejezet´nek elej´t!) Haszn´lni fogjuk az EOF (end-of-file) a e e a szimb´lumot is, amely ugyancsak az stdio.h-ban van defini´lva. Indulo a junk ki az al´bbi egyszer Pascal programb´l: a u o PROGRAM CHARCOPY(INPUT, OUTPUT); VAR CH: CHAR; BEGIN WHILE NOT EOF DO BEGIN READ(CH); WRITE(CH); END; END. Ennek C megfelelje: o #include main() { int ch;

/* int and char are compatible */

ch = getchar(); while (ch != EOF) { putchar(ch); ch = getchar(); } } Megjegyz´s: Mivel a VAX g´peken a VMS oper´ci´s rendszer alatt un. e e a o ´ bufferelt, ech´zott I/O van, ez´rt eg´szen addig, amig az els RETURN-t o e e o nem utj¨k le a termin´l billentyzet´n, gylnek a karakterek (´s ki is ´ od¨ u a u e u e ir´ nak a k´pernyre), a VMS csak ezut´n adja ´t az input buffer tartalm´t a e o a a a szabv´nyos bemenetet olvas´ rutinnak (a Pascal READ-nek, illetve a C geta o char-nak). A file-v´g´t a a PC-ken a CTRL-Z jelenti. A VAX CTRL-Z-t e e m´g beolvasott karakternek tekinti, de az EXIT uzenet ut´n be´ll az EOF e ¨ a a a ´llapot, ´ a program le´ll. igy a

6 Tov´bbfejleszt´s: a e

1. FEJEZET. C ALAPOK

Haszn´ljuk ki, hogy a C ´rt´kad´ oper´tor mell´khat´sa az, hogy a bal´rt´k a e e o a e a e e mint k´sz kifejez´s azonnal felhaszn´lhat´. Ilyenform´n a while ciklus logie e a o a kai kifejez´s´t ad´ rel´ci´s mvelet baloldal´n ´ll´ ch v´ltoz´nak mag´ban ee o a o u a a o a o a a while-felt´tel kifejez´sben adhatunk ´rt´ket. A mveletek helyes ki´rt´kee e e e u e e l´si sorrendj´t azzal biztos´ e e itjuk, hogy az ´rt´kad´ mveletet z´rojelek k¨z´ e e o u a o e tessz¨k. (A z´r´jel-p´r is egy oper´tor; hat´sa az, hogy az operandus´t u ao a a a a azonnal ki´rt´keli.) e e #include main() { int ch;

/* int and char are compatible */

while ((ch = getchar()) != EOF) { putchar(ch); } }

1.2.1.

Feladat: Karaktersz´ml´s a a

Az elbbi p´lda alapj´n ´ o e a irjunk olyan C programot, amely megsz´ml´lja, a a h´ny karaktert olvastunk be a szabv´nyos bemeneti ´llom´nyr´l! Annyi a a a a o m´dos´ asra van sz¨ks´g, hogy a ciklust¨rzsben nem iratjuk ki a beolvasott o it´ u e o karaktert, hanem csak egy sz´ml´l´ ´rt´ket n¨velj¨k. Ime a program: a aoe e o u #include main() { int n = 0; while (getchar() != EOF) { n = n + 1; /* or n += 1; or n++; */ } printf("\nNumber of characters read from stdin: %d\n",n); }

´ ´ 1.3. ELAGAZAS: IF, SWITCH

7

Amint azt a programbeli megjegyz´sbl is l´thatjuk, az igencsak Pascalos e o a n = n + 1; utas´ ast sokkal t¨merebben is le´ it´ o irhatjuk C-ben az un. post´ increment oper´tor felhaszn´l´s´val: n++; a aa a

1.3.
1.3.1.

El´gaz´s: if, switch a a
Feladat: Sorsz´ml´l´s a aa

Els l´p´sben bv´ uk ki ugy az elbbi, karaktersz´ml´l´ programot, hogy o e e o its¨ ´ o a ao azt is sz´ml´lja, h´ny sorb´l allt az input. Ehhez puszt´n a beolvasott '\n' a a a o ´ a karaktereket kell k¨l¨n sz´ml´lni: uo a a #include main() { int n, nl; int ch; n = nl = 0; while ((ch = getchar()) != EOF) { n++ if (ch == '\n') nl++; } printf("\nNumber of characters read from stdin: %d\n",n); printf("Number of lines read from stdin: %d\n",nl); } Most t¨m¨r´ unk egy kicsit ezen a programon! Kihaszn´lva azt, hogy a o o its¨ a rel´ci´s oper´torok ligikai ´rt´ket szolg´ltatnak, ami vagy 1 (ha igaz a rea o a e e a l´ci´), vagy 0 (ha nem igaz), a k¨vetkezk´ppen ´ a o o o e irhatjuk ´t programunkat: a #include main() { int n, nl; int ch; n = nl = 0; while ((ch = getchar()) != EOF) {

8 n++ nl += (ch == '\n');

1. FEJEZET. C ALAPOK

} printf("\nNumber of characters read from stdin: %d\n",n); printf("Number of lines read from stdin: %d\n",nl); }

1.4.
1.4.1.

¨ a o On´ll´ feladatok
Feladat: Blank-ek sz´ml´l´sa a aa

Irjunk ¨n´ll´an olyan programot, amely azt sz´ml´lja meg, hogy egy¨tto a o a a u v´ve h´ny un. blank karakter, azaz sz´k¨z, tabul´tor ('\t') vagy ujsor e a ´ o o a ´ karakter ('\n') j¨n be az inputr´l! o o (Az if utas´ ast ´s a logikai VAGY mveletet felhaszn´lva.) it´ e u a

1.4.2.

Feladat: Blank-ek sz´ml´l´sa t´ a aa ipusonk´nt e

Irjunk ¨n´ll´an olyan programot, amely megsz´ml´lja, hogy h´ny sz´k¨z, o a o a a a o o tabul´tor ('\t') ´s ujsor karakter ('\n') j¨n be az inputr´l! Haszn´ljuk a a e ´ o o a switch utas´ ast! it´

1.5.
1.5.1.

Az oper´torok gyakorl´sa a a
Feladat: A sizeof egyszer haszn´lta u a

Irjunk olyan programot, amely a sizeof oper´tor seg´ eg´vel meghat´roza its´ e a za ´s a k´pernyre ki´ az alap-adat´ e e o irja ipusok m´ret´t! e e

1.5.2.

Feladat: A sizeof ´s 2-vel val´ szorz´s a shiftee o a l´ssel e

Irjunk olyan programot, amely a blara shiftel´s oper´tor´nak a seg´ eg´vel e a a its´ e ki´ a k´pernyre 2 minden olyan hatv´ny´t, amely elf´r egy int-ben. irja e o a a e

1.5.3.

Feladatok: Aritmetikai m veletek int-ekkel u

Gyakoroljuk az aritmetikai oper´torok (¨sszead´s, kivon´s, szorz´s, oszt´s, a o a a a a marad´kk´pz´s) haszn´lat´t int t´ u adatok eset´n. Irjunk olyan proge e e a a ipus´ e ramot, amely a) el´ll´ egy eg´sz sz´m ¨sszes oszt´j´t, oa itja e a o oa

´ ´ 1.5. AZ OPERATOROK GYAKORLASA b) el´ll´ egy eg´sz sz´m pr´ enyezs felbont´s´t, oa itja e a imt´ o aa

9

c) eld¨nti egy eg´sz sz´mr´l, hogy t¨k´letes sz´m-e (Egy t¨k´letes sz´m o e a o o e a o e a eggyel nagyobb, mint az ¨sszes val´di oszt´j´nak az ¨sszege.), o o oa o d) megadja k´t eg´sz sz´m legkisebb k¨z¨s t¨bbsz¨r¨s´t. e e a o o o ooe

10

1. FEJEZET. C ALAPOK

2. fejezet

Bonyolultabb szerkezetek
Az elz fejezet v´g´re az alaputas´ asok haszn´lata sor´n siker¨lt elt´voo o e e it´ a a u a lodnunk a Pascal-szer megold´sokt´l. Most sorra vessz¨k azokat a leheu a o u ts´geket, amelyek a C-t igaz´n hat´kony programoz´si nyelvv´ teszik. oe a e a e Elsz¨r ´ttekintj¨k az elfeldolgoz´ haszn´lat´t, ennek kapcs´n utalunk o o a u o o a a a arra, hogy k´sz´ e ithetk port´bilis programok a felt´teles ford´ asi direkt´ ak o a e it´ iv´ felhaszn´l´s´val. Ezt k¨veten azzal foglakozunk, hogy ´ aa a o o irhatunk un. mak´ r´kat. o E fejezet folytat´sak´ppen ´ttekintj¨k azt, hogy a C alapt´ a e a u ipusaib´l hogy o sz´rmaztathatunk tov´bbi t´ a a ipusokat, ´ttekintj¨k a mutat´k ´s a t¨mb¨k a u o e o o kapcsolat´t. A f¨ggv´nypointerek haszn´lat´t a qsort f¨ggv´ny p´ld´j´n a u e a a u e e aa kereszt¨l mutatjuk be. u Szint´n a f¨ggv´nypointerek kapcs´n egy flexibilis numerikus integr´l´ e u e a ao f¨ggv´nyt ismertet¨nk. Ebbl, ´s n´h´ny integr´land´ f¨ggv´nybl, valau e u o e e a a o u e o mint egy main f¨ggv´nybl elk´sz´ unk egy t¨bb forr´smodulb´l ´ll´ progu e o e it¨ o a o a o ramot.

2.1.

Az elfeldolgoz´ haszn´lata o o a

Az elfeldolgoz´ egy sororient´lt sz¨vegfeldolgoz´ (m´s sz´val makr´nyelv), o o a o o a o o ami semmit sem "tud" a C nyelvrl. Ez k´t fontos k¨vetkezm´nnyel j´r: az o e o e a elfeldolgoz´nak sz´l´ utas´ asokat nem ´ o o oo it´ irhatjuk olyan k¨tetlen form´ban, o a mint az egy´b C utas´ asokat (teh´t egy sorba csak egy utas´ as ker¨lhet e it´ a it´ u ´s a parancsok nem l´ghatnak ´t m´sik sorba, hacsak nem jel¨lj¨k ki folye o a a o u tat´sornak); m´sr´szt minden, amit az elfeldolgoz´ mvel, szigor´an csak o a e o o u u sz¨vegmanipul´ci´, f¨ggetlen¨l att´l, hogy C nyelvi alapszavakon, kifejez´o a o u u o e seken vagy v´ltoz´kon dolgozik. Az elfeldolgoz´ ´s az un. bels ford´ o a o o o e ´ o it´ 11

12

2. FEJEZET. BONYOLULTABB SZERKEZETEK

C ford´ oprogram it´
forr´ssz¨veg a o elfeldolgoz´ o o bels ford´ o o it´ t´rgyk´d a o

2.1. ´bra. Az elfeldolgoz´ kapcsolata a k¨rnyezettel a o o o

´ Szimbolum STDC FILE LINE DATE TIME

´ ´ ´ ´ Ertelmezes, ertek 1 ´rt´kkel defini´lva van, ha ANSI C (eg´sz) e e a e a feldolgoz´s alatt ´ll´ file neve (sztring) a a o a feldolgoz´s alatt ´ll´ sor sz´ma (eg´sz) a a o a e a ford´ as d´tuma (sztring) it´ a a ford´ as ideje (sztring) it´

2.1. t´bl´zat. Elre defini´lt szabv´nyos szimb´lumok az ANSI C-ben a a o a a o

kapcsolat´t szeml´lteti a 2.1 ´bra. a e a A preprocesszornak sz´l´ parancsokat a sor elej´n (esetleg sz´k¨z¨k oo e o o o ´s/vagy tabul´torok ut´n) ´ll´ # karakter jelzi. A legfontosabb utas´ ae a a a o it´ sok: #define, #undef, #include, #if, #ifdef, #else, #elif, #endif.

2.1.1.

Szimb´lumok haszn´lata, felt´teles ford´ as o a e it´

Az elz fejezetben m´r l´ttuk, hogy a #define direkt´ seg´ eg´vel hogy o o a a iva its´ e "nevezhetj¨k el" sz´mkonstansainkat. Term´szetesen a #define-nal l´tu a e e rehoztt szimb´lumokat nemcsak konstans kifejez´sek elnevez´s´re haszn´lo e ee a hatjuk, hanem p´ld´ul felt´teles ford´ asvez´rl´sre. Ez´ltal egyes programe a e it´ e e a r´szletek leford´ as´t kikapcsolhatjuk, illetve bekapcsolhatjuk. e it´ a A felt´teles ford´ asi direkt´ ak haszn´lata elssorban a t¨bb, k¨l¨nb¨z e it´ iv´ a o o uo o o oper´ci´s rendszer alatti ford´ asra sz´nt programokra jellemz. Altal´ban a o it´ a o ´ a minden C nyelvi rendszer elre defini´l egyes szimb´lumokat, ´ p´ld´ul o a o igy e a olyanokat, amelyek megl´te vagy hi´nya alapj´n eld¨nthet, hogy milyen e a a o o oper´ci´s rendszer alatt t¨rt´nik a ford´ as. a o o e it´ Maga az ANSI C szabv´ny is elre defini´l egyes szimb´lumokat, amea o a o lyek alapj´n a program ford´ as k¨r¨lm´nyeirl szerezhet¨nk inform´ci´kat. a it´ o u e o u a o Ezeket a szimb´lumokat az 2.1. t´bl´zatban soroljuk fel. o a a B´r a leg´jabb VAX C sokmindenben megfelel az ANSI C-nek, m´gsincs a u e

´ ´ 2.1. AZ ELOFELDOLGOZO HASZNALATA

13

´ Szimbolum VAX vagy vax VMS vagy vms VAXC vagy vaxc VAX11C vagy vax11c TURBOC MSDOS BORLANDC TCPLUSPLUS cplusplus

´ ´ ´ ´ Ertelmezes, ertek A VAX C-ben 1 ´rt´kkel defini´lva van e e a A VAX C-ben 1 ´rt´kkel defini´lva van e e a A VAX C-ben 1 ´rt´kkel defini´lva van e e a A VAX C-ben 1 ´rt´kkel defini´lva van e e a Minden Turbo/Borland C-ben defini´lva van a ´ Altal´ban minden PC-s C-ben defini´lva van. a a A Borland C++-ban mindig defini´ltva van. a A verzi´sz´mra utal. o a Csak C++ uzemm´dban van defini´lva, ekkor a ¨ o a verzi´sz´mot adja. o a C++ uzemm´dban 1 ´rt´kkel van defini´lva, ¨ o e e a egy´bk´nt defini´latlan. e e a

2.2. t´bl´zat. a a A Borland C++-ban ´s a VAX C-ben defini´lt, az oper´ci´s rendszerre, e a a o illetve a ford´ ora utal´ szimb´lumok it´ o o

o o a a o elre defini´lva a STDC szimb´lum, j´llehet, az 2.1. t´bl´zatban szerepl o a t¨bbi szimb´lum l´tezik benne. o o e o a A Borland C++-ban a STDC szimb´lum akkor van defini´lva, ha az Options men¨ben ANSI C kompatibilisre ´ll´ u a itottuk be a ford´ ot. it´ Az ANSI C ´ltal megadott elredefini´lt szimb´lumokon k´ ul ­ mint a o a o iv¨ m´r eml´ a itett¨k ­ minden nyelvi rendszerben vannak olyan elredefini´lt u o a szimb´lumok, amelyek az adott nyelvi rendszert, ´s az oper´ci´s rendszert o e a o azonos´ ak. A VAX C-ben, illetve a Borland C++-ban elfordul´ ilyen itj´ o o szimb´lumokat a 2.2. t´bl´zatban foglatuk ¨ssze. o a a o

2.1.2.

Feladat: Programford´ as k¨r¨ lm´nyeinek kiirait´ o u e t´sa a

A elzek alapj´n ´ o o a irjunk olyan programot, amely abban az esetben, ha ANSI C, vagy VAXC kompatibilis ford´ oprogrammal ford´ it´ itott´k le, ki´ a a irja szabv´nyos kimenetre, hogy a · milyen nev forr´s´llom´nyb´l ford´ u aa a o itott´k, a · mikor (d´tum, id) t¨rt´nt a ford´ as, a o o e it´ · ki´ irja, hogy a main f¨ggv´ny h´ny sorb´l ´ll. u e a o a

14 A megold´s: a

2. FEJEZET. BONYOLULTABB SZERKEZETEK

/***** File: test.c ******/ #include int sor = 0; main() { #if defined(__STDC__) || VAXC sor = __LINE__; printf("The compilation circumstances of %s:\n", __FILE__); printf("Date of compilation: %s\n",__DATE__); printf("Time of compilation: %s\n",__TIME__); printf("Approximate length of 'main': %d\n", __LINE__ - sor); #else printf("The compiler is not ANSI C/VAX-C compatible\n"); printf("No way to identify compilation circumstances\n"); #endif } Az elbbi programot egy PC-n, a Borland C++-szal ANSI C uzemm´dban o ¨ o leford´ itva, majd az object modulb´l szerkesztett .exe programot lefuttatva o a k¨vetkez outputot kapjuk a k´pernyn: o o e o The compilation circumstances of TEST.C: Date of compilation: Mar 21 1992 Time of compilation: 11:30:35 Approximate length of 'main': 6 A fenti p´lda kapcs´n bemutatott lehetes´gek jelents´ge abban rejlik, e a oe oe hogy egy m´r k´sz, a felhaszn´l´k sz´m´ra csak exe file form´j´ban rendela e ao a a aa kez´sre ´ll´ programban is elhelyezhet¨nk olyan teszt-r´szleteket, amelyek e a o u e seg´ eg´vel p´ld´ul a felhaszn´l´ egy r´szletes hibajelent´st k¨ldhet a progits´ e e a ao e e u ram fejlesztinek. o

2.1.3.

Feladat: Az #ifdef alkalmaz´sa a

Eg´sz´ uk ki az elbbi test.c programot ugy, hogy att´l f¨ggen, hogy e its¨ o ´ o u o PC-n a DOS alatt, vagy egy VAX-on, a VMS oper´ci´s rendszer allat fora o d´ ak le, m´s-m´s azonos´ o sz¨veget ´ itj´ a a it´ o irjon ki.

´ ´ 2.1. AZ ELOFELDOLGOZO HASZNALATA

15

2.1.4.

Ford´ asi idben ´l szimb´lumok it´ o eo o

Term´szetesen nem csak az adott C nyelvi rendszer ´ltal elre defini´lt szime a o a b´lumok megl´t´t vizsg´lhatjuk az #ifdef preprocesszor utas´ assal, hanem o ee a it´ mi magunk is l´trehozhatunk szimb´lumokat a ford´ as idej´re. Ezeket nem e o it´ e kell a forr´sprogramjainkban elhelyezni, hanem ford´ asi idben, a ford´ o a it´ o it´ program sz´mara param´terk´nt adhatjuk meg. a e e A BORLAND C++ integr´lt k¨rnyezet´ben az Options | Compiler | a o e Code genaration dial´gus doboz Defines mezj´be ´ sztringre, illetve o o e irt a VAX C eset´ben a CC parancs /DEFINE= kapcsol´ja ut´n ´ sztringre e o a irt hivatkozva a C forr´sprogramban, ford´ askor ugy tal´ljuk, hogy az adott a it´ ´ a szimb´lum defini´lva van. Tekints¨k a k¨vetkez p´ld´t: o a u o o e a /***** File: testsymb.c *****/ #include main() { #ifdef MYSYMBOL printf("MYSYMBOL has been defined for %s\n",__FILE__); #else printf("MYSYMBOL has not been defined for %s\n",__FILE__); #endif } Ha teh´t a fenti programot egy VAX g´pen, VMS-ben a CC TESTSYMB /DEa e FINE=MYSYMBOL paranccsal ford´ itjuk le, akkor MYSYMBOL has been defined for TESTSYMB.C uzenetet fogja ki´ a k´pernyre a futtathat´ prog¨ irni e o o ram, m´ az egyszer CC TESTSYMB ford´ asi paranccsal ford´ ig u it´ itva, a futtathat´ program a m´sodik uzenetet ´ majd ki. Hasonl´ kis´rlet v´gezhet o a ¨ irja o e e o PC-ken a MYSYMBOL szimb´lum ford´ asi idre t¨rt´n defini´l´s´val (az o it´ o o e o aa a Options | Compiler | Code genaration | Defines mez kit¨lt´s´vel) o o ee

2.1.5.

´ e e Uj ´s r´gi st´ u f¨ ggv´nydeklar´c´k ilus´ u e a o

Az ANSI C szabv´ny szerint minden f¨ggv´ny deklar´ci´jakor nemcsak a a u e a o visszat´r´si t´ e e ipust kell megadnunk, (ha nem tessz¨k, akkor definici´ szeu o rint int t´ u visszat´r´si ´rt´ket t´telez fel a ford´ o ­ ez sok baj forr´sa ipus´ ee e e e it´ a lehet), hanem azt is pontosan meg kell adnunk, mennyi, ´s milyen t´ u e ipus´ param´terrel rendelkezik egy f¨ggv´ny. Ez a szoros deklar´ci´s k´nyszer lee u e a o e hets´get teremt arra, hogy a C ford´ o figyelmeztessen minket, ha esetleg oe it´ hi´nyos aktu´lis param´terlist´val, vagy esetleg nem a deklar´ci´ szerinti a a e a a o (vagy azokkal kompatibilis) t´ u adatokkal aktiviz´lunk egy f¨ggv´nyt. ipus´ a u e Tekints¨nk egy p´ld´t az ANSI C szerinti f¨ggv´nydeklar´ci´ra: u e a u e a o

16

2. FEJEZET. BONYOLULTABB SZERKEZETEK double mypower(double x, double y);

A mypower teh´t egy double visszat´r´si ´rt´ket szolg´ltat´, 2 double paa ee e e a o ram´tert v´r´ f¨ggv´ny. A deklar´ci´b´l a form´lis param´terek azonoe ao u e a o o a e s´ oi elhagyhat´k. (Term´szetesen a f¨ggv´nydefinici´n´l, teh´t amikor a it´ o e u e o a a f¨ggv´nyt¨rzset is megadjuk, m´r ki kell ´ u e o a irnunk a form´lis param´terek a e azonos´ oit is). it´ A f¨ggv´nyek k¨telez deklar´ci´j´nak, vagy m´s szakkifejez´ssel ´lve, u e o o a oa a e e a prot´ ipusmegad´snak egy m´sik elnye is van: az ilyen, ugynevezett uj a a o ´ ´ st´ u f¨ggv´nydeklar´ci´t alkalmaz´ C programjaink minden tov´bbi n´lilus´ u e a o o a e k¨l beilleszthetk egy objektum-orient´lt C++ programba, ahol a pontos u o a protot´ ipusmegad´s alapk¨vetelm´ny. a o e Az uj st´ u f¨ggv´nymegad´s mellett l´tezik azonban a r´gi st´ is. ´ ilus´ u e a e e ilus A r´gi st´ u deklar´ci´kn´l csak a visszat´r´si ´rt´k t´ at ´s a f¨ggv´ny e ilus´ a o a e e e e ipus´ e u e azonos´ oj´t adjuk meg, a param´terlist´r´l nem mondunk semmit. Csak it´ a e ao a f¨ggv´ny definici´n´l adjuk meg a param´terlist´t. A fenti f¨ggv´ny¨nk u e o a e a u e u r´gi st´ u deklar´ci´ja a k¨vetkezk´ppen n´z ki: e ilus´ a o o o e e double mypower(); A r´gi st´ u f¨ggv´nydefinici´ pedig ´ kezddik: e ilus´ u e o igy o double mypower(x, y) double x, y; majd ezt k¨veti a f¨ggv´ny t¨rzse. o u e o A r´gi ´s az uj f¨ggv´nydeklar´ci´s st´ alkalmaz´sa ´ltal´ban kiz´rja e e ´ u e a o ilus a a a a egym´st. Hogy k´sz´ a e ithet¨nk m´gis olyan programokat, amelyek ak´r egy u e a r´gi C ford´ oval, ak´r a leg´jabb ford´ okkal, vagy ak´r egy C++ ford´ oval e it´ a u it´ a it´ is leford´ ithat´? o Nos, a megold´st term´szetesen a felt´teles ford´ as, illetve az egyes a e e it´ nyelvi implement´ci´k ´ltal elre defini´lt szimb´lumok felhaszn´l´sa jea o a o a o aa lenti. Tekints¨k az al´bbi p´ld´t: u a e a /* * A PROTOTYPES szimb´olum csak a szabv´anyos C ford´it´ok * sz´am´ara lesz defini´alva: */ #undef PROTOTYPES #ifdef __STDC__ /* Ha ANSI C kompatibilis a ford´it´o */ #define PROTOTYPES 1 /* akkor kell f¨uggv´enyprotot´ipus */ #endif

´ ´ 2.1. AZ ELOFELDOLGOZO HASZNALATA /* A f¨uggv´enydeklar´aci´ok ekkor ´igy n´ezhetnek ki: double mypower( #ifdef PROTOTYPES double, double #endif );

17 */

A fenti m´don defini´lt PROTOTYPES szimb´lumot a f¨ggv´nydefinici´n´l is o a o u e o a felhaszn´ljuk: a /* A mypower f¨uggv´eny r´egi ´es ´uj st´ilus´u definici´oja: double mypower #ifdef PROTOTYPES (double x, double y) /* ´uj st´ilus #else (x, y) double x, y; /* r´egi st´ilus #endif { /* Ide ker¨ul maga a f¨uggv´enyt¨orzs } */

*/ */

*/

2.1.6.

Feladat:

´ Irjunk egy olyan C nyelv faktori´lis-sz´m´ o programot, amelyben a felu a a it´ haszn´l´val val´ kommunik´ci´t a main v´gzi, ´s a faktori´lis ´rt´k´t egy ao o a o e e a e e e saj´t f¨ggv´ny h´ as´val v´gzi! A faktori´lis sz´m´ o f¨ggv´ny ne v´gezzen a u e iv´ a e a a it´ u e e ´ I/O mveletet! Ugy ´ u irjuk meg a f¨ggv´nyeink (main, faktori´lis sz´m´ o) u e a a it´ definici´it, hogy a programunk mind r´gi st´ u C ford´ oval, mind pedig o e ilus´ it´ protot´ ipust ig´nyl ford´ oval leford´ e o it´ ithat´ legyen! Alkalmazzuk a kor´bban o a le´ irtakat! A ford´ ashoz a Unix cc-t, illetve a C++ uzemm´dba kapcsolt it´ ¨ o Borland C++-t haszn´ljuk! a

2.1.7.

Makr´definici´k o o

A #define direkt´ at nemcsak ford´ asvez´rl´sre, illetve szimb´likus konsiv´ it´ e e o tansok defini´l´sra haszn´lhatjuk, hanem param´terekkel rendelkez un. aa a e o ´ makr´k, azaz egyszer rutinok ´ as´ra is. P´ld´ul a math.h szabv´nyos o u ir´ a e a a fejl´cfile-ban defini´lt abs rutin makr´ megval´s´ asa ´ n´z ki: e a o o it´ igy e #define abs((x)) ((x) > 0 ? (x) : (-(x)))

18

2. FEJEZET. BONYOLULTABB SZERKEZETEK

Figyelj¨k meg, hogy a makr´ param´ter´t z´r´jelekkel v´dj¨k. Ez az´rt t¨ru o e e ao e u e o t´nik ´ hogy ¨sszetett kifejez´sekkel megh´ a makr´t, a makr´definic´ e igy, o e iva o o o behelyettes´ ese ut´n se keletkezhessen hib´s kifejez´s (l´sd precedenci´k). it´ a a e a a

2.1.8.

Feladatok: min, max, pow, toupper, tolower

Oldjuk meg a k¨vetkez feladatokat! o o a.) A fenti minta alapj´n k´sz´ uk el a min(a,b), illetve a max(a,b) a e its¨ makr´kat. Irjunk kipr´b´l´ fprogramot e makr´k haszn´lat´hoz! o o ao o o a a b.) Az xy = exp(y · log(x)) osszef¨gg´s felhszn´l´s´val ´ ¨ u e aa a irjuk meg a mypower(x,y) hatv´nyoz´ makr´t! Ugyelj¨nk arra, hogy a makr´ az x = 0 a o o ¨ u o esetre is helyes eredm´nyt (0.0) adjon. Ne feledj¨k, hogy a megold´se u a hoz sz¨ks´ges exp, illetve log f¨ggv´nyek double visszat´r´si ´rt´ku e u e ee e e u ek! (A math.h szabv´nyos fejl´cfile-ban vannak deklar´lva). Irjunk a e a egy keretprogramot, amellyel kipr´b´lhatjuk a saj´t, mypower hatv´o a a a nyoz´ makr´nkat! o o c.) Pr´b´ljuk saj´t makr´k´nt meg´ a ctype.h fejl´cfile-ban defini´lt o a a o e irni e a toupper, illetve tolower rutinokat! Nevezz¨k el a saj´t v´ltozatunkat u a a mytoupper-nek, illetve mytolower-nek. (A param´terk´nt kapott kae e ¨ raktert nagybetre, illetve kisbetre cser´lik.) Ugyelj¨nk arra, hogy u u e u t´nyleg csak a bet¨ karakterek eset´ben kell a konverzi´t elv´gezni. e u e o e A k¨vetkez programp´lda a c.) feladatban eml´ o o e itett toupper, illetve tolower szabv´nyos makr´k haszn´lat´t szeml´lteti: a o a a e /************************************************************ * File: pelda.c * * Tartalom: Kisbetu-nagybetu felcser´elo mintaprogram * *************************************************************/ #include #include /* A modulban defini´alt f¨uggv´enyek: */ void main(void); /* ======================================================== */ void main() { register c; while ((c = getchar()) != EOF) { /* c-be olvasunk, file v´eg´eig */ if (isupper(c)) /* Ha nagybetu, akkor.... */

¨ ´ ¨ ´ 2.2. TOMB-, POINTER- ES FUGGVENYT´ IPUSOK {

19

c = tolower(c); /* .... kisbeture cser´elj¨uk, */ } else /* .... egy´ebk´ent pedig .... */ { c = toupper(c); /* .... nagybeture cser´elj¨uk. */ } /* .............. Az 'if' utas´it´as v´ege ...... */ putchar(c); /* A megv´altoztatott c-t ki´irjuk */ } /* ................... A 'while' ciklus v´ege ....... */ } /* ....................... A 'main' blokk v´ege ......... */ M´dos´ o itsuk teh´t ezt a p´ldaprogramot ugy, hogy a szabv´nyos makr´k a e ´ a o helyett a saj´t makr´inkat haszn´lj´k a karakterkonverzi´ra. a o a a o

2.2.

T¨mb-, pointer- ´s f¨ ggv´nyt´ o e u e ipusok

A C alapt´ ipusaib´l (char, int, float, double) ´s ezek m´dos´ o jelzkkel o e o it´ o k´pzett v´ltozataib´l un. sz´rmaztatott t´ e a o ´ a ipusokat, ´s ezek felhaszn´l´s´val e aa a sz´rmaztatott t´ u t´rol´si egys´geket hozhatunk l´tre. P´ld´ul az int a ipus´ a a e e e a alapt´ ipusb´l l´trehozhatjunk eg´szre mutat´ pointer t´ o e e o ipust, az eg´szt tartale maz´ t¨mb¨k t´ at, illetve eg´szt visszaad´ f¨ggv´nyek t´ at. Ezekket o o o ipus´ e o u e ipus´ a t´ ipusokat felhaszn´lva l´trehozhatunk eg´szre mutat´ pointereket, eg´szt a e e o e tartalmaz´ t¨mb¨ket, eg´sz visszat´r´si ´rt´k f¨ggv´nyeket. o o o e ee e e u u e Egy alapt´ ipusb´l k´tf´lek´ppen hozhatunk l´tre sz´rmaztatott t´ u o e e e e a ipus´ t´rol´si egys´get: a a e 1. vagy a t´rol´si egys´g (v´ltoz´, f¨ggv´ny) deklar´ci´ja sor´n az adott a a e a o u e a o a t´rol´si egys´ggel kapcsolatban adjuk meg, hogy annak t´ a a e ipusa hogy sz´rmaztathat´ a deklar´ci´ alapt´ ab´l, a o a o ipus´ o 2. vagy pedig ´ltal´ban defini´ljuk a sz´rmaztatott t´ a a a a ipust a typedef kulcssz´ seg´ eg´vel, ´s ut´na az ´ l´trehozott uj t´ o its´ e e a igy e ´ ipusba, mint alapt´ ipusba tartoz´ t´rol´si egys´gk´nt deklar´ljuk a k´rd´ses objeko a a e e a e e tumot. P´ld´k az els esetre: e a o double d, dtomb[20], *dmut, dfugg(int); Az alapt´ ipus a double. Ilyen t´ u t´rol´si egys´g a d v´ltoz´ ­ amely, ipus´ a a e a o mint tudjuk, t´rter¨letfoglal´ t´rol´si egys´g. A fenti p´ld´ban 2 tov´bbi a u o a a e e a a t´rter¨letfoglal´ t´rol´si egys´get defini´lunk, ezeknek az azonos´ oi rendre a u o a a e a it´ dtomb, illetve dmut. Az elbbi egy 20 elem double alapt´ u t¨mb, az o u ipus´ o ut´bbi pedig egy double-ra mutat´ (inicializ´latlan) pointer. A fenti p´lo o a e d´ban szerepl utols´ elem ­ a dfunc ­ egy k´dgener´l´ t´rol´si egys´get, a o o o ao a a e

20

2. FEJEZET. BONYOLULTABB SZERKEZETEK

´ Operator ( ) [ ] *

´ Megnevezes f¨ggv´nyt´ u e ipust k´pz oper´tor e o a t¨mbt´ o ipust k´pz oper´tor e o a mutat´t´ o ipust k´pz oper´tor e o a

Jelleg postfix postfix prefix

2.3. t´bl´zat. a a T´ ipusm´dos´ o oper´torok. A precedencia fel¨lrl lefel´ cs¨kken. o it´ a u o e o azaz egy f¨ggv´nyt deklar´l. dfunc "egy double-t visszad´, egy int pau e a o ram´tert v´r´" t´ u f¨ggv´ny azonos´ oja. (Vegy¨k ´szre a k¨l¨nbs´get e a o ipus´ u e it´ u e uo e a definici´ ´s a deklar´ci´ k¨z¨tt: a definici´ l´tre is hozza a t´rol´si egyoe a o o o o e a a s´get, m´ a deklar´ci´ csak azt mondja meg, hogy milyen t´ u az illet e ig a o ipus´ o t´rol´si egys´g ­ egy f¨ggv´ny teljes´rt´k megad´s´hoz a f¨ggv´nyt¨rzsre a a e u e e e u aa u e o is sz¨ks´g lenne.) u e Egy sz´rmaztatott t´ a ipus megad´s´nak a logik´ja a k¨vetkez: megadaa a o o juk a defini´land´/deklar´land´ t´rol´si egys´g alapt´ at (ez itt most a a o a o a a e ipus´ double), majd megadjuk a t´rol´si egys´g azonos´ oj´t, ´s hozz´kapcsolunk a a e it´ a e a egy un. t´ ´ ipusm´dos´ o oper´tort. Term´szetesen egy adott t´rol´si egys´g o it´ a e a a e azonos´ oj´hoz nemcsak egy t´ it´ a ipusm´dos´ o oper´tor kapcsolhat´, hanem o it´ a o t¨bb is: o double d2dimtomb[20][5], **dmutmut, *dmutfunc(int);

Itt d2dimtomb egy 20·5-¨s, 2 dimenzi´s double alapt´ u t¨mb, dmuto o ipus´ o mut egy double-ra mutat´ pointerre mutat´ pointer, dmutfunc pedig egy o o double-ra mutat´ pointer visszat´r´si ´rt´ket ad´, egy int param´terrel o ee e e o e rendelkez f¨ggv´ny. Ez ut´bbi p´lda azt sejteti, hogy nem mindig egyszeo u e o e r dolog egy bonyolultabb sz´rmaztatott t´ u a ipus ´rtelmez´se. Ez egyr´szt a e e e t´ ipusm´dos´ o oper´torok k¨l¨nb¨z precedenci´ja miatt van ´ m´sr´szt o it´ a uo o o a igy, a e a * pointert´ ipust k´pz oper´tor un. prefix oper´tor, m´ a [ ] ´s a ( ) e o a ´ a igy e oper´tor un. postfix oper´tor. a ´ a K¨nnyebben tudunk ¨sszetetteb sz´rmaztatott t´ o o a ipusba tartoz´ t´rol´si o a a egys´geket deklar´lni, ha a typedef kulcssz´ seg´ eg´vel magukat a sz´re a o its´ e a maztatott t´ ipusokat is deklar´ljuk, ´s a bonyolultabb szerkezeteket l´p´srl a e e e o l´p´sre hozzuk l´tre. A typedef haszn´lat´nak ´ltal´nos s´m´ja a k¨vete e e a a a a e a o kez: o ´ ipust mindig valamilyen m´r megl´v t´ Uj t´ a e o ipusb´l (elemi t´ o ipusb´l, struko t´r´kb´l, vagy typedef-fel m´r kor´bban defini´lt t´ ua o a a a ipusb´l) hozhatunk l´to e re ugy, hogy megnevezz¨k az uj t´ ´ u ´ ipust:

¨ ´ ¨ ´ 2.2. TOMB-, POINTER- ES FUGGVENYT´ IPUSOK

21

typedef int ip; Teh´t a fenti p´ld´ban megnevezett uj t´ a e a ´ ipus az ip. Vegy¨k ´szre, hogy u e a fenti t´ ipusdeklar´ci´ olyan, mintha ip "typedef" t´rol´si oszt´ly´ int a o a a a u t´ u v´ltoz´ lenne. Persze nem az, hanem csak az int t´ ipus´ a o ipussal megegyez ´rtelm ujabb t´ oe u´ ipus azonos´ oja. A v´ltoz´deklar´ci´val anal´g logik´t it´ a o a o o a folytatva, alak´ itsuk ´t ip ´rtelmez´s´t. Legyen ip p´ld´ul egy int-re mua e ee e a tat´ pointer t´ anak az azonos´ oja: u ipus´ it´ typedef int *ip; K¨vetkez p´ld´nkban egy eg´sz t´ o o e a e ipust visszaad´, k´t eg´sz param´tert o e e e v´r´ f¨ggv´ny t´ at defini´ljuk: ao u e ipus´ a typedef int ifunc(int, int); Ebbl a t´ o ipusb´l most ­ fenti logik´t k¨vetve, a megfelel t´ o a o o ipusm´dos´ o it´ oper´tor seg´ eg´vel ­ egy pointert´ o a its´ e ipust sz´rmaztatunk: a typedef ifunc *ifuncptr; Megjegyzend, hogy a t´ o ipusm´dos´ o oper´torok a sz´ szorosan vett ´ro it´ a o e telm´ben v´ve nem oper´torok, mert nem valamilyen adathalmazon ´rtele e a e mezett mvelet v´grehajt´s´ra sz´l´ utas´ ast jelentenek, hanem csak a C u e aa oo it´ forr´sprogramok ford´ asakor van szerep¨k. a it´ u Term´szetesen a t´ e ipusm´dos´ o oper´toroknak van v´grehajthat´ mveo it´ a e o u letet jelent p´rjuk. Ezek a * indirekci´ oper´tor, a [ ] indexel oper´tor o a o a o a ¨ ´s a ( ) f¨ggv´nyaktiviz´l´ oper´tor. Osszefoglalva az eddigieket: e u e ao a
Alapt´ ipus´ u t´rol´si egys´g a a e char ch='a'; T´ ipusm´dos´ o o it´ oper´tor a * pointert´ ipust k´pz op. e o ( ) f¨ ggv´nyu e t´ ipust k´pz op. e o [ ] t¨mbo t´ ipust k´pz op. e o Sz´rmaztatott a t´ ipus´ t´rol´si u a a egys´g e char *chp=&ch; pointer int ifv(); f¨ ggv´ny u e float fvek[5]; t¨mb o [ ] indexel´s e ( ) fv.h´ as iv´ Alapt´ ipust k´pz e o oper´tor a * indirekci´ o Alapt´ ipus´ u kifejez´s e ´rtelmez´se e e *chp az a karakter, amire chp mutat (az 'a') i = ifv(); az ifv f¨ ggv´ny u e a ´ltal visszaadott eg´sz e f=fvek[1] fvek[1] egy float sz´m a fvek 2. eleme

int i=100;

float f=3.14;

22

2. FEJEZET. BONYOLULTABB SZERKEZETEK

Megjegyz´sek: e 1. A C-ben a t¨mb¨k indexel´se mindig 0-t´l kezddik. A C-ben nincs o o e o o automatikus indexhat´r ellenrz´s. a o e 2. Egy t¨mbv´ltoz´ azonos´ oja ¨nmag´ban, mint kifejez´s, a t¨mb kezo a o it´ o a e o dc´ et jelenti, teh´t alapt´ o im´ a ipus* t´ u kifejez´s. P´ld´ul a ipus´ e e a char string[ ] = "Ez egy sztring"; definici´j´ karaktert¨mb (melynek m´rete az inicializ´l´ sztringkonsou o e ao tans m´ret´vel fog megegyezni) ugy is felfoghat´, mint egy inicializ´lt e e ´ o a karakterpointer konstans: const char *string = "Ez egy sztring"; ahol a pointerkonstansnak kezd´rt´k¨l a sztringkonstans kezdc´ et oe e u o im´ adtuk. Ezek alapj´n ´ltal´ban ´rtelme van az al´bbiaknak: a a a e a char str1[ ] = "abcdefghijklmnopqrstuvwxyz"; char *str2; char str3[sizeof(str1)/sizeof(char)]; ... str2 = str1; ... *(str3 + 2) = str2[2] = 'C';

Teh´t pointernek t¨mbc´ adhat´ kezd´rt´k¨l, illetve az indexel a o im o oe e u o oper´tor alkalmazhat´ pointerkifejez´sekre is. a o e 3. Ak´r t¨mbv´ltoz´kra, ak´r pointerekre alkalmazhat´ az un. pinteraa o a o a o ´ ritmetika. Muvelet pointer + int pointer - int pointer - pointer ´ Eredmeny pointer pointer int

4. A C-ben a f¨ggv´nyek mindig ´rt´k szerint veszik ´t param´tereiket. u e e e a e Egy f¨ggv´nyparam´terk´nt megadott t¨mb val´j´ban a t¨mb kezdu e e e o oa o o c´ et jelenti. Teh´t p´ld´ul a im´ a e a

¨ ¨ ´ 2.3. KARAKTERTOMBOK ES POINTEREK

23

char *strcpy(char d[ ], char s[ ]); form´j´ f¨ggv´nydeklar´ci´, ´s a au u e a o e char *strcpy(char *d, char *s); form´j´ f¨ggv´nydeklar´ci´ l´nyeg´t tekintve egyen´rt´k. Az els au u e a o e e e e u o esetben tal´n jobban l´tszik, hogy t¨mb¨ket szeretn´nk param´tera a o o e e k´nt ´tadni. e a 5. Egy f¨ggv´nyazonos´ o ¨nmag´ban, mint kifejez´s, a f¨ggv´nyt alkot´ u e it´ o a e u e o ´ programk´d c´ et jelenti. Altal´ban ugy haszn´ljuk, hogy egy f¨ggo im´ a ´ a u v´nyekre mutat´ pointernek adjuk ´rt´k¨l. Erre vonatkoz´ p´ld´t egy e o e e u o e a kicsit k´sbb mutatunk be. eo 6. A t´ ipusm´dos´ o oper´torokra vonatkoz´ ismereteket a 2.3. t´bl´zato it´ a o a a ban foglaltuk ¨ssze. o

2.3.
2.3.1.

Karaktert¨mb¨k ´s pointerek o o e
Feladat: saj´t strcpy a

Pr´b´ljuk meg´ o a irni a string.h szabv´nyos fejl´cfile-ban deklar´lt strcpy a e a f¨ggv´nyt! A f¨ggv´nynek k´t param´tere van, mindkett egy-egy karaku e u e e e o tert¨mb. A f¨ggv´ny feladata, hogy a m´sodik param´terk´nt kapott sztrino u e a e e get az els param´terk´nt kapott t¨mbbe m´solja be. Visszat´r´si ´rt´k¨l o e e o a ee e e u a m´solat sztring c´ et adja! a im´ 1. megold´s: a char *strcpy(char d[ ], char s[ ]) { int i,l; l = strlen(s); for (i = 0; i < l; i++) d[i] = s[i]; return &d[0]; } Itt egyszeren egy szabv´nyos rutinnal (strlen) lek´rdezz¨k a forr´s sztring u a e u a hossz´t, majd egy for ciklust l-szer v´grehajtva karakterenk´nt m´solunk. a e e a ¨ Ugyesebb megold´s, ha kihaszn´ljuk, hogy a sztringek v´g´t mindig az EOS a a e e karakter jelzi. Az EOS figyel´s´vel a sztring hossza ´rdektelenn´ v´lik. Ezt ee e e a

24 szeml´lteti a e

2. FEJEZET. BONYOLULTABB SZERKEZETEK

2. megold´s: a char *strcpy(char d[ ], char s[ ]) { int i; while((d[i] = s[i]) != EOS) i++; return d; } Enn´l jobb megold´st adhatunk, ha kihaszn´ljuk, hogy a t¨mbparam´terek e a a o e a f¨ggv´nyeknak val´j´ban pointerk´nt lesznek ´tadva. u e oa e a 3. megold´s: a char *strcpy(char *d, char *s) { char *p = d; while ((*d = *s) != EOS) { d++; s++; } return p; } V´g¨l azt is kihaszn´lhatjuk, hogy az indirekci´ oper´tora (*) magasabb e u a o a precedenci´j´, mint a pointerekre alkalmazott ++ oper´tor´, tov´bba kiau a e a haszn´lhatjuk az is, hogy az EOS decim´lis ´rt´ke 0, azaz logikai ´rtelema a e e e bem hamis, enn´lfogva a rel´ci´s mveletre nincs is igaz´n sz¨ks´g a while e a o u a u e ciklusb´l val´ kil´p´s el´r´s´hez. o o e e eee 4. megold´s: a char *strcpy(char *d, char *s) { char *p = d; while ((*d++ = *s++)) ; return p; }

¨ ´ 2.4. FUGGVENYPOINTEREK

25

2.3.2.

Feladat: saj´t strlen a

Az elz feladat megold´sa sor´n tett megfontol´sokat alkalmazva pr´b´lo o a a a o a juk mi magunk meg´ irni a string.h-ban deklar´lt strlen f¨ggv´nyt! A a u e f¨ggv´ny bemenpram´terk´nt egy sztring kezdc´ et kapja, visszat´r´si u e o e e o im´ ee ´rt´k¨l a sztring z´r´ EOS n´lk¨li hossz´t adja. e e u ao e u a

2.4.

F¨ ggv´nypointerek u e

F¨ggv´nyekre mutat´ pointerekre sok esetben sz¨ks´g¨nk lehet. Gondolu e o u e u junk csak arra, hogy egy numerikus intger´l´st v´gz rutinnak tetszleges aa e o o integr´land´ f¨ggv´ny eset´ben mk¨dnie kell, lehetleg v´ltoztat´s n´lk¨l. a o u e e u o o a a e u Nos, erre a C kiv´l´ lehets´geket ny´jt. Mieltt azonban egy univerz´lis ao oe u o a integr´l´ rutint ´ ank, tek¨nts¨nk egy egyszerbb p´ld´t. ao irn´ u u u e a Felhaszn´l´s: qsort aa Tegy¨k fel, hogy egy adott t´ u adathalmazt valamilyen szempont szerint u ipus´ rendezn¨nk kell. Legyen ez az adathalmaz mondjuk egy t¨mbben adott. u o Felmer¨lhet benn¨nk, hogy az els f´l´v sor´n megismert valamelyik rendeu u o ee a z algoritmust mi magunk lek´doljuk C-ben, ´s ezzel a probl´ma meg is van o o e e oldva. Nos, ez egy j´rhat´ ut, de k´t ellenvet´s¨nk is lehet. Az egyik az, a o ´ e eu hogy az adatrendez´sre sok elre elk´sz´ e o e itett rutin l´tezik, ugyhogy nagy vae ´ l´szins´ggel idt ´s munk´t pazarlunk a saj´t pr´b´lkoz´sunkkal. A m´sik o ue o e a a o a a a ellenvet´s az lehet, hogy ha m´gis nekil´tunk egy rendez rutin ´ as´nak, e e a o ir´ a nagy val´szins´ggel az ´ltalunk elk´sz´ o ue a e itett v´ltozat t´ls´gosan testreszaa u a bott lesz, azt k´sbb neh´zkes lesz m´s programokban felhaszn´lni. eo e a a Az igzs´g az, hogy az adatrendez´st igen egyszeren megoldhatjuk az a e u stdlib.h szabv´nyos fejl´cfile-ban deklar´lt qsort f¨ggv´ny felhaszn´l´s´a e a u e aa a val. Ez a rutin az ismert quicksort (gyorsrendez) algoritmussal dolgozik. o Protot´ ipusa a k¨vetkezk´ppen n´z ki: o o e e void qsort(void *base, size_t nelem, size_t width, int (*fcmp) (const void *elem1, const void *elem2)); ´ Ertelmezz¨k az egyes param´tereket! Az els param´ter, base a rendezend u e o e o t¨mb kezdc´ o o ime. Mivel tetszleges t´ u adatok j¨hetnek sz´ba, base-t o ipus´ o o '´ltal´nos pointert´ a a ipusunak' (void*) deklar´lt´k. Majd a f¨ggv´nyh´ as a a u e iv´ sor´n nek¨nk kell az un t´ atalak´ o (type cast) oper´torral a mi mutat´a u ´ ipus´ it´ a o t´ ipusunkat void* t´ uv´ alak´ ipus´ a itanunk. A m´sodik param´ter (nelem) ´s a a e e a ipusjel¨l´s. oe harmadik param´ter (width) t´ e ipusa size t. Ez egy szabv´nyos t´ L´nyeg´ben ez egy int, de ez az alternat´ n´v arra h´ e e iv e ivja fel a programoz´ o

26

2. FEJEZET. BONYOLULTABB SZERKEZETEK

figyelm´t, hogy itt az aktu´lis adatt´ e a ipusra vonatkoz´ m´retinform´ci´kat o e a o kell megadni. nelem-ben a rendezend t¨mb m´ret´t kell megadnunk, m´ o o e e ig width-ben egy t¨mbelem m´ret´t v´rja a rutin sizeof egys´gben. A qsort o e e a e rutin utols´ param´tere fcomp. Ez egy f¨ggv´nypointer t´ u param´ter. o e u e ipus´ e Itt egy olyan f¨ggv´ny c´ et kell megadnunk, amelyet a qsort a rendeu e im´ z´s sor´n sz¨ks´ges elem¨sszehasonl´ asok elv´gz´s´re haszn´lhat fel. Ez a e a u e o it´ e ee a f¨ggv´ny eg´sz t´ u visszat´r´si ´rt´ket kell szolg´ltasson. Bemen pau e e ipus´ ee e e a o ram´terk´nt k´t ¨sszehasonlitand´ t¨mbelemre mutat´ pointert kap. A e e e o o o o visszat´r´si ´rt´ket a k¨vetkezk´ppen kell szolg´ltatnia az ¨sszehasonl´ o ee e e o o e a o it´ f¨ggv´nynek: u e -1 0 1 ha *elem1 < *elem2 ha *elem1 == *elem2 ha *elem1 > *elem2

L´ssunk egy p´ld´t a qsort haszn´lat´ra! a e a a a #include #include #include int sort_function (const void *a, const void *b); char list[ ][4] = { "cat", "car", "cab", "cap", "can" }; #define LISTSIZE #define ELEMSIZE int main(void) { int i; sizeof(list)/sizeof(char*) sizeof(list[0])/sizeof(char)

qsort((void*)list, LISTSIZE, ELEMSIZE, sort_function); for (i = 0; i < LISTSIZE; printf("%s\n", list[i++]) ; return 0; } /* ----------------------------------------------------- */ int sort_function(const void *a, const void *b) { return strcmp((char*)a,(char*)b); } /* ----------------------------------------------------- */

¨ ´ 2.4. FUGGVENYPOINTEREK

27

Teh´t a list nev, 4 karakteres sztringekbl ´ll´ t¨mb¨t szeretn´nk n¨a u o a o o o e o vekv sorrendbe rendezni. list els dimenzi´j´nak a meghat´roz´s´t a o o oa a aa ford´ ora b´ it´ izzuk ­ hiszen ez az adat az inicializ´l´ lista alapj´n egy´rtelao a e men kider¨l. Ezt az ´rt´ket a sizeof oper´tor felhaszn´l´s´val ki is sz´u u e e a aa a a moltatjuk, ´s LISTSIZE szimb´lumhoz rendelj¨k, hogy k´sbb egyszeren e o u eo u haszn´lhassuk. Ugyancsak a preprocesszorral sz´moltatjuk ki egy listaelem a a m´ret´t, ´s ezt az ELEMSIZE szimb´lumhoz rendelj¨k. e e e o u Ezeket a hozz´rendel´seket persze megelzte az ¨sszehasonl´ o sort funca e o o it´ tion f¨ggv´ny¨nk deklar´l´sa. Vegy¨k ´szre, hogy e f¨ggv´ny t´ u e u aa u e u e ipusa megegyezik a qsort form´lis param´terlist´j´n szerepl *fcmp t´ aval. a e aa o ipus´ A qsort rutin megh´ asakor csak list-et kellett void* t´ uv´ koniv´ ipus´ a vert´lnunk. Utols´ param´terk´nt szerepel a hasonl´ o f¨ggv´ny cime ­ a o e e it´ u e o e irtakkal. sort function ­ ¨sszhangban az 5. megjegyz´sben le´ Jelen p´ld´nkban a hasonl´ o f¨ggv´nyt igen k¨nnyen elk´sz´ e a it´ u e o e ithett¨k. u Mivel sztringkonstansokat kellett egym´ssal ¨sszehasonl´ a o itanunk, egyszeru en a string.h szabv´nyos fejl´cfile-ban deklar´lt strcmp f¨ggv´nyt hasza e a u e n´lhattuk, mert ennek param´terez´se ´s visszat´r´si ´rt´ke megfelel a qsort a e e e ee e e a ´ltal megk´ antaknak. Tulajdonk´ppen k¨zvetlen¨l is megadhattuk volna iv´ e o u strcmp-t a qsort h´ asakor, de ekkor megold´sunk nem lett volna korrekt: iv´ a *fcmp-n´l void* t´ u bemen param´terek vannak el´ e ipus´ o e oirva, m´ strcmp ig u e u a param´terei char* t´ uak. A mi sort function f¨ggv´ny¨nknek teh´t e ipus´ semmi m´s dolga nincs, mint ezt a t´ a ipuskonverzi´t v´grehajtani. o e Feladat: Defini´ljunk egy tetszleges t´ a o ipust (lehet ak´r a Pascal RECORDa nak megfefl struct is), ebbl hozzunk l´tre egy rendezetlen¨l kit¨lt¨tt o o e u o o t¨mb¨t, majd rendezz¨k a qsort rutinnal. ´ o o u Irjuk meg a rendez´shez sz¨ke u s´ges hasonl´ o f¨ggv´nyt. E f¨ggv´ny m´dos´ as´val v´ltoztassuk meg a e it´ u e u e o it´ a a rendez´si szempontot! e Indirekt f¨ ggv´nyh´ as u e iv´ L´ttuk, hogy a f¨ggv´nypointerek haszn´lata nagy flexibilit´st tud k¨lcs¨a u e a a o o n¨zni k´sz rutinok sz´m´ra. Ezt haszn´ljuk ki arra, hogy egy integr´l´ o e a a a ao f¨ggv´nyt ´ u e irjunk a f´l´v elej´n megismert valamelyik numerikus integr´l´ ee e ao algoritmus felhaszn´l´s´val. Az integr´l´ f¨ggv´ny deklar´ci´ja a k¨vetkez aa a ao u e a o o o legyen: double integration(double a, double b, int n, double (*f)(double x)); ´ Irjunk olyan fprogramot, amely egy-k´t ismertebb f¨ggv´nyoszt´lyba taro e u e a toz´ f¨ggv´ny integr´lj´t sz´molja ki! A sz¨ks´ges fprogram egy lehets´ges o u e a a a u e o e megval´s´ as´t a k¨vetkez oldalon tal´lhatjuk. Tekints¨k ´t alaposan ezt o it´ a o o a u a

28

2. FEJEZET. BONYOLULTABB SZERKEZETEK

a list´t. Pr´b´ljuk meg´rteni tpedef utas´ asokat, illetve az integrandusz a o a e it´ f¨ggv´nyek deklar´l´s´nak kiss´ szokatlan m´dj´t. (Ez ut´bbival kapcsou e aa a e o a o latban tess´k arra gondolni, hogy a t´ e ipusm´dos´ o oper´torokkal kapcsolato it´ a ban le´ logik´t k¨vetve, a k´dgener´l´ t´rol´si egys´geket ­ a f¨ggv´nyeirt a o o ao a a e u e ket ­ ugyan´gy deklar´ljuk, mint a t´rter¨letfoglal´ t´rol´si egys´geket. u a a u o a a e Ha teh´t a double-t visszaad´, egy doble param´tert v´r´ f¨ggv´ny t´ a o e a o u e ipust typedef-fel defini´ljuk ­ ez a mi eset¨nkben a dfunc t´ a u ipus ­ akkor ennek felhaszn´l´s´val t´rol´si egys´geket deklar´lhatunk. Megjegyzend, hogy aa a a a e a o f¨ggv´nydefinici´t m´r nem v´gezhet¨nk typedef-fel defini´lt f¨ggv´nyt´ u e o a e u a u e ipus seg´ eg´vel. its´ e #include typedef double dfunc(double x); typedef dfunc *dfp; /* ----------------------------------------------------double integration(double, double, int, dfp); /* ----------------------------------------------------dfunc expon, /* a+b*exp(c*x) power, /* a*x^y sinus, /* a+b*sin(c*x+d) polin; /* a+b*x+c*x^2+d*x^3 /* The same as

*/ */ */ */ */ */

double expon(double x), power(double x), sinus(double x), polin(double x); */ /* ----------------------------------------------------- */ dfp functions[ ] = { expon, power, sinus, polin }; char *fstrings[ ] = { "a+b*exp(c*x)", "a*x^y", "a+b*sin(c*x+d)", "a+b*x+c*x^2+d*x^3" }; double a = 0, b = 0, c = 0, d = 0; /* ----------------------------------------------------- */ int main(void) { int i = -1; double xa, xb; while ((i < 0)||(i > 3)) { printf("0 - %s\n1 - %s\n2 - %s\n3 - %s\n\n", fstrings[0],fstrings[1],fstrings[2],fstrings[3]); scanf("%d",&i); putchar('\n'); } switch(i) {

¨ ´ 2.4. FUGGVENYPOINTEREK case 2: case 3: printf("d="); scanf("%lf",&d); case 0: printf("c="); scanf("%lf",&c); printf("b="); scanf("%lf",&b); case 1: printf("a="); scanf("%lf",&a);

29

putchar('\n'); putchar('\n'); putchar('\n'); putchar('\n');

} printf("xa="); scanf("%lf",&xa); putchar('\n'); printf("xb="); scanf("%lf",&xb); putchar('\n'); printf("\nIntegral of %s = %12.5g\n",fstrings[i], integral(xa,xb,50,functions[i])); } /* ----------------------------------------------------- */ double polin(double x) { return a + b*x + c*x*x + d*x*x*x; } ... /* ----------------------------------------------------- */ double integration(double a, double b, int n, double (*f)(double x)); { double integr, x, dx; for (integr = 0, x = xa, dx = (xa-xb)/n; n; n--, x+=dx) { integr += (*f)(x) * dx; } return integr; } /* ----------------------------------------------------- */ Feladatok: Integr´l´s f¨ ggv´nypointerrel adott integranduszokaa u e kal a) Dolgozzuk ki teljesen az integr´l´ programot, futtassuk le! ao b) Bv´ uk az integr´lhat´ f¨ggv´nyoszt´lyok halmaz´t! o its¨ a o u e a a c) Alak´ itsuk ´t a programot ugy, hogy az integration f¨ggv´ny egy a ´ u e tov´bbi int t´ u param´ter´vel v´laszthassunk k¨l¨nb¨z integr´a ipus´ e e a uo o o a l´si m´dszerek k¨z¨tt. Ezt szint´n indirekt (f¨ggv´nypointer t¨mb¨n a o o o e u e o o kereszt¨l t¨rt´n) f¨ggv´nyh´ assal val´s´ u o e o u e iv´ o itsuk meg!

30

2. FEJEZET. BONYOLULTABB SZERKEZETEK

2.5.

T¨bb modulb´l ´ll´ programok k´sz´ ese o o a o e it´

Az elz feladatok megold´sokar feltnhetett, hogy milyen buta dolog az, o o a u ha olyan m´dos´ asokat v´gz¨nk, aminek semmi k¨ze az integration f¨ggo it´ e u o u v´nyhez, azt akkor is ujra kell ford´ e ´ itanunk a val´szinleg szint´n v´ltozatlan o u e a main-nel egy¨tt. Vagy ha a numerikus integr´l´st v´gz f¨ggv´nyek k¨ru aa e o u e o ny´k´n t¨rt´nt v´ltoz´s, akkor az integr´land´ f¨ggv´nyeket ford´ e e o e a a a o u e itjuk ujra. ´ Ezen csak ugy tudunk v´ltoztatni, ha a forr´s´llom´nyunkat hat´kony ´ a aa a e m´don atszervezz¨k: t¨bb, egym´st´l f¨ggetlen¨l ford´ o ´ u o a o u u ithat´ modulra bonto juk, ´s a v´gs futtathat´ program ¨ssze´ll´ as´t az adott C nyelvi rendszer e e o o o a it´ a linkel programj´ra b´ o a izzuk. Milyen r´szekre ´rdemes bontani a programune e kat? C´lszer az al´bbi feloszt´st k¨vetni: e u a a o · mainint.c A main f¨ggv´nyt (fprogramot) tartalmazza. u e o · myfunc.c A saj´t, integr´land´ f¨ggv´nyek (p´ld´ul polin, expon, a a o u e e a stb) definic´it tartalmazza. o · numint.c A numerikus integr´l´s f¨ggv´nyeit (a k¨ls modulokkal aa u e u o kapcsolatot tart´ integration f¨ggv´nyt, valamint az egyes bels o u e o integr´l´ f¨ggv´nyeket ­ ilyen lehet mondjuk egy simpson nev f¨ggao u e u u v´ny) tartalmazza. e · myvars.c A t¨bb modul ´ltal is haszn´lt publikus glob´lis v´ltoz´k o a a a a o definici´it tartalmazza. o M´r majdnem optim´lis a forr´sp´llom´ny feloszt´sa. A fenti feloszt´s a a a a a a a t´nyleg a program optim´lis modulstrukt´r´j´nak felel meg, de a forr´s´lloe a uaa aa m´nyt m´g c´lszer tov´bb tagolni. Ennek a tov´bbi tagol´snak a c´lja az, a e e u a a a e hogy minden .c kiterjeszt´s file-b´l gener´lt modul ugyanazokat a deklaeu o a r´ci´kat l´ssa, illetve az egyes modulok ezen dekl´r´ci´k utj´n kapcsolatban a o a aa o a legyenek egym´ssal. Igy a k¨vetkez un. deklar´ci´s fejl´cfile-okat c´lszer a o o´ a o e e u m´g l´trehozni: e e · mytypes.h A saj´t t´ a ipusdefinici´inkat (dfunc, dfp tartalmazza. Ezt o minden .c forr´s´llom´ny elej´re ´p´ uk be az #include "mytypes.h" aa a e e its¨ preprocesszor utas´ assal! it´ · myfunc.h Az egyes .c ´llom´nyokban defini´lt publikus f¨ggv´nyek a a a u e extern deklar´ci´it tartalmazza. Ezt minden forr´s´llom´ny elej´re, a o aa a e a mytypes.h ut´n ´p´ uk be az #include "myfunc.h" preprocesza e its¨ szor utas´ assal! it´

¨ ´ ´ ´ ´ IT ´ 2.5. TOBB MODULBOL ALLO PROGRAMOK KESZ´ ESE

31

´ Elettartam statikus statikus statikus dinamikus

L´that´s´g a oa glob´lis a modulra lok´lis a blokkra lok´lis a blokkra lok´lis a

Deklar´tor helye a b´rmely modulban a minden blokkon k´ ul iv¨ adott modulban minden blokkon k´ ul iv¨ adott blokkban adott blokkban

T´rol´si oszt´ly a a a extern static static auto, register

2.4. t´bl´zat. V´ltoz´k ´lettartama, l´that´s´ga ´s t´rol´si oszt´lya a a a o e a oa e a a a · myvars.h A myvars.c ´llom´nyban defini´lt publikus glob´lis v´la a a a a toz´k extern deklar´ci´it tartalmazza. Ezt minden f¨ggv´nyeket deo a o u e fini´l´ forr´s´llom´ny elej´re, a myfunc.h ut´n ´p´ uk be az #incao aa a e a e its¨ lude "myvars.h" preprocesszor utas´ assal! it´ A v´ltoz´dejklar´ci´k, illetve definici´k helyes kialak´ as´ban ny´jthat a o a o o it´ a u seg´ eget a t´rol´si oszt´lyokat ¨sszefoglal´ 2.4 t´bl´zat. its´ a a a o o a a Feladat: A fenti elveknek megfelen szervezz¨k ´t programunkat, k¨o u a u l¨n-k¨l¨n ford´ o uo itsuk le az egyes .c forr´smodulokat, majd linkelj¨k ¨ssze a u o a programot.

32

2. FEJEZET. BONYOLULTABB SZERKEZETEK

3. fejezet

A dinamikus t´rkezel´s a e alapjai
3.1. Dinamikus adatok

Pointereknek ´rt´k¨l eddig vagy egy v´ltoz´ c´ et adtuk (a & ­ address of e e u a o im´ oper´tor seg´ eg´vel), vagy egy t¨mb kezdc´ et. Azt is l´ttuk, hogy nincs a its´ e o o im´ a elvi k¨l¨nbs´g egy t¨mbv´ltoz´ ´s egy azonos alapt´ uo e o a oe ipusba tartoz´ pointer o k¨z¨tt. A gondot csak az jelenthette, hogy a C t¨mb¨k m´rte ­ hasonl´an o o o o e o a Pascal t¨mb¨k´hez ­ a deklar´ci´kor (ak´r ´ltalunk explicit m´don, ak´r o o e a o a a o a egy inicializ´l´ kifejez´s ´ltal implicit m´don) megadott, k¨t¨tt ´rt´k. Hogy ao e a o oo e e ´ irjunk ekkor olyan programot, amelyik mindig csak akkora t¨mb¨ket haszo o n´l, emekkor´kra t´nylegesen sz¨ks´g van a programfut´s sor´n, ´s a m´r a a e u e a a e a nem sz¨ks´ges t¨mb¨k ´ltal elfoglalt mem´riater¨letet fel is szabad´ u e o o a o u itja? A fenti probl´m´t sz´munkra az stdlib.h szabv´nyos fejl´c file-ban e a a a e deklar´lt malloc mem´riafoglal´, illetve a free mem´riafelszabad´ o f¨gga o o o it´ u v´nyek oldj´k meg. E f¨ggv´nyek protot´ e a u e ipusai ´ n´znek ki: igy e #include void *malloc(int size); void free(void*); A malloc f¨ggv´ny size darab byte t´rol´s´ra szolg´l´ mem´riater¨letet u e a aa ao o u k´r az oper´ci´s rendszertl. Ha a k´r´s teljes´ e a o o ee ithet, akkor lefoglalja az o adott mem´riablokkot, ´s visszat´r´si ´rt´k¨l egy, a blokkra mutat´ ´ltao e ee e e u oa l´nos t´ u (void*) pointer ´rt´ket ad. Ha a mem´riafoglal´si k´r´s nem a ipus´ e e o a ee teljes´ ithet, visszat´r´si ´rt´k¨l NULL-t kapunk. A C-ben a NULL ugyanazt u ee e e u 33

34

´ ´ 3. FEJEZET. A DINAMIKUS TARKEZELES ALAPJAI

jelenti, mint a Pascal-ban a NIL: azaz ez a sehova se mutat´ pointer, amely o minden ´rv´nyes mem´riac´ ol egy´rtelmen megk¨l¨nb¨ztethet. e e o imt e u uo o o Tekints¨nk egy p´ld´t! Kesz´ unk egy n m´ret double t´ u t¨mb¨t! u e a its¨ e u ipus´ o o A t¨mb m´ret´t a felhaszn´l´ adja meg! o e e ao #include ... int n; double *tombmut; ... printf("Size="); scanf("%d",&n); putchar('\n'); tombmut = (double*) malloc(n * sizeof(double)); if (tombmut == NULL) { printf("Unable to allocate for %d double numbers!\n",n); exit(1); } ... for (i = 0; i < n; i++) { tombmut[i] = 0.0; } ... free(tombmut); ... A fenti p´ld´ban a k¨vetkez ´rdekesebb megold´sokat alkalmaztuk. e a o oe a 1. Elsz¨r is a malloc ´ltal visszaadott pointer kifejez´s t´ at az un. o o a e ipus´ ´ type-cast oper´torral olyan t´ uv´ alak´ a ipus´ a itottok, amilyen t´ u ponipus´ terre konkr´tan sz¨ks´g¨nk van. A type-cast oper´tor ´ltal´nos alake u e u a a a ja: (´j t´ u ipus). Hat´sa az, hogy operandus´nak t´ at uj t´ a a ipus´ ´ ipuss´ a alak´ itja. A mi konkr´t eset¨nkben az ´ltal´nos mutat´t´ e u a a o ipusb´l, a o void*-b´l csin´ltunk double-ra mutat´ t´ o a o ipust double*-ot. 2. A malloc sz´m´ra meg kell adnunk a lefoglaland´ mem´riablokk a a o o byte-okban kifejezett m´ret´t. A felhaszn´l´t´l mi csak a t¨mb logikai e e ao o o m´ret´t k´rdezz¨k meg (ez az n), a t´nyleges fizikai m´ret meg´llae e e u e e a p´ as´hoz a logikai m´retet meg kell szorozni a t¨mb alapt´ anak it´ a e o ipus´ byte-okban kifejezett m´ret´vel. Ez ut´bbi adatot a sizeof oper´e e o a torral ´ll´ a itottuk el. o

3.1. DINAMIKUS ADATOK

35

3. Term´szetesen a malloc ´ltal visszaadott pointer-kifejez´st meg kell e a e vizsg´lnunk, hogy nem NULL-e? Ha NULL, akkor a mem´riafoglal´si a o a k´relem nem volt teljes´ e ithet. Ez sokszor fat´lis programfut´si hib´t o a a a jelez, ´ a megfelel hiba¨zenet kirat´sa ut´n az exit f¨ggv´ny feligy o u a a u e haszn´l´s´val f´lbeszak´ aa a e itjuk a programfut´st, ´s az oper´ci´s rendszer a e a o sz´m´ra egy megfelel hibak´dot ´tadunk. (Ezt a k´dot megvizsg´la a o o a o a hatja a programot aktiviz´l´ parancs-file, vagy batch-file.) Vegy¨k ao u ´szre, hogy a Pascal NIL-hez hasonl´an a NULL tetszleges pointer-t´ e o o ipussal kompatibilis. 4. Ha sikeres volt a mem´riafoglal´s, akkor a malloc ´ltal visszaadott, ´s o a a e megfel t´ uv´ alak´ o ipus´ a itott pointerkifejez´sre ugy tekinthet¨nk, mint e ´ u egy t¨mb b´zisc´ ere, ´ ak´r indexelhetj¨k is, mint az igazi t¨mo a im´ igy a u o b¨ket. (Annyi a k¨l¨nbs´g az igazi t¨mb¨kh¨z k´pest, hogy tombmut o uo e o o o e ´rt´ke megv´ltoztathat´. e e a o 5. Egy C program mem´ria-haszn´lata att´l lesz igaz´n dinamikus, hogy o a o a a nem haszn´lt mem´raietr¨letek felszabad´ a program. A mi egya o u itja szer p´ld´nkban ezt az utols´ utas´ as, a free(tombmut) v´gzi el. u e a o it´ e Fontos, hogy ha a free f¨ggv´nynek nehogy NULL ´rt´k pointer-kiu e e e u fejez´st adjunk ´t, mert k¨l¨nben "elsz´llhat" a programunk. e a uo a

3.1.1.

Feladat: line´ris egyenletrendszer megold´sa a a

Irjunk egy line´ris egyenletrendszer megold´s´ra alkalmas programot! A a aa program k´rdezze meg az ismeretlenek sz´m´t, ´s fut´si idben foglajon e a a e a o helyet az egy¨tthat´ m´trixnak, a konstans vektornak, illetve az ismeretleu o a nek vektor´nak! Az eredm´nyek kiirat´sa ut´n, de m´g a visszat´r´s eltt a e a a e ee o szabad´ itsuk fel a lefoglalt mem´ri´t! o a Seg´ eg a megold´shoz: its´ a C´lszer egy m´r l´tez programot (ak´r Pascal, ak´r C) ´t´ e u a e o a a a irni, illetve m´o dos´ itani. A vektorok sz´m´ra a helyfoglal´st a bevezet isemertet alapj´n a a a o o a k¨nnyen megval´s´ o o ithatjuk. Gondot csak a 2 dimenzi´s egy¨tthat´ m´trix o u o a jelenthet. Tegy¨k f¨l, hogy statikus helyfoglal´s eset´ben a m´trix deklau o a e a r´ci´ja a k¨vetkez: a o o o #define N 3

double amat[N][N]; Az amat t¨mb¨t ugy is felfoghatjuk, mintha az al´bbi m´don lenne deklao o ´ a o r´lva: a

36 #define N

´ ´ 3. FEJEZET. A DINAMIKUS TARKEZELES ALAPJAI 3

double sor0[N], sor1[N], sor2[N]; double *amat[] = { sor0, /* ez mind double* tipusu */ sor1, sor2 }; azaz amat nem m´s, mint double* t´ u pointerek t¨mbje. Itt m´g mina ipus´ o e den statikus ­ az egyes sorok m´rt´t explicit m´don defini´ltuk, m´ amat e e o a ig m´ret´t implicit m´don, az inicializ´l´ kifejez´s adja meg. L´tjuk teh´t, e e o ao e a a hogy amat egy double-ra mutat´ pointerek t¨mbj´nek kezdcime, maga is o o e o egy ­ igaz, konstans ­ pointer, olyan, mintha double** t´ unak deklar´lipus´ a tuk volna. Ennek alapj´n fel´ a irhatjuk most m´r a dinamikus helyfoglal´sra a a alkalmas deklar´ci´t is: a o double** amat; /* Sehova nem mutat, de majd fog! */

Maga a dinamikus helyfoglal´s k´t r´szbl rakhat´ ¨ssze. Elsz¨r az amat a e e o oo o o nev, n elem (n fut´si idben megadott eg´sz param´ter ­ az aktu´lis u u a o e e a ismeretlenek sz´ma) duplapontoss´g´ val´s sz´mokra mutat´ pointerek t´a a u o a o a rol´s´r szolg´l´ t¨mb¨t hozzuk l´tre az amat = ((double*)*) malloc(n aa ao o o e * sizeof(double*)); utas´ssal, majd minden egyes sor sz´m´ra foglaa a a lunk helyet. P´ld´ul az i-edik sort az amat[i] = (double*) malloc(n * e a sizeof(double)); utas´ assal hozhatjuk l´tre. it´ e A m´trix ´ltal elfoglalt mem´riater¨let felszabad´ asakor ford´ a a o u it´ itott sorrendet kell k¨vetn¨nk. Elszor az egyes sorokat szntetj¨k meg, majd o u o u u mag´t az amat t¨mb¨t. a o o Fontos figyelmeztet´sek: e 1. Att´l, hogy egy pointert deklar´ltunk, m´g nem lesz ´rt´ke, ´ sehoo a e e e igy va sem mutat! 2. Att´l, hogy egy pointernek van ´rt´ke, azaz mutat valahov´, m´g mino e e a e dig nem biztos, hogy ´rv´nyes mem´ria-ter¨letre mutat. Azt a mee e o u m´riater¨letet, ahov´ egy pointerrel mutatni szeretn´nk, LE KELL o u a e FOGLALNI! 3. A C-ben az indexel´s 0-t´l indul, ´s t¨mbm´ret - 1-ig tart. A t¨mbt´le o e o e o u c´ es miatt nem sz´l a ford´ o, legfeljebb elsz´ll a program. Komoimz´ o it´ a lyabb oper´ci´s rendszerekben (VMS, UNIX) maga az oper´ci´s renda o a o szer figyelmeztet arra, hogy ´rv´nytelen mem´ric´ e e o imre hivatkozunk.

3.1. DINAMIKUS ADATOK

37

´ Altal´ban access violation hiba¨zenet ´s rutin-h´ asi lista (symbolic a u e iv´ stack dump) kis´ret´ben a programfut´st megszak´ e e a itja az oper´ci´s a o rendszer. Sajnos a DOS ilyesmire nem figyel!

38

´ ´ 3. FEJEZET. A DINAMIKUS TARKEZELES ALAPJAI

4. fejezet

Az oper´ci´s rendszerrel a o val´ kapcsolat o
4.1. Folyam jelleg I/O u

Tekints¨k a kor´bbr´l m´r ismert, a szabv´nyos bemeneti ´llom´nyt a szabu a o a a a a v´nyos kinenetre m´sol´ programot! a a o #include main() { int ch;

/* int and char are compatible */

ch = getchar(); while (ch != EOF) { putchar(ch); ch = getchar(); } } Most m´r tudjuk, hogy itt egyszeren arr´l van sz´, hogy az stdin elre a u o o o defini´lt folyamb´l az stdout elre defini´lt folyamra m´solunk. Ezek a a o o a a folyamok ­ hacsak az oper´ci´s rendszer szintj´n ´t nem ir´ny´ a o e a a itottuk ket o ­ a billentyzethez, illetve a termin´lk´pernyh¨z vannak hozz´rendelve. u a e o o a 39

´ ´ ´ 404. FEJEZET. AZ OPERACIOS RENDSZERREL VALO KAPCSOLAT

4.1.1.

Feladatok: File-ok m´sol´sa a a

a) Alak´ itsuk ´t a fenti programot ugy, hogy a getchar, illetve a puta ´ char rutinok helyett az int fgetc(FILE *stream), illetve az int fputc(int c, FILE *stream) deklar´ci´j´ f¨ggv´nyekkel kezelj¨k a ou u e u az stdin-t ´s az stdout-ot! e b) Alak´ itsuk ´t az a) pont szerint kidolgozott programot ugy, hogy az a ´ INPUT.TXT fizikai ´llom´nyt az OUTPUT.TXT fizikai ´llom´nyba m´a a a a a soljuk at. (Feltehetj¨k, hogy mindk´t ´llom´ny az akt´ k¨nyvt´rban ´ u e a a iv o a van.)

4.1.2.

File-nyit´si hib´k, azok kezel´se a a e

Az elz b) feladat megold´sa sor´n felmer¨lhet a k´rd´s: mi van akkor, o o a a u e e ha az input adat´llom´ny nem l´tezik? Nos, ez k¨nnyen ellenrizhet. Ezt a a e o o o szeml´ltetj¨k az al´bbi programr´szlettel: e u a e #include ... FILE *finp; char inpfname[80]; ... printf("Name of the input file="); scanf("%s%,inpfname); putchar('\n'); ... finp = fopen(inpfname,"r"); if (finp == NULL) { printf("File %s does not exist!\n",inpfname); } A mechanizmus hasonl´, mint amit a dinamikus t´rfoglal´sn´l k¨z¨lt progo a a a o o ramr´szletn´l l´thattunk. A felhaszn´l´t´l bek´rj¨k a megfelel param´tert e e a ao o e u o e ­ ez itt a file neve; az ´ megadott sztring az adott oper´ci´s rendszerben igy a o ´rv´nyes teljes file-specifik´ci´ lehet (drive, directory, filename, extension, e e a o version ugy, ahogy azt az oper´ci´s rendszer megk´ anja). Ezut´n k¨vet´ a o iv´ a o kezik az oper´ci´s rendszerrel t¨rt´n kapcsolatfelv´tel. Most mem´riafoga o o e o e o lal´s helyett file-hozz´rendel´s t¨rt´nik. Az ezir´ny´ rendszer-szolg´ltat´s a a e o e a u a a ig´nybev´tel´nek eredm´ny´t term´szetesen mindig meg kell vizsg´lnunk: e e e e e e a siker¨lt-e l´trehoznunk azt, amit akartunk. Most azt n´zz¨k meg, hogy u e e u sikeres volt-e a file-megnyit´s. Ha igen, akkor az un. file-pointer nem NULL a ´ ´rt´ket kap, ha sikertelen volt, akkor NULL lesz az ´rt´ke. e e e e

4.2. A MAIN ARGUMENTUMAI

41

A sikertelen file-megnyit´snak k¨l¨nb¨z oka lehet, a leggakoribb azona uo o o ban az, hogy az olvas´sra megnyitott file nem l´tezeik. A hiba pontos ok´r´l a e ao is szerezhet¨nk inform´ci´t, de ennek t´rgyal´s´ra nem futja az idnkbl. u a o a aa o o A l´nyeg az, hogy minden un. file-megnyit´s eredm´ny´t meg kell vizsg´le ´ a e e a nunk! (Ugyan´ igy, ha ´ asra nyitunk meg egy file-t, akkor is elk´pzelhet, ir´ e o hogy NULL-t kapunk visszat´r´si ´rt´k¨l; p´ld´ul akkor, ha neml´tez k¨nyvee e e u e a e o o t´rra hivatkztunk a file-specifik´ci´ban.) a a o Feladat: M´dos´ o itsuk a file-m´sol´ programunkat ugy, hogy mind az ina o ´ put, mind az output file nev´t a felhaszn´l´ adja meg. K´sz¨lj¨nk fel arra, e ao e u u hogy esetleg hib´s file-specifik´ci´t ad meg a felhaszn´l´! a a o ao

4.2.

A main argumentumai

A main f¨ggv´nynek elre defini´lt argumentumai lehetnek ­ ezek az opeu e o a r´ci´s rendszer ´ltal a programnak ´tadott param´terek: a o a a e main(argc, argv) int argc; char *argv[]; Az argc azt mutatja meg, hogy az oper´ci´s rendszer parancs´rtelmezj´ben a o e oe h´ny param´tert adtunk ´t a programnak. Ezek a param´terek mindig a e a e sztringk´nt ker¨lnek ´tad´sra, a main m´sodik argumentuma, argv rendre e u a a a ezekre a sztringekre mutat. Megjegyzend, hogy argv[0] mindig a proo gram nev´t tartalmazza (teljes file specifik´ci´val), ´s ennek megfelelen e a o e o argc ´rt´ke mindig legal´bb 1. Ha teh´t a DOS-ban a myprog.exe, C e e a a nyelven meg´ program a C:\mydir k¨nyvt´rb´l lett beh´ akkor a proirt o a o iva, gramon bel¨l argv[0] ´rt´ke C:\MYDIR\MYPROG.EXE" lesz. u e e

4.2.1.

Feladat: A copy parancs ­ saj´t kivitelben a

Alak´ itsuk ´t a file-m´sol´ programot ugy, hogy els parancs-sor param´terek´nt a a o ´ o e e a forr´s-file nev´t, m´sodik param´terk´nt pedig a c´l-file nev´t vegye ´t a e a e e e e a ´ az oper´ci´s rendszertl. A program neve legyen mycopy! Ugy ´ a o o irjuk meg a mycopy programot, hogy ha 0 param´terrel h´ ak meg (azaz argc == e ivt´ 1), akkor egy r¨vid helpet ´ o irjon ki a k´pernyre a hiv´si m´dj´r´l, majd a e o a o ao From: k´rd´ssel k´rdezze meg az input file nev´t, a To: prompttal pedig az e e e e output file nev´re k´rdezzen r´. Ha a felhaszn´l´ a From: file-t a parance e a ao ssorban megadta, ´s csak a To: file hi´nyzik (argc == 2), akkor csak arra e a

´ ´ ´ 424. FEJEZET. AZ OPERACIOS RENDSZERREL VALO KAPCSOLAT kell r´k´rdezni. Minden esetben ellenrizz¨k, hogy l´tezik-e a From: file! a e o u e (A joker karakterek, illetve a r´szleges output file specifik´ci´ kezel´s´tl e a o eeo eltekintve ez a mycopy program a UNIX cp, illetve a VMS ´s a DOS 5.0 e copy parancs´nak a kever´ke.) a e Fontos megjegyz´s a VMS-ben dolgoz´k sz´m´ra! A VMS els e o a a o k¨zel´ esben nem t´mogatja, hogy a felhaszn´l´i programoknak parancs-sor o it´ a ao param´tereket adhassunk ´t. Ez azt jelenti, hogy a parancs-sor param´tereket e a e v´r´ programok a VMS RUN parancs´val nem futtathat´k. A dolog m´gsem ao a o e katasztr´f´lis: term´szetresen lehtes´g van a C konvenci´ szerinti parancsoa e oe o sor param´terek ´tad´s´ra is. A fenti myprog program futtat´sa eltt adjuk e a aa a o ki a myprog:=="myprog.exe" parancsot a VMS-nek Ezut´n egyszeren a myprog from.txt to.txt bea u g´pel´s´re a myprog program megkapja a parancs-sor param´tereket, ´ a e ee e igy from.txt file-t a to.txt ´llom´nyba prob´lja ´tm´solni ­ felt´ve persze, a a a a a e hogy maga a C program hibamentes!

5. fejezet

Fejlettebb technik´k a
5.1.
5.1.1.

Strukt´ r´k ­ l´ncolt lista u a a
Fealadat: L´ncolt lista k´sz´ ese a e it´

Oldjuk meg C-ben a k¨vetkez feladatot! Egy l´git´rsas´g sz´m´ og´pen o o e a a a it´ e t´rolja az utaslist´kat. Az ¨sszes´ a a o itett ´llom´ny (UTAZAS.DAT) minden utas a a minden utj´r´l egy-egy bejegyz´st tartalmaz. Egy bejegyz´s szerkezete a ´ ao e e k¨vetkez: o o J´rat sz´ma a a D´tum a Utas neve L´gi km e Jelleg ­ ­ ­ ­ ­ 8 karakter 6 karakter 32 karakter eg´sz sz´m e a Szolg´lati vagy Egy´ni a e

K´sz´ e itsen olyan programot, amely kikeresi, ´s a TORZS.DAT nev sz¨veges e u o a ´llom´nyba ki´ a mag´n´ton legt¨bbet rep¨lt k´t utas nev´t, valamint a irja a u o u e e legut´bbi utjuk d´tum´t. A bemen ´llom´nyt a fscanf f¨ggv´nnyel olvassa, o ´ a a oa a u e a kimen allom´nyba sz´pen tabul´lva az fprintf f¨ggv´nnyel ´ o´ a e a u e irjon. A bemen ´llom´ny m´gnes-szalagon van, ´ csak egyszer olvashat´ be. (P´ld´ul oa a a igy o e a egy VAX-on az MSA0: nev eszk¨z¨n ­ a szalagegys´gen ­ tal´lhat´ az u o o e a o UTAZAS.DAT ´llom´ny.) a a Seg´ eg a megold´shoz: Nyilv´nval´, hogy az input file-b´l valamilyen its´ a a o o struc t´ u (a Pascal RECORD-nak megfelel) adatokb´l k´pzett l´ncolt ipus´ o o e a list´ba kell beolvasnunk az utasok adatait. Az´rt kell a dinamukis adatkezel´s, a e e mert az input file-t csak egyszer olvashatjuk be, nem tudjuk a m´ret´t, vise e zont a m´r beolvasott adatokkal rendszeresen ¨ssze kell hasonl´ a o itanunk az 43

44

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK

uj´lag beolvasott adatokat. N´zz¨k a sz¨ks´ges adatstrukt´r´t! -- ´o e u u e ua typedef enum trtyp {private, buisness} travel; typedef struct flgt { flgtno; /* date[7]; /* name[32];/* flghtkm; /* type; /* *nextrec,/* *prevrec;/* } psngr_rec; int char char int travel flgt flight number */ date of the flight */ passenger's name */ flight km */ 0:prv 1:bsns */ ->nxt record in lst*/ ->prv record in lst*/

Figyelj¨k meg, mennyivel vil´gosabb a lista-szerkezet definic´ja a C-ben, u a o mint a Pascal-ban! A C az enum, illetve struct t´ ipusok deklar´ci´jakor a o megengedi az un. t´ ´ ipusc´ imke megad´s´t. A dolog l´nyege az, hogy a aa e t´ ipusc´ imke a t´ ipusdefinici´s blokkot p´tolhatja. Ezt haszn´lhatjuk ki akkor, o o a amikor listaszerkezetek kialak´ as´ra szolg´l´ ¨nhivatkz´ adatstrukt´r´kat it´ a aoo o ua hozunk l´tre. A mi p´ld´nkban a nextrec, illetve prevrec olyan pointer e e a ua ipus´ t´ u mezi a psngr rec strukt´r´nak, amelyek psngr rec t´ u adatokipus´ o tra k´pesek mutatni. e Egy uj rekord beolvas´sa: ´ a psngr_rec int FILE *actptr, *wrkptr; typ, endflag; *finput; /* File pointer to UTAZAS.DAT eg. on tape device EET751::MSA0: */

... /* We assume that actptr points to a valid data field */ endflag = 5; while (endflag == 5) { workptr = (psngr_rec*)malloc(sizeof(psngr_rec)); if (workptr == NULL) { printf("Error building the dynamic list\n"); return 1; } actptr->nextrec = workptr; /* Build the chain */ (*workptr).prevrec = actptr; /* structptr->structfield or

´ ´ ´ 5.1. STRUKTURAK ­ LANCOLT LISTA (*structptr).structfield are the same!

45 */ */

/* We assume that finput != NULL

endflag = fscanf{finput,"%d%s%s%d%d", &(workptr->flgtno), workptr->date, workptr->name, &(workptr->flgtkm), &typ); /* read int from file */ workptr->type = (travel)typ; /* make it enum */ ... }

Akinek m´r j´l megy a C, megpr´b´lkozhat ennek a feladatnak a teljes kia o o a dolgoz´s´val. A l´ncolt lista ´p´ es´nek le´ll´si felt´tele az, hogy az input aa a e it´ e a a e file-b´l m´r nem tudunk olvasni. Ez p´ld´ul ugy der¨lhet ki, hogy folyamo a e a ´ u atosan ellenrizz¨k, hogy az fscanf f¨ggv´ny mindig a specifik´ci´ szerinti o u u e a o sz´m´ adatot olvasott-e be. Ez a sz´m a f¨ggv´ny visszat´r´si ´rt´ke. a u a u e ee e e

A programb´l val´ kil´p´s eltt ne feledkez¨nk meg arr´l, hogy illik o o e e o u o felszabad´ itanunk a programunk ´ltal lefoglalt mem´ri´t (hasonl´an ahhoz, a o a o ahogy illik lez´rni a lez´ratlan file-okat is). a a

46

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK

5.2.

Men¨ rendszer u

Ide j¨n egy r¨videbb men¨rendszer o o u

¨ ´ 5.3. OSSZETETT MINTAPELDA

47

5.3.

¨ Osszetett mintap´lda e

Jelen p´ld´nk egy igen flexibilis men¨kezel rendszer v´z´t tartalmazza. e a u o a a Az itt felhaszn´lt megold´sok sokat seg´ a a ithetnek a t´ ipusdefinici´kkal, struko t´r´kkal, pointerekkel, f¨ggv´ny-pointerekkel kapcsolatban le´ ua u e irtak meg´re t´s´ben. ee E p´lda f c´lja a port´bilis programoz´si st´ bemutat´sa, m´sr´szt e o e a a ilus a a e igyeksz¨nk r´vil´g´ u a a itani arra, hogy egy c´lszeren megtervezett adat- ´s e u e szubrutinstrukt´ra mennyire ´ttekinthetv´ ´s k¨nnyen m´dos´ u a o ee o o ithat´v´ teo a szi a felhaszn´l´i programjainkat. Felh´ ao ivjuk az olvas´ figyelm´t, hogy ezzel o e a p´ldprogrammal nem azt akarjuk sugallni, hogy ez az igazi men¨kezel, e u o illetve felhaszn´l´i fel¨let. L´teznek olyan objektum-orient´lt k¨nyvt´rak, ao u e a o a amelyek az itt le´ irtakn´l sokkal fejletteb felhaszn´l´i fel¨letet val´s´ a ao u o itanak meg ­ term´szetesen haszn´latukhoz ismerni kell a C++-t, illetve ha Wine a dows alkalmaz´i programot k´sz´ unk, a programvez´rl´srl ´s a men¨krl o e it¨ e e o e u o alkotott k´p¨nket mindenk´ppen ´t kell alak´ e u e a itanunk.

5.3.1.

A tervez´s egyes f´zisai e a

Minden programfejleszt´si munka sor´n elj¨n az a feladat, hogy az adott e a oo program sz´m´ra egy felhaszn´l´i fel¨letet (user interface-t) kell ´ a a ao u irni. Ez a fel¨let az esetek legnagyobb r´sz´ben valamilyen men¨rendszert jelent. u e e u Egy men¨rendszert ugy c´lszer kialak´ u ´ e u itani, hogy az ´ltala ny´jtott szola u g´ltat´sok az eg´sz felhaszn´l´i programban ig´nybevehetk legyenek, ´s a a a e ao e o e felhaszn´l´i program t¨bbi r´sz´ben lehets´g szerint ne kelljen a k´pernyao o e e oe e o ´s billentyzetkezel´ssel foglalkozni. Az eg´sz felhaszn´l´i program, illetve e u e e ao a hozz´kapcsol´d´ men¨rendszer tervez´sekor egy m´sik fontos szempont a o o u e a az, hogy a program bels vez´rl´si szerkezetei t¨kr¨zz´k azt a vez´rl´si o e e u o e e e szerkezetet, amit a felhaszn´l´ ´szlel a program haszn´lata sor´n. M´sao e a a a k´ppen ezt ugy fogalmazhatjuk meg, hogy ne az egyes programfunkci´k e ´ o aktiviz´ljanak kisebbnagyobb men¨rutinokat, hanem egy ´tfog´, hierarchia u a o kus men¨rendszer gondoskodjon arr´l, hogy mindig a felhaszn´l´ k´ ans´ga u o a o iv´ a szerinti programfunkci´k legyenek aktiviz´lva. o a Portabilit´si megfontol´sok a a Ha f´radts´gos munk´val megtervez¨nk ´s l´trehozunk egy, a fenti k´ anala a a u e e iv´ maknak megfelel felhaszn´l´i fel¨letet, c´lszer azt ugy programozni, hogy o ao u e u ´ ne csak IBM-PC kompatibilis sz´m´ og´peken, a DOS oper´ci´s rendszer a it´ e a o alatt, BORLAND C++ ford´ oval leford´ it´ itva fusson, hanem j´l k¨r¨lhat´o ou a rolt m´dos´ asok ut´n b´rmely, C ford´ oval rendelkez g´pt´ o it´ a a it´ o e ipuson, b´ra mely oper´ci´s rendszeren (pl. VT100-as termin´lokkal rendelkez VAX a o a o

48

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK

g´peken) is haszn´lhassuk a meg´ rutinjaink t¨bbs´g´t. e a irt o e e Ennek ´rdek´ben c´lszer a meg´ e e e u irand´ men¨rendszert 3 r´szre osztani. o u e Az els r´sz tartalmazza a legmagasabb szint f¨ggv´nyeket, amelyek v´tozo e u u e a tat´s n´lk¨l port´bilisak. A m´sodik, k¨zbens szint tartalmazza azokat a a e u a a o o f¨ggv´nyeket, amelyeknek t¨rzs´t az aktu´lis C ford´ o ´s oper´ci´s rendszer u e o e a it´ e a o rendszerf¨ggv´nyei, illetve az aktu´lis sz´m´ og´p-konfigur´ci´ k´pernyje u e a a it´ e a o e o szerint m´dos´ o itani kell. A harmadik, legalacsonyabb szinten c´lszer elhee u lyezni a teljesen hardver-specifikus f¨ggv´nyeket. Ilyenek lehetnek p´ld´ul u e e a az IBM PC BIOS rutinh´ asok. iv´ Jelen p´ld´nkban csak a legmagasabb szint r´szeit mutatjuk be men¨e a u e u kezel rendszer¨nknek. A m´sodik, ´s harmadik csoprtba tartoz´ f¨ggv´o u a e o u e nyek k¨z¨l csak a k¨zvetlen¨l felhaszn´lt f¨ggv´nyek deklar´ci´it k¨z¨lj¨k o u o u a u e a o o o u r¨vid magyar´zatokkal. o a A l´tv´ny (look-and-feel) megtervez´se a a e Alapveten a BORLAND C++ integr´lt fejleszti k¨rnyezet´nek men¨kono a o o e u cepci´j´t igyeksz¨nk megval´s´ oa u o itani a hot key-k kiv´tel´vel. Igyeksz¨nk egy e e u egyszer help-rendszert is megval´s´ u o itani, de nem c´lunk a BORLAND C++ e k¨rnyezetf¨gg rendszer´nek a lem´sol´sa. o u o e a a A men¨rendszert ugy l´tja a felhaszn´l´, hogy t¨bb alfanumerikus abu ´ a ao o lak van a k´pernyn. A BORLAND C++ erre t´nylegesen is lehets´get e o e oe ny´jtana, de a hordozhat´s´g miatt ezt nem haszn´ljuk ki. A men¨keu oa a u zel rendszerben az ¨sszes karakternyomtat´ utas´ as az eg´sz k´pernyre o o o it´ e e o vonatkozik, mi magunk figyel¨nk arra, hogy csak a k´perny bekeretezett u e o r´sz´n t¨rt´njen nyomtat´s. A k´pernyn mi magunk hozunk l´tre keree e o e a e o e tezett r´szeket, dobozokat az IBM PC kiterjesztett karakterk´szlet´vel. A e e e felhaszn´lt 'jobb fels sarok', 'bal fels sarok', 'f¨ggleges vonal', stb. kaa o o u o rakterek egyes sz´m´ og´p termin´lokon is l´teznek, "term´szetsen" m´s a it´ e a e e a k´dokkal, ´ c´lszeren ezeket p´ld´ul a #define direkt´ aval szimb´luo igy e u e a iv´ o mokhoz rendelj¨k. u Minden men¨ egy ilyen dobozba ker¨l, az egyes almen¨k dobozai a sz¨u u u u l men¨ doboz´t´l egy kicsit lejebb ker¨lnek a k´pernyre. K´sz´ unk egy o u ao u e o e it¨ fmen¨ keretet is. Ennek a legfels sora lesz a fmen, azaz az egym´st´l o u o o u a o f¨ggetlen men¨f´k gy¨ker´nek a gyjthelye. A fmenbl az egyes meu ua o e u o o u o n¨pontokat vagy egy dedik´lt billenty le¨t´s´vel, vagy a kurzor-mozgat´ u a u uee o nyilak (, illetve nyilak) ´s az Enter billenty seg´ eg´vel v´laszthate u its´ e a juk ki. A kiv´laszt´s hat´s´ra a men¨pont alatt megjelenik a megfelel a a aa u o almen¨ kerete, benne az egyes almen¨pontokkal. Egy almen¨ponthoz vagy u u u egy k¨zvetlen¨l v´grehajthat´ programr´sz, vagy egy tov´bbi almen¨ tartoo u e o e a u zik. Az almen¨k pontjait a kurzorvez´rl billentyk ´s az Enter, illetve u e o u e dedik´lt billentyk seg´ eg´vel v´laszthatjuk ki. a u its´ e a

¨ ´ 5.3. OSSZETETT MINTAPELDA

49

Egy almen¨bl az Esc, vagy a minden men¨ben szerepl eXit men¨u o u o u ponthoz rendelt X billenty le¨t´s´vel l´phet¨nk ki. (Az eXit men¨pontot u uee e u u ´s a hozz´ tartoz´ X billentyt a portabilit´s miatt defini´ltuk: egyes termie a o u a a n´lokon az Esc billenty k´dja termin´lvez´rl karakterszekvenci´k r´sze, a u o a e o a e ´ e billenty le¨t´s´t vagy nem tudjuk ´rz´kelni, vagy a termin´l "megigy u uee e e a bolondul" tle.) Egy men¨pontk´nt aktiviz´lt programr´szbl, vagy egy o u e a e o almen¨bl visszat´rve a h´ o men¨ k´pe mindig regener´l´dik, ´s az utolu o e iv´ u e ao e j´ra aktiviz´lt men¨pont marad kiv´lasztva, azaz egyszeren csak az Enter a a u a u billenty le¨t´s´vel ujra aktiviz´lhat´. u uee ´ a o Lek´pez´s adatstrukt´ r´kra ´s vez´rl´si szerkezetekre e e u a e e e Az elbb v´zolt megjelen´s a k´pernyn, illetve kezel´si m´d azt sugallja, o a e e o e o hogy sz¨ks´g¨nk van egy, a fmen¨t le´ o adatstrukt´r´ra ´s az azt keu e u o u ir´ ua e zel fmen¨ f¨ggv´nyre, illetve l´tre kell hozni egy olyan adatstrukt´r´t, o o u u e e ua amellyel le´ irhatjuk, hogy egy almen¨ hol helyezkedik el a k´pernyn, miu e o lyen men¨pontjai vannak, azokhoz milyen funkci´ (milyen v´grehajtand´ u o e o programr´sz, vagy milyen tov´bbi almen¨) tartozik, stb. e a u Nyilv´nval´ teh´t, hogy kell egy adatstrukt´ra, ami az egyes men¨pona o a u u tokra vonatkoz´ inform´ci´kat tartja nyilv´n (a men¨pont neve, a hozz´ o a o a u a tartoz´ help-inform´ci´, a hozz´rendelt kiv´laszt´ billenty, kiv´lasztott´ko a o a a o u a a e, milyen feladatot l´t el, esetleges param´ter). A men¨pontokat men¨lisa e u u t´kba kell szervezn¨nk. Egy ilyen list´t ki kell eg´sz´ unk a k´pernyn a u a e iten¨ e o val´ megjelen´sre vonatkoz´ inform´ci´kkal (milyen hossz´ a lista, h´ny o e o a o u a karakter sz´les, a list´t tartalmaz´ doboz hol helyezkedik el a k´pernyn, e a o e o stb.), ´s megadhatjuk azt is, hogy egy adott men¨ milyen hierarchia szinten e u helyezkedik el a men¨-f´n. u a A look-and-feel-re vonatkoz´ meggondol´sokb´l k¨vetkezik, hogy az alo a o o men¨ket kezel men¨f¨ggv´nyt ugyanolyan funkci´k´nt ´rdemes felfogni, u o uu e o e e mint a programunk t´nylegesen v´grehajtand´ egyes r´szeit. Igy teh´t c´le e o e a e szer az egyes men¨list´kat megsz´mozni, ´s a men¨kezelnk ezen sz´m u u a a e u o a alapj´n tudja eld¨nteni, melyik men¨list´t kell megjelen´ a o u a itenie ´s kezelnie. e Term´szetesen az is c´lszer, hogy az egyes men¨pontok a v´grehajtane e u u e d´ programr´szletekre vonatkoz´ default param´tereket tartalmaznak, ´s o e o e e a men¨pont kiv´laszt´sakor ezen param´terrel h´ u a a e ivja meg a men¨kezel a u o megfelel r´szprogramot. o e Ilyen meggondol´sok mellett egy almen¨ megjelen´ ese bels vez´rl´a u it´ o e e si szerkezetk´nt ugy nyiv´nul meg, hogy a men¨kezel f¨ggv´ny ¨nmag´t e ´ a u o u e o a h´ ivja meg ugy, hogy a rekurz´ h´ as alkalm´val az almen¨ azonos´ oj´t, ´ iv iv´ a u it´ a mint param´tert haszn´lja. e a Hogy val´s´ o itsuk meg egy adott men¨ponthoz tartoz´ f¨ggv´ny aktiviz´u o u e a l´s´t? A v´lasz igen egyszer: indirekt f¨ggv´nyh´ ast kell alkalmaznunk, aa a u u e iv´

50

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK

azaz a men¨pont le´ o strukt´r´ban egy f¨ggv´nyre mutat´ pointermezt u ir´ ua u e o o kell deklar´lnunk. Az egyes men¨pontok defini´l´sakor ezt a strukt´ramea u aa u zt a t´nylegesen megh´ o e ivand´ f¨ggv´ny c´ evel kell majd inicializ´lnunk. o u e im´ a A konkr´t deklar´ci´k e a o Most tekints¨k teh´t az egyes t´ u a ipusdeklar´ci´kat! A men¨rendszer¨nk k¨a o u u u l¨nb¨z men¨kbl ´ll, a k¨l¨nb¨z men¨k pedig t¨bb men¨pontb´l. Egy o o o u o a uo o o u o u o men¨pont legfontosabb jellemzje az a f¨ggv´ny, amit a men¨pont kiv´u o u e u a laszt´sakor aktiviz´lni kell. Ezek a f¨ggv´nyek igen sokf´l´k lehetnek, ´ a a u e ee igy hagyom´nyos C-ben c´lszer a f¨ggv´nyek c´ a e u u e imeit nyilv´ntartani. Ehhez a k´t l´pcsben defini´ljuk a fad (function address) t´ e e o a ipust: typedef int intfunc(int);/* int-et visszaado, 1 int-et varo * * fuggvenytipus */ typedef intfunc *fad; /* intfunc tipusu tarolasi * segre mutato tipus egy* */

A fent defini´lt intfunc t´ a ipust felhaszn´lhatjuk a majdan megh´ a ivand´ o egyes f¨ggv´nyek elzetes deklar´l´s´ra. u e o aa a A v´grehajtand´ f¨ggv´nyen k´ ul egy men¨pont fontos jellemzje az ile o u e iv¨ u o let men¨pont neve (azonos´ o sz¨vege), az a nyomtathat´ karakter, amivel o u it´ o o Enter megnyom´sa helyett kiv´laszthat´ a men¨pont. C´lszer megengeda a o u e u n¨nk, hogy a men¨pont ´ltal megh´ u u a ivand´ f¨ggv´nynek egy, a men¨pont o u e u le´ as´ban t´rolt param´tert is ´tadjunk. Ha a men¨rendszer¨nkh¨z alkalir´ a a e a u u o mas help-rendszert is szeretn´nk, c´lszer az egyes men¨pontokhoz rendelt e e u u help-sz¨vegre utal´ inform´ci´t (p´ld´ul egy file-indexet) is t´rolni. Ezeo o a o e a a ket az inform´i´kat ­ a men¨ponthoz rendelt f¨ggv´ny c´ evel egy¨tt ­ az ao u u e im´ u al´bb deklar´lt menuitem (men¨pont) strukt´r´ba szervezt¨k: a a u ua u typedef struct { char *text; char key; int helpindex; fad function; int param; } menuitem;

/* /* /* /* /*

A A A A A

menupont azonosito szovege menupontot kivalaszto betu menuponthoz rendelt help-kod menuponthoz tartozo fv-re mutat '*function' fuggveny parametere

*/ */ */ */ */

A figyelj¨k meg, hogy a fenti strukt´ra definic´b´l kimaradt a t´ u u o o ipusc´ imke, hiszen typedef-fel eleve azonos´ ot rendel¨nk hozz´ ­ rekurz´ adatdefiniit´ u a iv c´r´l pedig sz´ sincs. oo o

¨ ´ 5.3. OSSZETETT MINTAPELDA

51

Most l´ssuk, hogy szervezhet¨nk egy men¨t a fenti m´don deklar´lt a u u o a menuitem strukt´r´k seg´ eg´vel. ua its´ e A men¨pontjainkat c´lszeren egy menuitem t´ u t¨mbben t´roljuk, u e u ipus´ o a amelynek m´ret´t is tudnunk kell. A men¨ tartalma mellett fontos annak e e u megjelen´se is. Sz¨ks´g¨nk lehet arra, hogy a men¨t keretez doboz tetee u e u u o j´n esetleg egy men¨nevet, egy fejl´cet (header-t) is megjelen´ unk. Fontos e u e its¨ azt is tudnunk, hogy melyik x-y karakterpozici´ba ker¨l a men¨doboz (ano u u nak p´ld´ul a bal fels sarka) a k´pernyn, ´s az is l´nyeges inform´ci´, e a o e o e e a o hogy h´ny karakterpozici´t foglal le a men¨doboz v´ a o u izszintes ´s f¨ggleges e u o ir´nyban. Azt is nyilv´ntarthatjuk egy men¨rl, hogy melyik men¨pontot a a uo u v´lasztottuk ki benne utolj´ra ´s fontos lehet az is, hogy az adott men¨ hol a a e u helyezkedik el egy hierarchikus men¨-f´n. Ezeket az inform´ci´kat foglaltuk u a a o egybe az al´bbi menutype strukt´r´ban: a ua typedef struct { char *header; int x; int y; int xs; int ys; int itemno; menuitem *items; int hierarch; int lastitem; } menutype;

/* /* /* /* /* /* /* /* /*

A menu fejlecszovegere mutat A menudoboz bal felso sarkanak x es y koordinatai, valamint a menudoboz x es y iranyu merete. A menupontok szama A menupontok listajara mutat. Ha 1, kozvetlenul a fomenu hivja Utoljara kivalasztott pont szama

*/ */ */ */ */ */ */ */ */

A menuitem t´ ipusb´l egy-egy inicializ´lt t¨mb¨t szervezve hozhatjuk l´tre o a o o e az egyes men¨k tartalm´ra vonatkoz´ adathalmazt. Egy ilyen lista kezu a o dc´ o ime ker¨l egy menutype strukt´ra items mezj´be. Egy-egy menutype u u oe strukt´ra egy komplett men¨ le´ as´t tartalmazza. Ezekbl a strukt´r´ku u ir´ a o ua b´l szint´n egy t¨mb¨t szervez¨nk, ez lesz a menus t¨mb. E t¨mb els o e o o u o o o n´h´ny eleme egy-egy men¨fa gy¨ker´t (azaz a fmen¨ egyes pontjaik´nt e a u o e o u e aktiviz´land´ men¨ket) reprezent´lja, a t¨bbi elem pedig az egyes f´kra fela o u a o a fz¨tt almen¨ket ´ le. Tekints¨k ´t teh´t a teljes men¨rendszert defini´l´ u o u irja u a a u ao adatstrukt´r´t: ua /* Kulso fuggvenyek deklaracioja extern intfunc data, regr, save, r_data, w_data, statf, linf, barf, load; */

52

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK */ */ */ */

/* A a menukezelo fuggveny prototipus erteku deklaracioja intfunc menu; /* El\-ore hivatkozashoz intfunc dir, shell; /* Tovabbi fv-ek el\-ore hivatkozshoz /* Az egyes menulistak (items_0 .. items_3) es a menuk: menuitem items_0[ ] = { /* text key hlp func. param. */ "Directory", 'D', 1, dir, 0, "Os shell", 'O', 2, shell, 0, "File", 'F', 3, menu, 3,/*a 3.sz. menu almenu lesz exitxt, 'X',-1, NULL, 0 /*-1-es parameter: exit }; /* Tombmeret: #define N0 sizeof(items_0)/sizeof(menuitem) menuitem items_1[ ] = { "Default", 'D', 4, data, 7, "Read data", 'R', 5, r_data,1, "List data", 'L', 6, w_data,2, "Statistics",'S', 7, statf, 3, exitxt, 'X',-1, NULL, 0 }; #define N1 sizeof(items_1)/sizeof(menuitem) menuitem items_2[ ] = { "Regression",'R', 8, regr, 4, "Plot", 'P', 9, linf, 5, "Bar", 'B',10, barf, 6, exitxt, 'X',-1, NULL, 0 }; #define N2 sizeof(items_2)/sizeof(menuitem) menuitem items_3[ ] = { "Save", 'S',11, savef, 0, "Load", 'L',12, loadf, 0, exitxt, 'X',-1, NULL, 0 }; #define N3 sizeof(items_3)/sizeof(menuitem)

*/ */ */

¨ ´ 5.3. OSSZETETT MINTAPELDA

53

/* A teljes menurendszer leirasa: menutype menus[ ] = {/* head. x y xs ys itemno items hier. last "", 9, 2, 13, N0+3, N0, items_0, 1, 0, "", 35, 2, 14, N1+3, N1, items_1, 1, 0, "", 61, 2, 14, N2+3, N2, items_2, 1, 0, "Files",11, 6, 8, N3+3, N3, items_3, 0, 1 };

*/ */

Figyelj¨k meg, hogy a men¨list´k m´ret´nek meghat´roz´s´t a ford´ o progu u a e e a aa it´ ramra b´ iztuk: a sizeof oper´tor seg´ eg´vel megkapjuk mind az egyes a its´ e men¨list´kat tartalmaz´ t¨mb¨k helyfoglal´s´t byte-okban, mind a menuu a o o o aa item t´ ipus m´ret´t; ezek h´nyadosa adja meg a men¨lista t¨mb¨k logikai e e a u o o m´ret´t (azaz azt, hogy h´ny elem egy men¨lista). Ezeket a kifejez´seket e e a u u e #define makr´k´nt defini´ljuk, ´s az ´ kapott kifejez´seket haszn´ljuk o e a e igy e a fel a menus t¨mb inicializ´l´s´ra. Ez egy igen flexibilis megold´s, ugyanis o aa a a egy men¨lista bv´ ese sor´n a menus t¨mb inicializ´l´sakor a men¨doboz u o it´ a o aa u m´ret´re ´s a men¨lista hossz´ra vonatkoz´an automatikusan helyes adatot e e e u a o fog a ford´ o felhaszn´lni. A menus t¨mb kit¨lt´s´t legfeljebb csak akkor it´ a o o ee kell m´dos´ o itani, ha egy uj men¨lista-elem hossza nagyobb, mint az adott ´ u men¨dobozhoz megadott xs ´rt´k. u e e

Saj´t include file-ok a Men¨rendszer¨nk egy f¨ggv´nyekre mutat´ pointerekbl ´ll´ t¨mb seg´ u u u e o o a o o its´g´vel aktiviz´lja az egyes men¨pontokhoz rendelt f¨ggv´nyeket. Ahhoz, e e a u u e hogy ezt a pointert¨mb¨t ki lehessen t¨lteni, sz¨ks´g van a saj´t f¨ggv´nyeo o o u e a u e ink protot´ ipusaira. Fontos, hogy csak int t´ ipust visszaad´, egyetlen int o t´ u param´tert v´r´ f¨ggv´nyeket illeszthet¨nk be a men¨rendszerbe. ipus´ e ao u e u u Ha ettl elt´r rutinjaink vannak, akkor azokat "fejelj¨k meg" ugy, hogy o eo u ´ ennek a k¨vetelm´nynek eleget tegyenek. Ezeket a f¨ggv´nyeket vagy ugy o e u e ´ deklar´ljuk, ahogy azt az adatstrukt´ra le´ asakor tett¨k, vagy egy include a u ir´ u file-ba foglajuk a deklar´ci´kat. A kett egyszerre is alkalmazhat´, felt´ve, a o o o e ha a k´tf´le deklar´ci´ ¨sszhangban ´ll egym´ssal. Mi most a men¨kezel e e a oo a a u o rendszerben t¨rt´n deklar´ci´t alkalmazzuk, ´s csak a men¨kezel rutinok o e o a o e u o deklar´ci´it helyezz¨k el a saj´t file-ban. a o u a A bevezetben eml´ o itett, nem port´bilis k´pernykezel f¨ggv´nyeinket a e o o u e egy ¨n´ll´ .c file-ban ´rdemes t´rolni, protot´ o a o e a ipusaikat szint´n a f¨ggv´ny e u e rpotot´ ipusokat tartalmaz´ include file-unkban ´rdemes elhelyezni. o e Ezt az include file-t, amit p´ld´ul myfunc.h-nak nevezhet¨nk ­ majd a e a u men¨kezel rendszert tartalmaz´ .c file fogja beh´ u o o ivni a

54

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK #include "myfunc.h"

preprocesszor utas´ assal. it´ ´ Erdemes a men¨kezel rendszer¨nk ´ltal haszn´lt k¨l¨nf´le szimb´luu o u a a uo e o mokat is ­ p´ld´ul egyes speci´lis billentyk k´djainak szimb´likus neveit, e a a u o o mint p´ld´ul RIGHT ami a billenty k´dj´nak, LEFT, UP, DOWN, ESC, BEe a u o a GIN, END, HELP rendre a , , , Esc, Enter, Home, End ´s az F1 billenty e u k´dj´nak felel meg az IBM PC-n ­ egy szimb´lum file-ba foglalni. Legyen o a o ennek a file-nak a neve p´ld´ul mysymb.h. Ezt a file-t szint´n az #include e a e direkt´ aval ´p´ iv´ e ithetj¨k be a rendszer minden egyes .c file-j´ba. (Megjeu a gyezz¨k, hogy ez a file ak´r #define-nal deklar´lt makr´szer konstansokat u a a o u tartalmazhat, ak´r const-k´nt defini´lt konstansok deklar´ci´it tartalmaza e a a o hatja ­ az itt k¨z¨lt programr´szletek szempontj´b´l ez l´nyegtelen. Egy o o e a o e m´sik megjegyz´s az egyes billentykh¨z rendelt k´dokra vonatkozik: A a e u o o speci´lis billentykh¨z c´lszer 128-n´l nagyobb k´dokat rendelni. ´ a a u o e u a o Igy billentyzet kezel f¨ggv´ny altal visszadott billentyk´dok k¨z¨l k¨nnyen u o u e ´ u o o u o kiszrhetk a k¨zvetlen ASCII karakterk´dok. A men¨kezel rendszerben u o o o u o ezzel a felt´telez´ssel ´l¨nk. e e eu

¨ ´ 5.3. OSSZETETT MINTAPELDA

55

5.3.2.

A men¨ kezel rendszer list´ja u o a

/************************************************************ * File: menu.c * * Tartalom: Menukezelo mintaprogram * *************************************************************/ #include #include #include #include /* /* /* /* Standard i/o csomag Sztring- es memoriakezelo rutinok Altalanos celu standard fuggvenyek Karakterkezelo makrok */ */ */ */

#include "myfunc.h" /* Sajat fuggvenyek prototipusai */ #include "mysymb.h" /* Szimbolumok (spec. billentyuk kodjai)*/ /* ======================================================== */ /* Tipusdeklaraciok */ typedef int intfunc(int);/* int-et visszaado, 1 int-et varo * * fuggvenytipus */ typedef intfunc *fad; /* intfunc tipusu tarolasi * segre mutato tipus egy* */

typedef struct { char *text; char key; int helpindex; fad function; int param; } menuitem; typedef struct { char *header; int x; int y; int xs; int ys; int itemno; menuitem *items;

/* /* /* /* /*

A A A A A

menupont azonosito szovege menupontot kivalaszto betu menuponthoz rendelt help-kod menuponthoz tartozo fv-re mutat '*function' fuggveny parametere

*/ */ */ */ */

/* /* /* /* /* /* /*

A A x a y A A

menu fejlecszovegere mutat menudoboz bal felso sarkanak es y koordinatai, valamint menudoboz x es iranyu merete. menupontok szama menupontok listajara mutat.

*/ */ */ */ */ */ */

56

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK */ */

int hierarch; /* Ha 1, kozvetlenul a fomenu hivja int lastitem; /* Utoljara kivalasztott pont szama } menutype;

/* ======================================================== */ /* Tarolasi egysegek deklaracioi, definicioi: */ static char exitxt[~] = "eXit"; /* Majd sokszor kell ez a sztring. /* Kulso fuggvenyek deklaracioja extern intfunc data, regr, save, r_data, w_data, statf, linf, barf, load; */ */ */ */

*/ */

/* A a menukezelo fuggveny prototipus erteku deklaracioja intfunc menu; /* El\-ore hivatkozashoz intfunc dir, shell; /* Tovabbi fv-ek el\-ore hivatkozshoz /* Az egyes menulistak (items_0 .. items_3) es a menuk: menuitem items_0[ ] = { /* text key hlp func. param. */ "Directory", 'D', 1, dir, 0, "Os shell", 'O', 2, shell, 0, "File", 'F', 3, menu, 3,/*a 3.sz. menu almenu lesz exitxt, 'X',-1, NULL, 0 /*-1-es parameter: exit }; /* Tombmeret: #define N0 sizeof(items_0)/sizeof(menuitem) menuitem items_1[ ] = { "Default", 'D', 4, data, 7, "Read data", 'R', 5, r_data,1, "List data", 'L', 6, w_data,2, "Statistics",'S', 7, statf, 3, exitxt, 'X',-1, NULL, 0 }; #define N1 sizeof(items_1)/sizeof(menuitem)

*/ */ */

¨ ´ 5.3. OSSZETETT MINTAPELDA menuitem items_2[ ] = { "Regression",'R', 8, regr, 4, "Plot", 'P', 9, linf, 5, "Bar", 'B',10, barf, 6, exitxt, 'X',-1, NULL, 0 }; #define N2 sizeof(items_2)/sizeof(menuitem) menuitem items_3[ ] = { "Save", 'S',11, savef, 0, "Load", 'L',12, loadf, 0, exitxt, 'X',-1, NULL, 0 }; #define N3 sizeof(items_3)/sizeof(menuitem) /* A teljes menurendszer leirasa: menutype menus[ ] = {/* head. x y xs ys itemno items hier. last "", 9, 2, 13, N0+3, N0, items_0, 1, 0, "", 35, 2, 14, N1+3, N1, items_1, 1, 0, "", 61, 2, 14, N2+3, N2, items_2, 1, 0, "Files",11, 6, 8, N3+3, N3, items_3, 0, 1 };

57

*/ */

/* Mivel a fmen¨nek semmi m´s funkci´ja nincs, mint a menu f¨ggv´nynek o u a o u e a ´tadni a vez´rl´st a megfelel men¨indexszel, komolyabb adatstrukt´r´kat e e o u ua nem defini´ltunk a sz´m´ra. Csak az al´bbiakra van sz¨ks´g a fmen¨h¨z: a a a a u e o u o */ static char main_header[ ] = /* A fomenu fejlecszovege " Highly Portable Menu System "; */

static char options[ ]=/*Az egyes menuk kivalaszto gombjai */ "FDP"; /*Sorrendjuk ugyan\-az, mint az alab- */ /*bi sztring-tomb el\-emeinek sorrendje*/ /* Az options sztring hossza adja meg, hogy a menus t¨mb h´nyadik elem´ig o a e tekintj¨k a men¨ket a fmen¨ r´szeinek. u u o u e */

58

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK */ */ */ */ */ */ */

static char *headers[ ]= { "File", /* A fomenube felvett "Data", /* menuk fejlec szove"Plot" /* gei. }; static int mainselect = 0; /* Az utoljara kiv.fomenu elem static char buffer[81]; /* Ide generaljuk a fomenut static int xp,yp,j; /* Segedvaltozok a rutinokhoz static char inpbuff[256]; /* Altalanos input buffer

/* A magyar´zatok ´s deklar´ci´k ut´n k¨vetkezzenek maguk a f¨ggv´nyek! a e a o a o u e A men¨kezel rendszert ugy hoztuk l´tre, hogy programunk main-je csak u o ´ e ilyen r¨vid legyen: o */ /************************************************************/ void main(void) /* Ez tetszoleges program 'main'-je lehet */ /************************************************************/ { displ_ini(); /* A kepernyokezelo rendszer inicializalasa */ main_frame();/* Keretrajzolas a fomenuhoz: mint az IDE */ main_menu(0);/* Fomenu. Addig fut, amig ESC-pel ki nem szallnak belole */ displ_end(); /* A kepernyo alapallapotanak helyreallitasa */ exit(0); /* OK hibakod visszadasa az operacios rendszernek */ } /* Most tekints¨k mag´t a men¨kezel rutincsomagot! */ u a u o /************************************************************/ int menu(int index)/*Az aktualisan hasznalando menu indexe */ /* Funkci´: o A f¨ggv´ny a menus[index]-ben adott men¨t megjelen´ a k´pernyn. Az u e u iti e o egyes men¨pontokat a men¨le´ as szerinti dobozban jelen´ meg. A meu u ir´ iti nus[index].lastitem index men¨pont kiemelve l´tszik a k´pen. A kiu u a e emelt men¨pontot a ´s kurzorvez´rlkkel v´ltoztathatjuk. Ha le¨tu e e o a u j¨k az Enter billentyt, akkor a kiemelt szin men¨pont f¨ggv´ny´t hivu u u u u e e juk meg, ha pedig valamelyik men¨ponthoz rendelt nagybett utj¨k le a u u ¨ u billentyzeten, akkor az illet men¨pont f¨ggv´nye lesz aktiviz´lva a meu o u u e a nus[index].items[selected].param parameterrel, ahol index a kiv´lasza tott men¨pont indexe. Amint a megh´ u ivott f¨ggv´ny visszaadja a vez´rl´st, u e e e

¨ ´ 5.3. OSSZETETT MINTAPELDA

59

a menu szubrutin regener´lja az aktu´lis men¨list´t a keretezett dobozban. a a u a Ha menus[index].hierarch == 1 akkor a menu f¨ggv´ny visszat´r´si ´ru e ee e t´ke e ­ RIGHT ha a kurzorvez´rl gombot nyomt´k meg, e o a ­ LEFT ha a kurzorvez´rl gombot nyomt´k meg. e o a Minden egy´b esetben a visszat´r´si ´rt´k 0, teh´t amikor e ee e e a ­ az ESC gombot nyomt´k meg (kil´p´s a menu f¨ggv´nybl), a e e u e o ­ olyan men¨pontot v´lasztottak ki, amelynek a helpindex-e -1 u a *************************************************************/ { int i, /* A menupontok szamat tesszuk bele */ l, /* for-ciklushoz ciklusvaltozo */ exit, /* Kilepest jelzo flag */ par, /* A kivalasztott fv. parametere */ cmd; /* A vezerlo-karakternek */ /* .......... E L O K E S Z I T E S E K ............... */ j = menus[index].lastitem;/* j-ben az aktualis index i = menus[index].itemno; if (!i) return 0; /* Nulla meretu menuvel nem torodunk menu_regen(index,1);/* A menut kiiratjuk a kepernyore exit = FALSE; /* A kilepest jelzo flag kezdoerteke /* .............. F O */ */ */ */

C I K L U S ................... */ */ */

while (! exit) /*Addig tart,amig exit igaz nem lesz { cmd = 0; /* Kezdetben ures parancs while (!(cmd == SELECT || cmd == CR)) { cmd = getkey(); /* VT100-on ketfele ENTER van, switch(cmd) /* ezert van CR is es SELECT is. { case BEGIN: o_gotoxy(xp,yp+j); /* HOME-ot nyomott printf("%s",menus[index].items[j].text);

*/ */

*/

60

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK j = 0; o_gotoxy(xp,yp); highlight(EMPHAS,menus[index].items[j].text); break; case END: o_gotoxy(xp,yp+j); /* END-et nyomott */ printf("%s",menus[index].items[j].text); j = i-1; o_gotoxy(xp,yp+j); highlight(EMPHAS,menus[index].items[j].text); break; case UP: /* 'fel' nyil */ { o_gotoxy(xp,yp+j); printf("%s",menus[index].items[j].text); if (j > 0) j--; else j = i - 1; o_gotoxy(xp,yp+j); highlight(EMPHAS,menus[index].items[j].text); } break; case DOWN: /* 'le' nyil */ { o_gotoxy(xp,yp+j); printf("%s",menus[index].items[j].text); if (j < i-1) j++; else j = 0; o_gotoxy(xp,yp+j); highlight(EMPHAS,menus[index].items[j].text); } break; case HELP: /* F1-et nyomtak */ menus[index].lastitem = j; menu_help(menus[index].items[j].helpindex); if (menus[index].items[j].helpindex >= 0 && menus[index].y + menus[index].ys > 11) menu_regen(index,0); break; case ESC: /* ESC-et nyomtak */ exit = 1; cmd = SELECT; break; case LEFT: case RIGHT:

¨ ´ 5.3. OSSZETETT MINTAPELDA

61

/* Ha 'main_menu' hivta 'menu'-t, akkor a 'jobbra', 'balra' nyilak eseten a menut toroljuk, es a nyil-gomb kodjat visszaadjuk. Igy a fomenu a roll-in menut felvaltja egy masikkal: */ if (menus[index].hierarch == 1) { menu_remove(index); return cmd; } default: /* Kilepunk, ha dedikalt gombot nyomtak */ if (cmd < 128) { cmd = toupper(cmd); for(l = 0; l < i; l++) { if (menus[index].items[l].key == cmd) { o_gotoxy(xp,yp+j); printf("%s",menus[index].items[j].text); cmd = SELECT; j = l; break; } } } break; } /* ............... end switch .................. */ } /* ................. end while .................... */ if (! exit) { exit = (menus[index].items[j].helpindex == -1); } /* Ezen a ponton m´r eldlt, hogy ki akarunk-e l´pni. Ha nem, akkor viszont a o e tudjuk, hogy melyik men¨pont f¨ggv´ny´t kell aktiviz´lni: u u e e a */ if (! exit) { /* Az 'eXit' pontnak mindig -1 helpindexe legyen! */

62

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK /* .... A kivalasztott fuggveny aktivizalasa:.... /* (j indexeli a kivalasztott fuggvenyt) o_gotoxy(xp,yp+j); highlight(EMPHAS,menus[index].items[j].text); menus[index].lastitem = j; par = menus[index].items[j].param (*menus[index].items[j].function)(par); menu_regen(index,0); } else { menu_remove(index); } } return 0; /* A menu-box regeneralasa */ */ */

} /************************************************************/ void menu_regen(int index, /* A regeneralando menu indexe */ int rem) /* TRUE: torolni kell a dobozt */ /* Funkci´: o A menus[index] men¨ regener´l´sa (´jra rajzolja a dobozt, ki´ a men¨u aa u irja u list´t ´s kiemel szinnel nyomtatja az utolj´ra kiv´lasztott men¨pontot.) a e o a a u Ha rem == 1 akkor a men¨ ´ltal elfoglalt k´pernyter¨letet t¨rli a men¨ua e o u o u lista ki´ asa eltt, ha rem == 0, akkor nem t¨r¨l. ir´ o oo *************************************************************/ { int i,k,l,m,n,xx,yy; int x1,x2; xp = menus[index].x; /* Pozicio, meret el\-ovetele */ yp = menus[index].y; i = menus[index].itemno; xx = menus[index].xs; yy = menus[index].ys; /* Dobozrajzolas */ box_draw(menus[index].header,xp,yp,xx,yy,rem); xp += 2;

¨ ´ 5.3. OSSZETETT MINTAPELDA yp += 2; for (k = 0; k < i; k++) /* A menulista megjelenitese { o_gotoxy(xp,yp+k); if (k == menus[index].lastitem) { highlight(EMPHAS,menus[index].items[k].text); j = k; } else printf("%s",menus[index].items[k].text); }

63

*/

} /************************************************************/ void menu_remove(int index) /* A torlendo menu indexe */ /* Funkci´: o A menus[index] men¨ t¨rl´se a k´pernyrl u o e e oo *************************************************************/ { int xx,yy,x1,y1; x1 = menus[index].x; y1 = menus[index].y; xx = menus[index].xs; yy = menus[index].ys; box_delete(x1,y1,xx,yy); } /************************************************************/ void box_draw(char* header, /* ->a doboz fejlec-szevege */ int xp, int yp,/* a doboz pozicioja, */ int xs, int ys,/* merete */ int rem) /* 1, ha torles kell, egyebkent 0 */ /* Funkci´: o Egy xs, ys m´ret dobozt rajzol az xp, yp pozici´ba. A keret fels r´sz´nek e u o o e e k¨zep´re a header fejl´cet ´ ki. Ha rem == 1, akkor a doboz rajzol´sa o e e irja a eltt t¨rli a doboz ´ltal elfoglaland´ ter¨letet. o o a o u *************************************************************/ {

64

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK int l,n,xx,yy; int x1,x2; l = strlen(header); /* A fejlec hossza xx = xs-2; /* Egyeb adatok el\-okeszitese x1 = (xx - l)/2; x2 = xx - (x1 + l); yy = ys-2; if (rem) box_delete(xp,yp,xs,ys); o_gotoxy(xp,yp); /* A legfelso sor a fejleccel printf("%c",UPLEFT); for (n = 0; n < x1; n++) printf("%c",HORIZ); highlight(REVERSE|BRIGHT,header); for (n = 0; n < x2; n++) printf("%c",HORIZ); printf("%c",UPRIGHT); yp++; for (n = 0; n < yy; n++) /* Maga a doboz { o_gotoxy(xp,yp+n); printf("%c",VERT); o_gotoxy(xp+1+xx,yp+n); printf("%c",VERT); } o_gotoxy(xp,yp+yy); /* A doboz legalso sora printf("%c",DOWNLEFT); for (n = 0; n < xx; n++) printf("%c",HORIZ); printf("%c",DOWNRIGHT);

*/ */

*/

*/

*/

} /************************************************************/ void box_delete(int xp, int yp, /* Egy dobozt torol */ int xs, int ys) /* Pozicio, meret */ /* Funkci´: o Egy xs, ys m´ret dobozt t¨r¨l az xp, yp pozici´r´l. e u oo oo *************************************************************/ { int n, m;

¨ ´ 5.3. OSSZETETT MINTAPELDA for (n = ys-1; n >= 0; n--) { o_gotoxy(xp,yp+n); for (m = 0; m < xs; m++) putc(' '); } }

65

/************************************************************/ void menu_help(int index) /* A menupont help-indexe */ /* Funkci´: o Az index ´ltal meghat´rozott help-sz¨veget kikeresi egy help-file-b´l, ´s a a o o e ki´ a k´pernyre. A ki´ ashoz egy 7 soros ablakot nyit, a sz¨veget 7 soirja e o ir´ o ronk´nt ´ ki. Ha van m´g kiirand´ sz¨veg, akkor a More ... uzenet ut´n e irja e o o ¨ a egy billentyle¨t´sre v´r, ha nincs, akkor a Press any key ... uzenet ut´n u ue a ¨ a t¨rli a k´pernyrl a help-dobozt, ´s visszat´r. A help-file form´tuma a o e oo e e a k¨vetkez: o o index_i sor_1_i sor_2_i ... sor_n_i index_j ... n_i

n_j

o ahol index i az i-edik help-index, n i az ehhez az indexhez tertoz´ helpsz¨veg sorainak a sz´ma, valamint sor 1 i, ... sor n i a help-sz¨veg egyes o a o sorai. Form´tum hiba, vagy file v´ge eset´n szint´n hibajelz´s t¨rt´nik. a e e e e o e *************************************************************/ { static char hunex[] = "Unexpected end of the help-file!!!"; #define YP 24 FILE *fp; int i,j,k,err; if (index < 0) return; /* Negativra visszater box_draw(" HELP ",2,11,76,9,1);/* Help-box rajzolasa */ */

66

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK fp = fopen(helpdat,"r"); /* Help-file megnyitasa */

if (fp == NULL) /* Ha nem letezik a file, hibajelzes */ { o_gotoxy((80-(21+strlen(helpdat)))/2-1,16); printf("Help-file %s not found!",helpdat); goto helpend1; } i = -1; while (i != index) /* Help-index keresese a file-ban */ { err = fscanf(fp,"%d%d",&i,&j); if (err == EOF) /* Nem talaljuk: hibajelzes */ { o_gotoxy(19,16); printf("No help is available for this menu item!"); goto helpend0; } if (err != 2) { o_gotoxy((79-(31+strlen(helpdat)))/2,16); printf("Format error in the %s help-file!",helpdat); goto helpend0; } if (i != index)/* Ha meg nem talalja, tovabb olvas. */ { for (; j >= 0; j--) { if (NULL == fgets(inpbuff,74,fp)) { o_gotoxy((79-strlen(hunex))/2,16); printf(hunex); goto helpend0; /* A 'goto'-t legfeljebb igy */ } /* hasznaljuk! */ } } } for (k = i = 0; i < j; i++) { if (NULL == fgets(inpbuff,74,fp)) { o_gotoxy((79-strlen(hunex))/2,16);

¨ ´ 5.3. OSSZETETT MINTAPELDA printf(hunex); goto helpend0; } o_gotoxy(4,12+k); printf(inpbuff); k++; if (k == 7)/*Megvan a helpszoveg. 7-esevel kiirjuk: { o_gotoxy(66,YP); highlight(BRIGHT,"More ..."); bell(); err = getkey(); o_gotoxy(66,YP); printf(" "); if (err == ESC)/* ESC-re kiszallunk { fclose(fp); box_delete(2,11,76,9); return; } box_draw(" HELP ",2,11,76,9,1); k = 0; } } helpend0: /* Minden befejezeskor ezeket a muveleteket fclose(fp); /* kell elvegezni, tehat takarekos meghelpend1: /* oldas a 'goto' hasznalat. Csinjan banpress_key();/* junk az ilyennel, hogy olvashato maradbox_delete(2,11,76,9); /* jon a programunk! }

67

*/

*/

*/ */ */ */ */

/************************************************************/ void main_frame(void) /* Funkci´: o Keretet rajzol a fmen¨nek. Ha valamelyik f¨ggv´ny t¨rli az eg´sz k´pero u u e o e e iv´ a a ithatja azt. nyt, akkor main frame megh´ as´val helyre´ll´ o *************************************************************/ { erase(); box_draw(main_header,0,0,80,23,0);/* Main box fejleccel */

68

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK

main_menu(1); /* Fomenu statusz-sora */ } /************************************************************/ void main_menu(int stl)/*Ha 1, akkor a statusz-sort kiirja */ /* Funkci´: o A men¨kezel rendszer f rutinja, ezt kell a main-bl megh´ u o o o ivni. A menus t¨mbbl annyi men¨t kezel k¨zvetlen¨l, amennyi az options sztring o o u o u hossza. A men¨-opci´kat a k´perny m´sodik, kivil´g´ u o e o a a itott sor´ban jelen´ a iti meg. Egy men¨pont a szok´sos m´don v´laszthat´ (kurzorral kiemel´s, u a o a o e majd Enter, vagy a kezd bet le¨t´se). Ha egy almen¨ ´l (azaz l´tszik a o u ue ue a k´pernyn), akkor a , illetve nyilakkal a szomsz´dos men¨re v´lthae o e u a tunk. *************************************************************/ { int i,j,k,l, posinc, hno,xp, cmd,flag; /* 'buffer'-ben lesz az inverzen kiirando statusz-sor hno = sizeof(headers)/sizeof(char*); posinc = 78/hno; xp = posinc/2; if (stl) { for (i = 0; i < 78; buffer[i++] = ' ') ; for (j = 0; j < hno; j++) { l = strlen(headers[j]); for(k = 0; k < l; k++) buffer[xp+j*posinc+k] = *(headers[j]+k); } buffer[78] = '\0'; o_gotoxy(1,1); highlight(REVERSE,buffer); */

¨ ´ 5.3. OSSZETETT MINTAPELDA } /* A kivalasztott menut normal modon jelenitjuk meg: i = mainselect; xp++; if (stl) { o_gotoxy(xp+i*posinc,1); printf(headers[i]); return; } /* A fo parancs-ciklus. Csak ESC-re lephetunk ki belole. dontquit: /* Ide ugrunk, ha megse lepunk ki. flag = cmd = 0; while (cmd != ESC) { if (! flag) cmd = getkey(); flag = 0; switch (cmd) /* Nincs el\-o almenu. Kurzorvezerlok { /* feldogozasa, status-sor modositasa case RIGHT: o_gotoxy(xp+i*posinc,1); highlight(REVERSE,headers[i]); if (i < hno-1) i++; else i = 0; o_gotoxy(xp+i*posinc,1); printf(headers[i]); break; case LEFT: o_gotoxy(xp+i*posinc,1); highlight(REVERSE,headers[i]); if (i) i--; else i = hno-1; o_gotoxy(xp+i*posinc,1); printf(headers[i]); break; case SELECT: crselect: /* Kivalasztottak egy almenut. Megje*/ /* gyezzuk indexet 'mainselect'-ben */ mainselect = i;

69

*/

*/ */

*/ */

70

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK flag = menu(i);/* A 'menu' rutin behivasa switch (flag) /* Mi a visszateresi ertek? { case RIGHT: /* Stat.sor modositas ... o_gotoxy(xp+i*posinc,1); highlight(REVERSE,headers[i]); if (i < hno-1) i++; else i = 0; o_gotoxy(xp+i*posinc,1); printf(headers[i]); break; case LEFT: o_gotoxy(xp+i*posinc,1); highlight(REVERSE,headers[i]); if (i) i--; else i = hno-1; o_gotoxy(xp+i*posinc,1); printf(headers[i]); break; } l = strlen(headers[i]); o_gotoxy(xp+i*posinc+l,1); break; default: if (cmd < 128) /*Kezdobetuvel valasztottak { cmd = toupper(cmd); for (l = 0; l < hno; l++) if (cmd == options[l]) { o_gotoxy(xp+i*posinc,1); highlight(REVERSE,headers[i]); i = mainselect = l; o_gotoxy(xp+i*posinc,1); printf(headers[i]); /* Ugy teszunk, mintha 'nyil+Enter'-rel valasztottak volna. */ cmd = SELECT; goto crselect; } } break; } */ */ */

*/

¨ ´ 5.3. OSSZETETT MINTAPELDA } /* Az ESC-pel valo kilepes szandekat meg\-erosittetjuk: box_draw("",28,5,24,3,0); o_gotoxy(30,6); highlight(BRIGHT,"Are you sure? (y/n) "); cmd = yesno(); box_delete(28,5,24,3); o_gotoxy(1,1); if (!cmd) goto dontquit; /*Nem lep ki, vissza az elejere erase();

71

*/

*/

} *************************************************************/ /* K´t gyakori funkci´ port´bilis megval´s´ as´t tal´ljuk itt. Ezek az akt´ e o a o it´ a a iv k¨nyvt´r tartalm´nak kiirat´sa a k´pernyre, illetve az oper´ci´s rendszer o a a a e o a o parancs-´rtelmez burk´nak (command shell) az aktiviz´l´sa. Mindkettt e o a aa o a system f¨ggv´ny seg´ eg´vel oldjuk meg. A system argumentuma egy u e its´ e oper´ci´s rendszernek sz´l´ parancsot tartalmaz´ sztring. Ezek a mi esea o oo o t¨nkben egy-egy #define makr´k´nt lettek megadva, ´ azok oper´ci´s u o e igy a o rendszertl f¨gg felt´teles ford´ assal megfelelen be´ll´ o u o e it´ o a ithat´k. Tah´t a o a system f¨ggv´nynek (process.h) ´tadand´ oper´ci´s endszer parancsok: u e a o a o */ #ifdef __MSDOS__ #define DIRSTR "dir /w/p" /* A burok (shell) 'dir' parancsa #define SHELL "COMMAND.COM" /* Maga az operacios r. burok (shell) #endif

*/ */

/* A fenti sztringeket csak a DOS-ban adhatjuk ´t a system-nek, ez´rt hasza e it´ e o iv´ n´ltuk az #ifdef MSDOS ford´ asvez´rl direkt´ at. UNIX-ban a mega felel sztringek ´rt´ke rendre "ls -C|more", illetve "sh" lenne. o e e */ /************************************************************/ int dir(int d) /* Az aktiv konyvtar tartalmat nezzuk meg */ /* d: Dummy parameter */

72

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK

/************************************************************/ { displ_end(); system(DIRSTR); /* Az op. rendszer DIR parancsat kerjuk. Ennel lehetne hatekonyabb meg\-oldast is talalni, de ez igy portabilis. */ displ_ini(); press_key(); erase(); main_frame(); return d; } /************************************************************/ int shell(int d)/* A parancsertelmezo burok hivasa */ /* d: Dummy parameter */ /************************************************************/ { displ_end(); printf("\nType exit to return!\n\n"); system(SHELL); displ_ini(); erase(); main_frame(); return(x); }

¨ ´ 5.3. OSSZETETT MINTAPELDA A saj´t include file tartalma a A k¨vetkez lista a myfunc.h include file javasolt tartalm´t mutatja be: o o a

73

/************************************************************ * File: myfunc.h * * Tartalom: Menukezelo mintaprogram fuggveny proto* * tipusai: el\-orehivatkozasokhoz, illetve a * * kepernyokezelo rendszer hasznalatahoz. * *************************************************************/ /* ======================================================== */ /* A menukezelo rendszer fuggvenyeinek deklaracioi */ void main_menu(int stl); /* Fomenu-rutin. Ezt kell a mainbol meghivni */ void main_frame(void); /* A fomenuhoz keretet rajzol a kepernyore */ int menu(int index); /* Ez a menurutin: az adott sorszamu menut kezeli */ void menu_regen(int index); /* Az adott sorszamu menut regeneralja a kepen */ void menu_remove(int index);/* Az adott sorszamu menut letorli a keprol */ void menu_help(int index); /* Adott menuponthoz helpet ir ki egy file-bol */ void box_draw(char *header, /* Adott fejleccel, */ int xp,int yp,/* adott xp,yp poxicioban, */ int xs,int ys,/* adott xs,ys meretben dobozt */ int rem); /* rajzol, ha kell, torol alatta*/ void box_delete(int xp, /* Adott helyrol adott meretu */ int yp, /* dobozt torol */ int xs, int ys); /* ======================================================== */ /* A keprnyokezelo rutinok prototipusai magyarazatokkal */ void o_gotoxy(int x, int y); /* Sajat pozicionalo. x=0..24, y=0..79 void home(void); /* A kurzort a 0,0 pozicioba helyezi void erase(void); /* Torli a kepernyot es a 0,0-ba pozicional

*/ */ */

74 void displ_ini(void); void void void void void void int int int

´ 5. FEJEZET. FEJLETTEBB TECHNIKAK /* Bekapcsolja a kepernyokezelo rendszert, torol displ_end(void); /* Kikapcsolja a kepernyokezelo rendszert, torol cursor_left(int n); /* A kurzort egy pozicioval balra viszi cursor_right(int n); /* A kurzort egy pozicioval jobbra viszi cursor_up(int n); /* A kurzort egy pozicioval feljebb helyezi cursor_down(int n); /* A kurzort egy pozicioval lejebb helyezi highlight(unsigned mode,/* 'mode' szerinti attributumchar* string);/* mal 'string'-et nyomtatja read_in(char* string); /* Egy sztringet olvas be yesno(void); /* y/Y/I/i/N/n (igen/nem) valaszt var. 0, ha 'nem'

*/ */ */ */ */ */ */ */

*/

input(char* string, int pos,int len);/* Sor-editor. Adott pozicion, adott hosszt edital void press_key(void); /* A 'Press a key' kiirasa utan gombnyomasra var void bell(void); /* Egy BEL karaktert kuld az stdout-ra: igy beep-el int getkey(void); /* A billentyuzetet kezeli, ASCII-t, illetve #define erteket ad vissza (pl. UP)

*/ */ */

*/

Irodalomjegyz´k e
[1] Benk Tiborn´ ­ Urb´n Zolt´n. Az IBM PC programoz´sa Turbo C 2.0 o e a a a nyelven. BME M´rn¨ki Tov´bbk´pz Int´zete, 1990. Jegyzet. e o a e o e [2] Benk Tiborn´ ­ Poppe Andr´s ­ Benk L´szl´. Bevezet´s a BORLAND o e a o a o e C++ programoz´ba. Computer Books, 1991. s [3] B. W. Kernighan ­ D. M. Ritchie. A C programoz´si nyelv. Mszaki a u K¨nyvkiad´., 1985. Ford´ o o itotta Dr. Siegler Andr´s. a [4] B. W. Kernighan ­ D. M. Ritchie. The C Programming Language. Prentice Hall, 1988. Second Edition.

75

Hasonló témájú dokumentumok
A mások által feltöltött dokumentumokat értékelheted. Ha úgy ítéled meg, hogy a vizsgára való felkészülés szempontjából hasznos volt egy dokumentum, akkor adj rá sokcsillagos értékelést.
Ha hibákat tartalmaz, vagy egyéb probléma van vele, akkor keveset.
A dokumentumok sorrendje az értékelések alapján adódik. Ami fentebb van a listában, azt hasznosabbnak ítélték társaid. Az új dokumentumok pedig (értékelések hiányában) szintén a lista tetején kezdenek.

Hozzászólások

Ha észrevételed van egy dokumentummal kapcsolatban (például hibát találtál benne), akkor a Hozzászólások részben jelezheted. Az olyan jellegű kérdéseket mint pl.: A 2. feladat 4. sorából milyen átalakítással jutottunk az 5. sorban szereplő képlethez? - szintén ide érdemes írni
Egy tipp az oldalhoz! - Sikeres vizsga után írd meg tapasztalataid a tantárggyal, vizsgával kapcsolatban. Miből érdemes tanulni, mennyi készülés kell, milyen volt a vizsga... Ha mindenki így tesz, sokkal egyszerűbb lesz elkezdeni a tanulást egy olyan ember tapasztalatainak a birtokában, aki már elvégezte a tantárgyat. Ehhez kattints a tantárgyra a Tanulmányaimban, majd a Véleményem a tárgyról linkre a jobb felső részen.

Cimkefelhő

3. aggregált kereslet áramlástan atombomba b1 beszerzés bevezetés biokémia civilizáció deriválás dinamika durkheim ea európai civilizációk eredete föld földrajz földtudomány gazdjog genetika gyak gyakorlat 1 hőtan inverz függvény kafka ket kiefer ferenc konfiguraciokonformacio. lévi-strauss lézer makro mintavizsga nevelés neveléstörténet pol.s. prax program regterv rékai miklós rezgéstan szervezeti magatartás szili táblázatkezelés tanirodai témák természetvédelem török válgazd vállalat helye vállalkozási ismeretek vizsga