You are on page 1of 179

Forrs: http://www.doksi.

hu

Elsz a magyar kiadshoz


A C programnyelvet eredetileg a Bell Laboratriumban az UNIX opercis rendszerhez, az alatt
fejlesztettk ki PDP-11_ szmtgpen. A kifejlesztse ta eltelt vek sorn bebizonyosodott, hogy a C
nem egyszeren egy a napjainkban gombamd szaporod programnyelvek kzl. Korszer vezrlsi s
adatszerkezetei, rugalmassga, knny elsajtthatsga szles alkalmazsi terletet biztostott
szmra, klnsen a 16 bit-es mikroprocesszorok megjelense ta rendkvl sok gpen dolgoznak C
nyelven. C fordt kszlt olyan gpekre, mint az IBM System/370, a Honeywell 6000 s az Interdata
8/32. A nyelv a kutats-fejlesztsi, tudomnyos cl programozs npszer eszkzv vlt.
Magyarorszgon szintn egyre tbb olyan szmtgp mkdik, amely alkalmas a C megvalstsra.
Ilyenek a hazai gyrtmnyok kzl a TPA-11 sorozat, az R-11 , a szocialista gyrtmnyok kzl az
SZM-4 szmtgpek, de meg kell emltennk a haznkban ugyancsak elterjedt PDP-11 sorozat
tagjait is. Igy rtheten a magyar szmtstechnikai szakemberek krben mind nagyobb az rdeklds
a C nyelv irnt, egyre tbben szeretnnek megtanulni programozni ezen a nyelven.
Ebben szeretnnk segteni e knyv megjelentetsvel, amely didaktikusan, b plda- s
gyakorlatanyaggal kiegsztve szl a C sszetevirl, jellemzirl, de tartalmazza a nyelv referenciakziknyvt is. Az Olvas a legavatottabb forrsbl merthet : a vilghr szerzpros egyik tagja,
Dennis Ritchie a C nyelv tervezje, a msik, Brian W. Kernighan tbb, magyarul is megjelent nagy
siker szakknyv szerzje. Remljk, mind a kezd, mind a gyakorlott C-programozk haszonnal
forgatjk majd a mvet.
A Kiad
Elsz
A C ltalnos cl programnyelv. Tmrsg, a korszer vezrlsi s adatstruktrk hasznlata, bsges
opertorkszlet jellemzi. Nem nevezhet sem nagyon magas szint, sem nagy nyelvnek, s nem ktdik
egyetlen specilis alkalmazsi terlethez sem. Ugyanakkor a megktsek hinya, az ltalnos jelleg sok
magas szint nyelvnl knyelmesebb s hatkonyabb teszi.
A C nyelvet tervezje, Dennis Ritchie eredetileg az UNIX opercis rendszer programnyelvnek
sznta. Az opercis rendszer, a C fordt s lnyegben az sszes UNIX alkalmazsi program (a knyv
eredetijnek a nyomdai elksztshez hasznlt szoftver is) C nyelven rdott. Dennis Ritchie az els C
fordtt PDP- 11-en rta meg, de azta nhny ms gpre, gy az IBM System/370-re, a Honeywell
6000-re s az Interdata 8/32-re is kszlt C fordt: A C nyelv nem ktdik szorosan egyetlen
hardverhez vagy rendszerhez sem, knnyen rhatunk olyan programokat, amelyek vltoztats nlkl
futnak brmely ms, a C nyelvet tmogat gpen.
Knyvnkkel a C nyelv programozs elsajttshoz szeretnnk segtsget adni. Az olvas mr az
Alapismeretek c. fejezet megrtse utn elkezdhet programozni. A knyv ezutn kln-kln fejezetben
ismerteti a C nyelv f sszetevit, majd referencia-kziknyv formjban is sszefoglalja a nyelvet. Az
anyag tlnyomrszt pldaprogramok rsbl, olvassbl s mdostsbl ll, nem szraz
szablygyjtemnyt adunk az olvas kezbe. A legtbb plda teljes, ellenrztt, mkdkpes program,
s nem csupn elszigetelt programrsz. Knyvnkben nemcsak a nyelv hatkony hasznlatt kvntuk
ismertetni. Trekedtnk arra is, hogy j stlus, ttekinthet, hasznos algoritmusokat s programozsi
elveket mutassunk be. A knyv nem bevezet jelleg programozsi segdknyv; felttelezi, hogy az
olvas ismeri a programozs olyan alapfogalmait, mint: vltozk, rtkad utastsok, ciklusok,
fggvnyek. [A C nyelvben hasznlatos terminolgia szerint a szubrutinokat fggvnyeknek
(functions) nevezik. A ford.] Ugyanakkor a knyv alapjn egy kezd programoz is megtanulhatja a
nyelvet, br szksge lehet jrtasabb kollga segtsgre. Tapasztalataink szerint a C sokfle feladat
megfogalmazsra alkalmas, kellemes, kifejez s rugalmas nyelv. Knnyen elsajtthat, s aki
megismerte, szvesen hasznlja. Remljk, hogy knyvnk segtsget nyjt a nyelv hatkony
hasznlatban. A knyv megszletshez s a megrsakor rzett rmnkhz nagyban hozzjrultak
bartaink, kollgink gondolatgazdag brlatai s javaslatai.
Klnsen hlsak vagyunk Mike Bianchinak, Jim Blue-nak, Stu Feldmannek, Doug Mcllroynak, Bill
Roome-nak, Bob Rosinnek s Larry Roslernek, akik figyelmesen elolvastk a knyv tbb vltozatt
is. Al Aho, Steve Bourne, Dan Dvorak, Chuck Haley, Debbie Haley, Marion Harris, Rick Holt, Steve
Johnson, John Mashey, Bob Mitze, Ralph Muha, Peter Nelson, Elliot Pinson, Bill Plauger, Jerry

Forrs: http://www.doksi.hu

Spivack, Ken Thompson s Peter Weinberger megjegyzseikkel sokat segtettk munknkat klnbz
fzisaiban. Ksznet illeti tovbb Mike Lesket s Jim Ossant a knyv szedsben val rtkes
kzremkdskrt.
Brian W. Kernighan
Dennis M. Ritchie

Bevezets
A C ltalnos cl programnyelv. Trtnetileg szorosan kapcsoldik az UNIX opercis rendszerhez,
mivel ezen rendszer alatt fejlesztettk ki s mivel az UNIX s szoftvere C nyelven kszlt. A nyelv
azonban nem ktdik semmilyen opercis rendszerhez vagy gphez. Noha _ rendszerprogramnyelvnek szoks nevezni, mivel opercis rendszerek rsban jl hasznlhat, ugyanolyan
clszeren alkalmazhat nagyobb numerikus, szvegfeldolgoz s adatbzis-kezel programok
esetben is. A C viszonylag alacsony szint nyelv. Ez nem lebecslst jelent, csupn azt, hogy a C
nyelv - mint a legtbb szmtgp - karakterekkel, szmokkal s cmekkel dolgozik. Ezek
kombinlhatk, s az adott gpen rendelkezsre ll aritmetikai s logikai opertorokkal mozgathatk.
A C nyelvben nincsenek olyan mveletek, amelyekkel sszetett objektumokat, pl. karakterlncokat,
halmazokat, listkat vagy tmbket egy egsznek tekinthetnnk. Hinyzik pldul azoknak a PL/1
mveleteknek a megfelelje, amelyek egy egsz tmbt vagy karakterlncot kezelnek. A nyelvben
nincs ms trfoglalsi lehetsg, mint a statikus definci s a fggvnyek loklis vltozinl
alkalmazott verem elv. Nincs tovbb olyan, hulladk trterletek sszegyjtsre alkalmas
mechanizmus (garbage collection), mint amilyet az ALGOL 68 nyjt. Vgl pedig maga a C nyelv nem
biztost be- s kiviteli szolgltatsokat: nincsenek read s write utastsok, sem rgztett llomnyelrsi
(file-elrsi) mdszerek. Az sszes ilyen magasabb szint tevkenysget explicit mdon hvott
fggvnyekkel kell megvalstani.
Hasonlkppen a C nyelv csak egyszer, egy szlon fut vezrlstadsi struktrkat tartalmaz:
ellenrzseket, ciklusokat s alprogramokat, de nem teszi lehetv a multiprogramozst, a prhuzamos
mveleteket, a szinkronizlst vagy prhuzamos rutinok (korutinok) hasznlatt.
Br e szolgltatsok nmelyiknek hinya slyos hinyossgnak tnhet, a nyelv szerny mretek kz
szortsa valjban elnykkel jrt. A C nyelv viszonylag kicsi, ezrt kis helyen lerhat s gyorsan
elsajtthat. A C fordt egyszer s tmr lehet, ugyanakkor knnyen megrhat: a jelenlegi
technolgival egy j gpen fut fordt nhny hnap alatt elkszthet, s kdjnak 80%-a vrhatlag
kzs lesz a mr ltez fordtk kdjval. Ez nagyban segti a nyelv terjedst, a programok cserjt.
Mivel a C nyelvben definilt adattpusokat s vezrlsi szerkezeteket a legtbb mai szmtgp
kzvetlenl tmogatja, kicsi lesz az nll programok megvalstshoz futsi idben szksges
rutinknyvtr, amely a PDP-11 -en pldul csak a 32 bit-es szorzst s ; osztst vgrehajt rutinokat,
illetve a szubrutinba val belpst s az onnan val kilpst szolgl szekvencikat tartalmazzk.
Termszetesen
a nyelv valamennyi megvalstst kiterjedt, az adott gphez illeszked
fggvnyknyvtr teszi teljess. A fggvnyek biztostjk a be- s kiviteli mveletek elvgzst, a
karakterlncok kezelst s a trfoglalsi mveletek vgrehajtst. Mivel azonban csak explicit
mdon hvhatk, szksg esetn elhagyhatk, ezenkvl C programknt gpfggetlen mdon is
megrhatk. Minthogy a C a mai szmtgpek kpessgeit tkrzi, a C nyelv programok ltalban
elg hatkonyak ahhoz, hogy ne kelljen helyettk assembly programokat rni. Ennek legjellemzbb
pldja maga az UNIX opercis rendszer, amely majdnem teljes egszben C nyelven rdott.
13000 sornyi rendszerkdbl csak a legalacsonyabb szinten elhelyezked 800 sor kszlt assemblyben.
Ezenkvl majdnem minden UNIX alkalmazsi szoftver forrsnyelve is a C; az UNIX felhasznlk
tlnyom tbbsge (belertve e knyv szerzinek egyikt is) nem is ismeri a PDP-11 assembly
nyelvet. A C nyelv sok szmtgp kpessgeihez illeszkedik, minden konkrt szmtgparchitektrtl fggetlen, gy knnyen rhatunk gpfggetlen, teht olyan programokat, amelyek
klnfle hardvereken vltoztats nlkl futtathatk. A szerzk krnyezetben ma mr szokss vlt,
hogy az UNIX alatt kifejlesztett szoftvert tviszik a helyi Honeywell, IBM s Interdata rendszerekre.
Valjban az ezen a ngy gpen mkd C fordtk s futtatsi szolgltatsok egymssal sokkal inkbb
kompatibilisek, mint az ANSI-szabvnyos FORTRAN megfelel vltozatai. Maga az UNIX opercis
rendszer jelenleg mind a PDP-11-en, mind pedig az Interdata 8/32-n fut. Azokon a programokon
kvl, amelyek szksgszeren tbb-kevsb gpfggek, mint a C fordt, az assembler vagy a

Forrs: http://www.doksi.hu

debugger, a C nyelven rt szoftver mindkt gpen azonos. Magn az opercis rendszeren bell az
assembly nyelv rszeken s a perifriahandlereken kvli 7000 sornyi kd mintegy 95%-a azonos.
Ms nyelveket mr ismer programozk szmra az sszehasonlts kedvrt rdemes megemlteni a C
nyelv nhny trtneti, technikai s filozfiai vonatkozst.
A C nyelv sok alaptlete a nla jval rgebbi, de mg ma is l BCPL nyelvbl szrmazik, amelyet
Martin Richards fejlesztett ki. A BCPL a C nyelvre kzvetett mdon, a B nyelven keresztl hatott,
amelyet Ken Thompson 1970-ben a PDP-7-esen fut els UNIX rendszer szmra rt.
Br a C nyelvnek van nhny kzs vonsa a BCPL-lel, mgsem nevezhet semmilyen rtelemben a
BCPL egyik vltozatnak. A BCPL s a B tpus nlkli nyelvek: az egyetlen adattpus a gpi sz s
msfle objektumokhoz val hozzfrs specilis opertorokkal s fggvnyhvsokkal trtnik.
A C nyelvben az alapvet adatobjektumok a karakterek, a klnfle mret egsz (integer) tpusok s a
lebegpontos szmok. Ehhez jrul mg a szrmaztatott adattpusok hierarchija, amelyek mutatk
(pointerek), tmbk, struktrk, unionok s fggvnyek formjban hozhatk ltre. A C nyelv
tartalmazza a jl struktrlt programok ksztshez szksges alapvet vezrlsi szerkezeteket: az
sszetartoz utastssorozatot, a dntshozatalt (if), a programhurok tetejn (while for) vagy aljn (do)
vizsglatot tartalmaz ciklust s a tbb eset valamelyiknek kivlasztst (switch). (Ezek mindegyike
rendelkezsre llt a BCPL-ben is, szintaxisuk azonban nmileg klnbztt a C-belitl; a BCPL nhny
vvel megelzte a struktrlt programozs elterjedst.)
A C nyelv lehetv teszi a mutatk hasznlatt s a cmaritmetikt.
A fggvnyek argumentumainak tadsa az argumentum rtknek lemsolsval trtnik, s a hvott
fggvny nem kpes megvltoztatni az aktulis argumentumot a hvban. Ha nv szerinti hvst
akarunk megvalstani, egy mutatt adhatunk t explicit mdon s a fggvny megvltoztathatja azt az
objektumot, amire a mutat mutat. A tmbnv gy addik t, mint a tmb kezdcme, teht
tmbargumentumok tadsa nv szerinti hvssal trtnik.
Brmely fggvny rekurzv mdon hvhat s loklis vltozi rendszerint automatikusak, azaz a
fggvny minden egyes meghvsakor jra ltrejnnek. A fggvnydefincik nem skatulyzhatk
egymsba, a vltozk azonban blokkstruktrban is deklarlhatk. A C programokban szerepl
fggvnyek kln is fordthatk. Megklnbztethetnk egy fggvnyre nzve bels, kls (csak
egyetlen forrsllomnyban ismert) s teljesen globlis vltozkat. A bels vltozk automatikusak s
statikusak lehetnek. Az automatikus vltozk a hatkonysg nvelse rdekben regiszterekbe
helyezhetk, de a register deklarci csak ajnls a fordtnak s nem vonatkozik adott gpi
regiszterekre.
A PASCAL-lal vagy az ALGOL 68-cal sszehasonltva a C nem szoros tpusmegkts nyelv,
viszonylag engedkeny az adatkonverzikat illeten, de az adattpusok konverzija nem a PL/1-re
jellemz szabadossggal trtnik. A jelenlegi fordtk nem ellenrzik futs kzben a tmbindexeket,
argumentumtpusokat stb.
Ha szigor tpusellenrzs szksges, a C fordt egy specilis vltozatt, a lint-et kell hasznlni. A lint
nem generl kdot, hanem a fordts s tlts sorn lehetsges legtbb szempontbl igen szigoran
ellenriz egy adott programot. Jelzi a nem illeszked tpusokat, a kvetkezetlen
argumentumhasznlatot, nem hasznlt vagy nyilvnvalan inicializlatlan vltozkat, az esetleges
gpfggetlensgi problmkat stb. Azok a programok, amelyekben a lint nem tall hibt, ritka
kivtelektl eltekintve krlbell ugyanolyan mrtkben mentesek a tpushibktl, mint pldul az
ALGOL 68 programok. A megfelel helyen a lint tovbbi szolgltatsait is ismertetjk.
Vgezetl a C-nek, mint minden ms nyelvnek, megvannak a maga gyengesgei. Nmelyik
opertornak rossz a precedencija; a szintaxis bizonyos rszei jobbak is lehetnnek; a nyelvnek tbb,
kismrtkben eltr vltozata l. Mindezzel egytt a C nyelv szles krben alkalmazhat, rendkvl
hatkony s kifejezkpes nyelvnek bizonyult.
A knyv felptse a kvetkez: Az 1. fejezet a nyelv megtanulst segt bevezets a C nyelv kzponti
rszbe. Ennek az a clja, hogy az olvas minl hamarabb elkezdhessen programozni, mivel a szerzk
hite szerint egy j nyelv megtanulsnak egyetlen mdja, ha programokat runk az illet nyelven. A
fejezet felttelezi, hogy az olvas rendelkezik a programozs alapjainak aktv ismeretvel; az anyag
nem magyarzza meg, hogy mi a szmtgp, mi a fordts, sem pedig az olyan kifejezsek jelentst,
mint n = n + 1 . Br lehetleg mindentt hasznos programozsi mdszereket prbltunk bemutatni, nem

Forrs: http://www.doksi.hu

szntuk mvnket az adatstruktrk s algoritmusok kziknyvnek: knyszer vlaszts esetn


elssorban a nyelvre koncentrltunk.
A 2. ... 6. fejezet rszletesen, az 1. fejezetnl preczebben trgyalja a C nyelv klnbz elemeit, a
hangsly azonban itt sem a rszleteken, hanem a teljes, a gyakorlatban alkalmazhat pldaprogramokon
van. A 2. fejezet az alapvet adattpusokat, opertorokat s kifejezseket ismerteti. A 3. fejezet a
programvezrlssel: if-else, while, for stb. foglalkozik. A 4. fejezet tmi : a fggvnyek s a program
felptse, kls vltozk, az rvnyessgi tartomny szablyai stb. Az 5. fejezet a mutatkkal s a
cmaritmetikval, a 6. fejezet a struktrkkal s unionokkal kapcsolatos tudnivalkat tartalmazza. A 7.
fejezet a szabvnyos be- s kiviteli (I/o) knyvtrat ismerteti, amely kzs csatlakozfelletet kpez az
opercis rendszer fel. Ezt a be- s kiviteli knyvtrat minden olyan gp tmogatja, amely a C-t
tmogatja, teht azok a programok, amelyek ezt hasznljk bevitel, kivitel s ms rendszerfunkcik
cljbl, lnyegben vltoztats nlkl vihetk t egyik rendszerrl a msikra.
A 8. fejezet a C programok s az UNIX opercis rendszer kztti csatlakozsokat rja le, elssorban a
be- s kivitelre, az llomnyrendszerre s a gpfggetlensgre koncentrlva. Br e fejezet egy rsze
UNIX-specifikus, a nem UNIX-ot hasznl programozk is hasznos tudnivalkat tallhatnak benne megtudhatjk pl., hogyan valstottk meg a szabvnyos knyvtr adott verzijt, s hogyan nyerhetnk
gpfggetlen programkdot. Az A. fggelk a C nyelv referencia-kziknyvt, a C szintaxisnak s
szemantikjnak hivatalos lerst tartalmazza. Ha az elz fejezetekben esetleg ktrtelmsgekre
vagy hinyossgokra bukkanunk, mindig ezt kell vgs dntbrnak tekinteni.
Mivel a C olyan, mg fejldsben lev nyelv, amely szmos rendszeren fut, elfordulhat, hogy a knyv
egy-egy rsze nem felel meg valamely adott rendszer fejldse pillanatnyi llapotnak. Igyekeztnk
elkerlni az ilyen problmkat, s megprbltuk felhvni a figyelmet a lehetsges nehzsgekre. Ktes
esetekben azonban ltalban a PDP-11 UNIX rendszer esetben rvnyes helyzet lerst vlasztottuk,
mivel a C programozk tbbsgnek ez a munkakrnyezete. Az A. fggelkben ismertetjk a fontosabb
C rendszerek megvalstsaiban mutatkoz klnbsgeket is.
_
A. fggelk : C referencia-kziknyv
1.
Bevezets
A kziknyv a DEC PDP 11 , a Honeywell 6000, az IBM System/370 s az Interdata 8/32 gpeken
hasznlhat C nyelvet ismerteti. Eltrsek esetn a PDP 11 -es vltozatot helyezi eltrbe, de
igyekszik rmutatni a megvalstsfgg rszletekre. Nhny kivteltl eltekintve ezek a gpfgg
rszletek kzvetlenl a hardver alaptulajdonsgaibl kvetkeznek; a klnfle fordtk ltalban elgg
kompatibilisek.
2.
Szintaktikai egysgek
A szintaktikai egysgek hat osztlyba sorolhatk: azonostk, kulcsszavak, llandk, karakterlncok,
opertorok s egyb szepartorok. A szkzket, tabultorokat, jsorokat, megjegyzseket (kzs
nevkn res helyeket), mint az albbiakban is ltni fogjuk, a C fordt nem veszi figyelembe,
eltekintve attl, hogy feladatuk a szintaktikai egysgek elvlasztsa. res helyre van szksg az
egybknt szomszdos azonostk, kulcsszavak s llandk elvlasztsra.
Ha a beolvasott szveg szintaktikai egysgekre bontsa adott karakterig megtrtnt, a fordt azt a
lehet leghosszabb karakterlncot tekinti a kvetkez egysgnek, amelyrl felttelezhet, hogy mg
egyetlen szintaktikai egysget kpez.
2.1.
Megjegyzsek
A /*karakterek megjegyzst (comment) vezetnek be, amely a */ karakterekkel zrul. A
megjegyzsek nem skatulyzhatk egymsba.
2.2.
Azonostk (nevek)
Az azonost betk s szmjegyek sorozata; az els karakter bet kell, hogy legyen. A alhzsjel
betnek szmt. A nagy-s kisbetk klnbzk. Csupn az els nyolc karakter rtkes, br tbb is
hasznlhat. A klnfle
, assemblerek s betltprogramok ltal hasznlt kls azonostk
ennl ktttebbek:

Forrs: http://www.doksi.hu

DEC PDP 11

7 karakter, ktfle bettpus (kis-s nagybet).

Honeywell 6000
6 karakter, egyfle bettpus.
IBM 360/370
7 karakter, egyfle bettpus.
Interdata 8/32
8 karakter, ktfle bettpus.
2.3.
Kulcsszavak
Az albbi azonostk a nyelv kulcsszavai, gy egyb clra nem hasznlhatk:
int
extern
else
char
register for
float
typedef
do
double
static
while
struct
goto
switch
union
return
case
long
sizeof
default
short
break
entry
auto
unsigned
continue if
Az entry kulcsszt egyetlen jelenleg mkd fordtban sem valstottk meg, ksbbi fejlesztsekhez
tartottuk fenn. Bizonyos megvalstsokban a fortran s az asm szavak is kulcsszknt szerepelnek.
2.4.
llandk
Tbbfajta lland van; ezeket a kvetkezkben soroljuk fel. A mreteket rint hardverjellemzket
a 2.6. pontban foglaljuk ssze.
2.4.1.
Egsz llandk
A szmjegyek sorozatt tartalmaz egsz tpus (integer) llandt a fordt oktlisnak tekinti, ha
0-val (a nulla szmjeggyel) kezddik, egybknt decimlisnak veszi. A 8 s 9 szmjegyek
oktlis rtke 10, ill. 11 . Az olyan szmjegysorozatot, amelyet 0X vagy 0x (a 0 a nulla
szmjegy) elz meg, a fordtprogram hexadecimlis egsznek tekinti. Hexadecimlis
szmjegyek az a-tl, ill. A-tl f-ig, ill. F-ig elhelyezked karakterek, amelyeknek rtke 10, . . .,
15. Azt a decimlis llandt, amelynek rtke meghaladja a gpenbr zolhat legnagyobb
eljeles egszt, a fordtprogram long-nak veszi; hasonlkppen long lesz az az oktlis vagy
hexadecimlis lland, amelynek rtke meghaladja a legnagyobb, eljel nlkli gpi egszt.
2.4.2.
Explicit long llandk
Az a decimlis, oktlis vagy hexadecimlis egsz, amelyet kzvetlenl l (el bet) vagy L
kvet, long (hossz) lland. Amint arrl az albbiakban sz lesz, bizonyos gpeken az int s
long rtkek azonosak.
2.4.3.
Karakterllandk
A karakterlland
aposztrfok
(szimpla idzjelek) kz zrt karakter, pl. x. A
karakterlland rtke a karakternek a gp karakterkszletben szerepl numerikus rtke.
Bizonyos nem grafikus karaktereket, pl. az aposztrfot () vagy a fordtott trtvonalat (\) az
albbi escape-szekvencikkal brzolhatunk:
jsor
NL (LF)
\n
vzszintes tab
HT
\t
vissza-szkz
BS
\b
kocsi-vissza
CR
\r
lapdobs
FF
\f
fordtott trtvonal
\
\\
aposztrf

\
bitminta
ddd
\ddd
A \ddd escape-szekvencia egy fordtott trtvonalat s 1 , 2 vagy 3 rkvetkez oktlis szmjegyet
tartalmaz, amelyek a kvnt karakter rtkt hatrozzk meg. E konstrukci specilis esete a \0 (amit
nem kvet szmjegy), amely a NULL karaktert jelli. Ha a fordtott trtvonalat kvet karakter nem az
elbbiek egyike, a fordt a fordtott trtvonalat nem veszi figyelembe.
2.4.4.
Lebegpontos llandk
A lebegpontos lland egsz rszbl, tizedespontbl, trtrszbl, e-bl vagyE-bl s (esetleg
eljeles) kitevbl ll. Mind az egsz, mind a trt rsz szmjegyek sorozata. Akr az egsz, akr
a trt rsz hinyozhat (de mind a kett nem!); ill. a tizedespont vagy az e s a kitev kzl az
egyik szintn elmaradhat. Minden lebegpontos lland duplapontossg.

Forrs: http://www.doksi.hu

2.5.
Karakterlncok
A karakterlnc idzjelek kz zrt karaktersorozat: . . .. A karakterlnc tpusa szerint
karaktertmb, trolsi osztlya static (l. a kvetkezkben a 4. szakaszt), s a megadott karakterek
inicializljk. Az egyes karakterlncok, mg az azonos mdon lertak is, kln egysget kpeznek.
A fordt minden karakterlnc vgre elhelyezi a \0 nullabyte-ot abbl a clbl, hogy a
karakterlncot vizsgl programok megtalljk a karakterlnc vgt. A karakterlncon bell
elhelyezett idzjelet \ kell, hogy megelzze; a karakterllandknl ismertetett sszes escapeszekvencia hasznlhat. Vgl megjegyezzk, hogy az \-t s az azt kzvetlenl kvet jsort a
fordt nem veszi figyelembe.
2.6.
Hardverjellemzk
Az albbi tblzatban nhny olyan hardvertulajdonsgot foglaltunk ssze, amely gprl gpre
vltozik. Noha ezek a programok gpfggetlensgt rintik, mgis jval kisebb problmt okoznak,
mint azt valaki eleve gondoln. (A szmokbitekben rtendk.)

char
int
short
long
float
double
rtktartomny

DEC PDP-11
ASCII
8
16
16
32
32
64

Honeywell 6000
ASCII
9
36
36
36
36
72

IBM 370
EBCDIC
8
32
16
32
32
64

Interdata 8/32
ASCII
8
32
16
32
32
64

+-10+-38

+-10+-38

+-10+-76

+-10+-76

E ngy gp esetben a lebegpontos szmoknak 8 bites kitevjk van.


3.
A szintaxis jellse
A kziknyvben hasznlt szintaktikai jellsmdban a
kulcsszavakat s karaktereket - ahol az egyrtelmsg megkvnja
kvr szedssel jelljk. A vlaszthat (alternatv)
kategrik kln sorban szerepelnek. Az elhagyhat (opcionlis)
szimblumokat az opc index jelli, gy
{ kifejezsopc } kapcsos zrjelek kz zrt elhagyhat kifejezst jell. A szintaxist ksbb a 18.
pontban foglaljuk ssze.
4.
Az azonostk rtelmezse
A C nyelv az azonostk rtelmezst az azonostk kt tulajdonsgra alapozza: a trolsi osztlyra s
a tpusra. A trolsi osztly az azonosthoz rendelt trhely elhelyezkedst s lettartamt, a tpus az
azonosthoz rendelt trterleten tallt rtkek jelentst hatrozza meg.
Ngy deklarlhat trolsi osztly van: automatikus, statikus, kls s regiszterosztly. Az automatikus
vltozk egy blokk minden hvsra nzve loklisak (l. a 9.2. pontot) rtkket a blokkbl val
kilpskor elvesztik; a statikus vltozk egy blokkra nzve loklisak, de mg akkor is megtartjk
rtkket, ha a vezrls idkzben kilpett a blokkbl; a kls vltozk megmaradnak s megtartjk
rtkket az egsz program vgrehajtsa sorn s fggvnyek kztti kommunikcira hasznlhatk,
mg kln-kln lefordtott fggvnyek esetben is. A regisztervltozk (ha lehetsges) a gp gyors
regisztereiben troldnak; az automatikus vltozkhoz hasonlan az egyes blokkokra nzve loklisak s
a blokkbl val kilpskor eltnnek.
A C nyelv tbb alapvet objektumtpus hasznlatt engedi meg:
A karakterknt (char) deklarlt objektumok elegenden nagyok ahhoz, hogy az adott implementci
karakterkszletnek tetszleges elemt trolni tudjk, s ha valban egy, az illet karakterkszletbl
vett karaktert akarunk karakter tpus vltozban trolni, annak rtke meg fog egyezni a karakter egsz
rtk kdjval. Ms mennyisgek is trolhatk karakter tpus vltozkban, de ennek megvalstsa
gpfgg. Maximum hromfle egsz tpus mret ll rendelkezsre, amelyeket short int (rvid egsz),

Forrs: http://www.doksi.hu

int (egsz) s long int (hossz egsz) alakban deklarlunk. A hosszabb egszek bizonyosan nem
ignyelnek kevesebb trhelyet, mint a rvidebbek, de az adott nyelvi megvalsts a short int-eket
a long int-ekkel vagy akr mind a kettt kznsges egszekkel (int) egyenl mretv teheti. A
kznsges egszeknek a befogad gp architektrjbl kvetkez termszetes mretk van; a tbbi
mret specilis ignyek kielgtsre szolgl.
Az unsigned-knt deklarlt, eljel nlkli egszekre a modulo Zn aritmetika szablyai vonatkoznak,
ahol n a bitek szma az adott megvalstsban. (A PDP-11 az eljel nlkli long mennyisgeket nem
tmogatja.)
Az egyszeres pontossg lebegpontos (float) s a duplapontossg lebegpontos (double) brzols
egyes gpeken azonos lehet.
Mivel az emltett tpus objektumok clszeren rtelmezhetk szmokknt, ezekre mint aritmetikai
tpusokra fogunk hivatkozni. Az sszes char s int tpust (mrettl fggetlenl) egyttesen integrlis
tipusnak, a float-ot s a double-t egyttesen lebegpontos tipusnak fogjuk nevezni.
Az alapvet aritmetikai tpusokon kivl elvileg vgtelen szm leszrmaztatott tpus kpezhet az
alaptpusokbl, az albbi mdokon:
tmbk, amelyek a legtbb tpus objektumbl kpezhetk;
fggvnyek, amelyek adott tpus objektumot adnak vissza;
mutatk, amelyek adott tpus objektumra mutatnak;
struktrk, amelyek klnfle tpus objektumok
sorozatt tartalmazzk;
unionok, amelyek klnfle tpus objektumok brmelyikt tartalmazhatjk.
Az objektumok ltrehozsnak ezek a mdszerei ltalban rekurzv mdon alkalmazhatk.
5.
Objektumok s balrtkek
Az objektum a tr valamely mveletekkel kezelhet rsze; a balrtk (lvalue) objektumra hivatkoz
kifejezs. A balrtk kifejezsre kzenfekv plda az azonost. Bizonyos opertorok balrtkeket
eredmnyeznek: ha E mutat tpus kifejezs, akkor *E olyan balrtk kifejezs, amely arra az
objektumra hivatkozik, amire az E mutat. A balrtk elnevezs az E1 =E2 rtkad kifejezsbl
szrmazik, amelyben az E1 bal oldali operandusnak balrtk kifejezsnek kell lennie. Az egyes
opertorok albb kvetkez ismertetse sorn kzljk hogy az adott opertor balrtk
operandusokat vr-e s hogy balrtket ad-e eredmnyl.
6.
Konverzik
Operandusuktl fggen szmos opertor vlthatja ki valamelyik operandusa rtknek egyik tpusbl
valamilyen msik tpusba trtn talaktst. Ebben a szakaszban az ilyen konverzik vrhat
eredmnyt ismertetjk. A kznsges opertorok tbbsge ltal megkvetelt konverzikat a 6.6.
pontban foglaltuk ssze; ezt szksg szerint az egyes opertorok trgyalsnl tovbbi informcikkal
egsztettk ki.
6.1.
Karakterek s egszek
Karaktert s rvid _egszt mindentt hasznlhatunk, ahol kznsges egsz hasznlhat. Az rtk
minden esetben int-t alakul. Rvidebb egsz hosszabb egssz trtn konvertlsa mindig eljelkiterjesztssel jr: az egszek eljeles mennyisgek. Az adott gptl fgg, hogy karakterek esetben
is trtnik-e eljel-kiterjeszts, de annyi bizonyos, hogy a szabvnyos karakterkszlet valamennyi
eleme nemnegatv. Azok kzl a szmtgpek kzl, amelyeket ez a kziknyv figyelembe vesz,
csak a PDP- 11 vgez eljel-kiterjesztst. A PDP-11 -en a karakter tpus vltozk rtktartomnya
-128 s 127 kztt van; az sszes ASCII karakter pozitv. Az oktlis escape-szekvencia segtsgvel
megadott karakterllandkra eljel-kiterjeszts trtnik, s negatvknt is megjelenhetnek, pl.
\077 rtke -1.
Ha egy hosszabb egszt rvidebb egssz vagy char-r alaktunk, a levgs bal oldalon trtnik : a
felesleges bitek egyszeren elmaradnak.

Forrs: http://www.doksi.hu

6.2.
Float s double
A C-ben mindenfle lebegpontos mvelet duplapontossg; amikor egy kifejezsben float fordul
el, az a trt rsz nullkkal val kitltse rvn double-l hosszabbodik. Ha double-t kell float-t
alaktani, pl. rtkads sorn, a double elszr kerektdik s csak ezutn rvidl float
hosszsgv.
6.3.
Lebegpontos s integrlis mennyisgek
A lebegpontos rtkek integrlis tpusv alaktsa ltalban elgg gpfgg mvelet;
klnskppen a negatv szmok csonktsnak irnya vltozik gprl gpre. Ha a rendelkezsre
ll helyen az eredmny nem fr el, hatrozatlan lesz. Integrlis rtkek lebegpontoss alaktsa
problmamentes. A pontossg nmileg cskken, ha a clhelyen nincs elegend bit.
6.4.
Mutatk s egszek
Az int vagy long int mennyisgek a mutatkhoz hozzadhatk vagy azokbl levonhatk; ebben az
esetben az elbbiek az sszead opertornl lertak szerint alakulnak t.
Kt, ugyanolyan tpust megcmz mutat egymsbl kivonhat: ez esetben az eredmny egssz
alakul t, amint azt a kivon opertornl trgyaljuk.
6.5.
Eljel nlkli egszek
Ha eljel nlkli (unsigned) s kznsges egszeket kombinlunk, a kznsges egsz eljel
nlkliv alakul t, s az eredmny is eljel nlkli. Az rtk az a legkisebb eljel nlkli egsz,
amely kongruens az eljeles egsszel (modulo 2szmret). 2-es komplemens brzolsban a
konverzi csupn elvi, a bitminta valjban nem vltozik.
Ha az eljel nlkli egsz long-g alakul, az eredmny rtke szmszerleg ugyanaz, mint az eljel
nlkli egsz. Igy a konverzi csupn a bal oldali kitlt nullk elhelyezsbl ll.
6.6.
Aritmetikai konverzik
Szmos opertor hasonl konverzit vlt ki, s az eredmnyt ugyanabban a tpusban szolgltatja.
Ezt az eljrst szoksos aritmetikai konverzinak nevezni.
Elszr is minden char vagy short tpus operandus int-t s minden float operandus double-l
alakul.
Ezutn, ha valamelyik operandus double, akkor a msik is double-l alakul, s az eredmny szintn
double lesz.
Egybknt, ha valamelyik operandus long, a msik operandus s az eredmny tpusa is long lesz.
Egybknt, ha valamelyik operandus unsigned, a msik is unsigned-d alakul, s ez lesz az
eredmny tpusa is.
Minden ms esetben mindkt operandusnak int-nek kell lennie s ez lesz az eredmny tpusa is.
7.
Kifejezsek
A kifejezsekben elfordul opertorok precedencija ugyanaz, mint ebben a fejezetben az alfejezetek
(pontok) sorrendje; a legmagasabb precedencia az els. gy pl. azokat a kifejezseket, amelyekre mint a
+ operandusaira hivatkozunk (7.4. pont) a 7. 1 . .. 7.3. pontokban definiljuk. Az egyes pontokon bell
minden opertor azonos precedencij. Minden pontban megadjuk, hogy az ott trgyalt opertorokra
bal-, ill. jobbirny asszociativits vonatkozik-e.
A kifejezsekben alkalmazott opertorok
precedencijt s asszociativitst a 18. pontban kzlt nyelvtan foglalja ssze.
Egyb esetekben a kifejezsek kirtkelsnek sorrendje hatrozatlan. A fordtprogram a
rszkifejezseket sajt megtlse szerint abban a sorrendben szmtja ki, amit leghatkonyabbnak vl,
mg abban az esetben is, ha a rszkifejezseknek mellkhatsaik vannak. A mellkhatsok
elfordulsnak sorrendje meghatrozott. Kommutatv s asszociatv opertorokat (*, +, &, |, n~)
tartalmaz kifejezsek tetszs szerint rendezhetk mg zrjelek jelenltben is; ha adott sorrendben
vgzend kirtkelst kvnunk elrni, explicit ideiglenes vltozt kell hasznlnunk.
A kifejezsek kirtkelse sorn a tlcsorduls s az oszts ellenrzsnek kezelse gpfgg. A C
nyelv minden ltez megvalstsa figyelmen kvl hagyja az egszek tlcsordulst; a 0-val val
oszts kezelse, ill. a lebegpontos kivtelek gprl gpre vltoznak, s ltalban valamilyen knyvtri
fggvnnyel mdosthatk.

Forrs: http://www.doksi.hu

7.1.
Elsdleges kifejezsek
A . s -> szimblumokat, indexelst s fggvnyhvsokat tartalmaz elsdleges kifejezsek
csoportostsa balrl jobbra trtnik.
elsdleges_kifejezs:
azonost
lland
karakterlnc
(kifejezs)
elsdleges_kifejezs [kifejezs]
elsdleges_kifejezs [kifejezslistaopc]
elsdleges_balrtk.azonost
elsdleges_kifejezs->azonost
Kifejezslista:
kifejezs
kifejezslista, kifejezs
Az azonost elsdleges kifejezs, feltve, hogy az albbi ismertetett mdon helyesen deklarltk.
Tpust a deklarcija hatrozza meg. Ha azonban az azonost tpusa valamilyen tmb, akkor az
azonost kifejezs rtke a tmb els objektumt megcmz mutat, s a kifejezs tpusa a tmb
alaptpusra hivatkoz mutat. A tmbazonost tovbb nem balrtk kifejezs. Hasonlkppen a
fggvnyknt deklarlt azonost is a fggvny mutatjv alakul t, kivve, ha valamely
fggvnyhvs fggvnynv-pozcijn fordul el.
Az lland elsdleges kifejezs. Tpusa az alakjtl fggen lehet int, long vagy double. A
karakterllandk tpusa int, a lebegpontos llandk double.
A karakterlnc elsdleges kifejezs. Tpusa eredetileg char-ok tmbje, de az azonostkra vonatkoz
fenti szably rtelmben az a char-mutatv mdosul, s az eredmny a karakterlnc els karaktert
megcmz mutat. (Kivtelt kpeznek egyes kezdetirtk-belltk (l. a 8.6. pontot.))
A zrjelezett kifejezs olyan elsdleges kifejezs, amelynek tpusa s rtke azonos a zrjel nlkli
kifejezsvel. A zrjelek jelenlte nem befolysolja azt a tnyt, hogy a kifejezs balrtk-e vagy sem.
Az elsdleges kifejezs s az azt kvet szgletes zrjelek kztti kifejezs szintn elsdleges
kifejezst kpez [kifejezs]. Az elsdleges kifejezs ltalban valamilyen mutat tpus, az index
kifejezs int, s az eredmny tpusa az a tpus, amelyre a mutat mutat. Az E1[E2] kifejezs definci
szerint azonos a *((E1)+(E2))-vel. Ez a pont, valamint az azonostkkal, a +-szal, ill. *-gal foglalkoz
7.1., 7.2., ill. 7.4. pont az sszes tudnivalt tartalmazza, ami ennek a jellsmdnak a megrtshez
szksges. Az indexelsrl a 14.3. pontban szlunk.
A fggvnyhvs olyan elsdleges kifejezs, amelyet zrjelek kztt a fggvny aktulis
argumentumait alkot kifejezsek esetleg res, vesszkkel elvlasztott listja kvet. Az elsdleges
kifejezsnek fggvny, amely visszaadja . . .-t tpusnak kell lennie, s a fggvnyhvs eredmnye
. . . tpus. Mint a kvetkezkben ltni fogjuk, minden korbban el nem fordult azonost, amelyet
kzvetlenl nyit zrjel kvet, a szvegkrnyezet alapjn egszt visszaad fggvnyknt
deklarldik, gy a legkznsgesebb esetben az egsz rtk fggvnyeket nem kell deklarlni.
A float tpus argumentumok hvs eltt double-l alakulnak t; minden char s short int-t
konvertldik, s a tmbnevek, mint mindig, mutatkk alakulnak. Automatikusan semmilyen ms
konverzi nem trtnik; lnyeges tudnunk, hogy a fordt az aktulis argumentumok tpust nem
hasonltja ssze a formlis argumentumokval.
Ha konverzira van szksg, hasznljunk
tpusmdost szerkezetet (l. a 7.2. s 8.7. pontot).
A fggvnyhvs elksztsekppen msolat kszl minden aktulis paramterrl, gy a C nyelvben
minden argumentumtads szigoran rtk szerint trtnik. A fggvny megvltoztathatja formlis
paramtereinek rtkt, de ezek a vltoztatsok nem befolysolhatjk az aktulis paramterek rtkt.
Lehetsg van viszont mutat tadsra, tudva azt, hogy a fggvny megvltoztathatja annak az
objektumnak az rtkt, amelyre a mutat mutat. A tmbnv mutatkifejezs. Az argumentumok
kirtkelsnek sorrendjt a nyelv nem definilja; ne feledjk, hogy a klnbz fordtk eltrek!
Brmilyen fggvny rekurzv mdon hvhat.

Forrs: http://www.doksi.hu

Egy elsdleges kifejezs, az azt kvet pont s az azutn kvetkez azonost egyttesen kifejezst
alkot. Az els kifejezsnek olyan balrtknek kell lennie, amely struktrt vagy uniont nevez meg, az
azonost pedig meg kell, hogy nevezze a struktra vagy union egy tagjt. Az eredmny a struktra
vagy union megnevezett tagjra vonatkoz balrtk.
Egy elsdleges kifejezs, az azt kvet nyl (amelyet egy - s egy > alkot) s az azutn kvetkez
azonost egyttesen kifejezst alkot. Az els kifejezsnek struktrt vagy uniont megcmz mutatnak
kell lennie, s az azonostnak a struktra vagy union egy tagjt kell megneveznie. Az eredmny olyan
balrtk, amely a mutatkifejezs ltal megcmzett struktra vagy union megnevezett tagjra
vonatkozik. gy az E1->MOS kifejezs azonos a (*E1).MOS kifejezssel. A struktrkkal s
unionokkal a 8.5. pont foglalkozik. A hasznlatukra vonatkozan itt megadott szablyokat a fordt
rugalmasan alkalmazza, hogy ki lehessen lpni a tpusmechanizmusbl (l. a 14.1. pontot).
7.2.
Egyoperandus opertorok
Az egyoperandus opertorokkal alkotott kifejezsek csoportostsa jobbrl balra trtnik.
egyoper_kifejezs:
*kifejezs
&balrtk
kifejezs
!kifejezs
~kifejezs
++balrtk
balrtk
balrtk++
balrtk
(tpusnv) kifejezs
sizeof kifejezs
sizeof (tpusnv)
Az egyoperandus * opertor indirekcit fejez ki: a kifejezs mutat kellhogy legyen, s az eredmny
olyan balrtk, amely a kifejezs ltal megcmzett objektumra vonatkozik. Ha a kifejezs mutat tpus,
akkor az eredmny tpusa a mutatval megcmzett objektum tpusa.
Az egyoperandus & opertor hatsra a balrtk ltal hivatkozott objektumot megcmz mutat
keletkezik. Ha a balrtk tpusa . . ., akkor az eredmny tpusa mutat . . .-ra Az egyoperandus opertor az operandus negatv rtkt eredmnyezi. A szoksos aritmetikai konverzik mennek vgbe.
Eljel nlkli (unsigned) mennyisg esetben a negatv rtket gy kell kiszmtani, hogy 2n-bl
levonjuk az operandus rtkt, (n az int-beli bitek szma). Egyoperandus + opertor nincs. A ! logikai
neglopertor hatsra az eredmny 1 lesz, ha az operandus nulla, 0 lesz, ha az operandus nemnulla.
Az eredmny tpusa int. Brmilyen aritmetikai tpusra s mutatkra alkalmazhat.
A ~ opertor hatsra az operandus 1-es komplemense jn ltre. Megtrtnnek a szoksos aritmetikai
konverzik. Az operandus integrlis tpus kell, hogy legyen.
A ++ opertor balrtk operandusa eltt alkalmazva inkrementlja az operandus ltal hivatkozott
objektumot. Az rtk az operandus j rtke, amely azonban nem balrtk. A ++x kifejezs x+=1-gyel
egyenrtk. A konverzikra vonatkozan l. az sszeadsra (7.4. pont) s rtkad opertorokra (7.14.
pont) vonatkoz ismertetst.
Aopertor, ha balrtk operandusa eltt ll, az elbbiekhez hasonlan dekrementlja az operandust.
Ha a ++ opertort valamely balrtk utn alkalmazzuk, az eredmny a balrtk ltal hivatkozott
objektum rtke lesz. Az eredmny feljegyzse utn az objektum ugyangy inkrementldik, mint az
ellrl alkalmazott ++ opertor esetben. Az eredmny tpusa ugyanaz, mint a balrtk kifejezs.
Ha aopertort valamely balrtk utn alkalmazzuk, az eredmny a balrtk ltal hivatkozott objektum
rtke lesz. Az eredmny feljegyzse utn az objektum ugyangy dekrementldik, mint az eltag
opertor esetben. Az eredmny tpusa ugyanaz, mint a balrtk kifejezs.
Ha egy kifejezst valamelyik adattpus zrjelek kz rt neve elz meg, a kifejezs rtke a megadott
tpusv alakul t. Ezt a konstrukcit tpusmdost szerkezetnek (cast) nevezzk. A tpusneveket a 8.7.
pontban rjuk le.

10

Forrs: http://www.doksi.hu

A sizeof opertor az operandusnak a byte-okban kifejezett mrett lltja el. (A byte-ot a nyelv
csupn sizeof rtknek segtsgvel definilja. Azonban minden ltez megvalstsban a byte az a
terlet, amely alkalmas egy char trolsra.) Tmbre alkalmazva az eredmny az sszes tmbbeli byteok szma lesz. A mretet a kifejezsben elfordul objektumok deklarcii hatrozzk meg. Ez a
kifejezs szemantikailag egsz tpus lland, brhol hasznlhat, ahol llandra van szksg.
Leginkbb olyan rutinokkal trtn kommunikci cljaira hasznlatos, mint pl. a trterlet-foglal
fggvnyek s a be-s kivitel rendszerek.
A sizeof opertor zrjelben ll tpusnvre is alkalmazhat. Ekkor egy, a megjellt tpus objektum
mrett szolgltatja byte-okban.
A sizeof(tpus) szerkezet sszefgg egysg, gy a sizeof(tpus)-2 kifejezs ugyanaz, mint
(sizeof(tpus))-2.
7.3.
Multiplikatv opertorok
A * , / s % multiplikatv opertorok balrl jobbra csoportostanak. Megtrtnnek a szoksos
aritmetikai konverzik.
multiplikatv_kifejezs:
kifejezs * kifejezs
kifejezs / kifejezs
kifejezs % kifejezs
A ktoperandus * opertor a szorzst jelli. A * opertor asszociatv, s az ugyanazon a szinten tbb
szorzst tartalmaz kifejezseket a fordt trendezheti.
A ktoperandus / opertor az osztst jelli. Pozitv egszek
osztsakor a csonkts nulla fel trtnik, de ha brmelyik
operandus negatv, akkor a csonkts formja gpfgg. Az ebben
a kziknyvben figyelembe vett gpek esetben az osztand s a
maradk eljele megegyezik. Mindig igaz, hogy
(a / b) * b + a % b megegyezik a-val (ha b nemnulla).
A ktoperandus % opertor az els kifejezsnek a msodikkal trtn osztsbl szrmaz maradkot
lltja el. A mvelet szoksos aritmetikai konverzikkal jr. Az operandusok nem lehetnek float
tpusak.
7.4.
Additv opertorok
A + s - additv opertorok balrl jobbra csoportostanak. A szoksos aritmetikai konverzikat
eredmnyezik. Mindkt opertor esetben vannak tovbbi tpuslehetsgek.
additv_kifejezs:
kifejezs + kifejezs
kifejezs - kifejezs
A + opertor alkalmazsnak eredmnye az operandusok sszege. Egy tmbbeli objektumot megcmz
mutat s brmelyik integrlis tpus rtke sszeadhat. Az utbbi minden esetben relatv cmm alakul
oly mdon, hogy megszorzdik annak az objektumnak a hosszsgval, amelyre a mutat mutat. Az
eredmny az eredetivel megegyez tpus mutat, amely ugyanannak a tmbnek egy msik elemre
mutat, megfelel eltolssal az eredeti objektumhoz kpest. Ha teht P tmbelemet megcmz mutat,
akkor a P+1 kifejezs a tmb kvetkez elemt megcmz mutat lesz. Mutatkra semmilyen ms
tpus kombinci sem megengedett!
A + opertor asszociatv, s az ugyanazon a szinten tbb sszeadst tartalmaz kifejezseket a fordt
trendezheti. A - opertor alkalmazsnak hatsra a kt operandus klnbsge keletkezik, a szoksos
aritmetikai konverzik alkalmazsval. Ezenkvl mutatkbl le szabad vonni brmely integrlis tpus
rtket, ekkor megtrtnnek ugyanazok a konverzik, mint az sszeadsnl.
Ha kt ugyanolyan tpus objektumot megcmz mutatt vonunk ki egymsbl, az eredmny (az
objektum hosszval trtn oszts rvn) int-t alakul, s a megcmzett objektumok kztt

11

Forrs: http://www.doksi.hu

elhelyezked objektumok darabszmt adja meg. ltalnos esetben ez a konverzi vratlan eredmnyre
vezet, kivve, ha a mutatk ugyanannak a tmbnek az elemeire mutatnak. Ennek az az oka, hogy mg
az ugyanolyan tpus objektumok tvolsga sem felttlenl az objektumhosszsg tbbszrse.
7.5.
Lptet opertorok
A << s >> lptet (shift) opertorok balrl jobbra csoportostanak. Mindkett elvgzi az
operandusokon a szoksos aritmetikai konverzikat; az operandusok mindegyike integrlis kell, hogy
legyen. A mvelet sorn a jobb oldali operandus int-t alakul t; az eredmny tpusa megegyezik a bal
oldali operandusval. Az eredmny hatrozatlan, ha a jobb oldali operandus negatv vagy nagyobb,
mint az objektum bitekben mrt hosszsga, vagy pedig azzal megegyezik.
lptet_kifejezs:
kifejezs << kifejezs
kifejezs >> kifejezs
Az E1<<E2 rtke a bitmintaknt rtelmezett E1 E2 szm bittel balra lptetve; a kirlt bitek 0-val
tltdnek fel. Az E1>>E2 rtke gy ll el, hogy E1 rtke E2 bittel balra lptetdik. A jobbra
garantltan logikai jelleg (0-val trtn feltlts), ha az E1 unsigned; ms esetben aritmetikai lehet (s
a PDP 11 -en az is lesz) ilyenkor a feltltds az eljelbittel trtnik.
7.6.
Relcis opertorok
A relcis opertorok balrl jobbra csoportostanak, de ez a tny nem klnsebben hasznos: a < b <
cjelentse nem az, amit gondolnnk.
relcis_kifejezs:
kifejezs < kifejezs
kifejezs > kifejezs
kifejezs <= kifejezs
kifejezs >= kifejezs
A < (kisebb, mint), > (nagyobb, mint), <= (kisebb vagy egyenl) s >= (nagyobb vagy egyenl)
opertorok mindegyike 0-t eredmnyez, ha a megadott relci rtke hamis, s 1 -et, ha igaz. Az
eredmny tpusa int. A mveletek a szoksos aritmetikai konverzikkal jrnak. Kt mutat
sszehasonlthat: az eredmny a megcmzett objektumok cmnek a cmtartomnyban val egymshoz
kpesti elhelyezkedstl fgg. A mutat sszehasonlts csak akkor gpfggetlen, ha a mutatk
ugyanabban a tmbben elhelyezked objektumokra mutatnak.
7.7.
Egyenlsgi opertorok
egyenlsg_kifejezs:
kifejezs == kifejezs
kifejezs != kifejezs
A == (egyenl) s != (nem egyenl) opertorok pontosan
ugyanolyanok, mint a relcis opertorok - csak a precedencijuk
alacsonyabb. (Igy
a < b == c < d rtke 1 , ha a < b s c < d igazsgrtke megegyezik.) Mutat s egsz
sszehasonlthat, de az eredmny gpfgg, kivve ha az egsz a 0 lland. Az a mutat, amelyhez a
0-t rendeltnk hozz, garantltan nem mutat semmilyen objektumra, s 0-val egyenlknt fog
megjelenni; a hagyomnyos hasznlatban az ilyen mutatt nullnak tekintjk.
7.8.
Bitenknti S opertor
s_kifejezs:
kifejezs & kifejezs
Az & opertor asszociatv, s az &-et tartalmaz kifejezsek trendezhetk. A szoksos aritmetikai
konverzik mennek vgbe; az eredmny az operandusok bitenknti S fggvnye. Az opertor csak
integrlis operandusokra alkalmazhat!

12

Forrs: http://www.doksi.hu

7.9.
Bitenknti kizr VAGY opertor
kizr_vagy_kifejezs:
kifejezs ^ kifejezs
A ^ opertor asszociatv, s a ^-t tartalmaz kifejezsek trendezhetk. A mvelet a szoksos
aritmetikai konverzikkal jr; az eredmny az operandusok bitenknti kizr VAGY fggvnye. Az
opertor csak integrlis operandusokra alkalmazhat!
7.10.
Bitenknti inkluzv VAGY opertor
inkluzv vagy_kifejezs:
kifejezs | kifejezs
A | opertor asszociatv, s a |-ot tartalmaz kifejezsek trendezhetk. A mvelet a szoksos
aritmetikai konverzikkal jr; az eredmny az operandusok bitenknti inkluzv VAGY fggvnye. Az
opertor csak integrlis operandusokra alkalmazhat!
7.11.
Logikai S opertor
logikai s_kifejezs:
kifejezs && kifejezs
Az && opertor balrl jobbra csoportost. 1-et ad vissza; ha egyik operandusa sem nulla, egybknt 0t. Az &-tl eltren az && biztostja a balrl jobbra trtn kirtkelst; ezen fell a msodik
operandus nem rtkeldik ki, ha az els 0. Az operandusoknak nem kell azonos tpusaknak lennik,
de mindegyikk tpusa vagy valamelyik alaptpus, vagy pedig mutat kell, hogy legyen. Az eredmny
mindig int.
7.12.

logikai VAGY opertor


logikai vagy_kifejezs:
kifejezs || kifejezs
A || opertor balrl jobbra csoportost. 1_t ad vissza, ha valamelyik operandusa nemnulla, 0-t
egybknt. A |-tl eltren a || biztostja a balrl jobbra trtn kirtkelst; ezen fell a msodik
operandus nem rtkeldik ki, ha az els nemnulla. Az operandusoknak nem kell azonos tpusaknak
lennik, de mindegyikk tpusa vagy valamelyik alaptpus, vagy pedig mutat kell, hogy legyen. Az
eredmny mindig int.
7.13.
A feltteles opertor
feltteles_kifejezs:
kifejezs ? kifejezs : kifejezs
A feltteles kifejezsek balrl jobbra csoportostanak. Az els kifejezs kirtkeldik, s ha az rtke
nemnulla, az eredmny a msodik kifejezs rtke lesz, egybknt pedig a harmadik kifejezs.
Lehetsg szerint megtrtnnek a szoksos aritmetikai konverzik, amelyek rvn a msodik s a
harmadik kifejezs azonos tpusv vlik; egybknt, ha mindkett ugyanolyan tpus mutat, az
eredmny tpusa ez a kzs tpus lesz; vagy pedig az egyiknek mutatnak, a msiknak a 0 llandnak
kell lennie, s az eredmny tpusa a mutat tpusa lesz. A msodik s a harmadik kifejezs kzl csak
az egyik rtkeldik ki.
7.14.
rtkad opertorok
Tbb rtkad opertor van, amelyek mindegyike jobbrl balra csoportost. Bal oldali operandusknt
mindegyikk egy-egy balrtket ignyel, az rtkad kifejezs tpusa a bal oldali operandus tpusval
fog megegyezni. Az rtkad_ kifejezs rtke az az rtk lesz, amely az rtkads utn a bal oldali
operandusban tallhat. Az sszetett rtkad opertor kt rsze klnll szintaktikai egysget kpez.
rtkad_kifejezs:
balrtk = kifejezs

13

Forrs: http://www.doksi.hu

balrtk += kifejezs
balrtk -= kifejezs
balrtk *= kifejezs
balrtk /= kifejezs
balrtk %= kifejezs
balrtk >>= kifejezs
balrtk <<= kifejezs
balrtk &= kifejezs
balrtk ^= kifejezs
balrtk |= kifejezs
A legegyszerbb rtkadsnl, ahol az = opertort alkalmazzuk, a kifejezs rtke behelyettestdik a
balrtk ltal hivatkozott objektum rtkbe. Ha mindkt operandus aritmetikai tpus, a jobb oldali
operandus mg az rtkads eltt bal oldali tpusv alakul t.
Az
E1 op= E2
alak kifejezs hatst kikvetkeztethetjk, ha azt
E1 = E2 op (E2) alaknak tekintjk; az E1 azonban csak egyszer rtkeldik ki. A += s -= esetben a
bal oldali operandus mutat is lehet, ekkor az (integrlis)jobb oldali operandus a 7.4. pontban
mondottak szerint alakul t; minden jobb oldali operandus s az sszes nem-mutat jelleg bal oldali
operandus aritmetikai tpus kell, hogy legyen.
A jelenlegi fordtk megengedik mutat rtkl adst egsznek, egszt mutatnak, valamint mutatt
ms tpus mutatnak. Az rtkads tisztnmsolsi mvelet, konverzi nlkl. Ez a fajta hasznlat
gpfgg, s olyan mutatkat eredmnyezhet, amelyek hasznlatuk sorn cmzsi problmkhoz
vezetnek. Annyi azonban bizonyos, hogy a 0 llandnak mutathoz val hozzrendelse olyan nullamutatt eredmnyez, amely brmilyen objektumot jell mutattl megklnbztethet.
7.15.
A vessz opertor
vessz_kifejezs:
kifejezs , kifejezs
A vesszvel elvlasztott kifejezspr balrl jobbra rtkeldik ki, s a bal oldali kifejezs rtke
megegyezik a jobb oldali operandus tpusval s rtkvel. Ez az opertor balrl jobbra csoportost.
Olyan szvegkrnyezetben, ahol a vessznek specilis jelentse van, pl. fggvnyek aktulis
argumentumainak listjban (7.1. pont) s a kezdeti rtkek listjban (8.6. pont), az itt ismertetett
vessz opertor csak zrjelek kztt jelenhet meg; pl.
f (a, (t = 3 , t + 2), c)
nek hrom argumentuma van; ezek kzl a msodiknak az rtke 5.

8.
Deklarcik
A deklarcik segtsgvel hatrozzuk meg, hogyan rtelmezze a C fordt az egyes azonostkat; a
deklarcik nem felttlenl jelentenek trterlet-foglalst az azonost szmra. A deklarcik alakja:
deklarci:
dekl._specifiktorok deklartorlistaopc;
A deklartorlistban elhelyezked deklartorok a deklarland azonostkat tartalmazzk. A
deklarcispecifiktorok tpus- s trolsiosztly-meghatrozsok sorozatbl llnak.
dekl._specifiktorok:
tpusspecifiktor dekl._specifiktorokopc
t.o._specifiktor dekl._specifiktorokopc
A listt az albbiak szerint kvetkezetesen kell
megszerkeszteni.

14

Forrs: http://www.doksi.hu

8.1.

Trolsiosztly-specifiktorok A trolsiosztly-specifiktorok az albbiak:


t.o._specifiktor:

auto
static
extern
register
typedef
A typedef specifiktor nem foglal trhelyet, s csak a szintaktikai knyelem kedvrt nevezzk
trolsiosztly-specifiktornak (l. a 8.8. pontot). A klnfle trolsi osztlyok jelentst a 4. pontban
ismertettk. Az auto, static s register deklarcik definciknt is szolglnak, amennyiben megfelel
nagysg trterlet lefoglalst is elidzik. Az extern esetben a megadott azonostk kls
defincijnak (10. pont) is szerepelnie kell valahol azon a fggvnyen kvl, amelyben deklarltuk
ket. A register deklarcit legclszerbb olyan auto deklarcinak tekinteni, amely mg azt is jelzi a
fordtnak, hogy a deklarlt vltozkat srn fogjuk hasznlni. Csupn az els nhny ilyen
deklarcinak lesz hatsa. Ezenkvl csupn nhny tpus troldik tnylegesen regiszterekben; a PDP11 -en ezek a tpusok az int, a char s a mutat. Mg egy megszorts vonatkozik a regiszter tpus
vltozkra: nem alkalmazhat rjuk az & (cme valaminek) opertor. A regiszterdeklarcik megfelel
hasznlatval kisebb mret, gyorsabb programokhoz juthatunk, a kdgenerls tovbbfejlesztsvel
azonban lehet, hogy alkalmazsuk feleslegess vlik.
Egy deklarciban legfeljebb egy t. o. -specifiktort lehet megadni. Ha a t.o._specifiktor hinyzik a
deklarcibl, akkor azt a fordt fggvnyen bell auto-nak, fggvnyen kvl extern-nek tekinti.
Kivtel: a fggvnyek sohasem automatikusak!
8.2.
Tpus-specifiktorok A tpus-specifiktorok az albbiak :
tpus-specifiktor:
char
short
int
long
unsigned
float
double
strukt._vagy_union_specifiktor
typedef_nv
A long (hossz), short (rvid) s unsigned (eljel nlkli) szavakat jelzknek tekinthetjk; az albbi
kombincik fogadhatk el:
short int
long int
unsigned int
long float
Az utbbi ugyanazt jelenti, mint a double. Egybknt egy deklarcin bell legfeljebb egy tpusspecifiktor adhat meg. Ha a deklarcibl hinyzik a tpus-specifiktor, akkor a deklarlt vltozt a
fordt int-nek tekinti.
Struktrk s unionok specifiktoraival a 8.5. pont foglalkozik; a typedef nevekkel trtn
deklarcikat a 8.8. pont trgyalja.
8.3.
Deklartorok
A deklarciban megjelen deklartorlista deklartorok vesszkkel elvlasztott sorozata, amelyek
mindegyike kezdeti rtkkel (k..) rendelkezhet.
deklartorlista:
k.._deklartor
k.._deklartor , deklartorlista
k.._deklartor:

15

Forrs: http://www.doksi.hu

deklartor inicializlopc
A kezdeti rtkekkel a 6.6. pont foglalkozik. A deklarcibeli specifiktorok megadjk azoknak az
objektumoknak a tpust s trolsi osztlyt, amelyekre a deklartorok vonatkoznak. A deklartorok
szintaxisa:
deklartor:
azonost
(deklartor)
*deklartor
deklartor ()
deklartor [lland_kifejezsopc]
A csoportosts ugyanolyan, mint a kifejezsekben.
8.4.
A deklartorokjelentse
Minden deklartort arra vonatkoz lltsnak tekinthetnk, hogy ha valamely kifejezsben a
deklartorral megegyez alak szerkezet jelenik meg, akkor az a megjellt tpus s trolsi osztly
objektumot fogja eredmnyezni. Minden deklartor pontosan egy azonostt tartalmaz, ez az azonost
az, amelyet deklarlunk.
Ha deklartorknt bvtmny nlkli azonost szerepel, akkor annak tpusa az lesz, amit a deklarcit
bevezet specifiktor megjell.
A zrjelek kztti deklartor azonos a zrjel nlklivel, de az sszetett deklartorok ktsi sorrendje
zrjelekkel megvltoztathat (l. a kvetkez pldkat).
Most kpzeljk el a
T D1
deklarcit, ahol T a tpus-specifiktor (mint az int stb.) s
D1 a deklartor. Tegyk fel, hogy e deklarci hatsra az
azonost tpusa . . .T lesz, ahol . . res, ha D1 csupn
sima azonost (teht x tpusa int x-ben egyszeren int). Ha
viszont D1 alakja
*D akkor az ltala tartalmazott azonost tpusa . . .mutat T-re.
Ha D1 alakja
D ()
akkor az ltala tartalmazott azonost tpusa . . . fggvny, amely T-t ad vissza.
Ha D1
D [lland_kifejezs]
vagy
D []
alak, akkor az ltala tartalmazott azonost tpusa T . . . tmbje. Az els esetben az lland
kifejezs olyan kifejezs, amelynek rtke fordtsi idben meghatrozhat s amelynek tpusa int Az
lland kifejezsek pontos defincija a 15. pontban tallhat.) Ha tbb . . .tmbje specifikci
egymssal szomszdos, akkor tbbdimenzis tmb keletkezik; a tmbhatrokat rgzt lland
kifejezsek csupn a sorozat els tagjnl hinyozhatnak. Ez az elhagys akkor hasznos, ha kls
tmbrl _ van sz, s a trfoglalst elidz definci mshol szerepel. Az els lland kifejezs akkor
is elhagyhat, ha a deklartort kezdeti rtk kveti. Ilyenkor a fordt a mretet a megadott kezdeti
rtkek szmbl szmtja ki.

16

Forrs: http://www.doksi.hu

Tmbt az alaptpusok valamelyikbl, mutatkbl, struktrkbl, unionokbl vagy ms tmbkbl


(tbbdimenzis tmbt generlva) alkothatunk.
A fenti szintaxissal definilt lehetsgek kzl nem mindegyik megengedett. A megszortsok a
kvetkezk : fggvnyek nem adhatnak vissza tmbket, struktrkat, unionokat vagy fggvnyeket, de
visszaadhatnak ilyeneket megcmz mutatkat; fggvnyekbl nem kpezhet tmb, de ltezik
fggvnyeket megcmz mutatkbl kpzett tmb. Hasonlkppen, a struktrk s unionok sem
tartalmazhatnak fggvnyt, legfeljebb fggvnyt megcmz mutatt.
Pldul
int i, *ip, f (), *fip (), (*pfi) () deklarlja az i egszt, az ip egszt megcmz mutatt, az egszt visszaad
f fggvnyt, az egszt megcmz mutatt visszaad fip fggvnyt s a pfi mutatt, amely egy egszt
visszaad fggvnyre mutat. Klnsen hasznos ha a kt utolst hasonltjuk ssze. A *fip() ktsi
sorrendje *(fip()), gy a deklarci azt rja el, ill. egy kifejezsben elfordul ilyen szerkezet azt vltja
ki, hogy a fip fggvny meghvsa utn a (mutatjelleg) eredmnyen keresztli indirekcival egy
egsz lljon el. A (*pfi)() deklartorban (vagy a szerkezetet felhasznl kifejezsekben) a plusz
zrjelek szksgesek: azt jelzik, hogy a fggvnyt megcmz mutatn keresztli indirekci fggvnyt
eredmnyez, amely meghvsa utn egszt ad vissza.
Msik pldaknt
float fa [17], *afp [17];
egy float szmokbl ll tmbt s egy float szmokat megcmz
mutatkbl ll tmbt deklarl. Vgezetl
static int x3d [3)[5][7]; egszek statikus, hromdimenzis tmbjt deklarlja, amelynek mrete 3 * 5
* 7. Rszleteiben nzve x3d hromelem tmb; minden elem t tmbt tartalmaz; az utbbiak
mindegyike 7 darab egszbl ll. Az x3d, x3d[i], x3d[i][j], x3d[i][j][k] alakok brmelyike elfordulhat
valamely kifejezsben. Az els hrom tmb tpus, az utols tpusa int.
8.5.
Struktra- s union deklarcik
A struktra nvvel elltott tagok sorozatt tartalmaz objektum. Minden tag tetszleges tpus lehet. Az
union olyan objektum, amely adott idpillanatban tbb lehetsges tag brmelyikt tartalmazhatja. A
struktra- s az unionspecifiktorok azonos alakak.
strukt._vagy_union_specifiktor:
strukt._vagy_union { strukt._dekl._lista}
strukt._vagy_union azonost {strukt._dekl._lista}
strukt._vagy_union azonost
strukt._vagy_union:
struct
union
A struktradeklartor-lista a struktra vagy union tagjaira vonatkoz deklarcik felsorolsa:
strukt._dekl._lista:
strukt._deklarci
strukt._deklarci strukt._dekl._lista
strukt._deklarci:
tpus_specifiktor strukt._deklartor_lista strukt._deklartor_lista:
strukt._deklartor
strukt._deklartor , strukt._deklartor_lista
Kznsges esetben a strukt. deklartor egyszeren a struktra vagy union valamely tagjnak
deklartora. A struktra tagjai adott szm bitet is tartalmazhatnak. Az ilyen tag neve mez (field),
hosszt a nvtl kettspont vlasztja el.

17

Forrs: http://www.doksi.hu

strukt. _deklartor:
deklartor
deklartor : lland_kifejezs
: lland_kifejezs
A struktrn bell a deklarlt objektumok cmei a deklarcikban balrl jobbra haladva nvekednek. A
struktra minden nem-mez tagja a tpusnak megfelel cmhatron kezddik, gy a struktrban nv
nlkli lyukak helyezkedhetnek el. A mez jelleg tagok gpi egszekben helyezkednek el,
szhatrokon nem nylnak t. Az a mez, amely nem fr el egy szban mg fennmaradt helyen, a
kvetkez szba kerl. A mez nem lehet szlesebb, mint a sz. Mezk hozzrendelse PDP-11-en
jobbrl balra, ms gpeken balrljobbra trtnik.
A deklartor nlkli, csupn kettspontot s a szlessget tartalmaz struktradeklartor olyan nv
nlkli mezt jell ki, amelyet kvlrl elrt elrendezseknek megfelel kitltsre hasznlhatunk.
Specilis esetben a 0 szlessg nv nlkli mez a kvetkez mez szhatrra trtn illesztst rja
el. A kvetkez mez felteheten tnyleg mez, nem pedig kznsges struktratag, mivel az utbbi
esetben ez az illeszts automatikusan megtrtnne.
A nyelv nem r el korltozst a mezknt deklarlt objektumok tpusra vonatkozlag, a
megvalstsoktl azonban nem vrjuk el, csak az egsz tpus mezk tmogatst. St, mg az int
mezket is eljel nlklinek tekinthetik. A PDP-11-en a mezknek nincs eljelk, s csak egsz
rtkek lehetnek. Egyetlen megvalstsban sincsenek mezkbl kpzett tmbk, tovbb a mezkre
az & cmopertor sem alkalmazhat, vagyis nincsenek mezket megcmz mutatk sem.
Az uniont olyan struktrnak kpzelhetjk, amelynek tagjai a 0 relatv cmen kezddnek, s amelynek
mrete elegenden nagy ahhoz, hogy brmelyik tagjt tartalmazhassa. Az union egyszerre legfeljebb
egy tagjt tartalmazhatja.
A msodik alak struktra- vagy unionspecifiktor, vagyis a
struct azonost {strukt._dekl._lista}
union azonost {strukt._dekl._lista}
egyike, az azonostt a lista ltal meghatrozott struktra
struktracmkjeknt (vagy unioncmkjeknt) deklarlja. Az ezt
kvet deklarcikban azutn a specifiktor harmadik alakja, a
struct azonost
union azonost
alakok egyike hasznlhat. A struktracmkk lehetv teszik nhivatkoz struktrk definilst;
megengedik, hogy a deklarci hossz rszt csupn egyszer adjuk meg s tbb alkalommal hasznljuk.
Tilos olyan struktrt vagy uniont deklarlni, amelyben sajt maga elfordul, de a struktra vagy union
tartalmazhat sajt magt megcmz mutatt!
A tagok s cmkk nevei megegyezhetnek a kznsges vltozk neveivel. A cmkk s a tagok
nevnek azonban egymstl el kell trnik!
Kt struktrnak lehet kzs kezdeti tagsorozata, azaz ugyanaz a tag kt klnbz struktrban is
megjelenhet, ha mindkettben azonos a tpusa s ha az sszes megelz tag is mind a kettben azonos.
(A fordt tulajdonkppen csak azt ellenrzi, hogy a kt klnbz struktrban elfordul nv tpusa
s relatv cme megegyezik-e, de ha a megelz tagok klnbznek, akkor a szerkezet nem
gpfggetlen.)
A struktradeklarci egyszer pldja:
struct

tnode {
char tword [20];
int count;
struct tnode * left;
struct tnode *right;

};
amely 20 karakterbl ll tmbt, egy egszt s kt, hasonl
struktrt megcmz mutatt tartalmaz. E deklarci megadsa

18

Forrs: http://www.doksi.hu

utn a
struct tnode s, *sp;
deklarci szerint s a megadott jelleg struktra lesz, s sp az
ilyen jelleg struktrt megcmz mutat. Ezeknek a
deklarciknak az alapjn az
sp->count kifejezs annak a struktrnak a count nev mezjre mutat, amelyre az sp utal;
s.left
az s struktra bal oldali rszfjnak mutatjra vonatkozik, mg
s.right->tword [0] az s struktra jobb oldali rszfja tword nev tagjnak els karakterre utal.
8.6.
Inicializls
A deklartor megadhatja a deklarlt azonost kezdeti rtkt. Az inicializlt = elzi meg, s kapcsos
zrjelek kz zrt kifejezst vagy rtklistt tartalmaz.
inicializl:
= kifejezs
= { inicializl_lista }
= { inicializl_lista ,}
inicializl_lista:
kifejezs
inicializl_lista , inicializl_lista
( inicializl_lista )
A statikus vagy kls vltozk inicializliban kizrlag lland kifejezsek (l. a 15. pontot), vagy
pedig olyan kifejezsek szerepelhetnek, amelyek valamelyik korbban deklarlt vltoz cmre
reduklhatk (az albbitl egy lland kifejezssel val cmeltols is lehetsges). Az automatikus s
regisztervltozk esetben tetszleges inicializls lehetsges llandk, korbban deklarlt vltozk s
fggvnyek bevonsval. Inicializlatlan statikus s kls vltozk kezdeti rtke garantltan nulla; az
inicializlatlan automatikus s regisztervltozkban pedig indulskor biztos hulladk van. Ha az
inicializlt skalr mennyisgre (mutatra vagy aritmetikai tpus objektumra) alkalmazzuk, tartalma
egyetlen, esetleg kapcsos zrjelek kztti kifejezs. Az objektum kezdeti rtkt a gp a kifejezs
alapjn szmtja ki; a konverzik ugyanazok, mint rtkadsnl.
Ha a deklarlt vltoz aggregtum (struktra vagy tmb jelleg sszetett mennyisg), akkor az
inicializl az aggregtum tagjainak kapcsos zrjelek kztti, vesszkkel elvlasztott listjt
tartalmazza. Az inicializlkat az indexek vagy tagok nvekv sorrendjben adjuk meg. Ha az
aggregtum rszaggregtumokat tartalmaz, ugyanez a szably vonatkozik rekurzv mdon az
aggregtum tagjaira. Ha a listban kevesebb inicializl van, mint ahny tagja van az aggregtumnak,
akkor az aggregtum nullkkal tltdik ki. Unionok s automatikus aggregtumok inicializlsa nem
megengedett!
A kapcsos zrjeleket a kvetkez mdon hagyhatjuk el. Ha az inicializl bal oldali kapcsos zrjellel
kezddik, akkor a rkvetkez, vesszkkel elvlasztott inicializllista az aggregtum tagjait
inicializlja; Ha, ha itt tbb inicializl van, mint tag. Ha azonban az inicializl nem bal oldali kapcsos
zrjellel kezddik, akkor a fordtprogram a listbl csupn az aggregtum tagjainak megfelel szm
elemet vesz figyelembe; a listban fennmarad tagok annak az aggregtumnak a kvetkez elemt
fogjk inicializlni, amelynek a szban forg aggregtum a rsze.
Vgl megemltjk, hogy a char tmbk rviden, karakterlncokkal inicializlhatk. Ez esetben a lnc
egymst kvet karakterei a tmb egyes elemeit inicializljk.
Inicializlsi pldk:
int x [] = {1,3,5}; az x-et olyan egydimenzis tmbknt deklarlja s inicializlja, amelynek hrom
eleme van, mivel mretet nem adtunk meg s hrom inicializl van.
float y [4][3] ={

19

Forrs: http://www.doksi.hu

{1, 3, 5},
{2, 4, 6},
{3, 5, 7},
};
teljes zrjelezett inicializls: 1 , 3 s 5 az y[0] tmb els
sort, mgpedig az y[0][0], y[0][1] s y[0][2] elemeket
inicializljk. A kvetkez kt sor hasonl mdon inicializlja
y[1]-et s y[2]-t. Az inicializl tl hamar r vget, s ezrt
y[3] 0-val inicializldik. Pontosan ugyanezt az eredmnyt rtk
volna el
float y [4][3] ={
1, 3, 5, 2, 4, 6, 3, 5, 7
};
megadsval. y inicializlja bal oldali kapcsos zrjellel kezddik, de y[0]- nem, gy a gp a listbl
hrom elemet hasznl fel. Hasonlkppen a kvetkez hrom y[1 ]-, az azt kvet hrom pedig y[2]-
lesz. Ugyangy,
;
float y [4][3] ={
{1}, {2}, {3}, {4}
};
a (ktdimenzis tmbnek tekintett) y els oszlopt inicializlja s a tbbi elemet 0 rtknek hagyja
meg.
Vgezetl
char msg [] = Szintaktikai hiba a %s-edik sorban \n;
olyan karaktertmbt mutat, amelynek elemeit
karakterlnccal inicializltuk.

8.7.
Tpusnevek
Kt sszefggsben (tpusmdost szerkezettel vgzett explicit tpuskonverzi esetn s a sizeof
argumentumaknt) kell valamilyen adattpus nevt megadnunk. Ez tpusnv hasznlatval trtnik, ami
lnyegben egy adott tpus objektum olyan deklarcija, amelybl hinyzik az objektum neve.
tpus_nv:
tpus_specifiktor absztrakt_deklartor absztrakt_deklartor:
res
( absztrakt_deklartor )
*absztrakt_deklartor
absztrakt_deklartor ()
absztrakt_deklartor [lland_kifejezsopc]
A ktrtelmsg elkerlse rdekben az
( absztrakt_deklartor ) szerkezetben az absztraktdeklartor nem lehet res. E megszorts
figyelembevtelvel egyrtelmen azonosthat az absztrakt-deklartorban az a hely, ahol az azonost
megjelenne, ha a szerkezet egy deklarcin belli deklartor lenne. A megnevezett tpus ekkor ugyanaz
lesz, mint a hipotetikus azonost tpusa. Pl.
int
int *
int *[3]
int (*) [3]

20

Forrs: http://www.doksi.hu

int * ()
int (*) ()
sorban megnevezi az egsz, egszt megcmz mutat, 3 darab egszmutatbl ll tmb, 3 egszbl
ll tmbt megcmz mutat, egszt megcmz mutatt visszaad fggvny s az egszt visszaad
fggvnyt megcmz mutattpusokat.
8.8.
Typedef
Az olyan deklarcik, amelyeknek a trolsi osztlya typedef, nem trterletet definilnak, hanem olyan
azonostkat, amelyeket a ksbbiekben gy hasznlhatunk, mintha az alapvet vagy a leszrmaztatott
tpusokat megnevez kulcsszavak lennnek:
typedef_nv:
azonost
A typedef-et tartalmaz deklarci rvnyessgi tartomnyn bell minden ott elfordul deklartor
rszeknt megjelen azonost szintaktikusan egyenrtk lesz azzal a tpuskulcsszval, amely a 8.4.
pontban lert mdon megnevezi az azonosthoz trstott tpust. Pl.
typedef int MILES, *KLICKSP; typedef struct { double re, im;}complex;
utn a
MILES distance; extern KLICKSP metricp; complex z, *zp;
szerkezetek mindegyike megengedett deklarci; a distance tpusa int, a metricp- int-et megcmz
mutat, a z- pedig a megadott struktra. zp az ilyen struktrt megcmz mutat. A typedef nem
teljesen j tpusokat vezet be, csupn ms mdon is megadhat tpusok szinonimit. Igy a fenti
pldban distance pontosan ugyanolyan tpus, mint minden ms int objektum.
9.
Utastsok
Az utastsok egymst kveten, sorban hajtdnak vgre, az ettl val eltrst kln jelezzk.
9.1.
A kifejezs utasts A legtbb utasts kifejezs jelleg; ezek alakja:
kifejezs;
A kifejezs jelleg utastsok legtbbszr rtkadsok vagy fggvnyhvsok.
9.2.
Az sszetett utasts vagy blokk
Annak rdekben, hogy ott, ahol elvileg csak egy utasts helyezhet el, tbb utasts is hasznlhat
legyen, rendelkezsre ll az sszetett utasts (ms szval blokk).
sszetett_utasts:
{ deklarcilistaopc utastslistaopc} deklarcilista:
deklarci
deklarci deklarcilista
utastslista:
utasts
utasts utastslista
Ha a deklarcilistban elfordul brmelyik azonostt mr korbban deklarltuk, a kls deklarci a
blokk vgrehajtsnak idtartamra rvnyt veszti, majd annak befejeztvel visszanyeri hatlyt.
Az auto s register vltozk brmilyen inicializlsa minden alkalommal jra megtrtnik, amikor a
vezrls a blokkba fellrl belp. Jelenleg lehetsges (de helytelen gyakorlat) a blokk belsejbe val
ugrats; ez esetben az inicializlsok elmaradnak. A static vltozk kezdeti rtknek belltsa csupn
egyszer, a program vgrehajtsnak kezdetn trtnik meg. A blokkon bell az extern deklarcik
hatsra nincs trfoglals, gy ezek inicializlsa nem megengedett.

21

Forrs: http://www.doksi.hu

9.3.
A feltteles utasts
if (kifejezs)
utasts
if (kifejezs)
utasts
else utasts
A gp mindkt esetben kirtkeli a kifejezst, s ha rtke nemnulla, az els alutastst hajtja vgre. A
msodik esetben, ha a kifejezs rtke 0, a msodik alutastst hajtja vgre. Az else-vel kapcsolatos
szoksos ktrtelmsget a C gy oldja fel, hogy az else az utoljra tallt else nlkli if-hez ktdik.
9.4.
A while utasts A while utasts alakja:
while (kifejezs)
utasts
Az alutasts vgrehajtsa mindaddig ismtldik, amg a kifejezs rtke nemnulla marad. A vizsglat
mindig az utasts egyes vgrehajtsai eltt trtnik.
9.5.
A do utasts
A do utasts alakja
do
utasts
while (kifejezs);
Az alutasts vgrehajtsa mindaddig ismtldik, amg
kifejezs rtke nullv nem vlik. A vizsglat mindig az
utasts egyes vgrehajtsai utn trtnik.

9.6.
A for utasts A for utasts alakja:
for (1._kifejezsopc; 2._kifejezsopc; 3._kifejezsopc)
utasts
Ez az utasts egyenrtk az
1._kifejezs;
while (2._kifejezs) {
utasts
3._kifejezs;
}
alakkal. Eszerint az els kifejezs a ciklust inicializlja; a msodik azt a vizsglatot hatrozza meg,
amely minden itercit megelz, s a vezrls kilp a ciklusbl, ha a kifejezs nullv vlik; a harmadik
kifejezs gyakran az egyes itercik utn vgrehajtand inkrementlst hatrozza meg.
A kifejezsek brmelyike, vagy akr mindegyik elhagyhat. Ha a 2. kifejezs hinyzik, akkor a
megfelel while utastsbl while( 1 ) lesz; a tbbi hinyz kifejezs egyszeren elmarad az elbbi
kifejtett formbl.
9.7.
A switch utasts
A switch utasts hatsra a megadott kifejezs rtktl fggen a vezrls tbb utasts valamelyikre
addik t.
Alakja:
switch (kifejezs)
utasts
A kifejezsben megtrtnnek a szoksos aritmetikai konverzik, de az eredmnynek int-nek kell lennie.
Az utasts ltalban sszetett. A switch utastson bell elfordul brmelyik utasts megcmkzhet
egy vagy tbb case eltaggal az albbi mdon :

22

Forrs: http://www.doksi.hu

case lland_kifejezs: ahol az lland kifejezs int kell, hogy legyen. Ugyanazon a switch-en bell kt
case llandnak nem lehet egyforma rtke. Az lland kifejezsek pontos defincijt a 15. pont
tartalmazza.
Legfeljebb egy darab
default: alak utasts-eltag is elfordulhat a switch utastsban. A switch utasts vgrehajtsa sorn a
gp kirtkeli a benne elfordul kifejezst s sszehasonltja minden egyes case llandval. Ha a case
llandk valamelyike megegyezik a kifejezs rtkvel, a vezrls az illeszked case eltagot kvet
utastsra addik t. Ha egyik lland sem egyezik meg a kifejezs rtkvel, s szerepel a default
eltag, akkor a program vgrehajtsa az ezt kvet utastson folytatdik. Ha egyik case sem
illeszkedik s nincs default, akkor a gp a switch-ben elfordul utastsok kzl egyiket sem hajtja
vgre. A case s default eltagok egymagukban nem vltoztatjk meg a vezrls menett, amely
zavartalanul vgighalad ezeken az eltagokon. A switchbl val kilpsre vonatkozlag l. a break
utastst a 9.8. pontban.
A switch trgyt kpez utasts legtbbszr sszetett. Deklarcik szerepelhetnek ennek az
utastsnak a fejben, de az automatikus s regisztervltozk inicializlsai hatstalanok.
9.8.
A

A break utasts

break; utasts hatsra befejezdik a break-et krlvev legbels while, do, for vagy switch utasts
vgrehajtsa; a vezrls a befejezett utastst kvet utastsra addik t.
9.9.
A

A continue utasts

continue;
utasts hatsra a vezrls a continue-t krlvev legbels
while, do vagy for utasts ciklusfolytat rszre addik t,
vagyis a ciklus vgre. Pontosabban, a
while (...) {

do {

for (...) {

...
contin: ;

...
...
contin: ;
contin: ;
}
} while (...);
}
utastsok mindegyikben a continue utasts egyenrtk a goto contin-nel. A contin: utn nulla
utasts szerepel, (l. a 9.13. pontot).
9.10.
A return utasts
A fggvny a hvjhoz a return utasts segtsgvel tr vissza, amelynek lehetsges alakja:
return ; return kifejezs;
Az els esetben a visszaadott rtk hatrozatlan. A msodik esetben a kifejezs rtke kerl vissza a
fggvny hvjhoz. Szksg esetn az rtkadshoz hasonlan a kifejezs olyan tpusv alakul t,
mint amilyen tpus fggvnyben elfordul. A fggvny vgnek tlpse azonos a visszatrsi rtk
nlkli return-nel.
9.11.
A goto utasts
A vezrls felttel nlkl a
goto azonost; utasts segtsgvel adhat t. Az azonost az ppen vgrehajtott fggvnyen bell
elhelyezett cmke (l. a 9.12. pontot) kell, hogy legyen.

23

Forrs: http://www.doksi.hu

9.12.
A cmkzett utasts
Brmelyik utastst megelzhetik az
azonost: alak eltagok, amelyek az azonostt cmkeknt deklarljk. A cmke egyedl a goto
clpontjaknt szolgl. A cmke rvnyessgi tartomnya az a fggvny, amelyben elfordul, kivve
azokat az alblokkokat, amelyekben ugyanezt az azonostt jradeklarltk (l. a 11. pontot).
9.13.

A nulla utasts A nulla utasts alakja:


;
A nulla utasts hordozhat pl. cmkt kzvetlenl valamely sszetett utasts }-e eltt, vagy pedig a
while-hoz hasonl valamelyik ciklusutasts szmra res ciklustrzset kpezhet.

10.
Kls defincik
A C program kls (external) defincik sorozatt tartalmazza. A kls definci a vltozt extern (ez
az alaprtelmezs) vagy static trolsi osztlynak s megadott tpusnak deklarlja. A tpusspecifiktor (l. a 8.2. pontot) lehet res, ebben az esetben a tpust int-nek tekintjk. A kls defincik
rvnyessgi tartomnya annak az llomnynak a vgig tart, amelyben deklarltk ket;
hasonlkppen a deklarcik is az llomny vgig rvnyesek. A kls defincik szintaxisa ugyanaz,
mint az sszes deklarci, azzal a klnbsggel, hogy a fggvnyeket csak ezen a szinten lehet
definilni.
10.1.
Kls fggvnydefincik A fggvnydefincik alakja:
fggvnydefinci:
dekl._specifiktorokopc fggvny deklartor fggvnytrzs A deklarcispecifiktorok kzl
trolsiosztly-specifiktorknt csupn az extern s a static megengedett; a kett kztti klnbsgre
nzve l. a 11.2. pontot. A fggvnydeklartor hasonl a fggvny, amely . . .-t ad vissza jelleg
deklartorhoz, azzal a klnbsggel, hogy megadja a definilt fggvny formlis paramtereinek
listjt.
fggvnydeklartor:
deklartor (paramterlistaopc) paramterlista:
azonost
azonost , paramterlista
A fggvnytrzs alakja:
fggvnytrzs:
deklarcilista sszetett_utasts A paramterlistabeli azonostk - s csakis ezek deklarlhatk a
deklarcilistban. Az olyan azonostt, amelynek tpust nem adtuk meg, a fordts int-nek tekinti. Az
egyetlen megadhat trolsi osztly a register; ha ez szerepel, akkor a neki megfelel aktulis
paramter, amennyiben lehetsges, a fggvny vgrehajtsnak kezdetn valamelyik regiszterbe kerl.
Egyszer plda a teljes fggvnydefincira:
int max (a, b, c)
int a, b, c;
{
int m;
m = (a > b) ? a : b;
return ((m > c) ? m : c);
}
Itt az int a tpus-specifiktor; max(a, b, c) a
fggvnydeklartor;
int a, b, c; a formlis paramterek deklarciinak listja; { . . } az utasts programkdjt megad
blokk.

24

Forrs: http://www.doksi.hu

A C az sszes float tpus aktulis paramtert double-l alaktja t, gy a float-nak deklarlt formlis
paramterek deklarcii is double-l mdosulnak. Tovbb, mivel a tmbre trtn hivatkozs
brmilyen sszefggsben klnsen aktulis paramterknt) olyan mutatt jelent, amely a tmb els
elemre mutat, a . . . tmbje alakban deklarlt formlis paramterek deklarcii mutat . . .-ra
alakra mdosulnak. Vgezetl, mivel a struktrk, unionok s fggvnyek nem adhatk t
fggvnynek, rtelmetlen dolog formlis paramtereket struktrnak, unionnak vagy fggvnynek
deklarlni (az ilyen objektumokat megcmz mutatk termszetesen megengedettek).
10.2.
Kls adatdefincik A kls adatdefincik alakja:
adatdefinci:
deklarci
Az ilyen adatok trolsi osztlya lehet extern (ez az alaprtelmezs) vagy static, de nem lehet auto, sem
pedig register.
11.
Az rvnyessgi tartomny szablyai
Nem szksges az egsz C programot egyszerre fordtani: a program forrsszvege tbb llomnyban
trolhat, s knyvtrakbl elre lefordtott rutinokat lehet betlteni. A program fggvnyei kztti
kommunikci akr explicit hvsokkal, akr kls adatokon keresztl megvalsthat. Ennek
kvetkeztben ktfle rvnyessgi tartomnyrl kell beszlnnk: elszr is arrl, amit az azonost
lexiklis rvnyessgi tartomnynak neveznk, s ami lnyegben a programnak az a rsze, amelyben
a definilatlan azonost (undefined identifier) hibazenet elfordulsa nlkl hasznlhatjuk,
msodszor pedig a kls azonostkhoz tartoz rvnyessgi tartomnyrl, amelyre az a szably
jellemz, hogy az ugyanarra a kls azonostra vonatkoz hivatkozsok ugyanarra az objektumokra
val hivatkozsokat jelentenek.
11.1.
Lexiklis rvnyessgi tartomny
A kls defincikban deklarlt azonostk lexiklis rvnyessgi tartomnya a definciktl az ket
tartalmaz forrsllomny vgig tart. A formlis paramterknt elfordul azonostk rvnyessgi
tartomnya az a fggvny, amelyhez tartoznak. A blokkok fejben deklarlt azonostk rvnyessgi
tartomnya a blokk vgig terjed. A cmkk rvnyessgi tartomnya az egsz fggvny,amelyben
elfordulnak. Mivel az ugyanarra a kls azonostra utal sszes hivatkozs ugyanarra az
objektumra vonatkozik (l. a 11.2. pontot), a fordtprogram ellenrzi, hogy ugyanannak a kls
azonostnak az sszes deklarcija kompatibilis-e; valjban ezek rvnyessgi tartomnya
kiterjed az egsz llomnyra, amelyben elfordulnak.
Minden esetben fennll azonban, hogy ha egy azonost explicit mdon egy blokk - akr fggvnyt
alkot blokk - fejben deklarlunk, akkor annak vgig az illet azonost sszes, a blokkon kvl
elfordul deklarcija felfggesztdik. Emlkezznk arra is (l. a 8.5. pontot), hogy egyrszt a
kznsges vltozkhoz, msrszt a struktra-, ill. uniontagokhoz s - cmkkhez kapcsold
vltozk kt kln osztlyt alkotnak, amelyek kztt nincs tkzs. A tagokra s cmkkre
ugyanazok az rvnyessgi tartomny szablyok vonatkoznak, mint a tbbi azonostkra. A typedef
nevek ugyanabba az osztlyba tartoznak, mint a kznsges azonostk, bels blokkokban
jradeklarlhatk, de a bels deklarciban a tipust explicit mdon meg kell adni:
typedef float distance;
...
{
auto int distance;
...
Az int-nek szerepelnie kell a msodik deklarciban, klnben a fordt deklartor nlkli, distance
tpus deklarcinak tekinten.
11.2.
A kls azonostk rvnyessgi tartomnya
Ha egy fggvny extern-knt deklarlt azonostra hivatkozik, akkor a teljes programot alkot
llomnyok, ill. knyvtrak kzl valamelyikben szerepelnie kell az azonost kls defincijnak.
Egy adott programban elfordul minden olyan fggvny, amely ugyanarra a kls azonostra
hivatkozik, egyben ugyanarra az objektumra is hivatkozik, ezrt gyelnnk kell arra, hogy a

25

Forrs: http://www.doksi.hu

definciban megadott tpus s mret kompatibilis legyen minden egyes, az adatokra hivatkoz
fggvnyben megadott tpussal s mrettel. Az extern kulcssz a kls definciban azt jelzi, hogy a
deklarlt azonostk szmra szksges trhelyet valamely msik llomnyban foglaljuk le. gy
tbb llomnybl ll programban extern specifiktor nlkli kls adatdefinci egy s csakis egy
llomnyban szerepelhet. Az sszes tbbi llomnyban, ahol kls defincival kvnjuk
valamelyik vltozt megadni, a definciban szerepelnie kell az extern-nek. Az azonost csak
abban a deklarciban inicializlhat, ahol a trhely lefoglalsa trtnt.
A legfels szinten kls defincikban static-knt deklarlt azonostk ms llomnyokban nem
lthatk. Fggvnyek is deklarlhatk static-knt.
12.
A fordtnak szl vezrlsorok
A C fordt rsze egy elfeldolgoz program, amely makrohelyettestsre, feltteles fordtsra s
megadott nev llomnyok beiktatsra kpes. Az elfeldolgoz a # karakterrel kezdd sorokat
rtelmezi. E sorok szintaxisa fggetlen a nyelv tbbi rsztl, brhol elfordulhatnak, s (rvnyessgi
tartomnytl fggetlenl) hatsuk az adott forrsprogram-llomny vgig tart.
12.1.
A

Szintaktikai egysgek helyettestse

#define azonost szint._egysgek_karakterlnca alak fordt vezrl sor (vigyzat: nincs zr


pontosvessz) hatsra az elfeldolgoz az azonost minden tovbbi elfordulst a szintaktikai
egysgek megadott karakterlncval helyettesti.
A
#define azonost(azonost, . . .,azonost)
szint._egysgek_karakterlnca alak sor, ahol az els azonost s a ( kztt nincs szkz,
argumentumokkal elltott makrodefinci. Az els azonostnak azon tovbbi elfordulsait, ahol az
azonostt ( , szintaktikai egysgek vesszkkel elvlasztott sorozata s egy )
kveti, a definciban megadott szintaktikai egysg
karakterlnccal helyettesti. A definci formlis
paramterlistjban emltett azonost sszes elfordulsa helyre a hvs hatsra a megfelel
szintaktikai egysg karakterlnc kerl. A hvs aktulis argumentumai vesszkkel elvlasztott
szintaktikai egysg karakterlncok, azonban az idzjelek kztti vagy zrjelekkel vdett vesszk nem
argumentumelvlasztk. A formlis s aktulis paramterek darabszma egyenl kell, hogy legyen.
Karakterlncon vagy karakterllandn belli szvegre nem vonatkozhat a helyettests.
A helyettest karakterlncot (mindkt vltozatban) jra tvizsglja az elfeldolgoz, hogy megtallja
az esetleges tovbbi definilt azonostkat. A hossz defincik mindkt alakban j sorban folytathatk
oly mdon, hogy a folytatand sor vgre \-t runk.
A #define hasznlat_ leginkbb a hangslyozott funkcij llandk definilsra elnys, pl.:
#define TABSIZE 100
int table[TABSIZE];
Az
#undef azonost alak vezrlsor hatsra megsznik az azonost elfeldolgoz-defincija.
12.2.
Az

llomnyok beiktatsa

#include llomnynv
alak vezrlsort az elfeldolgoz program az llomnynv nev
llomny teljes tartalmval helyettesti. A megnevezett llomny
keresse az eredeti forrsllomny katalgusban kezddik, majd

26

Forrs: http://www.doksi.hu

sorban, szabvnyos helyeken folytatdik. Megadhatjuk az


#include <llomnynv> alak vezrlsort is, amikor a keress csak a szabvnyos helyeken trtnik, s
nem terjed ki a forrsllomny katalgusra. Az #include-ok egymsba skatulyzhatk.
12.3.
Az

Feltteles fordts

#if lland_kifejezs
alak fordtsvezrl sor ellenrzi, hogy az lland kifejezs
(l. a 15. pontban) rtke nemnulla-e. Az
#ifdef azonost
alak vezrlsor megvizsglja, hogy az azonost pillanatnyilag
definilva van-e az elfeldolgozban, azaz szerepelt-e mr
valamelyik #define vezrlsorban. Az
#ifndef azonost alak vezrlsor azt ellenrzi, hogy az azonost pillanatnyilag definilatlan-e az
elfeldolgozban.
Mindhrom alakot tetszleges szm, esetleg az
#else
vezrlsort is tartalmaz sor, majd az
#endif vezrlsor kveti. Ha a vizsglt felttel igaz, akkor az #else s az #endif kztti sorok
hatstalanok. Ha a vizsglt felttel hamis, akkor az ellenrzs s az #else vagy annak hinyban a
#endif kztti sorok lesznek hatstalanok.
E szerkezetek egymsba skatulyzhatk.
12.4.
Sorvezrls
Egyb, C programokat ltrehoz elfeldolgozk szempontjbl
hasznos a
#line lland_azonost alak sor. Hatsra - diagnosztikai clokbl a fordt azt hiszi, hogy a
kvetkez forrssor sorszma az lland ltal megadott rtk, s a pillanatnyi bemeneti llomny az,
amelyet az azonost megnevez. Azonost hinyban a megnevezett llomnynv nem vltozik.
13.
Implicit deklarcik
A deklarciban nem mindig kell a trolsi osztlyt s az azonostk tipust is megadnunk. A trolsi
osztlyt kls defincikban s formlis paramterek ill. a struktratagok deklarciiban a
szvegkrnyezet hatrozza meg. Fggvnyen belli deklarciban, ha a trolsi osztlyt megadtuk, de a
tpust nem, az azonost felttelezs szerint int; ha tpus szerepel, de trolsi osztly nem, akkor az
azonostt auto-nak tekinti a fordt. Az utbbi szably all kivtelek a fggvnyek, mivel az auto
fggvnyeknek nincs rtelmk (a C nem kpes kdot generlni a verembe); ha valamely azonost
tpusa fggvny, amely ...-t ad vissza, akkor az implicite extern-nek deklarldik.
Kifejezsekben az olyan, mg nem deklarlt azonostt, amelyet ( kvet, a szvegkrnyezet alapjn
a fordt int-et visszaad fggvnynek tekinti.
14.
Mg egyszer a tpusokrl
Ez a szakasz azokat a mveleteket foglalja ssze, amelyeket csak bizonyos tpus objektumokon lehet
elvgezni.
14.1.
Struktrk s unionok Struktrkkal s unionokkal kt dolgot tehetnk:
megnevezhetjk valamelyik tagjukat (a . opertorral), vagy elllthatjuk a cmket (az
egyoperandus &-tel). Az egyb mveletek, mint a struktrk vagy unionok valamihez trtn

27

Forrs: http://www.doksi.hu

hozzrendelse, paramterknt val tadsa, vagy nekik val rtkads hibazenetet von maga utn.
Remljk, hogy a jvben a C, ha egyebekkel nem is, de ezekkel a mveletekkel kiegszl. A 7.1.
pontban mondottak szerint a ( . vagy -> segtsgvel trtn) direkt vagy indirekt
struktrahivatkozsban a jobb oldalon ll nvnek a bal oldali kifejezs ltal megnevezett vagy
megcmzett struktra tagjnak kell lennie. A rugalmas tpuskezels rdekben ezt a megktst a
fordt kveteli meg szigoran. Valjban a . eltt brmilyen balrtk megengedett, s a fordt
felttelezi, hogy ez a balrtk olyan alak struktra, mint amilyen a jobb oldali nv tagja. A -> eltti
kifejezsnek ugyancsak mutatnak vagy egsznek kell lennie. Ha a kife_ezs mutat, akkor
felttelezs szerint arra a struktrra mutat, amelyiknek a jobb oldalon ll nv tagja. Ha a kifejezs
egsz tpus, akkor a fordt a megfelel struktra (gpi trolsi egysgekben kifejezett) abszolt
cmnek tekinti. Az ilyen konstrukcik nem gpfggek.
14.2.
Fggvnyek
Fggvnnyel csupn kt mveletet vgezhetnk: meghvhatjuk vagy elllthatjuk a cmt. Ha a
fggvny neve kifejezsen bell nem valamely hvs fggvnynv-pozcijn jelenik meg, akkor a
fggvnyt megcmz mutat jn ltre. Ha teht egy fggvnyt egy msiknak akarunk tadni, azt
mondhatjuk, hogy:
int f ();
...
g (f);
Ekkor a g defincija
g (funcp) int (*funcp) ();
{
...
(*funcp) ();
...
}
lehet. Jegyezzk meg, hogy f-et a hv rutinban explicit mdon deklarlni kell, mivel g (f)-beli
elfordulst nem kvette (.
14.3.
Tmbk, mutatk s indexels
Minden alkalommal, amikor tmb tpus azonost jelenik meg egy kifejezsben, az azonost a
tmb els elemt megcmz mutatv alakul t. E konverzi miatt a tmbk nem balrtkek.
Definci szerint a [ ] indexopertor rtelmezse olyan, hogy
E1 [E2]
azonos
*((E1)+(E2))
vel. A +-ra vonatkoz konverzis szablyok kvetkeztben, ha E1 tmb s E2 egsz, akkor
E1 [E2]
az E1 tmb E2-dik elemre hivatkozik. Emiatt - _aszimmetrikus megjelense ellenre - az indexels
kommutatv mvelet.
A tbbdimenzis tmbkre kvetkezetes szably
vonatkozik. Ha E n-dimenzis, i * j * . . . * k-rang tmb ,
akkor kifejezsekben (n-1 )-dimenzis, j*...*k-rang tmbt
megcmz mutatv alakul t. Ha a * opertor akr explicit, akr
indexels kvetkeztben implicit mdon erre a mutatra
alkalmazzuk, az eredmny a megcmzett (n-1 )-dimenzis tmb,
amely maga is azonnal mutatv alakul t.
Tekintsk pl. az
int x [3][5]; deklarcit. Itt x 3*5-s egsz tmb. Ha x kifejezsben jelenik meg, akkor x a hrom darab
5-tag egsz tmb kzl az elst megcmz mutatv alakul t. Az x[i) kifejezsben, amely *(x+i)vel egyenrtk, x elszr az ismertetett mdon mutatv, majd i az x tpusval azonos tpusv alakul,

28

Forrs: http://www.doksi.hu

ami magban foglalja azt, hogy i megszorzdik annak az objektumnak a hosszval, amelyre a mutat
mutat: ez jelen esetben 5 egsz objektum. Az eredmnyek sszeaddnak, s indirekci alkalmazsval
(5 egszbl ll) tmb keletkezik, amely viszont ezen egszek kzl az elst megcmz mutatv alakul
t. Ha mg tovbbi index is van, ismt ugyanezt a megfontolst kell alkalmazni; esetnkben az
eredmny egsz.
A fentiekbl kvetkezik, hogy a C-ben a tmbk sorfolytonosan troldnak (az utols index vltozik a
leggyorsabban), tovbb, hogy a deklarciban elfordul els index segtsgvel hatrozhat meg a
tmb ltal elfoglalt trterlet nagysga, egyb szerepe azonban az indexszmtsokban nincs.
14.4.
Explicit mutatkonverzik
A mutatkra bizonyos konverzik megengedettek ugyan, de
gpfgg vonatkozsaik vannak. Valamennyi ilyen konverzit
explicit tpuskonverzis opertorral rhatjuk el (l. a 7.2. s
8.7.
pontot).
Mutatk brmely olyan integrlis tpuss talakthatk, amelyben elfrnek. Az, hogy ez a tpus int
vagy long-e, gpfgg. A lekpzs maga is gpfgg, de azok szmra, akik ismerik a gp cmzsi
struktrjt, nem okozhat meglepetst. A ksbbiekben nhny gpre vonatkozan a rszleteket
is ismertetjk.
Az integrlis tpus objektumok explicit mdon mutatkk alakthatk t. A lekpzs hatsra a
mutatkbl ltrejtt egszek ugyanazokk a mutatkk alakulnak vissza, egybknt a folyamat
gpfgg.
Adott tpust megcmz mutat ms tpust megcmz mutatv alakthat. Az eredmnyl kapott
mutat cmzsi zavarokat okozhat, ha a szban forg mutat ltal megcmzett objektum illeszkedse
a trban nem megfelel. Bizonyos azonban, hogy adott mret objektumot megcmz mutat
vltozatlan marad, ha elszr kisebb mret objektumot, majd ismt az eredeti mret objektumot
megcmz mutatv alaktjuk.
A trterlet-foglal rutin pl. elfogadhatja valamely kiutaland objektum (byte-okban megadott)
mrett s char mutatt adhat vissza:
extern char *alloc (); double *dp; dp = (double *) alloc (sizeof (double));
*dp = 22.0 / 7.0;
Az alloc-nak (gpfgg mdon) biztostani kell, hogy a visszaadott rtket t lehessen alaktani double
mutatv; ebben az esetben a fggvny hasznlata gpfggetlen.
A PDP- 11 mutatbrzolsa 16 bites egsznek felel meg, egysge a byte. A char-okkal szemben
nincsenek illeszkedsi kvetelmnyek; minden msnak pros cmnek kell lennie. A Honeywell 6000
gpen a mutat 36 bites egsznek felel meg: a szrsz a bal oldali 18 biten van, s az a kt bit, amely a
szn bell a karaktert vlasztja ki, ettl kzvetlenl jobbra tallhat. Igy a karaktermutatkat a 216
byte-os egysgekben mrjk, minden ms 218 gpi sz egysgekben mrhet. A double
mennyisgeknek s az azokat tartalmaz aggregtumoknak pros szcmen kell elhelyezkednik (0 mod
219).
Az IBM 370 s az Interdata 8/32-es gpek hasonlak. A cmeket mindkettn byte-okban mrjk; az
elemi objektumoknak a hosszuknak megfelel hatrra kell illeszkednik, gy a short-ot megcmz
mutatknak (0 mod 2)-nek, az int-re s float-ra mutatknak (0 mod 4)-nek s a double-ra mutatknak (0
mod 8)-nak kell lennik. Aggregtum illesztse az alkotelemeire vonatkoz illeszkedsi felttelek
kzl a legszigorbb szerint trtnik.
15.
lland kifejezsek
A C nyelvben tbb helyen kell alkalmaznunk olyan
kifejezseket, amelyeket kirtkelve lland eredmnyt kapunk:
case utn, tmbhatrknt, kezdeti rtkekknt. Az els kt
esetben a kifejezsben csupn egsz llandk, karakterllandk

29

Forrs: http://www.doksi.hu

s sizeof kifejezsek szerepelhetnek, amelyeket a


+ - * / % & | ^ << >> == != < > <= >=
kt-, ill a
-~
egyoperandus opertorok valamelyike vagy a hromoperandus
?:
opertor kthet ssze egymssal. A zrjelek csoportostsra hasznlhatk, fggvnyhvsra azonban
nem.
Kevesebb megkts vonatkozik a kezdeti rtkekre; az elbb trgyalt lland kifejezseken kvl kls
s statikus objektumokra, valamint lland kifejezssel indexelt kls s statikus tmbkre is
alkalmazhat az egyoperandus & opertor. Implicit mdon az egyoperandus &-et indexeletlen
tmbk s fggvnyek megjelensekor ugyancsak alkalmazhatjuk. Az alapszably az, hogy a kezdeti
rtkek kirtkelsvel vagy llandt, vagy pedig valamely mr korbban deklarlt kls vagy statikus
objektum (esetleg llandval nvelt vagy cskkentett) cmt kell megkapnunk.
16.
Gpfggetlensg
A C nyelv bizonyos rszei lnyegknl fogva gpfggk. Az albbiakban nem trhettnk ki minden
problmra, csak a legfontosabbakat akartuk kiemelni.
Az olyan tisztn hardverkrdsek, mint a szavak mrete, a lebegpontos aritmetika tulajdonsgai s az
egszek osztsa a gyakorlatban nem okoztak klnsebb gondot. A hardver egyb jellegzetessgei az
eltr megvalstsokban mutatkoznak meg. Ezek nmelyike, klnsen az eljel-kiterjeszts (negatv
karakter negatv egssz trtn talaktsa), valamint a byte-ok szavakon belli elhelyezkedsi
sorrendje olyan kellemetlen tnyezk, amelyekre klns figyelmet kell fordtanunk. Az egyb
gpfgg tulajdonsgok mr nem jelentenek nagyobb problmt.
A regiszterekben tnylegesen elhelyezked register tpus vltozk szma - a megengedett
tpuskszlethez hasonlan - gprl gpre vltozik. Minden fordt helyesen vgzi azonban a dolgt a
sajt gpe szempontjbl: a fls szm vagy rvnytelen register deklarcikat nem veszi figyelembe.
Nehzsgek csak akkor tmadnak, amikor valaki rossz programozsi mdszereket alkalmaz. Ne rjunk
olyan programokat, amelyek az adott architektra brmilyen specifikus tulajdonsgtl fggetlenek!
A fggvnyargumentumok kirtkelsi sorrendjt a nyelv nem hatrozza meg. PDP- 11-en jobbrl
balra, a tbbi gpen balrl jobbra trtnik. A mellkhatsok rvnyeslsnek sorrendje ugyancsak nem
meghatrozott.
Mivel a karakterllandk valjban int tpus objektumok, tbb karakterbl ll karakterllandk
hasznlata is megengedett. Ennek megvalstsa azonban rendkvl gpfgg, mivel a karakterek
szhoz trtn hozzrendelsnek sorrendje gprl gpre vltozik.
Mezk hozzrendelse szavakhoz, karakterek egszekhez a PDP 11-en jobbrl balra, a tbbi gpen
balrl jobbra trtnik. Elszigetelt programok szmra e klnbsgek lthatatlanok maradnak, hacsak
nem viszik tlzsba a tpusokkal folytatott jtkot (pl. azltal, hogy valamely int mutatt char mutatv
alaktanak t, majd megvizsgljk a megcmzett trterletet).
Szmolnunk kell azonban e
klnbsgekkel akkor, ha a programunkat kvlrl megszabott trterlet-elrendezsekkel akarjuk
sszhangba hozni.
A klnfle fordtk ltal elfogadott nyelvek csupn egszen kis rszletekben trnek el egymstl. A
leglnyegesebb, hogy a pillanatnyilag hasznlatos PDP-11-es fordt nem inicializlja a bitmezket
tartalmaz struktrkat, s egyes rtkad opertorokat nem fogad el olyan krnyezetben, ahol ki
akarjuk hasznlni a hozzrendels rtkt.
17.
Anakronizmusok
Mivel a C fejldsben lev nyelv, egyes rgebbi programokban bizonyos elavult szerkezetek tallhatk.
Br a fordt legtbb vltozata az ilyen anakronizmusokat is tmogatja, elbb-utbb ezek el fognak
tnni, csupn gpfggsgi problmt hagyva maguk utn.
A C nyelv korbbi vltozatai rtkad opertorknt az =op

30

Forrs: http://www.doksi.hu

alakot hasznltk az op= alak helyett. Ez ktrtelmsgekhez


vezet, amelynek tipikus esete
x = -1
amely a valsgban x-et dekrementlja, mivel az = s a szomszdosak, de amivel knnyen az lehetett a szndkunk, hogy
1-et rendeljnk x-hez.
A kezdeti rtkek szintaxisa megvltozott: korbban a kezdeti
rtket bevezet egyenlsgjel nem szerepelt, gy az
int x = 1;
alak helyett az
int x 1;
alak volt hasznlatban. A vltoztats azrt trtnt, mert az
int f (1+2) alak inicializls ppen elgg hasonlt a fggvnydeklarcira ahhoz, hogy megtvessze a
fordtkat.
18.
A szintaxis sszefoglalsa
A C nyelv szintaxisnak sszefoglalsa sokkal inkbb tmr segdletl, mintsem a nyelv rvid
sszefoglalsul szolgl.
18.1.
Kifejezsek Az alapvet kifejezsek a kvetkezk:
kifejezs:
elsdleges_kifejezs
*kifejezs
&kifejezs
kifejezs
!kifejezs
~kifejezs
++balrtk
balrtk
balrtk ++
balrtk
sizeof kifejezs
(tpus_nv) kifejezs
kifejezs ktop kifejezs
kifejezs ? kifejezs : kifejezs
balrtk rtkad_op kifejezs
kifejezs , kifejezs
elsdleges_kifejezs:
azonost
lland
karakterlnc
( kifejezs )
elsdleges_kifejezs ( kifejezs_listaopc)
elsdleges_kifejezs [ kifejezs ]
balrtk . azonost
elsdleges_kifejezs -> azonost
balrtk:
azonost
elsdleges_kifejezs [ kifejezs ]
balrtk . azonost

31

Forrs: http://www.doksi.hu

elsdleges_kifejezs -> azonost


*kifejezs
( balrtk )
A
() [] . ->
elsdleges kifejezs opertorok prioritsa a legmagasabb, s az
ilyen opertorok balrl jobbra ktnek. Az egyoperandus
& - ! ~ ++ -- sizeof (tpusnv)
opertorok prioritsa az elsdleges opertoroknl alacsonyabb, de magasabb az sszes ktoperandus
opertornl: ezek az opertorokjobbrl balra ktnek. Az sszes ktoperandus opertor s a feltteles
opertor balrljobbra kt, ezeket az albbiakban cskken prioritsi sorrendben soroljuk fel: ktop:
*/%
+>> <<
< > <= >=
== !=
&
^
|
&&
||
?:
Az rtkad opertorok mindegyike azonos priorits, s mindegyik jobbrl balra kt. rtkad_op:
= += -= *= /= %= >>= <<= &= ^= |=
A vessz opertor (,) prioritsa a legalacsonyabb, s balrl jobbra csoportost.
18.2.
Deklarcik
deklarci:
dekl._specifiktorok deklartorlistaopc; dekl._specifiktorok:
tpus_specifiktor dekl._specifiktorokopc
t.o._specifiktor dekl._specifiktorokopc
t.o._specifiktor:
auto
static
extern
register
typedef
tpus_specifiktor:
char
short
int
long
unsigned
float
double
strukt._vagy_union_specifiktor
typedef_nv
k.._deklartorlista:
k.._deklartor
k.._deklartor , k.._deklartorlista

32

Forrs: http://www.doksi.hu

k.._deklartor:
deklartor inicializlopc deklartor:
azonost
( deklartor )
*deklartor
deklartor ()
deklartor [ lland_kifejezsopc] strukt._vagy_union_specifiktor:
struct { strukt._dekl._lista }
struct azonost { strukt._dekl._lista }
struct azonost
union { strukt._dekl._lista }
union azonost {strukt._dekl._lista }
union azonost
strukt._dekl._lista:
strukt._deklarci
strukt._deklarci strukt._dekl._lista
strukt._deklarci:
tpus_specifiktor strukt._deklartor_lista; strukt._deklartor_lista:
strukt._deklartor
strukt._deklartor , strukt._deklartor_lista
strukt._deklartor:
deklartor
deklartor : lland_kifejezs
: lland_kifejezs
inicializl:
= kifejezs
= { inicializl_lista }
= { inicializl_lista, }
inicializl_lista:
kifejezs
inicializl_lista , inicializl_lista
{ inicializl_lista }
tpus_nv:
tpus_specifiktor absztrakt_deklartor absztrakt_deklartor:
res
( absztrakt_deklartor )
*absztrakt_deklartor
absztrakt_deklartor ()
absztrakt_deklartor [ lland_kifejezsopc] typedef_nv:
azonost
18.3.
Utastsok
sszetett_utasts:
{ deklarcilistaopc utastslistaopc } deklarcilista:
deklarci
deklarci deklarcilista
utastslista:
utasts

33

Forrs: http://www.doksi.hu

utasts utastslista
utasts:
sszetett_utasts
kifejezs;
if ( kifejezs )
utasts
if ( kifejezs )
utasts
else utasts
while ( kifejezs )
utasts
do
utasts
while ( kifejezs ) ;
for (kifejezs_1opc; kifejezs_2opc; kifejezs_3opc)
utasts
switch ( kifejezs )
utasts
case lland_kifejezs:
utasts
default:
utasts
break;
continue;
return;
return kifejezs;
goto azonost;
azonost:
utasts
;

18.4.
Kls defincik
program:
kls_definci
kls_definci program
kls_definci:
fggvnydefinci
adatdefinci
fggvnydefinci:
dekl._specifiktoropc fggvnydeklartor fggvnytrzs fggvnydeklartor:
deklartor ( paramterlistaopc ) paramterlista:
azonost
azonost , paramterlista
fggvnytrzs:
deklarcilista fggvny_utasts fggvny_utasts:
deklarcilistaopc utastslista adatdefinci:
externopc
tpus_specifiktoropc
k.._deklartorlista;

k.._deklartorlista;

staticopc

tpus_specifiktoropc

18.5.
Elfeldolgoz
#define azonost szint._egysgek_karakterlnca #define azonost(azonost, ..., azonost)
szint._egysgek_karakterlnca

34

Forrs: http://www.doksi.hu

#undef azonost
#include llomnynv
#include <llomnynv>
#if lland_kifejezs
#ifdef azonost
#ifndef azonost
#else
#endif
#line lland azonost
_
1.

fejezet: Alapismeretek

A C nyelv tanulst kezdjk az alapismeretek gyors elsajttsval. Clunk az, hogy mkdkpes
programokon, de a rszletekbe, formlis szablyokba s kivtelekbe val belebonyolds nlkl
mutassuk be a nyelv legfontosabb elemeit. Nem treksznk teht teljessgre, st pontossgra sem
(eltekintve attl, hogy a pldknak helyeseknek kell lennik). Az olvasnak a lehet leggyorsabban el
kell jutnia addig a pontig, ahol mr hasznlhat programokat tud rni. ppen ezrt bevezetnk az
alapvet tudnivalkra koncentrl: a vltozkra, az llandkra, az aritmetikra, a vezrlstadsra, a
fggvnyekre, a be- s kivitellel kapcsolatos elemi ismeretekre. Tudatosan kihagytuk ebbl a fejezetbl
a C nyelv olyan sszetevit, amelyek nagyobb programok rsnl ltfontossgak. Ilyenek a mutatk, a
struktrk, a C nyelv gazdag opertorkszletnek legnagyobb rsze, nhny vezrlstad utasts s
mg ezernyi rszlet.
Ennek a megkzeltsnek megvannak termszetesen a maga htrnyai is.
Ezek kzl a legfontosabb, hogy a nyelv valamely sszetevjt ler sszes informci nem egy helyen
tallhat, s a bevezet fejezet rvidsgnl fogva flrevezet lehet. Tovbb, mivel nem hasznlhat a
C nyelv egsz fegyvertra, a pldk nem olyan tmrek s elegnsak, mint lehetnnek. Ezeket a
htrnyokat igyekeztnk a minimlisra cskkenteni, de minderrl azrt ne feledkezznk meg.
Tovbbi htrny, hogy a bevezet egyes rszei a ksbbiekben szksgszeren megismtldnek.
Remljk, hogy ez az ismtls inkbb segti, mintsem bosszantja az olvast.
Tapasztalt programozk mindenesetre mr ennek a fejezetnek az anyagbl ki tudjk kvetkeztetni a
szmukra szksges programozsi informcit. Kezdknek ajnljuk, hogy maguk is rjanak az itt
bemutatottakhoz hasonl, kismret programokat. A bevezet mindkt csoportnak keretknt szolglhat
a ksbbi fejezetek anyagnak befogadshoz.
1.1.
Induls
Egy j programnyelv elsajttsnak egyetlen mdja, ha
programokat runk az adott nyelven. Az els megrand program
minden nyelv tanulsakor hasonl szokott lenni : Nyomtassuk ki a
Figyelem, emberek! szavakat.
Ez az els akadly. Ahhoz, hogy tugorjuk, kpesnek kell lennnk arra, hogy (valahol) ltrehozzuk
a programszveget, sikeresen lefordtsuk, betltsk, lefuttassuk, s ki kell tallnunk, hov kerl a
kivitt szveg. Ha ezeken a_mechanikus rszleteken tljutottunk, minden ms viszonylag knnyen
fog menni.
C nyelven a Figyelem, emberek! szveget kinyomtat program a kvetkez:
main ()
{
printf (Figyelem, emberek! \ n);
}
A program futtatsnak mdja az ppen hasznlt rendszertl fgg.
Az UNIX opercis rendszerben pl. a forrsprogramot olyan

35

Forrs: http://www.doksi.hu

llomny alakjban kell ltrehozni, amelynek a neve .c-re


vgzdik, mint pldul figyel.c, majd ezt a
cc figyel.c
paranccsal le kell fordtani. Ha nem kvettnk el semmilyen
hibt, pl. nem hagytunk ki egy karaktert, vagy nem rtunk
valamit hibsan, a fordts rendben vgbemegy s egy
vgrehajthat llomny keletkezik, amelynek neve a.out . Ha ezt
az
a.out
paranccsal lefuttatjuk, akkor a
Figyelem, emberek! szveg jelenik meg a kimeneten. Ms opercis rendszerekben a szablyok
eltrek, ilyen esetben forduljunk megfelel szakemberhez.
1. 1. Gyakorlat. Futtassa le a fenti programot a sajt rendszern! Ksrletezzen a program egyes
rszeinek elhagysval, hogy meglssa, milyen hibazenetek rkeznek!
Most pedig nhny megjegyzs magrl a programrl. A C programok mretktl fggetlenl
egy vagy tbb fggvnyt tartalmaznak, amelyek meghatrozzk az ppen elvgzend szmtsi
mveleteket. A C-beli fggvnyek a FORTRAN fggvnyeihez vagy szubrutinjaihoz, ill. a PL/1
, a PASCAL stb. eljrsaihoz hasonltanak. Pldnkban a main ilyen fggvny. A fggvny neve
ltalban tetszleges lehet, de a main specilis nv - programunk vgrehajtsa mindig a main
elejn kezddik. Ebbl az kvetkezik, hogy minden programban el kell hogy forduljon egy
main valahol. A main a feladat vgrehajtsa rdekben ltalban ms fggvnyeket fog
meghvni, amelyek kzl egyesek ugyanabban a programban szerepelnek, mg msok elzleg
megrt fggvnyknyvtrakbl szrmaznak.
A fggvnyek kztti adattads egyik mdja az argumentumok hasznlata. A fggvnynevet
kvet zrjelek az argumentumlistt hatroljk: jelen esetben main argumentum nlkli
fggvny, amit () jell. A { } kapcsos zrjelek a fggvnyt alkot utastsokat zrjk kzre;
szerepk a PL/1beli do-end-del, az ALGOL s PASCAL begin-end-jvel azonos. A fggvny
hvsa a fggvny megnevezsvel trtnik, amit az argumentumok zrjelezett listja kvet. A
FORTRAN-tl vagy PL/1-tl eltren itt nincs call utasts. A zrjeleknek akkor is
szerepelnik kell, ha egyetlen argumentum sincs.
A
printf (Figyelem, emberek!\ n); sor nem ms, mint fggvnyhvs, amely a printf nev fggvnyt
hvja a Figyelem, emberek!\ n argumentummal. printf knyvtri fggvny, amely az eredmnyt esetnkben az argumentumt alkot karakterlncot - (egyb perifria megadsa hjn) a terminlra
rja.
Egy tetszleges szm karakterbl ll, idzjelek () kz zrt karaktersorozatot karakterlncnak,
karakter-llandnak (stringnek, ill. stringkonstansnak) neveznk. Pillanatnyilag a karakterlncokat
csak a printf s ms fggvnyek argumentumaiknt hasznljuk.
A karakterlncban elfordul \ n karaktersorozat az jsor
karakter C-beli jellsmdja. Hatsra a kirs a kvetkez sor
bal szln folytatdik. Ha a \ n-et elhagyjuk (rdemes
megksrelni), azt tapasztaljuk, hogy a kirs vgn a kocsi
vissza -soremels elmarad. Az jsor karaktert csakis egy \n
segtsgvel iktathatjuk be a printf-be: ha valami olyasmivel
prblkozunk, mint

36

Forrs: http://www.doksi.hu

printf (Figyelem, emberek!


);
akkor a C fordt bartsgtalan zeneteket fog kldeni bizonyos hinyz idzjelekrl.
A printf sohasem helyez el jsor karaktert automatikusan, gy tbbszri hvs segtsgvel egyetlen
kimeneti sort fokozatosan rakhatunk ssze. Els programunkat gy is rhattuk volna:
main ()
{
printf (Figyelem, );
printf (emberek!);
printf (\ n);
}
miltal a korbbival azonos kimenetet kaptunk volna. Megjegyezzk, hogy \ n egyetlen karaktert jelent.
A \ n-hez hasonl, n. escape jelsorozatok ltalnosan hasznlhat s bvthet mechanizmust alkotnak
nehezen elllthat vagy lthatatlan karakterek jellsre. A C nyelvben ilyenek mg a \t a tabultor, a
\b a visszalptets (backspace), a \ az idzjel s a \\ magnak a fordtott trtvonalnak (backslash) a
jellsre.
1.2.
Gyakorlat. Prblja ki, mi trtnik, ha a printf
argumentum-karakterlnca \ x-et tartalmaz, ahol x egy, a fenti listban nem szerepl karakter!
1.2.
Vltozk s aritmetika
Az albbi program a kvetkez Fahrenheit-hmrskleteket s a
megfelel Celsius-rtkeket tartalmaz tblzatot nyomtatja ki a
C = (5/9)(F-32)
kplet alkalmazsval.
0
-17.8
20
-6.7
40
4.4
60
15.6
...
...
260
126.7
280
137.8
300
148.9
me maga a program:
/* Fahrenheit-Celsius tblzat kinyomtatsa f = 0, 20, . . ., 300 rtkekre */ main ()
{
int lower, upper, step;
float fahr, celsius;
lower = 0;
/* A hmrsklet-tblzat als hatra */
upper = 300; /* fels hatr */
step = 20;
/* lpskz */
fahr = lower;
while (fahr <= upper) {
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf (%4.0f %6.1f \n, fahr, celsius);
fahr = fahr + step;
}
}
Az els kt sor:
/* Fahrenheit-Celsius tblzat kinyomtatsa
f = 0, 20, . . ., 300 rtkekre */

37

Forrs: http://www.doksi.hu

egy megjegyzs (comment), amely esetnkben rviden elmondja, hogy mit csinl a program. A fordt
minden, a /* s */ kztt elfordul karaktert figyelmen kvl hagy; gy ide tetszleges, a program
megrtst segt szveget berhatunk. Megjegyzsek mindentt elfordulhatnak, ahol szkz vagy
jsor elfordulhat. A C nyelvben hasznlat eltt minden vltozt deklarlni kell, ltalban a fggvny
elejn, az els vgrehajthat utasts eltt. Ha errl megfeledkeznk, hibazenetet kapunk a fordttl.
A deklarci egy tpus megadsbl s az illet tpus vltozk felsorolsbl ll. Plda erre az elbbi
program kt sora:
int lower, upper, step; float fahr, celsius;
Az int tpus azt jelenti, hogy a felsorolt vltozk egsz (integer) tpusak. float jelli a lebegpontos
(floating point) vltozkat, vagyis az olyan szmokat, amelyeknek trt rszk is van. Mind az int, mind
a float szmok pontossga az adott szmtgptl fgg. A PDP-11 -en pldul az int 16 bit-es eljeles
szm, vagyis olyan szm, amelynek rtke -32768 s +32767 kztt van. A float szm 32 bites
mennyisg, ami krlbell 7 rtkes szmjegyet jelent, 10-38 s 1038 kztti nagysgrendben. A 2.
fejezet ms gpekre is kzli a szmbrzolsi tartomnyokat.
Az int s float mellett a C nyelvben ms alapvet adattpusok is vannak:
char
karakter egyetlen byte,
short
rvid egsz,
long
hossz egsz,
double duplapontossg lebegpontos szm.
Ezen objektumok mretei ugyancsak gpfggek, a rszleteket a 2. fejezet tartalmazza. Ezekbl az
alapvet tpusokbl tmbk, struktrk s unionok kpezhetk, mutatk mutathatnak rjuk, fggvnyek
trhetnek vissza a hvhoz ezekkel a tpusokkal: mindezekkel rvidesen tallkozunk.
A hmrsklet-tszmt programban a tnyleges szmts a
lower = 0; upper = 300; step = 20; fahr = lower;
rtkad utastsokkal kezddik, amelyek a vltozk kezdeti rtkt lltjk be. Az egyes utastsokat
pontosvessz zrja le.
A tblzat minden sort azonos mdon kell kiszmtani, ezrt egy ciklust hasznlunk, amely
tblzatsoronknt egyszer ismtldik; ez a clja a while utastsnak :
while (fahr <= upper) {
...
}
Programfuts kzben a gp megvizsglja, teljesl-e a zrjelek kztti felttel. Ha az rtke igaz (fahr
kisebb vagy egyenl, mint upper), akkor vgrehajtja a ciklustrzs (a { s } kapcsos zrjelek kz zrt)
utastsait. Ezutn ismt megvizsglja a felttelt, s ha az rtke igaz, jra vgrehajtja a trzset. Ha a
vizsglat a hamis logikai rtket szolgltatja (fahr meghaladja upper-t), akkor a ciklus lezrul s a
vgrehajts a ciklust kvet els utastson folytatdik. Az adott program nem tartalmaz tbb utastst,
teht a program vget r.
A while trzse egy vagy tbb, kapcsos zrjelek kz zrt utasts lehet, mint a hmrsklet-tszmt
programban, vagy egyetlen, kapcsos zrjel nlkli utasts, mint pl.:
while (i < j) i = 2 * i;
A while ltal vezrelt utastsokat mindkt esetben kt pozcival beljebb rtuk, hogy els pillantsra
vilgos legyen, mely utastsok helyezkednek el a cikluson bell. A bekezds a program logikai
szerkezett hangslyozza. Br a C nyelv meglehetsen ktetlen az utastsok pozcionlst illeten, ha
azt akarjuk, hogy programunk knnyen olvashat legyen, nagyon fontos a megfelel bekezdsek s res
helyek hasznlata. Clszer, ha egy sor egy utastst tartalmaz, s (ltalban) hagyjunk egy-egy szkzt
az opertorok eltt s utn. A zrjelek pozcija kevsb lnyeges: e tekintetben a tbbfle divatos
stlus egyikt vlasztottuk. Az olvas brmilyen neki megfelel stlus mellett dnthet, clszer azonban,
ha ezt azutn kvetkezetesen hasznlja.
A munka nagyja a ciklus trzsben kszl el. A
celsius = (5.0 / 9.0) * (fahr - 32.0); utastssal kiszmtjuk a Celsius-fokokban kifejezett hmrskletet,
s rtkt hozzrendeljk a celsius vltozhoz. Az ok, ami miatt 5.0 / 9.0-t hasznltunk, 5 / 9 helyett

38

Forrs: http://www.doksi.hu

az, hogy a C nyelv csakgy, mint sok ms nyelv, az egsz szmokkal vgzett osztsnl az eredmny trt
rszt elhagyja. Teht 5 / 9 rtke 0, s 0 lenne az sszes hmrsklet is. Az llandn belli tizedespont
jelzi, hogy az illet lland lebegpontos, gy 5.0 / 9.0 rtke 0.555..., amire szksgnk van.
Ugyancsak 32.0-t rtunk 32 helyett, noha mivel a fahr vltoz float 32 automatikusan float-t (32.0-v)
alakulnak t a kivons eltt. Blcsebb azonban azt a stlust kvetni, hogy a lebegpontos llandkat
tizedesponttal rjuk akkor is, ha az rtkk egsz : ezzel az olvas szmra hangslyozzuk ezek
lebegpontos termszett, s biztostjuk, hogy a fordt is eszerintkezelje ket.
A 2. fejezet rszletesen tartalmazza annak szablyait, hogy az
egsz szmok mikor alakulnak t lebegpontoss. Egyelre csak
annyit jegyznk meg, hogy a
fahr = lower;
rtkad utasts s a
while (fahr <= upper) vizsglat egyarnt a vrt mdon mkdik (az int a mvelet elvgzse eltt float-t
alakul t).
Ez a plda a printf mkdsbl is valamivel tbbet mutat meg.
A printf ltalnos cl formtumkonvertl fggvny, amelyet
teljes egszben majd a 7. fejezetben ismertetnk. Els
argumentuma a kinyomtatand karakterlnc, ahol az egyes %-jelek
mutatjk, hogy hov kell a tovbbi (msodik, harmadik, . . .)
argumentumokat behelyettesteni s milyen formtumban kell
azokat kinyomtatni. Pldul a
printf (%4.0f %6.1f \n, fahr, celsius); utastsban a %4.0f konverzi-elrs szerint a lebegpontos
szmot egy legalbb ngy karakter szles helyre kell berni gy, hogy a tizedespontot nem kvetik
szmjegyek. %6.1f egy msik szmot r le, amely legalbb 6 szkzt foglal el s a tizedespont utn 1
szmjegyet tartalmaz - hasonlan a FORTRAN-beli F6.1 vagy a PL/1-beli F(6,1) alakhoz. A
specifikci egyes rszei elhagyhatk:%6f azt rja el, hogy a szm legalbb 6 karakter szles; %.2f
legalbb kt helyet ignyel a tizedespont utn, de a szlessget nem korltozza, s %f egyszeren azt
mondja, hogy a szmot lebegpontosknt kell kinyomtatni. Hozztehetjk, hogy a printf a %d-t
decimlisknt, %o-t oktlisknt, %x-et hexadecimlisknt, %c-t karakterknt, %s-et karakterlncknt s
%%-ot %-knt rtelmezi.
A printf els argumentumban tallhat minden egyes % konstrukcihoz hozzrendeldik a neki
megfelel msodik, harmadik stb. argumentum; ezeknek szm szerint s tpus szerint is meg kell
egyeznik, ellenkez esetben rtelmetlen vlaszokat kapunk.
Egybknt a printf nem rsze a C nyelvnek: a C nyelven bell a
be- s kivitel nincs definilva. A printf-ben nincs semmi
rendkvli: csupn egy hasznos fggvny, amely rsze a C
programok ltal kznsgesen elrhet szabvnyos
rutin-knyvtrnak. Azrt, hogy magra a C nyelvre
koncentrlhassunk, nem foglalkozunk tl sokat a be- s kivitellel, egszen a 7. fejezetig. Elssorban a
formtumozott adatbevitel krdst halasztjuk el addig. Ha szmokat kell beolvasnunk, olvassuk el a 7.
fejezet 7.4. szakasznak a scanf fggvnyrl szl rszt. A scanf - az adatmozgs irnytl eltekintve nagyon hasonl a printf fggvnyhez.
1.3.
Gyakorlat. Mdostsuk gy a hmrsklet-tszmt programot, hogy az a tblzat fl
fejlcet is nyomtasson!
1.4.
Gyakorlat. Irjunk programot a korbbi pldnak megfelel Celsius-Fahrenheit tblzat
kinyomtatsra!
1.3. A for utasts
Az olvas is nyilvn tudja, hogy egy programot sokflekppen meg lehet rni: prblkozzunk
meg a hmrsklet-tszmt program egy msik vltozatval :

39

Forrs: http://www.doksi.hu

main ()

/ * Fahrenheit-Celsius tblzat*/

{
int fahr; for (fahr = 0; fahr <= 300; fahr = fahr + 20) printf (%4d %6.1f \n, fahr, (5.0 / 9.0) * (fahr
- 32));
}
Ez ugyanazokat az eredmnyeket adja, de lthatan mskpp
nz ki. Az egyik f eltrs, hogy a legtbb vltoz
szksgtelenn vlt: csak a fahr maradt meg int vltozknt
(azrt, hogy mutassa a printf-ben a %d konverzit). Az als s a
fels hatr, valamint a lpskz csak llandknt jelenik meg a
for utastsban, amely maga is j szmunkra. A
Celsius-hmrskletet szmt kifejezs most nem kln
rtkad utastsknt, hanem mint a printf harmadik argumentuma
szerepel.
Ez az utbbi mdosts egy egszen ltalnos C-beli szablyon
alapul, amely kimondja, hogy minden olyan sszefggsben, ahol
valamely adott tpus vltoz rtkt hasznlhatjuk, ugyanolyan
tpus kifejezst is hasznlhatunk. Minthogy a printf harmadik
argumentumnak a %6.1f-re val illeszkeds rdekben
lebegpontosnak kell lennie, tetszleges lebegpontos kifejezs
is elfordulhat ezen a helyen.
Maga a for egy ciklusutasts, a while ltalnostsa. Ha az
elbbi while-lal sszehasonltjuk, mkdse rgtn vilgoss
vlik. Hrom rszt tartalmaz, amelyeket pontosvesszk
vlasztanak el. Az els rsz, vagyis
fahr = 0 egyszer hajtdik vgre a ciklusba val belps eltt. A msodik rsz a ciklust vezrl
ellenrzs vagy felttel:
fahr <= 300
A gp megvizsglja a felttelt; ha igaz, akkor vgrehajtja a
ciklus trzst (itt egyetlen printf), amit az jrainicializl
lps, azaz
fahr = fahr + 20 s jabb felttelvizsglat kvet. A ciklus akkor r vget, amikor a felttel hamiss
vlik. Csakgy, mint a while esetben, a trzs vagy egyetlen utasts, vagy pedig kapcsos zrjelek kz
zrt utastsok csoportja. Az inicializl s jrainicializl rsz egy-egy tetszleges kifejezs lehet. A
while s a for kztt szabadon vlaszthatunk aszerint, hogy mi tnik vilgosabbnak. A for alkalmazsa
ltalban olyan ciklusok esetben clszer, amelyekben az inicializls s jrainicializls egy-egy
logikailag sszefgg utasts, mivel a for sokkal tmrebb, mint a while s egy helyen tartja a
ciklusvezrl utastsokat.
1.5.
Gyakorlat. Mdostsuk gy a hmrsklet-tszmt programot, hogy az a tblzatot fordtott
sorrendben, teht 300 foktl 0 fokig nyomtassa ki!
1.4. Szimbolikus llandk
Mg egy megjegyzs, mieltt elbcsznnk a hmrsklet-tszmtstl. Nem j gyakorlat,
ha bvs szmokat, pldul 300-at vagy 20-at ptnk be a programba: ezek nem sokat
mondanak annak, aki ksbb olvassa majd a programot, s megvltoztatsuk is nagyon nehz.
Szerencsre a C nyelv lehetsget ad az ilyen bvs szmok elhagysra. A #define szerkezet
segtsgvel a program elejn szimbolikus nevet vagy szimbolikus llandt rendelhetnk egyegy megadott karakterlnchoz. Ezekutn a fordt a nv mindennem idzjelezett elfordulst
a megfelel karakterlnccal helyettesti. A nv nemcsak szmot, hanem tetszleges szveget is
helyettesthet, pl. :
#define LOWER 0
/* A tblzat als hatra*/
#define UPPER 300
/ * A tblzat fels hatra*/
#define STEP 20 /* Lpsnagysg*/
main () /*Fahrenheit-Celsius tblzat*/

40

Forrs: http://www.doksi.hu

{
int fahr; for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP) printf(%4d %6.1f\n, fahr,
(5.0/9.0) * (fahr-32));
}
A LOWER, UPPER s STEP mennyisgek llandk, gy deklarciban nem jelennek meg. A
szimbolikus neveket nagybetkkel szoks rni, gy azonnal megklnbztethetk a kisbets
vltoznevektl. gyeljnk arra, hogy a defincik utn nincs pontosvessz! Mivel a nevet kvet
teljes sor behelyettestdik, a for-ban tl sok pontosvessz lenne.
1.5. Nhny hasznos program
A kvetkezkben
ttekintnk
nhny egymssal
sszefgg programot, amelyek
karakteradatokon vgeznek egyszer mveleteket. Ki fog derlni, hogy sok program csupn az
itt kzlt prototpusok bvtett vltozata.
Karakterek be- s kivitele
A szabvnyos knyvtrban rendelkezsre llnak olyan fggvnyek,
amelyekkel egyszerre egy karaktert lehet rni vagy olvasni. A
getchar() minden egyes hvsakor beolvassa a kvetkez bemeneti
karaktert s a visszatrsi rtke ez a karakter lesz. Teht
c = getchar() utn a c vltoz a kvetkez bemeneti karaktert tartalmazza. A karakterek kznsges
esetben a terminlrl rkeznek, de ezzel a 7. fejezetig nem kell trdnnk. A putchar fggvny a
getchar ellentte:
putchar a c vltoz tartalmt valamilyen kimeneti perifrira rja ki, ami ltalban ismt a terminl. A
putchar s a printf hvsai keverhetk: a kivitt karakterek a hvs sorrendjben fognak megjelenni.
Hasonlan a printf-hez, a getchar s putchar fggvnyekben sincs semmi rendkvli. Ezek nem rszei a
C nyelvnek, de mindentt rendelkezsre llnak.
llomnymsols getchar s putchar birtokban meglepen sok hasznos programot rhatunk anlkl,
hogy ezen kvl brmi egyebet tudnnk a be- s kivitelrl. A legegyszerbb plda az a program, amely
a bemenetet karakterenknt a kimenetre msolja. A program vza:
egy karakter beolvassa while (a beolvasott karakter nem az llomny vge jel)
az ppen beolvasott karakter kimenetre rsa
egy j karakter beolvassa
Mindezt C nyelven kifejezve:
main()

/*A bemenet tmsolsa a kimenetre. 1. vltozat*/

{
int c ;
c = getchar();
while (c != EOF) {
putchar;
c = getchar();
}
}
A != relcis opertor jelentse : nem egyenl .
A f problma a bemenet vgnek az rzkelse. Megllapods
szerint a getchar az llomny vgnek megtallsakor olyan
rtkkel tr vissza, amely nem valamely rvnyes karakter kdja:
ily mdon a program szlelni tudja, hogy mikor fogytak el a
_bemeneten a karakterek. Az egyetlen problma - ami azonban igen

41

Forrs: http://www.doksi.hu

bosszant -, hogy ktfle megllapods is kzforgalomban van


arra nzve, hogy valjban mi az llomny vge rtk. Ezt a
problmt egyelre azzal kerltk ki, hogy a szmszer rtk
helyett az EOF szimbolikus nevet hasznltuk, fggetlenl a
tnyleges rtktl. A gyakorlatban EOF vagy -1 , vagy 0, a
programot ennek megfelelen vagy
#define EOF -1
vagy
#define EOF 0 kell, hogy megelzze ahhoz, hogy helyes mkdst kapjunk. Azltal, hogy az EOF
szimbolikus llandt hasznltuk annak az rtknek a jellsre, amit llomny vge esetn a getchar
visszaad, elrtk, hogy az egsz programban csupn egyetlen dolog fgg az llomny vge tnyleges
rtktl.
A c vltozt int-nek s nem char-nak deklarltuk, gy abban trolhat a getchar ltal visszaadott rtk.
Mint azt a 2. fejezetben ltni fogjuk, ez a vltoz azrt int tpus, mert alkalmasnak kell lennie arra,
hogy az sszes lehetsges karakteren kvl az EOF rtket is felvegye.
Gyakorlott C programozk a msolprogramot tmrebben rnk le.
A C nyelvben az olyan rtkadsok, mint
c = getchar() kifejezsekben is hasznlhatk; a kifejezs rtke egyszeren a bal oldalhoz hozzrendelt
rtk. Ha a c-re vonatkoz rtkads egy while felttelvizsgl rsznek belsejbe kerl, akkor az
llomnymsol program a kvetkezkppen rhat :
main()

/*A bemenet tmsolsa a kimenetre - 2. vltozat*/

{
int c;
while ((c = getchar()) != EOF)
putchar ;
}
A program beolvas egy karaktert, hozzrendeli c-hez, majd ellenrzi, hogy a karakter azonos-e az
llomny vge jellel. Ha nem, akkor a programfuts a while trzsnek vgrehajtsval, azaz a karakter
kinyomtatsval folytatdik. Ezutn a while ciklus ismtldik. Ha a program vgl elri a bemeneti
karaktersorozat vgt, akkor a while s vele egytt a main is befejezdik.
Ez a vltozat egy helyre vonja ssze a beolvasst - most csak egy getchar hvs van -, s egyben le is
rvidti a programot. Az rtkads behelyezse a felttelvizsglatba az egyik olyan eset, amikor a C
nyelv hasznos tmrtst tesz lehetv. (Megvan persze a lehetsge annak, hogy ezt tlzsba vigyk s
ttekinthetetlen programkdot hozzunk ltre, de ezt igyeksznk elkerlni.)
Lnyeges ltnunk, hogy az rtkads krli zrjelek a
felttelen bell tnyleg szksgesek. A != precedencija
magasabb, mint az = szimblum ami azt jelenti, hogy zrjelek
hinyban a != relcivizsglat megelzn az = rtkadsi
mvelet vgrehajtst. Igy a
c = getchar() != EOF
utasts egyenrtk a
c = (getchar() != EOF) utastssal. Ez azzal a nemkvnatos eredmnnyel jr, hogy c 0 vagy 1 lesz, attl
fggen, hogy a getchar hvsakor llomny vge jel rkezett-e vagy sem. (Errl rszletesebben a 2.
fejezetben szlunk.)
Karakterszmlls

42

Forrs: http://www.doksi.hu

A kvetkez program, amelyet a msolprogram kis mdostsval kaptunk, megszmllja a beolvasott


karaktereket:
main()

/* Megszmllja a bemeneten rkez karaktereket*/

{
long nc;
nc = 0;
while (getchar () != EOF)
++nc;
printf(%ld\n, nc);
}

A
++nc; utasts egy j opertort mutat be, amelynek jele ++, s a jelentse: inkrementlj eggyel.
Irhatnnk azt is, hogy nc = nc + 1, de ++nc tmrebb s gyakran hatkonyabb is. Ltezik egy ennek
megfelelopertor, amely 1-gyel dekrementl. A ++ s a egyarnt lehet prefix (eltag) opertor
(++nc) vagy postfix (uttag) opertor (nc++)- e kt alakhoz kifejezsekben klnbz rtkek
tartoznak, amint azt a 2. fejezetben ltni fogjuk, de ++nc s nc++ egyarnt inkrementlja nc-t. Egyelre
megmaradunk a prefix opertornl.
A karakterszmll program a karakterek szmt int helyett egy long tpus vltozban trolja. A PDP11-en egy int mennyisg maximlis rtke 32767, gy a szmll viszonylag kevs bemen rtk
esetn is tlcsordulna, ha int-nek deklarlnnk. A Honeywell s IBM C-ben a long s az int ugyanaz, de
a maximlis rtk sokkal nagyobb. A %ld konverzimegads azt jelzi printf-nek, hogy a megfelel
argumentum egy hossz egsz (long integer).
Ennl is nagyobb szmok esetn a double tpus (duplahosszsg lebegpontos szm) hasznlhat. A
while helyett for utastst fogunk hasznlni,hogy bemutathassuk a ciklusszervezs egy msik
lehetsgt.
main()

/*Megszmllja a bemeneten rkez karaktereket*/

{
double nc;
for (nc = 0; getchar() != EOF; ++nc)
;
printf (%.0f \n, nc);
}
A printf mind float, mind double esetn %f-et hasznl; a %.0f elnyomja a nemltez trt rsz kirst.
A for ciklus trzse res, mivel az egsz feladat a felttelvizsgl s jrainicializl rszben hajtdik
vgre. A C nyelvtani szablyai azonban megkvnjk, hogy a for utastsnak legyen trzse. Az
egymagban ll pontosvessz, vagyis a nulla (res)utasts e kvetelmny kielgtse miatt szerepel.
Kln sorba rtuk, hogy feltnbb legyen.
Mieltt befejeznnk a karakterszmll program elemzst, felhvjuk a figyelmet, hogy ha a bemeneten
nincsenek karakterek, akkor getchar legels hvsakor a while vagy a for felttelvizsglata hamis rtket
eredmnyez, s gy a program eredmnye elvrsunknak megfelelen 0 lesz. Ez lnyeges megfigyels.
A while s a for egyik elnys tulajdonsga, hogy a felttelvizsglat a ciklus fejben van, megelzi a
trzset. Ha teht semmit sem kell csinlni, akkor tnyleg semmi sem trtnik, mg akkor sem, ha emiatt
a program sohasem halad t a ciklus trzsn. A programoknak akkor is rtelmesen kell mkdnik, ha a
bemenet res. A while s a for segtsgvel a programok hatresetekben is sszeren viselkednek.
Sorok szmllsa
A kvetkez program megszmllja a bemenetre rkez sorokat. Felttelezzk, hogy a bemen sorok
a \n jsor karakterrel fejezdnek be, amely szigoran minden kirt sor vgn megjelenik.
main()

/*A bemenetre rkez sorok szmllsa*/

43

Forrs: http://www.doksi.hu

int c, nl ;
nl = 0;
while ((c = getchar()) != EOF)
if (c == \n)
++nl; printf (%d\n, nl );
}
A while trzse most egy if-et tartalmaz, amely pedig a ++ nl inkrementl mveletet vezrli. Az if
utasts elvgzi a zrjelezett felttel vizsglatt, ha ennek eredmnye igaz, akkor vgrehajtja a
rkvetkez utastst (vagy kapcsos zrjelek kztti utastscsoportot). A sorokat ismt gy rendeztk
el, hogy vilgos legyen, mit mi vezrel.
A C nyelv jellsmdjban az == (ketts egyenlsgjel) jelentse: egyenl . . .-vel (hasonlan a
FORTRAN-beli .EO.-hoz). Ezzel a szimblummal klnbztetjk meg az egyenlsg vizsglatt a
szimpla = jeltl, amit rtkadsra hasznlunk. Minthogy tipikus C programokban az rtkads
krlbell ktszer olyan gyakran fordul el, mint az egyenlsgvizsglat, sszer, hogy az rtkad
opertor fele olyan hossz legyen. Brmely egymagban ll karakter aposztrfok kz rva az illet
karakternek a gp karakterkszletben szerepl numerikus rtkt jelenti: ezt karakterllandnak
nevezzk. Igy pldul A karakterlland; az ASCII karakterkszletben ennek rtke 65, vagyis az A
karakter bels brzolsa. Termszetesen knyelmesebb A-t rni, mint 65-t: A jelentse vilgos s
fggetlen az adott karakterkszlettl.
A karakterllandkban a karakterlncokban hasznlt escape jelsorozatok is megengedettek, gy a
felttelvizsglatokban s aritmetikai kifejezsekben \n az jsor karakter kdrtkt jelenti. Ne
feledjk, hogy \n egyetlen karakter, amely kifejezsekben egy egsz szmmal egyenrtk, \n viszont
karakterlnc, amely az adott esetben egyetlen karaktert tartalmaz! A karakterek s karakterlncok
tmjt a 2. fejezetben folytatjuk.
1.6. Gyakorlat. rjunk olyan programot, amely megszmllja a szkzket, tab s jsor
karaktereket!
1.7. Gyakorlat. rjunk olyan programot, amely a bemenetet tmsolja a kimenetre, mikzben az egy
vagy tbb szkzbl ll karakterlncokat egyetlen szkzzel helyettesti!
1.8. Gyakorlat. rjunk olyan programot, amely minden egyes tab karaktert a > , visszalptets
(backspace), - hromkarakteres sorozattal helyettest, ami thzott > -knt fog megjelenni,
tovbb, amely a visszalptets karaktereket a hasonlan thzott < szimblummal helyettesti!
Ezltal a tab karakterek s visszalptetsek lthatv vlnak.

Szavak szmllsa
Negyedik hasznos programunk sorokat, szavakat s karaktereket szmll annak a laza defincinak az
alapjn, amely sznak tekint minden olyan karaktersorozatot, amely nem tartalmaz szkzt, tab vagy
jsor karaktert. (Az albbi program az UNIX wc segdprogramjnak a vza.)
#define YES 1
#define NO 0
main () /*A bemenet sorainak, szavainak,
karaktereinek szmllsa*/
{
int c, nl, nw, nc, inword;
inword = NO;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == \n)
++nl; if (c == ||c == \n ||c == \t)
inword = NO;
else if (inword == NO) {
inword = YES;

44

Forrs: http://www.doksi.hu

++nw;
}
}
printf (%d %d %d\n, nl, nw, nc);
}
Ahnyszor a program egy sz els karaktervel tallkozik, nveli a szmllt. Az inword vltoz jelzi,
hogy a program pillanatnyilag egy szn bell van-e vagy sem; kezdetben nincs szn bell, miltal a NO
rtk rendeldik hozz. Elnyben rszestjk a YES s NO szimbolikus llandkat az 1 s 0
szmrtkekkel szemben, mivel olvashatbb teszik a programot. Termszetesen egy ilyen kis
programban, mint ez, ennek nemigen van jelentsge, de nagyobb programokban az rthetsg javulsa
sokszorosan megri azt a szerny plusz fradsgot, ami, az ilyen stlus programrshoz szksges.
Mdostani is knnyebb az olyan programot, ahol a szmok csupn szimbolikus llandknt jelennek
meg.
Az
nl =nw=nc=0;
sor mindhrom vltozt kinullzza. Ez nem specilis eset, hanem
annak a tnynek a kvetkezmnye, hogy az rtkadsok jobbrl
balra mennek vgbe. Ez valjban ugyanaz, mintha azt rtuk
volna, hogy
nc = (nl = (nw = 0));
A || opertor jelentse VAGY, teht az
if (c == ||c == \n ||c == \t) sor azt jelenti, hogy ha c szkz vagy c jsor vagy c tab karakter . . . .
(Mint mondottuk, a \t escape szekvencia a tab karakter lthat megjelensi formja.) Ltezik az ennek
megfelel && opertor is az S kifejezsre. Az && vagy || opertorokkal sszekapcsolt kifejezsek
kirtkelse balrl jobbra trtnik, s a kirtkels rgtn abbamarad, amint az egsz kifejezs igaz
vagy hamis volta nyilvnvalv vlik. Ha teht c szkz karakter, nincs szksg annak megllaptsra,
hogy c jsort vagy tabot tartalmaz-e, teht ezek a vizsglatok nem mennek vgbe. Itt most ez nem
klnsen lnyeges, de bonyolultabb esetekben nagyonis fontos lehet, amint azt nemsokra ltni fogjuk.
A pldban a C nyelv else utastsa is szerepel, amely megadja azt az alternatv tevkenysget, amit
akkor kell elvgezni, ha az if felttelrsze hamis rtk. ltalnos alakja:
if (kifejezs)
1.utasts
else
2.utasts
Az if-else-hez tartoz kt utasts kzl egy s csakis egy, mgpedig ha a kifejezs rtke igaz, akkor az
1. utasts, ha hamis, akkor a 2. utasts hajtdik vgre. Mindkt utasts valjban egszen bonyolult is
lehet. A szavakat szmll programban pl. az else utni utasts egy jabb if, amely a kapcsos zrjelek
kztti kt utastst vezrli.
1.9. Gyakorlat. Hogyan ellenrizhetjk a szavakat szmll programot? Mik lehetnek szhatrok.
1.10. Gyakorlat. Irjunk olyan programot, amely kln-kln sorokban nyomtatja ki a bemenetre
rkez szavakat!
1.11. Gyakorlat. Mdostsuk a szavakat szmll programot gy, hogy jobban definiljuk a sz
fogalmt, pldul a sz legyen betk, szmjegyek s aposztrfok olyan sorozata, amely betvel
kezddik!
1.6.
Tmbk
rjunk olyan programot, amely megszmllja, hogy hnyszor fordulnak el az egyes szmjegyek,
hny res helyet ad karakter (szkz, tab, jsor) s hny egyb karakter van a beolvasott
llomnyban! Ez a feladat nyilvn mesterklt, de lehetv teszi, hogy egyetlen programban
szemlltessk a C tbb jellegzetessgt.

45

Forrs: http://www.doksi.hu

Tizenktfle bemeneti karaktert kell megklnbztetnnk, gy rdemes az egyes szmjegyek


elfordulsainak szmt egy tmbben nyilvntartani ahelyett, hogy tz kln vltoznk lenne. A
program egyik lehetsges vltozata:
main() /*Szmjegyek, res helyek s
egyb karakterek szmllsa*/
{
int c, i, nwhite, nother;
int ndigit [10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit [i] = 0;
while ((c = getchar()) != EOF)
if (c >= 0 && c <= 9)
++ ndigit [c - 0]; else if (c == || c == \n || c == \t)
++ nwhite;
else
++nother;
printf (szmjegyek=);
for (i = 0; i < 10; ++i)
printf (%d, ndigit [i]);
printf (\n res hely = %d, egyb = %d\n,
nwhite, nother);
}
Az
int ndigit [10]; deklarci azt fejezi ki, hogy az ndigit egy 10 egszbl ll tmb. A tmbindexek a C
nyelvben mindig 0-val kezddnek (s nem 1 -gyel, mint a FORTRAN-ban s a PL/1-ben), gy a tmb
elemei: ndigit[0], ndigit [1], . . ., ndigit[9]. Ezt tkrzi a kt for ciklus: az egyik inicializlja, a msik
kiratja a tmbt. Az index tetszleges egsz tpus kifejezs. gy termszetesen lehet az index egsz
tpus vltoz, mint pl. i, valamint egsz rtk lland is.
Az adott program lnyeges mdon kihasznlja a szmjegyek
karakterbrzolsnak tulajdonsgait. Pldul az
if (c >= 0 && c <= 9)
...
vizsglat eldnti, hogy a c-ben lev karakter szmjegy-e. Ha az,
akkor az illet szmjegy numerikus rtke
c - 0
Ez a mdszer csak akkor alkalmazhat, ha 0, 1, . . . nveked sorrend pozitv szmok s 0 s 9
kztt csak szmjegyek vannak. Szerencsre ez minden szoksos karakterkszlet esetben gy van.
A char-okat s int-eket tartalmaz kifejezsekben definci szerint kirtkels eltt minden int-t
konvertldik, gy a char vltozk s llandk aritmetikai szempontbl lnyegben az int
mennyisgekkel azonosak. Ez egszen termszetes s knyelmes megolds: pldul c - 0 egsz tpus
kifejezs, amelynek rtke 0 s 9 kztt van a c-ben trolt 0 s 9 kztti karaktereknek megfelelen,
s gy rvnyes indexe az ndigit tmbnek.
Annak eldntse, hogy a karakter szmjegy, res hely vagy
valami ms, az
if (c >= 0 && c <= 9)

46

Forrs: http://www.doksi.hu

++ndigit [c - 0]; else if (c == || c == \n || c == \t)


++nwhite;
else
++nother;
programrsz segtsgvel trtnik. Az
if (felttel)
utasts
else if (felttel)_
utasts
else
utasts programszerkezetet gyakran alkalmazzk tbbutas elgazsok lersra.
A programszveg beolvassa fellrl kezdve mindaddig folytatdik, amg a gp igaz felttelt nem tall.
Ekkor vgrehajtja az odatartoz utasts rszt, s az egsz mvelet vgetr. (Az utasts termszetesen
tbb, kapcsos zrjelek kz zrt utasts is lehet.) Ha egyik felttel sem igaz, a gp az utols else utni
utastst hajtja vgre, amennyiben van ilyen.
Ha az utols else s a hozztartoz utasts hinyzik (mint a
szavakat szmll programban), semmi sem trtnik. A kezd if,
valamint a zr else kztt tetszleges szm
else if (felttel)
utasts csoport fordulhat el. Stilris szempontbl clszer a bemutatott mdon megszerkeszteni ezt a
programrszt, hogy a hossz dntsi lncok ne nyljanak tl a papr jobb szln. A 3. fejezetben
fogunk szlni a switch utastsrl, amely szintn tbbutas programelgaztatsok lersra ad
lehetsget. A switch alkalmazsa klnsen akkor elnys, amikor azt vizsgljuk, hogy egy adott
egsz vagy karakter tpus kifejezs rtke egyenl-e egy llandkbl ll halmaz valamelyik elemvel.
Az sszehasonlts cljbl a 3. fejezetben bemutatjuk az elbbi a program switch utastssal megrt
vltozatt.
1.12. Gyakorlat. rjunk olyan programot, amely kinyomtatja a bemenetn elfordul szavak
hosszsgnak hisztogramjt! A legegyszerbb, ha a hisztogramot vzszintesen rajzoljuk; a
fggleges irny rajzols nehezebb feladat.
1.7.
Fggvnyek
A C nyelvben a fggvny ugyanaz, mint a FORTRAN-ban a szubrutin, ill. fggvny, vagy a PL/1ben, a PASCAL-ban s ms nyelvekben az eljrs.
A fggvny knyelmes lehetsget nyjt szmunkra, hogy valamely szmtsi rszt fekete
dobozba zrjunk, amelyet azutn hasznlhatunk anlkl, hogy tartalmval trdnnk kellene.
Valjban csak a fggvnyek segtsgvel brkzhatunk meg nagy s bonyolult programokkal.
Helyesen tervezett fggvnyek esetben teljesen figyelmen kvl hagyhatjuk, hogyan keletkezik a
fggvny rtke (eredmnye); elegend a feladat s az eredmny ismerete.
A C nyelv egyszer, knyelmes s hatkony fggvnyhasznlatot tesz lehetv. Gyakran fogunk
olyan fggvnyekkel tallkozni, amelyek csupn nhny sorbl llnak s amelyeket csak egyszer
hvunk meg: ezeket kizrlag a program vilgosabb ttele rdekben hasznljuk.
Ezidig csak olyan fggvnyeket hasznltunk, mint a printf, a getchar vagy a putchar, amelyeket
kszen kaptunk; itt az ideje, hogy magunk is rjunk nhnyat. Mivel a C nyelvnek nincs olyan
hatvnyoz opertora, mint a ** a FORTRAN-ban vagy a PL/1-ben, szemlltessk a
fggvnydefinils technikjt a power(m, n) fggvny megrsval, amely az m egsz tpus
vltozt a pozitv egsz n hatvnyra emeli. Teht a power(2,5) fggvny rtke 32. Ez a fggvny
nyilvnvalan nem tudja mindazt, amit ** tud, mivel csak kis egsz szmok pozitv hatvnyait tudja
kezelni, de legjobb, ha egyszerre csak egy problmra sszpontostunk. Az albbiakban a power
fggvnyt egy fprogramba gyazva mutatjuk be. Ne feledjk, hogy a main() maga is fggvny!
main ()

/*Hatvnyoz fggvny tesztelse*/

47

Forrs: http://www.doksi.hu

{
int i;
for (i = 0; i < 10; ++i)
printf (%d %d %d\n, i, power (2,i), power (-3,i));
}
power (x,n) /*x n-dik hatvnyra emelse; n >0*/ int x, n;
{
int i, p;
p = 1;
for (i = 1; i <= n; ++i)
p=p*x;
return (p);
}
Mindkt fggvny az albbi alak:
nv (opcionlis argumentumlista)
opcionlis argumentumdeklarcik
{
deklarcik
utastsok
}
A fggvnyek tetszleges sorrendben szerepelhetnek, s egy vagy kt forrsllomnyban egyarnt
llhatnak. Termszetesen, ha a forrs kt llomnyban tallhat, bonyolultabb a fordts s a tlts,
mintha minden egyetlen llomnyban van, de ez az opercis rendszer krdse s nem a
nyelvjellegzetessge. Pillanatnyilag feltesszk, hogy a kt fggvny ugyanabban az llomnyban van,
teht mindaz, amit a C programok futtatsrl megtanultunk, nemvltozik.
A power fggvnyt a
printf (%d %d %d\n, i, power(2,i), power(-3,i)); sorban ktszer hvtuk meg. Mindkt hvs kt
argumentumot ad t a power fggvnynek, amely mindkt alkalommal visszaad egy-egy egsz szmot,
amit a hv program formtumoz s megjelent. Kifejezsen bell power(2, i) ugyanolyan egsz, mint
2 s i. (Nem minden fggvny eredmnyez egsz rtket: ezt a tmt a 4. fejezetben folytatjuk.)
A power argumentumait megfelelkppen deklarlni kell ahhoz,
hogy a tpusuk ismert legyen. Ez a fggvny nevt kvet
int x, n; sorban trtnik. Az argumentumdeklarcik az argumentumlista s a nyit bal kapcsos zrjel
kztt vannak; minden deklarcit pontosvessz zr le. A power fggvny ltal a sajt argumentumai
szmra hasznlt nevek teljes mrtkben loklisak a power fggvnyre nzve, azokhoz semmilyen ms
fggvny sem frhet hozz: ms rutinok veszlytelenl hasznlhatjk ugyanezeket a neveket. Ez a p s
az i vltozra is vonatkozik: a power-beli i vltoznak semmi kze a main-ben hasznlt i-hez.
A power fggvny ltal kiszmtott rtket - mint a PL/1-ben - a return utasts adja vissza a main-nek.
A zrjelek kztt tetszleges kifejezs elfordulhat. Egy fggvnynek nem felttlenl szksges
rtket visszaadnia: egy kifejezs nlkli return utasts tadja a vezrlst, de nem ad t hasznos rtket
a hvnak - ez trtnik olyankor, amikor a vezrls a fggvny vgt tlpi azltal, hogy elri a jobb
oldali zr kapcsos zrjelet.
1.13. Gyakorlat. Irjunk olyan programot, amely a beolvasott szveget kisbetss alaktja t egy
olyan lower fggvny segtsgvel, amely c-vel tr vissza, ha c nem bet, s c kisbets
megfeleljt adja vissza, ha c bet! D
1.8.
Argumentumok; rtk szerinti hvs
A C fggvnyek egyik tulajdonsgt ms nyelvekben - klnsen a FORTRAN-ban vagy PL/1ben - jratos programozk szokatlannak tallhatjk: a C-ben mindig rtk szerinti
fggvnyargumentum-tads trtnik. Ez azt jelenti, hogy a hvott fggvny az argumentumainak
nem a cmt, hanem - ideiglenes vltozban (valjban egy veremben) - az rtkt kapja meg. Ez
bizonyos eltr tulajdonsgokhoz vezet az olyan nv szerint hv nyelvekhez kpest, mint amilyen a

48

Forrs: http://www.doksi.hu

FORTRAN s a PL/1, amelyekben a hvott rutin az argumentum cmt, nem pedig az rtkt kapja
meg.
A f klnbsg az, hogy a C-ben a hvott fggvny nem tudja megvltoztatni a hv fggvny
vltozinak rtkt, csak a sajt, ideiglenes vltozpldnyainak tud j rtket adni. Az rtk
szerinti hvs azonban elny, nem pedig htrny. ltala legtbbszr tmrebb programokat
llthatunk el, kevesebb segdvltozt kell hasznlnunk, mivel a hvott rutinban az argumentumok
ugyanolyan mdon kezelhetk, mint a hagyomnyosan inicializlt vltozk. Nzzk pldul a
power kvetkez vltozatt, amely kihasznlja ezt a tnyt:
power (x,n)

/*x n-edik hatvnyra emelse; n > 0;

2. vltozat*/
int x, n;
{
int p;
for (p = 1; n > 0; --n)
p = p * x;
return (p);
}
Az n argumentumot ideiglenes vltozknt hasznltuk s addig dekrementltuk, amg el nem rte a 0-t;
gy nincs szksg az i vltozra. Mindannak, ami az n-nel a power-en bell trtnik, nincs befolysa
arra az argumentumra, amellyel eredetileg a fggvnyt meghvtuk.
Szksg esetn megoldhat, hogy a fggvny mdostani tudja az t hv rutin valamelyik vltozjt. A
hvnak meg kell adnia a mdostand vltoz cmt (gyakorlatilag egy, a vltozt megcmz mutatt),
s a hvott fggvnynek az argumentumot mutatknt kell deklarlnia, a tnyleges vltozra ezen
keresztl, indirekt mdon kell hivatkoznia. Ezzel az 5. fejezetben foglalkozunk.
Ha egy tmb nevt hasznljuk argumentumknt, akkor a fggvnynek tadott rtk tnylegesen a tmb
kezdetnek helye vagy cme. (A tmbelemek nem msoldnak t). Ezt az rtket indexelve a fggvny
a tmb tetszleges elemt elrheti s megvltoztathatja. Ezzel a kvetkez fejezet foglalkozik.
1.9.
Karaktertmbk
A C nyelvben leggyakoribb tmbtpus valsznleg a karaktertmb. A karaktertmbk s az ket
kezel fggvnyek hasznlatt egy olyan programmal szemlltetjk, amely sorokat olvas be s
kzlk a leghosszabbat megjelenti.
Az alapstruktra meglehetsen egyszer :
while (van mg sor) if (hosszabb, mint az eddigi leghosszabb sor)
trold a sort s a hosszt nyomtasd ki a leghosszabb sort Ez a struktra vilgoss teszi a program
termszetes tagozdst. Az egyik rsz beolvassa s megvizsglja az jsort, a msik trolja, a
harmadik vezrli a folyamatot.
Minthogy a feladatok ilyen szpen elklnthetk, helyes, ha a programot is eszerint rjuk meg. Ennek
megfelelen elszr rjunk egy kln getline fggvnyt, amely beolvassa a bemenetrl a kvetkez
sort,_ ez a getchar fggvny ltalnostsa. Szeretnnk ha a fggvny ms krnyezetben is hasznlhat
lenne, ezrt igyeksznk a lehet legrugalmasabb tenni. A minimlis igny, hogy a getline jelezze
vissza az esetleges llomnyvget; ltalnosabban hasznlhat lesz a fggvny, ha a sor hosszt adja
vissza, vagy pedig nullt, ha elrte az llomny vgt. A nulla bizonyosan nem valdi sorhossz, mivel
minden sor legalbb egy karaktert kell, hogy tartalmazzon, mg a csupn egyetlen soremelst
tartalmaz sor hossza is 1.
Ha azt talljuk, hogy egy sor hosszabb, mint az addigi leghosszabb sor, valahov el kell mentennk.
Logikus, hogy ez egy msodik fggvny, a copy feladata legyen, amely az j sort biztos helyre menti.
Vgezetl szksgnk van egy fprogramra, amely vezrli a getline-t s a copy-t. Ime az egsz
program:
#define MAXLINE 1000 /*A beolvasott sor maximlis mrete*/
main ()

/*A leghosszabb sor kivlasztsa*/

49

Forrs: http://www.doksi.hu

{
int len; /*A pillanatnyi sor hossza*/
int max; / *Az eddigi maximlis hossz*/
char line [MAXLINE]; /*A pillanatnyilag olvasott sor*/
char save [MAXLINE]; /*A leghosszabb sor mentsre*/
max = 0;
while ((len = getline (line,MAXLINE)) > 0)
if (len > max) {
max = len; copy (line,save);
}
if (max > 0) /*Volt sor*/
printf (%s, save);
}
getline (s,lim)

/*Sor beolvassa s-be,


a hosszt adja vissza*/

char s [];
int lim;
{
int c, i;
for (i = 0; i < lim - 1 && (c =getchar ()) != EOF &&
c != \n; ++i) s [i] = c;
if (c == \n) {
s [i] = c;
++i;
}
s [i] = \0;
return (i);
}
copy (s1,s2)

/*s1 msolsa s2-be;


s2-t elg nagynak felttelezi*/

char s1 [], s2 [];


{
int i;
i = 0;
while ((s2 [i] = s1 [i]) != \0)
++i;
}
main csakgy, mint getline, kt argumentumon s egy visszaadott
rtken keresztl kommunikl. A getline-ban az argumentumokat a
char s []; int lim;
sorok deklarljk, amelyek elrjk, hogy az els argumentum tmb, a msodik pedig egsz tpus
legyen. Az s tmb hossza getline-ban nincs megadva, mivel azt a main-ben hatrozzuk meg. A getline a
return utasts segtsgvel kld vissza rtket a hvnak gy, ahogy azt a power fggvnynl lttuk.
Egyes fggvnyekhasznos rtket szolgltatnak, mg msokkal, gy a copy-val is valamely adott
feladatot vgeztetnk el, s nem adnak vissza hasznos rtket.
A getline az ltala ltrehozott tmb vgre, a karakterlnc
vgnek jelzsre egy \0 karaktert (egy nulla karaktert,
amelynek rtke 0) helyez el. gy mkdik a C fordt is: amikor
egy karakterlnc lland, mint pldul

50

Forrs: http://www.doksi.hu

hello\n van a C programban, a fordt a lnc karaktereit tartalmaz karaktertmbt hoz ltre, amelyet
egy \0-val zr le. A fggvnyek, pl. a printf, gy kpesek a karakterlnc vgnek az rzkelsre:
h e l l o \n \0
A printf %s formtumspecifikcija egy ilyen formban brzolt karakterlncot vr. Ha megvizsgljuk
a copy fggvnyt, szrevehetjk, hogy az is arra tmaszkodik, hogy az s1 bemeneti argumentumot \0
zrja le, s ezt a karaktert is tmsolja az s2 kimeneti argumentumra. (Mindez azt felttelezi, hogy \0
nem rsze a norml szvegnek.)
Futlag rdemes megjegyeznnk, hogy mg egy ilyen kis program is felvet nhny knyes tervezsi
problmt. Pldul mit csinljon main, ha olyan sorral tallkozik, amely hosszabb, mint a megadott
korlt? A getline helyesen mkdik: amikor a tmb megtelt, lell, mg akkor is, ha nem tallt jsort. A
hosszat s az utolsnak visszaadott karaktert ellenrizve a main el tudja dnteni, hogy a sor tl hossz
volt-e, majd tetszs szerint cselekedhet. A rvidsg kedvrt ezt a problmt figyelmen kvl hagytuk.
Aki a getline fggvnyt hasznlja, nem tudhatja elre, hogy milyen hossz lehet egy beolvasott sor, gy
a getline ellenrzi a tlcsordulst. Msfell a copy hasznlja mr tudja (vagy kidertheti), hogy
mekkork a karakterlncok, ezrt gy dntttnk, hogy ezt a fggvnyt nem egsztjk ki
hibaellenrzssel.
1.14. Gyakorlat. Mdostsuk a leghosszabb sort keres program f rutinjt oly mdon, hogy
helyesen rja ki tetszlegesen hossz bemeneti sorok hosszt s a szvegbl annyit, amennyi
csak lehetsges!
1.15. Gyakorlat. Irjunk programot, amely minden olyan sort megjelent, amely 80 karakternl
hosszabb!
1.16. Gyakorlat. Irjunk olyan programot, amely eltvoltja a sorvgi szkzket s tab karaktereket
a bemenet minden sorbl s trli a teljesen res sorokat!
1.17. Gyakorlat.Irjunk olyan reverse(s) fggvnyt, amely megfordtja az s karakterlncot!
Hasznljuk fel ezt a fggvnyt olyan program megrshoz, amely soronknt megfordtja a
beolvasott szveget!
1.10.
rvnyessgi tartomny; kls vltozk
A main-en belli vltozk (line, save stb.) a main sajt vltozi, vagyis a main-re nzve loklisak.
Mivel ezeket a main-en bell deklarltuk, egyetlen ms fggvny sem tud kzvetlenl hozzjuk
frni. Ugyanez mondhat ms fggvnyek vltozirl; pldul a getline fggvnyen belli i vltoz
fggetlen a copy i vltozjtl. A fggvnyek loklis vltozi csak meghvsukkor jnnek ltre, s
megsemmislnek, amikor a vezrls a fggvnybl kilp. Az ilyen dinamikus loklis vltozkat
ezrt - ms nyelvek szhasznlathoz hasonlan - automatikus vltozknak nevezzk. A 4.
fejezetben trgyaljuk az n. static trolsi osztlyt, amelyben a loklis vltozk megtartjk az
rtkket kt fggvnyhvs kztt.
Minthogy az automatikus vltozk lettartama arra az idre korltozdik, amg a vezrls a
fggvnyen van, rtkket nem rzik meg egyik hvstl a msikig, gy minden belpskor explicit
mdon rtket kell adni nekik. Ha ezt elmulasztjuk, tartalmuk bizonytalan.
Az automatikus vltozk mellett olyan vltozkat is definilhatunk, amelyek az sszes fggvnyre
nzve klsk, gy rtkk fggvnyhvsoktl fggetlenl fennmarad. Ezeket a globlis vltozkat
brmelyik fggvny nv szerint elrheti (hasonlan a FORTRAN nyelv common vagy a PL/1
external mechanizmushoz). Globlis hozzfrhetsgk miatt a fggvnyek kztti adattadst
argumentumlistk helyett kls vltozkon keresztl is megoldhatjuk.
A kls vltozkat az sszes fggvnyen kvl kell definilni:
ezzel trolhelyet foglalunk le szmukra. A vltozkat minden olyan fggvnyben, ahol hasznlni
akarjuk, vagy explicit mdon az extern alapszval, vagy implicit mdon rtelemszeren, de
deklarlnunk is kell. Mindez bizonyra rthetbb lesz, ha pldaknt jra megrjuk a leghosszabb
sort keres programot gy, hogy a line, a save s a max kls vltoz legyen. Ehhez
mindhromfggvnyben meg kell vltoztatnunk a hvsokat, a deklarcikat s a fggvnyek
trzseit.
#define MAXLINE 1000 /*A beolvasott sor maximlis mrete*/
char line [MAXLINE]; /* A beolvasott sor*/
char save [MAXLINE]; /*A leghosszabb sor mentsre*/

51

Forrs: http://www.doksi.hu

int max; /*Az eddigi maximlis hossz*/


main () /*A leghosszabb sor kivlasztsa;
specilis vltozat*/
{
int len; /*A pillanatnyi sor hossza*/
extern int max;
extern char save [ ];
max = 0;
while ((len = getline ()) > 0)
if (len > max) {
max = len;
copy ();
}
if (max > 0) /*Volt sor*/
printf (%s, save);
}
getline ()

/* Specilis vltozat*/

{
int c, i;
extern char line [];
for (i = 0; i < MAXLINE - 1 && (c=getchar ()) != EOF
&& c != \n; ++i) line (i] = c;
if (c == \n) {
line [i] = c;
++i;
}
line [i] = \0;
return (i);
}
copy ()

/*Specilis vltozat*/

{
int i;
extern char line [], save [];
i = 0;
while ((save [i] = line [i]) != \0)
++i;
}
Pldnkban a main, a getline s a copy fggvnyben elfordul kls vltozkat az els sorokban
definiltuk, itt hatroztuk meg tpusukat s foglaltuk le a szksges trterletet. Ezek a kls defincik
ugyanolyan felptsek, mint a korbban ltott deklarcik, de mivel fggvnyeken kvl fordulnak
el; kls vltozkat adnak meg. Fggvnyben kls vltozt csak akkor hasznlhatunk, ha elzleg
kzljk a fggvnnyel a vltoz nevt. Ennek egyik mdja, hogy a fggvnyben egy extern deklarcit
helyeznk el, amely mindssze abban klnbzik az eddigi deklarciktl, hogy az extern alapszval
kezddik. Bizonyos krlmnyek kztt az extern deklarci elhagyhat; ha a forrsszvegben egy
vltoz kls defincija megelzi a vltoz hasznlatt valamely fggvnyben, akkor e fggvnyben
nincs szksg extern deklarcira. Igy a main, a getline s a copy fggvnyben az extern deklarcik
feleslegesek. Gyakorlott C-programozk ltalban a forrsszveg elejn definiljk az sszes kls
vltozt, s nem hasznlnak extern deklarcikat.
Ktelez azonban az extern deklarci, ha forrsprogramunk
tbb llomnyra tagoldik, s egy vltozt, mondjuk az A
llomnyban definilunk, de B-ben hasznlunk, hiszen ilyenkor a
vltoz kt elfordulsa kztt csak a B-ben elhelyezett extern

52

Forrs: http://www.doksi.hu

deklarcival teremthetnk kapcsolatot. Ezt a tmt bvebben a


4. fejezetben fejtjk ki.
Nem szabad sszetvesztennk a kls vltozk deklarcijt s defincijt! A definci az a
programsor, ahol a vltozt tnylegesen ltrehozzuk, szmra trhelyet foglalunk le; a deklarci
viszont olyan programrsz, ahol csupn lerjuk a vltoz tulajdonsgait, de trhelyfoglals nem
trtnik. Megjegyezzk, hogy az ember hajlamos az gvilgon mindent kls vltozknt
megadni, mivel az ltszlag egyszersti az adattadst - az argumentumlistk rvidek, s a
vltozk mindig rendelkezsre llnak, amikor csak akarjuk. Csakhogy a kls vltozk akkor is
ott vannak, ha nem akarjuk! Ez a programozsi stlus slyos veszlyeket hord magban. Az gy
rt programokban az adattadsok ttekinthetetlenek - a vltozk vratlanul, st a programoz
szndktl teljesen eltr mdon megvltozhatnak, s a program igen nehezen mdosthat.
Emiatt a leghosszabb sort keres program msodik vltozata gyengbb az elsnl, de hibja az
is, hogy a vltozk nevnek rgztsvel kt hasznos fggvny elveszti ltalnos jellegt.
1.18. Gyakorlat. Az elbbi getline fggvny for utastsban a felttelvizsglat meglehetsen
gyetlen. Javtsunk rajta, de gy, hogy az llomny vgn vagy puffertlcsordulskor a program
az eddigi mdon mkdjn! Biztos, hogy ez a legjobb szervezs?
1.11.
sszefoglals
Az 1. fejezetben ttekintettk a C nyelv legfontosabb elemeit. Ebbl a nhny ptelembl is
tekintlyes mret, hasznos programokat rhatunk, s valsznleg j gondolat, ha ennek rdekben
az olvas most megfelel sznetet tart a knyv olvassban. Az albb kvetkez gyakorlatokban
programtleteket szeretnnk adni olyan programokra, amelyek bonyolultabbak mint azok,
amelyeket ez a fejezet bemutatott.
Ha az olvas mr elsajttotta a C nyelv eddig ismertetett elemeit, folytassa az olvasst, mivel a
kvetkez nhny fejezetben olyan jellegzetessgekrl szlunk, amelyek nagyban hozzjrulnak a
nyelv erejhez s kifejezkpessghez.
1.19.
Gyakorlat. Irjunk detab nven programot, amely a bemeneten tallt tab karakterek
mindegyikt annyi szkzzel helyettesti, amennyi a kvetkez tabultorstop-ig htravan!
Ttelezznk fel egy rgztett tabultorstopkszletet, a stop-ok mondjuk minden n-edik pozcin
tallhatk.
1.20.
Gyakorlat. Irjuk meg az entab programot, amely a szkzkbl ll karakterlncok helybe a
minimlis szm tab karaktert s szkzt rja gy, hogy a tvolsg ne vltozzon! Hasznljuk
ugyanazokat a tab stop-okat, mint a detab-nl!
1.21.
Gyakorlat. Irjunk olyan programot, amely a sor n-edik pozcija eltt elfordul utols, nem
szkz karakter utn sszehajtjaa hossz bemeneti sorokat (n paramter)! Gyzdjnk meg
rla, hogy a program tnyleg rtelmesen mkdik nagyon hossz sorok esetn, de akkor is, ha
a megadott pozci eltt egyltaln nem szerepel szkz vagy tab!
1.22.
Gyakorlat. Irjunk olyan programot, amely egy C programbl az sszes megjegyzst eltnteti!
Ne felejtkezznk meg az idzjelezett karakterlncok s karakterllandk helyes kezelsrl!
1.23.
Gyakorlat. Irjunk olyan programot, amely a C programban megtallja az olyan alapvet
szintaktikai hibkat, mint a nem azonos szm nyit s zr kerek, szgletes, ill. kapcsos zrjelek!
Ne felejtkezznk meg az aposztrfokrl, idzjelekrl, valamint a megjegyzsekrl sem ! (Ezt a
programot teljes ltalnossgban nehz elkszteni.)
_
2.

fejezet: Tpusok, opertorok s kifejezsek

A programok alapvet adatobjektumai a vltozk s az llandk. A deklarcik felsoroljk a hasznlni


kvnt vltozkat, kzlik a tpusukat, valamint az esetleges kezdeti rtkket. Az opertorok azt
hatrozzk meg, hogy mit kell tenni a vltozkkal. A kifejezsek a vltozkbl s llandkbl j
rtkeket hoznak ltre. Fejezetnkben ezekkel foglalkozunk.
2.1.
Vltoznevek
Br eddig errl nem beszltnk, a vltozk s szimbolikus llandk neveire nzve vannak bizonyos
megktsek. A nevek betkbl s szmjegyekbl llnak: az els karakter bet kell, hogy legyen. Az
alhzs karakter (_) betnek szmt: ezzel javthatjuk a hossz vltoznevek olvashatsgt. A nagy-

53

Forrs: http://www.doksi.hu

s a kisbet klnbznek szmt; a hagyomnyos C programozsi gyakorlat szerint a vltoznevek


kisbetsek, a szimbolikus llandk csupa nagybetbl llnak.
A bels nevekben csupn az els nyolc karakter rtkes, br ennl hoszszabb nevek is hasznlhatk.
Kls nevek esetn, gy fggvnyneveknl s kls vltozknl ez a szm nyolcnl kevesebb is lehet,
mivel a kls neveket klnfle assemblerek s tltprogramok (loaderek) is hasznljk. Ennek
rszleteit az A fggelk ismerteti. Ezenkvl az olyan kulcsszavak, mint if, else, int, float stb. fenntartott
szavak; vltoznvknt nem hasznlhatk. (Kisbetseknek kell lennik.)
Termszetesen sszer olyan vltozneveket vlasztani, amelyek jelentenek valamit, kapcsoldnak a
vltoz funkcijhoz, s tipogrfiailag nem zavark.
2.2.

Adattpusok s mretek A C-ben csak nhny alapvet adattpus van:


char
egyetlen byte, amely az rvnyes karakterkszlet
egy elemt tartalmazhatja.
int
egsz szm, amely tipikusan a befogad gpre
jellemz egsz szm brzolsi mretet tkrzi.
float
egyszeres pontossg lebegpontos szm.
double ktszeres pontossg lebegpontos szm.
Ezen kvl van nhny minst szimblum, amely az int mennyisgekre alkalmazhat: short, long,
valamint unsigned. short (rvid), ill. long (hossz) klnbz mret egsz szmot jell. Az unsigned
(eljel nlkli) szmokra a modulo 2n aritmetika szablyai vonatkoznak, ahol n az int tpust brzol
bit-ek szma; az unsigned szmok mindig pozitvak. A minstk deklarcijnak alakja:
short int x; long int y; unsigned int z;
Ilyen esetekben az int sz elhagyhat, s el is szoks hagyni. Ezeknek az objektumoknak a pontossga
a rendelkezsre ll gptl fgg; a kvetkez tblzat nhny - bitekben megadott - jellemz
rtketmutat.
DEC PDP-11
ASCII
char
8
int
16
short
16
long
32
float
32
double 64

Honeywell6000
ASCII
8
36
36
36
36
72

IBM 370
EBCDIC
8
8
32
32
16
16
32
32
32
32
64
64

Interdata 8/32
ASCII

A cl az, hogy ahol kvnatos, a short, ill. a long klnbz hosszsg egszeket hozzon ltre; int
ltalban az adott gpnek megfelel legtermszetesebb mret. Lthat, hogy minden fordt a sajt
hardverjnek megfelelen szabadon rtelmezheti a short, ill. long minstket, az azonban bizonyos,
hogy a short nem hosszabb, mint a long.
2.3.
llandk
Az int s float llandkkal mr vgeztnk, csupn azt tesszk
mg hozz, hogy a szoksos
123.456e-7
vagy a
0. 123E3 jellsmd a float szmok esetben egyarnt megengedett. Minden lebegpontos lland
double-nak szmt, ezrt az e jells a float s a double szmokra egyarnt megfelel.
A long llandk rsmdja: 123L. Azok a kznsges egsz llandk, amelyek hosszabbak annl, hogy
egy int-be belefrjenek, ugyancsak long-nak szmtanak.
Kln jellsmdja van az oktlis s a hexadecimlis llandknak:ha egy int tpus lland 0-val
(nullval) kezddik, a szm nyolcas (oktlis) szmrendszerben rtend; a vezet 0x vagy 0X pedig azt
jelenti, hogy hexadecimlis (tizenhatos szmrendszerbeli) szmrl van sz. Pldul a decimlis 31

54

Forrs: http://www.doksi.hu

ugyanannyi, mint az oktlis 037 vagy a hexadecimlis 0x1F, ill. 0X1F. A hexadecimlis s oktlis
llandkbl az utnuk rt L-lel szintn kpezhetnk long mennyisget.
A karakterlland egyetlen, aposztrfok kz rt karakter, pldul x. A karakterlland rtke a
karakternek a gp karakterkszletn belli numerikus rtke. Pldul a nulla karakter, vagyis 0 rtke
az ASCII karakterkszletben 48, az EBCDIC-ben pedig 240, mindkt rtk teljesen klnbz a 0
numerikus rtktl. Ha szmrtkek, mint 48 vagy 240 helyett 0-t runk, akkor a program fggetlenn
vlik a karakter adott rtktl. A karakterllandk ugyangy vesznek rszt a numerikus mveletekben,
mint brmilyen ms szm, br leggyakrabban ms karakterekkel val sszehasonltsra hasznljuk ket.
A konverzis szablyokkal egy ksbbi fejezet foglalkozik.
Bizonyos nemgrafikus karakterek escape szekvencik
segtsgvel brzolhatk karakterllandknt, mint pldul \n
(jsor), \t (tab), \0 (nulla), \\(fordtott trtvonal), \
(aposztrf) stb., amelyek kt karakternek ltszanak, de
valjban mindegyik csak egy karakter. Ezenkvl tetszleges,
egy byte mret bit-minta hozhat ltre a
\ddd alak segtsgvel, ahol ddd egy, kett vagy hrom oktlis szmjegy, pl.:
#define FORMFEED \014 /* ASCII lapdobs karakter*/ A \0 karakterlland a nulla rtk
karaktert jelli. 0 helyett gyakran runk \0-t, amivel valamely kifejezs karakter jellegt
hangslyozzuk.
Az lland kifejezs olyan kifejezs, amely csak llandkat tartalmaz. Az ilyen kifejezsek kirtkelse
fordtsi idben trtnik, nem pedig futsi idben, s gy egyszer llandnak felelnek meg. Pldul:
#define MAXLINE 1000
char line [MAXLINE + 1];
vagy
seconds = 60 * 60 * hours;
A karakterlnc-lland (stringkonstans) idzjelek kz zrt, nulla vagy tbb karakterbl ll sorozat,
pl.
ez itt egy karakterlnc
vagy

/* res karakterlnc*/
Az idzjelek nem rszei a karakterlncnak, csupn
karakterlncokban ugyanazok az escape szekvencik
karakterllandknl lttunk; \ az idzjel karaktert jelli.

annak hatrolsra szolglnak. A


hasznlhatk, mint amelyeket a

Gyakorlatilag a karakterlnc olyan tmb, amelynek minden eleme egy-egy karakter. A fordt
automatikusan elhelyezi a \0 nullakaraktert minden ilyen karakterlnc vgre, gy a programok
knyelmesen megtallhatjk a karakterlnc vgt. Ez a fajta brzols azt jelenti, hogy nincs tnyleges
hatra a karakterlnc hossznak, de egy adott karakterlnc hossznak megllaptshoz a programnak
vgig kell mennie az illet karakterlncon.
A szksges fizikai trhely nagysga egy trhellyel tbb, mint az idzjelek kz rt karakterek szma.
Az albbi strlen(s) fggvny az s karakterlnc hosszt adja vissza, kizrva ebbl a zr \0-t.
strlen (s)
/* s hossznak kiszmtsa*/
char s [];
{
int i;
i = 0;
while (s [i] != \0)
++i;
return (i);

55

Forrs: http://www.doksi.hu

}
Vigyzat! A karakterlland s az egyetlen karaktert tartalmaz karakterlnc kt klnbz dolog: x
nem ugyanaz, mint x. Az elbbi egyetlen karakter, amely az x betnek a gp karakterkszlete szerint
megfelel szmrtk ellltsra szolgl, az utbbi egy karakterlnc, amely egy karaktert (az x bett)
s egy \0-t tartalmaz.
2.4.
Deklarcik
Hasznlat eltt minden vltozt deklarlni kell, br bizonyos deklarcik implicit mdon,
rtelemszeren keletkeznek. A deklarci meghatroz egy tpust, amelyet az illet tpus vltoz(ka)t
megad lista kvet, mint pldul:
int lower, upper, step; char c, line [1000];
A vltozk tetszleges mdon oszthatk szt a deklarcik kztt; az elz listkat gy is rhattuk
volna:
int lower; int upper; int step; char c; char line [1000];
az utbbi forma tbb helyet ignyel, de gy pl. minden deklarcihoz vagy az azt kvet
mdostsokhoz megjegyzst fzhetnk.
A vltozk sajt deklarciikban inicializlhatk is, br ezzel kapcsolatban vannak megktsek. Ha a
nevet egy egyenlsgjel s egy lland kveti, akkor az az illet vltoz kezdeti rtknek megadst
(inicializlst) jelenti:
char backslash = \\; int i = 0;
float eps = 1.0e-5;
Kls vagy statikus vltoz esetn az inicializls csak egyszer
rtelemszeren a program vgrehajtsnak megkezdse eltt - trtnik meg.
Az explicit mdon inicializlt automatikus vltozk minden alkalommal inicializldnak, amikor az
ket tartalmaz fggvnyt egy program meghvja.
Az explicit inicializls nlkli automatikus vltozk rtke hatrozatlan.
A kls s statikus vltozk kezdeti rtke alaprtelmezs szerint nulla, de stilrisan helyesebb, ha
minden esetben megadjuk a kezdeti rtket.
Az inicializls tmjt akkor folytatjuk, amikor a tovbbi adattpusokrl lesz sz.
2.5.
Aritmetikai opertorok
Az aritmetikai opertorok a +, -, *, / s a % (modul) opertor. Van egyoperandus -, de nincs
egyoperandus +.
Az egsz tpus (integer) oszts levgja a trt rszt. Az
x % y kifejezs az x-nek y-nal trtn osztsakor keletkez maradkot jelenti, teht rtke nulla, ha x
pontosan oszthat y-nal.
Pldul egy v ltalban akkor szkv, ha az vszm 4-gyel
oszthat, de nem oszthat 100-zal. Kivtelt jelentenek a
400-zal oszthat vek, amelyek szintn szkvek. gy
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
szkv van
else
nincs szkv
A % opertor float s double mennyisgekre nem alkalmazhat. A + s - opertorok precedencija
azonos s alacsonyabb, mint a * , / s % (egymssal szintn azonos) precedencija, amely viszont
alacsonyabb, mint az egyoperandus mnusz. Az aritmetikai opertorok balrl jobbra ktnek.
(A 2. fejezet vgn kzlt tblzat sszefoglalja az sszes

56

Forrs: http://www.doksi.hu

opertor precedencijt s ktsi mdjt.) A kirtkels


sorrendje olyan asszociatv s kommutatv opertoroknl, mint a
s +, nincs meghatrozva; a fordt trendezheti az olyan zrjelezett szmtsokat, amelyek ezek
valamelyikt tartalmazzk. gy a+(b+c) azonos (a+b)+c-vel. Ennek ritkn van jelentsge, de ha
adott sorrendre van szksg, akkor explicit ideiglenes vltozkat hasznlhatunk.
A tlcsorduls s alulcsorduls esetnek kezelse az adott gptl fgg.
2.6.

Relcis s logikai opertorok

A relcis opertorok:
> >= < <= =
Ezek mindegyiknek azonos a precedencija. Eggyel alacsonyabb - s egyms kzt egyez precedencijak az egyenlsgopertorok:
== !=
A relcis opertorok precedencija alacsonyabb, mint az aritmetikaiak, gy a vrakozsnak
megfelelen i < lim - 1 ugyanaz, mint i < (lim - 1).
Mg rdekesebbek a && s || logikai sszekapcsol mveletek. A && vagy || szimblumokkal
sszekapcsolt kifejezsek kirtkelse balrl jobbra trtnik, s a kirtkels azonnal megll, amint az
eredmny igaz vagy hamis volta kiderl. Ezek a tulajdonsgok lnyegbevgak, ha jl mkd
programokat akarunk rni. Itt van pldul az 1. fejezetben rt getline sorbeolvas fggvny egyik
ciklusa:
for (i = 0; i < lim - 1 && (c = getchar()) != \n
&& c != EOF; ++i) s [i] = c;
j karakter beolvassa eltt nyilvnvalan ellenriznnk kell, hogy a beolvasand karakter trolshoz
van-e elg hely az s tmbben, gy az i < lim - 1 vizsglatot kell elsknt vgrehajtani! St, ha a felttel
nem ll fenn, jabb karaktert mr nem szabad beolvasni!
Ugyancsak nem volna szerencss, ha a c-nek az EOF-fal trtn sszehasonltsa a getchar hvsa eltt
trtnne meg_ a hvsnak meg kell elznie a c-ben tallhat karakter vizsglatt!
&& magasabb precedencij ||-nl, de mindketten alacsonyabb
precedencijak, mint a relcis s egyenlsgopertorok, gy az
olyan kifejezsek, mint
i < lim - 1 && (c = getchar()) != \n && c != EOF
kln zrjeleket nem ignyelnek. De mivel a != precedencija
magasabb, mint az rtkads, a kvnt eredmny elrse
rdekben a
(c = getchar()) != \n kifejezsben zrjelekre van szksg.
A ! egyoperandus negl opertor a nemnulla, msszval igaz operandusbl 0-t, a nulla, azaz hamis
operandusbl pedig 1-et csinl. A ! opertort ltalban olyan szerkezetekben hasznljk, mint pl.
if (! inword),
s ezzel helyettestjk az
if (inword == 0) formt. Nehz ltalnossgban megmondani, hogy melyik alak a jobb. Az elbbi
ltalban jl olvashat (ha nem sz belsejben vagyunk), bonyolultabb esetben azonban nehezen
rthet.
2.1.

Gyakorlat. Irjunk az elz, for ciklussal egyenrtk ciklust, amely a &&-et hasznlja!

2.7.

Tpuskonverzik

57

Forrs: http://www.doksi.hu

Ha egy kifejezsben klnbz tpus operandusok fordulnak el, a kifejezs kirtkelshez az


operandusokat azonos tpusakk kell alaktani. ltalban csak az rtelmes konverzik trtnnek meg
automatikusan, pldul egsz tpus mennyisgek talaktsa lebegpontoss olyan kifejezsekben,
mint f + i, ahol f float, i pedig int tpus. Az rtelmetlen kifejezsek, mint pldul a float indexknt val
hasznlata, nem megengedettek.
A char s int tpus mennyisgek aritmetikai kifejezsekben szabadon keveredhetnek: a kifejezsekben
elfordul minden char automatikusan int-t alakul t. Ez nagymrv rugalmassgot tesz lehetv
bizonyos karaktertranszformcikban. Plda erre az atoi fggvny, amely egy szmjegyekbl ll
karakterlncot a megfelel numerikus rtkk alakt t:
atoi (s)
/ * s egssz alaktsa*/
char s [];
{
int i, n;
n = 0;
for (i = 0; s [i] >= 0 && s [i] <= 9; ++i)
n = 10 * n + s [i] - 0;
return (n);
}
Amint az 1. fejezetben emltettk, az
s [i] - 0 kifejezs ellltja az s[i] -ben trolt karakter numerikus rtkt, mivel a 0, 1 stb. rtkek
folytonosan nvekv pozitv sorozatot alkotnak.
A char-bl int-t trtn talakts msik pldja az albbi lower fggvny, amely egyetlen karaktert
alakt t kisbetss, kizrlag ASCII karakterkszlet esetn. Ha a karakter nem nagybet, a lower
vltozatlanul adja vissza.
lower

/*c konvertlsa kisbetss; csak ASCII*/ int c;

{
if (c >= A && c <= Z)
return (c + a - A);
else
return ;
}
Ez a program csak az ASCII kdkszlet hasznlata esetn mkdik helyesen, mivel abban a megfelel
kis- s nagybetk tvolsga rgztett, mind a kisbets, mind a nagybets bc numerikus rtkei
folytonosan kvetik egymst - A s Z kztt csak betk vannak. Az EBCDIC karakterkszletre
(IBM 360/370) ez az utbbi tulajdonsg nem rvnyes, gy lower nem mkdne helyesen - nem csak
betket konvertlna.
A karaktereknek egsz szmokk trtn talaktsval kapcsolatban megemltjk a nyelv egy
finomsgt. A C nyelv nem hatrozza meg, hogy a char tpus vltozk eljeles vagy eljel nlkli
mennyisgek-e. Krds teht, hogy egy char mennyisg int tpusv alaktsakor ltrejhet-e negatv
egsz is? Sajnos ez az architektrtl fggen gprl gpre vltozik. Bizonyos gpeken (pldul a
PDP-11-en)
az olyan char, amelynek legbaloldalibb bitje 1,negatv egssz alakul t (eljelkiterjeszts: sign extension).Ms gpeken a char oly mdon vlik int mennyisgg, hogy a szmtgp a
sz bal oldalhoz nullkat illeszt, s gy a keletkez rtk mindig pozitv.
A C nyelv defincija garantlja, hogy a gp szabvnyos karakterkszletben tallhat egyetlen karakter
sem lesz negatv, gy ezeket a karaktereket szabadon hasznlhatjuk kifejezsekben pozitv
mennyisgekknt. Ha azonban ms, tetszleges bit-mintkat trolunk karakter tpus vltozkban, azok
egyes gpeken pozitv szmknt, msokon negatv szmknt jelenhetnek meg.
Tipikus pldja ennek, amikor EOF-nak a -1 rtket hasznljuk.
Tekintsk a
char c; c = getchar(); if (c == EOF)
...

58

Forrs: http://www.doksi.hu

programrszt! Olyan gpen, amely nem vgez eljel-kiterjesztst, c mindig pozitv, mivel char-nak
deklarltuk, EOF viszont negatv. gy a felttel sohasem teljesl. Ennek elkerlse rdekben gyeltnk
arra, hogy minden olyan vltozt int-nek s ne char-nak deklarljunk, amely a getchar fggvny ltal
visszaadott rtket tartalmaz.
Valjban persze nem csak az esetleges eljel-kiterjeszts miatt hasznlunk int-et char helyett.
Egyszeren arrl van sz, hogy a getchar fggvnynek minden lehetsges karaktert vissza kell adnia
(oly mdon, hogy az brmilyen jabb programbemenethez felhasznlhat legyen), de vissza kell adnia
az ezektl klnbz EOF rtket is! gy a getchar fggvny rtke nem jelenhet meg char-knt, hanem
azt int-knt kell trolni.
Az automatikus tpuskonvertl msik hasznos formja, hogy a
relcis kifejezsek (pl. i > j) s az &&, ill. ||
szimblumokkal sszekapcsolt logikai kifejezsek rtke
definciszeren 1 , ha a kifejezs igaz, ill. 0, ha hamis.
gy az
isdigit = c >= 0 && c <= 9; rtkads az isdigit vltoznak az 1 rtket adja, ha c szmjegy s a 0
rtket ha nem az. (Az if, while, for stb. felttelvizsglatban az igaz jelentse egyszeren: nemnulla.)
Az implicit aritmetikai konverzik mkdse teljesen
rtelemszer. ltalban, ha egy ktoperandus opertor, mint a
vagy a * operandusai klnbz tpusak, a program a mvelet elvgzse eltt az alacsonyabb
tpus vltozt magasabb tpusv alaktja t. Az eredmny a magasabb tpus. Pontosabban szlva
az aritmetikai opertorok az albbi konverzis szablyok szerint hatnak:
A char s short mennyisgek int tpusv, a float mennyisgek double tpusv alakulnak t.
Ezutn ha az egyik operandus double, a msik is double tpusv alakul t, s az eredmny is double.
Egybknt ha az egyik operandus long, a msik is long tpusv alakul t, s az eredmny is long lesz.
Egybknt ha az egyik operandus unsigned, a msik is unsigned tpusv alakul t, s az eredmny is
unsigned lesz. Egybknt az operandusoknak int tpusaknak kell lennik, s az eredmny int.
Jegyezzk meg, hogy egy kifejezsben elfordul minden float mennyisg double-l alakul t: a C-ben
minden lebegpontos mvelet ktszeres pontossg!
Az rtkads is tpuskonverzival jr: a jobb oldal rtke
talakul bal oldali tpusv, s ez lesz egyben az eredmny
tpusa is. A karakterek egssz alakulnak t - akr
eljel-kiterjesztssel, akr anlkl -, amint azt az elbbiekben
ismertettk. Az ellenttes irny mvelet, az int-bl char-ba
trtn konverzi egyrtelm - a felesleges magas helyirtk
bit-ek egyszeren elmaradnak. gy
int i; char c; i = c; c = i;
esetben c rtke nem vltozik. Ez mindig igaz, fggetlenl attl, hogy van-e eljel-kiterjeszts vagy
sem.
Ha x float s i int, akkor: x=i valamint i= x egyarnt konverzihoz vezet; a float-bl int-be trtn
konverzi a trt rsz levgst eredmnyezi. A double kerektssel alakul t float-t.
A hosszabb int-ek rvidebbekk vagy char-okk gy alakulnak t, hogy a program a felesleges magas
helyirtk bite-ket levgja.
Mivel a fggvnyargumentumok kifejezsek, a fggvnyeknek trtn argumentumtads ugyancsak
tpuskonverzikkal jr. Konkrtan a char s a short int-t vlik, a float pedig double mennyisgg.
Ezrt deklarltuk a fggvnyargumentumokat int-nek s double-nak mg akkor is, amikor a fggvnyt
char-ral s float-tal hvtuk meg.

59

Forrs: http://www.doksi.hu

Vgezetl tetszleges kifejezsben is kivlthatunk,


kiknyszerithetnk tpuskonverzit, ha n. tpusmdost (cast)
szerkezetet hasznlunk. A (tipusnv) kifejezs szerkezetben a
kifejezs az elz szablyok alkalmazsval az elrt tpusv
alakul t, gy mintha a kifejezs hozz lenne rendelve egy, a
megadott tpus vltozhoz, amelyet azutn az egsz szerkezet
helyett hasznlunk. Pldul az sqrt (gykvon) knyvtri rutin
double tpus argumentumot vr, s rtelmetlen eredmnyt ad, ha
vletlenl valami mst kap. Ha teht n egsz tpus, akkor
sqrt ((double) n) az n-et a sqrt-nek trtn tads eltt double-l konvertlja. (Jegyezzk meg, hogy a
tpusmdost szerkezet n rtkt a kvnt tpusban szolgltatja; n tnyleges tartalma azonban nem
vltozik.) A tpusmdost opertor precedencija ugyanaz, mint a tbbi egyoperandus opertor,
amint azt a fejezet vgn kzlt sszefoglal tblzat is mutatja.
2.2.
Gyakorlat. Irjuk meg a htoi(s) fggvnyt, amely egy hexadecimlis szmjegyekbl ll
karakterlncot a neki megfelel egsz rtkk alakt t! A megengedett szmjegyek; 0...9, a...f s
A...F.
2.8.
Inkrementl s dekrementl opertorok
A C nyelv tartalmaz kt szokatlan opertort, amelyekkel vltozk inkrementlhatk s
dekrementlhatk. A ++ inkrementl opertor operandushoz 1 -et ad hozz, adekrementl
opertor pedig 1 -et von le belle. A ++-t gyakran hasznljuk vltozk inkrementlsra, pldul:
if (c == \n)
++nl;
A szokatlansg abban rejlik, hogy a ++ s aegyarnt hasznlhat prefix opertorknt (a vltoz eltt,
mint a ++n esetben) vagy postfix opertorknt (a vltoz mg rva: n++).
Az eredmny mindkt esetben n inkrementlsa. De mg a ++n
kifejezs n-et az eltt nveli, hogy felhasznln annak rtkt,
n++ csak azt kveten inkrementl. Eszerint olyan esetekben
amikor nemcsak az inkrementl tulajdonsgot, hanem n rtkt is
felhasznljuk, ++n s n++ klnbznek egymstl. Ha n rtke 5,
akkor
x = n++;
az x-et 5-re lltja, de
x = ++n;
x-et 6-ra lltja. n mindkt esetben 6 lesz. Az inkrementl s
dekrementl opertorok csak vltozkra alkalmazhatk; az olyan
kifejezs, mint
x = (i + j)++ nem megengedett !
Ha az rtkre nincs szksg, csak az inkrementl hatsra, pl.
if (c == \n) nl++;
esetben, a prefix vagy a postfix opertort tetszs szerint vlaszthatjuk meg. Vannak azonban olyan
feladatok, amikor specilisan az egyikre vagy a msikra van szksg. Tekintsk pldul a squeeze(s, c)
fggvnyt, amely az sszes elfordul c karaktert trli az s karakterlncbl:

60

Forrs: http://www.doksi.hu

squeeze (s, c) /*Valamennyi c karakter trlse s-bl*/ char s []; int c;


{
int i, j;
for (i = j = 0; s [i] != \0; i++)
if (s [i] != c)
s [j++] = s [i]; s [j] = \0;
}
Minden alkalommal, amikor a program az s karakterlncban
c-vel nem azonos karaktert tall, bemsolja azt a pillanatnyi j
pozciba, s csak ezutn inkrementlja j-t, hogy fogadhassa a
kvetkez karaktert. Hatsa pontosan azonos az
if (s [i] != c) {
s [j] = s [i];
j++;
}
alakval. Hasonl plda fordult el az 1. fejezetben ltott
getline fggvnyben, ahol az
if (c == \n) {
s [i] = c;
++i;
}
sorokat az ennl tmrebb
if (c == \n) s [i++] = c;
alakkal helyettesthetjk.
Harmadik pldnk az strcat(s, t) fggvny, amely a t karakterlncot az s karakterlnc vghez illeszti
(konkatenlja). strcat felttelezi, hogy s-ben elg hely van ahhoz, hogy ott az sszeillesztett karakterlnc
elfrjen.
strcat (s,t)
/*t illesztse s vghez*/
char s[], t []; / * s-nek elg nagynak kell lennie * /
{
int i, j;
i = j = 0;
while (s[i] != \0)
/*Keresi s vgt*/
while (s [i] = \ ) /
i++;
while ((s [i++] = t[j++]) != \0)
/*t tmsolsa*/
;
}

eresi s vg /

Mikzben a program az egyes karaktereket t-bl s-be msolja, a ++ postfix opertor mind i, mind pedig
j rtkt nveli, hogy azok a kvetkez ciklusban a megfelel pozcira mutassanak.
2.3.
Gyakorlat. rjuk meg az squeeze(s1 , s2) egy msik vltozatt, amely s1-bl minden olyan
karaktert trl, amely megegyezik brmelyik s2 beli karakterrel!
2.4.
Gyakorlat. rjuk meg az any(s1, s2) fggvnyt, amely megadja az s1 karakterlncnak azt a
legels pozcijt, ahol brmelyik, s2 karakterlncbeli karakter elfordul, s -1 rtket szolgltat, ha
s1 egyetlen s2-beli karaktert sem tartalmaz!
2.9.
Bitenknti logikai opertorok
A C nyelvben tbb bitmanipulcis opertor van; ezek a float s double tpus vltozkra nem
alkalmazhatk.
&

bitenknti S,

61

Forrs: http://www.doksi.hu

|
bitenknti megenged (inkluzv) VAGY,
^
bitenknti kizr (exkluzv) VAGY,
<<
bitlptets (shift) balra,
>>
bitlptets (shift) jobbra,
~
egyes komplemens (egyoperandus).
A bitenknti S opertort gyakran hasznljuk valamely bithalmaz maszkolsra. Pldul:
c = n & 0177; mindent nullz, az n kis helyirtk bitjeinek kivtelvel. A | bitenknti VAGY
opertorral lehet biteket 1 -re lltani.
x = x | MASK; ugyanazokat a biteket lltja 1-be x-ben, mint amelyek 1-be vannak lltva MASK-ban.
Gondosan meg kell klnbztetnnk az & s | bitenknti opertorokat az && s || logikai mveletektl,
amelyek egy igazsgrtk balrl jobbra trtn kirtkelst rjk el. Ha pldul x rtke 1 s y rtke
2, akkor x & y rtke 0, x&&y rtke pedig 1 . (Mirt?)
A << s >> lptet (shift) opertorok bal oldali operandusukon annyi bitlptetst hajtanak vgre, ahny
bitpozcit a jobb oldali operandusuk elr. Igy x <<2 az x-et kt pozcival balra lpteti, a megrlt
biteket pedig 0-val tlti fel; ez 4-gyel val szorzssal egyenrtk. unsigned mennyisg jobbra
lptetse esetn a felszabadul bitekre nullk kerlnek. Eljeles mennyisg jobbra lptetse esetn
bizonyos gpeken, gy a PDP-11-en a felszabadul bitekre az eljel kerl (aritmetikai lptets), ms
gpeken 0 bitek (logikai lptets).
A ~ binris opertor egsz tpus mennyisg 1 -es komplemenst
kpezi, vagyis minden 1 -es bitet 0-ra llt s viszont. Ezt az
opertort leggyakrabban olyan kifejezsekben hasznljuk, mint
x & ~077 amely x utols 6 bitjt 0-ra maszkolja. Vegyk szre, hogy x & ~077 fggetlen a
szhosszsgtl, s gy elnysebb, mint pldul x & 0177700, amely felttelezi, hogy x 16 bites
mennyisg. A gpfggetlen alak nem nveli a futsi idt, mivel ~077 lland kifejezs, s mint ilyen,
fordtsi idben rtkeldik ki.
Kvetkez programpldnkban nhny bitopertor mkdst szemlltetjk. A getbits(x, p, n)
fggvny x-nek a p-edik pozcin kezdd n-bites mezjt adja vissza (jobbra igaztva). Felttelezzk,
hogy a 0 bitpozci a jobb szlen van s hogy n s p rtelmes pozitv rtkek. Pldul getbits
(x,4,3) a 4, 3 s 2 pozcin lev hrom bitet szolgltatja, jobbra igaztva.
getbits (x, p, n)

/*n bit a p pozcitl kezdve*/ unsigned x, p, n;

{
return ((x >> (p + 1 - n)) & ~(~0 << n));
}
x >> (p + 1 - n) a kvnt mezt a sz jobb szlre mozgatja. Az x argumentumot unsigned
mennyisgnek deklarlva biztostjuk, hogy a jobbra lptetskor a felszabadul bitek ne eljelbitekkel,
hanem nullkkal tltdjenek fel, fggetlenl attl, hogy a program ppen milyen gpen fut. ~0 csupa 1
bitet jelent, amelyet az ~0 << n utasts segtsgvel n bitpozcival balra lptetve a jobb oldali n biten
csupa nullkbl ll, a tbbi pozcin egyesekbl ll maszk jn ltre. Ezt a ~ opertorral
komplementlva olyan maszk keletkezik, amelyben a jobb oldali biteken llnak egyesek.
2.5.
Gyakorlat. Mdostsuk a getbits fggvnyt gy, hogy a bitpozcik sorszma balrl jobbra
njn!
2.6.
Gyakorlat. Irjunk olyan wordlength() fggvnyt, amely kiszmtja a befogad gp
szhosszsgt, azaz meghatrozza, hogy egy int mennyisgben hny bit van! A fggvny legyen
gpfggetlen, vagyis a forrskd minden gpen mkdjn!
2.7.
Gyakorlat. Irjunk olyan rightrot(n, b) fggvnyt, amely b szm bitpozcival jobbra trtn
bitrotcit vgez az n egsz tpus mennyisgen!
2.8.
Gyakorlat. Irjunk olyan invert(x, p, n) fggvnyt, amely az x-ben a p pozcitl kezdve n bitet
invertl(vagyis az 1-eseket 0-ra, a 0-kat 1-esekre cserli fel), mikzben a tbbi bit vltozatlan
marad!
2.10.
rtkad opertorok s kifejezsek
Az olyan kifejezsek, mint

62

Forrs: http://www.doksi.hu

i=i+2
amelyekben a bal oldal a jobb oldalon megismtldik, a +=
rtkad opertor segtsgvel az
i += 2 tmrtett alakban is rhatk.
A C-ben a legtbb ktoperandus opertornak megvan az op=
alak rtkad megfelelje, ahol op a
+ - * / % << >> & |
szimblumok egyike. Ha e1 s e2 kifejezs, akkor
e1 op= e2 jelentse:
e1 = (e1) op (e2).
Az egyetlen eltrs, hogy az elbbi esetben a gp e1-et csak egyszer szmtja ki. gyeljnk az e2 krli
zrjelekre:
x *= y + 1
jelentse
x = x * (y + 1)
nem pedig
x=x*y+1
Az albbi pldban a bitcount fggvny megszmllja az egsz tpus argumentumban tallhat 1 -es
bitek szmt.
bitcount (n) /*1-es bitek megszmllsa n-ben*/ unsigned n;
{
int b;
for (b = 0; n != 0; n >>= 1)
if (n & 01)
b++; return (b);
}
Tmrsgk mellett az rtkad opertoroknak elnye az is, hogy jobban megfelelnek az emberi
gondolkodsmdnak. Azt mondjuk:
adj 2-t i-hez vagy nveld i-t 2-vel (teht: i += 2), nem
pedig: vedd i-t, adj hozz 2-t majd tedd vissza az eredmnyt
i-be (i = i + 2). Bonyolult kifejezsekben mint
yyval [yypv [p3 + p4] + yypv [p1 + p2]] += 2 az rtkad_opertor rthetbb teszi a kdot, mivel az
olvasnak nem kell krlmnyesen ellenriznie, hogy kt hossz kifejezs tnyleg megegyezik-e; ha
pedig nem egyezik meg, nem kell azon tndnie, hogy mirt nem. Ezenkvl az rtkad opertor mg
a fordtnak is segthet a hatkonyabb kd ellltsban. Korbban mr kihasznltuk azt a tnyt, hogy
az rtkad utastsnak rtke van s kifejezsekben is elfordulhat; a legkznsgesebb plda:
while ((c = getchar()) != EOF)
...
Ugyangy, a tbbi rtkad opertort hasznl rtkadsok is szerepelhetnek kifejezsekben, br ezek
ritkbban fordulnak el.
Az rtkad kifejezs tpusa megegyezik bal oldali
operandusnak tpusval.
2.9.
Gyakorlat. 2-es komplemens aritmetikban x & (x-1 ) trli x legjobboldalibb 1-es bitjt.
(Mirt?) Kihasznlva ezt a megfigyelst, rjuk meg a bitcount egy gyorsabb vltozatt!

63

Forrs: http://www.doksi.hu

2.11.
Feltteles kifejezsek
Az
if (a > b)
z = a;
else
z = b;
feltteles utasts eredmnyeknt z a s b kzl a nagyobbik rtkt veszi fel.
A C-ben a hromoperandus ?: opertor segtsgvel az ilyen
szerkezeteket sokkal rvidebben lerhatjuk. Legyen e1, e2, e3
hrom kifejezs. Az
e1 ? e2 : e3 feltteles kifejezsben a gp elszr e1-et rtkeli ki. Ha rtke nem nulla (igaz), akkor e2,
egybknt e3 kirtkelse kvetkezik, s a kapott rtk lesz a feltteles kifejezs rtke. A program e2
s e3 kzl teht csak az egyiket rtkeli ki. gy z-be a s b kzl a nagyobbat az albbi feltteles
kifejezssel tlthetjk:
z = (a > b) ? a : b; _/* z = max(a,b) */
Megjegyezzk, hogy a feltteles kifejezs is igazi kifejezs, s
ugyangy hasznlhat, mint brmilyen ms kifejezs. Ha e2 s e3
klnbz tpus, az eredmny tpust a fejezetnkben korbban
ismertetett konverzis szablyok hatrozzk meg. Ha pldul f
float s n int, akkor az
(n > 0) ? f : n kifejezs double lesz, fggetlenl attl, hogy n pozitv-e vagy sem.
A feltteles kifejezsben az els kifejezst nem ktelez zrjelbe tenni, mivel ?: precedencija igen
alacsony (pontosan az rtkads fltti). Zrjelezssel azonban rthetbb tehetjk a kifejezs
felttelrszt.
A feltteles kifejezsek hasznlata gyakran tmr s vilgos kdot eredmnyez. Az albbi ciklus
pldul soronknt tzesvel kinyomtatja egy tmb N elemt oly mdon, hogy az egyes oszlopokat egyegy szkz vlasztja el, s minden sort (az utolst is belertve) pontosan egy jsor karakter zr le.
for (i = 0; i < N; i++)
printf (%6d %c, a[i],
(i % 10_== 9 || i == n - 1)_? \n : );
Minden tizedik s az N-edik elem utn egy jsor karaktert ad ki a program. Minden ms elemet egy-egy
szkz kvet. Gyakorlskppen prblja meg az olvas ugyanezt feltteles kifejezs hasznlata nlkl
lerni!
2.10.
Gyakorlat. rjuk t a lower fggvnyt, amely a nagybets karaktereket kisbetsekk
konvertlja! Az if-else helyett hasznljunk feltteles kifejezst!
2.12.
Precedencia; a kirtkels sorrendje
A kvetkez tblzat sszefoglalja valamennyi opertor precedencia- s ktsi szablyait, azokt is,
amelyekrl idig nem volt sz. Az egy sorba rt opertorok precedencija azonos; a tblzatban
lefel haladva a precedencia cskken, gy pldul * , / s % precedencija azonos s magasabb + s
- precedencijnl.
Opertor
() []
! ~ ++ -- - (tipus) * & . -> sizeof
*/%
+<< >>
< <= > >=
== !=

Asszociativits
balrl jobbra
jobbrl balra
balrl jobbra
balrl jobbra
balrl jobbra
balrl jobbra
balrl jobbra

64

Forrs: http://www.doksi.hu

&
^
|
&&
||
?:
= += -= stb.
, (3. fejezet)

balrl jobbra
balrl jobbra
balrl jobbra
balrl jobbra
balrl jobbra
jobbrl balra
jobbrl balra
balrl jobbra

A -> s . opertorok segtsgvel struktrk elemeihez frhetnk hozz, ezekkel, valamint a sizeof
(objektum mrete) opertorral a 6. fejezetben foglalkozunk. A * (indirekci) s az & (valaminek a
cme) opertorral az 5. fejezetben tallkozunk. gyeljnk arra, hogy az &, ^ s | bitenknti logikai
opertorok precedencija kisebb, mint az == s != precedencija.
Emiatt az olyan bitvizsgl kifejezsek, mint
if ((x & MASK) == 0)
...
a zrjelezs nlkl nem mkdnek helyesen.
Mint emltettk, az asszociatv s kommutatv opertorokkal (*, +, &, ^, |) felptett kifejezseket a
fordtprogram trendezheti, mg akkor is, ha zrjele(ket)t tartalmaznak. Az esetek tbbsgben ennek
nincs jelentsge; azokban az esetekben, ahol mgis van, explicit ideiglenes vltozk hasznlatval
gondoskodhatunk a kvnt kirtkelsi sorrendrl.
A legtbb nyelvhez hasonlan a C sem hatrozza meg egy-egy
opertor operandusainak kirtkelsi sorrendjt. Az
x = f () + g (); utastsban pl. nem tudjuk, hogy f-et g eltt vagy g utn szmtja ki a gp. gy, ha akr f,
akr g olyan kls vltozt mdost, amelytl a msik fgg, x rtke fgghet a mveletek
vgrehajtsnak sorrendjtl. Ha adott sorrendre van szksgnk, ezt megint csak gy biztosthatjuk,
hogy a rszeredmnyeket ideiglenes vltozkban troljuk.
Ugyancsak hatrozatlan a fggvnyargumentumok kirtkelsi
sorrendje, gy a
printf (%d %d \n, ++n, power (2,n));
/* ROSSZ */ utasts klnbz gpeken klnbz
eredmnyeket adhat (s ad is) attl fggen, hogy a gp n-et a power hvsa eltt vagy utn
inkrementlja. A helyes megolds termszetesen:
++n; printf (%d %d \n, n, power(2,n));
A fggvnyhvsok, egymsba skatulyzott rtkad utastsok, az
inkrementl s dekrementl opertorok mellkhatsokat
okozhatnak. Ez azt jelenti, hogy egy kifejezs kiszmtsnak nem szndkos - mellktermkeknt megvltozhat egy vltoz
rtke. A mellkhatsokkal jr kifejezsekben sok fgghet
attl, milyen sorrendben trolja a gp a kifejezsben szerepl
vltozkat. Szerencstlen, de elg gyakori esetet pldz az
a [i] = i++; utasts. Krds, hogy az index i rgi vagy j rtkvel azonos. A vlasz klnbz lehet,
aszerint, hogy a fordt hogyan rtelmezi, kezeli ezt az utastst. Mindig a fordt dnti el teht, lesz-e
mellkhats (mdosul-e a vltozk rtke) vagy sem, hiszen az optimlis sorrend ersen fgg a gp
architektrjtl.
A tanulsg: egy nyelven sem szabad olyan programot rni, amelynek eredmnye fgg a konkrt
kirtkelsi sorrendtl! Termszetesen j, ha tudjuk, mire vigyzzunk, ugyanakkor, ha nem tudjuk,
hogy valami hogyan mkdik klnbz gpeken, ez a tudatlansg meg is vdhet bennnket. (A lint
nev C helyessgvizsgl program a legtbb esetben felfedezi a kirtkelsi sorrendtl val fggst.)

65

Forrs: http://www.doksi.hu

_
3.

fejezet: Vezrlsi szerkezetek

A nyelv vezrlstad utastsai a szmtsok vgrehajtsnak sorrendjt hatrozzk meg. A korbbi


pldkban mr tallkoztunk a C leggyakoribb vezrlstad utastsaival. Ebben a fejezetben teljess
tesszk a kszletet s rszletesen ismertetjk a mr korbban emltett utastsokat is.
3.1.
Utastsok s blokkok
A kifejezsek, pl. x = 0, i++ vagy printf(. . .) utastss vlnak, ha pontosvessz kveti ket:
x = 0; i++; printf (. . .);
A C-ben a pontosvessz utastslezr jel (termintor) s nem elvlaszt szimblum, mint az ALGOLszer nyelvekben. A { s } kapcsos zrjelek felhasznlsval deklarcikat s utastsokat egyetlen
sszetett utastsba vagy blokkba foghatunk ssze. Ez szintaktikailag egyetlen utastssal egyenrtk.
Nyilvnval pldi ennek a fggvnyek utastsait hatrol kapcsos zrjelek, vagy azok a zrjelek,
amelyek egy if, else, while vagy for szimblumot kvet utastssort vesznek krl. (Vltozk brmely
blokkon bell deklarlhatk, errl a 4. fejezetben lesz sz.) A blokkot lezr jobb oldali kapcsos
zrjel utn soha nincs pontosvessz.
3.2.
Az if-else utasts
Az if-else utastssal dntst, vlasztst runk le. Az utasts szintaxisa formlisan :
if (kifejezs)
1.utasts
else
2.utasts
ahol az else rsz nem ktelez. A gp a kifejezs kirtkelse utn, ha annak rtke igaz (vagyis
nemnulla), az 1. utastst, ha rtke hamis (nulla), s ha van else rsz, akkor a 2. utastst hajtja vgre.
Mivel az if egyszeren a kifejezs numerikus rtkt
vizsglja, lehetsg van bizonyos programozsi rvidtsre. A
legnyilvnvalbb, ha
if (kifejezs)
t runk
if (kifejezs != 0) helyett. Ez nha termszetes s vilgos, mskor viszont nehezen megfejthet.
Minthogy az if-else konstrukci else rsze elhagyhat, sokszor
nem egyrtelm, hogy az egymsba skatulyzott if utastsok
melyikhez tartozik else g. A ktrtelmsget a C ms
nyelvekhez hasonlan azzal oldja fel, hogy az else a hozz
legkzelebbi else nlkli if-hez kapcsoldik. Pldul az
if (n > 0) if (a > b)
z = a;
else
z = b; esetben az else a bels if hez tartozik, amint azt a sorbetolssal szemlltettk. Ha nem ezt
akarjuk, zrjelekkel rhetjk el a helyes sszerendelst:
if (n > 0) {
if (a > b)
z = a;
}
else
z = b;
A ktrtelmsg klnsen veszlyes az olyan esetekben, mint:

66

Forrs: http://www.doksi.hu

if (n > 0)
for (i = 0; i < n; i++)
if (s[i] > 0 ) {
printf (. . .);
return (i);
}
else /*ROSSZ*/
printf(hiba, n rtke nulla \n);
A sorbetols ugyan flrerthetetlenl mutatja, hogy mit akarunk, de ezt a szmtgp nem rzkeli, s
az else-t a bels if-hez kapcsolja. Az ilyen tpus hibkat igen nehz felfedezni.
Egybknt vegyk szre, hogy a z = a utn pontosvessz van az
if (a > b )
; z = a;
else
z = b;
programrszben. Ennek az az oka, hogy nyelvtanilag egy utasts kveti az if-et, mrpedig az olyan
kifejezs jelleg utastsokat is, mint z = a mindig pontosvessz zrja le.
3.3.
Az else-if utasts
Az
if (kifejezs)
utasts
else if (kifejezs)
utasts else if (kifejezs)
utasts
else
utasts szerkezet olyan gyakran fordul el, hogy megr nmi kln fejtegetst.
Tbbszrs elgazst (dntst) ltalban ilyen if-sorozattal valstunk meg. A gp sorban kirtkeli a
kifejezseket. Ha valamelyik kifejezs igaz, akkor a hozz tartoz utastst a gp vgrehajtja, s ezzel
az egsz lnc lezrul. Az egyes utastsok helyn egyetlen utasts vagy kapcsos zrjelek kz zrt
utastscsoport egyarnt llhat.
Az utols else a fentiek kzl egyik sem (alaprtelmezs
szerinti) esetet kezeli. Ha a vezrls ide kerl, egyetlen
korbbi felttel sem teljeslt. Nha ilyenkor semmit sem kell
csinlni, gy a zr
else
utasts
elhagyhat, vagy - valamilyen tiltott felttel figyelsvel - hibaellenrzsre hasznlhat.
Kvetkez pldnkban egy hromutas dntst lthat az olvas. Olyan binris keres fggvnyt
mutatunk be, amely egy rendezett v tmbben egy bizonyos x rtket keres. v elemeinek nvekv
sorrendben kell kvetnik egymst. Ha x elfordul v-ben, akkor a fggvny x v-beli (0 s n-1 kztti)
sorszmt szolgltatja, ellenkez esetben rtke -1 lesz:
binary (x, v, n)

/*x keresse v[0] . . .

v[n - 1]-ben*/ int x, v[], n;


{
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high) {
mid = (low + high) / 2;
if (x < v[mid])

67

Forrs: http://www.doksi.hu

high = mid - 1; else if (x > v[mid])


low = mid + 1;
else / *Megtallta*/
return (mid);
}
return (-1);
}
Minden lpsben meg kell vizsglni, hogy x kisebb, mint a v[mid] kzps elem, nagyobb nla vagy
egyenl vele, ami egszen termszetes mdon rhat le else-if szerkezettel.
3.4.
A switch utasts
A switch utasts a tbbirny programelgaztats egyik eszkze. Megvizsglja, hogy valamely
kifejezs rtke megegyezik-e tbb lland rtk valamelyikvel, s ennek megfelel ugrst hajt
vgre. Az 1. fejezetben olyan programot lttunk, amellyel az egyes szmjegyek, res s egyb
karakterek elfordulsait szmlltuk meg. Ugyanazt a programot most az if ... else if... ...else
szerkezet helyett a switch utastssal rtuk meg:
main () /*Szmjegyek, res s egyb karakterek
szmllsa*/
{
int c, i, nwhite, nother, ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; i++)
ndigit [i] = 0;
while ((c = getchar()) != EOF)
switch {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: ndigit [c
- 0] ++; break; case : case \n: case \t: nwhite++; break; default : nother++; break;
}
printf (szmjegyek=);
for (i = 0; i < 10; i++)
printf (%d, ndigit[i]);
printf (\n res hely = %d, egyb = %d \n,
nwhite, nother);
}
A switch kirtkeli a zrjelek kztti kifejezst (ebben a programban ez a c karakter), s
sszehasonltja az sszes case (eset) rtkvel. Minden case-t egsz rtkkel, karakterllandval vagy
lland kifejezssel meg kell cimkzni. Ha valamelyik case azonos a kifejezs rtkvel, a vgrehajts
ennl a case-nl kezddik. A default cimkj case-re akkor kerl a vezrls, ha a tbbi case egyike sem
teljesl. A default elhagyhat : ha nem szerepel s a case-ek egyike sem teljesl, semmi nem trtnik. A
case-ek s a default tetszleges sorrendben kvethetik egymst. A case utastsok cmkinek
klnbznik kell egymstl.
A break utasts hatsra a vezrls azonnal kilp a switch-bl. Mivel a case-ek cmkeknt mkdnek,
miutn valamelyik case-hez tartoz programrsz vgrehajtsa befejezdtt, a vezrls a kvetkez
case-re kerl, hacsak explicit mdon nem intzkednk a kilpsrl. A switch-bl val kilps
legkznsgesebb mdja a break s a return. Ugyancsak break utastssal lehet kilpni a while, for s
do ciklusokbl, errl e fejezet ksbbi rszben lesz sz.
Az egymst kvet case-ekbe val belps nem egyrtelmen elnys. A dolog pozitv oldala, hogy
mint pldnkban a szkznl, az jsor s a tab karakternl is lttuk, egyetlen tevkenysg szmra tbb
esetet enged meg. De ebbl az is kvetkezik, hogy ltalban minden case-t break-nek kell lezrnia,
nehogy a vezrls a kvetkez case-re lpjen. A case-ken trtn lpkeds azrt is veszlyes, mert a
vezrls szteshet, ha a programot mdostjuk. Azokat az eseteket kivve, amikor ugyanahhoz a
szmtshoz tbb cmke tartozik, a case-ek kztti tmenetek hasznlatval clszer takarkoskodni.
A j klalak rdekben mg akkor is helyezznk el break-et az utols eset utn (az elz pldnkban a

68

Forrs: http://www.doksi.hu

default utn), ha az logikailag szksgtelennek ltszik. Ha valamikor ksbb a szekvencia vghez


jabb case-t illesztnk, ez a fajta defenzv programozsi taktika fog megmenteni minket.
3.1. Gyakorlat. Irjuk meg azt az expand(s, t) fggvnyt, amely - mikzben az s karakterlncot a t
karakterlncba msolja - a lthatatlan karaktereket (pl.jsor s a tab) lthat escape
szekvencikk (pl.\n s\t) alaktja t! Hasznljunk switch utastst!
3.5.
A while s a for utasts
Mr tallkoztunk a while s for ciklusokkal. A
while (kifejezs)
utasts
szerkezetben a gp kirtkeli a kifejezst. Ha rtke nem nulla, akkor vgrehajtja az utastst s ismt
kirtkeli a kifejezst. Ez a ciklus mindaddig folytatdik, amg a kifejezs 0 nem lesz, amikor is az
utasts utn a vgrehajts vgetr.
A
for (kif1; kif2; kif3)
utasts
alak for utasts egyenrtk a
kif1;
while (kif2) {
utasts
kif3;
}
alakkal. Nyelvtanilag a for mindhrom sszetevje kifejezs.
Tbbnyire kif1 s kif3 rtkads vagy fggvnyhvs, kif2 pedig
relcis kifejezs. A hrom kifejezs brmelyike elhagyhat, de
a pontosvesszknek meg kell maradniuk. Ha kif1 vagy kif3 marad
el, akkor a ; egyszeren elmarad a kifejtsbl. Ha a kif2
vizsglat nem szerepel, akkor llandan igaznak tekintjk, gy
for( ;;) {
...
}
vgtelen ciklus, amelybl valsznleg ms mdon kell kiugrani (pl. return vagy break rvn).
A while s a for kztt lnyegben zlsnk szerint
vlaszthatunk. Pldul a
while ((c = getchar()) == || c == \n || c == \t)
;
/*tugorja a lthatatlan karaktereket*/
programrszben nincs inicializls, sem jrainicializls, gy a while hasznlata a lehet
legtermszetesebbnek tnik.
A for nyilvnvalan elnysebb olyankor, amikor egyszer
inicializls s jrainicializls fordul el, mivel a ciklust
vezrl utastsok egyms kzelben, a ciklus tetejn jelennek
meg. Ez a legszembetnbb a
for (i = 0; i < N; i++) esetben, amely egy tmb els N eleme feldolgozsnak C nyelv
megfogalmazsa, a FORTRAN s PL/1 DO ciklusnak megfelelje. Az analgia azonban nem teljes,
mivel a for hatrai a cikluson bellrl vltoztathatk, s az i vezrlvltoz megtartja rtkt, amikor
valamilyen oknl fogva a ciklus vgetr. Minthogy a for sszetevi tetszleges kifejezsek, a for ciklus

69

Forrs: http://www.doksi.hu

nem korltozdik aritmetikai lptetsekre. Stilris szempontbl mgis helyesebb, ha a for-ban nem
helyeznk el tle fggetlen szmtsokat; a for-t inkbb ciklusvezrl mveletekre tartsuk fenn.
Nagyobb pldaknt bemutatjuk az atoi fggvny msik vltozatt. Az atoi fggvny egy
karakterlncot a neki megfelel numerikus rtkk alakt t. Az itt kvetkez vltozat a korbbinl
ltalnosabb: kezeli az esetleges vezet szkzket s az esetleges - vagy + eljelet. (A 4. fejezet
tartalmazza az atof fggvnyt, amely ugyanezt a konverzit lebegpontos szmokra vgzi el. )
A program alapstruktrja a bemenet alakjt tkrzi:
ugord t az res kzket, ha vannak
olvasd be az eljelet, ha van
olvasd be az egsz rszt s konvertld
Minden lps elvgzi a maga feladatt, s a dolgokat tiszta llapotban adja t a kvetkez lpsnek. Az
egsz folyamat az els olyan karakter elfordulsakor r vget, amely nem lehet rsze szmnak.
atoi (s)
/*s konvertlsa egssz*/
char s [];
{
int i, n, sign;
for (i = 0; s [i] == || s [i] == \n
|| s [i] == \t; i++)
; /*Ugord t az res helyet*/
sign = 1;
if (s [i] == + || s [i] == -) /*Eljelvizsglat*/ sign = (s [i++] == +) ? 1 : -1; for (n = 0; s [i] >=
0 && s [i] <= 9; i++) n = 10 * n + s [i] - 0; return (sign * n);
}
A ciklusvezrls tmritsnek elnyei mg jobban kitkznek, ha tbb, egymsba skatulyzott hurok
van. A kvetkez fggvny az UNIX Shell sort funkcijt valsitja meg:feladata egy egsz tipus tmb
rendezse. A Shell sort alapgondolata, hogy kezdetben inkbb az egymstol tvoli elemek kerljenek
sszehasonltsra, nem pedig szomszdosak, mint az egyszer cserlgets rendezprogramokban.
Ezltal a nagyfok kezdeti rendezetlensg vrhatan gyorsan eltnik, gy a ksbbi lpseknek
kevesebb dolga akad. Az sszehasonltott elemek kztti tvolsg fokozatosan 1-re cskken, amikor is
a rendezs szomszdcserlgetsi mdszerr alakul t.
shell (v,n)

/*v[0]...v[n-1]-et nvekv sorba rendezi*/ int v[], n;

{
int gap, i , j, temp;
for (gap = n / 2; gap > 0; gap /= 2)
for (i = gap; i < n; i++)
for (j = i - gap; j >= 0
&& v [j] > v[j + gap]; j -= gap) { temp = v [j]; v [j] = v [j + gap]; v [j + gap] = temp;
}
}
Hrom egymsba skatulyzott ciklus van. A legkls ciklus az sszehasonltott elemek kztti
tvolsgot vezrli, amit n/2-rl minden ciklusban felre cskkent, amg a tvolsg 0 nem lesz. A
kzps ciklus minden olyan elemprt sszehasonlt, amelyek egymstl gap-nyire vannak. A legbels
ciklus minden, nem megfelel sorrendben lev sszehasonltott elemprt megfordt. Mivel gap az
utols ciklusban 1-re cskken, vgl minden elem helyes sorrendbe rendezdik. Vegyk szre, hogy a
for utasts ltalnos jellegnl fogva a kls ciklus ugyanolyan alak, mint a tbbi, br nem vgez
aritmetikai lptetst.
Az egyik utols C opertor a , (vessz), amelyet legtbbszr a for utastsban hasznlunk. A
vesszvel elvlasztott kifelyezsprok kirtkelse balrl jobbra trtnik, s az eredmny tpusa, ill.
rtke megegyezik a jobb oldali operandus tpusval, ill. rtkvel. gy a for utasts egyes rszeiben
tbb kifejezst is elhelyezhetnk pldul azrt, hogy prhuzamosan kt indexet dolgozzunk fel. Ezt
mutatjuk be a reverse(s) fggvnyben, amely az s karakterlncot helyben megfordtja:

70

Forrs: http://www.doksi.hu

reverse (s)

/*Az s karakterlnc helyben megfordtsa*/ char s [];

{
int c, i, j; for (i = 0 , j = strlen (s) - 1; i < j; i++ , j--) { c = s [i]; s [i] = s [j]; s [j] = c;
}
}
A fggvnyargumentumokat, a deklarcikban elfordul vltozkat stb. elvlaszt vesszk nem
vesszopertorok, s nem garantljk a balrl jobbra trtn kirtkelst.
3.2.
Gyakorlat. rjuk meg az expand(s1, s2) fggvnyt, amely az s1 karakterlncban tallhat
rvidtseket s2-ben teljes listv bvti ki (pl. a-z helyett abc. . .xyz-t r)! Engedjk meg a kis- s a
nagybetket, ill. a szmjegyeket is, s kszljnk fel az olyan esetek kezelsre is, mint a-b-c s az0-9 s -a-z! (Hasznos megllapods, ha a vezet vagy zr - karaktert bet szerint vesszk.)
3.6. A do-while utasts
Mint az 1. fejezetben mondottuk, mind a while, mind a for ciklus rendelkezik azzal a kvnatos
tulajdonsggal, hogy a kiugrsi felttel teljeslst nem a ciklus vgn, hanem a ciklus elejn
vizsglja. A harmadik C-beli ciklusfajta, a do-while a vizsglatot a ciklus vgn, a ciklustrzs
vgrehajtsa utn vgzi el; a trzs teht legalbb egyszer mindenkppen vgrehajtdik. A
szintaxis:
do
utasts
while (kifejezs);
A gp elbb vgrehajtja az utastst, majd kirtkeli a kifelyezst. Ha az rtke igaz, ismt vgrehajtja
az utastst, s gy tovbb. Ha a kifelyezs rtke hamiss vlik, a ciklus vgetr.
Mint vrhat, a do-while-t sokkal ritkbban szoks hasznlni, mint a while-t s a for-t, taln az sszes
ciklusok t szzalkban. Idnknt azonban mgiscsak rdemes elvenni, mint pldul az itt kvetkez
itoa fggvnyben, amely egy szmot karakterlncc alakt t (atoi inverze).A feladat kicsit
bonyolultabb, mint gondolnnk, mivel az egyszer szmjegygenerl mdszerek a szmjegyeket rossz
sorrendben hozzk ltre.gy dntttnk, hogy a karakterlncot visszafel generljuk, majd
megfordtjuk.
itoa (n,s)

/*n karakterr konvertlsa s-be*/ char s []; int n;

{
int i, sign;
if ((sign = n) < 0)
/*eljelvizsglat s trols*/
n = -n;
/*n pozitv legyen*/
i = 0;
do { /*szmjegyek generlsa fordtott
sorrendben */
s [i++] = n % 10 + 0; /*megkapja a kvetkez
szmjegyet*/
} while ((n /= 10) > 0);
if (sign < 0)
s [i++] = -;
s [i] = \0;
reverse (s);
}

/*trli*/

Pldnkban a do-while hasznlata tnyleg knyelmes, mivel n rtktl fggetlenl legalbb egy
karaktert el kell helyezni az s tmbben. A do-while trzst alkot egyetlen utastst - br itt
szksgtelen - kapcsos zrjelek kz zrtuk, hogy a siets olvas se higgye azt, hogy a while egy while
ciklus kezdete.
3.3.
Gyakorlat. Kettes komplemens szmbrzolsban az itoa fggmny ltalunk rt vltozata nem
kezeli a legnagyobb negatv szmot, teht a (2 szmret-1) rtk n-et. Magyarzzuk meg, hogy

71

Forrs: http://www.doksi.hu

mirt! Mdostsuk gy a programot, hogy ezt az rtket is helyesen rja ki, fggetlenl attl, hogy
milyen gpen fut!
3.4.
Gyakorlat. rjuk meg azt a hasonl itob (n,s) fggvnyt, amely az n unsigned egsz szmot
binris karakterbrzolsban az s karakterlncba konvertlja! rjuk meg az itoh fggvnyt is, amely
egy egsz szmot hexadecimlis brzolsmdba alakt t!
3.5.
Gyakorlat. rjuk meg az itoa fggvnynek azt a vltozatt, amely kett helyett hrom
argumentumot fogad! A harmadik argumentum a minimlis mezszlessg; az tkonvertlt szmot
szksg esetn balrl res kzkkel kell kitlteni, hogy elg szles legyen.
3.7.
A break utasts
Nha knyelmes, ha a ciklusbl val kilpst nem a ciklus elejn vagy vgn val felttelvizsglattal
vezreljk. A break utastssal a vizsglat eltt is ki lehet ugrani a for, while s do ciklusokbl,
csakgy, mint a switch-bl. A break utasts hatsra a vezrls azonnal kilp a legbels zrt
ciklusbl __t;_st_s h;_tsra a vezrlcs azonnal kilp a leghels zrt ciklusbl (vagy switch-bl).
A kvetkez program az sszes sor vgrl eltvoltja a szkzket s tab karaktereket oly mdon,
hogy break utasts segtsgvel kilp a ciklusbl, amikor a legjobboldalibb nem - szkz s nem tab karaktert megtallja.
#define MAXLINE 1000
main ()

/*Sorvgi szkzk s tabok eltvoltsa*/

{
int n;
char line [MAXLINE];
while ((n = getline (line,MAXLINE)) > 0) { while (--n >= 0)
if (line [n] != && line [n] != \t
&& line [n] != \n)
break;
line [n + 1] = \0;
printf_(%s \n, line);
}
}
A getline a sor hosszt adja vissza. A bels while ciklus a line utols karaktern kezddik (ne felejtsk
el, hogyn elbb dekrementlja n-et s csak azutn hasznlja az rtkt), s visszafel haladva keresi
az els olyan karaktert, amely nem szkz, tab vagy jsor. Ha ilyen karaktert tall, vagy ha n negatvv
vlik (vagyis, ha az egsz sort megvizsglta), akkor a ciklus megszakad. Igazolja az olvas, hogy ez
akkor is helyes mkds, ha az egsz sor csupa res helyeket megjelent karakterekbl ll!
A break alkalmazsa helyett vlaszthatjuk azt a megoldst is, hogy a vizsglatot magba a ciklusba
tesszk:
while ((n = getline (line,MAXLINE)) > 0) {
while (--n >= 0 && (line [n] ==
|| line [n] == \t || line [n] == \n))
;
...
}
Ez a vltozat gyengbb, mint az elz, mivel a vizsglat nehezebben rthet. ltalban kerljk az
olyan vizsglatokat, amelyekben keverednek az &&, ||, ! szimblumok s a zrjelek.
3.8.
A continue utasts
A continue utasts a break-hez kapcsoldik, de a break-nl ritkbban hasznljuk; a continue-t
tartalmaz ciklus (for, while, do) kvetkez itercijnak megkezdst idzi el. A while s a do
esetben ez azt jelenti, hogy azonnal vgrehajtdik a felttelvizsglat, a for esetben pedig a
vezrls azonnal az jrainicializlsi lpsre kerl. (A continue csak ciklusokra alkalmazhat,
switch-re nem. Az olyan, switch-en belli continue, ahol a switch egy cikluson bell van, a
kvetkez ciklusiterci vgrehajtst vltja ki.)

72

Forrs: http://www.doksi.hu

Pldul a kvetkez programrsz az a tmbnek csak a pozitv elemeit dolgozza fel; a negatv
rtkeket tugorja:
for (i = 0; i < n; i++) {
if (a [i] < 0) /*Ugord t a negatv elemeket*/
continue;
. . . /*Dolgozd fel a pozitv elemeket*/
}
A continue utastst gyakran hasznljuk olyan esetekben, amikor a ciklus tovbbi rsze nagyon
bonyolult s ezrt a felttelvizsglat megfordtsa s egy jabb programszint (sorbetols) tl mlyen
skatulyzn a programot.
3.6.
Gyakorlat. rjunk olyan programot, amely a bemenett a kimenetre msolja, de ha a
bemenetre egyms utn tbbszr rkezik ugyanaz a sor, azt csak egyszer nyomtatja ki! (Ez egyszer
vltozata az UNIX uniq szolgltatsnak.)
3.9.
A goto utasts; cmkk
A C-ben is hasznlhatjuk a sokat szidott goto utastst, ugrathatunk cmkkre. Elmletileg a goto-ra
sohasincs szksg, s gyakorlatilag majdnem mindig egyszeren programozhatunk nlkle is. Ebben
a knyvben nem hasznltunk goto-t. Mindazonltal bemutatunk nhny olyan esetet, ahol a gotoknak meg lehet a maguk helye. A leggyakoribb eset, amikor a feldolgozst valamilyen mlyen
skatulyzott szerkezet belsejben akarjuk abbahagyni oly mdon, hogy egyszerre kt, egymsba
gyazott ciklusbl lpnk ki. A break utastst kzvetlenl nem hasznlhatjuk, mivel az egyszerre
csak a legbels ciklusbl ugratja ki a vezrlst. gy pldul :
for ( . . . )
for ( . . . ) {
...
if (zavar)
goto hiba;
...}
hiba:
szmold fel a zavart
Ez a fajta szervezs clszer, ha a hibakezel program nemtrivilis s ha a hibk klnbz helyeken
fordulhatnak el. A cmkk alakja ugyanaz, mint a vltoznevek, csak kettspont kveti ket.
Ugyanazon a fggvnyen bell, mint ahol a goto elfordul, brmelyik utastst megcmkzhetjk.
Msik pldaknt tekintsk azt a problmt, amikor egy ktdimenzis tmb els negatv elemt akarjuk
megtallni. (A tbbdimenzis tmbkrl az 5. fejezetben lesz sz.) Az egyik lehetsg:
for (i = 0; i < n; i++)
for (j = 0; j < m; j ++)
if (v [i][j] < 0)
goto found;
/*Nem tallt*/
...
found:
/*Az i, j pozcin megtallta*/
...
Brmely goto-t tartalmaz program megrhat goto nlkl, de esetleg csak megismtelt vizsglatok
vagy kln bevezetett vltoz rn. Pldul a tmbben val keress goto nlkl :
found = 0; for (i = 0; i < N && !found; i++) for (j = 0;j < M && !found; j++)
found = v[i][j] < 0; if (found)

73

Forrs: http://www.doksi.hu

/*i-1, j-1-nl volt*/


...
else
/*Nem tallt*/
...
Br nem kvnunk az gyben dogmatikusak lenni, kimondjuk : minl kevesebbet hasznljuk a goto-t,
annl jobb.
_
4.
fejezet: Fggvnyek s programstruktra
A fggvnyek a nagy szmtsi feladatokat kisebbekre bontjk. gy a programoz pthet arra, amit
msok mr megcsinltak, s nem kell mindent ellrl kezdenie. A jl megrt fggvnyek gyakran
elrejtik a mveletek rszleteit a program azon rszei ell, amelyeknek nem is kell tudniuk rluk. Ezltal
az egsz program vilgosabb vlik, s a vltoztatsok is knnyebben elvgezhetk.
A C nyelvet gy terveztk meg, hogy a fggvnyek hatkonyak s knnyen hasznlhatk legyenek. A C
programok ltalban sok kis mret fggvnyt tartalmaznak. Egy program tbb forrsllomnyra is
tagoldhat. Az llomnyok kln-kln is fordthatk, s a knyvtrakban tallhat, mr korbban
lefordtott fggvnyekkel egytt betlthetk. Ezt a folyamatot most nem trgyaljuk, mivel a rszletek a
helyi opercis rendszertl fggenek.
A legtbb programoz mr ismeri a be- s kivitel cljra szolgl knyvtri fggvnyeket (getchar,
putchar) s a numerikus szmtsok knyvtri fggvnyeit (sin, cos, sqrt). Ebben a fejezetben
rszletesebben szlunk arrl, hogyan rhatunk j fggvnyeket.
4.1.
Alapfogalmak
Kezdetknt tervezznk s rjunk olyan programot, amely a
bemenetnek minden olyan sort kinyomtatja, amely adott
karakterlncbl ll mintt tartalmaz! (Ez specilis esete az
UNIX grep segdprogramjnak.) Pldul a the minta keresse a
Now is the time
for all good
men to come to the aid
of their party.
sorokban a

/Ideje, hogy
minden j
ember segtsgre siessen
embertrsainak./

Now is the time


men to come to the aid
of their party.
kimeneti szveget fogja eredmnyezni. A feladat alapstruktrja knnyen felbonthat hrom klnll
rszre:
while (van mg sor) if (a sor tartalmazza a mintt)
nyomtats
Br nyilvn elhelyezhetjk az egsz programkdot a f rutinban, mgis az a jobb megolds, hogy
kihasznljuk az elz termszetes struktrt s minden rszbl egy-egy kln fggvnyt ksztnk.
Hrom kis program knnyebben kezelhet, mint egy nagy, mivel az egymsra nem tartoz rszletek a
fggvnyekbe rejthetk s a nem kvnatos klcsnhatsok lehetsge minimlis lesz. Mi tbb, az
egyes rszek a ksbbiekben nmagukban is hasznosak lehetnek.
A while (van mg sor) feladatot az 1. fejezetben rt getline fggvny, a nyomtats feladatt pedig a
szabvnyos knyvtrban rendelkezsnkre ll printf fggvny vgzi el. Eszerint csupn azt a rutint
kell megrnunk, amely eldnti, hogy a sor tartalmazza-e a krdses mintt. A problma megoldsnak
tervt a PL/1-bl lophatjuk el: az index(s, t) fggvny azt az s karakterlncbeli pozcit vagy indexet
adja vissza, ahol a t karakterlnc kezddik, vagy pedig -1-gyel tr vissza, ha s nem tartalmazza t-t. sbeli kezdpozciknt 0-t hasznlunk, nem 1-et, mivel a tmbk a C nyelvben a 0 indexszel kezddnek.

74

Forrs: http://www.doksi.hu

Ha a ksbbiekben bonyolultabb minta-sszehasonltsi feladatot akarunk megoldani, csak az index


fggvnyt kell kicserlnnk; a programkd tbbi rsze vltozatlan marad.
Ennyi tervezs utn mr gyorsan megrhatjuk a programot. Jl lthat, hogyan illeszkednek egymshoz
az egyes rszek. Ne dolgozzunk a legltalnosabb esettel: a keresett minta egyelre legyen csupa
betbl ll karakterlnc. Nemsokra sz lesz a karaktertmbk inicializlsrl, s az 5. fejezetben
megmutatjuk, hogyan tehetjk a mintt olyan paramterr, amelyet a program futsa sorn lltunk be.
Pldnk egyben a getline fggvny jabb vltozata is: tanulsgos lesz, ha sszehasonltjuk az 1.
fejezetbeli vltozattal!
#define MAXLINE 1000
main ()

/* Adott mintra illeszked sszes sor megkeresse*/

{
char line [MAXLINE];
while (getline (line, MAXLINE) > 0)
if (index (line, the) >= 0)
printf(%s, line);
}
getline (s, lim)

/*Sor beolvassa s-be,

visszatrsi rtk a
sorhosszsg*/
char s []; int lim;
{
int c, i;
i = 0;
while (--lim > 0 && (c = getchar ()) != EOF && c != \n) s [i++] = c; if (c == \n) s [i++] = c; s [i]
= \0; return (i);
}
index (s, t)

/*Visszaadja t s-beli indext;

1 , ha t nincs s-ben*/
char s [], t [];
{
int i, j, k;
for (i = 0; s [i] != \0; i++) {
for (j = i , k = 0; t [k] != \0
&& s [j] == t [k];j++ , k++)
;
if (t [k] == \0)
return (i);
}
return (-1);
}
Minden fggvny az albbi alak :
nv (argumentumlista, ha van)
argumentumdeklarcik, ha vannak
{
deklarcik s utastsok, ha vannak
}
Mint lthat, a klnfle rszek hinyozhatnak; a legrvidebb fggvny :

75

Forrs: http://www.doksi.hu

dummy () { } ami semmit sem csinl. (Az ilyen semmit sem csinl fggvny gyakran hasznos, ha a
programfejleszts sorn le akarjuk foglalni egy ksbb megrand programrsz helyt.) A
fggvnynevet tpusnv is megelzheti, amennyiben a fggvny nem egsz tpus rtkkel tr vissza;
errl a kvetkez szakaszban lesz sz.
A program lnyegben egyedi fggvnydefincik halmaza. A fggvnyek kztti kommunikci
(ebben az esetben) argumentumokkal s a fggvnyek ltal visszaadott rtkekkel trtnik, de trtnhet
kls vltozkon keresztl is. A fggvnyek a forrsllomnyon bell tetszleges sorrendben
fordulhatnak el, s a forrsprogram tbb llomnyra bonthat, csak fggvnyeket nem szabad
kettvgni.
A hvott fggvny meghvjnak a return utasts segtsgvel adhat vissza rtket. A return utastst
tetszleges kifejezs kvetheti:
return (kifejezs)
A hv fggvnynek jogban ll a visszaadott rtket figyelmen kvl hagyni. Nem szksges tovbb,
hogy a return utn kifejezs lljon, ez esetben a hv nem kap vissza semmit. A vezrls akkor is rtk
tadsa nlkl tr vissza a hvhoz, ha a vgrehajts a fggvny vgn elri a zr jobb oldali kapcsos
zrjelet. Ez a megolds megengedett, de valsznleg valamilyen bajt jelez, ha a fggvny rtket ad
vissza az egyik helyrl s nem ad rtket egy msikrl. Mindenesetre az olyan fggvny rtke, amely
nem ad vissza rtket, bizonyosan rtelmetlen (hatrozatlan, hulladk). Az ilyen jelleg hibkat a C
nyelv lint nev helyessgvizsgl programja jelzi.
A tbb llomnyra tagold C programok fordtsnak s
betltsnek mechanizmusa rendszerrl rendszerre vltozik. Az
UNIX opercis rendszerben pl. az 1. fejezetben emltett cc
parancs vgzi el ezt a feladatot. Tegyk fel, hogy a hrom
fggvny hrom llomnyban tallhat, amelyeknek a neve main.c,
getline.c s index.c. Ekkor a
cc main.c getline.c index.c parancs lefordtja a hrom llomnyt, az eredmnyl kapott thelyezhet
formtum trgykdot a main.o, getline.o s index.o nev llomnyokba helyezi, s betlti ket az a.out
nev vgrehajthat llomnyba.
Ha hiba fordul el, mondjuk a main.c-ben, akkor az illet
llomny nmagban jrafordthat s az eredmny betlthet a
korbban kapott llomnyokkal egytt a
cc main.c getline.o index.o paranccsal. A cc parancs a .c, ill. az .o nvadsi konvencik
segtsgvel klnbzteti meg a forrsllomnyokat (source) a trgykdot tartalmaz (object)
llomnyoktl.
4.1.
Gyakorlat. rjunk egy rindex(s, t) nev fggvnyt, amely t
s-beli legjobboldalibb
elfordulsnak pozcijt adja vissza, ill. -1-et ad, ha t nem fordul el s-ben!
4.2.
Nemegsz tpus rtkekkel visszatr fggvnyek Idig egyetlen programunk sem
tartalmazott a fggvny tpusra vonatkoz deklarcit. Ennek az az oka, hogy alaprtelmezs
szerint a fggvnyek implicit mdon deklarltak azltal, hogy megjelennek valamely utastsban
vagy kifejezsben, mint pl.: while (getline (line, MAXLINE) > 0)
Ha valamely kifejezsben korbban mg nem deklarlt nv fordul el, amelyet bal oldali kerek
zrjel kvet, akkor ezt a gp a szvegkrnyezet alapjn fggvnynvknt deklarlja. Ezenkvl
alaprtelmezs szerint a fggvnyrl azt felttelezzk, hogy int tpus rtket ad vissza. Mivel a
char kifejezsekben int mennyisgg alakul t, a char tpussal visszatr fggvnyeket sem kell
deklarlni. Ezzel az esetek tbbsgt lefedtk, belertve sszes eddigi pldnkat is.
Mi trtnik azonban, ha a fggvnynek valamilyen ms tpus rtket kell visszaadnia? Sok
numerikus fggvny - mint pl. az sqrt, sin s cos - double tpus rtket ad vissza; ms specilis
fggvnyek ms tpusokat. Ezek alkalmazst az atof(s) fggvnnyel szemlltetjk, amely az s
karakterlncot a neki megfelel duplapontossg lebegpontos szmm alaktja. Az atof az atoi
kiterjesztse, amelynek tbb vltozatt is megrtuk a 2. s 3. fejezetben. Az atof kezeli az esetleges

76

Forrs: http://www.doksi.hu

eljelet s tizedespontot, valamint a jelenlev vagy hinyz egsz, ill. trt rszt. (Ez azonban nem
nevezhet j minsg bemeneti konverzis rutinnak; ilyen rutin megrsa tbb helyet ignyelne,
mint amit most erre a clra sznunk.)
Elszr is az atof maga kell, hogy deklarlja az ltala visszaadott rtk tpust, mivel az nem int.
Tekintve, hogy kifejezsekben a float double mennyisgg alakul t, nincs rtelme azt mondanunk,
hogy az atof float rtket ad vissza; jl kihasznlhatjuk a ktszeres pontossgot, s a fggvnyt
double rtkkel visszatrnek deklarljuk. A tpus neve megelzi a fggvny nevt:
double atof (s)

/*Az s karakterlnc talaktsa double-l*/ char s [];

{
double val, power;
int i, sign;
for (i = 0; s [i] == || s [i] == \n
|| s [i] == \t; i++)
; /* res hely tugrsa*/
sign = 1;
if (s [i] == + || s [i] == -)
/*Eljel*/ sign = (s [i++] == +) ? 1 : -1; for (val = 0; s [i] >= 0
&& s [i] <= 9; i++) val = 10 * val + s [i] - 0; if (s [i] == .) i++; for (power = 1 ; s [i] >= 0 &&
s [i] <= 9; i++) { val = 10 * val + s [i] - 0; power *= 10;
}
return (sign * val / power);
}
Msodszor is, ugyanilyen fontos, hogy a hv rutinnak kzlnie kell, hogy az atof nemegsz rtket ad
vissza. A deklarcit a kvetkez primitv kalkultor-program mutatja (a program pphogy elegend pl.
egy csekknyv egyenlegnek kiszmtshoz). A program soronknt egy-egy szmot olvas be, amelyet
eljel elzhet meg, a szmokat sszeadja s az sszeget minden beolvass utn kinyomtatja:
#define MAXLINE 100
main ()
/*Primitv kalkultor*/
{
double sum, atof();
char line [MAXLINE];
sum = 0;
while (getline (line, MAXLINE) > 0)
printf (\t %.2f \n, sum += atof (line));
}

A
double sum, atof (); deklarci rtelmben sum double tpus vltoz, s atof olyan fggvny, amely
double rtkkel tr vissza.
Amennyiben atof nincs mindkt helyen explicit mdon deklarlva a C felttelezi, hogy egsz tpus
rtkkel tr vissza, s gy rtelmetlen vlaszokat kapunk. Ha maga az atof s main-beli hvsa
kvetkezetlen mdon fordul el ugyanabban a forrsllomnyban, ezt a fordt szreveszi. Ha azonban
az atof fggvnyt kln fordtottuk (ami valszn), az eltrst a gp nem veszi szre, az atof double
rtket ad vissza, amit a main int rtkknt kezel, s rtelmetlen vlaszokat kapunk. (A lint kimutatja az
ilyen hibt!)
Az atof birtokban elvileg gy is megrhatjuk az atoi fggvnyt (karakterlnc konvertlsa int-t):
atoi (s)

/*Az s karakterlnc talaktsa

egsz szmm*/ char s [];


{
double atof ();
return (atof (s));

77

Forrs: http://www.doksi.hu

}
Figyeljk meg a deklarcik s a return utasts struktrjt. A
kifejezs rtke a
return (kifejezs)
ben mindig olyan tpusv alakul t, mint amilyen a fggvny tpusa, mg mieltt a hvhoz val
visszatrs megtrtnne. gy atof rtke, ami double, automatikusan int tpusv alakul t a
return-ben val megjelenskor, mivel az atoi fggvny int rtkkel tr vissza. (A lebegpontos
rtk int tpusv trtn konverzija levgja az esetleges trt rszt, amint errl a 2. fejezetben
sz volt.)
4.2.
Gyakorlat. Bvtsk ki atof-ot oly mdon, hogy az
123.45e-6 alak tudomnyos jellsmdot is kezelni tudja, ahol a lebegpontos szmot e vagy E s
egy esetleges eljellel elltott kitev kvetheti!
4.3.
Tovbbi tudnivalk a fggvnyargumentumokrl Az 1. fejezetben megtrgyaltuk a nyelvnek
azt a tulajdonsgt, hogy a fggvnyargumentumok rtk szerint addnak t, vagyis a hvott
fggvny az egyes argumentumoknak nem a cmt, hanem a kln ideiglenes msolatt kapja meg.
Eszerint a fggvny nem kpes befolysolni a hv fggvnyben tallhat eredeti argumentumot. A
fggvnyen bell valjbanminden argumentum loklis vltoz, amely azzal az rtkkel
inicializldott, amivel a fggvnyt meghvtk.
Ha a fggvny argumentumaknt tmbnv jelenik meg, a tmb kezdcme addik t; a tmbelemek
nem msoldnak t. A fggvny az tadott cmtl kezdd indexelssel megvltoztathatja a tmb
elemeit. A tmbk teht nv szerint addnak t. Az 5. fejezetben elmondjuk, hogyan lehet a
mutatkat gy hasznlni, hogy a hv fggvnyekben tallhat nemtmb jelleg vltozkat is
befolysolni tudjuk.
Megjegyezzk, hogy nincs teljesen kielgt mdszer olyan gpfggetlen fggvnyek rsra,
amelyek vltoz szm argumentumot fogadnak. Nincs ugyanis olyan gpfggetlen eljrs, amellyel
a hvott fggvny meg tudn hatrozni, hogy adott hvs alkalmval tnylegesen hny argumentumot
kapott. gy nem tudunk pldul olyan, igazn gpfggetlen programot rni, amely ki tudn vlasztani
tetszleges szm argumentum kzl a legnagyobbat, amint azt a FORTRAN s a PL/1 max nev
beptett fggvnye teszi.
Vltoz szm argumentum ltalban biztonsgosan hasznlhat, ha a hvott fggvny nem
hasznl olyan argumentumot, amit tnylegesen nem kapott meg, tovbb ha a tpusok hasznlata
kvetkezetes. A printf, amely a legkznsgesebb vltoz-argumentumszm C fggvny, az els
argumentumban tallhat informci alapjn hatrozza meg, hogy mg hny argumentum
kvetkezik s azoknak mi a tpusa. Slyos hiba lp fel, ha a hv nem ad elegend szm
argumentumot, vagy ha a tpusok nem azonosak azzal, amit az 1. argumentum mond. A printf sem
gpfggetlen, s klnbz krnyezetek esetben mdostani kell.
Msik lehetsg, hogy amennyiben az argumentumok ismert tpusak, valamilyen megllapods
szerint, pl. egy specilis argumentumrtkkel (ami gyakran a nulla) meg lehet jellni az
argumentumlista vgt.
4.4.
Kls vltozk
A C program kls objektumok halmaza. Ezek vltozk vagy fggvnyek lehetnek. A kls jelzt a
bels fogalommal val szembellts kedvrt hasznljuk, amely utbbi a fggvnyeken bell
definilt argumentumokat s automatikus vltozkat rja le. A kls vltozkat fggvnyeken
kvl definiljuk, gy sok fggvny szmra elrhetk. Maguk a fggvnyek mindig klsk, mivel a
C-ben nem lehet fggvnyeket ms fggvnyeken bell definilni. Megllapods szerint a kls
vltozk egyben globlis vltozk is teht minden, az ilyen vltozra ugyanazzal a nvvel trtn
hivatkozs (mg a teljesen kln fordtott fggvnyekbl is) ugyanarra a fizikai objektumra trtn
hivatkozst jelent. Ebben az rtelemben a kls vltozk a FORTRAN vagy PL/1 externaljainak
felelnek meg. Ksbb ltni fogjuk, hogyan definilhatunk olyan kls vltozkat s fggvnyeket,
amelyek globlisan nem hozzfrhetk, hanem csupn egyetlen forrsllomnyon bell lthatk.
Mivel a kls vltozk globlisan hozzfrhetk, helyettesthetik a fggvnyargumentumokat s a
fggvnyek kztti kommunikci cljait szolgl visszatrsi rtkeket. Brmelyik fggvny

78

Forrs: http://www.doksi.hu

hozzfrhet kls vltozhoz az illet vltoz nevre trtn hivatkozssal, ha a nevet korbban
deklarltk.
Ha fggvnyek kztt nagy szm vltozt kell megosztani, a kls vltozk hasznlata
knyelmesebb s hatkonyabb, mint a hossz argumentumlistk.
Amint az 1. fejezetben rmutattunk, ezt az okoskodst fenntartssal kell fogadnunk, mivel az ilyen
megolds rontja a program ttekinthetsgt s olyan programokat eredmnyez, amelyekben sok a
fggvnyek kztti adatkapcsolat. A kls vltozk hasznlatnak msodik oka az inicializlssal
kapcsolatos. Klnsen lnyeges, hogy a kls tmbk inicializlhatk, az automatikus tmbk
azonban nem. E fejezet vge fel foglalkozunk az inicializlssal.
A harmadik ok - ami miatt kls vltozkat hasznlunk - rvnyessgi tartomnyuk s fennmaradsi
idejk. Az automatikus vltozk valamely fggvnyre nzve bels vltozk : akkor jnnek ltre,
amikor a vezrls belp a rutinba, s megsznnek az onnan val kilpskor. A kls vltozk
viszont llandan megmaradnak: nem jnnek-mennek, gy az egyik fggvnyhvstl a msikig
megtartjk rtkket. Ha teht kt fggvnynek meg kell osztoznia valamilyen adathalmazon s
egyik fggvny sem hvja a msikat, gyakran az a legknyelmesebb, ha a kzsen hasznlt adatokat
kls vltozkban tartjuk s nem adogatjuk t ide-oda argumentumokon keresztl.
Vizsgljuk tovbb ezt a krdst egy nagyobb pldn keresztl!
A feladat egy jabb, az elznl jobb kalkultorprogram rsa. Ez a program mr megengedi a +, -,
* , / s = mveleteket. A kalkultor az infix jellsmd helyett a fordtott lengyel (reverse Polish)
jellsmdot hasznlja, mivel az utbbi knyelmesebb. (gy mkdnek pl. a Hewlett Packard
gyrtmny zsebszmolgpek.) Ebben a jellsmdban minden opertor az operandusai utn ll;
az olyan infix kifejezst, mint pl.
(1 - 2) * (4 + 5) = gy rjuk be, hogy:
1 2 - 4 5 + * = Zrjelekre nincs szksg.
A megvalsts egszen egyszer. Minden operandust egy verembe tolunk; opertor rkezsekor
a megfelel darabszm operandus (ktoperandus opertorok esetben kett) kilp a verembl,
elvgezzk rajtuk az opertor ltal meghatrozott mveletet, majd az eredmnyt ismt visszarjuk a
verembe. A fenti esetben pl. elbb 1 s 2 a verembe kerl, majd a helykbe a kett klnbsgt,
vagyis -1-et rjuk. Ezutn 4-et s 5-t toljuk a verembe, amelyeket azutn az sszegk, vagyis 9
helyettest. Vgl a szorzs utn -1 s 9 helyre szorzatuk, vagyis -9 kerl a verembe. Az =
opertorral kinyomtatjuk a verem legfels elemt anlkl, hogy onnan elmozdulna (gy egy szmts
rszeredmnyei is ellenrizhetk).
Br a verembe tols s az onnan trtn kilptets (push s pop) mveletei egyszerek, mire a
hibafigyelst s javtst is hozzfzzk, elg hossz programot kapunk ahhoz, hogy mindent kln
fggvnybe tegynk, ahelyett, hogy ugyanazt a programkdot ismtelgetnnk az egsz programon
keresztl. Szksg van tovbb egy kln fggvnyre, amely beolvassa a kvetkez bemen
opertort vagy operandust. gy a program felptse:
while (a kvetkez opertor vagy operandus
nem az llomny vge) if (szm)
told a verembe else if (opertor)
lptesd ki az operandusokat
vgezd el a mveletet
told a verembe az eredmnyt
else
hiba
Nem dntttnk mg a f krdsben - hol legyen a verem, vagyis mely rutinok frhessenek hozz
kzvetlenl. Az egyik lehetsg, hogy a vermet a main rutinban tartjuk, s a vermet s a pillanatnyi
verempozcit tadjuk a verembe rst s az onnan trtn kilptetst vgz rutinoknak. A main
rutinnak azonban nem kell tudnia a vermet vezrl vltozkrl; csupn a verembe trtn rsra s az
onnan trtn kilptetsre kell gyelnie. Ezrt gy dntttnk, hogy a vermet s a hozz kapcsold
informcit olyan klsvltozkkal brzoljuk, amelyekhez a push s pop fggvnyek hozzfrhetnek,

79

Forrs: http://www.doksi.hu

a main azonban nem. Ezt a megoldst egyszeren lefordthatjuk a programozs nyelvre. A


fprogram lnyegben az opertorok s operandusok tpusra vonatkoz nagy switch-bl ll, ez taln
tipikusabb hasznlata a switch utastsnak, mint amit a 3. fejezetben lttunk:
#define MAXOP 20
#define NUMBER 0
#define TOOBIG 9

/*Operandus s opertor max.mrete*/


/*Szm szlelsnek jelzse*/
/*Jelzi, hogy a karakterlnc
tl nagy*/
main () /*Fordtott lengyel logikj kalkultor*/
{
int type;
char s [MAXOP];
double op2, atof(), pop(), push();
while ((type = getop (s, MAXOP)) != EOF)
switch (type) {
case NUMBER: push (atof(s)); break; case + : push (pop() + pop()); break; case * : push (pop()
* pop()); break; case - : op2 = pop (); push (pop() - op2); break; case /: op2 = pop (); if (op2 !=
0.0)
push (pop () / op2);
else
printf (az oszt nulla\n); break; case =: printf (\t %f \n, push(pop())); break; case c: clear ();
break; case TOOBIG: printf (%.20s . . .tl hossz\n, s); break; default: printf (ismeretlen parancs
%c \n, type); break;
}
}
#define MAXVAL 100 /*rtkverem max. mlysge*/
int sp = 0;
/*Veremmutat*/
double val [MAXVAL]; /* rtkverem*/
double push (f) /*f rsa az rtkverembe*/
double f;
{
if (sp < MAXVAL)
return (val [sp++] = f);
else {
printf (hiba: a verem megtelt\n);
clear ();
return (0);
}
}
double pop () /*A legfels rtk kiemelse a verembl*/
{
if (sp > 0)
return (val [--sp]);
else {
printf (hiba: a verem res\n);
clear ();
return (0);
}
}
clear ()

/*A verem kirtse*/

{
sp = 0;

80

Forrs: http://www.doksi.hu

}
A c parancs annak a clear fggvnynek a segtsgvel rti ki a vermet, amit hiba esetn a push s a pop
is hasznl. A getop fggvnnyel rvidesen foglalkozunk.
Amint arrl az 1. fejezetben mr sz volt, egy vltoz akkor
kls, ha az sszes fggvny trzsn kvl definiljuk. gy a
push, a pop s a clear ltal hasznlt vermet s veremmutatt e
hrom fggvnyen kvl definiltuk. Maga a main azonban nem
hivatkozik a veremre s a veremmutatra - a verem brzolst
gondosan elrejtettk. gy az = opertorra vonatkoz
programrsznek a
push (pop ()); utastst kell hasznlnia ahhoz, hogy a verem tetejt a verem megvltoztatsa nlkl meg
lehessen vizsglni.
Figyeljk meg tovbb, hogy mivel a + s a * kommutatv opertorok, a kilptetett operandusok
kombinlsnak sorrendje kzmbs, a - s a / opertorok esetben azonban meg kell klnbztetni a
bal oldali s a jobb oldali operandust.
4.3.
Gyakorlat. Az alapvet programkeret megtartsval egyszeren kibvthetjk a
kalkultorprogramot. Vezessk be a modul (_%) s az egyoperandus mnusz opertorokat!
Vezessk be tovbb az erase parancsot, amely trli a verem legfels elemt! Vezessnk be
vltoznevek kezelst lehetv tev parancsokat! (A huszonhat egybets vltoznvre egyszeren
megoldhat.)
4.5.
Az rvnyessgi tartomny szablyai
Nem szksges egyszerre lefordtani a C programot alkot sszes fggvnyt s kls vltozt: a
program forrsszvege tbb llomnyban trolhat, s knyvtrakbl mr elzleg lefordtott
rutinok is betlthetk. Ezzel kapcsolatban kt rdekes krds merl fel:
Hogyan lehet a deklarcikat gy megrni, hogy a fordts sorn a vltozk helyesen
deklarldjanak?
Hogyan kell elkszteni a deklarcikat ahhoz, hogy a program betltsekor az sszes rszlet
helyesen kapcsoldjon ssze?
Egy nv rvnyessgi tartomnya a programnak az a rsze, amelyre vonatkozan a nevet definiltuk. A
fggvny elejn definilt automatikus vltoz rvnyessgi tartomnya az a fggvny, amelyben a
nevet deklarltuk, s a ms fggvnyekben ugyanilyen nven ltez vltozkat ez nem rinti. Ugyanez
igaz a fggvny argumentumaira.
A kls vltoz rvnyessgi tartomnya ott kezddik, ahol a forrsllomnyban a vltozt deklarltuk
s az illet llomny vgig tart. Ha pl. a val, sp, push, pop s clear ebben a sorrendben, egyetlen
llomnyban vannak definilva, vagyis:
int sp = 0; double val [MAXVAL];
double push (f) { . . . }
double pop () { . . . }
clear () { . . . }
akkor a val s sp vltozk a push, pop s clear fggvnyekben egyszeren megnevezskkel
hasznlhatk, s nincs szksg tovbbi deklarcikra.
Ha viszont egy kls vltozra mg annak definilsa eltt kell hivatkozni, vagy ha egy kls vltozt
ms forrsllomnyban definilunk, mint ahol hasznlunk, akkor ktelezen extern deklarcit kell
alkalmazni.
Lnyeges, hogy klnbsget tegynk valamely kls vltoz
deklarcija s defincija kztt! A deklarci a vltoz
tulajdonsgait rja le (tpust, mrett stb.), mg a
defincival trterletet is lefoglalunk. Ha az
int sp;
double val [MAXVAL];
sorok minden fggvnyen kvl jelennek meg, akkor definiljk az
sp s val nev kls vltozkat, trterletet foglalnak le, s
az adott forrsllomny tbbi rsze szmra deklarciknt is

81

Forrs: http://www.doksi.hu

szolglnak. Msrszt az
extern int sp; extern double val [];
sorok deklarljk, hogy sp int tpus, val pedig double tpus tmb (amelynek mrett mshol
hatrozzuk meg), de ezek a sorok nem hozzk ltre a vltozkat s nem foglalnak le szmukra
trterletet.
A forrsprogramot alkot llomnyok kztt csupn egyben kell a kls vltoz defincijnak
szerepelnie; a tbbi llomnyban extern deklarcival biztostjuk a vltoz elrst. (A defincit
tartalmaz llomnyban is lehet extern deklarci.) Kls vltozt csak definilskor lehet inicializlni.
A tmbmreteket a definciban kell megadni, de opcionlisan extern deklarciban is szerepelhetnek.
Br az elbbi programban az ilyenfajta szervezs nem valszn, elkpzelhet, hogy a val s sp
vltozkat az egyik llomnyban definiljuk s inicializljuk, mg a push, pop s clear fggvnyeket
egy msikban. Ekkor sszekapcsolsukhoz a kvetkez defincik s deklarcik szksgesek:
Az 1. llomnyban:
int sp = 0;
/* Veremmutat*/
double val [MAXVAL]; /* rtkverem*/
A 2. llomnyban:
extern int sp;
extern double val [];
double push (f) { . . . }
double pop () { . . . }
clear () { . . . }
Minthogy a 2. llomnyban tallhat extern deklarcik a hrom fggvny eltt s azokon kvl
fordulnak el, ezrt mindegyikkre vonatkoznak, teht egyetlen deklarcikszlet elegend lesz az
egsz 2. llomnyhoz.
Fejezetnkben sz lesz mg a nagyobb programoknl elnys #include szolgltatsrl, amely lehetv
teszi, hogy csak egyszer rjuk le az extern deklarcikat, amelyek azutn fordts kzben minden
forrsllomnyba beillesztdnek. Nzzk most a getop megvalstst, amely a kvetkez opertort
vagy operandust olvassa be. Az alapfeladat egyszer: a szkzk, tabok s jsorok tugrsa. Ha a
kvetkez karakter nem szmjegy s nem tizedespont, akkor getop visszaadja az illet karaktert.
Egybknt sszegyjti a szmjegyekbl ll karakterlncot (amely tizedespontot is tartalmazhat) s
NUMBER-rel tr vissza, jelezve, hogy a bemenetre szm rkezett. A rutin elg bonyolult, mivel arra
trekedtnk, hogy azt az esetet is helyesen kezelje, amikor a beolvasott szm tl hossz. A getop
mindaddig szmjegyeket olvas be (esetleg kzben egy tizedespontot is), amg azok el nem fogynak, de
csupn azokat trolja, amelyek elfrnek. Ha nem volt tlcsorduls, akkor NUMBER-rel s a
szmjegyek karakterlncval tr vissza. Ha azonban a szm tl hossz volt, akkor figyelmen kvl
hagyja a beolvasott sor htralev rszt, s gy a felhasznl a hiba helytl kezdve egyszeren
jrarhatja a sort. A fggvny a tlcsordulst a TOOBIG-gel val visszatrssel jelzi:
getop (s, lim) /*A kv. opertor vagy operandus beolvassa*/ char s []; int lim;
{
int i, c; while ((c = getch()) == || c == \t || c == \n)
;
if (c != . && (c < 0 || c > 9))
return ;
s [0] = c;
for (i = 1; (c = getchar()) >= 0 && c <= 9; i++) if (i < lim)
s [i] = c; if (c == .) { /*A trt rsz beolvassa*/ if (i < lim)
s [i] = c; for (i++; (c = getchar()) >= 0 && c <= 9; i++)
if (i < lim) s [i] = c;
}
if (i < lim) { /*A szm rendben van*/
ungetch;
s [i] = \0;

82

Forrs: http://www.doksi.hu

return (NUMBER);
}
else {
/*Tl nagy, a sor tbbi rszt tugorja*/ while (c != \n && c != EOF)
c = getchar(); s [lim - 1] = \0; return (TOOBIG);
}
}
Mit jelent getch s ungetch? Gyakran az a helyzet, hogy a bemenetet olvas program csak akkor jn r,
hogy eleget olvasott, amikor mr a kelletnl tbb karaktert olvasott be. Ilyen eset pl., amikor egy
szmot alkot karaktereket kell beolvasni: amg a program nem szleli az els nem-szmjegyet, a szm
nem teljes. Ehhez azonban a programnak a szksgesnl eggyel tbb karaktert kell beolvasnia, egy
olyan karaktert, amelyre nincs felkszlve.
Valahogy teht nembeolvasott kellene tenni a nemkvnt karaktert. Amikor a program a szksgesnl
eggyel tbb karaktert olvasott be, vissza kellene helyezni azt a bemenetre, gy a program a
tovbbiakban gy viselkedhetne, mintha ezt a felesleges karaktert sohasem olvasta volna be.
Szerencsre mindezt kt, egymssal egyttmkd fggvny megrsval knnyen megoldhatjuk. getch
szlltja a kvetkez megvizsgland bejv karaktert; ungetch visszar egy karaktert a bemenetre oly
mdon, hogy a kvetkez getch hvs ismt ezt a karaktert szolgltatja. Az egyttmkds mdja
egyszer. Az ungetch a felesleges karaktereket egy megosztott pufferbe - egy karaktertmbbe - rja
vissza. A getch kiolvassa a puffert, amennyiben abban van valami, ill. ha res, meghvja a getchar
fggvnyt. Szksg van egy olyan indexvltozra is, amely az ppen vizsglt karakter pufferbeli
pozcijt mutatja.
Mivel a getch s az ungetch a puffert s az indexet kzsen hasznlja, az utbbiaknak a hvsok kztt
meg kell tartaniuk rtkket, mindkt rutinra nzve kls vltozknak kell lennik. gy a getch,
ungetch s az ltaluk megosztva hasznlt vltozk az albbi mdon rhatk:
#define BUFSIZE 100
char buf [BUFSIZE];
/*Az ungetch puffere*/
int bufp = 0;
/*A kvetkez szabad pozci buf-ban*/
getch () /*Kiolvas egy (esetleg visszart)
karaktert*/
{
return ((bufp > 0) ? buf [--bufp] : getchar());
}
ungetch

/* Karakter visszahelyezse a bemenetre*/ int c;

{
if (bufp > BUFSIZE)
printf(ungetch, tlsok karakter\n);
else
buf [bufp++] = c;
}
A pufferbe trtn visszarsra egyetlen karakter helyett tmbt hasznltunk, mivel ez az ltalnosts a
ksbbiekben mg jl jhet.
4.4.
Gyakorlat. rjuk meg az ungets(s) nev rutint, amely egy teljes karakterlncot r vissza a
bemenetre! Szksges, hogy az ungets fggvnynek tudomsa legyen buf-rl s bufp-rl, vagy
csak egyszeren hasznlja az ungetch fggvnyt?
4.5.
Gyakorlat. Tegyk fel, hogy sohasem helyeznk vissza egynl tbb karaktert. Mdostsuk a
getch s ungetch fggvnyeket ennek megfelelen !
4.6.
Gyakorlat. getch s ungetch rutinjainak a visszahelyezett EOF-ot gpfgg mdon kezelik.
Hatrozzuk meg, hogyan viselkedjenek rutinjaink, amikor EOF-ot runk vissza, majd valstsuk meg
ezt a megoldst!
4.6.
Statikus vltozk

83

Forrs: http://www.doksi.hu

A mr korbban megismert extern s automatikus vltozk mellett a statikus (static) vltozk


jelentik a harmadik trolsi osztlyt. A static vltozk akr belsk, akr klsk lehetnek. A bels
static vltozk ugyangy loklisak valamely fggvnyre nzve, mint az automatikus vltozk, de az
automatikusaktl eltren llandan fennmaradnak s nem jnnek ltre, ill. sznnek meg a fggvny
minden egyes aktivizlsa alkalmval. Eszerint a bels static vltozk a fggvnyen bell sajt,
lland trat kpeznek. A fggvnyeken bell megjelen karakterlncok, mint pl. a printf
argumentumai, bels static vltozk.
A kls static vltoz annak a forrsllomnynak a tovbbi rszben lesz ismert, amelyben
deklarltk, de rvnyessgi tartomnya nem terjed ki egyetlen ms llomnyra sem. A kls static
vltozk segtsgvel lehetsgnk van arra, hogy az olyan neveket mint buf s bufp elrejtsk a
getch-ungetch kombinciban. A vltozknak klsknek kell lennik ahhoz, hogy megoszthatk
legyenek, ugyanakkor rejtve kell maradniuk a fggvnyek felhasznli ell, mivel gy kizrjuk a
konfliktus lehetsgt. Ha a kt rutint s a kt vltozt egyetlen llomnyba szerkesztjk:
static char buf [BUFSIZE];
/*Az ungetch puffere*/
static int bufp = 0 /*A kvetkez szabad pozci
buf-ban*/
getch () { . . . }
ungetch { . . . }
akkor egyetlen ms rutin sem frhet hozz a buf s bufp vltozkhoz; de nem kerlhetnek
sszetkzsbe a vltozk az ugyanezen program ms llomnyaiban elfordul ugyanilyen nevekkel
sem.
A statikus trolst, legyen az akr bels, akr kls, gy definiljuk, hogy a kznsges deklarci el a
static szt rjuk. A vltoz kls, ha az sszes fggvnyen kvl, ill. bels, ha valamelyik fggvnyen
bell definiljk.
A fggvnyek ltalban kls objektumok, a nevk globlisan ismert. Ugyanakkor a fggvnyek static
tpusnak is deklarlhatk, az ilyen fggvnyek neve ismeretlen lesz azon az llomnyon kvl, ahol
deklarltk.
A C nyelvben a static deklarci nem csupn llandsgot rejt magban, hanem bizonyos mrtk
elzrtsgot is. A bels static objektumok csupn az adott fggvnyen bell ismertek; a kls static
objektumok (vltozk vagy fggvnyek) pedig csak abbl a forrsllomnybl hozzfrhetk,
amelyben megjelennek, s neveik nem kerlnek sszetkzsbe a ms llomnyokban elfordul
ugyanilyen nev vltozkkal, ill. fggvnyekkel.
Kls static vltozk s fggvnyek segtsgvel elrejthetjk az adatobjektumokat s a velk dolgoz
bels rutinokat, gy ms rutinok s adatok ezekkel mg vletlenl sem kerlhetnek sszetkzsbe.
A getch s az ungetch fggvny pl. karakterbeolvas_ s -visszar modult alkot; buf s bufp pedig
static kell, hogy legyen ahhoz, hogy kvlrl ne legyen elrhet. Hasonlkppen push, pop s clear egy
veremkezel modult alkot; val-nak s sp-nek ugyancsak kls static-nak kell lennie.
4.7.
Regisztervltozk
A negyedik s egyben utols trolsi osztly neve register. A register deklarci kzli a
fordtprogrammal, hogy a krdses vltozra nagyon gyakran trtnik hivatkozs. Amennyiben
lehetsges, a register tpus vltozk a gp regisztereibe kerlnek, miltal rvidebb s gyorsabb
programokjnnek ltre. A register deklarci alakja:
register int x; register char c;
s gy tovbb; az int rsz elhagyhat. A register deklarci csupn automatikus vltozkra, valamint
fggvnyek formlis paramtereire alkalmazhat. Utbbi esetben a deklarci alakja:
f (c, n) register int c, n;
{
register int i;
...
}
A gyakorlatban a regisztervltozkra nzve olyan megszortsok llnak fenn, amelyek az adott hardver
tulajdonsgait tkrzik. Az egyes fggvnyeknek csupn nhny vltozja trolhat regiszterekben s

84

Forrs: http://www.doksi.hu

csak bizonyos tpusok megengedettek. A fls szm, ill. meg nem engedett deklarcik esetben a
register szt a gp figyelmen kvl hagyja. Nem hivatkozhatunk tovbb valamely regisztervltoz
cmre (ezzel a tmval az 5. fejezetben foglalkozunk). A specilis megktsek gprl gpre
vltoznak: pldul a PDP- 11 szmtgpen csupn a fggvnyen belli els hrom regiszterdeklarci
hatsos, a tpus pedig int, char vagy mutat lehet.
4.8.
Blokkstruktra
A PL/1, ill. az ALGOL rtelmben a C nem blokkstruktrlt nyelv, amennyiben fggvnyek nem
definilhatk ms fggvnyek belsejben.
Vltozkat azonban definilhatunk blokkstruktrlt mdon.
Nyit kapcsos zrjel utn - amely nemcsak fggvny, hanem
mindenfajta sszetett utasts kezdett jelzi vltozdeklarcik s inicializlsok egyarnt llhatnak. Az ily
mdon deklarlt vltozk fellbrljk a klsbb blokkokban
ugyanilyen nv alatt elfordul vltozkat s a vonatkoz jobb
oldali kapcsos zrjelig rvnyben maradnak. Pl. az
if (n > 0) {
int i; /* j i deklarlsa*/
for (i = 0; i < n; i++)
...
}
programban az i vltoz rvnyessgi tartomnya az if utasts igaz ga; ennek az i-nek semmi kze a
programban elfordul brmely egyb i-hez.
A blokkstruktra kls vltozkra is alkalmazhat.
Ha adottak az
int x; f ()
{
double x;
...
}
deklarcik, akkor az f fggvnyen bell az x elfordulsai a bels, double tpus vltozra, f-en kvl
a kls int vltozra vonatkoznak. Ugyanez igaz a formlis paramterek neveire :
int z; f (z) double z;
{
...
}
Az f fggvnyen bell z a formlis s nem a kls paramterre vonatkozik.
4.9.
Inicializls
Az inicializlsrl futlag mr tbbszr is szltunk, de mindig csak mellkesen valamely ms tma
kapcsn. Ebben a fejezetben sszefoglaljuk a szablyok egy rszt, miutn mr megtrgyaltuk a
klnfle trolsi osztlyokat.
Explicit inicializls hinyban a kls s a statikus vltozk kezdeti rtke garantltan nulla lesz;
az automatikus s a regisztervltozk rtke hatrozatlan.
Az egyszer vltozk (nem a tmbk s a struktrk) a deklarlsukkor inicializlhatk oly mdon,
hogy a nevket egyenlsgjel s egy lland kifejezs kveti :
int x = 1;
char squote = \;
long day = 60 * 24;

/*Aposztrf*/
/*Percek szma a napban*/

85

Forrs: http://www.doksi.hu

Kls s statikus vltozk esetben az inicializls egyszer, mgpedig rtelemszeren a fordtsi idben
trtnik meg. Az automatikus s a regisztervltozk minden alkalommal inicializldnak, amikor a
vezrls belp a fggvnybe vagy blokkba.
Automatikus s regisztervltozk esetben az inicializls jobb oldaln nemcsak egy lland llhat tetszleges, korbban definilt rtkeket, akr fggvnyhvsokat tartalmaz kifejezs is megengedett.
A 3. fejezetben emltett binris keresprogram kezdeti rtk belltsai pl. a kvetkez mdon rhatk :
binary (x, v, n)
int x, v [], n;
{
int low = 0;
int high = n-1;
int mid;
...
}
a mr ltott:
binary (x, v, n) int x, v [], n;
{
int low, high, mid;
low = 0;
high = n - 1;
...
}
alak helyett.
Az automatikus vltozk inicializlsai valjban rtkad utastsok rvidtett formi. Lnyegben
csupn zls krdse, hogy valaki melyik alakot rszesti elnyben. ltalban explicit rtkadsokat
hasznltunk, mivel a deklarcikban elfordul inicializlsok nehezebben kvethetk.
Automatikus tmbk nem inicializlhatk. Kls s statikus
tmbk gy inicializlhatk, hogy a deklarcit a kezdeti
rtkek kapcsos zrjelek kz zrt s vesszkkel elvlasztott
listja kveti. Az 1. fejezetben ismertetett karakterszmll
program, amelynek kezdete
main ()

/*Szmjegyek, res kzk s egyebek szmllsa*/

{
int c, i, nwhite, nother;
int ndigit [10];
nwhite = nother = 0;
for (i = 0; i < 10; i++)
ndigit [i] = 0;
...
}
volt, ehelyett gy is rhat:
int nwhite = 0;
int nother = 0;
int ndigit [10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } ;
main ()

/*Szmjegyek, res kzk s egyebek szmllsa*/

{
int c, i;
...
}

86

Forrs: http://www.doksi.hu

Az adott esetben ezek az inicializlsok szksgtelenek, mivel mindegyik kezdeti rtk nulla, ennek
ellenre clszer explicit alakban megadni ket. Ha a megadott mretnl kevesebb szm kezdeti rtk
van, akkor a tbbi kezdeti rtk nulla lesz. Tl sok kezdeti rtk megadsa hibt jelent. Sajnos nincs
lehetsg valamely kezdeti rtk ismtldsnek megadsra, sem pedig arra, hogy a tmb valamely
kzbens elemt az sszes tbbi kezdeti rtk megadsa nlkl inicializljuk.
A karaktertmbk a kezdetirtk-bellts specilis esett jelentik: a kapcsos zrjelekkel s
vesszkkel trtn jellsmd helyett karakterlnc is hasznlhat :
char pattern [] = the;
Ez rvidtse a hosszabb, de ezzel egyenrtk rsmdnak:
char pattern [] = { t, h, e, \0};
Ha egy - tetszleges tpus - tmb mrett elhagyjuk, a fordt a tmbhosszsgot a megadott kezdeti
rtkek darabszmbl szmtja ki. A fenti esetben a mret ngy (hrom karakter s a zr \0).
4.10.
Rekurzi
A C megengedi a fggvnyek rekurzv hasznlatt, vagyis a fggvnyek (kzvetlenl vagy
kzvetve) sajt magukat is hvhatjk. Ennek hagyomnyos pldja valamely szmnak
karakterlncknt trtn nyomtatsa. Amint korbban emltettk, a szmjegyek rossz sorrendben
generldnak: a kis helyirtk szmjegyek a nagyobb helyirtk szmjegyek eltt jnnek ltre, de
a nyomtats fordtott sorrendben kell, hogy trtnjk. A problmnak kt megoldsa van. Az egyik
megolds szerint a szmjegyeket a generls sorrendjben troljuk egy tmbben, majd fordtott
sorrendben nyomtatjuk ki ket, ahogy ezt a 3. fejezetben az itoa fggvny tette. A printd els
vltozata ezt a megoldst kveti.
printd (n)

/*n nyomtatsa decimlis alakban*/ int n;

{
char s [10];
int i;
if (n < 0) {
putchar (-);
n = -n;
}
i = 0;
do {
s [i++] = n % 10 + 0; /*Veszi a kvetkez
karaktert*/
} while ((n /= 10) > 0);
while (--i >= 0)
putchar (s [i]);
}

/*Elhagyja*/

A msik lehetsg a rekurzv megolds, amelyben printd minden hvsakor elszr sajt magt hvja
meg - feldolgozza az sszes vezet szmjegyet, majd kinyomtatja az utols szmjegyet.
printd (n)

/*n nyomtatsa decimlis alakban


(rekurzv)*/

int n;
{
int i;
if (n < 0) {
putchar (-);
n = -n;
}
if ((i = n / 10) != 0)
printd (i);
putchar (n % 10 + 0);
}

87

Forrs: http://www.doksi.hu

Amikor a fggvny nmagt rekurzv mdon meghvja, minden hvs az automatikus vltozk friss
kszlett kapja meg, fggetlenl a korbbi kszlettl. gy printd(123) esetben az els printd
fggvnyben n = 123. tadja a 12-t az jabb printd fggvnynek, s 3-at nyomtat ki annak visszatrse
utn. Ugyangy a msodik printd 1 -et ad t a harmadiknak (amely kinyomtatja), majd kirja a 2-t.
A rekurzi ltalban nem gyorsabb, s tr-megtakartst sem jelent, mivel valahol ltre kell hozni egy
vermet a feldolgozott rtkek szmra. A rekurzv programkd azonban tmrebb s gyakran
knnyebben lerhat s megrthet. Mint a 6. fejezetben ltni fogjuk, a rekurzi klnsen knyelmes a
rekurzv mdon definilt adatstruktrk, pl. a fastruktrk esetben.
4.7.
Gyakorlat. A printd-ben alkalmazott megoldsok felhasznlsval rjuk meg az itoa rekurzv
vltozatt, vagyis rekurzv rutin segtsgvel konvertljunk egy egsz szmot karakterlncc!
4.8.
Gyakorlat. rjuk meg az s karakterlncot megfordt reverse(s) fggvny rekurzv vltozatt!
4.11.
A C elfeldolgoz
A C nyelv egy egyszer makro-elfeldolgoz (preprocesszor) segtsgvel bizonyos nyelvi
kiterjesztseket is nyjt szmunkra. E kiterjesztsek kzl a legkznsgesebb a mr ltott #define,
de ide tartozik az a nyelvi eszkz is, amely llomnyok tartalmnak a fordts sorn trtn
beiktatst teszi lehetv.
llomnyok beiktatsa
A #define szimblumok, deklarcik s ms nyelvi objektumok kezelst is megknnyti a C
llomnybeiktatsi szolgltatsa.
Minden sor, amelynek alakja:
#include llomnynv az llomnynv nev llomny tartalmval helyettestdik. (Az idzjelek
ktelezk!) Gyakran minden forrsllomny elejn megjelenik egy vagy kt ilyen alak sor, amely a
kzs #define utastsoknak s a globlis vltozk extern _deklarciinak beiktatsra szolgl. A
#include parancsok egymsba skatulyzhatk.
Az #include a legelnysebb mdja annak, hogy egy nagy mret program deklarciit sszegyjtsk.
E megolds eredmnyekppen az sszes forrsllomny ugyanazokat a defincikat s
vltozdeklarcikat kapja meg, s ezltal klnsen kellemetlen hibkat kerlhetnk el.
Termszetesen olyankor, amikor valamelyik beiktatott llomny megvltozik, az sszes ettl fgg
llomnyt jra le kell fordtani.
Makrohelyettests
A
#define YES 1
alak defincival a legegyszerbb tpus makrohelyettestst
valstjuk meg - egy nevet egy karakterlnccal helyettestnk. A
#define-ban elfordul nevek alakja azonos a C azonostkval; a
helyettest szveg tetszleges. A helyettest szveg ltalban
a sor tovbbi rsze; hossz defincik gy folytathatk, hogy a
folytatand sor vgre \-t helyeznk el. A #define szimblummal
definilt nv rvnyessgi tartomnya a definci helytl az
adott forrsllomny vgig tart. A nevek jradefinilhatk; a
defincik korbbi defincikat hasznlhatnak. Idzjelek kz
rt karakterlncokra nzve, teht amikor pl. YES definilt nv,
a
printf(YES)
ben nem trtnik helyettests.
Minthogy a #define-t egy makro-elfeldolgoz, nem pedig maga a

88

Forrs: http://www.doksi.hu

fordt dolgozza fel a defincikra csak nagyon kevs


nyelvtani megkts vonatkozik. Az ALGOL hvei pl. a
#define then
#define begin {
#define end; }
defincik utn azt rhatjk, hogy:
if (i > 0) then begin
a = 1;
b = 2; end
Lehetsg van argumentumokkal rendelkez makrk definilsra, amikor is a helyettest szveg a
makr hvsnak mdjtl fgg.
Pldaknt definiljuk a max nev makrt az albbi mdon :
#define max(A, B) ((A) > (B) ? (A) : (B))
Ekkor az
x = max(p+q, r+s);
sort az
x =((p + q) > (r + s) ? (p + q) : (r + s)); sor fogja helyettesteni. Olyan maximum fggvnyt kaptunk
teht, amelynek nem fggvnyhvs, hanem soron belli programkd a kifejtse. Ha az
argumentumokat kvetkezetesen kezeljk, ez a makro brmilyen adattpusra meg fog felelni: nem
szksges klnfle max-okat ksztennk a klnbz adattpusokra, mint ahogy azt fggvnyhvsok
esetben tennnk.
Amennyiben kzelebbrl megvizsgljuk a max elz kifejtst, tallhatunk benne nhny buktatt. A
kifejezsek ktszer rtkeldnek ki; ez nem j olyankor, amikor mellkhatsuk pl. fggvnyhvs vagy
inkrementl opertorok alkalmazsa.
gyelnnk kell tovbb a zrjelek hasznlatra, nehogy
megvltozzon a kirtkels sorrendje! (tekintsk a
#define square(x) x * x makrt, amikor azt square(z + 1) alakban hvjuk.) Vannak tisztn jellsbeli
problmk is: nem szabad, hogy a makro neve s az argumentumlistjt bevezet bal oldali zrjel
kztt szkz legyen!
Mindezek ellenre a makrk igen hasznosak. Erre nzve gyakorlati plda a 7. fejezetben ismertetend
szabvnyos be- s kiviteli (I/O) knyvtr, amelyben a getchar s putchar fggvnyeket makrkknt
definiljuk (putchar nyilvn argumentumot ignyel). Ezltal elkerljk azt a plusz terhelst, amit a
minden egyes feldolgozand karakter esetben trtn fggvnyhvs jelentene.
A makroprocesszor tovbbi szolgltatsait az A fggelk ismerteti.
4.9.
Gyakorlat. Definiljuk a swap(x, y) makrt, amely megcserli a kt int tpus argumentumt!
(A blokkstruktra segtsgnkre lesz.)
_
5.

fejezet: Mutatk s tmbk

A mutat (pointer) olyan vltoz, amely egy msik vltoz cmt tartalmazza. A C-ben gyakran
hasznlunk mutatkat, rszben azrt, mert nha csupn gy tudunk kifejezni valamilyen szmtst,
rszben pedig azrt, mert hasznlatuk ltalban tmrebb s hatkonyabb kdot eredmnyez, mint
amelyet ms mdon kaphatnnk.
Azt szoktk mondani, hogy a mutat, csakgy, mint a goto utasts, csak arra j, hogy sszezavarja s
rthetetlenn tegye a programot. Ez biztos gy is van, ha sz nlkl hasznljuk, hiszen knnyszerrel
gyrthatunk olyan mutatkat, amelyek valamilyen nem vrt helyre mutatnak. Kell nfegyelemmel
azonban a mutatkat gy is alkalmazhatjuk, hogy ezltal programunk vilgos s egyszer legyen. Ezt
ksreljk meg bemutatni a kvetkezkben.

89

Forrs: http://www.doksi.hu

5.1.
Mutatk s cmek
Mivel a mutat valamilyen objektum cmt tartalmazza, rajta
keresztl az illet objektum indirekt mdon rhet el. Tegyk
fel, hogy x - pl. int - vltoz, px pedig mutat, amelyet
valamilyen eddig mg nem ismertetett mdon hoztunk ltre. Az &
egyoperandus opertor valamely objektum cmt adja meg, teht a
px = &x; utasts x cmt rendeli hozz a px vltozhoz; ilyenkor azt mondjuk, hogy px az x rtkre
mutat (azt cmzi meg). Az & opertor csupn vltozkra s tmbelemekre alkalmazhat; az olyan
konstrukcik, mint &(x + 1) vagy &3 nem megengedettek. Ugyancsak tilos valamely register vltoz
cmre hivatkozni!
A * egyoperandus opertor gy kezeli az operandust, mint a
keresett rtk cmt, s megkeresi ezt a cmet, hogy tartalmt
behozza. Ha teht y is int, akkor
y = *px;
annak a tartalmt rendeli y-hoz, amire px mutat. gy a
px = &x; y = *px;
szekvencia ugyanazt az rtket rendeli y-hoz, mint
y = x;
A mveletekben rszt vev vltozkat deklarlnunk is kell :
int x, y;
int *px;
x s y deklarcija ugyanolyan, mint eddig. A px mutat deklarcija azonban j.
int *px; azt fejezi ki, hogy a *px kombinci int tpus mennyisg, vagyis ha px a *px krnyezetben
fordul el, akkor egy int tpus vltoznak felel meg. Gyakorlatilag a vltozk deklarcijnak
szintaxisa azoknak a kifejezseknek a szintaxist utnozza, _melyekben az illet vltozk
elfordulhatnak. Ez a meggondols mindig hasznos, mg bonyolult deklarcik esetben is. Pl.
double atof (), *dp; azt fejezi ki, hogy kifejezsekben atof() s *dp double tpus rtkkel rendelkeznek.
Vegyk szre tovbb, hogy a deklarci azt is kimondja, hogy a mutatnak mindig a megadott tpus
objektumra kell mutatnia. Mutatk kifejezsekben is elfordulhatnak. Ha pl. px az egsz tpus x-re
mutat, akkor *px minden olyan szvegkrnyezetben elfordulhat, ahol x elfordulhat.
y = *px + 1 hatsra y 1 -gyel nagyobb lesz, mint x;
printf (%d \n, *px)
kinyomtatja x pillanatnyi rtkt, tovbb
d = sqrt((double)*px) d-ben ellltja x ngyzetgykt, ahol x double tpusv alakul t, mieltt
taddna az sqrt fggvnynek (l. a 2. fejezetet).
Az olyan kifejezsekben, mint
y = *px + 1
a * s & egyoperandus opertorok szorosabban ktnek, mint az
aritmetikai opertorok, gy a kifejezst kirtkel program
elszr kiolvassa azt, amire px mutat, majd hozzad 1 -et, s
hozzrendeli y-hoz. Rvidesen visszatrnk arra, hogy mit
jelenthet
y = *(px + 1)

90

Forrs: http://www.doksi.hu

Mutathivatkozsok rtkadsok bal oldaln is elfordulhatnak.


Ha px s x-re mutat, akkor
*px = 0
az x-et kinullzza s
*px += 1
vagy
(*px)++ inkrementlja. Az utbbi pldban a zrjelek szksgesek: nlklk a kifejezs px-_t
inkrementln, nem pedig azt, amire px mutat, mivel az egyoperandus opertorok, esetnkben * s ++
jobbrl balra rtkeldnek ki.
Vgl, mivel a mutatk vltozk, ugyangy kezelhetk, mint a
tbbi vltoz. Ha py egy msik, int tpus mennyisgre mutat,
akkor
py = px a px tartalmt py-ba msolja, miltal py ugyanarra fog mutatni, mint px.
5.2.
Mutatk s fggvnyargumentumok
Mivel a C nyelv az argumentumokat rtk szerinti hvs
formjban adja t a fggvnyeknek, a hvott fggvny semmilyen
kzvetlen mdon nem tudja megvltoztatni a hv fggvny
vltozit. Mit tegynk, ha tnyleg meg kell vltoztatnunk
valamelyik kznsges argumentumot? Pldnak okrt a
rendezrutin megcserlhet kt, rossz sorrendben lev elemet a
swap nev fggvny segtsgvel. Nem elg, ha azt rjuk, hogy
swap (a, b); ahol a swap fggvny defincija:
swap (x, y)
int x, y;
{
int temp;
temp = x;
x = y;
y = temp;
}

/*ROSSZ*/

Az rtk szerint trtn hvs miatt a swap nem kpes az t meghv rutinban elfordul a s b
argumentumokat megvltoztatni.
Szerencsre van lehetsg a kvnt hats elrsre. A hv rutin a megvltoztatand rtkeket
megcmz mutatkat ad t:
swap (&a, &b);
Mivel az & opertor a vltoz cmt lltja el, &a az a vltozt megcmz mutat lesz. Magban a
swap rutinban az argumentumokat mutatkknt deklarljuk, s az aktulis operandusokat ezeken
keresztl rjk el:
swap (px, py) /*px s py megcserlse*/ int *px, *py;
{
int temp;
temp = *px;
*px = *py;
*py = temp;

91

Forrs: http://www.doksi.hu

}
A mutatargumentumokat gyakran alkalmazzk az olyan fggvnyekben, amelyeknek egynl tbb
rtket kell visszaadniuk.
(Mondhatjuk pl., hogy swap kt rtket ad vissza, tudniillik
argumentumainak az j rtkeit.) Pldaknt tekintsk a getint fggvnyt, amely szabadformtum
bemeneti konverzit vgez oly mdon, hogy egy karaktersorozatot egsz tpus rtkekre trdel,
hvsonknt egy-egy egsz rtket szolgltatva. A getint fggvnynek vagy mr ltala tallt rtket kell
visszaadnia, vagy pedig - amennyiben nincs tbb beolvasand karakter az llomny vge jelet. Az
rtkeknek kln-kln objektumokknt kell visszatrnik, fggetlenl attl, hogy milyen rtket
hasznlunk EOF-knt, amely maga is egy beolvasott egsz mennyisg lehet.
Az egyik megolds szerint, amely a 7. fejezetben ismertetsre kerl scanf beolvasfggvnyen alapul,
getint az EOF-ot mint sajt fggvnyrtkt adja vissza olyankor, amikor megtallta az llomny vgt;
minden ms visszatr rtk kznsges egsz szmra utal. A megtallt egsz szm numerikus rtke
argumentumon keresztl addik vissza, amelynek egsz szmot megcmz mutatnak kell lennie. Ez a
fajta szervezs elvlasztja az llomny vge llapotot a numerikus rtkektl.
A kvetkez ciklus a getint hvsai segtsgvel egsz szmokkal tlt fel egy tmbt:
int n, v, array [SIZE]; for (n = 0; n < SIZE && getint (&v) != EOF; n++) array [n] = v;
Minden egyes hvs berja a v vltozba a bemeneten tallt kvetkez egsz szmot. Vegyk szre,
hogy a getint argumentumaknt &y-t kell rnunk v helyett. Ha a puszta v-t hasznljuk, akkor
valsznleg cmzsi hibt kvetnk el, mivel getint azt hiszi, hogy rvnyes mutatt kapott.
Maga a getint a mr korbban megrt atoi termszetes mdostsa:
getint (pn)

/*A kvetkez egsz beolvassa a


bemenetrl*/

int *pn;
{
int c, sign; while ((c = getch ()) == || c == \n || c == \t)
; /*Az res kzt tugorja*/
sign = 1;
if (c == + || c == -) {

/*Feljegyzi az eljelet*/ sign = (c == +) ? 1 : -1; c = getch ();

}
for (*pn = 0; c >= 0 && c <= 9; c = getch ())
*pn = 10 * *pn + c - 0;
*pn *= sign; if (c != EOF) ungetch ; return ;
}
A getint fggvnyben a *pn vgig kznsges int tipus vltozknt szerepel. Felhasznltuk a geth s
ungeth fggvnyeket is (lersukat l. a 4. fejezetben), gy azt az egy plusz karaktert, amit mg ki kell
olvasni, vissza lehet helyezni a bemenetre.
5.1.
Gyakorlat. rjuk meg a getfloat fggvnyt, amely a getint lebegpontos megfelelje! Milyen
tipust ad vissza getfloat fggvnyrtkknt?
5.3.
Mutatk s tmbk
A C nyelvben szoros kapcsolat van a mutatk s a tmbk kztt. Ez indokolja, hogy a mutatkkal
s a tmbkkel egyidejleg foglalkozzunk. Valamennyi mvelet, amely tmbindexelssel
vgrehajthat, mutatk hasznlatval ppgy elvgezhet. ltalban az utbbi vltozat gyorsabb, de
klnsen a kezdk szmra els rnzsre nehezebben rthet.
Az
int a [10]
deklarci definilja azt a tmbt, amelynek mrete 10, vagyis
egy tz, egymst kvet objektumbl, az a[0], a[1], . . ., a[9]
nev elemekbl ll blokkot hatroz meg. Az a[i] jellsmd a

92

Forrs: http://www.doksi.hu

tmbnek a kezdettl szmtott i-edik pozcijt fejezi ki. Ha pa


egszt megcmz mutat, amelyet
int *pa
deklarl, akkor a
pa =&a[0]
rtkads gy lltja be pa-t, hogy az az a nulladik elemre
mutasson, vagyis pa az a[0] elem cmt tartalmazza. Ekkor az
x = *pa rtkads a[0] tartalmt x-be msolja.
Ha pa az a tmb adott elemre mutat, akkor definci szerint
pa + 1 a tmb kvetkez elemre mutat. ltalban pa - i i
elemmel pa el, pa + i pedig i elemmel pa mg mutat. gy ha pa
az a[0]-ra mutat, akkor
*(pa + 1) a[1] tartalmt szolgltatja, pa+i az a[i] elem cme s *(pa+i) az a[i] elem tartalma.
Ezek a megjegyzsek az a tmbben elhelyezked vltozk tipustol fggetlenl mindig igazak. Az adj
1-et a mutathoz s ennek kiterjesztseknt az egsz mutataritmetika alapdefincija, hogy a
nvekmny mrtkegysge annak az objektumnak a trbeli mrete, amire a mutat mutat. gy pa+i
esetben a pa-hoz hozzads eltt i azoknak az objektumoknak a mretvel szorzdik, amire pa mutat.
Az indexels s a mutataritmetika kztt lthatan nagyon
szoros kapcsolat van. Gyakorlatilag a tmbre val hivatkozst a
fordt a tmb kezdett megcmz mutatv alaktja t. Ennek
hatsra a tmb neve nem ms, mint egy mutatkifejezs, amibl
szmos hasznos dolog kvetkezik. Mivel a tmb neve ugyanaz, mint
az illet tmb nulladik elemnek cme, a
pa = &a[0]
rtkads gy is rhat, mint
pa = a
Legalbbis els rnzsre mg meglepbb az a tny, hogy az a[i]-re trtn hivatkozs *(a+i)-knt is
rhat. a[i] kirtkelsekor a C fordt azonnal talaktja ezt *(a+i)-v; a kt alak teljesen egyenrtk.
Ha az ekvivalencia mindkt elemre alkalmazzuk az & opertort, akkor azonnal kvetkezik, hogy
&a[i] s a+i szintn azonosak: a+i az a-t kvet i-edik elem cme. Az rem msik oldala viszont az,
hogy ha pa mutat, akkor azt kifejezsek indexelhetik: pa[i] azonos *(pa+i)-vel. Rviden, brmilyen
tmb vagy indexkifejezs lerhat, mint egy mutat plusz egy eltols s viszont, akr egy utastson
bell is.
Van azonban egy fontos klnbsg a tmbnv s a mutat kztt, amire gyelnnk kell. A mutat
vltoz, gy pa=a s pa++ rtelmes mveletek. A tmbnv azonban lland, nem pedig vltoz: az
olyan konstrukcik, mint a=pa vagy a++, vagy p=&a nem megengedettek!
Amikor a tmbnv egy fggvnynek addik t, a fggvny valjban a tmb kezdetnek cmt kapja
meg. A hvott fggvnyen bell ez az argumentum vltoz, ugyangy, mint a tbbi, a
tmbnvargumentum teht csakugyan mutat, vagyis egy cmet tartalmaz vltoz. E tnyt kihasznlva
megrhatjuk az strlen karakterlnchossz-szmt fggvny j vltozatt:
strlen (s)

/*Visszaadja az s karakterlnc hosszt*/ char *s;

{
int n;
for (n = 0; *s != \0; s++)
n++;

93

Forrs: http://www.doksi.hu

return (n);
}
s inkrementlsa teljesen megengedett, mivel a mutatk vltozk;
s++-nak nincs hatsa az strlen hv fggvnybeli karakterlncra
csupn a cmnek az strlen-ben tallhat msolatt inkrementlja. Fggvnydefinciban
char s [];
s
char *s; egyarnt szerepelhet formlis paramterknt; azt, hogy melyiket hasznljuk, nagymrtkben az
dnti el, hogy miknt rjuk le a kifejezseket a fggvnyen bell. Amikor a tmbnv addik t
valamelyik fggvnynek, a fggvny tetszse szerint hiheti azt, hogy tmbt vagy mutatt kapott, s
ennek megfelelen kezelheti azt. Akr mindkt tpus mveletet hasznlhatja, ha ez clszernek s
vilgosnak ltszik.
Lehetsg van arra, hogy a tmbnek csupn egy rszt adjuk t
valamelyik fggvnynek oly mdon, hogy a rsztmb kezdett
megcmz mutatt adunk t. Ha pl. a egy tmb neve, akkor
f (&a[2])
s
f (a+2)
egyarnt az a[2] elem cmt adja t az f fggvnynek, mivel
&a[2] s a+2 egyarnt mutatkifejezs, mindkett az a tmb
harmadik elemre vonatkozik. f-en bell az argumentumdeklarci
akr
f (arr) int arr [];
{
...
}
akr f (arr) int *arr;
{
...
}
is lehet. Ami f-et illeti, az a tny, hogy az argumentum valjban egy nagyobb tmb egy rszre
vonatkozik, semmifle kvetkezmnnyel sem jr.
5.4.
Cmaritmetika
Ha p mutat, akkor p++ oly mdon inkrementlja p-t, hogy az a megcmzett tetszleges tpus
objektum kvetkez elemre, p += i pedig gy, hogy az a pillanatnyilag megcmzett elem utni iedik elemre mutasson. Az ilyen s hasonl szerkezetek a mutat- vagy cmaritmetika legegyszerbb
s legkznsgesebb formi.
A C nyelv kvetkezetes s szablyos mdon kzelt a
cmaritmetikhoz; a mutatk, tmbk s a cmaritmetika egysges kezelse a nyelv egyik legfbb
ernye. Szemlltessk ezt azzal, hogy megrunk egy elemi trfoglal programot (amely azonban
egyszersge ellenre is hasznlhat)! Kt rutinunk van: az alloc(n) rutin n egymst kvet
karakterpozcit megcmz p mutatt ad vissza, amelyet az alloc hvja karakterek trolsra
hasznlhat; tovbb free(p), amely felszabadtja az alloc rutinnal nyert trterletet ksbbi
hasznlat cljra. A rutinok elemiek, mivel free hvsai fordtott sorrendben kell, hogy
trtnjenek, mint az alloc hvsai. gy az alloc s a free ltal kezelt trterlet egy verem, vagyis egy
utols-be, els-ki (last-in, first-out) lista. A szabvnyos C knyvtrban rendelkezsre llnak az
ezeknek megfelel fggvnyek, amelyekre azonban nem vonatkoznak ilyen megszortsok, s a 8.
fejezetben is bemutatunk javtott vltozatokat. Addig azonban szmos alkalmazshoz megfelel a
trivilis alloc is, ha arra van szksgnk, hogy elre nem lthat mret kisebb trterletek elre
nem lthat idpontokban rendelkezsre lljanak. A legegyszerbb megvalstsban az alloc egy

94

Forrs: http://www.doksi.hu

allocbuf-nak nevezett nagy karaktertmb darabjait szolgltatja. Ez a tmb az alloc s a free


kizrlagos tulajdona. Mivel ez a kt rutin mutatkat s nem tmbindexeket hasznl, a tmb nevt
egyetlen ms rutinnak sem kell ismernie, gy az static extern-knt deklarlhat, vagyis csak az alloc
s a free fggvnyeket tartalmaz llomnyban lesz rvnyes s azon kvl lthatatlan. A
gyakorlatban akr nem is kell, hogy nvvel rendelkezzen a tmb: ehelyett gy is elllthat, hogy a
program az opercis rendszertl elkr valamilyen nv nlkli trblokkot megcmz mutatt.
Tudnunk kell azt is, hogy mennyi kerlt felhasznlsra allocbuf-bl. E clbl egy, a kvetkez
szabad elemet megcmz mutatt hasznlunk, amelynek neve allocp. Ha valaki az alloc-tl n
karaktert kr, akkor az ellenrzi, hogy maradt-e mg ennyi hely allocbuf-ban. Ha igen, akkor alloc
visszaadja az allocp pillanatnyi rtkt (vagyis a szabad blokk kezdcmt), majd azt n-nel
inkrementlja, hogy a kvetkez szabad terletre mutasson. free(p) egyszeren p-re lltja be
allo_p-t, ha p az allocbuf-on bell van.
#define NULL 0 /*Mutat a hibajelzshez*/
#define ALLOCSIZE 1000
/*A rendelkezsre ll terlet
mrete*/
static char allocbuf [ALLOCSIZE];

/*Trhely

alloc-nak*/
static char *allocp = allocbuf;
char *alloc (n)

/*Kv. szabad hely*/

/*n karaktert megcmz mutatt ad vissza*/

int n;
{
if (allocp + n <= allocbuf + ALLOCSIZE) {

/*Befr*/ allocp += n;

return (allocp - n);


/*Rgi p*/
} else /*Nincs elg hely*/
return (NULL);
}
free (p)

/*p ltal megcmzett terlet felszabadtsa*/ char *p;

{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE) allocp = p;
}
Nhny megjegyzs: ltalban a mutat ppen gy
inicializlhat, mint brmilyen ms vltoz, noha kznsges
esetben rtelmes rtk csupn a NULL (l. a tovbbiakban) vagy
olyan kifejezs lehet, amely a korbban definilt megfelel
tpus adatok cmeit tartalmazza. A
static char *allocp = allocbuf; deklarci gy definilja allocp-t, hogy az karaktermutat legyen, s gy
inicializlja, hogy allocbuf-ra mutasson, amely a kvetkez szabad pozci a program indtsakor. Ezt
gy is rhattuk volna, hogy:
static char *allocp = &allocbuf [0]; mivel a tmb neve egyben a nulladik elemnek a cme; mindig a
termszetesebb vltozatot hasznljuk!
Az
if (allocp + n <= allocbuf + ALLOCSIZE)
vizsglat ellenrzi, hogy van-e elegend hely az n szm karakter elhelyezsre vonatkoz krs
teljestsre. Ha igen, akkor az allocp j rtke legfeljebb eggyel mutat tl az allocbuf vgn. Ha a
krs kielgthet, az alloc kznsges mutatval tr vissza (figyeljk meg magnak a fggvnynek a
deklarcijt). Ha a krs nem teljesthet, akkor az alloc-nak valamilyen jel visszaadsval kell
jeleznie, hogy nem maradt hely. A C nyelv gondoskodik arrl, hogy semmifle olyan mutat, amely

95

Forrs: http://www.doksi.hu

rvnyes mdon adatra mutat, nem tartalmazhat nullt, gy a nulla visszatrsi rtk hasznlhat az
abnormlis esemny jelzsre, adott esetben annak kzlsre, hogy nincs hely. Szmszer nulla helyett
azonban NULL-t runk, hogy ezzel vilgosabban jelezzk : ez a mutat klnleges rtke. ltalban
egsz szmok nem rendelhetk rtelmes mdon mutatkhoz, a nulla specilis eset.
Az olyan vizsglatok, mint
if (alloc + n <= allocbuf + ALLOCSIZE)
s
if (p >= allocbuf && p < allocbuf + ALLOCSIZE) a mutataritmetika lnyeges sajtossgaira
vilgtanak r. Elszr is, a mutatk bizonyos krlmnyek kztt sszehasonlthatk. Ha p s q
ugyanannak a tmbnek az elemeire mutat, akkor az olyan relcik, mint <, >= stb. megfelelen
mkdnek.
P < q pl. akkor igaz, ha p a tmb kisebb sorszm elemre mutat, mint q. Az == s != relcik
ugyancsak alkalmazhatk. Brmilyen mutat nullval val egyenlsge vagy nemegyenlsge rtelmes
mdon ellenrizhet. Vigyzat! Ne vgezznk viszont klnbz tmbket megcmz mutatkkal
aritmetikai mveleteket vagy sszehasonltsokat! Ha szerencsnk van, akkor minden gpen
nyilvnval rtelmetlensget kapunk. Ha azonban nincs szerencsnk, akkor a programunk mkdni fog
az egyik gpen, de rejtlyes mdon ssze fog omlani egy msikon.
Msodszor lttuk, hogy az egsz szmot megcmz mutatkkal sszeads s kivons vgezhet.
p + n a p ltal ppen megcmzett objektumot kvet n-edik objektumot jelenti. Ez igaz, fggetlenl
attl, hogy a p-t milyen tpus objektumot megcmz mutatnak deklarltuk: a fordt n-et olyan
egysgekben szmllja, amelyek megfelelnek a p ltal megcmzett objektum mretnek, amely utbbit p
deklarcija hatrozza meg. A PDP-11-en pldul a mretfaktor char esetben 1 short-nl 2, long s
float esetn 4 s double esetn 8.
Mutatk kivonsa szintn megengedett: ha p s q ugyanannak a tmbnek az elemeire mutatnak, akkor p
- q a p s q kztti elemek darabszma. E tnyt kihasznlva megrhatjuk az strlen jabb vltozatt:
strlen (s)

/*Visszaadja az s karakterlnc hosszt*/ char *s;

{
char *p = s;
while (*p != \0)
p++;
return (p - s);
}
A deklarciban p kezdeti rtkeknt s-et adtuk meg, vagyis p kezdetben az s els karakterre mutat. A
while ciklusban addig vizsgljuk az egymst kvet karaktereket, amg a vget jelz \0 el nem kerl.
Mivel \0 rtke nulla, s mivel a while csupn azt vizsglja, hogy a kifejezs nulla-e, elhagyhat az
explicit vizsglat. Az ilyen ciklusokat gyakran az albbi alakban rjk:
while (*p) p++;
Minthogy p karakterekre mutat, p++ minden alkalommal a kvetkez karakterre lpteti p-t, s p - s az
tlpett karakterek szmt, vagyis a karakterlnc hosszt adja meg. A mutataritmetika kvetkezetes: ha
float mennyisgekkel dolgoznnk, amelyek a char-oknl tbb trterletet foglalnak el, s ha p float-ot
megcmz mutat lenne, akkor p++ a kvetkez float-ra lptetne. gy az alloc msik vltozatt, amely
pl. char-ok helyett float vltozkkal dolgozik, egyszeren gy rhatjuk meg, hogy az alloc-ban s freeben vgig float-okra cserljk a char vltozkat. Az sszes mutatmvelet automatikusan szmtsba
veszi a megcmzett objektum mrett, gy semmi egyebet nem kell megvltoztatni.
Az emltett mveleteken kvl (mutat s integer sszeadsa s kivonsa, kt mutat kivonsa s
sszehasonltsa) minden ms mutatmvelet tilos! Nincs megengedve kt mutat sszeadsa, szorzsa,
osztsa, mutatk lptetse, maszkolsa, sem pedig float vagy double mennyisgeknek mutatkhoz
trtn hozzadsa.
5.5.
Az

Karaktermutatk s fggvnyek

96

Forrs: http://www.doksi.hu

Ez itt egy karakterlnc alak karakterlnclland nem ms, mint egy karaktertmb. A fordt a bels
brzolsban a tmbt a \0 karakterrel zrja le, hogy a programok megtallhassk a karakterlnc vgt.
A trterlet hossza teht eggyel nagyobb, mint az idzjelek kztti karakterek szma.
A karakterlnc-lland leggyakrabban taln
fggvnyargumentumokban fordul el, mint pl.
printf (Figyelem, emberek\n);
A programban ily mdon megjelen karakterlnc karaktermutatn keresztl rhet el; printf a
karaktertmbt megcmz mutatt kap.
A karaktertmbknek termszetesen nem kell felttlenl deklarlja, akkor a
message = now is the time;
/*Ideje*/ utasts message-hez a tnyleges karaktereket megcmz
mutatt rendel hozz. Ez nem karakterlnc-msols, a dolog csak a mutatkat rinti.
A C nyelvben nincsen olyan opertor, amellyel teljes karakterlncot egy egysgknt dolgozhatnnk fel.
A mutatk s tmbk tovbbi vonatkozsait a 7. fejezetben ismertetend szabvnyos be- s kiviteli
(I/O) knyvtr kt hasznos fggvnyn keresztl mutatjuk be.
Az els fggvny az strcpy(s, t), amely a t karakterlncot az
s karakterlncba msolja. Az argumentumokat az rtkadshoz val
hasonlsg miatt rtuk ebben a sorrendben, hiszen a t
karakterlncnak az s karakterlnchoz trtn hozzrendelsekor
azt mondannk, hogy
s=t
Elszr a tmbs vltozatot mutatjuk be:
strcpy (s, t) /*t msolsa s-be*/
char s [], t [];
{
int i;
i = 0;
while ((s [i] =t [i]) != \0)
i++;
}
sszehasonltsul me az strcpy mutatval rt vltozata:
strcpy (s, t)

/*t msolsa s-be;

1. mutatt alkalmaz vltozat*/ char *s, *t;


{
while ((*s = *t) != \0) {
s++;
t++;
}
}
Mivel az argumentumok tadsa rtk szerint trtnik, strcpy tetszs szerinti mdon hasznlhatja s-t s
t-t. Az adott esetben ezek alkalmas mdon inicializlt mutatk, amelyek karakterenknt vgighaladnak
a tmbkn, amg a t-t lezr \0 t nem msoldik s-be.
A gyakorlatban strcpy-t nem az elbb bemutatott mdon rnnk meg. Egy msik lehetsg pl. :
strcpy (s, t)

/*t msolsa s-be;

2. mutatt alkalmaz vltozat*/ char *s, *t;


{
while ((*s++ = *t++) != \0)
;

97

Forrs: http://www.doksi.hu

}
Ez a programkd s s t inkrementlst a felttelvizsglatba helyezi t. *t++ rtke az a karakter,
amire t inkrementls eltt mutatott; a ++ postfixum mindaddig nem vltoztatja meg t-t, amg ez a
karakter feldolgozsra nem kerlt. Hasonlkppen, s inkrementlsa eltt a karakter a rgi s pozciban
troldik. Egyben ez a karakter lesz az az rtk, amelyet a ciklusvezrls rdekben \0-val
sszehasonltunk. Vgeredmnyben a karakterek a zr \0-ig, a zr \0-t is belertve tmsoldnak t-bl
s-be. Vgs lervidtsknt vegyk ismt szre, hogy a \0-val val sszehasonlts redundns, ezrt a
fggvny gyakran gy jelenik meg:
strcpy (s, t)

/*t msolsa s-be;

3. mutatt alkalmaz vltozat*/ char *s, *t;


{
while (*s++ = *t++)
;
}
Br els rnzsre titokzatosnak tnhet, ez a jells nagyon knyelmes, s mr csak azrt is el kell
sajttanunk, mert gyakran tallkozunk vele C programokban.
A msik rutin az strcmp(s, t), amely sszehasonltja az s s t karakterlncokat, s negatv szmot, nullt
vagy pozitv szmot ad vissza aszerint, hogy s lexikografikusan kisebb, mint t, egyenl t-vel vagy
nagyobb, mint t. A visszaadott rtket gy nyerjk, hogy az els olyan pozcin, ahol s s t nem
egyeznek meg, kivonjuk egymsbl a karaktereket.
strcmp (s, t)

/*A visszatr rtk < 0, ha s < t;


0, ha s == t, > 0, ha s > t*/

char s [], t [];


{
int i;
i = 0;
while (s [i] == t [i])
if (s [i++] == \0)
return (0); return (s [i] - t [i]);
}
Az strcmp mutat alkalmazsval:
strcmp (s, t)

/*A visszatr rtk < 0, ha s < t;


0, ha s == t; > 0, ha s > t*/

char *s, *t;


{
for (; *s == *t; s++,t++)
if (*s == \0)
return (0); return (*s - *t);
}
Mivel ++ s -- akr prefix, akr postfix opertorok lehetnek, ritkbban ugyan, de a * s ++, ill.ms
kombincii is elfordulhatnak. Pl.
*++p p-t mg azeltt inkrementlja, hogy a p ltal megcmzett karakterhez val hozzfrs
megtrtnne.
*--p elszr dekrementlja p-t.
5.2.
Gyakorlat. rjuk t a 2. fejezetben bemutatott strcat fggvnyt mutat alkalmazsval (strcat(s,
t) a t karakterlncot az s karakterlnc vgre msolja)!
5.3.
Gyakorlat. rjunk makrt strcpy-ra!

98

Forrs: http://www.doksi.hu

5.4.
Gyakorlat. rjuk t a korbbi fejezetek erre alkalmas programjait s gyakorlatait gy, hogy
tmbindexels helyett mutatkat hasznlunk! J lehetsg pl. a getline (l. az 1. s
4. fejezetet), az atoi az itoa s vltozataik (l. a 2., 3., 4. fejezetet), valamint az index s a getop (4.
fejezet).
5.6.
A mutatk nem egsz szmok
Rgebbi C programok igen liberlisan kezeltk a mutatk msolsnak krdst. ltalban a
legtbb gpen a mutatt hozz lehetett rendelni egy egsz tpus_ mennyisghez s viszont, anlkl,
hogy maga a mutat megvltozott volna sem mretszmts, sem konverzi nem trtnt, nem
vesztek el bitek. Sajnos azonban ez oda vezetett, hogy sokan szabadosan kezeltk a mutatkat
visszaad rutinokat, s a kapott mutatkat egyszeren ms rutinoknak adtk t gyakran elmulasztva
a szksges mutatdeklarcikat. Tekintsk pl. az strsave(s) fggvnyt, amely az alloc hvsval
kapott biztos helyre msolja az s karakterlncot, majd az azt megcmz mutatval tr vissza. E
program helyesen gy fest :
char *strsave (s)

/*Elmenti az s karakterlncot*/ char *s;

{
char *p, *alloc (); if ((p = alloc (strlen (s) + 1)) != NULL) strcpy (p, s); return (p);
}
A gyakorlatban ers a ksrts, hogy elhagyjuk a deklarcikat:
strsave (s)

/*Elmenti az s karakterlncot*/

{
char *p; if ((p = alloc (strlen (s) + 1)) != NULL) strcpy (p, s); return (p);
}
Ez sok gpen mkdni fog, mivel a fggvnyek s argumentumok alaprtelmezs szerinti tpusa int, s
az int-ek s mutatk kztt ltalban mindkt irnyban biztonsgosan vgezhet hozzrendels. Mgis,
az ilyenfajta programkd hasznlata kockzatos, mivel hatsa az adott nyelvi megvalststl s a gpi
architektrtl fgg, s gy az ltalunk ppen hasznlt fordt esetben esetleg nem a vrt mdon
mkdik. sszerbb teht, ha minden egyes deklarcit kirunk. (Ha errl mgis elfeledkeznnk, a lint
program figyelmeztet az ilyen esetekre.)
5.7.
Tbbdimenzis tmbk
A C nyelv mtrixjelleg tbbdimenzis tmbk hasznlatt is megengedi, noha a gyakorlatban
ilyeneket sokkal ritkbban hasznlunk, mint mutattmbket. Ebben a szakaszban ezek nhny
tulajdonsgt mutatjuk be.
Tekintsk a dtumkonverzi problmjt: a hnap adott napjnak az v egy napjv s vissza
trtn alaktst. Pldnak okrt a mrcius 1. nem szkvekben a 60., szkvekben a 61. nap.
Az talaktsok elvgzsre definiljunk kt fggvnyt: day_of_year a hnapot s napot az v
napjv, mg month_day az v adott napjt hnapp s napp alaktja t. Mivel az utbbi fggvny
kt rtkkel tr vissza, a hnap s a nap argumentum mutat lesz:
month_day (1977, 60, &m, &d) hatsra m 3 s d 1 lesz (mrcius 1 .).
Mindkt fggvnynek ugyanarra az informcira van szksge, tudniillik az egyes hnapok
napjainak szmt tartalmaz tblzatra. Mivel a hnapokban lev napok szma eltr a
szkvekben s a nem szkvekben, egyszerbb, ha ezeket egy ktdimenzis tmb kt sorban
elklntjk, mint ha a szmts sorn prblnnk nyomonkvetni, hogy mi is trtnik februrban.
A tmb s az talaktsokat vgz fggvnyek a kvetkezk :
static int day_tab [2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

99

Forrs: http://www.doksi.hu

day_of_year (year, month, day)

/*Az ven belli


napsorszm kiszmtsa
a hnapbl s napbl*/

int year, month, day;


{
int i, leap;
leap = year % 4 == 0 && year % 100 != 0
|| year % 400 == 0; for (i = 1; i < month; i++) day += day_tab [leap][i]; return (day);
}
month_day (year, yerday, pmonth, pday)

/*Hnap s nap
kiszmtsa az*/
int year, yearday, *pmonth, *pday; /*v adott sorszm
napjbl*/
{
int i, leap;
leap = year % 4 == 0 && year % 100 != 0
|| year % 400 == 0; for (i = 1; yearday > day_tab [leap][i]; i++) yearday -= day_tab [leap][i];
*pmonth = i;
*pday = yearday;
}
A day_tab tmbnek kvl kell lennie mind a day_of_year, mind pedig a month_day fggvnyen, hogy
mindketten hasznlhassk. A day_tab az els ktdimenzis tmb, amellyel eddig tallkoztunk. A Cben definci szerint a ktdimenzis tmb valjban olyan egydimenzis tmb, amelynek minden eleme
tmb.
Ezrt rjuk az indexeket
day_tab [i][j]
nem pedig
day_tab [i,j] alakban, mint a legtbb ms nyelvben. Ettl eltekintve a ktdimenzis tmb ugyangy
kezelhet, mint a tbbi nyelvben. Az elemek soronknt troldnak, vagyis a legjobboldalibb index
vltozik a leggyorsabban, amikor az elemekhez a trols sorrendjben trtnik hozzfrs.
A tmbt a kezdeti rtkek kapcsos zrjelek kz zrt
listjval inicializljuk; a ktdimenzis tmb minden sort a
megfelel allista inicializlja. A day_tab tmbt egy nullkat
tartalmaz oszloppal kezdtk, hogy a hnapszmok ne 0-tl 11
ig, hanem a megszokott mdon 1 -tl 12-ig fussanak. Mivel az adott esetben az elfoglalt trhely
mennyisge nem lnyeges, ez a megolds egyszerbb, mint az indexek kiigaztsa. Ha a
ktdimenzis tmbt fggvnynek kell tadni, a fggvnybeli argumentumdeklarcinak
tartalmaznia kell az oszlopmretet; a sormret kzmbs, mivel mint korbban, most is mutatt
adunk t. Az adott esetben ez a 13 int-et tartalmaz tmbkre mint objektumokra mutat. gy, ha
a day_tab tmbt kell tadni az f fggvnynek, akkor f deklarcija:
f (day_tab) int day_tab [2][13];
{
...
}
Az f-beli argumentumdeklarci lehetne
int day_tab [][13];

100

Forrs: http://www.doksi.hu

is, mivel a sorok szma kzmbs, vagy lehetne


int (*day_tab)[13];
amely azt fejezi ki, hogy az argumentum egy 13 egszbl ll
tmbt jell mutat. A zrjelek szksgesek, mivel [ ]
(szgletes zrjelek) precedencija nagyobb, mint a *
szimblum, gy zrjelek nlkl az
int *day_tab [13]; deklarci egy 13 darab, egszt megcmz mutatbl ll tmbt jelent, amint ezt a
kvetkezkben ltni fogjuk.
5.8.
Mutattmbk; mutatkat megcmz mutatk
Mivel a mutatk maguk is vltozk, joggal vrhat, hogy mutatkbl ll tmbk is hasznlhatk.
Ez valban gy van. E lehetsget olyan program megrsn keresztl mutatjuk be, amely egy
szvegsorokbl ll halmazt alfabetikus sorrendbe rendez: ez a UNIX-beli sort rendez
segdprogram egyszerstett vltozata. A 3. fejezetben bemutattuk a Shell sort fggvnyt, amely
egszekbl ll tmbt rendez. Ugyanez az algoritmus fog itt is mkdni, attl eltekintve, hogy
most szvegsorokkal kell foglalkoznunk, amelyek klnbz hosszsgak, s az egszektl
eltren nem hasonlthatk ssze, s egyetlen mvelettel nem mozgathatk. Olyan adatbrzolsra
van szksgnk, amely hatkonyan s knyelmesen brkzik meg vltoz hosszsg
szvegsorokkal.
Itt lpnek be a mutatkbl ll tmbk. Ha a rendezend sorokat elejtl vgig egyetlen hossz
karaktertmbben troljuk (amelyet esetleg az alloc kezel), akkor minden sor elrhet az els
karaktert megcmz mutatn keresztl. Maguk a mutatk egy tmbben trolhatk. Kt sor oly
mdon hasonlthat ssze, hogy mutatikat tadjuk strcmp-nek. Ha kt, nem megfelel sorrendben
lev sort meg kell cserlni, akkor a mutattmbben lev mutatk cserldnek fel, nem pedig maguk
a szvegsorok. Ezltal elkerljk azt a kt sszetartoz problmt, amit a bonyolult trkezels s a
tnyleges szvegsorok mozgatsval egyttjr nagy megterhels jelentene.
A rendezs folyamata hrom lpsbl tevdik ssze:
az sszes bemeneti sor beolvassa,
a beolvasott sorok rendezse,
a helyes sorrendben trtn kinyomtats.
Szoks szerint legclszerbb, ha a programot olyan fggvnyekre bontjuk fel, amelyek ezt a
termszetes felosztst kvetik, s a frutin vgzi a folyamat vezrlst.
Egy pillanatra hagyjuk a rendezsi lpst s sszpontostsunk az adatstruktrra, valamint a be- s
kivitelre. A bemeneti rutinnak ssze kell gyjtenie, majd trolnia kell az egyes sorok karaktereit s
ssze kell lltania a sorokat megcmz mutatk tmbjt. Ugyancsak a bemeneti rutinnak kell
megszmllnia a berkez sorokat, mivel erre az informcira a rendezskor s nyomtatskor szksg
lesz. Tekintve, hogy a beolvasfggvny csak vges szm bemeneti sorral tud megbrkzni,
valamifle nemltez sor-darabszmot, pl. -1-et ad vissza, ha tl sok szveg rkezett. A kimeneti
rutinnak abban a sorrendben kell kinyomtatnia a sorokat, amelyben azok a mutatk tmbjben
megjelennek.
#define NULL 0
#define LINES 100
/*A rendezend sorok max. szma*/
main () /*Beolvasott sorok rendezse*/
{
char * lineptr [LINES];
/*A szvegsorokatmegcmz
mutatk*/ int nlines; /*A beolvasott sorok szma*/ if ((nlines = readlines (lineptr, LINES)) >= 0)
{ sort (lineptr, nlines); writelines (lineptr, nlines);
}
else printf (a bemenet tl nagy a rendezshez \n);
}
#define MAXLEN 1000

101

Forrs: http://www.doksi.hu

readlines (lineptr, maxlines)


/*Sorok beolvassa*/
char *lineptr []; /*Rendezshez*/
int maxlines;
{
int len, nlines;
char *p, *alloc (), line [MAXLEN];
nlines = 0;
while ((len = getline (line, MAXLEN)) > 0) if (nlines >= maxlines)
return (-1); else if ((p = alloc (len)) == NULL)
return(-1);
else {
line [len - 1] = \0;

/*Az jsort levgja*/ strcpy (p, line); lineptr [nlines++] = p;

}
return (nlines);
}
A sorok vgn tallhat jsor karakterek trldnek, gy nem befolysoljk a rendezsi sorrendet.
writelines (lineptr, nlines)

/*A kimenetre kerl

sorok kirsa*/ char *lineptr []; int nlines;


{
int i;
for (i = 0; i < nlines; i++)
printf (%s \n, lineptr [i]);
}
A legfontosabb j dolog lineptr deklarcija:
char *lineptr [LINES]; azt jelenti, hogy a lineptr egy LINES szm elembl ll, mutatkat tartalmaz
tmb, amelynek minden eleme egy-egy char-ra mutat. Ms szval lineptr [i] karaktermutat, s *lineptr
[i] egy karakterhez fr hozz.
Mivel lineptr tmb, amelyet writelines-nak adunk t, pontosan ugyangy kezelhetjk mutatknt, mint
azt a korbbi pldkban lttuk. A fggvny teht gy is rhat:
writelines (lineptr, nlines)

/*A kimenetre kerl

sorok krsa*/ char *lineptr []; int nlines;


{
while (--nlines >= 0)
printf (%s \n, *lineptr++);
}
A *lineptr kezdetben az els sorra mutat; minden inkrementls a kvetkez sorra lpteti, mikzben
nlines-t leszmlljuk. Most, hogy a be- s kimenet a keznkben van, rtrhetnk a rendezsre. A 3.
fejezetben ltott Shell rendezprogramot kismrtkben meg kell vltoztatnunk: mdostani kell a
deklarcikat, s az sszehasonlts mvelett kln fggvnyben kell elhelyezni. Az alapvet
algoritmus vltozatlan, ezrt bzhatunk abban, hogy a program tovbbra is mkdni fog.
sort (v, n)

/*A v [0] ... v [n - 1] karakterlncok


rendezse nvekv sorrendben*/

char *v [];
int n;
{
int gap, i, j;
char *temp;
for (gap = n/2; gap > 0; gap /= 2)

102

Forrs: http://www.doksi.hu

for (i = gap; i < n; i++)


for (j = i - gap; j >= 0; j -= gap) { if (strcmp (v [j], v [j + gap]) <=0)
break; temp = v [j]; v [j] = v [j + gap]; v [j + gap] = temp;
}
}
Mivel v (azaz lineptr) minden egyes eleme karaktermutat, temp-nek is annak kell lennie, hogy az
egyik a msikba msolhat legyen.
A programot a lehet legegyszerbbre rtuk meg, hogy minl gyorsabban el tudjuk indtani. Lehetne
azonban gyorsabb is, ha pl. a bejv sorokat kzvetlenl a readlines ltal karbantartott tmbbe
msolnnk, nem pedig elszr a line-ba, majd az alloc ltal kezelt, rejtett helyre. Az els vltozatot
azonban blcsebb gy megrni, hogy minl rthetbb legyen. A hatkonysggal rrnk ksbb
foglalkozni. Programunkon valsznleg nem sokat gyorstana, ha kikszblnnk a bemeneti sorok
szksgtelen tmsolst. Lnyeges javulst csak az hozhat, ha a Shell sort programjt valami jobbal,
pl. a quicksort programmal cserljk fel.
Az 1. fejezetben rmutattunk, hogy mivel a while s a for ciklusok a vgfelttelt a ciklustrzs els
vgrehajtsa eltt vizsgljk, hozzjrulnak ahhoz, hogy a programok a lehet leggyorsabban
mkdjenek, klnsen, ha nincs bemenet. Tanulsgos, ha vgigmegynk a rendezprogram
fggvnyein, s megvizsgljuk, mi trtnik, ha egyltaln nincs bemeneti szveg.
5.5.
Gyakorlat. rjuk jra a readlines fggvnyt oly mdon, hogy a sorokat a main ltal adott
tmbben hozzuk ltre s nem az alloc-ot hvjuk a tr karbantartsa cljbl! Mennyivel gyorsabb
gy a program?
5.9. Mutattmbk inicializlsa
rjuk meg a month_name(n) fggvnyt, amely egy olyan mutatt ad vissza, amely az n-edik
hnap nevt tartalmaz karakterlncra mutat. Ez a bels static tmb idelis alkalmazsa. A
month_name a karakterlncok szmra kln tmbt tartalmaz, s hvs utn a megfelel
karakterlncot megcmz mutatt adja vissza. E szakasz tmja az, hogy hogyan kell a nevek
tmbjt inicializlni.
A szintaxis hasonlt a korbbi inicializlsokra:
char *month_name (n) /*Visszaadja az n-edik hnap nevt*/ int n;
{
static char *name [] = {
nem ltez hnap,
janur,
februr,
mrcius,
prilis,
mjus,
jnius,
jlius,
augusztus,
szeptember,
oktber,
november,
december
}
return ((n < 1 || n > 12) ? name [0] : name [n]);
}
A name karaktermutatkbl ll tmb. Deklarcija ugyanaz, mint lineptr- a rendezsi pldban. A
kezdeti rtk egyszeren a karakterlncok listja; mindegyik hozz van rendelve a tmb megfelel
pozcijhoz. Pontosabban szlva az i-edik karakterlnc karakterei valamilyen ms helyre kerlnek, s
az ket megcmz mutat name [i]-ben tallhat. Mivel a tmb mrete nincs megadva, maga a fordt
szmllja meg a kezdeti rtkeket s tlti be a helyes darabszmot.

103

Forrs: http://www.doksi.hu

5.10. Mutatk s tbbdimenzis tmbk


A kezd C programozkat gyakran megzavarja a ktdimenzis
tmbk s az olyan mutattmbk kztti klnbsg, mint amilyen
a fenti pldban name volt. Pl. az
int a [10][10]; int *b [10];
deklarcikban a s b hasznlata ugyan hasonl, amennyiben a[5] [5] s b[5] [5] egyarnt egy bizonyos
int-re trtn megengedett hivatkozsok. a azonban igazi tmb : 100 trrekeszt foglaltunk le szmra,
egy adott elemt a hagyomnyos mtrixszer indexszmtssal vlaszthatjuk ki. b esetben azonban a
deklarci csupn 10 mutatt foglal le: ezek mindegyikt gy kell belltani, hogy egy-egy egszekbl
ll tmbre mutasson. Feltve, hogy mindegyikk egy-egy tzelem tmbre mutat, 100 trrekeszt
foglaltunk le, ezenkvl tovbbi tz rekeszre van szksg a mutatk szmra. gy a mutatkbl ll tmb
valamivel tbb terletet foglal el, s explicit inicializlst ignyelhet. Van azonban kt elnye: egyrszt
az elemeket nem szorzssal s sszeadssal, hanem mutatn keresztl, indirekt mdon rjk el,
msrszt a tmb sorai klnbz hosszsgak lehetnek. gy nem szksges, hogy b minden eleme egyegy tzelem vektorra mutasson: lehet kztk amelyik kt elemre, esetleg hszra, st amelyik egyetlen
elemre sem mutat.
Br az elbbi fejtegetsben egszekrl beszltnk, a mutattmbk hasznlatnak messze leggyakoribb
esete az, amelyet a month_name-ben mutattunk be: klnbz hosszsg karakterlncok kezelse.
5.6.
Gyakorlat. rjuk t a day_of_year s a month_day rutint oly mdon, hogy indexels helyett
mutatkat hasznljunk!
5.11. Parancssor-argumentumok
A C nyelvet tmogat krnyezetekben lehetsg van arra, hogy a vgrehajts megkezdsekor a
programnak parancssor-argumentumokat vagy paramtereket adjunk t. Amikor a vgrehajts
megkezdsekor main-t meghvjuk, a hvsban kt argumentum szerepel. Az els (amit szoks
szerint argc-nek neveznk) azoknak a parancssor-argumentumoknak a darabszma, amelyekkel a
programot meghvtuk. A msodik argumentum (argv) egy mutat: ez arra a karakterlnc-tmbre
mutat, amely az elbbi argumentumokat tartalmazza. Egy karakterlnc egy argumentumnak felel
meg. E karakterlncok kezelse a tbbszrs mlysg mutathasznlat tipikus esete.
A tbbszint mutathasznlathoz szksges deklarciknak, a
mdszer alkalmazsnak legegyszerbb szemlltet pldja az echo
program, amely egyszeren megismtli (visszhangozza) az egy
sorban megjelen, szkzkkel elvlasztott
parancssor-argumentumokat. Vagyis, ha kiadjuk az
echo Figyelem, emberek
parancsot, akkor a kimeneten
Figyelem, emberek jelenik meg.
Megllapods szerint argv [0] az a nv, amellyel a programot hvtk, gy argc legalbb 1 . Az elbbi
pldban argc 3 s argv[0], argv [1], ill. argv [2] sorra echo, Figyelem s emberek. Az els igazi
argumentum argv [1] s az utols argv[n-1]. Ha argc rtke 1, akkor a program nevt nem kvetik
parancssor-argumentumok. Mindezt az echo programban mutatjuk be:
main (argc, argv)

/*Visszhangozza az argumentumokat

1. vltozat*/ int argc; char *argv [];


{
int i;
for (i = 1; i < argc; i++)
printf (%s %c, argv [i], (i < argc-1) ? : \n);
}
Mivel argv mutattmbt megcmz mutat, tbbflekppen is megrhatjuk ezt a programot gy, hogy
a tmb indexelse helyett a mutatt kezeljk. Lssunk kt vltozatot :

104

Forrs: http://www.doksi.hu

main (argc, argv) /*Visszhangozza az argumentumokat ;


2. vltozat*/ int argc; char *argv [];
{
while (--argc > 0) printf (%s %c, *++argv,(argc > 1) ? : \n);
}
Mivel argv az argumentum-karakterlncok tmbjnek kezdett megcmz mutat, 1-gyel trtn
inkrementlsnak (++argv) hatsra argv[0] helyett az eredeti argv[1]-re fog mutatni. Az egymst
kvet inkrementlsok hatsra mindig a kvetkez argumentumra lp; *argv az illet argumentumot
megcmz mutat. Ezzel egyidejleg argc dekrementldik: amikor nullv vlik, nincs tbb
kinyomtatand argumentum.
Egy msik vltozat :
main (argc, argv)

/*Visszhangozza az argumentumokat

3. vltozat*/ int argc; char *argv [];


{
while (--argc > 0) printf ((argc > 1) ? %s : %s \n, *++argv);
}
Ez a vltozat azt mutatja be, hogy a printf formtumargumentuma ppgy lehet kifejezs, mint
brmilyen ms fggvny. Ez a fajta hasznlat nem tl gyakori, de rdemes r emlkezni. Msodik
pldaknt vgezznk nhny javtst a 4. fejezet mintakeres programjban. Taln emlkeznk arra,
hogy a keressi minta mlyen a programon bell helyezkedett el, ami nem valami kellemes megolds.
Az UNIX grep segdprogramjnak fonalt kvetve vltoztassuk meg a programot oly mdon, hogy az
sszehasonltand mintt a parancssor els argumentuma adja meg.
#define MAXLINE 1000
main (argc, argv)

/*Megkeresi az 1. argumentum

szerinti mintt*/ int argc; char *argv [];


{
char line [MAXLINE];
if (argc != 2)
printf (Mintakeress \n);
else
while (getline (line, MAXLINE) > 0)
if (index (line, argv [1]) >= 0) printf (%s, line);
}
Most kidolgozhatjuk az alapmodellt, amivel a tovbbi mutatalkalmazsokat szemlltethetjk. Tegyk
fel, hogy kt opcionlis (szabadon vlaszthat) argumentumot engednk meg. Az egyik azt
mondja,hogy nyomtass ki minden sort, kivve azokat, amelyek illeszkednek a mintra, mg a msodik
azt mondja, rd minden kinyomtatott sor el annak sorszmt.
A C programokban a mnusz jellel kezdd argumentumok
megllapodsszeren opcionlis jelzt (flaget) vagy paramtert
jelentenek. Ha teht az inverzi (a kivve, a fordtottsg)
jellsre -x-et vlasztunk, s a sorszmozst -n-nel krjk,
akkor a
find -x -n the
parancs a
Now is the time
for all good men

105

Forrs: http://www.doksi.hu

to come to the aid


of their party.
bemeneti szveg esetn a
2: for all good men kimenetet fogja eredmnyezni.
Az opcionlis argumentumok sorrendje tetszleges kell, hogy legyen, s a program tovbbi rsznek
nem szabad fggenie a tnylegesen megadott argumentumok szmtl. Az adott esetben az index
hvsnak nem szabad argv[2]-re hivatkoznia olyankor, amikor csupn egyetlen opcionlis argumentum
volt, vagy argv[ 1 ]-re, ha egyltaln nem volt ilyen argumentum. A felhasznlk szmra knyelmes
tovbb, ha az opcionlis argumentumok konkatenlhatk, mint pl.:
find -nx the me a program:
#define MAXLINE 1000
main (argc, argv)

/*Megkeresi az 1. argumentum

szerinti mintt*/ int argc; char *argv [];


{
char line [MAXLINE], *s;
long lineno = 0;
int except = 0, number = 0;
while (--argc > 0 && (*++argv) [0] == -) for (s = argv [0] + 1; *s != \0; s++)
switch (*s) {
case x:
except = 1;
break;
case n:
number = 1;
break;
default:
printf (keress: illeglis opci %c \n, *s); argc = 0; break;
}
if (argc != 1)
printf (Mintakeress: -x -n \n);
else
while (getline (line, MAXLINE) > 0) {
lineno++; if ((index (line, *argv) >= 0) != except) { if (number)
printf (%1d: , lineno); printf (%s, line);
}
}
}
argv minden egyes opcionlis argumentum eltt inkrementldik, argc pedig dekrementldik. Ha
nincsenek hibk, akkor a ciklus vgn argc rtke 1 s *argv a mintra mutat. Vegyk szre, hogy
*++argv argumentum-karakterlncot megcmz mutat: (*++argv) [0] az els karaktere. A zrjelek
szksgesek, mivel nlklk a kifejezs *++(argv[0]) lenne, aminek az rtelme teljesen ms (s rossz).
Megengedett alak lenne mg *++argv is.
5.7.
Gyakorlat.rjuk meg az add nev programot, amely kirtkel egy, a parancssorban szerepl
fordtott lengyel alak kifejezst! Pldul add 2 3 4 + *
2 * (3+4)-et szmtja ki.
5.8.
Gyakorlat. Mdostsuk az entab s detab programokat
(amelyeket az 1. fejezetben gyakorlatknt rtunk meg) oly mdon, hogy az a tabultor stop-ok
listjt
argumentumokknt fogadja!
Argumentum
megadsnak hinyban a norml
tabultorbelltsokat hasznljuk!

106

Forrs: http://www.doksi.hu

5.9.
Gyakorlat. Bvtsk az entab s detab programokat gy, hogy elfogadjk az entab m +n
rvidtett jellst, amely az m-edik oszloptl kezdve minden n-edik oszlopon egy-egy tabultor
stop-ot jelent. Vlasszunk (a felhasznl szmra) knyelmes magatartst az alapesetre (default)!
5.10.
Gyakorlat. rjuk meg a tail nev programot, amely kinyomtatja az utols n bemeneti sort! Az n
alaprtelmezse legyen pl. 10, amit opcionlis argumentum vltoztathat meg, teht tail - n az utols
n sort nyomtatja ki. A programnak elfogadhatan kell viselkednie, fggetlenl attl, hogy mennyire
rtelmetlen a bemenet vagy n rtke. Irjuk meg gy a programot, hogy a legjobban kihasznlja a
rendelkezsre ll trterletet: a sorokat troljuk gy, mint a sort-ban, nem pedig rgztett mret
ktdimenzis tmbben!
5.12.Fggvnyeket megcmz mutatk
A C nyelvben maga a fggvny nem vltoz, de md vanfggvnyt megcmz mutat definilsra,
amellyel mveletek vgezhetk, fggvnyeknek tadhat, tmbkbe helyezhet stb. Mindezt a
fejezet korbbi rszben bemutatott rendezprogram mdostsval szemlltetjk: ha megadjuk a n opcionlis argumentumot, akkor a program nem lexikografikusan, hanem numerikusan rendezi a
bejv sorokat.
A rendezs gyakran hrom rszbl ll - sszehasonltsbl, amely tetszleges objektumpr
sorrendjt hatrozza meg, cserbl, amely megfordtja ezek sorrendjt s rendezalgoritmusbl,
amely mindaddig vgzi az sszehasonltsokat s cserket, amg az objektumok a helyes sorrendbe
nem kerlnek. Maga a rendezalgoritmus fggetlen az sszehasonltsi s felcserlsi mveletektl,
gy klnbz sszehasonlt s felcserl fggvnyeket tadva klnbz kritriumok szerint
rendezhetnk. Ezt az elvet alkalmazzuk az j rendezprogramban.
A korbbiaknak megfelelen kt sor lexikografikus sszehasonltst az strcmp, felcserlst pedig
a swap vgzi. Szksgnk lesz mg a numcmp rutinra, amely numerikus rtkk alapjn hasonlt
ssze kt sort, s strcmp-hez hasonlan valamifle feltteljelzst ad vissza. Ezt a hrom fggvnyt a
mainben deklarljuk, s az ket megcmz mutatkat adjuk t sort-nak. A sort viszont a mutatkon
keresztl hvja a fggvnyeket. Az argumentumokkal kapcsolatos hibafeldolgozst elhanyagoltuk,
hogy a f feladatokkal foglalkozhassunk.
#define LINES 100

/*A rendezend sorok


maximlis szma*/
main (argc, argv) /*Beolvasott sorok rendezse*/
int argc;
char *argv [];
{
char *lineptr [LINES]; /*Mutatk a szvegsorokra*/
int nlines;
/*A beolvasott sorok szma*/
int strcmp (), numcmp ();
/*sszehasonlt
fggvnyek*/
int swap ();
/*Felcserl fggvny*/
int numeric = 0;
/*1, ha a rendezs numerikus*/
if (argc > 1 && argv [1][0] == - && argv [1][1] == n) numeric = 1; if ((nlines = readlines
(lineptr, LINES)) >= 0) { if (numeric)
sort(lineptr, nlines, numcmp, swap);
else
sort (nlineptr, lines, strcmp, swap); writelines (lineptr, nlines);
} else printf (a bemenet tl nagy a rendezshez \n);
}
Az strcmp, numcmp s swap - fggvnyek cmei; mivel ezek bizonyosan fggvnyek, az & opertor
ugyangy nem szksges, mint ahogy nincs r szksg a tmbk neve eltt sem. A fordt gondoskodik
a fggvny cmnek tadsrl.
Msodik lpsben a sort-ot mdostjuk:
sort (v, n, comp, exch)

/*A v[0] ... v[n-1] karakterlncok

107

Forrs: http://www.doksi.hu

rendezse nvekv sorrendbe*/


char *v [];
int n;
int (*comp) () , (*exch) ();
{
int gap, i, j;
for (gap = n / 2; gap > 0; gap /= 2)
for (i = gap; i < n; i++)
for (j = i - gap; j >= 0; j -= gap) { if ((*comp) (v [j], v [j + gap]) <= 0)
break;
(*exch) (&v [j], &v [j + gap]);
}
}
Vizsgljuk meg a deklarcikat!
int (*comp) ()
azt fejezi ki, hogy a comp olyan fggvnyt megcmz mutat,
amely int-et ad vissza. Az els zrjelpr szksges, nlklk
int *comp ()
azt fejezn ki, hogy a comp olyan fggvny, amely int-et
megcmz mutatt ad vissza, ami egszen ms dolog. comp
hasznlata az
if ((*comp) (v [j],v [j + gap]) <= 0)
sorban sszhangban van a deklarcival: comp a fggvnyt
megcmz mutat, *comp a fggvny, s
(*comp) (v [j], v [j + gap]) annak hvsa. Ahhoz. hogy az sszetevk helyesen kapcsoldjanak, szksg
van a zrjelekre.
Korbban mr lttuk strcmp-t, amely kt karakterlncot hasonlt ssze. me numcmp amely vezet
numerikus rtkeik szerint hasonlt ssze kt karakterlncot :
numcmp (s1, s2)

/*s1 s s2 numerikus sszehasonltsa*/ char *s1 , *s2;

{
double atof (), v1 , v2;
v1 = atof (s1);
v2 = atof (s2);
if (v1 < v2)
return (-1);
else if (v1 > v2)
return (1);
else
return (0);
}
Az utols lps a kt mutat felcserlst vgz swap fggvny megrsa. Ezt kzvetlenl arra
alapozhatjuk, amit a fejezet korbbi rszben mr kzltnk:
swap (px, py) /* *px s *py felcserlse*/ char *px [], *py [];
{
char *temp;
temp = *px;
*px = *py;

108

Forrs: http://www.doksi.hu

*py = temp;
}
A rendezprogram tovbbi opcik egsz sorval egszthet ki; ezek kzl nhny rdekes gyakorlat
lehet.
5.11.
Gyakorlat. Mdostsuk a sort programot oly mdon, hogy kezelje -r-t, amely ellenttes irny
(cskken) rendezst r el! -r-nek termszetesen -n-nel is mkdnie kell!
5.12.
Gyakorlat. Illesszk hozz a -f opcit, amellyel egyestjk a kis- s nagybetket gy, hogy
azokat a rendezs sorn nem klnbztetjk meg: a kis- s nagybets adatokat egytt rendezzk,
teht a s A szomszdosknt jelennek meg, nem vlasztja el ket az egsz bc.
5.13.
Gyakorlat. Illesszk a fggvnyhez a -d (sztri rendezs) opcit, amely csak betket,
szmokat s szkzket hasonlt ssze! gyeljnk arra, hogy -f-fel egytt is mkdjn!
5.14.
Gyakorlat. Egsztsk ki a fggvnyt mezkezel szolgltatssal, amely lehetv teszi, hogy
sorokon bell kijellt mezkn is vgezhet legyen rendezs, mgpedig minden mezn egymstl
fggetlen opcikszlet szerint! (E knyv angol eredetijnek trgymutatjt kulcsszavakra -dffel
lapszmokra
n-nel rendeztk.)
_
6.

fejezet : Struktrk

A struktra egy vagy tbb, esetleg klnbz tpus vltoz egyttese, amelyeket az egyszer
kezelhetsg rdekben gyjtnk ssze. A struktrkat egyes nyelvekben, legismertebben a PASCALban rekordoknak nevezik.
A struktrt szemlltet hagyomnyos plda a brfizetsi lista: a dolgozt egy attributumkszlettel
jellemezzk, amelyben helyet kap az illet neve, cme, trsadalombiztostsi szma, bre stb. Ezek
nmelyike akr struktra is lehet: a nv, a cm vagy ppen a br maga is tbb rszbl llhat.
A struktrk klnsen a nagy mret programok esetben nyjtanak segtsget bonyolult
adathalmazok szervezsben, mivel sokszor lehetv teszik, hogy az sszetartoz vltozk egyttest
egy egysgknt, nem pedig klnll elemekknt kezeljk. Ebben a fejezetben megksreljk bemutatni
a struktrk hasznlatt. Mintaprogramjaink a knyvnkben megszokottaknl terjedelmesebbek
lesznek, de mg mindig elgszerny mretek.
6.1.
Alapfogalmak
Vegyk ismt el az 5. fejezetben trgyalt dtumkonverzis rutinokat. Egy-egy adat tbb rszbl
ll, ilyenek a nap, a hnap s az v, tovbb esetleg a nap sorszma az vben, s a hnap neve. Ez
az t vltoz az albbi mdon egyetlen struktrba foglalhat:
struct date {
int day; int month; int year; int yearday; char mon_name [4];
}
A struct kulcssz a struktra deklarcijt vezeti be, amely nem ms, mint egy kapcsos zrjelek kz
zrt deklarcilista. A struct kulcsszt struktracmke kvetheti (mint pl. az elbb a date). Ez egy nv,
amely megnevezi az adott tpus struktrt, s a tovbbiakban rvidtsknt hasznlhat a rszletes
deklarci helyett.
A struktrban elfordul elemeket, ill. vltozatokat tagoknak nevezzk. Valamely struktratagnak, ill.
-elemnek s egy kznsges (vagyis nem tag) vltoznak lehet ugyanaz a neve: ebbl nem szrmazik
zavar, mivel ezek a szvegkrnyezet alapjn mindig megklnbztethetk. Az mr termszetesen stlus
krdse, hogy az ember ugyanazokat a neveket csak szorosan sszetartoz objektumok esetben
hasznlja.
A tagok listjt lezr jobboldali zrjelet a vltozlista
kvetheti ugyangy, mint minden alaptipusnl. Eszerint
struct { . . . } x, y, z;
szintaktikusan hasonl az

109

Forrs: http://www.doksi.hu

int x, y, z; sorhoz abban az rtelemben, hogy mindkt utasts a megnevezett tipus vltozknt
deklarlja x-et, y-t s z-t, ill. helyet foglal szmukra.
Az olyan struktradeklarci, amit nem kvet vltozlista, nem foglal trhelyet, csupn a struktra
alakjt (template) rja le.
Ha azonban a deklarci cimkzett, akkor ez a cimke a
ksbbiekben a struktra konkrt elfordulsakor a defincikban
hasznlhat. Ha pl. adott a date elbbi deklarcija, akkor
struct date d;
gy definilja a d vltozt, hogy az date tipus struktra legyen. A kls, ill. a statikus struktra gy
inicializlhat, hogy defincijt az elemek kezdeti rtkeibl ll lista kveti:
struct date d = {4, 7, 1776, 186, jl};
Valamely struktra adott tagjra kifelyezsen bell a
struktranv.tag alak szerkezettel lehet hivatkozni.
A . struktratag opertor a struktra nevt s a tag nevt
kapcsolja ssze. Ha pl. a d struktrabeli dtum alapjn akarjuk
leap-et (a szkvet) belltani, akkor a kd
leap = d.year % 4 == 0 && d.year % 100 != 0
|| d.year % 400 == 0; lesz. A hnap nevnek vizsglata:
if (strcmp (d.mon_name, aug) == 0) . . .
Ha a hnapneveket az angol helyesrs szerint nagy kezdbetkkel rtuk volna, kisbetss alaktsuk a
kvetkezkppen trtnhetne:
d.mon_name [0] = lower (d.mon_name [0]);
A struktrk egymsba skatulyzhatk; a fizetsi jegyzk pl. gy nzhet ki:
struct person {
char name [NAMESIZE]; char address [ADRSIZE]; long zipcode; long ss_number; double salary;
struct date birthdate; struct date hiredate;
};
A person nev struktra kt dtumot tartalmaz. Ha az emp-et mint
struct person emp;
deklarljuk, akkor
emp.birthdate.month a szlets hnapjra vonatkozik. A .struktratag opertor balrl jobbra kt.
6.2.
Struktrk s fggvnyek
A C nyelvbeli struktrkra szmos megkts vonatkozik. Ezek kzl a leglnyegesebb, hogy
struktrn csak ktfle mvelet vgezhet - a struktra cmnek ellltsa az & szimblum
hasznlatval, s a struktra valamelyik tagjhoz val hozzfrs. Ebbl kvetkezleg a struktrkat
egy egysgknt nem lehet semmihez sem hozzrendelni (rtkl adni), ill. msolni, nem adhatk t
fggvnyeknek, s a fggvnyek sem adhatnak vissza struktrkat. (A C nyelv ksbb megjelen
vltozataibl ezek a megktsek ki fognak maradni.) A struktrkat megcimz mutatkra mr nem
vonatkoznak ezek a korltozsok, gy a struktrk s a fggvnyek knyelmesen egytt tudnak
mkdni. Vgezetl, az automatikus tmbkhz hasonlan az automatikus struktrk sem
inicializlhatk, ez csak a kls s a statikus struktrk esetben lehetsges.
Vizsgljunk meg e jellegzetessgek kzl nhnyat! Pldaknt rjuk t az elz fejezetben ltott
dtumkonverzis rutint, struktrk hasznlatval! Mivel a szablyok nem engedik meg, hogy
struktrt fggvnynek kzvetlenl tadjunk, vagy kln-kln az elemeket, vagy az egszt
megcmz mutatt kell tadnunk. Az els lehetsg gy hasznlja day_of_year-t, ahogy az 5.
fejezetben lertuk:

110

Forrs: http://www.doksi.hu

d.yearday = day_of_year(d.year, d.month, d.day);


A msik lehetsg a mutattads. Ha a hiredate-et
struct date hiredate;
alakban deklarltuk s day_of_year-t trtuk, akkor
hiredate.yearday = day_of_year (&hiredate); segtsgvel a hiredate-et megcmz mutatt tadhatjuk
day_of_year-nek. A fggvnyt mdostani kell, mivel argumentuma a korbbi vltozlista helyett most
mutat lett:
day_of_year (pd)

/*Az v napjnak ellltsa a

hnapbl s a napbl*/ struct date *pd;


{
int i, day, leap;
day = pd->day;
leap = pd->year % 4 == 0 && pd->year % 100 != 0
|| pd->year % 400 == 0; for (i = 1; i < pd->month; i++) day += day_tab [leap][i]; return (day);
}

A
struct date *pd;
deklarci szerint pd olyan mutat, amely date tpus
struktrra mutat. A
pd->year
plda szerinti jellsmd j. Ha p struktrt megcmz mutat,
akkor
p->struktratag az adott tagra vonatkozik. (A -> opertor mnuszjelbl s az azt kvet >-bl ll.)
Mivel pd a struktrra mutat, a year tagra a
(*pd).year
alakban is hivatkozhatunk, de struktrkat jell mutatkat
olyan gyakran hasznlunk, hogy knyelmes rvidtsknt a ->
jellsmd is rendelkezsre ll. A (*pd).year alakban a
zrjelek szksgesek, mivel a . struktratag opertor
precedencija magasabb, mint a * opertor. Mind ->, mind pedig
. balrl jobbra kt, gy
p->q->memb
emp.birthdate.month
rtelme :
(p->)->memb
(emp.birthdate).month
A teljessg kedvrt me a msik fggvny, month_day, amit szintn a struktra hasznlatval runk t :
month_day (pd)

/*Hnap s nap ellltsa az v napjbl*/ struct date *pd;

{
int i, leap;
leap = pd->year % 4 == 0 && pd->year % 100 != 0

111

Forrs: http://www.doksi.hu

|| pd->year % 400 == 0; pd->day = pd->yearday; for (i = 1; pd->day > day_tab [leap][i]; i++) pd>day -= day_tab [leap][i]; pd->month = i;
}
A -> s . struktraopertorok, valamint az argumentumlistkat
kzrefog () s az indexet tartalmaz [] a precedenciahierarchia
cscsn ll, s ezrt nagyon szorosan kt. Ha pl. adott a
struct {
int x; int *y;
} *P;
deklarci, akkor
++p->x nem p-t, hanem x-et inkrementlja, mivel az alaprtelmezs szerinti zrjelezs:
++(p->x)
Zrjelek hasznlatval a kts megvltoztathat: (++p)->x az x-hez val hozzfrs eltt nveli p-t,
mg (p++)->x azt kveten inkrementl. (Az utbbi zrjelkszlet felesleges. Mirt?)
Hasonlkppen, *p->y behozza, amire p mutat; *p->y++ azutn inkrementlja y-t, miutn hozzfrt
ahhoz, amire mutat (ppgy, mint *s++); (*p->y) ++ azt nveli, amire y mutat, mg *p++->y azutn
inkrementlja p-t, hogy hozzfrt ahhoz, amire y mutat.
6.3.
Struktratmbk
A struktrk klnsen alkalmasak egymssal sszefgg vltozk tmbjeinek kezelsre.
Tekintsk pl. azt a programot, amely a C nyelv kulcsszavainak elfordulsait szmllja. A nevek
trolshoz szksgnk lesz egy karakterlnc-tmbre, a darabszmok trolshoz pedig egy
egszekbl ll tmbre. Az egyik megolds szerint prhuzamosan kt tmbt hasznlunk.
Legyenek ezek pl. keyword s keycount:
char *keyword [NKEYS];
int keycount [NKEYS];
Azonban maga a tny, hogy a tmbk prhuzamosak, jelzi, hogy lehetsgnk van msfajta szervezsre
is. Valjban minden kulcsszbejegyzs egy pr:
char *keyword; int keycount;
Hozzuk ltre a prok tmbjt! A
struct key {
char *keyword; int keycount;
} keytab [NKEYS]; struktradeklarci az ilyen tpus struktrk keytab nev tmbjt definilja s
trterletet foglal le szmra. A tmb minden eleme struktra. Ezt gy is rhatjuk:
struct key {
char *keyword; int keycount;
};
struct key keytab [NKEYS];
Mivel a keytab struktra jelen esetben a nevek lland halmazt tartalmazza, legegyszerbb, ha
definilskor egyszer s mindenkorra inicializljuk. A struktrk inicializlsa mindenben hasonlt a
korbbiakhoz - a defincit a kezdeti rtkek kapcsos zrjelek kz zrt listja kveti:
struct key {
char *keyword; int keycount;
} keytab [] = {

112

Forrs: http://www.doksi.hu

break, 0,
case, 0,
char, 0,
continue, 0,
default, 0,
/* ... */
unsigned , 0,
while, 0,
};
A kezdeti rtkeket a struktratagoknak megfelelen pronknt
soroltuk fel. Pontosabb lenne, ha minden sor vagy struktra
kezdeti rtkeit zrnnk kapcsos zrjelek kz
{break, 0},
{ case, 0},
...
szerint, de a bels kapcsos zrjelekre nincs szksg, ha a kezdeti rtkek egyszer vltozk vagy
karakterlncok, mint a jelen esetben is. Amennyiben kezdeti rtkek vannak megadva, s a [] resen
maradt, a fordt most is ezek alapjn szmtja ki a keytab tmb elemeinek szmt.
A kulcssz-szmll program a keytab definilsval kezddik. A frutin a getword fggvny ismtelt
hvsval szavanknt olvassa a bemenetet. A program minden szt megkeres a keytab-ben a binris
keresfggvnynek a 3. fejezetben ltott vltozatval. (A helyes mkds rdekben a kulcsszavak
listjt termszetesen nvekv sorrendben kell megadnunk.)
#define MAXWORD 20
main ()
/*C kulcsszavak szmllsa*/
{
int n, t;
char word [MAXWORD];
while ((t = getword (word, MAXWORD)) != EOF) if (t == LETTER)
if ((n = binary (word, keytab, NKEYS)) >= 0) keytab [n].keycount++;
for (n = 0; n < NKEYS; n++) if (keytab [n].keycount > 0)
printf (%4d %s \n,
keytab [n].keycount, keytab [n].keyword);
}
binary (word, tab, n)

/*Sz megkeresse tab[0] . . .


tab[n-1]-ben*/

char *word;
struct key tab [];
int n;
{
int low, high, mid, cond;
low = 0;
high = n - 1;
while (low <= high) {
mid = (low + high) / 2;
if ((cond = strcmp (word, tab [mid].keyword)) < 0)
high = mid - 1; else if (cond > 0)
low = mid + 1;
else
return (mid);
}

113

Forrs: http://www.doksi.hu

return (-1);
}
Rvidesen sor kerl a getword fggvny bemutatsra; egyelre elg annyit tudnunk, hogy minden
alkalommal, amikor megtall egy kulcsszt, a LETTER rtket adja vissza s az illet szt az els
argumentumba msolja.
Az NKEYS mennyisg a kulcsszavak szma a keytab-ban. Br ezt magunk is megszmllhatnnk,
sokkal knnyebb s biztonsgosabb, ha a gpre bzzuk, klnsen, ha a lista vltozhat. Az egyik
lehetsg az lenne, hogy a kezdeti rtkek listjt a nulla mutatval zrjuk le, majd ciklusban addig
haladunk keytab-on, amg a vgt meg nem talltuk.
Ez azonban tbb, mint amire szksg van, mivel a fordt a tmb mrett fordts kzben pontosan
meghatrozza. A bejegyzsek szma ebbl:
keytab mrete / struct key mrete
A C-ben rendelkezsnkre ll a sizeof egyoperandus opertor,
amelynek segtsgvel brmilyen objektum mrete fordtsi idben
meghatrozhat. A
sizeof (objektum) kifejezs eredmnye olyan egsz szm, amely megegyezik a megadott objektum
mretvel. (A mretet byte-nak nevezett specifiklatlan egysgekben kapjuk, amelynek mrete ugyanaz,
mint egy char-.) Az objektum valamilyen aktulis vltoz, tmb vagy struktra, vagy pedig valamilyen
alap-, ill. leszrmaztatott tipus (l. int vagy double, ill. struktrk) neve lehet. Esetnkben a kulcsszavak
szma a tmbmret osztva egy tmbelem mretvel. Ezt a szmtst #define utastsban hasznlva,
lltjuk be az NKEYS rtkt:
#define NKEYS (sizeof (keytab) / sizeof (struct key))
Most pedig nzzk a getword fggvnyt. A getword-nek az adott program szmra szksgesnl
ltalnosabb vltozatt rtuk meg, amely azonban nem lnyegesen bonyolultabb, getword a bemeneten
soron kvetkez szt adja vissza, ahol a sz vagy betk s szmok betvel kezdd lnca, vagy pedig
egyetlen karakter. Az objektum tipust fggvnyrtkknt kapjuk meg; ez az rtk LETTER, ha az
adott egysg sz, EOF az llomny vgn, vagy maga a karakter, ha az nem alfabetikus.
getword (w,lim)

/*Vedd a kvetkez szt a bemenetrl*/ char *w; int lim;

{
int c,t; if (type (c = *w++ = getch ()) != LETTER) { *w = \0; return ;
}
while (--lim > 0) {
t = type (c = *w++ = geth ());
if (t != LETTER && t != DIGIT) {
ungetch ;
break;
}
}
*(w - 1) = \0;
return (LETTER);
}
A getword a getch s ungetch rutinokat hasznlja, amelyeket a 4. fejezetben rtunk meg. Amikor egy
alfabetikus szvegegysg begyjtse befejezdik, a getword mr a szksgesnl egy karakterrel tbbet
olvasott be. Az ungetch hvsval ezt a karaktert a getword kvetkez hvsig visszarjuk a bemenetre.
A getword a type hvsval llaptja meg az egyes bemeneti karakterek tpust. Az albbi vltozat csak
az ASCII karakterkszletben mkdik:
type

/*ASCII karakter tpusnak visszaadsa*/ int c;

114

Forrs: http://www.doksi.hu

if (c >= a && c <= z || c >= A && c <= Z) return (LETTER); else if (c >= 0 && c <= 9)
return (DIGIT);
else
return ;
}
A LETTER s a DIGIT szimbolikus lland minden olyan rtket felvehet, amely nem tkzik a nemalfanumerikus karakterekkel s az EOF-fal, kzenfekv pl. az albbi vlaszts:
#define LETTER a
#define DIGIT 0
A getword-t felgyorsthatjuk, ha a type fggvny hvsait valamely alkalmas type [] tmbre vonatkoz
hivatkozsokkal helyettestjk. A szabvnyos C knyvtrban rendelkezsnkre llnak az isalpha s
isdigit nev makrk, amelyek ily mdon mkdnek.
6.1.
Gyakorlat. Vgezzk el a getword-nek ezt a mdostst, s mrjk meg a program
sebessgnek vltozst!
6.2.
Gyakorlat. rjuk meg a type olyan vltozatt, amely fggetlen a karakterkszlettl!
6.3.
Gyakorlat. Irjuk meg a kulcsszszmll program olyan vltozatt, amely nem szmllja az
idzjelek kz zrt karakterlncokban elfordul kulcsszavakat!
6.4.
Struktrkat megcmz mutatk
A mutatkkal s struktratmbkkel kapcsolatos megfontolsaink szemlltetsre rjuk jra a
kulcsszszmll programot, ezttal tmbindexek helyett mutatk hasznlatval!
A keytab kls deklarcijt nem kell megvltoztatnunk, a main s a binary azonban mdostsra
szorul.
main () /*C kulcsszavak szmllsa;
mutatt alkalmaz vltozat*/
{
int t;
char word [MAXWORD];
struct key *binary (), *p;
while ((t = getword (word, MAXWORD)) != EOF) if (t == LETTER)
if ((p = binary (word, keytab, NKEYS)) != NULL) p->keycount++;
for (p = keytab; p < keytab + NKEYS; p++) if (p->keycount > 0)
printf (%4d %s \n, p->keycount, p->keyword);
}
struct key *binary (word, tab, n) /*Sz keresse*/
char *word;
/*tab [0] . . . tab [n-1]-ben*/
struct key tab [];
int n;
{
int cond;
struct key *low = &tab [0];
struct key *high = &tab [n - 1]; struct key *mid;
while (low <= high) {
mid = low + (high - low) / 2;
if ((cond = strcmp (word, mid->keyword)) < 0)
high = mid - 1; else if (cond > 0)
low = mid + 1;
else
return (mid);
}

115

Forrs: http://www.doksi.hu

return (NULL);
}
Ebben a programban tbb dolog is emltsre mlt. Elszr is binary deklarcijnak jeleznie kell,
hogy key tpus struktrt megcmz mutatt ad vissza, s nem egsz tpus mennyisget; ezt mind a
main-ben, mind binaryban deklarltuk. Ha binary megtallta a szt, az azt kijell mutatt adja vissza;
ha a keress eredmnytelen, a visszaadott rtk NULL.
Msodszor, a keytab elemeihez trtn minden hozzfrs
mutatkkal trtnik. Emiatt a binary rutin jelentsen
megvltozik: a kzps elem kiszmtsa mr nem lehet egyszeren
mid = (low + high) / 2
mivel kt mutat sszeadsa semmifle rtelmes vlaszt nem
eredmnyez (mg a 2-vel val osztskor sem), st ez a mvelet
tiltott ! Ehelyett a
mid = low +(high - low) / 2 alakra van szksg, amely gy lltja be mid-et, hogy az a low s a high
kztti terlet felezpontjra mutasson. Figyeljk meg low s high kezdeti rtkeit is! Lehetsg van
arra, hogy egy mutatt valamely korbban definilt objektum cmvel inicializljunk: itt ppen ezt
tettk.
A main-ben azt rtuk, hogy
for (p = keytab; p < keytab + NKEYS; p++)
Ha p struktrt megcmz mutat, akkor minden p-re vonatkoz aritmetikai szmts figyelembe veszi a
struktra tnyleges mrett, gy p++ a p-t a megfelel mennyisggel inkrementlja ahhoz, hogy
ellljon a struktrk tmbjnek kvetkez eleme. Ne higyjk azonban, hogy a struktra mrete
megegyezik az elemei mretnek az sszegvel - a klnbz jelleg objektumok elhelyezkedsi
kvetelmnyeinek folytn lyukak lehetnek a struktrban.
Vgezetl egy megjegyzs a program alakjval kapcsolatban. Ha
egy fggvny bonyolult tpust ad vissza, mint a
struct key *binary(word, tab, n) esetben, akkor a fggvny nevt esetleg nehz szrevenni, vagy
szvegszerkeszt programmal (text editorral) megtallni. Emiatt nha ms formt szoks hasznlni:
struct key
binary (word, tab, n)
Ez termszetesen leginkbb szemlyes zls krdse: vlasszuk ki a neknk tetsz alakot, s ahhoz
tartsuk magunkat.
6.5.
nhivatkoz struktrk
Tegyk fel, hogy ltalnosabb feladatknt a bemeneti szveg sszes szavnak elfordulsait akarjuk
megszmllni. Mivel a szavak listja elzetesen nem ismert, azt nem tudjuk alkalmas mdon
rendezni s nem hasznlhatunk binris keresst. Lineris keresst azonban vgre tudunk hajtani
minden berkez szra, amivel megnzzk, hogy volt-e mr ilyen sz: a program futsa azonban gy
rkk fog tartani. (Pontosabban szlva a vrhat futsi id a beolvasott szavak szmval
ngyzetesen n.) Hogyan szervezzk meg az adatokat ahhoz, hogy hatkonyan meg tudjunk
brkzni a tetszleges szavakbl ll listval?
Az egyik megolds szerint llandan rendezett llapotban tartjuk a mr megvizsglt szavakat oly
mdon, hogy a berkezs sorrendjben minden szt a neki megfelel helyre tesznk. Ezt azonban
nem gy vgezzk el, hogy a szavakat egy lineris tmbben tologatjuk, mivel ez is tl sokig
tartana. Ehelyett a binris fa nev adatstruktrt fogjuk hasznlni.
A fa minden klnbz szhoz egy-egy csompontot rendel, amelynek tartalma :
a sz szvegt megcmz mutat,
a sz elfordulsainak szma,
a bal oldali gyermek (leszrmazott) csompontot megcmz

116

Forrs: http://www.doksi.hu

mutat,
a jobb oldali gyermek csompontot megcmz mutat.
Egyetlen csompontnak sem lehet kettnl tbb gyermeke; lehet viszont nulla vagy egy gyermeke.
A csompontokat gy hozzuk ltre, hogy minden egyes csompont esetben a bal oldali rszfa csupa
olyan szt tartalmaz, amely kisebb, mint a csompontbeli sz, mg a jobb oldali rszfban csupa olyan
sz van, amely nla nagyobb. Ha el akarjuk dnteni, hogy egy j sz mr rajta van-e a fn, a vizsglatot
a fa gykernl kezdjk, s az j szt az illet csompontban trolt szval hasonltjuk ssze. Ha
megegyeznek, a vlasz igenl. Ha az j sz kisebb, mint a csompontbeli sz, a keress a bal oldali,
ellenkez esetben a jobb oldali gyermek csompontban folytatdik. Ha a kivlasztott irnyban nincs
leszrmazott, a sz nincs a fn, s ppen a hinyz leszrmazottnak megfelel csompontba kell
bernunk. Ez a keressi eljrs rekurzv, hiszen brmelyik csomponttl indul keress tartalmazza a
valamelyik leszrmazottjtl indul keresst is. Ennek megfelelen a legtermszetesebb az, ha a
beillesztsre s kirsra is rekurzv rutinokat hasznlunk.
Visszatrve a csompont lersra, a csompont nyilvn struktra lesz, amely ngy sszetevbl ll:
struct tnode { /*Alapcsompont*/
char *word;
/*A szvegre mutat*/
int count;
/*Elfordulsok szma*/
struct tnode *left; /*Bal oldali gyermek*/
struct tnode *right;
/*Jobb oldali gyermek*/
}
A csompontnak ez a rekurzv deklarcija taln bizonytalanul
fest, de valjban teljesen helyes s pontos. A struktra nem
tartalmazhatja sajt megnevezst, de
struct tnode *left; a left-et a csompontot megcmz mutatnak, nem pedig csompontnak deklarlja.
Az egsz program meglepen rvid, mivel mr korbban megrt segdrutinokat hasznl. Ezek: a
getword, amellyel az egyes bemeneti szavakat olvassuk be, s az alloc, amellyel helyet biztostunk a
szavak arrbbcssztatshoz.
A frutin egyszeren a getword segtsgvel beolvassa a szavakat s a tree hasznlatval elhelyezi
azokat a fn.
#define MAXWORD 20
main ()

/*Szavak gyakorisgnak szmllsa*/

{
struct tnode *root, *tree ();
char word [MAXWORD];
int t;
root = NULL;
while ((t = getword (word, MAXWORD)) != EOF) if (t == LETTER)
root = tree (root, word); treeprint (root);
}
Maga a tree egyszer. A main a fa tetejn (a gykr szintjn egy szt ad t. Ezt a szt minden lpsben
sszehasonltjuk az adott csompontnl mr trolt szval s a tree rekurzv hvsai rvn vagy a bal
oldali, vagy a jobb oldali rszfa irnyban haladunk tovbb. Vgl is a sz vagy megegyezik
valamelyik, mr a fn trolt szval (amikor is elfordulsainak szmt nveljk), vagy pedig a program
a nullamutatt tallja meg, ami azt jelzi, hogy j csompontot kell ltrehozni s a ft azzal ki kell
bvteni. Uj csompont ltrehozsakor a tree az azt megcmz mutatval tr vissza, ami bekerl a
szl csompontba:
struct tnode *tree (p, w)

/*w elhelyezse p-nl

vagy p alatt*/ struct tnode *p; char *w;

117

Forrs: http://www.doksi.hu

f
struct tnode *talloc (); char *strsave (); int cond;
if (p == NULL) {
/*j sz rkezett*/
p = talloc (); /*j csompont kszl*/
p->word = strsave (w);
p->count = 1;
p->left = p->right = NULL;
} else if ((cond = strcmp (w, p->word)) == 0)
p->count++; /*Mr volt ilyen sz*/
else if (cond < 0)
/*Kisebb - a bal
rszfba kerl*/
p->left = tree (p->left, w);
else /*Nagyobb - a jobb rszfba kerl*/
p->right = tree (p->right, w); return (p);
}

Az j csompont szmra szksges trhelyet a talloc szolgltatja, amely a mr korbban megrt alloc
mdostott vltozata. A talloc rutin a fa csompontjnak trolsra alkalmas szabad terletet megcmz
mutatt ad vissza. (errl rviden rszletesebben is szlunk.) Az j szt az strsave msolja be egy rejtett
hejre, a darabszm inicializldik, s a kt leszrmazott nulla lesz. A programkdnak ezt a rszt
csupn a fa szlein hajtjuk vgre, amikor j csompontot iktatunk be. A strsave s a talloc ltal
visszaadott rtkek hibaellenrzst elhagytuk (ami lesben hasznlt program esetben nem blcs
dolog).
A treeprint a ft a bal oldali rszfa sorrendjben nyomtatja ki; minden egyes csompontnl kinyomtatja
a bal oldali rszft (minden olyan szt, amely a krdses sznl kisebb), majd magt a szt s vgl a
jobb oldali rszft (minden olyan szt, amely nagyobb). Ha az olvas bizonytalannak rzi magt a
rekurzis technikval kapcsolatban, rajzoljon le egy ft s nyomtassa ki a treeprint-tel: kevs ennl
ttekinthetbb rekurzv rutint tallhatunk.
treeprint (p) /*A p fa rekurzv kinyomtatsa*/ struct tnode *p;
{
if (p != NULL) {
treeprint (p->left);
printf (%4d %s \n, p->count, p->word); treeprint (p->right);
}
}
Gyakorlati megjegyzs: ha a fa kiegyenslyozatlann vlik, mert a szavak nem vletlenszer
sorrendben rkeznek, a program futsi ideje tl gyorsan nvekedhet. A legrosszabb eset az, amikor a
szavak mr sorrendben vannak, ilyenkor ez a program igen kltsges mdon szimullja a lineris
keresst. A binris fnak vannak ltalnostsai, mgpedig a 2-3 fk s az AVL fk, amelyek mentesek
ettl a legrosszabb esetben bekvetkez viselkedstl, knyvnkben azonban ezeket nem
ismertethetjk. Mieltt befejeznnk a pldt, rdemes rvid kitrt tennnk a trterlet-lefoglalssal
kapcsolatos egyik problmra. Nyilvn j lenne, ha a programban csak egy trfoglal fggvny lenne,
mg akkor is, ha az klnfle jelleg objektumok szmra foglal helyet. Ha azonban ugyanaz a
fggvny foglal helyet pl. char-okat s struct tnode-okat megcmz mutatk szmra, kt krds merl
fel. Elszr is, hogyan elgti ez ki a legtbb valsgos gpnek azt a kvetelmnyt, hogy bizonyos
tpus objektumok adott elhelyezsi elrsoknak kell, hogy eleget tegyenek? (pl. az egsz tpus
mennyisgeket gyakran pros cmen kell elhelyezni.) Msodszor, milyen deklarcik tudnak
megbrkzni azzal a tnnyel, hogy az alloc szksgszeren klnbz tpus mutatkat ad vissza?
Az elhelyezsi elrsoknak ltalban - nmi hely elvesztse rn - egyszeren gy tehetnk eleget, ha
gondoskodunk arrl, hogy a helyfoglal mindig olyan mutatt adjon vissza, amely az sszes elhelyezsi
kvetelmnynek eleget tesz. A PDP-11-en pl. elegend, ha az alloc mindig pros mutatt ad vissza,
mivel pros cmen brmilyen tpus objektum trolhat. Ennek ra csupn egyetlen elvesztett
karakterpozci pratlan_ hosszsg mennyisg esetn. Hasonl intzkeds tehet ms gpeken is. gy

118

Forrs: http://www.doksi.hu

lehet, hogy az alloc megvalstsa nem gpfggetlen, a hasznlata azonban az. Az 5. fejezetben
ismertetett alloc semmifle megklnbztetett elhelyezkedst sem garantl, a 8. fejezetben bemutatjuk,
hogyan kell helyesen megoldani ezt a feladatot.
Az alloc tpusdeklarcijnak krdse minden olyan nyelvben gondot okoz, amely komolyan veszi a
tpusellenrzst. A C-ben a legjobb eljrs az, ha az alloc-ot gy deklarljuk, hogy char-t megcmz
mutatt adjon vissza, majd tpusmdost szerkezettel explicit knyszerrel vltoztatjuk a mutatt a
kvnt tpusv.
Ha teht p deklarcija
char *p;
akkor
(struct tnode *)p egy kifejezsben p-t tnode mutatv alaktja t. gy a talloc lersa:
struct tnode *talloc ()
{
char *alloc (); return ((struct tnode *) alloc (sizeof (struct tnode)));
}
Ez mr tbb, mint amire a jelenlegi fordtk esetben szksg van, azonban jelzi a jvre nzve a
legbiztosabb irnyt.
6.4.
Gyakorlat. rjunk olyan programot, amely beolvas egy C programot, s alfabetikus sorrendben
kinyomtatja a vltozneveknek azokat a csoportjait, amelyek els 7 karakterkben megegyeznek,
azonban ezt kveten valahol klnbznek! gyeljnk arra, hogy a 7 paramter legyen!
6.5.
Gyakorlat. rjunk elemi, keresztbe hivatkoz (cross-referencing) programot, amely kinyomtatja
egy dokumentumban elfordul szavak listjt, s minden szra megadja azoknak a soroknak a
sorszmt, ahol az illet sz elfordul!
6.6.
Gyakorlat. rjunk olyan programot, amely a bemenetn elfordul szavakat az elforduls
cskken sorrendjbe rendezve nyomtatja ki! Minden sz el rjuk oda az elfordulsok szmt!
6.6.
Keress tblban
Ebben a fejezetben egy tblakeres (table-lookup)
programcsomag belsejt rjuk meg, amivel a struktrk tovbbi
vonatkozsait illusztrljuk. Tipikusan ilyen programkd
tallhat a makroprocesszorok vagy fordtk
szimblumtbla-kezel rutinjaiban. Tekintsk pl. a C #define
utastst. Ha egy olyan sor, mint
#define YES 1 fordul el, a YES nv s az 1 helyettest szveg bekerl egy tblzatba. A
ksbbiekben, amikor a YES nv utastsokban fordul el, pl.
inword = YES; azt 1 -gyel kell helyettesteni.
Kt frutin kezeli a neveket s a helyettest szvegeket. Az install(s, t) berja az s nevet s a t
helyettest szveget egy tblzatba; az s s a t egyszeren karakterlncok. A lookup(s) megkeresi set a tblzatban, s egy mutatt ad vissza, amely arra a helyre mutat, ahol s-et megtallta, vagy
pedig NULL, ha s nincs a tblzatban.
Az n. hash keressi algoritmust hasznljuk - a program a berkez nevet kis pozitv egsz szmm
alaktja t, amelyet ksbb azutn egy mutattmb indexelsre hasznl. A tmb egy eleme olyan
blokkok lncnak kezdetre mutat, amelyek az illet hash rtk neveket rjk le. A tmbelem
NULL, ha egyetlen nv sem rendelkezik az adott hash rtkkel.
A lncban egy blokk olyan struktra, amely a nevet megcmz mutatkat, a helyettest szveget s
a kvetkez lncbeli blokkot megcmz mutatt tartalmazza. A lnc vgt a kvetkez blokk
mutatjnak nulla rtke jelzi :
struct nlist { /*Elemi tbla bejegyzs*/

119

Forrs: http://www.doksi.hu

char *name;
char *def;
struct nlist *next;

/*Kvetkez bejegyzs a

lncban*/
}
A mutattmb:
#define HASHSIZE 100 static struct nlist *hashtab [HASHSIZE];
/*Mutattbla*/ A lookup s az install ltal egyarnt hasznlt hash rtkkpz fggvny egyszeren
sszeadja a lncbeli karakterrtkeket s kpezi az sszegnek a tmbmrettel vett maradkt. (Ez nem a
lehet legjobb algoritmus, de megvan az az elnye, hogy rendkvl egyszer.)
hash (s)

/*Az s string hash rtknek kpzse*/ char *s;

{
int hashval;
for (hashval = 0; *s != \0; ;)
hashval += *s++;
return (hashval % HASHSIZE);
}
A hash-eljrs a hashtab _tmbben ltrehoz egy kezdindexet; ha a karakterlnc egyltaln
megtallhat, akkor az itt kezdd blokklncban kell lennie.
A keresst a lookup vgzi. Ha lookup megtallja a bejegyzst, a megfelel mutatt adja vissza; ha nem,
akkor NULL-lal tr vissza.
struct nlist *lookup (s) /*s keresse hashtab-ben*/ char *s;
{
struct nlist *np; for (np = hashtab [hash (s)]; np != NULL; np = np->next) if (strcmp (s, np->name)
== 0)
return (np);
return (NULL);

/*Megtallta*/
/*Nem tallta meg*/

}
Az install a lookup-ot hasznlja annak eldntsre, hogy a belltott nv mr jelen van-e. Ha igen, akkor
az j definci fellbrlja a rgit, egybknt pedig teljesen j bejegyzs keletkezik. Az install NULL-t
ad vissza, ha valamilyen oknl fogva nincs hely az j bejegyzs szmra.
struct nlist *install (name, def) /*(name, def)
elhelyezse
hashtab-ben*/
char *name, *def;
{
struct nlist *np, *lookup ();
char *strsave (), *alloc ();
int hasval;
if ((np = lookup (name)) == NULL) {
if (np == NULL)

/*Nem tallta meg*/ np = (struct nlist *) alloc (sizeof (np));

return (NULL); if ((np->name = strsave (name)) == NULL)


return (NULL); hashval = hash( np->name); np->next = hashtab [hashval]; hashtab [hashval] = np;
} else /*Mr ott van*/
free (np->def);
/*Felszabadtja az elz
defincit*/
if ((np->def (strsave (def))) == NULL) return (NULL); return (np);

120

Forrs: http://www.doksi.hu

}
Az strsave egyszeren tmsolja az argumentumban megadott karakterlncot valamilyen biztos helyre,
amit az alloc hvsval kapott. Ezt a programot az 5. fejezetben lttuk. Mivel az alloc s a free hvsai
tetszleges sorrendben elfordulhatnak, tovbb minthogy az elhelyezkeds is szmt, az alloc-nak az 5.
fejezetben kzlt egyszer vltozata itt nem elegend (l. a 7. s 8. fejezetet).
6.7.
Gyakorlat. rjunk olyan rutint, amely a lookup s install ltal kezelt tblbl trl egy nevet s
egy defincit!
6.8.
Gyakorlat. Az ebben a fejezetben kzlt rutinokat, ill. getch-t s ungetch-t alapul vve
valstsuk meg a #define processzor egyszer vltozatt, amely C programok szmra hasznlhat!
6.7.
Mezk
Ha szkben vagyunk a trhelynek, elfordulhat, hogy tbb objektumot egyetlen gpi szban kell
elhelyeznnk. Tipikus esete ennek az egybites feltteljelzk (flagek) alkalmazsa, pl. a
fordtprogramok
szimblumtbliban.
Kvlrl
knyszertett adatformtumok,
pl.
hardvereszkzk illesztsekor, gyakran ignylik azt a lehetsget, hogy a gpi sz egyes
darabjaihoz is hozzfrhessnk.
Kpzeljk el a fordtnak azt a rszt, amely a szimblumtblt kezeli. Minden programbeli
azonosthoz bizonyos informci trsul, pl. hogy kulcssz-e vagy sem, hogy kls s/vagy
statikus stb. mennyisgrl van-e sz. Az ilyen informci kdolsnak legtmrebb mdja az
egybites feltteljelzk kszletnek hasznlata egyetlen char-on vagy int-en bell.
Ez ltalban gy trtnik, hogy a vlasztott bitpozciknak
megfelelen egy maszk-kszletet definilnak, mint
#define KEYWORD 01
#define EXTERNAL 02
#define STATIC 04
(A szmoknak kett hatvnyainak kell lennik.) Ezek utn a biteket a 2. fejezetben ismertetett lptet,
maszkol s komplementl opertorokkal mr knnyen elrhetjk.
Bizonyos fordulatok klnsen gyakoriak:
flags = EXTERNAL | STATIC;
1-re lltja a flags-ben az EXTERNAL s STATIC biteket, mg
flags &= ~(EXTERNAL | STATIC);
ugyanezeket a biteket kinullzza, s
if ((flags &(EXTERNAL | STATIC)) == 0) . . . igaz, ha mindkt bit nulla.
Br ez a forma gyorsan elsajtthat, a C nyelv azt is lehetv teszi, hogy valamely szn bell ne
bitenknti logikai opertorokkal, hanem kzvetlenl definiljunk s rjnk el egyes mezket. A mez
(field) szomszdos bitek halmaza egyetlen int-en bell. A mezdefinci s -elrs szintaxisa a
struktrkon alapul. Pl. az elbbi #define sorok hrom mez definilsval helyettesthetk:
struct {
unsigned is_keyword : 1; unsigned is_extern : 1; unsigned is_static : 1;
} flags;
Ez a flags nev vltozt definilja, amely hrom 1-bites mezt tartalmaz. A kettspontot kvet szm
jelenti a mezszlessget bitekben. A mezket unsigned-nak deklarltuk annak hangslyozsra, hogy
azok tnylegesen eljel nlkli mennyisgek.
Az egyes mezkre flags.is_keyword, flags.is_extern stb. alakkal hivatkozhatunk, ppgy, mint ms
struktratagok esetben. A mezk gy viselkednek, mint kis, eljel nlkli egsz szmok, s ppgy
rszt vehetnek aritmetikai mveletekben, mint ms egszek. gy a fenti pldkat termszetesebb mdon
a kvetkezkppen rhatjuk:
flags.is_extern = flags.is_static = 1; amely 1-re lltja;
flags.is_extern = flags.is_static = 0;

121

Forrs: http://www.doksi.hu

amely kinullzza, s
if (flags.is_extern == 0 && flags.is_static == 0) . . . amely megvizsglja a biteket.
A mez nem lpheti t az int hatrt; ha a megadott szlessg erre vezetne, a mez a kvetkez int
hatrra fog illeszkedni. A mezknek nem kell felttlenl nvvel rendelkeznik; nv nlkli mezket
(csak egy kettspont s a szlessg) hasznlunk kitltsre. A specilis 0 szlessg elrsval a
kvetkez int hatrra val illeszkedst knyszerthetjk ki.
A mezk hasznlatval kapcsolatban nhny dologra gyelnnk kell! Taln a leglnyegesebb, hogy
bizonyos gpeken a mezk hozzrendelse balrl jobbra, ms gpeken jobbrl balra trtnik, ami az
eltr hardverfelptst tkrzi. Ebbl kvetkezleg, br a mezk igen hasznosak belsleg definilt
adatstruktrk kezelsre, mieltt klsleg definilt adatok sztbontsra hasznlnnk ket, alaposan
meg kell fontolni, milyen is lesz, hol kezddik a mezkioszts.
Tovbbi megjegyzend megktsek : a mezk eljel nlkliek; csak int-ekben trolhatk (vagy az
ezzel egyenrtk unsigned-okban); a mezk nem tmbk; nincsen cmk, gy rjuk az & opertor nem
alkalmazhat.
6.8.
Unionok
A union olyan vltoz, amely (klnbz idpontokban) klnfle tpus s mret objektumokat
tartalmazhat oly mdon, hogy a fordt gyel a mretre s illeszkedsre vonatkoz kvetelmnyek
teljeslsre. A unionok lehetv teszik, hogy ugyanazon a trterleten klnbzfajta adatokkal
dolgozzunk anlkl, hogy a programban gpfgg informcit kellene elhelyeznnk.
Pldnkat ismt a fordt szimblumtbljbl vve tegyk fel, hogy llandink int-ek, float-ok
vagy karaktermutatk lehetnek. Valamely adott lland rtkt a megfelel tpus vltozban kell
trolnunk, ugyanakkor a tblakezels szempontjbl a legknyelmesebb, ha az rtk ugyanannyi
trterletet foglal el s ugyanazon a helyen troldik, a tpustl fggetlenl. Ez a union
hasznlatnak clja - olyan vltozt ltrehozni, amely megengedett mdon tbb tpus brmelyikt
tartalmazhatja. A mezkhz hasonlan a szintaxis a struktrkon alapul.
union

u_tag {
int ival;
float fval;
char *pval;

} uval;
Az uval vltoz elg nagy lesz ahhoz, hogy a hrom tpus kzl a legnagyobbat is tartalmazhassa,
fggetlenl attl a gptl, amelyen a fordts trtnik - a programkd fggetlen a hardver jellemzitl.
E tpusok brmelyike hozzrendelhet uval-hoz, majd kifejezsekben hasznlhat mindaddig, amg a
hasznlat kvetkezetes: a visszanyert tpus a legutoljra trolt tpussal kell, hogy megegyezzen. A
programoz feladata annak kvetse, hogy ppen mit trolt a unionban; ha valamit adott tpusknt
trolunk s ms tpusknt olvassuk ki, akkor az eredmnyek gpfggek.
A union tagjaihoz val hozzfrs szintaxisa:
unionnv.tag
vagy
unionmutat->tag csakgy, mint a struktrk esetben. Ha az utype vltoz segtsgvel kvetjk az
uval-ban trolt aktulis tpust, akkor az albbihoz hasonl kdot kapunk:
if (utype == INT) printf (%d \n, uval.ival); else if (utype == FLOAT)
printf (%f \n, uval.fval); else if (utype == STRING)
printf (%s \n, uval.pval);
else
printf (rossz tpus %d az utype-ban\n, utype);
Unionok elfordulhatnak struktrkban s tmbkben, ill.
viszont. A struktrabeli union (vagy megfordtva) egyik tagjhoz
val hozzfrst ler jellsmd azonos az egymsba

122

Forrs: http://www.doksi.hu

skatulyzott struktrk jellsmdjval. Pl. a


struct

{
char *name;
int flags;
int utype;
union {
int ival;
float fval;
char *pval ;

} uval;
} symtab [NSYM];
ltal definilt struktratmbben az ival vltozra a
symtab [i].uval.ival
alakban, mg a pval karakterlnc els karakterre a
*symtab [i].uval.pval alakban hivatkozhatunk.
Valjban a union olyan struktra, amelyben a tagok kztti eltols nulla, s amely elg nagy ahhoz,
hogy a legszlesebb tagot is tartalmazhassa gy, hogy az illeszkeds a benne elfordul sszes tpus
szmra megfeleljen.
A struktrkhoz hasonlan a unionokra jelenleg csak kt mvelet megengedett: valamelyik tagjhoz
val hozzfrs, ill. a cm ellltsa. A unionokhoz semmit sem lehet hozzrendelni, nem lehet ket
fggvnyeknek tadni, s fggvnyek sem adhatnak vissza unionokat. A unionokat megcmz mutatk
ugyangy hasznlhatk, mint a struktrk mutati.
A 8. fejezetben bemutatsra kerl trterlet-lefoglal szemllteti, hogyan lehet union hasznlatval
kiknyszerteni, hogy egy vltoz adott tpus trterlet hatrra illeszkedjen.
6.9.
Tpusnvdefincik
A C nyelv typedef-nek nevezett szolgltatsnak segtsgvel
j adattpus-neveket hozhatunk ltre. Pl. a
typedef int LENGTH; deklarci hatsra a LENGTH nv az int szinonimja lesz. A LENGTH
tpus deklarciban, tpusmdost szerkezetben stb. pontosan ugyangy hasznlhat, mint az int
tpus:
LENGTH len, maxlen;
LENGTH *lengths [];
Hasonlkppen, a
typedef char * STRING;
deklarci hatsra a STRING a char * , vagyis a karaktermutat
szinonimja lesz, amit azutn olyan deklarcikban
hasznlhatunk, mint
STRING p, lineptr [LINES], alloc ();
Figyeljk meg, hogy a typedef-ben deklarlt tpus a vltoznv helyn jelenik meg, nem pedig
kzvetlenl a typedef sz utn. A typedef szintaktikusan olyan, mint az extern, static stb. trolsi
osztlyok. A nevek hangslyozsa rdekben nagybetket hasznltunk.
Bonyolultabb pldaknt typedef-eket ksztnk az ebben a fejezetben korbban bemutatott
facsompontok szmra:
typedef struct

tnode { /*Alapcsompont*/
char *word;
/*A szvegre mutat*/
int count;
/*Elfordulsok szma*/

123

Forrs: http://www.doksi.hu

struct tnode *left; /*Bal oldali


gyermek*/
struct tnode *right;
/*Jobb oldali
gyermek*/
} TREENODE, *TREEPTR;
Ezzel kt j tpuskulcssz, TREENODE (struktra) s TREEPTR (a
struktramutatja)jn ltre. Ekkor a talloc rutinbl
TREEPTR talloc ()
{
char *alloc (); return ((TREEPTR) alloc (sizeof (TREENODE)));
}
lesz.
Hangslyozzuk, hogy a typedef deklarci semmilyen rtelemben sem hoz ltre j tpust; egyszeren j
nevet ad valamilyen, mr ltez tpusnak. Szemantikailag sincs benne semmi j : az ily mdon deklarlt
vltozk pontosan ugyanolyan tulajdonsgak, mint azok a vltozk, amelyeknek deklarciit explicit
mdon lertuk. Valjban typedef olyan, mint #define, attl eltekintve, hogy mivel a fordt rtelmezi,
olyan szveges helyettestsekkel ismeg tud brkzni, amelyek meghaladjk a C makroprocesszor
kpessgeit. Pl.:
typedef int (*PFI) ();
ltrehozza a PFI tpust az int-et visszaad fggvnyt megcmz
mutat szmra, amely olyan sszefggsekben hasznlhat, mint
PFI strcmp, numcmp, swap; az 5. fejezet rendezprogramjban.
A typedef deklarcik hasznlatnak kt f oka van. Az els ok a programok paramterezse a
gpfggsgi problmk kivdsre. Ha a typede-feket olyan adattpusokra hasznljuk, amelyek
gpfggek, akkor a program thelyezsekor csupn a typedef-eket kell megvltoztatni. Az egyik
szoksos eset az, amikor klnfle egsz mennyisgek szmra hasznlunk typedef neveket, majd
minden egyes befogad gpre elksztjk a short, int s long vlasztkbl ll megfelel kszletet.
A typedef-ek hasznlatnak msik clja a programdokumentls javtsa - a TREEPTR-nek nevezett
tpust knnyebb megrteni, mint azt, amelyiket csupn egy bonyolult struktra mutatjaknt
deklarltunk.
Vgezetl, mindig megvan annak a lehetsge, hogy a jvben a fordt vagy valamelyik msik
program, mint pl. a lint fel tudja hasznlni a typedef deklarcikban trolt informcit a program
valamilyen kln ellenrzse cljbl.
_
7.

fejezet

Bevitel s kivitel
A be- s kiviteli (I/O) szolgltatsok nem rszei a C nyelvnek, ezrt ezekre idig nem fordtottunk
klnsebb figyelmet. Ktsgtelen azonban, hogy a valdi programok sokkal bonyolultabb mdon
llnak kapcsolatban krnye-zetkkel, mint ahogy azt idig bemutattuk. Ebben a fejezetben a szabvnyos
(standard) be- s kiviteli knyvtrat ismertetjk; ez a fggvnyeknek olyan kszlete, amelyek a C
programok szabvnyos be- s kiviteli rendszert kpezik. E fggvnyek feladata, hogy knyelmes
programozsi csatlakozst biztostsanak, ugyanakkor csupn olyan mveleteket valstsanak meg, amelyek a legtbb modern opercis rendszerben rendelkezsre llnak. A rutinok - fggetlenl attl, hogy
milyen kritikus alkalmazsrl van sz - elg jl mkdnek, a felhasznlk ritkn rezhetik gy, hogy a
nagyobb hatkonysg rdekben ms megoldst kell alkalmazniuk. Vgl a rutinok gpfggetlenek
abban az rtelemben, hogy kompatibilis formban mkdnek minden olyan _ rendszeren, amelyen a C
ltezik, s azok a programok, amelyek a rendszerrel folytatott prbeszdket a szabvnyos knyvtr

124

Forrs: http://www.doksi.hu

ltal nyjtott szolgltat-sokra korltozzk, lnyegben vltoztats nlkl vihetk t egyik gprl a
msikra.
Ezen a helyen nem ksreljk meg a teljes be- s kiviteli knyvtr
lerst; sokkal fontosabbnak tartjuk, hogy bemutassuk, hogyan kell az opercis rendszerbeli krnyezetkkel kapcsolatot tart C programokat rni.
7.1.

Hozzfrs a szabvnyos knyvtrhoz

Minden olyan forrsllomnynak, amely valamelyik szabvnyos knyvtrbeli


fggvnyre hivatkozik, valahol az llomny elejn tartalmaznia kell az
#include < stdio.h >
sort.Az stdio.h llomny bizonyos, a be- s kiviteli knyvtr ltal hasznlt
makrkat s vltozkat definil. A < s > knykzrjeleknek a szoksos
idzjelek helyetti hasznlata hatsra a fordt az llomnyt abban a katalgusban (directory-ban) fogja keresni, amely a szabvnyos fej (header) infor(a UNIX-ban tipikusan usr include).
mcit tartalmaz
A program betltsekor szksges lehet tovbb a knyvtr explicit
megadsa, a PDP--11 UNIX rendszeren pl. a program fordtst elr
parancs
cc forrsllomnyook stb. ls
ahol ls jelzi a szabvnyos knyvtrbl trtn betltst. (Az 1 karakter az el bet, load = betlteni.)

7.2.

Szabvnyos be- s kivitel; getchar s putchar

A legegyszerbb beviteli mechanizmus az, amikor getchar-ral karakterenknt


olvasunk a szabvnyos bemenetrl (standard inputrl), ltalban a felhasznli terminlrl. getchar() minden hvsa utn a kvetkez bemeneti karaktert adja vissza. A legtbb olyan krnyezetben, amely a C-t tmogatja, a terminlt egy llomnnyal helyettesthetjk a C konvenci segtsgvel: ha a
prog program a getchar-t hasznlja, akkor a
prog C infile
parancssor hatsra a prog az infile-t fogja olvasni a terminl helyett. A bemenet tkapcsolsa oly mdon trtnik, hogy maga a prog rzketlen a vltoztatsra; kzelebbrl, az Cinfile karakterlnc nem kerl be az argv-beli
parancssor-argumentumok kz. Hasonl a helyzet, ha a bemenet parancslncon (pipe) keresztl valamelyik msik programtl rkezik; az
otherprog _ prog
parancssor kt programot futtat, mgpedig az otherprog-ot s a prog-ot, s gy intzkedik, hogy a prog
szabvnyos bemenete az otherprog szabvnyos kimenetrl jjjn.

125

Forrs: http://www.doksi.hu

A getchar az EOF rtket adja vissza, amikor az ltala ppen olvasott, brmifle bemenet vgre rt. A
szabvnyos knyvtr az EOF szimbolikus llandt -1-nek definilja (egy #define-nal az stdio.h
llomnyban), a vizsg-latokat ennek ellenre EOF-ra s ne -1-re vgezzk, hogy ezltal az adott
rtktl fggetlenek maradjunk.
Ami a kimenetet illeti, a putchar a c karaktert szabvnyos kimenetre
(standard outputra) teszi, ami alaprtelmezs szerint szintn a terminl. A kimenet > hasznlatval irnythat llomnyba; ha prog a putchar-t hasznlja,
akkor
prog > outfile
a szabvnyos kimenetet a terminl helyett az outfile-ra rja. A UNIX rend-szerben parancslncot (pipe)
is hasznlhatunk:
proglanotherprog
a prog szabvnyos kimenett az anotherprog szabvnyos bemenetre teszi.
A prog ebben az esetben sem vesz tudomst az tirnytsrl.
A printf ltal ltrehozott kimen szveg szintn a szabvnyos kimenetre kerl. A putchar s a printf
hvsai keverhetk.
Meglepen nagy azoknak a programoknak a szma, amelyek csupn
egyetlen bemeneti folyamot olvasnak s csupn egyetlen kimeneti folyamot rnak. Ilyen programok
esetben a be- s kivitel getchar, putchar, ill. printf fggvnyekkel trtn megvalstsa teljesen
megfelel, s az indulshoz fel-ttlenl elg. Ez klnsen igaz akkor, ha az egyik program
kimenetnek a kvetkez program bemenetvel trtn sszekapcsolsa cljbl rendelke-zsre ll az
llomny-tirnyts s a parancslnc-mechanizmus. Tekintsk pl. a lower programot, amely a
bemenetet kisbetss kpezi le:
#include < stdio.h>
main() /*A bemenet kisbetss alaktsa*/
int c;
while (( c = getchar ()) ! = EOF)
putchar(isupper ? tolower : c);
Az isupper s tolower fggvnyek valjban az stdio.h-ban definilt makrk. Az isupper makr
ellenrzi, hogy az argumentum nagybet-e s nemnullt ad vissza, ha az, ill. nullt, ha nem. A tolower
makr a nagybetket kisbetkk alaktja. Fggetlenl attl, hogy az adott gpen ezek a fggvnyek
hogyan vannak megvalstva, kvlrl nzve egyformn viselkednek, gy az azokat hasznl
programoknak nem kell ismernik a karakterkszletet.
Tbb llomny konvertlsakor az llomnyok sszegyjtsre olyan programot hasznlhatunk, mint a
UNIX cat segdprogramja:
cat file 1, file2. . . _ lower _ output gy nem kell megtanulnunk, hogyan lehet llomnyokat programbl
elrni. (A cat-ot e fejezet ksbbi rszben mutatjuk be.)
Mellkesen megjegyezzk, hogy a szabvnyos be- s kiviteli knyvtr-ban a getchar s putchar
fggvnyek valjban makrk lehetnek, gy elkerl-het a karakterenknti fggvnyhvs miatti
terhels (overhead). A 8. fejezet-ben fogjuk ennek tnyleges megvalstst megmutatni.

7.3.

Formtumozott kimenet; printf

A kivitel cljbl hasznlt printf s a beolvasst vgz scanf rutin (l. a kvet-kez szakaszt) numerikus
mennyisgek karakteres brzolsra s karakteres mennyisgek numerikus brzolsra trtn

126

Forrs: http://www.doksi.hu

talaktst, formtumozott sorok ltrehozst s rtelmezst teszi lehetv. A printf fggvnyt az


elz fejezetekben ktetlenl hasznltuk, me a teljesebb s pontosabb lers:
printf(control, argl, arg2, . . .)
A printf az argumentumait konvertlja, formtumozza s a szabvnyos kime-netre nyomtatja a control
karakterlnc vezrlete alatt. A vezrl karakterlnc ktfle tpus objektumot tartalmaz: kznsges
karaktereket, amelyeket egyszeren a kimeneti folyamra msol s konverzi-specifikcikat, amelyek
mindegyike a printf soron kvetkez argumentumnak konvertlst s ki-nyomtatst rja el.
Minden konverzi-specifikcit a % karakter vezet be, s konverzis karakter zr le. A % s a
konverzis karakter kztt a kvetkezk llhatnak:

Mnuszjel,amely az ebbe a mezbe konvertlt argumentum balra igaz-tst rja el.


Szmjegyekbl ll karakterlnc,amely a minimlis mezszlessget hatrozza meg. Az
talaktott szm legalbb ilyen szles vagy szksg esetn szlesebb mezbe nyomtatdik ki. Ha
a konvertlt argumentum kevesebb karakterbl ll, mint a mezszlessg, akkor bal oldalon
(vagy, ha a balra igazts jelz szerepel, akkor jobb oldalon) a mez kitltdik, hogy ezltal az
elrt mezszlessg meglegyen. A kitlt karakter k-znsges esetben szkz, ill. amennyiben
a mezszlessget elnullval adtuk meg, akkor nulla (ez a zrus nem jelent oktlisan
rtelmezett mezszlessget).
Pont,amely a mezszlessget a rkvetkez szmjegysorozattl v-lasztja el.
Szmjegysorozat (a pontossg),amely a lncbl kinyomtatsra kerl
karakterek maximlis szmt vagy float s double esetben a tizedesponttl jobbra kinyomtatand szmjegyek szmt hatrozza meg.
Az l (el bet) hosszmdost,amely arra utal,hogy a szban forg adat int helyett long.
A konverzis karakterek s jelentsk:

Az argumentum decimlis jellsmdv alakul.

Az argumentum eljel nlkli,oktlis szmm konvertldik (elnulla nlkl).


x Az argumentum eljel nlkli,hexadecimlis szmm konvertldik
(vezet 0x nlkl).
u Az argumentum eljel nlkli decimlis jellsmdv alakul.
c Az argumentumot egyetlen karakternek tekinti.
s Az argumentum karakterlnc; a lncbeli karakterek mindaddig nyomta, tdnak,amg a nullakarakter nem kerl sorra,vagy amg a pontossgi
I specifikci ltal elrt szm karakter kirsa meg nem trtnt.
e Az argumentumot float-nak vagy double-nak tekinti,s a
[-]m.nnnnnnE[-]xx decimlis jellsmdba konvertlja,ahol az n-ek
; karakterlncnak hosszt a pontossg adja meg. Az alaprtelmezs
szerinti pontossg 6.
f Az argumentumot float-nak vagy double-nak tekinti,s a
[-]mmm.nnnnn decimlis jellsmdba konvertlja,ahol az n-ek karakterlncnak hosszt a pontossg adja meg.Az alaprtelmezs szerinti
pontossg 6.Jegyezzk meg,hogy a pontossg nem hatrozza meg az f
formtumban kinyomtatott rtkes szmjegyek szmt!
%e s %f kzl a rvidebbet hasznlja; az rtktelen nullkat elhagyja.
Ha a %-ot kvet karakter nem konverzis karakter,az illet karakter
nyomtatsra kerl: gy a % mint %% nyomtathat ki.
A legtbb formtumkonverzi jelentse nyilvnval,s a korbbi fejezetekben ezeket megtrgyaltuk.Ez all az egyik kivtel az,hogy a pontossg
miknt vonatkozik a karakterlncokra.Az albbi tblzat klnfle specifikciknak a hall, vilg ( 12 karakter) kinyomtatsra gyakorolt hatst
mutatja. Minden mez kr kettspontokat helyeztnk, hogy ezzel szemlltessk a mez kiterjedst:
1Os :
: hall, vilg :
%- I Os : : hall, vilg :
%20s :
:
hall, vilg

127

Forrs: http://www.doksi.hu

%a-20s:
: hall, vilg
%20.I Os : :
hall,vil
%-20.l Os: : hall,vil
%.l Os:
: hall,vil :
Figyelmeztets: a printf az els argumentumt hasznlja annak eldntsre, hogy mg hny
argumentum kvetkezik, s azoknak mi a tpusa. A program sszezavarodik, s rtelmetlen vlaszt
kapunk, ha nincs elg argumentum; vagy ha azok nem a megfelel tpusak.
7.1. Gyakorlat. rjunk olyan programot, amely tetszleges bemenetet kpes sszer mdon
kinyomtatni! Minimlis feladatknt a nemgrafikus karaktereket (a helyi szoksnak megfelelen)
oktlisban vagy hexadecimlis-ban nyomtassa ki, s hajtogassa ssze a hossz sorokat!
7.4.
Formtumozott bemenet; scanf
A scanf fggvny a printf bemeneti megfelelje, amely az ellenkez irnyban nyjt szmos, a
fentiekben lert szolgltatst:
scanf(control, argl, arg2, . . .)
A scanf karaktereket olvas a szabvnyos bemenetrl, a control-ban meghat-rozott formtum szerint
rtelmezi azokat, s az eredmnyeket a tbbi argu-mentumban trolja. A vezrlargumentumot az
albbiakban rjuk le; a tbbi argumentum, amelyek mindegyike mutat kell, hogy legyen, azt jelzi, hogy
hol kell trolni az talaktott bemenetet.
A vezrl karakterlnc ltalban olyan konverzis utastsokat tartal-maz, amelyek feladata a bemeneti
jelsorozat kzvetlen rtelmezse. A vezr-l karakterlnc tartalmazhat:
Szkzket, tabokat s jsorokat (res karaktereket), amelyeket figyel-men kvl hagy.
Kznsges karaktereket (nem %-ot), amelyek vrhatan illeszkednek a bemeneti folyam kvetkez
nemres karakterre.
Konverzispecifikcikat, amelyek a % karakterbl, a * hozzrende-ls-elnyom karakterbl, egy, a
maximlis mezszlessget meghatroz szmbl, valamint egy konverzis karakterbl llnak, ezek
kzl a kt kzps (* s a szm) elhagyhat.
A konverzispecifikci a kvetkez bemeneti mez talaktst irnytja. Kznsgesen az eredmny a megfelel argumentum ltal megcmzett
vltozba kerl.Ha azonban a * karakter a hozzrendels elnyomst rja el, a vezrls a bemeneti
mezt egyszeren tugorja, s nem trtnik rtk-ads.A beolvasott mez definciszeren a nemres
karakterek lnca,teht vagy a kvetkez res karakterig tart,vagy addig,amg el nem fogy az esetleg
megadott mezszlessg. Ebbl kvetkezleg a scanfsorhatrokon keresztl is olvassa a bemenett,
mivel az jsor karakterek res helyek.
A konverzis karakter a beolvasott mez rtelmezsre utal; a hozz tartoz argumentumnak mutatnak
kell lennie,amint azt a C nyelv rtk szerint hv szemantikja megkvnja. A kvetkez konverzis
karakterek megengedettek :
d A bemeneten decimlis egsz szmot vr; a megfelel argumentumnak
egszre kell mutatnia.
A bemeneten oktlis egsz szmot vr (elnullval vagy anlkl); a meg-felel argumentumnak
egsz mutatnak kell lennie.
x A bemeneten hexadecimlis egsz szmot vr (vezet 0x-szel vagy
anlkl); a megfelel argumentumnak egsz mutatnak kell lennie.
h A bemeneten short egsz szmot vr; a megfelel argumentum short
egszt megcmz mutat kell,hogy legyen.
c Egyetlen karaktert vr; a megfelel argumentum karaktermutat kell,
hogy legyen; a kvetkez bemeneti karakter a megjellt helyre kerl.
Az res karakterek szoksos tugrsa ebben az esetben letiltdik; a kvetkez nemres karakter beolvasshoz hasznljunk %cls-t.
s Karakterlncot vr; a megfelel argumentum karaktermutat; olyan karaktertmbre mutat,amely elg nagy ahhoz,hogy befogadja a karakterlncot s a lezr \0-t.
f Lebegpontos szmot vr; a megfelel argumentum float-ot megcmz
mutat kell,hogy legyen.Az e konverzis karakter az f szinonimja.

128

Forrs: http://www.doksi.hu

A float-ok bemeneti formtuma: eljel (elhagyhat),szmokbl ll


lnc,amely tizedespontot s egy (elhagyhat) kitevmezt tartalmazhat,amely utbbi egy E-bl vagy e-bl s az azt kvet,esetleg eljeles
egsz szmbl ll.
A d,o s x konverzis karaktereket az l (el bet) elzheti meg,amely arra
utal,hogy az argumentumlistban long-ot s nem int-et megcmz mutat jelenik meg.Az e vagy f konverzis karaktereket ugyancsak megelzheti az 1,
ebben az esetben azt jelezve,hogy az argumentumlista double-ra s nem
float-ra hivatkoz mutatt tartalmaz.Pldul az
int i;
float x;
char name[50];
scanf(%d %af%s, &i, &x, name);
hvs a
25 54.32E 1 Tltompson
bemenet esetn az i-hez a 25 rtket rendeli hozz, az x-hez az 5.432 rtket
s a name-hez a \0-val rendesen lezrt Thompson karakterlncot. A hrom

bemeneti karakterlncot tetszleges szm szkzzel, tabbal s jsorral lehet


egymstl elvlasztani. Az
int i;
float x;
char name[50];
scanf(%,2d %f%*d %2s, &i, &x, name)
hvs az
56789 0123 45a72
bemenettel 56-ot rendel i-hez, 789.0-t az x-hez, tugorja a 0123-at s a 45
karakterlncot a name-be teszi. Brmelyik bemeneti rutin kvetkez hvsa
az a betnl trtn keresssel fog indulni. E kt pldban a name mutat, s
nem elzheti meg az & szimblum.
Msik pldaknt a 4. fejezetben ismertetett elemi kalkultorprogramot
most gy rjuk t, hogy a scanf vgezze a bemeneti konverzit:
#include < stdio.h>
main() / *Elemi kalkultorprogram*/
double sum, v;
sum = 0;
while (scanf(%lf, &v) != EOF)
printf(\t%.2f\n, sum += v);
A scanf akkor fejezi be mkdst, amikor kimertette a vezrl karakter-lnct, vagy amikor
valamelyik bemenet nem illeszkedik a vezrlsi specifi-kcira. A scanf visszatrsi rtke a sikeresen
illesztett s hozzrendelt be-meneti ttelek szma. Ebbl meghatrozhat, hogy a scanf hny bemeneti
ttelt tallt. Allomny vge esetn a visszaadott rtk EOF; gyeljnk arra, hogy ez nulltl eltr rtk,
amely azt jelenti, hogy a kvetkez bemeneti karakter nem illeszkedik a vezrl karakterlnc els
specifikcijra! A scanf kvetkez hvsakor a keress kzvetlenl az utoljra visszaadott karakter
utn folytatdik.
Mg egy utols figyelmeztets: a scanf argumentumainak mutatknak
kell lennik! A leggyakoribb hiba, amikor valaki azt rja, hogy
scanf(%d, n);
ahelyett, hogy
scanf(%d, &n) _

129

Forrs: http://www.doksi.hu

Ft rna.

7.5.

Formtumkonverzi a tron bell

A scanf s printf fggvnyekkel rokon az sscanf s sprintf, amelyek ugyan-ezeket a konverzikat


vgzik, de llomny helyett karakterlncon dolgoznak.
Az ltalnos formtum:
sprintf(string, control, argl, arg2, . . .)
sscanf(string, control, argl, arg2, . . .)
Az elzekhez hasonlan az sprintf a control szerint formtumozza az argl,
arg2 stb.-beli argumentumokat, az eredmnyt azonban a szabvnyos kimenet
helyett a string-be teszi. A string-nek termszetesen elg nagynak kell lennie
ahhoz, hogy befogadja az eredmnyt. Ha pl. string karaktertmb s n egsz,
akkor
sprintf(name, temp%d, n); a name-ben ltrehoz egy tempNNN alak karakterlncot, ahol NNN az n
rtke.
Az sscanf az ellenttes irny konverzikat hozza ltre - a control-ban
megadott formtum szerint vgighalad a karakterlncon, s a kapott eredmnyeket az argl, arg2 stb.-ben helyezi el. Ezen argumentumoknak mutatknak kell lennik. A
sscanf(name, temp%d, &n); hvs az n-et annak a szmjegyekbl ll karakterlncnak az rtkre
lltja be, amely a name-ban a temp-et kveti.
7.2. Gyakorlat. rjuk meg jra a 4. fejezetben ltott kalkultorprogra-mot gy, hogy a bemenetre s
a szmkonverzira a scanf s/vagy sscanf fgg-vnyeket alkalmazzuk!
7.6.

llomny-hozzfrs

Az idig megrt programok mindegyike a szabvnyos bemenetet olvasta s a szabvnyos kimenetre rt,
amelyekrl mindeddig feltteleztk, hogy valami-lyen varzslatos mdon a helyi opercis rendszer
elre definilta ket a sz-munkra.
A be- s kivitellel val ismerkedsnk kvetkez lpseknt olyan programot runk, amellyel programhoz nem rendelt llomnyhoz frhetnk
hozz. Az ilyen mveletek szksgessgt vilgosan bizonyt program a cat,
amely megnevezett llomnyok halmazt gyjti ki (konkatenlja) a szabvnyos kimenetre. A cat feladata llomnyoknak a terminlra trtn kinyomtatsa, valamint ltalnos cl bemeneti informcigyjts azon programok
szmra, amelyek maguk nem kpesek llomnyokhoz nv szerint hozzfrni. Pl. a
cat x.c y.c parancs az x.c s y.c llomnyok tartalmt a szabvnyos kimenetre nyom-tatja.
Krds, hogyan rjk el, hogy a megnevezett llomnyok beolvassra kerljenek - azaz, hogyan
kthetjk a felhasznl ltal kigondolt kls ne-veket azokhoz az utastsokhoz, amelyek tnylegesen
elolvassk az adatokat.
A szablyok egyszerek. Mieltt egy llomnyt olvasni vagy rni lehet-

130

Forrs: http://www.doksi.hu

ne, az fopen szabvnyos knyvtri fggvnnyel meg kell nyitni. Az fopen


vesz egy kls nevet (mint x.c vagy y.c), bizonyos nyilvntartst vgez, s prbeszdet folytat az
opercis rendszerrel (aminek rszleteivel nem kell trdnnk), s olyan bels nevet ad vissza, amelyet
az llomny ezutn kvetkez olvassai, ill. rsai sorn hasznlnunk kell.
E bels nv valjban mutat, amelyet llomnymutatnak neveznk, s amely egy, az llomnyrl
klnbz informcikat tartalmaz strukt-rra mutat. Itt tallhat pl. a puffer cme, a pillanatnyi
pufferbeli karakter-pozci, annak jelzse, hogy az llomny ppen olvass vagy rs alatt ll stb.
A felhasznlknak a rszleteket nem kell ismernik, mivel az stdio.h-tl
nyert szabvnyos be- s kiviteli defincik egyik rsze a FILE-nak nevezett
struktradefinci. Az llomnymutat szmra szksges egyetlen deklarcira nzve plda a
FILE *fopen(), *fp;
Eszerint fp FILE-t megcmz mutat, s fopen szintn ilyen mutatval tr vissza. Figyeljk meg, hogy
FILE, csakgy, mint int, tpusnv, nem pedig struktracmke; typedef-knt valstottk meg. (Annak
rszleteit, hogy mindez miknt mkdik a UNIX opercis rendszerben, a 8. fejezetben ismertetjk.)
Az fopen tnyleges hvsa a programon bell gy fest:
fp = fopen(name, mode);
Az fopen els argumentuma az llomny neve, amely egy karakterlnc. A m-sodik argumentum, amely
szintn karakterlnc, a md, amely azt jelzi, hogy a felhasznl hogyan akarja hasznlni az llomnyt.
A megengedett mdok az olvass (r: read), az rs (w: write) s a hozzfggeszts (a: append).
Ha rsra vagy hozzfggesztsre nem ltez llomnyt nyitunk meg, akkor az illet llomny (ha lehet)
ltrejn. Ltez llomny rsra trtn megnyitsnak hatsra annak korbbi tartalma elvsz. Hibt
jelent, ha nem-ltez llomnyt olvasni akarunk. Ms hibaokok is elfordulhatnak (pl. ha olyan
llomnyt prblunk meg olvasni, amelyre nincs engedlynk). Brmi-lyen hiba esetn az fopen a
NULL mutatrtkkel tr vissza (amelynek defi-ncija a knyelem kedvrt szintn stdio.h-ban van).
A kvetkezkben azt kell tudnunk, hogyan olvashatjuk a mr megnyitott llomnyokat. Tbb lehetsg van, amelyek kzl a getc s putc csupn
a legegyszerbb. getc az llomny soronkvetkez karaktervel tr vissza;
llomnymutatval kell megadnunk, hogy melyik llomnyrl van sz. Igy
c = getc(fp) az fp ltal hivatkozott llomnybl a kvetkez karaktert c-be helyezi, ill EOF kerl c-be,
ha elrtk az llomny vgt.
A putc a getc inverze :
putc(c, fp)
a c karaktert az fp llomnyba helyezi s c-t adja vissza. A getchar s putchar fggvnyekhez hasonlan
a getc s putc is lehet fggvny helyett makr.
Hrom llomny minden program indtsakor automatikusan megny-lik, s a rendszer
llomnymutatkat is rendelkezsre bocst szmukra. Ezek az llomnyok : a szabvnyos bemenet, a
szabvnyos kimenet s a szab-vnyos hibakimenet; az ezeknek megfelel mutatk neve: stdin, stdout s
stderr. Kznsges esetben ezek mindegyike a terminlhoz van rendelve, azonban az stdin s stderr
mutatkat a 7.2. szakaszban lert mdon llom-nyokba vagy parancslncokba lehet tirnytani. A
getchar s a putchar az albbi mdon definilhat a getc, a putc, az stdin s az stdout segtsgvel:
#define getchar() getc(stdin)
#define putchar putc(c, stdout)
llomnyok formtumozott beolvassra vagy kiratsra az fscanf s fprintf fggvnyeket
hasznlhatjuk. Ezek azonosak a scanf s printf fggvnyekkel, eltekintve attl, hogy az els
argumentum llomnymutat, amely az olva-sand vagy rand llomnyt hatrozza meg; a vezrl
karakterlnc a mso-dik argumentum.

131

Forrs: http://www.doksi.hu

E bevezets utn mr abban a helyzetben vagyunk, hogy megrhatjuk az llomnyokat konkatenl cat
programot. Az alapfelpts azonos azzal, ami mr sok programban knyelmesnek bizonyult: ha vannak
parancssor-ar-gumentumok, akkor azok feldolgozsa sorrendben trtnik. Ha nincsenek argumentumok,
akkor a szabvnyos bemenetet dolgozzuk fel. Ily mdon a program akr nllan, akr valamely
nagyobb feldolgozs rszeknt hasz-nlhat.
#include < stdio.h> main(argc, argv) /* cat: llomnyok konkatenlsa*/ int argc; char * argv [] ;
FILE *fp, * fopen();
if (argc == 1 ) /* Nincs arg., a szabvnyos bemenetet msolja*/
else
filecopy(stdin);
while (--argc _ 0)
if((fp = fopen(*++argv, r)) == NULL){
printf(cat: nem nyithat meg %cs\n, *argv);
break;
} else _
filecopy(fp);
fclose(fp);

filecopy(fp) /*llomny msolsa a szabvnyos kimenetre*/ FILE *fp;


int c;
while ((c = getc(fp)) != EOF)
putc(c, stdout);
Az stdin, ill. stdout llomnymutatk a be- s kiviteli knyvtrban szab-vnyos bemenetknt, ill.
szabvnyos kimenetknt elredefiniltak; min-dentt hasznlhatk, ahol FILE tpus objektumokat
hasznlni lehet. Ezek azonban llandk s nem vltozk, teht ne prbljunk semmit sem hozzjuk
rendelni !
Az fclose fggvny az fopen inverze: megszaktja az llomnymutat s a kls nv kztt az fopen
ltal ltrehozott kapcsolatot, s gy az llomny-mutat egy msik llomny szmra szabadul fel.
Mivel a legtbb opercis rendszerben az egyidejleg megnyitott llomnyok szma korltozott, clszer azokat felszabadtani, ha mr nincs rjuk szksg, amint ezt a cat-ban is tettk. Az fclose kimeneti
llomnyra val alkalmazsnak msik oka is van: rti azt a puffert, amelyben a putc a kimenetet
gyjti. (A program normlis befejezdsekor az fclose automatikusan meghvdik minden megnyitott
llomnyra. )

7.7.

Hibakezels; stderr s exit

A hibknak az a fajta kezelse, amit a cat-ban hasznltunk, nem idelis. A baj az, hogy ha az
llomnyok egyike valamely oknl fogva hozzfrhetetlen, a hibajelzs a konkatenlt kimenet vgre
nyomtatdik. Ez elfogadhat, ha a kimenet a terminlra irnyul, azonban rossz, ha egy llomnyba vagy
pa-rancslncon keresztl egy msik programba megy.
A jobb hibakezels rdekben az stdin s stdout llomnnyal azonos mdon a programhoz egy msodik
kimeneti llomny, az stderr is hozz van rendelve. Ha egyltaln lehetsges, az stderr-re rt kimenet
mg akkor is meg-jelenik a felhasznli terminlon, amikor a szabvnyos kimenetet tirny-tottk.
Mdostsuk a cat programot gy, hogy a hibazeneteket a szabvnyos hiballomnyra rja !
#include < stdio.h> main(argc, argv) /* cat: llomnyok konkatenlsa* / int argc; char * argv[ ];
FILE *fp, *fopen();
if (argc ==1 )

/*Nincs arg., a szabvnyos bemenetet

132

Forrs: http://www.doksi.hu

msolja* / filecopy(stdin);
else
while (--argc _ 0)
if ((fp = fopen(*++argv, r )) == NULL)_
fprintf(stderr, cat: nem nyithat meg %s\n,
argv) ;
exit( 1 );
} else {
filecopy(fp); fclose(fp);
exit(0); }
A program ktflekppen jelzi a hibkat. Az fprintf ltal ellltott diagnosz-tikai kimenet az stderr-re
megy, teht a felhasznl terminljra kerl, s nem tnik el egy parancslncon keresztl vagy
valamelyik kimeneti llo-mnyban.
A program az exit szabvnyos knyvtri fggvnyt is hasznlja. Az exit meghvsa a program
befejezdst eredmnyezi. Az exit argumentum br-milyen, az exit-et hv folyamat rendelkezsre
ll, gy a program sikeres vagy sikertelen lefutst egy msik program oly mdon ellenrizheti, hogy ezt
a programot mint rszfolyamatot hasznlja. Megllapods szerint a 0 visz-szatrsi rtk azt jelzi, hogy
minden rendben ment, mg a klnfle nem-nulla rtkek a normlistl eltr llapotokat jelzik.
Az exit minden megnyitott kimeneti llomnyra meghvja az fclose-t az sszes pufferelt kimenet
kirtse rdekben, majd meghvja az -exit nev rutint, amelynek hatsra a programfuts mindenfle
pufferrts nlkl azonnal vgetr. Az exit szksg esetn termszetesen kzvetlenl is hvhat.

7.8.

Szvegsorok beolvassa s kivitele

A szabvnyos knyvtrban rendelkezsre ll az fgets rutin, amely meglehetsen hasonlt a knyvben vgig hasznlt getline fggvnyhez. Az
fgets(line, MAXLINE, fp) hvs az fp llomnybl a line karaktertmbbe beolvassa a kvetkez bemeneti sort (az jsort is belertve); legfeljebb MAXLINE -1 sort fog olvasni. A kapott tmb \0-val zrul.
Norml esetben az fgets a line-t adja vissza, llo-mny vgn pedig NULL-t. (A getline fggvnynk a
sorhosszat, ill. llo-mny vge esetn a nullt adja vissza.)
Kivitelkor az fputs fggvny karaktersorozatot (amely nem kell, hogy jsort tartalmazzon) r az
llomnyra:
fputs(line, fp)
Annak rzkeltetsre, hogy az olyan fggvnyek krl, mint fgets s fputs nincs semmi varzslatos, a
szabvnyos be- s kiviteli knyvtrbl kzvetlenl ide msoltuk e fggvnyek programkdjt:

#include < stdio.h>


char * fgets(s, n, iop) / * Legfeljebb n karakter olvassa iop-rl* /
char * s;
int n;
register FILE *iop;
register int c;
register char * cs;
cs = s;
while ( --n > 0 && (c = getc(iop)) != EOF)
if ((*cs++ = c) =- \n)

133

Forrs: http://www.doksi.hu

break;
*cs = \0; return((c == EOF && cs == s) ? NULL : s);
fputs(s, iop) j *Az s karakterlncot az iop llomnyra rja*/
register char *s;
register FILE *iop;
register int c;
while (c = *s++)
putc(c, iop);

7.3. Cyakorlat. rjunk olyan programot, amelyik sszehasonlt kt llo-mnyt, s kirja az els
olyan sort s karakterpozcit, ahol az llomnyok el-trnek egymstl!
7.4. Gyakorlat. Mdostsuk az 5. fejezet mintakeres programjt oly mdon, hogy a bemenett
argumentumokknt megnevezett llomnyok hal-mazbl vegye, vagy ha ilyenek nincsenek,
akkor a szabvnyos bemenetrl! Ki kell-e ratni az llomny nevt, ha a program egymsra
illeszked sorokat tall?
7.5. Cy,akurlat. rjunk olyan programot, amely tbb llomnyt nyomtat ki, minden ijabb
llomnyt j oldalon, cm kirsval kezd, s az oldalakat llomnyonknt folyamatosan
szmozza!

7.9.

Nhny tovbbi fggvny

A szabvnyos knyvtr szmos fggvnyt bocst rendelkezsnkre, amelyek kzl nhny klnsen
hasznos. Mr emltettk az strlen, strcpy, strcat s strcmp harakterlnc-kezel fggvnyeket. me
nhny tovbbi fggvny.

Karakterosztly-vizsglat s -talakts
Tbb makro vgez karaktervizsglatot s talaktst
isalpha nemnulla,ha c alfabetikus,0,ha nem.
isupper nemnulla,ha c nagybet,0,ha nem.
islower nemnulla,ha c kisbet,0,ha nem.
isdigit nemnulla,ha c szmjegy,0,ha nem.
isspace nemnulla,ha c szkz,tab vagy jsor,0,ha nem
toupper c talaktsa nagybetss.
tolower c talaktsa kisbetss.

Az ungetch fggvny
A szabvnyos knyvtrban megtalljuk a 4. fejezetben ltalunk megrt ungetch fggvny egy
meglehetsen szktett vltozatt; ennek neve ungetc.
Az
ungetc(c, fp); a c karaktert az fp llomnyba helyezi vissza. llomnyonknt csak egy karakternyi
visszatols megengedett. Az ungetc minden olyan bemeneti fgg-vnnyel s makrval egytt
hasznlhat, mint a scanf, getc vagy a getchar.
Rendszerhvs
A system(s) fggvny az s karakterlncban tartalmazott parancsot hajtja

134

Forrs: http://www.doksi.hu

vgre, majd visszatr az adott program vgrehajtshoz. Az s tartalma ersen


fgg a helyi opercis rendszertl.Trivilis pldaknt a UNIX-ban a
system(date); sor hatsra lefut a date nev program; amely kinyomtatja a dtumot s a na-pon belli
idpontot.
Trkezels
A calloc fggvny igen hasonlt a korbbi fejezetekben hasznlt alloc fgg-vnyre.
calloc(n, sizeof(objektum)) egy mutatt szolgltat, amely olyan helyre mutat, ahol elegend hely van n
darab megadott mret objektum szmra, ill. a NULL rtket adja vissza, ha a krs nem teljesthet.
A trterlet kezdeti nagysga nulla.
A mutat a szban forg objektum tpusnak megfelel helyre mutat, azonban tpusmdost
szerkezettel a megfelel tpusv kell alaktani, pl.:
char * calloc() ;
int *ip;
ip = (int *) calloc(n, sizeof(int));

A cfree(p) felszabadtja a p ltal megcmzett helyet, ahol p-t eredetileg calloc valamelyik hvsval
nyertk. A helyfelszabadts sorrendjre nincs megkts, azonban vgzetes hiba, ha olyasvalamit
szabadtunk fel, amit nem a calloc hvsval nyertnk.
A 8. fejezetben bemutatjuk a calloc-hoz hasonl trterlet-foglal fgg-vny megvalstst, amelyben
a lefoglalt blokkok tetszleges sorrendben szabadthatk fel.

135

Forrs: http://www.doksi.hu

164

136

Forrs: http://www.doksi.hu

_
8.

fejezet

Csatlakozs a lJNIX opercis rendszerhez

E fejezet anyaga a C programok s a UNIX opercis rendszer kztti kapcsolattal foglalkozik. Mivel a
legtbb C programoz UNIX rendszer alatt dolgozik, ezek az ismeretek az olvask tbbsge szmra
hasznosak lesznek. St, mg ha az olvas a C nyelvet ms gpen is hasznlja, e pldk tanulmnyozsa rvn mlyebb betekintst nyerhet magba a C programozsba is.
A fejezet hrom f tmakrre oszlik: bevitel/kivitel, llomnykezels s trterlet-foglals. Az els kt
rsz felttelezi a UNIX kls meg_elensnek legalbb nmi ismerett.
A 7. fejezet olyan rendszer-hatrfellettel foglalkozott, amely szmos opercis rendszerben egyforma.
Brmelyik konkrt rendszerben a szabv-nyos knyvtr rutinjait a befogad rendszerben rendelkezsre
ll be- s kivi-teli szolgltatsok figyelembevtelvel kell megrni. A kvetkez nhny sza-kaszban a
UNIX opercis rendszer be- s kiviteli rendszernek alapvet bel-psi pontjait ismertetjk, s azt
szemlltetjk, miknt lehet ezek segtsgvel a szabvnyos knyvtr egyes rszeit megvalstani.

8.1.

Allomnylerk

A UNIX opercis rendszerben az sszes be- s kivitel llomnyok rsval s olvassval valsul meg,
mivel az sszes perifria, mg a felhasznl terminl-ja is egy-egy llomnyknt jelenik meg. Ez azt
jelenti, hogy egyetlen homo-gn csatolprogram kezeli a program s a perifrik kztt az sszes
kapcso-latot.
A legltalnosabb esetben egy llomny rsa vagy olvassa eltt rtestennk kell a rendszert errl a szndkunkrl. Ezt a folyamatot az llomny
megnyitsnak nevezzk. Ha rni akarunk egy llomnyba, akkor szksg
lehet az llomny ltrehozsra is. A rendszer ellenrzi, hogy minderre van-e
jogunk (Ltezik-e az llomny? Van-e hozzfrsi engedlynk?), s ha minden rendben van, akkor a programhoz egy llomnyleirnak nevezett kis
egsz szmmal tr vissz. Minden esetben, amikor az llomnyon be- vagy kiviteli mveletet akarunk vgezni, az llomny azonostsa cljbl annak
neve helyett az llomnylert hasznljuk (Ez nagyjbl hasonlt a
READ(5, . . .) s WRITE(6, . . .) hasznlatra a FORTRAN-ban.) A megnyi165

137

Forrs: http://www.doksi.hu

8.3.

Open, creat, close, unlink

Az alaprtelmezs szerinti szabvnyos bemeneti, kimeneti s hibakimeneti llomnyon kvl az sszes


llomnyt explicit mdon meg kell nyitnunk, ha azokat rni vagy olvasni akarjuk. Ebbl a clbl kt
rendszerbelpsi pont ll rendelkezsre: az open s a creat (vigyzat, nem create!).
Az open lnyegben ugyanolyan, mint a 7. fejezetben trgyalt fopen, el-tekintve attl, hogy nem
llomnymutatt ad vissza, hanem llomnylert, ami egyszeren egy int.
int fd ;
fd = open(name, rwmode);
Az fopen-hez hasonlan a name argumentum a kls llomnynvnek megfe-lel karakterlnc. Az
elrs mdja azonban eltr: az rwmode rtke olva-sskor 0, rskor 1, s egyidej rsi-olvassi
hozzfrs esetn 2. Hiba el-fordulsakor az open -1-et ad vissza, egybknt a visszatrsi rtk az
rv-nyes llomnyler. Hibhoz vezet, ha nem ltez llomnyt prblunk meg-nyitni.
A creat belpsi pont j llomnyok ltrehozsra vagy rgiek fell-rsra szolgl :
fd = creat(name, pmode); llomnylert ad vissza, ha ltre tudta hozni a name nev llomnyt, s -1-et,
ha nem. Ha az llomny mr ltezik, a creat nulla hosszsgra vgja le, nem jelent teht hibt mr
ltez llomny creat-tel trtn ltre-hozsa.
Ha az llomny vadonatj, a creat azt a pmode argumentumban meg-adott vdelmi mddal hozza ltre.
A UNIX rendszerben minden llomny-hoz kilenc bitbl ll vdelmi informci trsul. Ezek a bitek
az llomny tulajdonosra, a tulajdonos csoportjra, valamint a msokra vonatkoz olva-ssi, rsi s
vgrehajtsi engedlyeket szablyozzk. Az engedlyeket gy legknyelmesebben egy hromjegy
oktlis szmmal adhatjuk meg. PI. 0755 olvassi-rsi-vgrehajtsi engedlyt ad a tulajdonosnak, s
olvassi-vgrehaj-tsi engedlyt a csoport tagjainak s mindenki msnak.
Szemlltets cljbl kzljk a UNIX cp nev segdprogramjnak egy-szerstett vltozatt, amely
egy llomnyt egy msikba msol. (A f egysze-rsts az, hogy az itt kzlt vltozat csak egyetlen
llomnyt msol s nem teszi lehetv, hogy a msodik argumentum katalgus (directory) legyen.)

168

138

Forrs: http://www.doksi.hu

#define NULL 0
#define BUFSIZE 512
#define PMODE 0644 %* RW a tulajdonosnak, R a csQportnak s
msoknak* /
main(argc, argv)/ * cp: fl msolsa f2-be*/
int argc;
char * argv [ ] ;
int fl, f2, n;
char buf [BUFSIZE];
if (argc ! = 3 )
error(Hasznlat: cp honnan hov, NULL); if ((fl = open(argv[ 1 ], 0)) = -1 )
error(cp: nem nyithat meg %s, argv[1 ]); if((f2 = creat(argv[2], PMODE)) = -1)
error(cp: nem hozhat ltre %s, argv[2]); while ((n = read(fl, buf, BUFSIZE )) > 0)
if (write(f2, buf, n) != n) error(cp: rshiba, NULL);
exit(0);
error(sl, s2) / *A hibazenetet kirja s lell* /
char * s I, * s2 ;
printf(s 1, s2);
printf(\n);
exit(1 );
A programok ltal egyidejleg nyitva tarthat llomnyok szma korltozott (tipikusan 15-25). Ennek
megfelelen minden olyan programot, amelynek sok llomnyt kell feldolgoznia, gy kell elkszteni,
hogy kpes legyen az llomnylerk jbli hasznlatra. A close rutin megszaktja az llomny-ler s
a megnyitott llomny kztti kapcsolatot s felszabadtja az llo-mnylert, gy azt a ksbbiekben
ms llomny hasznlhatja. A program exit hatsra trtn befejezse s a fprogrambl val
visszatrs az sszes megnyitott llomnyt lezrja.
Az unlink(filename) fggvny a filename nev llomnyt trli az llo-mnyrendszerbl.
8.I. Gyakorlat. Irjuk t a 7. fejezetben ltott cat programot gy, hogy a read, write, open s close
rutinokat hasznljuk azok szabvnyos knyvtr-beli megfeleli helyett! Vgezznk ksrleteket a
kt vltozat egymshoz vi-szonytott sebessgnek meghatrozsra! 0

169

139

Forrs: http://www.doksi.hu

R.4.

Vletlen hozzfrs; seek s Iseek

llomnyok be- s kivitele ltalban soros: minden read s write az llo-mnynak azon a pozcijn
trtnik, amely kzvetlenl a megelz be- vagy kivitel llomnybeli pozcijt kveti. Szksg esetn
azonban az llomny tetszleges sorrendben olvashat vagy rhat. Az lseek rendszerhvs lehetv
teszi, hogy tnyleges olvass vagy rs nlkl mozoghassunk az llomnyban:
lseek(fd, offset, origin);
hatsra az fd lerj llomnyban az aktulis pozci az offset pozcira mozdul, amelyet az origin
ltal meghatrozott helyhez kpest relatven rtel-meznk. Az ezt kvet olvass vagy rs ezen az j
pozcin fog kezddni. Az offset long tpus: az fd s az origin int tpusak. Az origin 0, 1 vagy 2
lehet, jelezve, hogy az offset-et az llomny elejtl, a pillanatnyi pozcitl, vagy az llomny vgtl
kell szmtani. Ha pl. az llomnyhoz valamit hozz akarunk fggeszteni, rs eltt keressk meg az
llomny vgt :
lseek(fd, OL, 2);
Ha vissza akarunk trni az llomny elejre (visszatekercsels)
lseek(fd, OL, 0);
Figyeljk meg a OL argumentumot, ezt (long)0-nak is rhatnnk.
Az lseek hasznlatval lehetsgnk van arra, hogy az llomnyokat lassbb hozzfrs rn nagy
tmbkhz hasonlan kezeljk. Az albbi egyszer fggvny pl. az llomny tetszleges pontjrl
tetszleges szm byte-ot olvas be:
get(fd, pos, buf, n)

/ * n byte olvassa a pos pozcirl* / int fd, n; long pos; char * buf;

lseek(fd, pos, 0);


/*Elmegy pos-ra*/
return(read(fd, buf, n));

A UNlX rendszer 7-est megelz vltozataiban a be- s kiviteli rendszer alap-vet belpsi pontjnak
neve: seek. A seek s az lseek azonosak, attl elte-kintve, hogy az elbbinek az offset argumentuma
nem long, hanem int. Ennek megfelelen, mivel a PDP I 1 int-ek 16 bitesek, a seek-nek megadhat
offset fels korltja 65535; ezrt a 3, 4, 5 origin rtkek hatsra a seek a megadott offset rtket 512vel la fizikai blokkban tallhat byte-ok szm-val) megszorozza, majd az origin-t gy rtelmezi,
mintha az adott sorrendben 0, 1 vagy 2 lenne. lly mdon, ha egy nagy llomny tetszleges pontjra
akarunk lpni, akkor kt seek-re van szksgnk: az elsvel a blokkot vlaszt-juk ki, a msodikkal
pedig, amelyben az origin rtke I, a blokkon bell a k-vnt byte-ra mozdulunk.
8. ?. C__u_urlat. Vilgos, hogy az lseek a seek felhasznlsval megrhat
s viszont. Irjuk meg mindkettt a msik felhasznlsval!

140

Forrs: http://www.doksi.hu

8.5. Plda; az fopen s a getc megvalstsa


Prbljuk meg egysgbe foglalva szemlltetni a mondottakat az fopen s getc szabvnyos
knyvtri rutinok egyik megvalstsnak bemutatsval.
Emlkezznk arra, hogy a szabvnyos knyvtr llomny-ait nem llo_

mnylerk, hanem llomnymutatk jellemzik. Ez utbbiak olyan struktrra mutatnak, amely az llomnyra vonatkoz klnbz informcikat
tartalmaz: egy puffert megcmz mutatt, ami lehetv teszi az informci
nagy darabokban trtn beolvasst; a pufferben maradt karakterek darabszmt; a kvetkez pufferbeli karakterpozcit megcmz mutatt; nhny
_ jelzt (flag-et), amelyek pl. az olvass/rs mdot rjk le; s vgl az llomnylert.
Az llomnyt ler adatstruktra az stdio.h llomnyban tallhat, amelyet (#include-dal) minden olyan forrsllomnyba be kell iktatni, amely a
szabvnyos knyvtr valamelyik rutinjt hasznlja. A knyvtrbeli fggv_ nyek ugyancsak tartalmazzk. Az stdio.h-bl vett albbi kivonatban azok
a nevek, amelyeket csak a knyvtrbeli fggvnyek hasznlhatnak, alhzssa1 kezddnek, gy kisebb annak a valsznsge, hogy valamelyik felhasznli programbeli nvvel sszetkzsbe kerljenek.
#define -BUFSIZE 512
#define NFILE
20 /*Kezelhet llomnyok szma* !
typedef struct -iobuf(
char * -ptr;
/ * Kvetkez karakterpozci*/
int cnt;
/* Megmaradt karakterek szma* /
char * - base; /* A puffer cme* /
int flag;
/* Az llomnyelrs mdja* /
int fd;
/ * llomnyler* /
}FILE;
extern FILE iob[ NFILE];
#define stdin (& iob[0])
#define stdout (& iob[ 1 ])
#define stderr (& iob[2])
#define READ 01 j *llomnymegnyits olvassra*/
#define -WRITE 02 /* llomnymegnyits rsra */
#define UNBUF 04 /*Az llomny puffereletlen* j
#define -BIGBUF 010 /* Nagy pufferlefoglals* /
#define EOF 020 /* EOF fordult el ebben az llomnyban* /
#define ERR 040 /*Hiba fordult el ebben az llomnyban*/
#define NULL
0
#define EOF
( 1)
#define getc(p) ( = -(p) - 7 cnt > = 0\
? *(p) - >
ptr++ & 0377: fillbuf(p))
#define getchar() getc(stdin)
#define putc(x,p) (--(p) = _ cnt > = 0\
? *(p) - _ =ptr++ = (x) : -flushbuf((xj,p))
#define putehar(x) putc(x,stdout)

141

Forrs: http://www.doksi.hu

A getc makr norml esetben egyszeren dekrementlja a darabszmot, el-relpteti a mutatt, s


visszaadja a karaktert. (A hossz #define-okat ford-tott \ trtvonallal lehet folytatni.) Ha a darabszm
negatvv vlik, a getc meghvja a __fillbuf fggvnyt, amivel jratlti a puffert, jrainicializlja a
struktra tartalmt, s egy karaktert ad vissza. A fggvnyek rendelkezhet-nek gpfggetlen
csatlakozfellettel, akkor is, ha maguk gpfgg konstruk-cikat tartalmaznak: a getc 0377-tel
maszkolja a karaktert, amely fellbrlja a PDP =11 ltal vgrehajtott eljel-kiterjesztst, s biztostja,
hogy minden karakter pozitv legyen.
Br nem kvnunk rszletekbe menni, mgis beiktattuk a putc definci-jt annak bemutatsra, hogy az
lnyegben ugyangy mkdik, mint a getc, azaz amikor a puffere megtelt, meghvja a _flushbuf
fggvnyt.
Ezek utn megrhatjuk az fopen fggvnyt. Az fopen legnagyobb rsze azzal foglalkozik, hogy
megnyitja az llomnyt, a megfelel helyre pozicio-nlja, s gy lltja be a jelzbiteket, hogy azok a
helyes llapotot mutassk. Az fopen pufferterletet nem foglal le: ezt az llomny els olvassakor a
_fillbuf vgzi.

172

142

Forrs: http://www.doksi.hu

#include stdio.h
#define PMODE 0644 _ * R/W a tulajdonosnak; R msoknak* I
FILE *fopen(name, mode) /*Megnyitja az llomnyt, az llomnymutatt adja vissza* /
register char *name, *mode;
register int fd ;
register FILE *fp;
if(*mode != r && *mode != w && *mode != a) f
fprintf(stderr, tiltott md %s a %s megnyitsakor \n,
mode, name); exit(1 );
for (fp = _iob; fp C -iob + -NFILE; fp++) if ((fp- _ -flag & (-READ _ -WRITE)) == 0)
break; / * Szabad terletet tallt* / if (fp _ = -iob + -NFILE) /*Nincs szabad hely*/ return(NULL);
if (*mode =- w) /*Allomnyhozzfrs* I
fd = creat(name, PMODE);
else if (*mode == a) {
if ((fd = open(name,1 )) =- -1 )
fd = creat(name, PMODE); lseek(fd, OL, 2);
} else
fd = open(name, 0);
if (fd = -1 ) / * Nem tudta a nevet elrni* I
return(NULL);
fp- _ -fd = fd;
fp- > -cnt = 0;
fp- > -base = NULL;
fp- > -flag & = ^(-READ _ -WRITE);
fp- _ -flag _ = (*mode == r ) ? -READ : -WRITE; return(fp);
A -fillbuf fggvny jval bonyolultabb. A bonyolultsg f oka, hogy -fillbuf akkor is megksrli az
llomny-hozzfrs engedlyezst, ha eset-leg a be- s kivitel pufferelshez nincs elegend tr. Ha a
calloc-tl tovbbi hely nyerhet jabb puffer ltrehozsra, akkor minden rendben van. Ha nem, akkor
a -fillbuf puffereletlenbe- s kivitelt vgez egyetlen karakter hasznlatval, amelyet az egyik sajt
tmbjben trol.

173

143

Forrs: http://www.doksi.hu

#include < stdio.h>


fillbuf(fp) /*Bemeneti puffer lefoglalsa s feltltse*/ register FILE *fp;
static char smallbuf [ NFILE]; _*Puffereletlen I/O-ra*/
ehar * calloc( ) ;
if((fp-> --flag& READ)== 0 II (fp-7 flag&
(-EOF II -ERR)) != 0) return(EOF);
while (fp-> base == NULL) / *Pufferterletet keres* ;
if (fp-_ flag& UNBUF) /*Puffereletlen*/
fp> -base = & smallbuf[fp-_ _fd];
elseif ((fp-_ base = calloc(-BUFSIZE, 1))==_LLLl
fp-_ flag I = UNBUF; _ *Nem kap nagy
puffert* _
else
fp--_ -flag I = BIGBUF; ! * Nagy puffert kapott* !
fp-_ -ptr = fp- > base;
fp -> cnt = read(fp-_ fd, fp--_ ptr,
fp -> flag& UNBUF ? 1: -BUFSIZEl;
if (--fp -> cnt C 0) {
if (fp-> cnt =- --1 )
fp--] flag I = EOF.;
else
fp-> flag I = ERR; fp-_ cnt = 0; return(EOF);
return(*fp-> ptr++ & 0377); _*.A karaktert pozitvv teszi*;
A getc valamely llomnyra vonatkoz els hvsakor a darabszm 0, ami elidzi a fillbuf meghvst.
Ha a _fillbuf gy tallja, hogy az llomny nincs olvassra megnyitva, azonnal az EOF rtkkel tr
vissza. Egybknt megksrli a nagy puffer lefoglalst, s ha ez nem sikerl, az egykarakteres puffert
utalja ki a -flag-beli pufferelsi informci rtelemszer belltsval.
Ha egyszer a puffer ltrejtt, a fillbuf annak feltltsre egyszeren meghvja a read rutint, belltja a
darabszmot s a mutatkat, majd a puffer kezdetn tallhat karakterrel tr vissza. A _fillbuf tovbbi
hvsaikor a puf-fer mr rendelkezsre ll.
Az egyetlen dolog, amit mg nem tisztztunk, hogy minden hogyan indul. Az stdin, stdout s stderr
szmra definilni s inicializlni kell az iob tmbt:

174

144

Forrs: http://www.doksi.hu

FILE iob [ NFILEl ={


{NULL,_, NULL, READ, 0}, _* stdin */
{NULL, 0, NULL, WRITE, 1 }, / * stdout */
{NULL, 0, _ULL, WRITE _ UNBUF, 2 } / * stderr * /
};
A struktra flag rsznek inicializlsa mutatja, hogy stdin-t ovasni, stdout-ot rni kell, stderr-re
pedig pufferels nlkl runk.
8.3. Gyakorlat. Irjuk t fopen-t s fillbuf-ot gy, hogy explicit bitm-veletek helyett mezket
hasznlunk!
D
8.4. Gyakorlat.
Tervezzk
s
rjuk meg a
_flushbuf s fclose ruti-nokat!
0
8.5. Gyakorlat. A szabvnyos knyvtrban rendelkezsnkre ll az fseek(fp, offset, origin)
fggvny, amely azonos az lseek fggvnnyel attl eltekintve, hogy fp llo-mnymutat s nem
llomnyler. Irjuk meg fseek-et! Gondoskodjunk arrl, hogy az ltalunk rt fseek helyesen
mkdjn egytt a knyvtr tbbi fggvnyei szmra vgzett pufferkezelssel! 0

8.6. Plda; katalgusok kilistzsa


Idnknt az eddigiektl eltr jelleg prbeszdet kell folytatnunk az llo-mnyrendszerrel:
mag_ra az llomnyra vonatkoz informcira van szks-gnk, nem pedig arra, hogy mit
tartalmaz az llomny. Plda erre az ls (list directory) nev UNIX parancs, amely kinyomtatja az
adott katalgusban tallhat llomnyok nevt, s kvnsg szerint egyb informcit is kzl,
mint pl. a mreteket, az engedlyeket stb.
Mivel legalbbis a UNIX esetben a katalgus maga is egy llomny,

semmi klns nincs az olyan parancsokban, mint az ls: beolvas egy llomnyt, s kiemeli belle a szmra fontos informcit. Ennek az informcinak a formtumt ugyanakkor maga a rendszer hatrozza meg, nem pedig
a felhasznli program, gy az ls-nek ismernie kell az opercis rendszer brzolsmdjt.
E megjegyzsek kzl nhnyat az fsize program megrsval fogunk
szemlltetni. Az fsize az ls olyan specilis formja,amely az argumentumlistjban megnevezett sszes llomny mrett kinyomtatja. Ha az llomnyok valamelyike katalgus, az fsize erre rekurzvan alkalmazza nmagt.
Ha egyltaln nem adtunk meg argumentumot, az aktulis katalgust dolgozza fel.
Indulsknt rviden tismteljk az llomnykezelssel kapcsolatos
tudnivalkat. A katalgus (directory) olyan llomny, amely llomnynevek
listjt tartalmazza, s utal arra, hogy a megfelel llomnyok hol tallhatk.
175

145

Forrs: http://www.doksi.hu

Az llomnyok cime valjban egy msik tblzatba, az inode tblzatba mutat index. Az llomny
inodeja az a hely, ahol a nevet kivve az llo-mnyra vonatkoz sszes informci troldik. A
katalgus bejegyzs csupn kt ttelt tartalmaz: az inode-szmot s az llomny nevt. A pontos
specifikci a sys/dir.h llomny beiktatsval jn ltre, amelynek tartalma:
#define DIRSIZ 14/*Az llomnynv max. hossza* /
struct direct

_ * A katalgusbejegyzs struktrja* _

ino_t d ino; _ * Inode-szm* /


char d name[DIRSIZ); / *Allomnynv*/

Az ino_t tpus olyan typedef, amely az inode-tblzatba mutat indexet r le. A PDP =11 UNIX
esetben ez unsigned, de ilyenfajta informcit nem szoks a programba gyazni: ms rendszerben ez
eltr lehet. Innen a typedef. A rendszertpusok teljes kszlete a sys/types.h-ban tallhat.
A stat fggvny veszi az llomny nevt, s az annak inode jban tall-hat sszes informcit (vagy
hiba esetn -1-et) adja vissza. Eszerint :
struct stat stbuf;
char * name;
stat(name, &stbuf);
az llomnynvre vonatkoz inode informcival tlti fel az stbuf struktrt. A stat ltal visszaadott
rtket ler struktra a sys/stat.h-ban tallhat, for-mja a kvetkez:
struct stat _ *A stat ltal visszaadott struktra*_
dev t st-dev;
/*Az inode perifrija*
ino t st_ino;
/ * Inode-szm* /
short st-mode;
/* Md bitek* /
short st
nlink; /*Az llomnyra mutat linkek szma* I
short st
uid; /*A tulajdonds felhasznl azonostja*/
short st
gid; /*A tulajdonos csoportjnak azonostja*/
dev_t st
rdev; / * Specilis llomnyokra*/
off_t st
size; [*Allomnymret karakterekben* /
time- t st atime; /*Az utols hozzfrs idpontja* /
time t st_mtime;
/*Az utols mdosts idpontja* /
time t st-ctime;
/ *Az eredeti itrehozs idpontja* /
i;
Ezek legtbbjt a megjegyzsek megmagyarzzk. Az st_mode bejegyzs az llomnyt ler jelzket
tartalmaz; a knyelem kedvrt a jelzdefincik ugyancsak rszei a sys/stat.h-nak.
176

146

Forrs: http://www.doksi.hu

#define S_IFMT
0160000/* Az llomny tpusa* I
#define S IFDIR 0040000 /*Katalgus* /
#define S_IFCHR 0020000/*Specilis karakter* /
#define S_IFBLK 0060000/* Specilis blokk* /
#defineS IFREG 0100000/*Szablyos*/
#define S ISUID 04000 / * Felhasznl azonost belltsa vgrehaj tsra* _
#define S ISGID 02000 _* Csonortazonost belltsa vgrehajtsra* /
#define S ISVTX 01000 /*Az tvitt szveget hasznlat utn
menti* /
#define S IREAD 0400 I *,Olvassi engedly* /
#define S IWRITE 0200 /*Irsi engedly* /
#define S IEXEC 0100 /,* Vgrehajtsi engedly* _
Most mr meg tudjuk rni az fsize programot. Ha a stat-tl kapott md azt jelzi, hogy az llomny nem
katalgus, akkor a rendelkezsre ll mret kz-vetlenl kinyomtathat. Ellenkez esetben a katalgust
llomnyonknt fel kell dolgoznunk: ez maga is tartalmazhat alkatalgusokat, gy a folyamat rekurzv.
A frutin szoks szerint elssorban a parancssor-argumentumokkal fog-lalkozik: egy nagy pufferben ad
t minden egyes arugmentumot az fsize fggvnynek.
#include < stdio.h>
#indlude < sys/types.h> / *typedef-ek* /
#include < sys/dir.h> / * Katalgusbejegyzs struktra* /
#include < sys/stat.h> /*A stat ltal visszaadott struktra*_
#define BUFSIZE 256 main(argc, argv) /* fsize: llomnymretek kinyomtatsa*/ char * argv[ ] ;
char buf [BUFSIZE];
if (argc == 1 ) { /*Alaprtelmezs: az aktulis katalgus* /
strcpy(buf, .); fsize(buf);
} else
while ( argc_0) {
strcpy(buf, * ++argv);
fsize(buf);

Az fsize fggvny az llomny mrett nyomtatja ki. Azonban ha az llo-mny katalgus, akkor elszr
az sszes benne lev llomny kezelse rde-kben meghvja a directory fggvnyt. Figyeljk meg a
stat.h-ban az S IFMT s S IFAIR jelznevek hasznlatt:

147

Forrs: http://www.doksi.hu

fsize(name) /* Kinyomtatja a megadott nev llomny


mrett* /
char *name;
struct stat stbuf;
if (stat(name, &stbuf) =- -1 ) {
fprintf(stderr, fsize: %s nem tallhat\n, name); return;
if ((stbuf.st mode& S IFMT) == S IFDIR)
directory(name);
printf(%old %s\n, stbuf.st size, name);
A directory fggvny a legbonyolultabb.A legnagyobb rsze azonban a szban forg llomny teljes
elrsi nevnek (pathname) ellltsval foglal-kozik. directory(name) _ * fsize a name-ben lev
sszes llomnyra* ; char *name; struct direct dirbuf; char *nbp,*nep; int i,fd; nbp = name +
strlen(name);
*nbp++ = /; /* / hozzadsa a katalgus nevhez* _ if (nbp+DIRSIZ+2_ = name+BUFSIZE) / *A
nv tl hossz* !
return;
if ((fd = open(name, 0)) = -1 )
return;
while (read(fd, (char *) & dirbuf, sizeof(dirbuf)) _ 0(
if (dirbuf.d ino == 0) /*A rovat nincs hasznlatban* i
continue;
if (strcmp(dirbuf.d name, .) == 0
II strcmp(dirbuf.d name, ..) == 0) continue; /*nmagt s a szlt tugorja* !
for (i=0, nep=nbp; i C DIRSIZ; i++)
*nep++ = dirbuf.d name[i];
*nep++ = \0; fsize(name);
close(fd);
* - nbp = \0; /*Nv helyrelltsa* _

148

Forrs: http://www.doksi.hu

Ha a katalgus adott rovata. ppen nincs hasznlatban (mivel az llomnyt tneveztk), a md


bejegyzs nulla, s ezt a pozeit tugorjuk. Minden kata-lgus tartalmazza bejegyzsknt nmagt a
.nv alatt, valamint a szljt a .. nv alatt. Ezeket nyilvn t kell ugrani, klnben a program j
ideig futni fog.
Br az fsize program meglehetsen specilis, szmos fontos gondolatot mutat be. Elszr is, sok
program nem rendszerprogram, csupn olyan infor-mcit hasznl, amelynek formjt vagy tartalmt az
opercis rendszer kezeli. Msodszor, ilyen prograrxiok esetben lnyeges, hogy az informci
brzolsa csak olyan szabvnyos, n. fej (header) llomnyokban jelenjen meg, mint stat.h s dir.h,
tovbb, hogy a programok a konkrt deklarcik alkalmazsa helyett ezeket az llomnyokat iktassk
be.
8.7.

Plda; trterlet lefoglalsa

Az 5. fejezetben az alloc egyszerstett vltozatt mutattuk,be. A most meg-rand vltozat mr nem


tartalmaz korltozsokat abban az rtelemben, hogy most az alloc s a free hvsai tetszleges
sonendben kvethetik egy-mst, szksg esetn az alloc az opercis rendszertl ignyel tovbbi
trter-letet. Ezek a rutinok nmagukban is hasznosak, emellett rvilgtanak arra, hogyan lehet
gpfgg programokat viszonylag gpfggetlen mdon megrni, s a struktrk, az unionok, ill. a
typedef vals letbl vett alkalmazsait is bemutatj k.
Az alloc a helyfoglalst nem a program rszt kpez, rgztett mret tmbbl vgzi, hanem
szksg szerint az opercis rendszel-tl ignyel jabb trterletet. Mivel a porgramban foly egyb
tevkenysgek aszinkron mdon ugyancsak ignyelhetnek helyet, elfordulhat, hogy az alloc ltal
kezelt terlet nem lesz folytonos. gy a szabad terlet szabad blokkokbl ll lncot alkot. A
blokkok a tulajdonkppeni szabad hely mellett egy mretet s egy, a kvetkez blokkot megcmz
mutatt tartalmaznak. Nvekv trcm szerint kvetik egymst, s az utols (legmagasabb cm)
blokk a legelsre mutat. Ily mdon a lnc valjban gyrt kpez.
Trkrs esetn a program tvizsglja a szabad blokkok listjt, hogy tartalmaz-e elegenden nagy
szabad blokkot. Ha a tallt blokk mrete ponto-san megegyezik a krt mrettel, akkor lekapcsolja a
listrl s tadja a fel-hasznlnak. Ha a- blokk tlsgosan nagy, akkor a program kettvgja, s a
felhasznlnak csak a megfelel mret terletet utalja ki, a maradkot pedig visszahelyezi a szabad
listba. Vgl, ha nem tallt elegenden nagy blokkot, akkor jabb blokkot kr az opercis
rendszertl, rkapcsolja a sza-bad listra, majd jra kezeli a keresst.
A blokkfelszabadts szintn a szabad lista vizsglatval indul, a prog-ramnak ugyanis keresnie kell
a listban egy olyan helyet, ahov a felszabad-tani kvnt blokkot beillesztheti. Ha a felszabadtott
blokk brmelyik oidaln szomszdos egy listabeli blokkal, akkor a kett egyetlen, nagyobb blokk
egyesl, gy a tr nem tredezik fel tlsgosan. A szomszdossg tnyt knnyen megllapthatjuk,
hiszen a szabad listban a blokkokat cmnvekv sorrendben tartjuk nyilvn.

149

Forrs: http://www.doksi.hu

Az egyik problma, amit az 5. fejezetben rintettnk annak biztostsa volt, hogy az alloc ltal
visszaadott terlet helyesen illeszkedjen azokhoz az objektumokhoz, amelyeket ott trolni kvnunk.
Br a gpek klnbzek, minden gpen ltezik egy olyan tpus, amely, ha egy adott cmen
trolhat, akkor ott az sszes tbbi tpus is biztosan trolhat. P1. az IBM 360/370, a Iloneywell
6000 s sok ms gp esetben brmilyen objektum trolhat olyan hatron, amely a double szmra,
a PDP-11 esetben pedig az int szmra megfelel.
A szabad blokkban a tulajdonkppeni szabad terletet megelz vezr-lsi informcit (a lncban
kvetkez blokkot megcmz mutatt s a blokk mrett) fejnek nevezzk. Az illeszts
egyszerstse rdekben minden blokk a fejmret tbbszrse, maga a fej pedig megfelelen
illeszkedik. Ezt az albbi unionnal rhetjk el, amely tartalmazza a kvnt fejstruktrt, valamint a
legnehezebben illeszthet tpusra vonatkoz kittelt:
typedefint ALIGN; /*Illeszkedst biztost a PDP-11-en*_
union header{ / * Szabad blokk fej*_
struct{
union header * ptr; / * Kv. szabad blokk* /
unsigned size;

/ * Ennek a szabad blokknak a mrete* _

}s;
ALIGN x; / *A blokkok illesztse* /
_;
typedef union header HEADER;
Az alloc rutinban a karakterekben elrt mretet felkerektjk a megfelel szm fejmret egysgg. A
tnylegesen kiutalt blokk eggyel tbb ilyen egy-sget tartalmaz, t.i. egy egysgre magnak a fejnek is
szksge van, s ez a da-rabszm kerl a fej size mezjbe. Az alloc ltal visszaadott mutat a szabad
terletre mutat, nem pedig magra a fejre.

180

150

Forrs: http://www.doksi.hu

static HEADER base; / * res lista az indulshoz* / static HEADER *allocp = NULL; /*Az utols
lefoglalt blokk*/ char * alloc(nbytes) / * Altalnos cl trfoglal* / unsigned nbytes;
HEADER *morecore();
register HEADER *p, *q;
register int nunits;
nunits =1 + (nbytes+sizeof(HEADER)-1 )/sizeof(HEADER);
if ((q = allocp) == NULL) {_ /*Mg nincs szabad lista*I
base.s.ptr = allocp = q = &base; base.s.size = 0;
for (p=q- _ s.ptr; ; q=p, p=p- _ s.ptr)
if (p- _ s.size _= nunits){
if (p- _ s.size == nunits)
q- _ s.ptr = p- 7 s.ptr;
else {

/*Elg nagy* I
/*Pontosan akkora* I

/ * A hts felt foglalj a le* /

p- > s.size -= nunits; p += p- _ s.size; p- > s.size = nunits;


allocp = Q;
return((char * ) (p+ 1 ));
if (p == allocp) I * Krljrtaa szabad listt* /
if ((p = morecore(nunits)) == NULL)
return(NULL);

/* Nincs tbb* /

A base nev vltozt hasznljuk indulskor. Ha, mint alloc els hvsakor, az allocp rtke NULL, egy
elfajult szabad lista jn ltre: egyetlen, nulla mret blokkot tartalmaz s sajt magra mutat. Ezutn a
program minden esetben vgigkeresi a szabad listt. A megfelel mret szabad blokkot azon az
(allocp) ponton kezdi keresni, ahol legutoljra tallt szabad blokkot; ez a stratgia elsegti, hogy a lista
homogn maradjon. Ha a program tl nagy blokkot tall, akkor a felhasznl a blokk msodik felt
kapja meg, ily mdon az eredeti fejben csak a mretet kell helyesbteni. A felhasznl-nak tadott
mutat mindig a tnyleges szabad terletre mutat, amely egy egysggel a fej mgtt helyezkedik el.
Figyeljk meg, hogy p karakterr alakul t, mieltt az alloc visszaadn.
A morecore fggvny az opercis rendszertl kr trterletet. Ennek megoldsi mdja termszetesen
opercis rendszertl fggen vltozik.
A UNIX-ban az sbrk(n) rutin olyan mutatt ad vissza, amely n byte-nyi tr181

151

Forrs: http://www.doksi.hu

terletre mutat. (A mutat minden illeszkedsi megktsnek eleget tesz.) Mivel tr krse a rendszertl
viszonylag kltsges mvelet, ezt nem akarjuk az alloc minden hvsakor megtenni, ezrt a morecore a
krt egysgek szmt nagyobb rtkre kerekti fel; ezt a nagyobb blokkot aztn szksg szerint
darabolhatjuk fel. A megnvels rtke olyan paramter, amely az ignyek-nek megfelelen
vltoztathat.
#define NALLOC 128/* Az egyszerre lefoglaland egysgek
szma* / static HEADER *morecore(nu) /*Tr krse a rendszertl*/ unsigned nu;
char *sbrk();
register char *cp;
register HEADER *up;
register int rnu;
rnu = NALLOC * ((nu+NALLOC 1 ) / NALLOC);
cp = sbrk(rnu * sizeof(HEADER));
if ((int) cp = -1 ) _ * Egyltaln nincs hely* /
return(NULL); up = (HEADER *) cp; up- _ s.size = rnu; free((char * ) (up+ 1 )); return(allocp);
Amennyiben nem volt hely, az sbrk -1-et ad vissza, br a NULL clszerbb vlaszts lett volna. A
biztonsgos sszehasonlthatsg rdekben a = I -et int-t kell alaktani. Ismt srn hasznltuk a
tpusmdostst, gy a fggvny viszonylag rzketlen az egyes gpek mutatbrzolsnak
klnbzsgre.
Maga a free utolsnak maradt. Egyszeren tvizsglja a szabad listt az allocp-tl kezdve, mikzben
keresi a szabad blokk beillesztsre alkalmas helyet. Ez vagy kt, mr ltez blokk kz esik, vagy a
lista vgn van. Ha a felszabadtand blokk brmelyik esetben szomszdos valamely msik szabad
blokkal, akkor a program a kettt egyesti. Csupn arra kell gyelni, hogy a mutatk mindig a megfelel
helyre mutassanak s a mretek helyesek legyenek!

182

152

Forrs: http://www.doksi.hu

free(ap) / *Az ap blokkot a szabad listba teszi* / char * ap ;


register HEADER *p, *q;
p = (HEADER *) ap -1; _*A fejre mutat* /
for (q=allocp; !(p _ q && p C q-_ s.ptr); q=q-7 s.ptr) if (q _= q- _ s.ptr && (p > q I_ p C q-> s.ptr))
break; /*Egyik vagy msik vgn*/
if (p+p-_s.size == q->s.ptr){

/*Egyesl a fels szom-

szddal* / p-7s.size += q-7s.ptr-_s.size; p-7s.ptr = q-_s.ptr->s.ptr;


} else
p-7s.ptr = q-_s.ptr;
if (q+q- _s.size == p) /* Egyesl az als szomszddal* / q-_s.size += p ->s.size; q-7s.ptr = p-_s.ptr;
} else
q-_s.ptr = p;
allocp = q;
Br a trterletfoglals lnyegnl fogva gpfgg, a bemutatott program szemllteti, hogyan tarthatjuk
kzben s korltozhatjuk a program egszen kis rszre a gpfgg vonatkozsokat. A typedef s az
union segtsgvel gondoskodhatunk az sszeillesztsrl (feltve, hogy az sbrk a megfelel mutatt
szolgltatja). A tpusmdost szerkezetek hasznlata explicitt teszi a mutatkonverzikat, s mg
rosszul tervezett rendszercsatlakozssal is meg-brkzik. Noha az itt kzlt rszletek a
trterletfoglalsra vonatkoznak, az elv, a megkzelts ms esetekben is alkalmazhat.
8. 6. Gyakorlat. A calloc(n, size) szabvnyos knyvtri fggvny n darab size nagysg objektumot
megcmz mutatt ad vissza, a trterlet kezdeti nagysga nulla. Irjuk meg a calloc fggvnyt gy, hogy
az alloc-ot mintaknt vagy hvott fggvnyknt hasznljuk!
8. 7. Cyakorlat. Az alloc a mretre vonatkoz krst anlkl fogadja el, hogy annak jogossgt
ellenrizn. A free azt hiszi, hogy az a blokk, amely-nek felaszabadtst tle krik, rvnyes mret
mezt tartalmaz. Javtsuk e programok minsgt azzal, hogy nagyobb gondot fordtunk a hibaellenrzsre!
8.8.
Gyakorlat. rjuk meg a bfree(p, n) rutint, amely az alloc s a free ltal kezelt szabad lista
szmra felszabadtja az n karakterbl ll tetszleges p blokkot! bfree hasznlatval a felhasznl
brmikor beiktathat a szabad lis-tba egy statikus vagy kls tmbt.

153

Forrs: http://www.doksi.hu

_
SZMALK
Oktat- s Konzultcis Kzpont
C programozsi nyelv II.
TANANYAG
Ksztette: Dombai Norbert
Gpre vitte: Bognr Zoltn
C programozsi nyelv II.

Direkt konzol I/O


----------------Alapja: conio.h

header file

Lnyege, hogy minden billenty, illetve kperny mvelet pufferetlen, s tirnythatatlan. Ezrt sokkal
gyorsabb, mint a standard file-ok kezelse. Lssuk a fggvnyeket!

1.

int getch()

Bekr egy karaktert a billentyzetrl. Echo nlkl, puffereletlen beolvass.


Vissza: a beolvasott karakter kdja.

2.

/*Hibt nem ad vissza*/

int getche()

u. a. mint a getch() csak echoval.

3.

int ungetch
int c;
/* karakterkd */

Visszateszi c karaktert a billentyzetpufferbe. Ksbb ezt ki lehet


olvasni. Akr halkan is. /* pl. ch=getch() */
Vissza: a karakter kdja
HIBA esetn :EOF.

4.

int ungetch(c,fptr)
int c;
/* karakter */
FILE *fptr; /* file-pointer */

154

Forrs: http://www.doksi.hu

Visszateszi c karaktert az fptr file-ba. Pufferelt tvitelt kell ekkor megvalstani, s a file-nak olvassra
kell megnyitva lennie!
Vissza: a karakter kdja
HIBA: EOF
Figyelem! Semmi kze az ungetch()-hoz.

5.

int kbhit()

Ellenrzi a billentyzet-puffert, hogy van-e ott lettt karakter.


A puffert nem trli. / Ksbb getch()-val vrakozs nlkl lehet felolvasni. /
Vissza: 0, ha nincs semmi a pufferben
nem 0, ha van valami.

6.

char *cgets(s)
char *s; /* trcm az input adatok szmra */

Kzvetlenl a konzolrl olvas be egy stringet, s elhelyezi azt s+2 cmtl kezdve. Hvsa eltt s[0]
belltand; ide le kell tennnk a string maximlis hosszt. Olvass CR-LF/Enter-ig vagy(!) az adott
hosszig / s[0] /; azontl spol.
Enter-t /CR-LF/ \0-ra cserli.
s[1]-be automatikusan elhelyezi a tnyleges hosszt.
Vissza: pointer s+2cimre!
HIBA esetn: NULL pointer
Figyelem! Biztostand hossz: s[0]+3 minimun!
1. plda /C2P1.1 - String beolvassa kzvetlen konzolrl /

7.

void cputs(s)
char *s; /* a string kezdcme */

Kir egy stringet /\0-al lezrva! / kzvetlen konzolra. Nem kezeli a CR-LF kombincit! Ez azt jelenti,
hogy a \n csak j sorba lp, mg a sor elejre a \r-rel juthatunk.
Vissza: semmi.

8.

int cprintf(...u.a....)
...u.a.... mint printf()-nl mr lttuk.

A printf megfelelje, de direkt konzol I/O-val mkdik. Hasznlja a putch() fggvnyt. Figyeljnk itt is
\n s a \r kztti klmbsgre!
Vissza: sikeres konverzik szma.
9 int cscanf(...u.a....)
...u.a.... mint a scanf()-nl mr lttuk.

155

Forrs: http://www.doksi.hu

Kzvetlen a konzolrl valst meg formzott inputot. Httrben a getche() fggvnyt hasznlja.
Vissza: sikeres konverzik szma
EOF=EOF esetn;
0 ha hiba volt.

10.
int c;

void putch
/* kirand karakter kdja */

Kir egy karaktert /c/ kzvetlen konzolra.


Vissza: semmi.
A file-kezels alapjai:
---------------------- standard file-ok
/ stdin, stdout, stdprn, stdaux, stderr /
lemezes llomnyok mint egy byte-halmaz jelenik meg
nincs file-tpus, mindg az adott alkalmazs dnti el, hogy milyen tpusnak veszi a file-t.
Az stdio.h headerfile fontosabb rszei:
...
/* (ANSI / System V) # UNIX alatti fejlesztshez!
...
...
*/
#define BUFSIZ
512
#define _NFILE
20
#define EOF
(-1) /* mirt kell zrjel? */
#define FILE
struct_iobuf
#define P_tmpdir
//
#define SEEK_CUR
1
#define SEEK_END
2
#define SEEK_SET
0
#define SYS_OPEN

20

# if (defined(M_I86SM) || define(M_I86MM))
#define NULL

# elif (defined(M_I86CM) || define(M_I86LM) ||


defined(M_I86HM))
#define NULL

0L

#endif
Megjegyzs: V6.00 = ((void*)0)
/* file kontroll block */
# ifndef _IOB_DEFINED
extern FILE {
char *_prt; /* rsi/olvassi pointer */
int _cnt; /* karakterek / helye a pufferbe / */

156

Forrs: http://www.doksi.hu

char *_base; /* a puffer kezdcme */


char _flag; /* a file llapota (hiba: EOF) */
char _file; /* file handle */
} _NEAR _CDECL _iob[];
#define_OIB_DEFINED
#endif
#define
#define
#define
#define
#define
#define

fpos_t long /* file pozci */


stdin (&_iob[0])
stdout (&_iob[1])
stderr (&_iob[2])
stdaux (&_iob[3])
stdprn (&_iob[4])

/* Fggvny ill. makrdefincik. */


#define getc(f) (--(f)->_cnt>=0 ? 0xff & *(f)->_ptr++ :_filbuf(f))
/* Beolvas egy karaktert f-el azonostott file-bl. f file struktra;
lsd fentebb! */
#define putch(c,f) (--(f)->_cnt >=0 ? 0xff & *(f)->_ptr++=\
(char)) :_flsbuf(,(f))
/* c vltozbl egy karaktert kir a f (FILE*) vltozval azonostott
file-ba. _filbuf(),_flsbuf() bels file-kezel fggvnyek. */
#define getchar()
#define putchar()
#define feof(f)
#define ferror(f)
#define fileno(f)

getc(stdin)
putc(,stdout)
((f)->_flag &_IOEOF)
((f)->_flag &_IOERR)
((f)->_file)

/* elzekben */
#define _IOEOF 0x10 /* elrtk EOF-et */
#define _IOERR 0x20 /* hiba van */
#define _IOREAD 0x01 /* olvassra nyit */
#define _IOWRT 0x02 /* rsra nyitva */

File-kezels II. szint:


-----------------------

Karakteres/szveges md:
-----------------------/ alapja stdio.h headerfile /

11.
FILE *fopen(fazon,md)
char *fazon;
/* file azonostja */
char *md;
/* hasznlati md */
Megnyitja fazon-nal azonostott nev file-t.

157

Forrs: http://www.doksi.hu

Vissza: file-pointer sikeressg esetn


NULL pointer hiba esetn.
Md:
r: Ltez file megnyitsa olvassra.
/Nincs akkor hiba./
w: res file nyitsa rsra.
/Ha ltezett, akkor trli az eredeti tartalmt./
a: Ltez file megnyitsa hozzfzsre.
/Nem ltez file esetn ltrehozza./
r+: Ltez file-t megnyit rsra olvassra.
w+: res file-t megnyit rsra olvassra.
a+: Ltez file-t nyit olvassra s hozzrsra.
/Ltez adatoto nem rhat fell./
/* MSC-ben: */
t: Text md.
b: Binris md.
Text: input: CR+LF -> LF (\n)
output: LF -> CR+LF

12.
FILE *freopen(fazon,md,fptr)
char *fazon;
/* j file azonostja */
char *md;
/* hasznlati md */
FILE *fptr;
/* rgi file pointer-re */
Az fprt-rel azonostott file-t lezrja, s fazont megnyitja md hasznlati mddal. Az jonnan nyitott
file-t is fptr azonostja.
Vissza: lsd elbb.

13.

int fclose(f)
FILE *f;

Lezrja f-fel azonostott file-t. Minden puffert rt s trl.


Vissza: 0 - sikeres zrs
EOF - hiba esetn.

14.

int fcloseall()

Minden nyitott file-t lezr puffer rtssel. Kivve a standard file-ok.


Vissza: Lezrt file-ok szma
EOF - Hiba esetn.

15.

int ferror(f)
FILE *f;

158

Forrs: http://www.doksi.hu

Megvizsglja, hogy trtnt-e I/O hiba. Hiba esetn a hibajelz bekapcsolva marad, amg le nem zrjuk
a file-t, vagy nem hvjuk a clearerr() fggvnyt.
Vissza: 0 - nincs hiba
nem 0 - hiba volt.

16.

int fflush(f)
FILE *f;

Output: rti a puffereket melyek f-hez tartoznak.


Input: Trli a puffert.
Vissza: 0 - sikeres
EOF - hiba volt.
Irs s olvass:

17.

int getc(f)
FILE *f;

Az f-fel azonostott file-bl beolvassa a soron kvetkez egy karaktert.


Vissza: a beolvasott karakter kdja
EOF - hiba, vagy file-vg esetn.

18.
int putc(c,f)
char c; /* Kirand karakter kdja */
FILE *f; /* File-hoz tartoz pointer */
Az output file f aktulis pozcijba kirja c-t.
Vissza: a kirt karakter kdja
Hiba: EOF-et ad, hvjuk ferror()-t!

19.

int fgetc(f)
FILE *f;

U.a. mint getc(), de megvalstsa fggvny s nem makr!


[ Az fgetchar() - stdin-rl, szintn fggvny! ]

20.

int fputc(c,f)
char c;
FILE *f;

U.a. mint a putc(), csak fggvny.


[ Az fputchar() - stdout-ra, szintn fggvny! ]

159

Forrs: http://www.doksi.hu

21.

int feof(f)
FILE *f;

Az f-fel azonostott file-ra file-vget vizsgl. Ha egyszer file-vget szlel, akkor minden olvassnl
EOF-et ad.
Vissza: 0 - EOF mg nincs
nem 0 - EOF van.
2. plda: /C2P2.C - C2P2A.C - C2P2B.C szvegfile-ok kezelse./
Figyelem! std.. file-okat nem kell nyitni s zrni.
Formzott I/O:

22.

int fprintf((f,...u.a....)
FILE *f;
...u.a.... = mint a printf()-nl

Formtumozott adattvitelt hajt vgre az f-el megadott file-ra.


Vissza: az tvitt karakterek szma.

23.

int fscanf(f,...u.a....)
FILE *f;
...u.a.... = mint a scanf()-nl

Formtumozott adattvitelt hajt vgre f file-bl. Beolvas.


Vissza: sikeresen konvertlt s tvitt objektumok szma
EOF hiba, vagy file-vg esetn.
Tovbbi I/O lehetsgek:

24.
char *fgets(string,n,f)
char *string;
/* buffer az adatoknak */
int n;
/* max. beolv. karakter */
FILE *f;
/* file azonost */
Beolvas a file-bl / aktulis pozcitl / n -1 karaktert, ill. az els \n-ig! Attl fggen, hogy melyik
teljesl elbb.
Figyelem: a beolvasott\n-t is trolja. A vgre \0-t tesz! A rokon gets() NEM trolja \n-t!
Vissza: Pointer a stringre
NULL: hiba vagy EOF esetn.

25.
int fputs(s,f)
char *s; /* kirand string */
FILE *f; /* file-t azonost pointer */

160

Forrs: http://www.doksi.hu

Az output file f aktulis pozcijtol kezdi kirni a stringet s.


A \0-t nem viszi t.
Vissza: az utoljra tvitt karakter
0, ha a string res
EOF hiba esetn.

3. plda / szvegfile olvassa C2P3.C, C2P3A.C, C2P3B.C /


4. plda / szvegfile kezelse C2P4.C /

File kezels binris mdon:


---------------------------

26.
int fwrite(puffer,mret,db,f)
unsigned char *puffer;
/* honnan */
unsigned int meret;
/* obj. mrete */
unsigned int db;
/* obj. darabszma */
FILE
*f;
/* file azonostja */
Kir a file-ba (aktulis pozcitl) db-nyi mret hosszsg objektumot a pufferbl.
Vissza: tvitt objektumok szma
Hiba: kisebb mint db.
Megjegyzs: text mdnl LF CR-LF.
Tapasztalatok: text mdnl nmi bizonytalansg.

27.
unsigned int fread(puffer,mret,db,f)
unsigned char *puffer;
/* honnan */
unsigned int meret;
/* obj. mrete */
unsigned int db;
/* obj. darabszma */
FILE
*f;
/* file azonostja */
Beolvas aktulis pozcitl mret-hossz db-nyi adatot, s leteszi a puffer-be.
Vissza: beolvasott objektumok szma
HIBA esetn kevesebbet ad mint db.
Megjegyzs: Text llomnynl CR-LF helyett LF-et tesz le, de nem kezeli a \0-t.

28.

long ftell(f)
FILE *f;

Megadja az f file aktulis pozcijt a file elejhez kpest byte-ban.


Vissza: HIBA esetn -1L
hatrozatlan, ha nincs nyitott file-hoz rendelve f.

161

Forrs: http://www.doksi.hu

/ pl: stdprn /

29.
int fseek(f,eltols,honnan)
File *f;
/* file-pointer */
long eltols;
/* byte-ban mennyit */
int honnan;
/* pozci */
A file pointert az adott f file-ban a kvnt pozciba mozgatja.
honnan: SEEK_SET - file eleje
SEEK_CUR - aktulis pozci
SEEK_END - file vge
Vissza: 0 sikeres
nem 0 - hiba hatrozatlan, ha a mvelet rtelmetlen. (pl.: stdprn)
Figyelem: soremels (CR-LF)
5. plda / C2P5.C - megadott file utols 10 sornak listzsa /
6. plda / C2P6.C - nevek, s telefonok felrsa, visszaolvassa. /

30.

void rewind(f)
FILE *f;

Ujranyitja az f file-t! A file elejre pozcionl, puffert rt, ha kell [ fseek(f,0l,SEEK_SET); ], de a


rewind() trli az EOF-et s a hibajelzket is.
Vissza: nincs.
Segdfggvnyek:
----------------

31.

int fileno(f)
FILE *f;

Visszaadja az f file file-handle szmt. Ha tbb is tartozik hozz, akkor az els open-nek megfelelt.
Vissza: File-handle
hatrozatlan, ha nem tartozik nyitott file-hoz.

32.

long filelength(fh)
int fh; /* file-handle szm */

Vissza: a file hossza byte-ban


1L rvnytelen fh esetn.

33.

int flushall()

162

Forrs: http://www.doksi.hu

Minden outputra nyitott file puffert lemezre rti; input file-nl pedig trli.
Vissza: a file-ok szma amennyit rtett.
7. plda / C2P7.C - tmbk kirsa file-ba, filehossz kirsa /

File-kezels I. /alacsony szint/:


-------------------------------- file-handle szm
file, mint byte tmb
elssorban binris file-kezels (ekkor semmi konverzi nincs, ellenttben a szvegmddal!)
Alapja: fcntl.h
}
io.h
}
header file-ok
types.h
}
stat.h
}

34.
int open(nv,oflag[,md])
char *nv;
/* a file neve */
int oflag;
/* opercis kd */
int md;
/* hasznlati md */
Megnyitja a nv nev file-t oflag fggen.
oflag lehetsges llapotai fcntl.h-ban:
O_APPEND=hozzrs. File-pointert a file vgre teszi.
O_CREAT =ltrehozza. Ha ltezett akkor fellrja.
O_EXCL =Ha van nem rjuk fell. Rendszerint O_CREAT-tal
egytt hasznljuk.
O_RDONLY=csak olvassra nyitja a file-t. Nem hasznlhat az
O_WRONLY-val egytt, s az O_ROWR-rel sem.
O_ROWR =rs/olvassra nyitja a file-t. Nem hasznlhat az
O_RDONLY-val, s az O_WRONLY-val egytt.
O_WRONLY=csak rsra nyitja a file-t. Nem hasznlhat az
elbbi kettvel egytt.
O_TRUNC =nyitja, s lenullzza a file hosszt. Tartalom elvsz.
Ir mvelettel egytt szoks hasznlni.
O_BINARY=binris pufferetlentvitelt valst meg.
O_TEXT =szveges, pufferelt tvitelt valst meg.
Megjegyzsek: O_TEXT default
a hasznlati mdot csak O_CREAT esetn kell megadni
O_WRONLY MS-DOS rtelmetlen, de 3.0 vagy magasabb verzi esetn ha installljuk a
SHARE kls parancsot, akkor O_CREAT-tel hasznlhat.

163

Forrs: http://www.doksi.hu

Hasznlati md:
--------------/ stat.h. header file-ban /
S_IWRITE
=rs engedlyezse
S_IREAD
=olvass engedlyezse
S_IREAD|S_IWRITE=rs/olvass engedlyezse
( bitenknti vagy )
Vissza: file-handle szm
1: hiba esetn, a tnyleges hibakd az errno vltozban van.
errno:extern int errno;
/* ltalnos I/O hiba */
extern int _doserrno; /* DOS funkcik */
(stdlib.h vagy stddef.h-ban is van)

35.

int creat(nv,md)
char *nv; /* a file neve */
int md; /* hasznlati md */

Nemltez file-t ltrehoz, vagy ltezt fellr. Md lsd open()-nl.


Vissza: file-handle
hiba: -1,kd az errno-ban.
Figyelem: ha MS/PC-DOS krnyezetben S_IWRITE-tal hozunk ltre egy file-t, akkor mg rhatunk be,
de lezrs utn mr csak olvashat lesz. De azt aztn meg lehet szntetni.
Lehetsges hibk:
----------------/ alapja errno.h - mind #define.../
EACCESS = DOS 3.0 vagy magasabb verzik!
Nem osztott file elrse; read-only-t rsra probltak nyitni.
EEXIST = Ltezik a file.
EMFILE = Tl sok file van megnyitva.
ENDENT = File, vagy az tvonal nem tallhat.

36.

int close(fh)
int fh; /* file-handle szm */

Lezrja az fh-val azonostott file-t.


Vissza: 0 - Ok
1 - hiba errno=EBADF

37.
int write(fh,puffer,count)
int
fh;
/* file-handle szm */
char
*puffer;
/* adatok kezdcme */
unsigned int count;
/* kirand byte-ok szma */

164

Forrs: http://www.doksi.hu

Kir puffer kezdcmtl count-nyi byte-ot az fh-val azonostott file aktulis pozcijtl kezdve.
Vissza: Kirt byte-ok szma
HIBA: -1 lsd errno-t
EACCESS
EBADF
ENOSPC - nincs hely

Figyelem: egyszerre maximum 65534 byte-ot lehet kirni!

38.
int read(fh,p,c)
int
fh; /* file-handle szm */
char
*p; /* mutat a pufferre */
unsigned int c; /* olvasand byte-ok szma */
Beolvas s elhelyezi p cmtl kezdve c-nyi byte-ot.
Vissza: Beolvasott byte-ok szma
HIBA: -1 lsd errno-t
Figyelem: egyszerre maximum 65534 byte-ot lehet olvasni!
write/read ha O_TEXT-ben megy
CR-LF --> LF (read)
LF --> CR-LF (write)
MS-DOS alatt text md esetn file vge: ^Z, ekkor 0-t ad vissza.

39.

long tell(fh)
int fh; /* file-handle szm */

Visszaadja a file aktulis pozcijt byte-ban.


HIBA: -1 lsd errno-t.

40.

long lseek(fh,offs,origin)
int fh; /* file-handle szm */
long offs; /* hov byte-ban */
int origin; /* honnan */

A fseek() alacsony szint megfelelje. Pozcionl a file-ba.


SEEK_SET
SEEK_CUR
SEEK_END hasznlhat.

Vissza: File pozci


HIBA: -1 lsd errno-t.

165

Forrs: http://www.doksi.hu

41.

int eof(fh)
int fh; /* file-handle szm */

A fggvny EOF-et vizsgl alacsony szinten!


Vissza: 1 EOF esetn
0 ha nem EOF
1 hiba lsd errno-t.

42.
int sopen(nv,oflag,shflag[,md])
char *nv;
/* a file neve */
int oflag;
/* opercis kd */
int shflag;
/* osztott elrsi mdok */
int md;
/* hasznlati md */
Minden megegyezik az open()-nal, de osztott krnyezetben!
Fontos: share.h!
shflag:
------SH_COMPAT = kompatibilis md lltsa
SH_DENYRW = rs s olvass tiltsa
SH_DENYWR = rs tiltsa
SH_DENYRD = olvass tiltsa
SH_DENYNO = rs/olvass is engedve
Fontos: csak MS-DOS 3.1 vagy magasabb verzikban. Eltte installlni kell a SHARE.EXE (vagy
SHARE.COM) kls DOS parancsot! Kompatibilis md az op.rendszer verzik thidalsra.
Vissza: file-handle szma
HIBA -1 lsd errno:
EEXIST: O_CREAT!
O_EXCL-nl ltezik.
Pufferelt file-oknl nem korrekt a megvalsts!!

43.
int locking(fh,md,byte)
int fh; /* file-handle szm */
int md; /* zrolsi md */
long byte; /* lock-olt byte-ok szma */
Zrol, vagy felszabadt az fh file byte-nyi byte-jt. Byte szmlls az aktulis file-pointer pozcitl
indul. Csak MS-DOS 3.0 vagy magasabb verziknl hasznlhat!
Lock-olsi mdok: locking.h-ban
-------------------------------

166

Forrs: http://www.doksi.hu

LK_LOCK = zrolja a byte-okat (tbbszr prblkozik...) 10 x 1.


LK_RLCK = u.a. mint az elbb.
LK_NBLCK = zrolja a byte-okat egyszer prblkozik, majd hibt ad.
LK_NBRLCK = u.a. mint az elbb.
LK_UNLCK = felszabadtja a lock-olt (!!) byte-okat.
Figyelem: az sszes zrolst fel kell oldani mieltt lezrjuk a file-t, vagy kilpnk a process-bl.
Vissza: 0 = O.K.
HIBA = -1 lsd errno:
EDEADLOCK = LK_LOCK sikertelensge esetn EINVAL

= rvnytelen tartomnyt adtunk!

8. plda / C2P8.C - alacsony szint file-kezels /


9. plda / C2P9.C - locking plda /

Egyb file-kezelst segt fggvnyek:


44. int chdir(path)
/ dekl.: direct.h /
char *path;
/* katalgus neve */
Knyvtrat vlt, mint az MS-DOS parancs.
Vissza: 0 = O.K.
HIBA = -1 - nem ltez path.

45.
int rename(rgi,j)
char *rgi;
/* a file rgi neve */
char *uj;
/* a file j neve */
File illetve katalgus tnevezse ( MS/PC-DOS szabvnyos nv )
Vissza: 0 = O.K.
HIBA = -1 - lsd errno-t.

46.
int unlink(file)
char *file;
/* a file neve */
A file nev file trlse.

/ lsd mg remove() /

Vissza: 0 = O.K.
HIBA = -1 - lsd errno-t.

47.

int remove(file)
char *file;
/* a file neve */

Trli a megadott file nev file-t.


Vissza: 0 = O.K.
HIBA = -1 - lsd errno-t.

167

Forrs: http://www.doksi.hu

48. int mkdir(path)


/ dekl.: direct.h /
char *paht;
/* az j katalgus neve */
Ltrehoz egy j alknyvtrat.
Vissza: 0 = O.K.
HIBA = -1 - lsd errno-t.
49. int rmdir(path)
/ dekl.: direct.h /
char *paht;
/* a trlend katalgus neve */
Trli az alknyvtrat, melynek resnek kell lennie! Aktulis katalgus sem lehet.
Vissza: 0 = O.K.
HIBA = -1 - lsd errno-t.
50. int setmode(fh,md)
int fh; /* file-handle szm */
int md; /* j tviteli md */
Belltja az fh-file tviteli mdjt: O_TEXT vagy O_BINARY.
Vissza: elz md rtke - O.K.
1: HIBA, lsd errno-t.

50.a. char *getcwd(path,n)


dekl.: direct.h
char *path;
/* puffer a katalgusnvnek */
int n;
/* a path nv maximlis hossza */
Felemeli a teljes elrsi utat, ami pp az aktulis munkakatalgusunk. Az n = buffer hossz-1, most a
\0-nak is kell hely! Ha path-nak NULL-t adok t, akkor automatikusan hvja malloc()-ot s helyet
foglal. Felszabadts free()-vel visszaadott ptr -rel!
Vissza: mutat a puffer kezdcmre
NULL : hiba, lsd errno-t
ERANGE: tvonalnv hosszabb, mint n byte
ENOMEN: nincs elg memria
13. plda / C2P13.C - knyvtrvlts + file trlse /
Memriakezels:
-------------- memria modellek
dinamikus trkezels
Memria modellek:
az Intel processzorok miatt
6 modell ltezik
8 illetve 16 bites pointerezs
a.) small:

max. 64 Kb kd

max. 64 Kb adatszegmens

168

Forrs: http://www.doksi.hu

b.) medium: 1 Mb kd
( tbb kdszegmens )
c.) compact:

max. 64 Kb adatszegmens

max. 64 Kb kd

1 Mb adatszegmens

(szegmensenknt egy adat mrete gy is max. 64 Kb)


d.) large:

1 Mb kd

1 Mb adatszegmens

e.) huge:
1 Mb kd
1 Mb adatszegmens
(de! lehetsg van 64 Kb-nl nagyobb adatok kezelsre!)
f.) tiny:

kd+adat+stack <= 64 Kbyte (COM tpus)

C-ben a stack szegmens mindg az adatszegmens rsze! Default rtke 2 Kbyte. lltsa linker
opci: link... /ST:bytes
Szegmensek:
----------Kd:

_TEXT; tbb forrs modul esetn modulnv\_TEXT

Stack:
STACK:
vltozk helye.
Adat:

_BSS:

visszatrsi cmek, loklis (auto)


el nem ksztett (inicializlatlan)

statikus (static) vltozk. Fordt mindent binris nullval tlt fel.


C_COMMON:

inicializlatlan kls (globlis)

vltozk.
CONST:

konstans adatok, melyek elfordulnak

a programban, kivtel a
szvegkonstansok.
_DATA:

inicializlt globlis (kls) s a

statikus (static) vltozk. Tovbb a szvegkonstansok.


NULL:

az adatterlet fizikai szegmensnek


els nhny byte-ja. Tartalmt a
program kilpskor ellenrzi!

Fontos: szegmensek szma: tbb forrs modul esetn tbb is lehet.


Default: 128. lltsi lehetsg linker opci: link... /SEG: number.
51. char *malloc(m)
dekl.: malloc.h
unsigned int m; /* byte-ok szma */
Lefoglal m mret (byte) memriablokkot a near heap-ben. Eltr tpus esetn hasznljuk a cast
opertort.
Vissza: NULL: nincs elg memria
vagy pointer az alloklt blokk elejre.
52. void free(p)

dekl.: malloc.h

char *p;
Felszabadtja a korbban alloklt memrit. Fontos, hogy a p mutat a felszabadtand memria
kezdetre mutasson!

169

Forrs: http://www.doksi.hu

Hvhat: malloc(), calloc(), realloc() utn!


Vissza: nincs.

53.
char *calloc(n,mret)
unsigned int n;
/* elemek szma */
unsigned int mret;
/* egy elem mrete byte-ban */
Lefoglal n darab mret nagysg memriablokkot. Tipikus alkalmazsa a dinamikus tmbk
megvalstsa.
Vissza: pointer a terlet kezdetre
NULL: nincs elg hely a memriban.
54.
char *realloc(p,mret)
char *p;
/* a lefoglalt terlet kezdcme */
unsigned int mret;
/* j mret byte-ban */
A p-hez rendelt, mr elzleg lefoglalt memriablokk nagysgt mret-nyire mdostja.
Vissza: NULL: nincs elg memria, vagy mret=0,
pointer a lefoglalt blokk elejre.
14.

55.

plda / C2P14.C - lefoglal memrit, feltlti, visszaolvassa /

int memicmp(mit,mivel,hossz)
char *mit,*mivel;
unsigned int hossz;

sszehasonltja mit-et mivel-lel hossz-nyi hosszan. Nincs klmbsg kis s nagybet kztt!
Vissza:

56.

<0, ha mit < mivel


0, ha egyenl
>0, ha mit > mivel

int memcmp(mit,mivel,hossz)
char *mit,*mivel;
unsigned int hossz;

sszehasonltja mit-et mivel-lel hossz-nyi hosszan.

57.
char *memcpy(vev,ad,db)
char *vev;
/* output kezdcm */
char *ad;
/* input kezdcm */
unsigned int db; /* mennyit */
tmsol ad-bl vev-be db-nyi byte-ot.
Vissza: pointer vev-re.

170

Forrs: http://www.doksi.hu

58.
char *memset(puffer,kar,db)
char *puffer;
/* kezdcm */
int kar;
/* milyen karakterrel */
unsigned int db; /* mennyit */
Puffer els db-nyi byte-jt kar karakterrel tlti fel.
Vissza: pointer puffer-re.

59.

char *memccpy(vev,ad,c,db)
char *vev,*ad;
int c;
unsigned int db;

Byte-okat msol ad-bl vev-be c-vel bezrlag, vagy(!) db-nyit.


Amelyik elbb teljesl.
Vissza: pointer c-t kvet byte-ra
NULL, ha nem msolta c karaktert.

60.
char *memchr(puffer,c,db)
char *puffer;
/* honnan kezdden */
int c;
/* mit */
unsigned int db; /* milyen hosszan */
Megkeresi puffer-ben az els db-nyi byte kztt a c karaktert (els elfordulst).
Vissza: pointer a megtallt c-re
NULL, ha nincs.

61.
void movedata(si,oi,so,oo,db)
unsigned int si,oi;
/* input segment+offset */
unsigned int so,oo;
/* output segment+offset */
unsigned int db;
/* mennyit */
Byte-ok msolsa / db-nyit /. Far tpus adatok msolsra small s medium modelleknl. Persze ms
modellekben is hasznlhat. Figyelem: csak IBM PC-k esetben van implementlva!
Vissza: semmi.
unsigned int FP_OFF(adress)
unsigned int FP_SEG(adress)
char far *adress;

dekl.: dos.h
dekl.: dos.h

/* tvoli mutat a memriacmre */

Szegmens s offszet adat generlsa.


Vissza: a cm segment illetve offset rsze.
Segtsg:
--------char

far *ptr;

171

Forrs: http://www.doksi.hu

ptr = (char far *) 0xB800 0000;


tvoli
cast szegmens offszet
mutat
rtkek
[Ez a szvegmd -sznes monitor ltal hasznlt memria kezdcme.]
Orisi blokkok alloklsa:
62. char huge *halloc(n,meret)

dekl.: malloc.h

long n; unsigned int mret;


Trterletet allokl n elem mret nagysg huge tpus tmbknek. A terlet 0-val lesz feltltve.
Ha n*mret > 128K, akkor
mret = 2k (k=pozitv egsz hatvnykitev!).
A terlet a far heap-bl lesz levgva.

Vissza: huge mutat a memriaterlet elejre


NULL: nincs elg memria.
63. void hfree(p)

dekl.: malloc.h

char huge *p;


Felszabadtja a halloc() ltal lefoglalt memriablokkot.
Vissza: semmi.
64. char *_fmalloc(m)
unsigned int m; /* mennyit */

dekl.: malloc.h

Allokl m-nyi byte-ot a standard adatszegmensen kvl, a far heap terleten.


Vissza: pointer a terlet kezdetre
NULL: nincs elg memria.
65. void _ffree(fp)
dekl.: malloc.h
char far *fp;
/* mutat a memriablok kezdetre */
Felszabadtja az fp ltal megcmzett memriablokkot.
Vissza: semmi.

15.

plda /C2P15.C - kpments /

16.

plda /C2P16.C - kpments - feltlts /

Process-kezels:
---------------Ebben a rszben azokkal a fggvnyekkel ismerkednk meg, amelyek lehetv teszik, hogy egy C
programbl egy msik C programot, vagy akr brmilyen ms binris programot indtsunk.

172

Forrs: http://www.doksi.hu

66. int system(parancs)


dekl.: process.h vagy stdlib.h
char *parancs;
/* az indtand program neve */
Vgrehajtja a parancs-ban megadott nev parancsot. PC/MS-DOS vagy aktulis op. rendszer-beli
parancs. A COMMAND.COM-on keresztl dolgozik. (UNIX: subshell-t tlt!)
Vissza: 0 - O.K.
1 - hiba, lsd errno-t.

67. void exit(stat)


dekl.: process.h vagy stdlib.h
int stat;
/* visszatrsi kd */
Befejezi a program futtatst. Ha van hv program, akkor a stat als byte-jt (stat & 0xFF) megkapja.
Futs eltt befejezi az onexit fggvnyeket, minden puffert rt, lezrja a file-okat. Figyelem: main()
vgn automatikusan exit(0) hajtdik vgre!
Vissza: semmi.
68. void _exit(stat)
int stat;

/* visszatrsi kd */

Azonnali lells trlsek, zrsok nlkl! Egybknt mint exit() fggvny.


Vissza: semmi.
69. void abort()

dekl.: stdlib.h

Azonnali lells minden zrs, rts nlkl! Abnormal program termination zenetet r ki. exit
sttusz: -3.
70. onexit_t onexit(func)
dekl.: stdlib.h
onexit_t func;
/* kilp fggvny */
A fut program befejezsekor az elzleg belltott (onexit()-tel) fggvnyeket LIFO elv szerint
vgrehajtja. Kivve abort() s _exit()!
Vissza: pointer a fggvnyre!
NULL, ha nincs tbb hely a fggvny szmra.

17.

plda /C2P17.C - C2P17A.C - onexit /


typedef int (_CDECL*CEDCL onexit_t)();

Process hv utastsok:
/ Alap : process.h /
71. int execl(name,arg0,arg1,...,argn,NULL)
72. int execle(name,arg0,arg1,...,argn,NULL,env)
73. int execlp(name,arg0,arg1,...,argn,NULL)
74. int execlpe(name,arg0,arg1,...,argn,NULL,env)
75. int execv(name,argv)
76. int execve(name,argv,env)
77. int execvp(name,argv)
72. int execvpe(name,argv,env)

173

Forrs: http://www.doksi.hu

Deklarcik:
-----------char *name;
/* program neve
*/
char *arg0,*arg1,... /* pointerek a paramterekre
*/
char *argv[];
/* paramterek egy pointertmbben
*/
char *env[];
/* krnyezeti stringekre mutat pointerek tmbje */
Betltenek, s vgrehajtanak egy j gyerekfolyamatot. Ha a hvsi mechanizmus j, akkor a hv
helyre tltdik az j process. Ha nem adunk meg kiterjesztst, gy EXE-nek veszi. Ha viszont a nv
XXX. teht ponttal r vget, akkor nem tallja meg. Nv lehet akr teljes elrsi ttal is megadva.
Az execlp(), execlpe(), execvp() esetben a DOS PATH-ban vgig keresi a programot, ha az
aktulisban nem tallta!
Paramterek:

arg0 = prog.nv (hvand)

egyttes paramterhossz: 128 byte


NULL, mint lezr ktelez.

Vissza: siker esetn semmi


HIBA: -1, lsd errno-1.
HIBK:
-----EZBIG = 128-nl hosszabb paramterek
EACCESS = osztott elrsi problma
EMFILE = tl sok file van nyitva
ENOMEM = nincs elg memria
ENOEXEC = nem futtathat program
ENOENT = file, vagy path nem tallhat
Megjegyzs: krnyezeti rklds van, de a nyitott file-ok tviteli mdja nem rzdik meg. A
setmode() fggvny hasznlhat ekkor.
79. int spawnl(md,
)
80. int spawnle(md,
)
81. int spawnlp(md,
)
82. int spawnv(md, } u.a. mint az exec...- nl
83. int spawnve(md,
)
84. int spawnvp(md,
)
85. int spawnvpe(md,
)

Minden u.a. mint az exec...-nl, de a md paramter befolysolja a mkdst.


Md: szl-gyerek process kapcsolat
---P_WAIT
= szl vr, mg a gyerek fut!
P_NOWAIT
= konkurrens vgrehajts.
P_OVERLAY
= ngyilkos szl esete; megegyezik exec...-el!

Vissza: exit sttusz rtke: exit(), _exit()-el adhat vissza


1 HIBA, lsd errno-t

174

Forrs: http://www.doksi.hu

18.

plda / C2P18.C - C2P18A.C - szl gyerek process kapcsolat /

Rendszerid kezelse:
--------------------86. char *ctime(tsec)
const time_t tsec;

dekl.: time.h
/* numerikus idrtk */

( time.h-ban: typedef long time_t, / const = megvltoztathatatlan rtk /) A long tsec rtkknt trolt
idt karakterlncc konvertlja. Az aktulis tsec-et a time(time_t) dtum-fggvny segtsgvel kapjuk.
Vissza: 1970. jan. 1. 0 ra 0 perc 0 mp
(Greenwitch) ta eltelt idt adja sec-ben a time() fggvny.
Ebbl csinl a ctime() 26 karakteres lncot:
Sun Dec 21 12:43:00 1988\n\0. Erre mutat!
87. time_t time(timeptr)
time_t * timeptr;

/* ide trolja az idt numerikusan */

Vissza: NULL, ha nem sikerlt az rtket kpeznie!

19.

plda / C2P19.C - dtum kiratsa time() s ctime() segtsgvel /

88. char *asctime(time)

dekl.: time.h

struct tm{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mod;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
} *time;

/* msodpercek (0 - 59)
*/
/* percek
(0 - 59)
*/
/* rk
(0 - 23)
*/
/* hnap napja (0 - 31)
*/
/* hnap
(0 - 11)
*/
/* v 1900 - tl
*/
/* nap szma (0 - 6) 0=vas. */
/* nap szma Jan 1-tl
*/
/* flag
*/

A 26 karakteres stringg konvertlja a struktrban megadott idt!


Vissza: mutat a stringre.
89. char *_strdate(date)
dekl.: time.h
char *date;
/* memria a dtumnak */
Leteszi date-be a gp aktulis dtumt:

HH/NN/ formban.

Vissza: mutat a memriaterlet kezdetre.

175

Forrs: http://www.doksi.hu

90. char *_strtime(time)


char *time;

/* memria az idnek

Leteszi time-ba a gp aktulis idejt:

*/
/pp/mm formban.

Vissza: mutat a memriaterlet kezdetre.

20.

plda / C2P20.C - alkalmazzuk az _strdate() s az _strtime() fggvnyeket /

Nhny rdekes beptett fggvny:


----------------------------------

91. void qsort(base,num,width,comp)


dekl.: search.h
char *base;
/* rendezend adatok kezdcme
*/
unsigned int num; /* rendezend adatok db. szma
*/
unsigned int width; /* egy adat hossza
*/
int (*comp)();
/* int-tel visszatr - hasonlt - fggvnyre
mutat pointer
*/
Rendezi az adatokat a memriban. A QUICK-short algoritmust hasznlja.
Vissza: semmi.
Hasonlt fggvny visszatrsi rtkei:
<0 -> elem1 < elem2
0 -> elem1 = elem2
>0 -> elem1 > elem2

21.

plda / C2P21.C - parancssor paramterek rendezse qsort()-tal /

22.

plda / C2P22.C - egsz szmok rendezse qsort()-tal /

92. char *lsearch(key,base,num,width,comp)


93. char *lfind(key,base,num,width,comp)
char *key;
/* keresend kulcs
*/
char *base;
/* adathalmaz cme
*/
unsigned int num; /* adatok darabszma
*/
unsigned int width; /* egy adat hossza
*/
int (*comp)();
/* pointer a hasonlt fggvnyre
*/
Mindkt fggvny lineris keresst valst meg base adathalmazban gy, hogy key kulcsot keresi.
Hasonlt fggvny visszatrsi rtkei:
0, akkor azonos az aktulis elem a keresend kulccsal (meg van!)
nem 0, akkor nem azonos
Sok kzl az elst adja vissza, ha nincs: NULL pointert ad.
Klmbsg: ha nincs a keresett kulcs, akkor a lsearch() fggvny az adathalmaz vgre beilleszti a
keresett kulcsot, s mdostja a num pointer ltal mutatott db. szm rtket.

176

Forrs: http://www.doksi.hu

94. char *bsearch(key,base,num,width,comp)


char *key;
/* keresend kulcs
*/
char *base;
/* adathalmaz cme
*/
unsigned int num; /* adatok darabszma
*/
unsigned int width; /* egy adat hossza
*/
int (*comp)();
/* pointer a hasonlt fggvnyre
*/
Binris keresssel keresi meg a key kulcsot. Az adatoknak rendezettnek kell lennie.
Hasonlt (comp) rutin visszatrsi rtkei:
<0 -> elem1 < elem2
0 -> elem1 = elem2
>0 -> elem1 > elem2

23.

plda / C2P23.C - long tmbben adat keresse lfind()-dal /

24.

plda / C2P24.C - long tmbben adat keresse bsearch()-cal /

Rendszerkzeli programozs MS-DOS-ban:


--------------------------------------

Ez a leginkbb gpfgg rsze a C-nek.


Kzvetlen ROM-BIOS fggvnyek illetve DOS interruptok hvsa
Regiszterkonvencis paramtertads
Alap: dos.h;

itt vannak a regiszterek is definilva.

struct WORDREGS {
unsigned int ax; unsigned int bx; unsigned int cx; unsigned int dx; unsigned int si; unsigned int di;
unsigned int cflag;
}
struct BYTEREGS {
unsigned char al,ah; unsigned char bl,bh; unsigned char cl,ch; unsigned char dl,dh;
}
union REGS {
struct WORDREGS x;
struct BYTEREGS h;
}
Elfordulhat, hogy az ltalnos regiszterek mellett a szegmens regisztereket is mdostani kell. Emiatt
van deklarlva az albbi struktra:
struct SREGS {
unsigned int es; unsigned int cs; unsigned int ss; unsigned int ds;
}

Lssunk nhny fggvnyt:


-------------------------

177

Forrs: http://www.doksi.hu

95. int int86(intn,inregs,outregs)


int intn;
/* az interrupt sorszma */
union REGS *inregs;
/* bemen regiszterek */
union REGS *outregs;
/* kimen regiszterek */
Vgrehajt egy 8086-os szoftver megszaktst, amelyet az intn hatroz meg. A megfelel regisztereket
be kell lltani; hibakdokat a megfelelekben adja vissza. Ezeket az aktulis DOS verzi
kziknyvbl kell kinzni.
Vissza: AX tartalma hibakd
_doserrno (stdlib.h-ban) szintn hibakd
96. int intdos(inregs,outregs)

dekl.: dos.h

union REGS *inregs,*outregs;


A DOS 0x21-es rendszerhvst aktivizl, a belltott input regisztereknek megfelelen. Az inregs.h.ahba a DOS funkci sorszma tltend.
Vissza: AX tartalma hibakd
_doserrno (stdlib.h-ban) szintn hibakd
97. int int86x(intn,inregs,outregs,segregs)
int intn;
union REGS *inregs,*outregs;
union SREGS *segregs;
/* szegmens regiszterek rtke hvskor */
Hasonl az int86()-hoz, de llthatjuk az ES s DS szegmensregiszterek rtkt.
Visszatrskor visszatlti DS eredeti rtkt s lltja cflag-et az outregs-ben.
Vissza: AX regiszter rtke. Ha cflag nem egyenl 0-val, akkor _doserrno-ban
hibakd.
98. int intdosx(inregs,outregs,segregs)
union REGS *inregs,*outregs;
union SREGS *segregs;
DOS rendszerhvs hasonlan intdos()-hoz, de DS s ES regiszterek is bellthatk. Egyebekben
teljesen megegyeznek.

25.

plda / C2P25.C - interrupt kezels - kpernytrls /

26.

plda / C2P26.C - interrupt kezels - a DOS rjnak lekrdezse /

Van mg nhny lehetsg a DOS funkcik elrsre, de interrupt nlkl.


Ezek:
_dos ....fggvnyek:
_dosallocmem
_dos_close
_dos_creat /0x3C/
_dos_creatnew /0x5B/

_dos_getdrive
_dos_getfileattr
_dos_getftime
_dos_gettime

178

Forrs: http://www.doksi.hu

_dos_finfirst
_dos_findnext
_dos_freemem
_dos_getdate
_dos_getdiskfree

27.
_

_dos_getvect
_dos_keep(!)
_dos_open
_dos_setdate
_dos_setdrive stb...

plda / C2P27.C file-ok keresse /

fggvnyargumentumoknak lennik. Ha message-et


char *message;

179

You might also like