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
- 2008-12-29 19:27:15
C
- 2009-02-01 19:30:30
- 2007-11-28 17:41:12
- 2009-01-06 14:56:36
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! - Add hozzá azokat a tantárgyakat a saját tárgyakhoz, melyeket aktuálisan hallgatsz a félév során. Így megkapod mások üzeneteit akik tantárggyal kapcsolatban írnak, illetve Te magad is írhatsz ezzel kapcsolatban. Írhatsz naptári bejegyzést, kitöltheted a tantárgyi adatlapját és egy tárgy lapján látod azokat a hallgatókat akik szintén felvették ebben a félévben a tárgyat.

Cimkefelhő

... 1 eloadas 10.16-2 2008 tavasz 2008_12_17 26 4. óra ábra ábris altér ásvány- és kőzettan b1 cementálás citrátkör dns elte ttk érzékelő etnográfia filmtörténet filozófia fmea fogyasztóvédelem földalatti tartály freud füst írányítástechnika jogi alaptan jogviszony kérdések és válaszok kidolgozott lowie megtakarítás meteorológia miskolc montázs órai anyag őskor pápai rékai miklós rezgéstan sejttan speech sounds szocioógia tájékoztató topográfia tőkeelmélet török tükör vállalatirányítás valszám