Professional Documents
Culture Documents
hu
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
Forrs: http://www.doksi.hu
DEC PDP 11
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
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.
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.
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
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.
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
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
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
30
Forrs: http://www.doksi.hu
31
Forrs: http://www.doksi.hu
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
36
Forrs: http://www.doksi.hu
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()
{
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
{
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
{
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()
{
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()
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
46
Forrs: http://www.doksi.hu
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)
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 ()
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)
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)
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
/* 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
53
Forrs: http://www.doksi.hu
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.
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
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
{
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
60
Forrs: http://www.doksi.hu
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)
{
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.
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)
67
Forrs: http://www.doksi.hu
68
Forrs: http://www.doksi.hu
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)
{
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)
{
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)
{
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 ()
{
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
/Ideje, hogy
minden j
ember segtsgre siessen
embertrsainak./
74
Forrs: http://www.doksi.hu
{
char line [MAXLINE];
while (getline (line, MAXLINE) > 0)
if (index (line, the) >= 0)
printf(%s, line);
}
getline (s, lim)
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)
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)
{
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)
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
{
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
{
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
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 ()
{
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 ()
{
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)
{
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)
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
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
/*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)
int *pn;
{
int c, sign; while ((c = getch ()) == || c == \n || c == \t)
; /*Az res kzt tugorja*/
sign = 1;
if (c == + || c == -) {
}
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
{
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
/*Trhely
alloc-nak*/
static char *allocp = allocbuf;
char *alloc (n)
int n;
{
if (allocp + n <= allocbuf + ALLOCSIZE) {
/*Befr*/ allocp += n;
{
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)
{
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)
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)
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)
{
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
/*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
101
Forrs: http://www.doksi.hu
}
return (nlines);
}
A sorok vgn tallhat jsor karakterek trldnek, gy nem befolysoljk a rendezsi sorrendet.
writelines (lineptr, nlines)
char *v [];
int n;
{
int gap, i, j;
char *temp;
for (gap = n/2; gap > 0; gap /= 2)
102
Forrs: http://www.doksi.hu
103
Forrs: http://www.doksi.hu
/*Visszhangozza az argumentumokat
104
Forrs: http://www.doksi.hu
/*Visszhangozza az argumentumokat
/*Megkeresi az 1. argumentum
105
Forrs: http://www.doksi.hu
/*Megkeresi az 1. argumentum
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
107
Forrs: http://www.doksi.hu
{
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
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)
{
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)
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)
{
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
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 ()
{
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)
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)
{
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)
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
{
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
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.
7.2.
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.
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
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
129
Forrs: http://www.doksi.hu
Ft rna.
7.5.
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
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);
7.7.
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 )
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.
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:
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.
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
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
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.
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.
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;
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
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
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
174
144
Forrs: http://www.doksi.hu
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* _
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
148
Forrs: http://www.doksi.hu
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;
}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
/* 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
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.
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()
2.
int getche()
3.
int ungetch
int c;
/* karakterkd */
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()
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 */
20
# if (defined(M_I86SM) || define(M_I86MM))
#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
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 */
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
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;
14.
int fcloseall()
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;
17.
int getc(f)
FILE *f;
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;
20.
int fputc(c,f)
char c;
FILE *f;
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
23.
int fscanf(f,...u.a....)
FILE *f;
...u.a.... = mint a scanf()-nl
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
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;
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;
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 */
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 /
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 */
36.
int close(fh)
int fh; /* file-handle szm */
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
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 */
40.
long lseek(fh,offs,origin)
int fh; /* file-handle szm */
long offs; /* hov byte-ban */
int origin; /* honnan */
165
Forrs: http://www.doksi.hu
41.
int eof(fh)
int fh; /* file-handle szm */
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
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 */
167
Forrs: http://www.doksi.hu
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
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:
C-ben a stack szegmens mindg az adatszegmens rsze! Default rtke 2 Kbyte. lltsa linker
opci: link... /ST:bytes
Szegmensek:
----------Kd:
Stack:
STACK:
vltozk helye.
Adat:
_BSS:
vltozk.
CONST:
a programban, kivtel a
szvegkonstansok.
_DATA:
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
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.
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.
int memcmp(mit,mivel,hossz)
char *mit,*mivel;
unsigned int hossz;
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;
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
far *ptr;
171
Forrs: http://www.doksi.hu
dekl.: malloc.h
dekl.: malloc.h
dekl.: malloc.h
15.
16.
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
/* visszatrsi kd */
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.
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:
174
Forrs: http://www.doksi.hu
18.
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;
19.
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
*/
HH/NN/ formban.
175
Forrs: http://www.doksi.hu
/* memria az idnek
*/
/pp/mm formban.
20.
21.
22.
176
Forrs: http://www.doksi.hu
23.
24.
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;
}
177
Forrs: http://www.doksi.hu
dekl.: dos.h
25.
26.
_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...
179