Kernighan Ritchie - C Könyv

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 207

Elsz a magyar kiadshoz

A C programnyelvet eredetileg a Bell Laboratriumban az UNIX


opercis
rendszerhez,
az
alatt
fejlesztettk
ki
PDP-11_
szmtgpen. A kifejlesztse ta eltelt vek sorn bebizonyosodott,
hogy a C nem egyszeren egy a napjainkban gombamd szaporod
programnyelvek
kzl.
Korszer
vezrlsi
s
adatszerkezetei,
rugalmassga, knny elsajtthatsga szles alkalmazsi terletet
biztostott
szmra,
klnsen
a
16
bit-es
mikroprocesszorok
megjelense ta rendkvl sok gpen dolgoznak C nyelven. C fordt
kszlt olyan gpekre, mint az IBM System/370, a Honeywell 6000 s az
Interdata 8/32.
A nyelv a kutats-fejlesztsi, tudomnyos cl
programozs npszer eszkzv vlt.
Magyarorszgon szintn egyre tbb olyan szmtgp mkdik, amely
alkalmas a C megvalstsra. Ilyenek a hazai gyrtmnyok kzl a
TPA-11 sorozat, az R-11 ,
a szocialista gyrtmnyok kzl az SZM-4
szmtgpek, de meg kell emltennk a haznkban ugyancsak elterjedt
PDP-11
sorozat tagjait is. Igy rtheten a magyar szmtstechnikai
szakemberek krben mind nagyobb az rdeklds a C nyelv irnt, egyre
tbben szeretnnek megtanulni programozni ezen a nyelven.
Ebben
szeretnnk
segteni
e
knyv
megjelentetsvel,
amely
didaktikusan, b plda- s gyakorlatanyaggal kiegsztve szl a C
sszetevirl, jellemzirl, de tartalmazza a nyelv referenciakziknyvt is. Az Olvas a legavatottabb forrsbl merthet : a
vilghr szerzpros egyik tagja, Dennis Ritchie a C nyelv
tervezje, a msik, Brian W. Kernighan tbb, magyarul is megjelent
nagy siker szakknyv szerzje. Remljk, mind a kezd, mind a
gyakorlott C-programozk haszonnal forgatjk majd a mvet.
A Kiad
Elsz
A C ltalnos cl programnyelv. Tmrsg, a korszer vezrlsi s
adatstruktrk hasznlata, bsges opertorkszlet jellemzi. Nem
nevezhet sem nagyon magas szint, sem nagy nyelvnek, s nem ktdik
egyetlen
specilis
alkalmazsi
terlethez
sem.
Ugyanakkor
a
megktsek hinya, az ltalnos jelleg sok magas szint nyelvnl
knyelmesebb s hatkonyabb teszi.
A C nyelvet tervezje, Dennis Ritchie eredetileg az UNIX opercis
rendszer programnyelvnek sznta. Az opercis rendszer, a C fordt
s
lnyegben
az
sszes
UNIX
alkalmazsi
program
(a
knyv
eredetijnek a nyomdai elksztshez hasznlt szoftver is) C
nyelven rdott. Dennis Ritchie az els C fordtt PDP- 11-en rta
meg, de azta nhny ms gpre, gy az IBM System/370-re, a Honeywell
6000-re s az Interdata 8/32-re is kszlt C fordt: A C nyelv nem
ktdik szorosan egyetlen hardverhez vagy rendszerhez sem, knnyen
rhatunk olyan programokat, amelyek vltoztats nlkl futnak brmely
ms, a C nyelvet tmogat gpen.
Knyvnkkel a C nyelv programozs elsajttshoz szeretnnk
segtsget adni. Az olvas mr az Alapismeretek c. fejezet megrtse
utn elkezdhet programozni. A knyv ezutn kln-kln fejezetben
ismerteti a C nyelv f sszetevit, majd referencia-kziknyv
formjban is sszefoglalja a nyelvet.
Az anyag tlnyomrszt
pldaprogramok rsbl, olvassbl s mdostsbl ll, nem szraz
szablygyjtemnyt adunk az olvas kezbe. A legtbb plda teljes,
ellenrztt,
mkdkpes
program,
s
nem
csupn
elszigetelt
programrsz. Knyvnkben nemcsak a nyelv hatkony hasznlatt

kvntuk ismertetni.
Trekedtnk arra is, hogy j stlus,
ttekinthet,
hasznos
algoritmusokat
s
programozsi
elveket
mutassunk be. A knyv nem bevezet jelleg programozsi segdknyv;
felttelezi, hogy az olvas ismeri a programozs olyan alapfogalmait,
mint: vltozk, rtkad utastsok, ciklusok, fggvnyek. [A C
nyelvben hasznlatos terminolgia
szerint
a szubrutinokat
fggvnyeknek
(functions)
nevezik. A ford.] Ugyanakkor a knyv
alapjn egy kezd programoz is megtanulhatja a nyelvet, br szksge
lehet jrtasabb kollga segtsgre.
Tapasztalataink szerint a C
sokfle feladat megfogalmazsra alkalmas, kellemes, kifejez s
rugalmas nyelv. Knnyen elsajtthat, s aki megismerte, szvesen
hasznlja. Remljk, hogy knyvnk segtsget nyjt a nyelv hatkony
hasznlatban.
A knyv megszletshez s a megrsakor rzett
rmnkhz
nagyban
hozzjrultak
bartaink,
kollgink
gondolatgazdag brlatai s javaslatai.
Klnsen hlsak vagyunk Mike Bianchinak, Jim Blue-nak, Stu
Feldmannek, Doug Mcllroynak, Bill Roome-nak, Bob Rosinnek s Larry
Roslernek, akik
figyelmesen elolvastk
a
knyv
tbb vltozatt
is.
Al Aho, Steve Bourne, Dan Dvorak, Chuck Haley, Debbie Haley,
Marion Harris, Rick Holt, Steve Johnson, John Mashey, Bob Mitze,
Ralph Muha, Peter Nelson, Elliot Pinson, Bill Plauger, Jerry 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
(korutinok) hasznlatt.

szinkronizlst

vagy

prhuzamos

rutinok

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 PDP11 -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 szmtgp-architektrtl
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 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
szntuk mvnket az adatstruktrk s algoritmusok kziknyvnek:
knyszer vlaszts esetn elssorban a nyelvre koncentrltunk.
A 2. ... 6. fejezet rszletesen, az
1. fejezetnl preczebben
trgyalja a C nyelv klnbz elemeit, a hangsly azonban itt sem a
rszleteken,
hanem
a
teljes,
a
gyakorlatban
alkalmazhat
pldaprogramokon van. A 2. fejezet
az
alapvet adattpusokat,
opertorokat
s
kifejezseket
ismerteti.
A
3.
fejezet
a
programvezrlssel: if-else, while, for stb. foglalkozik. A 4.
fejezet tmi : a fggvnyek s a program felptse, kls vltozk,
az rvnyessgi tartomny szablyai stb. Az 5. fejezet a mutatkkal
s a cmaritmetikval, a 6. fejezet a struktrkkal s unionokkal
kapcsolatos tudnivalkat tartalmazza. A 7. fejezet a szabvnyos bes
kiviteli
(I/o)
knyvtrat
ismerteti,
amely
kzs
csatlakozfelletet kpez az opercis rendszer fel. Ezt a be- s
kiviteli knyvtrat minden olyan gp tmogatja, amely a C-t
tmogatja, teht azok a programok, amelyek ezt hasznljk bevitel,
kivitel s ms rendszerfunkcik cljbl, lnyegben vltoztats
nlkl vihetk t egyik rendszerrl a msikra.
A 8. fejezet a C programok s az UNIX opercis rendszer kztti
csatlakozsokat rja le, elssorban a be- s kivitelre, az
llomnyrendszerre s a gpfggetlensgre koncentrlva. Br e fejezet
egy rsze UNIX-specifikus, a nem UNIX-ot hasznl programozk is
hasznos tudnivalkat tallhatnak benne - megtudhatjk pl., hogyan
valstottk meg a szabvnyos knyvtr adott verzijt, s hogyan
nyerhetnk gpfggetlen programkdot.
Az A. fggelk a C nyelv
referencia-kziknyvt,
a
C
szintaxisnak
s
szemantikjnak
hivatalos lerst tartalmazza.
Ha az elz fejezetekben esetleg
ktrtelmsgekre vagy hinyossgokra bukkanunk, mindig ezt kell
vgs dntbrnak tekinteni.
Mivel a C olyan, mg fejldsben lev nyelv, amely szmos rendszeren
fut, elfordulhat, hogy a knyv egy-egy rsze nem felel meg valamely
adott rendszer fejldse pillanatnyi llapotnak.
Igyekeztnk
elkerlni az ilyen problmkat, s megprbltuk felhvni a figyelmet
a lehetsges nehzsgekre. Ktes esetekben azonban ltalban a PDP11 UNIX rendszer esetben rvnyes helyzet lerst vlasztottuk,
mivel a C programozk tbbsgnek ez a munkakrnyezete. Az A.
fggelkben ismertetjk a fontosabb C rendszerek megvalstsaiban
mutatkoz klnbsgeket is.
_
A. fggelk : C referencia-kziknyv
1.
Bevezets
A kziknyv a DEC PDP 11 , a Honeywell 6000, az IBM System/370 s az
Interdata 8/32 gpeken hasznlhat C nyelvet ismerteti.
Eltrsek
esetn a PDP
11 -es vltozatot helyezi eltrbe, de igyekszik
rmutatni
a
megvalstsfgg
rszletekre.
Nhny
kivteltl
eltekintve
ezek
a
gpfgg
rszletek
kzvetlenl
a
hardver
alaptulajdonsgaibl kvetkeznek; a klnfle fordtk ltalban
elgg kompatibilisek.

2.
Szintaktikai egysgek
A szintaktikai egysgek hat osztlyba sorolhatk: azonostk,
kulcsszavak,
llandk,
karakterlncok,
opertorok
s
egyb
szepartorok. A szkzket, tabultorokat, jsorokat, megjegyzseket
(kzs nevkn res helyeket), mint az albbiakban is ltni fogjuk, a
C fordt nem veszi figyelembe, eltekintve attl, hogy feladatuk a
szintaktikai egysgek elvlasztsa. res helyre van szksg az
egybknt
szomszdos
azonostk,
kulcsszavak
s
llandk
elvlasztsra.
Ha a beolvasott szveg szintaktikai egysgekre bontsa adott
karakterig
megtrtnt,
a
fordt
azt
a
lehet
leghosszabb
karakterlncot
tekinti
a
kvetkez
egysgnek,
amelyrl
felttelezhet, hogy mg egyetlen szintaktikai egysget kpez.
2.1. Megjegyzsek
A /*karakterek megjegyzst (comment) vezetnek be, amely a */
karakterekkel zrul. A megjegyzsek nem skatulyzhatk egymsba.
2.2. Azonostk (nevek)
Az azonost betk s szmjegyek sorozata; az els karakter bet
kell, hogy legyen. A
alhzsjel betnek szmt. A nagy-s
kisbetk klnbzk. Csupn az els nyolc karakter rtkes, br
tbb is hasznlhat. A klnfle
, assemblerek
s
betltprogramok
ltal
hasznlt
kls
azonostk
ennl
ktttebbek:
DEC PDP 11
nagybet).
Honeywell 6000
IBM 360/370
Interdata 8/32

7 karakter, ktfle bettpus (kis-s


6 karakter, egyfle bettpus.
7 karakter, egyfle bettpus.
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.
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.)

DEC PDP-11

Honeywell 6000

ASCII
8
16
16
32
32

ASCII
9
36
36
36
36

IBM 370

Interdata

8/32
char
int
short
long
float
double
rtktartomny

EBCDIC
8
32
16
32
32
64

64

72

+-10+-38

+-10+-38

ASCII
8
32
16
32
32

+-10+-76

64
+-10+-76

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


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

van;

tbbi

mret

specilis

ignyek

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
tartalmazhatjk.

klnfle

tpus

objektumok

brmelyikt

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
eljel-kiterjesztssel
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.
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
ugyanabban a tpusban szolgltatja. Ezt
aritmetikai konverzinak nevezni.
Elszr is minden char vagy short tpus
minden float operandus double-l alakul.

ki, s az eredmnyt
az eljrst szoksos
operandus

int-t

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 unsignedd alakul, s ez lesz az eredmny tpusa is.

10

Minden ms esetben mindkt operandusnak int-nek kell lennie


lesz az eredmny tpusa is.

s ez

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 0val val oszts kezelse, ill. a lebegpontos kivtelek gprl gpre
vltoznak,
s
ltalban
valamilyen
knyvtri
fggvnnyel
mdosthatk.
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.

11

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.
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.

12

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 2nbl 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.

13

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.
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 byte-ok 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,

14

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 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.

15

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 0val 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!
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 0-t. 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.

16

7.12. logikai VAGY opertor


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

17

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
nulla-mutatt
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.
8.1. Trolsiosztly-specifiktorok A trolsiosztly-specifiktorok
az albbiak:
t.o._specifiktor:
auto
static
extern
register
typedef

18

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
PDP- 11 -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
tpus-specifiktor
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.
foglalkozik; a typedef nevekkel trtn deklarcikat a 8.8.
trgyalja.

pont
pont

8.3. Deklartorok
A deklarciban megjelen deklartorlista deklartorok vesszkkel
elvlasztott sorozata, amelyek mindegyike kezdeti rtkkel (k..)
rendelkezhet.
deklartorlista:
k.._deklartor
k.._deklartor , deklartorlista

19

k.._deklartor:
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

20

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

azonost

strukt._vagy_union:
struct
union

21

A struktradeklartor-lista a struktra vagy union tagjaira vonatkoz


deklarcik felsorolsa:
strukt._dekl._lista:
strukt._deklarci
strukt._deklarci strukt._dekl._lista
strukt._deklarci:
tpus_specifiktor
strukt._deklartor_lista:

strukt._deklartor_lista

strukt._deklartor
strukt._deklartor , strukt._deklartor_lista
Kznsges esetben a strukt. deklartor egyszeren a struktra vagy
union valamely tagjnak deklartora. A struktra tagjai adott szm
bitet is tartalmazhatnak. Az ilyen tag neve mez (field), hosszt a
nvtl kettspont vlasztja el.
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

22

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
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 )

23

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] ={
{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] ={

24

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
karakterlnccal inicializltuk.

elemeit

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]
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

25

ksbbiekben
gy
hasznlhatunk,
mintha
az
alapvet
leszrmaztatott tpusokat megnevez kulcsszavak lennnek:

vagy

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
im;}complex;

MILES,

*KLICKSP;

typedef

struct

double

re,

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
fggvnyhvsok.

utastsok

legtbbszr

rtkadsok

vagy

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

26

deklarcik hatsra nincs trfoglals, gy ezek inicializlsa nem


megengedett.
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.

27

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 :
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).

28

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.
9.12. A cmkzett utasts
Brmelyik utastst megelzhetik az
azonost:
alak
eltagok,
amelyek
az
azonostt
cmkeknt
deklarljk. A cmke egyedl a goto clpontjaknt szolgl. A cmke
rvnyessgi tartomnya az a fggvny, amelyben elfordul, kivve
azokat az
alblokkokat,
amelyekben ugyanezt az azonostt
jradeklarltk (l. a 11. pontot).
9.13. A nulla utasts A nulla utasts alakja:
;
A nulla utasts hordozhat pl. cmkt kzvetlenl valamely sszetett
utasts }-e eltt, vagy pedig a while-hoz hasonl valamelyik
ciklusutasts szmra res ciklustrzset kpezhet.
10.
Kls defincik
A C program kls (external) defincik sorozatt tartalmazza.
A
kls definci a vltozt extern (ez az alaprtelmezs) vagy static
trolsi osztlynak s megadott tpusnak deklarlja. A tpusspecifiktor (l. a 8.2. pontot) lehet res, ebben az esetben a tpust
int-nek tekintjk. A kls defincik rvnyessgi tartomnya annak
az
llomnynak
a
vgig
tart,
amelyben
deklarltk
ket;
hasonlkppen a deklarcik is az llomny vgig rvnyesek. A kls
defincik szintaxisa ugyanaz, mint az sszes deklarci, azzal a
klnbsggel, hogy a fggvnyeket csak ezen a szinten lehet
definilni.
10.1. Kls fggvnydefincik A fggvnydefincik alakja:
fggvnydefinci:
dekl._specifiktorokopc
fggvny
deklartor
fggvnytrzs
A
deklarcispecifiktorok
kzl
trolsiosztly-specifiktorknt
csupn az extern s a static megengedett; a kett kztti klnbsgre
nzve l. a 11.2. pontot. A fggvnydeklartor hasonl a fggvny,
amely . .
.-t ad vissza jelleg deklartorhoz, azzal a
klnbsggel,
hogy
megadja
a
definilt
fggvny
formlis
paramtereinek listjt.
fggvnydeklartor:

29

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.
A C az sszes float tpus aktulis paramtert double-l alaktja t,
gy a float-nak deklarlt formlis paramterek deklarcii is doublel 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

30

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
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.

31

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. Szintaktikai egysgek helyettestse
A
#define azonost szint._egysgek_karakterlnca alak fordt vezrl
sor (vigyzat: nincs zr pontosvessz) hatsra az elfeldolgoz az
azonost minden tovbbi elfordulst a szintaktikai egysgek
megadott karakterlncval helyettesti.
A
#define azonost(azonost, . . .,azonost)
szint._egysgek_karakterlnca alak sor, ahol az els azonost s a
( kztt nincs szkz, argumentumokkal elltott makrodefinci. Az
els azonostnak azon tovbbi elfordulsait, ahol az azonostt
( , szintaktikai egysgek vesszkkel elvlasztott sorozata s egy )
kveti, a definciban megadott szintaktikai egysg
karakterlnccal helyettesti. A definci formlis
paramterlistjban emltett azonost sszes elfordulsa helyre a
hvs hatsra a megfelel szintaktikai egysg karakterlnc kerl. A
hvs aktulis argumentumai vesszkkel elvlasztott szintaktikai
egysg
karakterlncok,
azonban
az
idzjelek
kztti
vagy
zrjelekkel vdett vesszk nem argumentumelvlasztk. A formlis s
aktulis
paramterek
darabszma
egyenl
kell,
hogy
legyen.
Karakterlncon vagy karakterllandn belli szvegre nem vonatkozhat
a helyettests.
A
helyettest
karakterlncot
(mindkt vltozatban) jra
tvizsglja az elfeldolgoz, hogy megtallja az esetleges tovbbi
definilt azonostkat. A hossz defincik mindkt alakban j sorban
folytathatk oly mdon, hogy a folytatand sor vgre \-t runk.
A #define hasznlat_ leginkbb a hangslyozott funkcij llandk
definilsra elnys, pl.:
#define TABSIZE 100
int table[TABSIZE];
Az
#undef azonost alak vezrlsor hatsra megsznik az azonost
elfeldolgoz-defincija.
12.2. llomnyok beiktatsa
Az
#include llomnynv
alak vezrlsort az elfeldolgoz program az llomnynv nev
llomny teljes tartalmval helyettesti. A megnevezett llomny
keresse az eredeti forrsllomny katalgusban kezddik, majd
sorban, szabvnyos helyeken folytatdik. Megadhatjuk az

32

#include <llomnynv> alak vezrlsort is, amikor a keress csak a


szabvnyos helyeken trtnik, s nem terjed ki a forrsllomny
katalgusra. Az #include-ok egymsba skatulyzhatk.
12.3. Feltteles fordts
Az
#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.

33

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
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
deklarlni kell, mivel g (f)-beli elfordulst nem kvette (.

mdon

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))

34

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, 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:

35

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
s sizeof kifejezsek szerepelhetnek, amelyeket a
+ - * / % & | ^ << >> == != < > <= >=
kt-, ill a
- ~
egyoperandus opertorok valamelyike vagy a hromoperandus
? :
opertor
kthet
ssze
egymssal.
A
zrjelek
hasznlhatk, fggvnyhvsra azonban nem.

csoportostsra

Kevesebb megkts vonatkozik a kezdeti rtkekre; az elbb trgyalt


lland kifejezseken kvl kls s statikus objektumokra, valamint
lland kifejezssel indexelt kls s statikus tmbkre is
alkalmazhat az egyoperandus & opertor.
Implicit mdon az
egyoperandus &-et indexeletlen tmbk s fggvnyek megjelensekor
ugyancsak alkalmazhatjuk. Az alapszably az, hogy a kezdeti rtkek
kirtkelsvel vagy llandt, vagy pedig valamely mr korbban
deklarlt kls vagy statikus objektum (esetleg llandval nvelt
vagy cskkentett) cmt kell megkapnunk.
16.
Gpfggetlensg
A C nyelv bizonyos rszei lnyegknl fogva gpfggk. Az albbiakban
nem trhettnk ki minden problmra, csak a legfontosabbakat akartuk
kiemelni.
Az
olyan
tisztn
hardverkrdsek,
mint
a
lebegpontos aritmetika tulajdonsgai s az

szavak
egszek

mrete,
osztsa

a
a

36

gyakorlatban nem okoztak klnsebb gondot. A hardver egyb


jellegzetessgei az eltr megvalstsokban mutatkoznak meg.
Ezek
nmelyike, klnsen az eljel-kiterjeszts (negatv karakter negatv
egssz trtn talaktsa), valamint a byte-ok szavakon belli
elhelyezkedsi sorrendje olyan kellemetlen tnyezk, amelyekre
klns figyelmet kell fordtanunk. Az egyb gpfgg tulajdonsgok
mr nem jelentenek nagyobb problmt.
A regiszterekben tnylegesen elhelyezked register tpus vltozk
szma - a megengedett tpuskszlethez hasonlan - gprl gpre
vltozik. Minden fordt helyesen vgzi azonban a dolgt a sajt gpe
szempontjbl: a fls szm vagy rvnytelen register deklarcikat
nem veszi figyelembe. Nehzsgek csak akkor tmadnak, amikor valaki
rossz programozsi mdszereket alkalmaz. Ne rjunk olyan programokat,
amelyek az adott architektra brmilyen specifikus tulajdonsgtl
fggetlenek!
A fggvnyargumentumok kirtkelsi sorrendjt a nyelv nem hatrozza
meg. PDP- 11-en jobbrl balra, a tbbi gpen balrl jobbra trtnik.
A
mellkhatsok
rvnyeslsnek
sorrendje
ugyancsak
nem
meghatrozott.
Mivel a karakterllandk valjban int tpus objektumok, tbb
karakterbl ll karakterllandk hasznlata is megengedett.
Ennek
megvalstsa azonban rendkvl gpfgg, mivel a karakterek szhoz
trtn hozzrendelsnek sorrendje gprl gpre vltozik.
Mezk hozzrendelse szavakhoz, karakterek egszekhez a PDP 11-en
jobbrl balra, a tbbi gpen balrl jobbra trtnik.
Elszigetelt
programok szmra e klnbsgek lthatatlanok maradnak, hacsak nem
viszik tlzsba a tpusokkal folytatott jtkot (pl. azltal, hogy
valamely int mutatt char mutatv alaktanak t, majd megvizsgljk
a megcmzett trterletet). Szmolnunk kell azonban e klnbsgekkel
akkor,
ha
a
programunkat
kvlrl
megszabott
trterletelrendezsekkel akarjuk sszhangba hozni.
A klnfle fordtk ltal elfogadott nyelvek csupn egszen kis
rszletekben
trnek
el
egymstl.
A
leglnyegesebb,
hogy
a
pillanatnyilag hasznlatos PDP-11-es fordt nem inicializlja a
bitmezket tartalmaz struktrkat, s egyes rtkad opertorokat
nem fogad el olyan krnyezetben, ahol ki akarjuk hasznlni a
hozzrendels rtkt.
17.
Anakronizmusok
Mivel a C fejldsben lev nyelv, egyes rgebbi programokban bizonyos
elavult szerkezetek tallhatk. Br a fordt legtbb vltozata az
ilyen anakronizmusokat is tmogatja, elbb-utbb ezek el fognak
tnni, csupn gpfggsgi problmt hagyva maguk utn.
A C nyelv korbbi vltozatai rtkad opertorknt az =op
alakot hasznltk az op= alak helyett. Ez ktrtelmsgekhez
vezet, amelynek tipikus esete
x = -1
amely a valsgban x-et dekrementlja, mivel az = s a szomszdosak, de amivel knnyen az lehetett a szndkunk, hogy
1-et rendeljnk x-hez.
A kezdeti rtkek szintaxisa megvltozott: korbban a kezdeti
rtket bevezet egyenlsgjel nem szerepelt, gy az

37

int x = 1;
alak helyett az
int x 1;
alak volt hasznlatban. A vltoztats azrt trtnt, mert az
int
f
(1+2)
alak
inicializls
ppen
elgg
hasonlt
fggvnydeklarcira ahhoz, hogy megtvessze a fordtkat.
18.
A szintaxis sszefoglalsa
A
C
nyelv
szintaxisnak
sszefoglalsa
sokkal
inkbb
segdletl, mintsem a nyelv rvid sszefoglalsul szolgl.

tmr

18.1. Kifejezsek Az alapvet kifejezsek a kvetkezk:


kifejezs:
elsdleges_kifejezs
*kifejezs
&kifejezs
kifejezs
!kifejezs
~kifejezs
++balrtk
balrtk
balrtk ++
balrtk
sizeof kifejezs
(tpus_nv) kifejezs
kifejezs ktop kifejezs
kifejezs ? kifejezs : kifejezs
balrtk rtkad_op kifejezs
kifejezs , kifejezs
elsdleges_kifejezs:
azonost
lland
karakterlnc
( kifejezs )
elsdleges_kifejezs ( kifejezs_listaopc)
elsdleges_kifejezs [ kifejezs ]
balrtk . azonost
elsdleges_kifejezs -> azonost
balrtk:
azonost
elsdleges_kifejezs [ kifejezs ]
balrtk . azonost
elsdleges_kifejezs -> azonost
*kifejezs
( balrtk )
A
() [] . ->
elsdleges kifejezs opertorok prioritsa a legmagasabb, s az
ilyen opertorok balrl jobbra ktnek. Az egyoperandus
& - ! ~ ++ -- sizeof (tpusnv)
opertorok prioritsa az elsdleges opertoroknl alacsonyabb, de
magasabb
az
sszes
ktoperandus
opertornl:
ezek
az

38

opertorokjobbrl balra ktnek. Az sszes ktoperandus opertor s a


feltteles opertor balrljobbra kt, ezeket az albbiakban cskken
prioritsi sorrendben soroljuk fel: ktop:
* / %
+ >> <<
< > <= >=
== !=
&
^
|
&&
||
? :
Az rtkad opertorok mindegyike azonos priorits, s mindegyik
jobbrl balra kt. rtkad_op:
= += -= *= /= %= >>= <<= &= ^= |=
A vessz opertor (,) prioritsa a legalacsonyabb, s balrl jobbra
csoportost.
18.2. Deklarcik
deklarci:
dekl._specifiktorok deklartorlistaopc; dekl._specifiktorok:
tpus_specifiktor dekl._specifiktorokopc
t.o._specifiktor dekl._specifiktorokopc
t.o._specifiktor:
auto
static
extern
register
typedef
tpus_specifiktor:
char
short
int
long
unsigned
float
double
strukt._vagy_union_specifiktor
typedef_nv
k.._deklartorlista:
k.._deklartor
k.._deklartor , k.._deklartorlista
k.._deklartor:
deklartor inicializlopc deklartor:
azonost
( deklartor )
*deklartor
deklartor ()
deklartor
[
strukt._vagy_union_specifiktor:

lland_kifejezsopc]

39

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
utasts utastslista
utasts:
sszetett_utasts
kifejezs;
if ( kifejezs )
utasts
if ( kifejezs )
utasts

40

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:

fggvnydeklartor

fggvnytrzs

deklartor ( paramterlistaopc ) paramterlista:


azonost
azonost , paramterlista
fggvnytrzs:
deklarcilista fggvny_utasts fggvny_utasts:
deklarcilistaopc utastslista adatdefinci:
externopc tpus_specifiktoropc k.._deklartorlista;
tpus_specifiktoropc k.._deklartorlista;
18.5. Elfeldolgoz
#define
azonost
szint._egysgek_karakterlnca
azonost(azonost, ..., azonost)

staticopc

#define

szint._egysgek_karakterlnca
#undef azonost
#include llomnynv
#include <llomnynv>
#if lland_kifejezs
#ifdef azonost
#ifndef azonost
#else

41

#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);
}

42

program

futtatsnak

mdja az ppen hasznlt rendszertl fgg.

Az UNIX opercis rendszerben pl. a forrsprogramot olyan


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

43

ill. stringkonstansnak) neveznk. Pillanatnyilag a karakterlncokat


csak a printf s ms fggvnyek argumentumaiknt hasznljuk.
A

karakterlncban elfordul \ n karaktersorozat az jsor

karakter C-beli jellsmdja. Hatsra a kirs a kvetkez sor


bal szln folytatdik. Ha a \ n-et elhagyjuk (rdemes
megksrelni), azt tapasztaljuk, hogy a kirs vgn a kocsi
vissza -soremels elmarad. Az jsor karaktert csakis egy \n
segtsgvel iktathatjuk be a printf-be: ha valami olyasmivel
prblkozunk, mint
printf (Figyelem, emberek!
);
akkor a C fordt bartsgtalan
hinyz idzjelekrl.

zeneteket

fog

kldeni

bizonyos

A printf sohasem helyez el jsor karaktert automatikusan, gy


tbbszri hvs segtsgvel egyetlen kimeneti sort fokozatosan
rakhatunk ssze. Els programunkat gy is rhattuk volna:
main ()
{
printf (Figyelem, );
printf (emberek!);
printf (\ n);
}
miltal a korbbival azonos kimenetet kaptunk volna.
Megjegyezzk,
hogy \ n egyetlen karaktert jelent. A \ n-hez hasonl, n. escape
jelsorozatok ltalnosan hasznlhat s bvthet mechanizmust
alkotnak nehezen elllthat vagy lthatatlan karakterek jellsre.
A C nyelvben ilyenek mg a \t a tabultor, a \b a visszalptets
(backspace), a \ az idzjel s a \\ magnak a fordtott
trtvonalnak (backslash) a jellsre.
1.2. Gyakorlat. Prblja ki, mi trtnik, ha a printf
argumentum-karakterlnca \ x-et tartalmaz, ahol x egy, a fenti
listban nem szerepl karakter!
1.2. Vltozk s aritmetika
Az albbi program a kvetkez Fahrenheit-hmrskleteket s a
megfelel Celsius-rtkeket tartalmaz tblzatot nyomtatja ki a
C = (5/9)(F-32)
kplet alkalmazsval.
0
-17.8
20
-6.7
40
4.4
60
15.6
...
...
260
126.7
280
137.8
300
148.9
me maga a program:
/* Fahrenheit-Celsius tblzat kinyomtatsa f = 0, 20, . . ., 300
rtkekre */ main ()

44

{
int lower, upper, step;
float fahr, celsius;
lower = 0;
/* A hmrsklet-tblzat als hatra */
upper = 300; /* fels hatr */
step = 20;
/* lpskz */
fahr = lower;
while (fahr <= upper) {
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf (%4.0f %6.1f \n, fahr, celsius);
fahr = fahr + step;
}
}
Az els kt sor:
/* Fahrenheit-Celsius tblzat kinyomtatsa
f = 0, 20, . . ., 300 rtkekre */
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.

45

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 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).

46

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 :
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

47

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 hmrsklettszmtstl. 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
egy-egy
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*/
{
int fahr; for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
printf(%4d %6.1f\n, fahr, (5.0/9.0) * (fahr-32));
}

48

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
llomny vge jel)

while

(a

beolvasott

karakter

nem

az

az ppen beolvasott karakter kimenetre rsa


egy j karakter beolvassa
Mindezt C nyelven kifejezve:
main()

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

{
int c ;
c = getchar();
while (c != EOF) {
putchar;
c = getchar();
}
}
A != relcis opertor jelentse : nem egyenl .
A f problma a bemenet vgnek az rzkelse. Megllapods
szerint a getchar az llomny vgnek megtallsakor olyan
rtkkel tr vissza, amely nem valamely rvnyes karakter kdja:

49

ily mdon a program szlelni tudja, hogy mikor fogytak el a


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

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

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

50

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
A kvetkez program, amelyet a msolprogram
kaptunk, megszmllja a beolvasott karaktereket:
main()

kis

mdostsval

/* Megszmllja a bemeneten rkez karaktereket*/

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

/*Megszmllja a bemeneten rkez karaktereket*/

{
double nc;
for (nc = 0; getchar() != EOF; ++nc)
;
printf (%.0f \n, nc);
}
A printf mind float, mind double esetn
elnyomja a nemltez trt rsz kirst.

%f-et

hasznl;

%.0f

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

51

kvetelmny kielgtse
feltnbb legyen.

miatt

szerepel.

Kln

sorba

rtuk,

hogy

Mieltt befejeznnk a karakterszmll program elemzst, felhvjuk a


figyelmet, hogy ha a bemeneten nincsenek karakterek, akkor getchar
legels hvsakor a while vagy a for felttelvizsglata hamis rtket
eredmnyez, s gy a program eredmnye elvrsunknak megfelelen 0
lesz. Ez lnyeges megfigyels. A while s a for egyik elnys
tulajdonsga, hogy a felttelvizsglat a ciklus fejben van, megelzi
a trzset. Ha teht semmit sem kell csinlni, akkor tnyleg semmi sem
trtnik, mg akkor sem, ha emiatt a program sohasem halad t a
ciklus trzsn. A programoknak akkor is rtelmesen kell mkdnik, ha
a bemenet res. A while s a for segtsgvel a programok
hatresetekben is sszeren viselkednek.
Sorok szmllsa
A kvetkez program megszmllja a bemenetre rkez sorokat.
Felttelezzk, hogy a bemen sorok a \n jsor karakterrel fejezdnek
be, amely szigoran minden kirt sor vgn megjelenik.
main()

/*A bemenetre rkez sorok szmllsa*/

{
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!

52

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;
++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

53

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.
Tizenktfle bemeneti karaktert kell megklnbztetnnk, gy
rdemes az egyes szmjegyek elfordulsainak szmt egy tmbben
nyilvntartani ahelyett,
hogy
tz kln vltoznk lenne.
A
program egyik lehetsges vltozata:
main()

/*Szmjegyek, res helyek s


egyb karakterek szmllsa*/

{
int c, i, nwhite, nother;
int ndigit [10];
nwhite = nother = 0;
for (i = 0; i < 10;
++i)
ndigit [i] = 0;
while ((c = getchar()) != EOF)
if (c >= 0 && c <= 9)
++ ndigit [c - 0]; else if (c == || c == \n || c == \t)

54

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

55

utasts
else
utasts programszerkezetet
elgazsok lersra.

gyakran

alkalmazzk

tbbutas

A programszveg beolvassa fellrl kezdve mindaddig folytatdik,


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

56

legjobb, ha egyszerre csak egy problmra sszpontostunk.


Az
albbiakban a power fggvnyt egy fprogramba gyazva mutatjuk be.
Ne feledjk, hogy a main() maga is fggvny!
main ()

/*Hatvnyoz fggvny tesztelse*/

{
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

57

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

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

2. vltozat*/
int x, n;
{
int p;
for (p = 1; n > 0; --n)
p = p * x;
return (p);
}
Az n argumentumot ideiglenes vltozknt hasznltuk s addig
dekrementltuk, amg el nem rte a 0-t; gy nincs szksg az i
vltozra. Mindannak, ami az n-nel a power-en bell trtnik, nincs
befolysa arra az argumentumra, amellyel eredetileg a fggvnyt
meghvtuk.
Szksg esetn megoldhat, hogy a fggvny mdostani tudja az t
hv rutin valamelyik vltozjt. A hvnak meg kell adnia a
mdostand vltoz cmt (gyakorlatilag egy, a vltozt megcmz
mutatt), s a hvott fggvnynek az argumentumot mutatknt kell
deklarlnia, a tnyleges vltozra ezen keresztl, indirekt mdon
kell hivatkoznia. Ezzel az 5. fejezetben foglalkozunk.
Ha egy tmb nevt hasznljuk argumentumknt, akkor a fggvnynek
tadott rtk tnylegesen a tmb kezdetnek helye vagy cme. (A
tmbelemek nem msoldnak t). Ezt az rtket indexelve a fggvny a
tmb tetszleges elemt elrheti s megvltoztathatja. Ezzel a
kvetkez fejezet foglalkozik.
1.9. Karaktertmbk
A C nyelvben leggyakoribb tmbtpus valsznleg a karaktertmb. A
karaktertmbk s az ket kezel fggvnyek hasznlatt egy olyan

58

programmal szemlltetjk, amely


leghosszabbat megjelenti.

sorokat

olvas

be

kzlk

Az alapstruktra meglehetsen egyszer :


while (van mg sor) if (hosszabb, mint az eddigi leghosszabb sor)
trold a sort s a hosszt nyomtasd ki a leghosszabb sort Ez a
struktra vilgoss teszi a program termszetes tagozdst. Az
egyik rsz beolvassa s megvizsglja az jsort, a msik trolja, a
harmadik vezrli a folyamatot.
Minthogy a feladatok ilyen szpen elklnthetk, helyes, ha a
programot is eszerint rjuk meg. Ennek megfelelen elszr rjunk
egy kln getline fggvnyt, amely beolvassa a bemenetrl a kvetkez
sort,_ ez a getchar fggvny ltalnostsa.
Szeretnnk ha a
fggvny ms krnyezetben is hasznlhat lenne, ezrt igyeksznk a
lehet legrugalmasabb tenni. A minimlis igny, hogy a getline
jelezze vissza az esetleges llomnyvget; ltalnosabban hasznlhat
lesz a fggvny, ha a sor hosszt adja vissza, vagy pedig nullt, ha
elrte az llomny vgt. A nulla bizonyosan nem valdi sorhossz,
mivel minden sor legalbb egy karaktert kell, hogy tartalmazzon, mg
a csupn egyetlen soremelst tartalmaz sor hossza is 1.
Ha azt talljuk, hogy egy sor hosszabb, mint az addigi leghosszabb
sor, valahov el kell mentennk. Logikus, hogy ez egy msodik
fggvny, a copy feladata legyen, amely az j sort biztos helyre
menti.
Vgezetl szksgnk van egy fprogramra, amely vezrli a getline-t
s a copy-t. Ime az egsz program:
#define MAXLINE 1000 /*A beolvasott sor maximlis mrete*/
main ()

/*A leghosszabb sor kivlasztsa*/

{
int len; /*A pillanatnyi sor hossza*/
int max; / *Az eddigi maximlis hossz*/
char line [MAXLINE]; /*A pillanatnyilag olvasott sor*/
char save [MAXLINE]; /*A leghosszabb sor mentsre*/
max = 0;
while ((len = getline (line,MAXLINE)) > 0)
if (len > max) {
max = len; copy (line,save);
}
if (max > 0) /*Volt sor*/
printf (%s, save);
}
getline (s,lim)
/*Sor beolvassa s-be,
a hosszt adja vissza*/
char s [];
int lim;
{
int c, i;
for (i = 0; i < lim - 1 && (c =getchar ()) != EOF &&
c != \n; ++i) s [i] = c;
if (c == \n) {
s [i] = c;
++i;
}

59

s [i] = \0;
return (i);
}
copy (s1,s2)

/*s1 msolsa s2-be;


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

60

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*/
int max; /*Az eddigi maximlis hossz*/
main ()

/*A leghosszabb sor


specilis vltozat*/

kivlasztsa;

{
int len; /*A pillanatnyi sor hossza*/
extern int max;

61

extern char save [ ];


max = 0;
while ((len = getline ()) > 0)
if (len > max) {
max = len;
copy ();
}
if (max > 0) /*Volt sor*/
printf (%s, save);
}
getline ()

/* Specilis vltozat*/

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

/*Specilis vltozat*/

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

62

4. fejezetben fejtjk ki.


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

63

valamint a megjegyzsekrl sem !


ltalnossgban nehz elkszteni.)

(Ezt

programot

teljes

_
2.

fejezet: Tpusok, opertorok s kifejezsek

A programok alapvet adatobjektumai a vltozk s az llandk.


A
deklarcik felsoroljk a hasznlni kvnt vltozkat, kzlik a
tpusukat, valamint az esetleges kezdeti rtkket. Az opertorok azt
hatrozzk meg, hogy mit kell tenni a vltozkkal. A kifejezsek a
vltozkbl s llandkbl j rtkeket hoznak ltre. Fejezetnkben
ezekkel foglalkozunk.
2.1. Vltoznevek
Br eddig errl nem beszltnk, a vltozk s szimbolikus llandk
neveire nzve vannak bizonyos megktsek. A nevek betkbl s
szmjegyekbl llnak: az els karakter bet kell, hogy legyen. Az
alhzs karakter (_) betnek szmt: ezzel javthatjuk a hossz
vltoznevek olvashatsgt. A nagy- s a kisbet klnbznek
szmt; a hagyomnyos C programozsi gyakorlat szerint a vltoznevek
kisbetsek, a szimbolikus llandk csupa nagybetbl llnak.
A bels nevekben csupn az els nyolc karakter rtkes, br ennl
hoszszabb
nevek
is
hasznlhatk.
Kls
nevek
esetn,
gy
fggvnyneveknl s kls vltozknl ez a szm nyolcnl kevesebb is
lehet, mivel a kls neveket klnfle assemblerek s tltprogramok
(loaderek) is hasznljk. Ennek rszleteit az A fggelk ismerteti.
Ezenkvl az olyan kulcsszavak, mint if, else, int, float stb.
fenntartott szavak; vltoznvknt nem hasznlhatk. (Kisbetseknek
kell lennik.)
Termszetesen sszer olyan vltozneveket vlasztani, amelyek
jelentenek
valamit,
kapcsoldnak
a
vltoz
funkcijhoz,
s
tipogrfiailag nem zavark.
2.2.
van:

Adattpusok s mretek A C-ben csak nhny alapvet adattpus


char

egyetlen byte, amely az rvnyes karakterkszlet


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

char
int

DEC PDP-11
ASCII
8
16

Honeywell6000
IBM 370
Interdata 8/32
ASCII
EBCDIC
ASCII
8
8
8
36
32
32

64

short 16
long 32
float 32
double

36
36
36
64

16
32
32
72

16
32
32
64

64

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 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.

65

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 annak hatrolsra
szolglnak. A karakterlncokban ugyanazok az escape szekvencik
hasznlhatk, mint amelyeket a 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);
}
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:

66

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
hatrozatlan.

inicializls

nlkli

automatikus

vltozk

rtke

A kls s statikus vltozk kezdeti rtke alaprtelmezs szerint


nulla, de stilrisan helyesebb, ha minden esetben megadjuk a kezdeti
rtket.
Az inicializls tmjt
adattpusokrl lesz sz.

akkor

folytatjuk,

amikor

tovbbi

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
opertor precedencijt s ktsi mdjt.) A kirtkels
sorrendje olyan asszociatv s kommutatv opertoroknl, mint a
s +, nincs meghatrozva; a fordt trendezheti az olyan
zrjelezett szmtsokat, amelyek ezek valamelyikt tartalmazzk.
gy a+(b+c) azonos (a+b)+c-vel. Ennek ritkn van jelentsge, de
ha adott sorrendre van szksg, akkor explicit ideiglenes
vltozkat hasznlhatunk.

67

A tlcsorduls s alulcsorduls esetnek kezelse az adott gptl


fgg.
2.6.

Relcis s logikai opertorok

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

Tpuskonverzik

68

Ha egy kifejezsben klnbz tpus operandusok fordulnak el, a


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

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

{
if (c >= A && c <= Z)
return (c + a - A);
else
return ;
}
Ez a
program csak az ASCII kdkszlet hasznlata esetn mkdik
helyesen, mivel abban a megfelel kis- s nagybetk tvolsga
rgztett, mind a kisbets, mind a nagybets bc numerikus rtkei
folytonosan kvetik egymst - A s Z kztt csak betk vannak.
Az EBCDIC karakterkszletre (IBM 360/370) ez az utbbi tulajdonsg
nem rvnyes, gy lower nem mkdne helyesen - nem csak betket
konvertlna.
A karaktereknek egsz szmokk trtn talaktsval kapcsolatban
megemltjk a nyelv egy finomsgt. A C nyelv nem hatrozza meg, hogy
a char tpus vltozk eljeles vagy eljel nlkli mennyisgek-e.
Krds teht, hogy
egy
char mennyisg int tpusv
alaktsakor
ltrejhet-e negatv egsz is? Sajnos ez az architektrtl fggen
gprl gpre vltozik. Bizonyos gpeken (pldul a PDP-11-en)
az
olyan char, amelynek legbaloldalibb bitje 1,negatv egssz alakul t
(eljel-kiterjeszts: 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.

69

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)
...
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!

70

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.
Vgezetl tetszleges kifejezsben is kivlthatunk,
kiknyszerithetnk tpuskonverzit, ha n. tpusmdost (cast)
szerkezetet hasznlunk. A (tipusnv) kifejezs szerkezetben a
kifejezs az elz szablyok alkalmazsval az elrt tpusv
alakul t, gy mintha a kifejezs hozz lenne rendelve egy, a
megadott tpus vltozhoz, amelyet azutn az egsz szerkezet
helyett hasznlunk. Pldul az sqrt (gykvon) knyvtri rutin
double tpus argumentumot vr, s rtelmetlen eredmnyt ad, ha
vletlenl valami mst kap. Ha teht n egsz tpus, akkor
sqrt ((double) n) az n-et a sqrt-nek trtn tads eltt double-l
konvertlja.
(Jegyezzk meg, hogy a tpusmdost szerkezet n
rtkt a kvnt tpusban szolgltatja; n tnyleges tartalma azonban
nem vltozik.) A tpusmdost opertor precedencija ugyanaz, mint a
tbbi egyoperandus opertor, amint azt a fejezet vgn kzlt
sszefoglal tblzat is mutatja.
2.2. Gyakorlat.
Irjuk
meg
a
htoi(s)
fggvnyt,
amely
egy
hexadecimlis szmjegyekbl ll karakterlncot a neki megfelel
egsz rtkk alakt t! A megengedett szmjegyek; 0...9, a...f s
A...F.
2.8. Inkrementl s dekrementl opertorok
A C nyelv tartalmaz kt szokatlan opertort, amelyekkel vltozk
inkrementlhatk s dekrementlhatk. A ++ inkrementl opertor
operandushoz 1 -et ad hozz, adekrementl opertor pedig 1 -et von
le belle. A ++-t gyakran hasznljuk vltozk inkrementlsra,
pldul:
if (c == \n)

71

++nl;
A szokatlansg abban rejlik, hogy a ++ s aegyarnt hasznlhat
prefix opertorknt (a vltoz eltt, mint a ++n esetben) vagy
postfix opertorknt (a vltoz mg rva: n++).
Az eredmny mindkt esetben n inkrementlsa. De mg a ++n
kifejezs n-et az eltt nveli, hogy felhasznln annak rtkt,
n++

csak azt kveten

inkrementl. Eszerint olyan esetekben

amikor nemcsak az inkrementl tulajdonsgot, hanem n rtkt is


felhasznljuk, ++n s n++ klnbznek egymstl. Ha n rtke 5,
akkor
x = n++;
az x-et 5-re lltja, de
x = ++n;
x-et 6-ra lltja. n mindkt esetben 6 lesz. Az inkrementl s
dekrementl opertorok csak vltozkra alkalmazhatk; az olyan
kifejezs, mint
x = (i + j)++ nem megengedett !
Ha az rtkre nincs szksg, csak az inkrementl hatsra, pl.
if (c == \n) nl++;
esetben, a prefix vagy a postfix opertort tetszs szerint
vlaszthatjuk meg. Vannak azonban olyan feladatok, amikor specilisan
az egyikre vagy a msikra van szksg. Tekintsk pldul a squeeze(s,
c) fggvnyt, amely az sszes elfordul c karaktert trli az s
karakterlncbl:
squeeze (s, c) /*Valamennyi c karakter trlse s-bl*/ char s [];
int c;
{
int i, j;
for (i = j = 0; s [i] != \0; i++)
if (s [i] != c)
s [j++] = s [i]; s [j] = \0;
}
Minden alkalommal,

amikor a program

az

s karakterlncban

c-vel nem azonos karaktert tall, bemsolja azt a pillanatnyi j


pozciba, s csak ezutn inkrementlja j-t, hogy fogadhassa a
kvetkez karaktert. Hatsa pontosan azonos az
if (s [i] != c) {
s [j] = s [i];
j++;
}
alakval. Hasonl plda fordult el az 1. fejezetben ltott
getline fggvnyben, ahol az
if (c == \n) {
s [i] = c;
++i;
}

72

sorokat az ennl tmrebb


if (c == \n) s [i++] = c;
alakkal helyettesthetjk.
Harmadik pldnk az strcat(s, t) fggvny, amely a t karakterlncot
az
s
karakterlnc
vghez
illeszti
(konkatenlja).
strcat
felttelezi, hogy s-ben elg hely van ahhoz, hogy ott az
sszeillesztett karakterlnc elfrjen.
strcat (s,t)
/*t illesztse s vghez*/
char s[], t [];
/ * s-nek elg nagynak kell lennie * /
{
int i, j;
i = j = 0;
while (s[i] != \0) /*Keresi
s
vgt*/
while (s [i] = \ ) /
eresi s vg
/
i++;
while ((s [i++] = t[j++]) != \0)
/*t tmsolsa*/
;
}
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,
|
bitenknti megenged (inkluzv) VAGY,
^
bitenknti kizr (exkluzv) VAGY,
<<
bitlptets (shift) balra,
>>
bitlptets (shift) jobbra,
~
egyes komplemens (egyoperandus).
A bitenknti S opertort gyakran hasznljuk valamely
maszkolsra. Pldul:

bithalmaz

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

73

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)
p, n;

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

{
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 xben a p pozcitl kezdve n bitet invertl(vagyis az 1-eseket 0ra, a 0-kat 1-esekre cserli fel), mikzben a tbbi bit
vltozatlan marad!
2.10. rtkad opertorok s kifejezsek
Az olyan kifejezsek, mint
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=

74

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,
jobban megfelelnek az emberi gondolkodsmdnak. Azt mondjuk:

hogy

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
szerepelhetnek kifejezsekben, br ezek ritkbban fordulnak el.

is

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!
2.11. Feltteles kifejezsek
Az
if (a > b)
z = a;
else

75

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 egy-egy 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
Asszociativits
() []
balrl jobbra
! ~ ++ -- - (tipus) * & . -> sizeof jobbrl balra
* / %
balrl jobbra

76

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

balrl jobbra
balrl jobbra
balrl jobbra
balrl jobbra
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

77

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.)
_
3.

fejezet: Vezrlsi szerkezetek

A nyelv vezrlstad utastsai a szmtsok vgrehajtsnak


sorrendjt hatrozzk meg. A korbbi pldkban mr tallkoztunk a C
leggyakoribb vezrlstad utastsaival. Ebben a fejezetben teljess
tesszk a kszletet s rszletesen ismertetjk a mr korbban
emltett utastsokat is.
3.1. Utastsok s blokkok
A kifejezsek, pl. x = 0, i++ vagy
vlnak, ha pontosvessz kveti ket:

printf(.

.)

utastss

x = 0; i++; printf (. . .);


A C-ben a pontosvessz utastslezr jel (termintor) s nem
elvlaszt szimblum, mint az ALGOL-szer nyelvekben.
A { s }
kapcsos zrjelek felhasznlsval deklarcikat s utastsokat
egyetlen sszetett utastsba vagy blokkba foghatunk ssze. Ez
szintaktikailag egyetlen utastssal egyenrtk. Nyilvnval pldi
ennek a fggvnyek utastsait hatrol kapcsos zrjelek, vagy azok
a zrjelek, amelyek egy if, else, while vagy for szimblumot kvet
utastssort
vesznek
krl.
(Vltozk
brmely
blokkon
bell
deklarlhatk, errl a 4.
fejezetben lesz sz.) A blokkot
lezr
jobb oldali kapcsos zrjel utn soha nincs pontosvessz.
3.2. Az if-else utasts
Az if-else utastssal dntst, vlasztst runk le. Az utasts
szintaxisa formlisan :
if (kifejezs)
1.utasts
else
2.utasts
ahol az else rsz nem ktelez. A gp a kifejezs kirtkelse utn,
ha annak rtke igaz (vagyis nemnulla), az 1. utastst, ha rtke
hamis (nulla), s ha van else rsz, akkor a 2.
utastst hajtja
vgre.
Mivel az if egyszeren a kifejezs numerikus rtkt
vizsglja, lehetsg van bizonyos programozsi rvidtsre. A
legnyilvnvalbb, ha
if (kifejezs)
t runk
if (kifejezs != 0) helyett. Ez nha termszetes s vilgos, mskor
viszont nehezen megfejthet.

78

Minthogy az if-else konstrukci else rsze elhagyhat, sokszor


nem egyrtelm, hogy az egymsba skatulyzott if utastsok
melyikhez tartozik else g. A ktrtelmsget a C ms
nyelvekhez hasonlan azzal oldja fel, hogy az else a hozz
legkzelebbi else nlkli if-hez kapcsoldik. Pldul az
if (n > 0) if (a > b)
z = a;
else
z = b; esetben az else a bels if
sorbetolssal szemlltettk. Ha nem
rhetjk el a helyes sszerendelst:

hez tartozik,
ezt akarjuk,

amint azt a
zrjelekkel

if (n > 0) {
if (a > b)
z = a;
}
else
z = b;
A ktrtelmsg klnsen veszlyes az olyan esetekben, mint:
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
kln fejtegetst.
Tbbszrs
valstunk

olyan

gyakran fordul el,

elgazst
(dntst)
meg. A gp sorban

ltalban
kirtkeli

hogy megr nmi

ilyen
if-sorozattal
a kifejezseket. Ha

79

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
hibaellenrzsre hasznlhat.

tiltott

felttel

figyelsvel

Kvetkez pldnkban egy hromutas dntst lthat az olvas. Olyan


binris keres fggvnyt mutatunk be, amely egy rendezett v tmbben
egy bizonyos x rtket keres. v elemeinek nvekv sorrendben kell
kvetnik egymst. Ha x elfordul v-ben, akkor a fggvny x v-beli (0
s n-1 kztti) sorszmt szolgltatja, ellenkez esetben rtke -1
lesz:
binary (x, v, n)

/*x keresse v[0] . . .

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


{
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high) {
mid = (low + high) / 2;
if (x < v[mid])
high = mid - 1; else if (x > v[mid])
low = mid + 1;
else
/ *Megtallta*/
return (mid);
}
return (-1);
}
Minden lpsben meg kell vizsglni, hogy x kisebb, mint a v[mid]
kzps elem, nagyobb nla vagy egyenl vele, ami egszen termszetes
mdon rhat le else-if szerkezettel.
3.4. A switch utasts
A switch utasts a tbbirny programelgaztats egyik eszkze.
Megvizsglja, hogy valamely kifejezs rtke megegyezik-e tbb
lland rtk valamelyikvel, s ennek megfelel ugrst hajt
vgre. Az 1. fejezetben olyan programot lttunk, amellyel az egyes
szmjegyek, res s egyb karakterek elfordulsait szmlltuk
meg. Ugyanazt a programot most az if ... else if... ...else
szerkezet helyett a switch utastssal rtuk meg:
main ()

/*Szmjegyek,
szmllsa*/

res

egyb

karakterek

{
int c, i, nwhite, nother, ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; i++)
ndigit [i] = 0;

80

while ((c = getchar()) != EOF)


switch {
case 0: case 1: case 2: case 3: case 4: case 5: case
6: case 7: case 8: case 9: ndigit [c - 0] ++; break;
case : case \n: case \t: nwhite++; break; default : nother+
+; break;
}
printf (szmjegyek=);
for (i = 0; i < 10; i++)
printf (%d, ndigit[i]);
printf (\n res hely = %d, egyb = %d \n,
nwhite, nother);
}
A switch kirtkeli a zrjelek kztti kifejezst (ebben a
programban ez a c karakter), s sszehasonltja az sszes case (eset)
rtkvel. Minden case-t egsz rtkkel, karakterllandval vagy
lland kifejezssel meg kell cimkzni. Ha valamelyik case azonos a
kifejezs rtkvel, a vgrehajts ennl a case-nl kezddik. A
default cimkj case-re akkor kerl a vezrls, ha a tbbi case
egyike sem teljesl. A default elhagyhat : ha nem szerepel s a
case-ek egyike sem teljesl, semmi nem trtnik. A case-ek s a
default tetszleges sorrendben kvethetik egymst. A case utastsok
cmkinek klnbznik kell egymstl.
A break utasts hatsra a vezrls azonnal kilp a switch-bl.
Mivel a case-ek cmkeknt mkdnek, miutn valamelyik case-hez
tartoz programrsz vgrehajtsa befejezdtt, a vezrls a kvetkez
case-re kerl, hacsak explicit mdon nem intzkednk a kilpsrl. A
switch-bl val kilps legkznsgesebb mdja a break s a return.
Ugyancsak break utastssal lehet kilpni a while, for s do
ciklusokbl, errl e fejezet ksbbi rszben lesz sz.
Az egymst kvet case-ekbe val belps nem egyrtelmen elnys. A
dolog pozitv oldala, hogy mint pldnkban a szkznl, az jsor s a
tab karakternl is lttuk, egyetlen tevkenysg szmra tbb esetet
enged meg. De ebbl az is kvetkezik, hogy ltalban minden case-t
break-nek kell lezrnia, nehogy a vezrls a kvetkez case-re
lpjen. A case-ken trtn lpkeds azrt is veszlyes, mert a
vezrls szteshet, ha a programot mdostjuk. Azokat az eseteket
kivve, amikor ugyanahhoz a szmtshoz tbb cmke tartozik, a caseek kztti tmenetek hasznlatval clszer takarkoskodni.
A j
klalak rdekben mg akkor is helyezznk el break-et az utols eset
utn (az elz pldnkban a default utn), ha az logikailag
szksgtelennek ltszik. Ha valamikor ksbb a szekvencia vghez
jabb case-t illesztnk, ez a fajta defenzv programozsi taktika fog
megmenteni minket.
3.1.
Gyakorlat.
Irjuk meg azt az expand(s, t) fggvnyt,
amely - mikzben az s karakterlncot a t karakterlncba msolja
- a lthatatlan karaktereket (pl.jsor s a tab) lthat escape
szekvencikk (pl.\n s\t) alaktja t! Hasznljunk switch
utastst!
3.5. A while s a for utasts
Mr tallkoztunk a while s for ciklusokkal. A
while (kifejezs)
utasts
szerkezetben a gp kirtkeli a kifejezst. Ha rtke nem nulla,
akkor vgrehajtja az utastst s ismt kirtkeli a kifejezst. Ez

81

a ciklus mindaddig folytatdik, amg a kifejezs 0 nem lesz, amikor


is az utasts utn a vgrehajts vgetr.
A
for (kif1; kif2; kif3)
utasts
alak for utasts egyenrtk a
kif1;
while (kif2) {
utasts
kif3;
}
alakkal. Nyelvtanilag a for mindhrom sszetevje kifejezs.
Tbbnyire kif1 s kif3 rtkads vagy fggvnyhvs, kif2 pedig
relcis kifejezs. A hrom kifejezs brmelyike elhagyhat, de
a pontosvesszknek meg kell maradniuk. Ha kif1 vagy kif3 marad
el, akkor a

egyszeren elmarad a kifejtsbl. Ha a kif2

vizsglat nem szerepel, akkor llandan igaznak tekintjk, gy


for( ;;) {
. . .
}
vgtelen ciklus, amelybl valsznleg ms mdon kell kiugrani (pl.
return vagy break rvn).
A

while

s a for kztt lnyegben zlsnk szerint

vlaszthatunk. Pldul a
while ((c = getchar()) == || c == \n || c == \t)
;
/*tugorja a lthatatlan karaktereket*/
programrszben nincs inicializls, sem jrainicializls,
while hasznlata a lehet legtermszetesebbnek tnik.

gy

A for nyilvnvalan elnysebb olyankor, amikor egyszer


inicializls s jrainicializls fordul el, mivel a ciklust
vezrl utastsok egyms kzelben, a ciklus tetejn jelennek
meg. Ez a legszembetnbb a
for (i = 0; i < N; i++) esetben, amely egy tmb els N eleme
feldolgozsnak C nyelv megfogalmazsa, a FORTRAN s PL/1 DO
ciklusnak megfelelje. Az analgia azonban nem teljes, mivel a for
hatrai a cikluson bellrl vltoztathatk, s az i vezrlvltoz
megtartja rtkt, amikor valamilyen oknl fogva a ciklus vgetr.
Minthogy a for sszetevi tetszleges kifejezsek, a for ciklus 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. )

82

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)
n;
int
for
for
for

{
gap,
(gap
(i =
(j =

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

i , j, temp;
= n / 2; gap > 0; gap /= 2)
gap; i < n; i++)
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

83

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:
reverse (s)
[];

/*Az s karakterlnc helyben megfordtsa*/ char s

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

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

{
int i, sign;
if ((sign = n) < 0) /*eljelvizsglat s trols*/
n = -n;
/*n pozitv legyen*/
i = 0;
do {
/*szmjegyek generlsa fordtott
sorrendben */

84

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

/*Sorvgi szkzk s tabok eltvoltsa*/

{
int n;
char line [MAXLINE];
while ((n = getline (line,MAXLINE)) > 0) { while (--n >= 0)
if (line [n] != && line [n] != \t
&& line [n] != \n)
break;
line [n + 1] = \0;
printf_(%s \n, line);
}
}
A getline a sor hosszt adja vissza. A bels while ciklus a line
utols
karaktern
kezddik
(ne
felejtsk
el,
hogyn
elbb

85

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.)
Pldul a kvetkez programrsz az a tmbnek csak
elemeit dolgozza fel; a negatv rtkeket tugorja:

pozitv

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 goto-knak 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

86

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)
/*i-1, j-1-nl volt*/
. . .
else
/*Nem tallt*/
. . .
Br nem kvnunk az gyben dogmatikusak lenni, kimondjuk : minl
kevesebbet hasznljuk a goto-t, annl jobb.
_
4.
fejezet: Fggvnyek s programstruktra
A fggvnyek a nagy szmtsi feladatokat kisebbekre bontjk. gy a
programoz pthet arra, amit msok mr megcsinltak, s nem kell
mindent ellrl kezdenie. A jl megrt fggvnyek gyakran elrejtik
a mveletek rszleteit a program azon rszei ell, amelyeknek nem is
kell tudniuk rluk. Ezltal az egsz program vilgosabb vlik, s a
vltoztatsok is knnyebben elvgezhetk.

87

A C nyelvet gy terveztk meg, hogy a fggvnyek hatkonyak s


knnyen hasznlhatk legyenek. A C programok ltalban sok kis mret
fggvnyt
tartalmaznak.
Egy
program
tbb
forrsllomnyra
is
tagoldhat.
Az
llomnyok
kln-kln
is
fordthatk,
s
a
knyvtrakban tallhat, mr korbban lefordtott fggvnyekkel
egytt betlthetk. Ezt a folyamatot most nem trgyaljuk, mivel a
rszletek a helyi opercis rendszertl fggenek.
A legtbb programoz mr ismeri a be- s kivitel cljra szolgl
knyvtri fggvnyeket (getchar, putchar) s a numerikus szmtsok
knyvtri fggvnyeit (sin, cos, sqrt).
Ebben a fejezetben
rszletesebben szlunk arrl, hogyan rhatunk j fggvnyeket.
4.1. Alapfogalmak
Kezdetknt tervezznk s rjunk olyan programot, amely a
bemenetnek minden olyan sort kinyomtatja, amely adott
karakterlncbl ll mintt tartalmaz! (Ez specilis esete az
UNIX grep segdprogramjnak.) Pldul a the minta keresse a
Now is the time
/Ideje, hogy
for all good
minden j
men to come to the aid ember segtsgre siessen
of their party.
embertrsainak./
sorokban a
Now is the time
men to come to the aid
of their party.
kimeneti szveget fogja eredmnyezni. A
knnyen felbonthat hrom klnll rszre:

feladat

alapstruktrja

while (van mg sor) if (a sor tartalmazza a mintt)


nyomtats
Br nyilvn
elhelyezhetjk
az egsz programkdot a f rutinban,
mgis az a jobb megolds, hogy kihasznljuk az elz termszetes
struktrt s minden
rszbl
egy-egy
kln fggvnyt ksztnk.
Hrom kis program knnyebben kezelhet, mint egy nagy, mivel az
egymsra nem tartoz rszletek a fggvnyekbe rejthetk s a nem
kvnatos klcsnhatsok lehetsge minimlis lesz. Mi tbb, az egyes
rszek a ksbbiekben nmagukban is hasznosak lehetnek.
A while (van mg sor) feladatot az 1. fejezetben rt getline
fggvny, a nyomtats feladatt pedig a szabvnyos knyvtrban
rendelkezsnkre ll printf fggvny vgzi el. Eszerint csupn azt a
rutint kell megrnunk, amely eldnti, hogy a sor tartalmazza-e a
krdses mintt. A problma megoldsnak tervt a PL/1-bl lophatjuk
el: az index(s, t) fggvny azt az s karakterlncbeli pozcit vagy
indexet adja vissza, ahol a t karakterlnc kezddik, vagy pedig -1gyel tr vissza, ha s nem tartalmazza t-t. s-beli kezdpozciknt 0t hasznlunk, nem 1-et, mivel a tmbk a C nyelvben a 0 indexszel
kezddnek. Ha a ksbbiekben bonyolultabb minta-sszehasonltsi
feladatot
akarunk
megoldani,
csak
az
index
fggvnyt
kell
kicserlnnk; a programkd tbbi rsze vltozatlan marad.
Ennyi tervezs utn mr gyorsan megrhatjuk a programot. Jl lthat,
hogyan illeszkednek egymshoz az egyes rszek. Ne dolgozzunk a
legltalnosabb esettel: a keresett minta egyelre legyen csupa
betbl ll karakterlnc. Nemsokra sz lesz a karaktertmbk
inicializlsrl, s az 5. fejezetben megmutatjuk, hogyan tehetjk a
mintt olyan paramterr, amelyet a program futsa sorn lltunk be.

88

Pldnk egyben a getline fggvny jabb vltozata is: tanulsgos


lesz, ha sszehasonltjuk az 1. fejezetbeli vltozattal!
#define MAXLINE 1000
main ()

/* Adott mintra illeszked sszes sor megkeresse*/

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

/*Sor beolvassa s-be,

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

/*Visszaadja t s-beli indext;

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

klnfle

rszek

hinyozhatnak;

legrvidebb

{ } ami semmit sem csinl. (Az ilyen semmit sem csinl


gyakran hasznos, ha a programfejleszts sorn le akarjuk
egy ksbb megrand programrsz helyt.) A fggvnynevet
is megelzheti, amennyiben a fggvny nem egsz tpus
tr vissza; errl a kvetkez szakaszban lesz sz.

89

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 sbeli 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

90

kell deklarlni. Ezzel az


sszes eddigi pldnkat is.

esetek

tbbsgt

lefedtk,

belertve

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 eljelet s tizedespontot,
valamint a jelenlev vagy hinyz egsz, ill.
trt rszt. (Ez
azonban nem nevezhet j minsg bemeneti konverzis rutinnak;
ilyen rutin megrsa tbb helyet ignyelne, mint amit most erre a
clra sznunk.)
Elszr is az atof maga kell, hogy deklarlja az ltala
visszaadott rtk tpust,
mivel az nem
int. Tekintve, hogy
kifejezsekben a float double mennyisgg alakul t, nincs rtelme
azt mondanunk, hogy az atof float rtket ad vissza; jl
kihasznlhatjuk a ktszeres pontossgot, s a fggvnyt double
rtkkel visszatrnek deklarljuk. A tpus neve megelzi a
fggvny nevt:
double atof (s) /*Az s karakterlnc talaktsa double-l*/ char s
[];
{
double val, power;
int i, sign;
for (i = 0; s [i] == || s [i] == \n
|| s [i] == \t; i++)
; /* res hely tugrsa*/
sign = 1;
if (s [i] == + || s [i] == -)/*Eljel*/ sign = (s [i++] ==
+) ? 1 : -1; for (val = 0; s [i] >= 0 && s [i] <= 9; i++)
val = 10 * val + s [i] - 0; if (s [i] == .) i++; for (power =
1 ; s [i] >= 0 && s [i] <= 9; i++) { val = 10 * val + s [i] 0; power *= 10;
}
return (sign * val / power);
}
Msodszor is, ugyanilyen fontos, hogy a hv rutinnak kzlnie kell,
hogy az atof nemegsz rtket ad vissza. A deklarcit a kvetkez
primitv kalkultor-program mutatja (a program pphogy elegend pl.
egy csekknyv egyenlegnek kiszmtshoz). A program soronknt egyegy 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));
}

91

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
(karakterlnc konvertlsa int-t):

megrhatjuk

az

atoi

fggvnyt

atoi (s) /*Az s karakterlnc talaktsa


egsz szmm*/ char s [];
{
double atof ();
return (atof (s));
}
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

92

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
vltozargumentumszm 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
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

93

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, a
main azonban nem. Ezt a megoldst egyszeren lefordthatjuk a
programozs nyelvre. A fprogram lnyegben az opertorok s
operandusok tpusra vonatkoz nagy switch-bl ll, ez taln

94

tipikusabb hasznlata a switch utastsnak, mint amit a 3. fejezetben


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

/*f rsa az rtkverembe*/

{
if (sp < MAXVAL)
return (val [sp++] = f);
else {
printf (hiba: a verem megtelt\n);
clear ();
return (0);
}
}
double pop ()

/*A legfels rtk kiemelse a verembl*/

{
if (sp > 0)
return (val [--sp]);
else {
printf (hiba: a verem res\n);
clear ();
return (0);
}
}
clear () /*A verem kirtse*/
{
sp = 0;

95

}
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.

96

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
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 NUMBERrel 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

97

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;
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

98

char buf [BUFSIZE];


/*Az ungetch puffere*/
int bufp = 0;
/*A kvetkez szabad pozci buf-ban*/
getch ()
/*Kiolvas egy (esetleg visszart)
karaktert*/
{
return ((bufp > 0) ? buf [--bufp] : getchar());
}
ungetch /* Karakter visszahelyezse a bemenetre*/ int c;
{
if (bufp > BUFSIZE)
printf(ungetch, tlsok karakter\n);
else
buf [bufp++] = c;
}
A pufferbe trtn visszarsra egyetlen karakter helyett tmbt
hasznltunk, mivel ez az ltalnosts a ksbbiekben mg jl jhet.
4.4. Gyakorlat. rjuk meg az ungets(s) nev rutint, amely egy teljes
karakterlncot r vissza a bemenetre! Szksges, hogy az ungets
fggvnynek tudomsa
legyen
buf-rl
s
bufp-rl, vagy csak
egyszeren hasznlja az ungetch fggvnyt?
4.5. Gyakorlat. Tegyk fel, hogy sohasem helyeznk vissza egynl
tbb karaktert.
Mdostsuk
a getch
s
ungetch fggvnyeket
ennek megfelelen !
4.6. Gyakorlat. getch s ungetch rutinjainak a visszahelyezett EOFot gpfgg mdon kezelik. Hatrozzuk meg, hogyan viselkedjenek
rutinjaink, amikor EOF-ot runk vissza, majd valstsuk meg ezt a
megoldst!
4.6. Statikus vltozk
A mr korbban megismert extern s automatikus vltozk mellett a
statikus (static) vltozk jelentik a harmadik trolsi osztlyt.
A static vltozk akr belsk, akr klsk lehetnek. A bels
static vltozk ugyangy loklisak valamely fggvnyre nzve, mint
az automatikus vltozk, de az automatikusaktl eltren llandan
fennmaradnak s nem jnnek ltre, ill. sznnek meg a fggvny
minden egyes aktivizlsa alkalmval. Eszerint a bels static
vltozk a fggvnyen bell sajt, lland trat kpeznek. A
fggvnyeken bell megjelen karakterlncok, mint pl. a printf
argumentumai, bels static vltozk.
A kls static vltoz annak a forrsllomnynak a tovbbi
rszben lesz ismert, amelyben deklarltk, de rvnyessgi
tartomnya nem terjed ki egyetlen ms llomnyra sem. A kls
static vltozk segtsgvel lehetsgnk van arra, hogy az olyan
neveket mint buf s bufp elrejtsk a getch-ungetch kombinciban.
A vltozknak klsknek kell lennik ahhoz, hogy megoszthatk
legyenek,
ugyanakkor
rejtve
kell
maradniuk
a
fggvnyek
felhasznli ell, mivel gy kizrjuk a konfliktus lehetsgt. Ha
a kt rutint s a kt vltozt egyetlen llomnyba szerkesztjk:
static char buf [BUFSIZE];
/*Az ungetch puffere*/
static int bufp = 0
/*A kvetkez szabad pozci
buf-ban*/
getch () { . . . }
ungetch { . . . }
akkor egyetlen ms rutin sem frhet hozz a buf s bufp vltozkhoz;
de nem kerlhetnek sszetkzsbe a vltozk az ugyanezen program ms
llomnyaiban elfordul ugyanilyen nevekkel sem.

99

A statikus trolst, legyen az akr bels, akr kls, gy


definiljuk, hogy a kznsges deklarci el a static szt rjuk. A
vltoz kls, ha az sszes fggvnyen kvl, ill.
bels, ha
valamelyik fggvnyen bell definiljk.
A fggvnyek ltalban kls objektumok, a nevk globlisan ismert.
Ugyanakkor a fggvnyek static tpusnak is deklarlhatk, az ilyen
fggvnyek neve ismeretlen lesz azon az llomnyon kvl, ahol
deklarltk.
A C nyelvben a static deklarci nem csupn llandsgot rejt
magban, hanem bizonyos mrtk elzrtsgot is. A bels static
objektumok csupn az adott fggvnyen bell ismertek; a kls static
objektumok
(vltozk
vagy
fggvnyek)
pedig
csak
abbl
a
forrsllomnybl hozzfrhetk, amelyben megjelennek, s neveik nem
kerlnek sszetkzsbe a ms llomnyokban elfordul ugyanilyen
nev vltozkkal, ill. fggvnyekkel.
Kls static vltozk s fggvnyek segtsgvel elrejthetjk az
adatobjektumokat s a velk dolgoz bels rutinokat, gy ms rutinok
s adatok ezekkel mg vletlenl sem kerlhetnek sszetkzsbe.
A getch s az ungetch fggvny pl. karakterbeolvas_ s -visszar
modult alkot; buf s bufp pedig static kell, hogy legyen ahhoz, hogy
kvlrl ne legyen elrhet. Hasonlkppen push, pop s clear egy
veremkezel modult alkot; val-nak s sp-nek ugyancsak kls staticnak kell lennie.
4.7. Regisztervltozk
A negyedik s egyben utols trolsi osztly neve register. A
register deklarci kzli a fordtprogrammal, hogy a krdses
vltozra
nagyon
gyakran
trtnik
hivatkozs.
Amennyiben
lehetsges, a register tpus vltozk a gp regisztereibe
kerlnek, miltal rvidebb s gyorsabb programokjnnek ltre. A
register deklarci alakja:
register int x; register char c;
s gy tovbb; az int rsz elhagyhat. A register deklarci csupn
automatikus vltozkra, valamint fggvnyek formlis paramtereire
alkalmazhat. Utbbi esetben a deklarci alakja:
f (c, n) register int c, n;
{
register int i;
. . .
}
A gyakorlatban a regisztervltozkra nzve olyan megszortsok llnak
fenn, amelyek az adott hardver tulajdonsgait tkrzik. Az egyes
fggvnyeknek csupn nhny vltozja trolhat regiszterekben s
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

100

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
vonatkozik.

bell

formlis

nem

kls

paramterre

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 = \;
/*Aposztrf*/
long day = 60 * 24;
/*Percek szma a napban*/
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

101

megengedett. A 3. fejezetben emltett binris keresprogram kezdeti


rtk belltsai pl. a kvetkez mdon rhatk :
binary (x, v, n)
int x, v [], n;
{
int low = 0;
int high = n-1;
int mid;
. . .
}
a mr ltott:
binary (x, v, n) int x, v [], n;
{
int low, high, mid;
low = 0;
high = n - 1;
. . .
}
alak helyett.
Az automatikus vltozk inicializlsai valjban rtkad utastsok
rvidtett formi. Lnyegben csupn zls krdse, hogy valaki
melyik alakot
rszesti
elnyben.
ltalban
explicit
rtkadsokat
hasznltunk,
mivel
a
deklarcikban
elfordul
inicializlsok nehezebben kvethetk.
Automatikus tmbk nem inicializlhatk. Kls s statikus
tmbk gy inicializlhatk, hogy a deklarcit a kezdeti
rtkek kapcsos zrjelek kz zrt s vesszkkel elvlasztott
listja kveti. Az 1. fejezetben ismertetett karakterszmll
program, amelynek kezdete
main ()

/*Szmjegyek, res kzk s egyebek szmllsa*/

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

/*Szmjegyek, res kzk s egyebek szmllsa*/

{
int c, i;
. . .
}
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

102

rtk megadsa hibt jelent. Sajnos nincs lehetsg valamely kezdeti


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

/*n nyomtatsa decimlis alakban*/ int n;

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

/*Veszi a kvetkez
/*Elhagyja*/

A msik lehetsg a rekurzv megolds, amelyben printd


hvsakor elszr sajt magt hvja meg - feldolgozza az
vezet szmjegyet, majd kinyomtatja az utols szmjegyet.
printd (n)

minden
sszes

/*n nyomtatsa decimlis alakban


(rekurzv)*/

int n;
{
int i;
if (n < 0) {
putchar (-);
n = -n;
}

103

if ((i = n / 10) != 0)
printd (i);
putchar (n % 10 + 0);
}
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

104

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
fordt dolgozza

fel

a defincikra csak nagyon kevs

nyelvtani megkts vonatkozik. Az ALGOL hvei pl. a


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

105

A makroprocesszor tovbbi szolgltatsait az A fggelk ismerteti.


4.9. Gyakorlat. Definiljuk a swap(x, y) makrt, amely megcserli a
kt int tpus argumentumt! (A blokkstruktra segtsgnkre
lesz.)
_
5.

fejezet: Mutatk s tmbk

A mutat (pointer) olyan vltoz, amely egy msik vltoz cmt


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

mint

eddig.

px

mutat

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,

106

_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)
Mutathivatkozsok rtkadsok bal oldaln is elfordulhatnak.
Ha px s x-re mutat, akkor
*px = 0
az x-et kinullzza s
*px += 1
vagy
(*px)++ inkrementlja. Az utbbi pldban a zrjelek szksgesek:
nlklk a kifejezs px-_t inkrementln, nem pedig azt, amire px
mutat, mivel az egyoperandus opertorok, esetnkben * s ++ jobbrl
balra rtkeldnek ki.
Vgl, mivel a mutatk vltozk, ugyangy kezelhetk, mint a
tbbi vltoz. Ha py egy msik, int tpus mennyisgre mutat,
akkor
py = px a px tartalmt py-ba msolja, miltal py ugyanarra fog
mutatni, mint px.
5.2. Mutatk s fggvnyargumentumok
Mivel a C nyelv az argumentumokat rtk szerinti hvs
formjban adja t a fggvnyeknek, a hvott fggvny semmilyen
kzvetlen mdon nem tudja megvltoztatni a hv fggvny

107

vltozit. Mit tegynk, ha tnyleg meg kell vltoztatnunk


valamelyik kznsges argumentumot? Pldnak okrt a
rendezrutin megcserlhet kt, rossz sorrendben lev elemet a
swap nev fggvny segtsgvel. Nem elg, ha azt rjuk, hogy
swap (a, b); ahol a swap fggvny defincija:
swap (x, y)
int x, y;
{
int temp;
temp = x;
x = y;
y = temp;
}

/*ROSSZ*/

Az rtk szerint trtn hvs miatt a swap nem kpes az t meghv


rutinban elfordul a s b argumentumokat megvltoztatni.
Szerencsre van lehetsg a kvnt hats elrsre. A hv rutin a
megvltoztatand rtkeket megcmz mutatkat ad t:
swap (&a, &b);
Mivel az & opertor a vltoz cmt lltja el, &a az a vltozt
megcmz mutat lesz.
Magban
a swap rutinban
az argumentumokat
mutatkknt
deklarljuk,
s
az
aktulis
operandusokat
ezeken
keresztl rjk el:
swap (px, py)

/*px s py megcserlse*/ int *px, *py;

{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
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 klnkln
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:

108

int n, v, array [SIZE]; for (n = 0; n < SIZE && getint (&v) !=


EOF; n++) array [n] = v;
Minden egyes hvs berja a v vltozba a bemeneten tallt kvetkez
egsz szmot. Vegyk szre, hogy a getint argumentumaknt &y-t kell
rnunk v helyett. Ha a puszta v-t hasznljuk, akkor valsznleg
cmzsi hibt kvetnk el, mivel getint azt hiszi, hogy rvnyes
mutatt kapott.
Maga a getint a mr korbban megrt atoi termszetes mdostsa:
getint (pn) /*A kvetkez egsz beolvassa a
bemenetrl*/
int *pn;
{
int c, sign; while ((c = getch ()) == || c == \n || c ==
\t)
; /*Az res kzt tugorja*/
sign = 1;
if (c == + || c == -) {/*Feljegyzi az eljelet*/ sign = (c ==
+) ? 1 : -1; c = getch ();
}
for (*pn = 0; c >= 0 && c <= 9; c = getch ())
*pn = 10 * *pn + c - 0;
*pn *= sign; if (c != EOF) ungetch ; return ;
}
A getint fggvnyben a *pn vgig kznsges int tipus vltozknt
szerepel. Felhasznltuk a geth s ungeth fggvnyeket is (lersukat
l. a 4. fejezetben), gy azt az egy plusz karaktert, amit mg ki kell
olvasni, vissza lehet helyezni a bemenetre.
5.1. Gyakorlat. rjuk meg a getfloat fggvnyt, amely a getint
lebegpontos megfelelje! Milyen tipust ad vissza getfloat
fggvnyrtkknt?
5.3. Mutatk s tmbk
A C nyelvben szoros kapcsolat van a mutatk s a tmbk kztt. Ez
indokolja,
hogy
a
mutatkkal
s
a
tmbkkel
egyidejleg
foglalkozzunk.
Valamennyi
mvelet,
amely
tmbindexelssel
vgrehajthat, mutatk hasznlatval ppgy elvgezhet. ltalban
az utbbi vltozat gyorsabb, de klnsen a kezdk szmra els
rnzsre nehezebben rthet.
Az
int a [10]
deklarci definilja azt a tmbt, amelynek mrete 10, vagyis
egy tz, egymst kvet objektumbl, az a[0], a[1], . . ., a[9]
nev elemekbl ll blokkot hatroz meg. Az a[i] jellsmd a
tmbnek a kezdettl szmtott i-edik pozcijt fejezi ki. Ha pa
egszt megcmz mutat, amelyet
int *pa
deklarl, akkor a
pa =&a[0]
rtkads gy lltja be pa-t, hogy az az a nulladik elemre

109

mutasson, vagyis pa az a[0] elem cmt tartalmazza. Ekkor az


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

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

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

110

}
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 i-edik
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

111

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

/*Kv. szabad hely*/

/*n karaktert megcmz mutatt ad vissza*/

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

/*Befr*/ allocp += n;

return (allocp - n);


/*Rgi p*/
} else /*Nincs elg hely*/
return (NULL);
}
free (p) /*p ltal megcmzett terlet felszabadtsa*/ char *p;
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE) allocp = p;
}
Nhny megjegyzs: ltalban a mutat ppen gy
inicializlhat, mint brmilyen

ms vltoz,

noha kznsges

esetben rtelmes rtk csupn a NULL (l. a tovbbiakban) vagy

112

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 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:

113

strlen (s)

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

{
char *p = s;
while (*p != \0)
p++;
return (p - s);
}
A deklarciban p kezdeti rtkeknt s-et adtuk meg, vagyis p
kezdetben az s els karakterre mutat. A while ciklusban addig
vizsgljuk az egymst kvet karaktereket, amg a vget jelz \0 el
nem kerl. Mivel \0 rtke nulla, s mivel a while csupn azt
vizsglja, hogy a kifejezs nulla-e, elhagyhat az explicit
vizsglat. Az ilyen ciklusokat gyakran az albbi alakban rjk:
while (*p) p++;
Minthogy p karakterekre mutat, p++ minden alkalommal a kvetkez
karakterre lpteti p-t, s p - s
az tlpett karakterek szmt,
vagyis
a
karakterlnc
hosszt
adja
meg.
A
mutataritmetika
kvetkezetes: ha float mennyisgekkel dolgoznnk, amelyek a charoknl 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 free-ben
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

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
tnyleges
karaktereket
megcmz mutatt rendel hozz.
Ez
karakterlnc-msols, a dolog csak a mutatkat rinti.

a
nem

A C nyelvben nincsen olyan opertor, amellyel teljes karakterlncot


egy egysgknt dolgozhatnnk fel.
A mutatk s tmbk tovbbi
vonatkozsait a 7. fejezetben ismertetend
szabvnyos
bes
kiviteli (I/O) knyvtr kt hasznos fggvnyn keresztl mutatjuk be.
Az els fggvny az strcpy(s, t), amely a t karakterlncot az

114

s karakterlncba msolja. Az argumentumokat az rtkadshoz val


hasonlsg miatt rtuk ebben a sorrendben, hiszen a t
karakterlncnak az s karakterlnchoz trtn hozzrendelsekor
azt mondannk, hogy
s = t
Elszr a tmbs vltozatot mutatjuk be:
strcpy (s, t) /*t msolsa s-be*/
char s [], t [];
{
int i;
i = 0;
while ((s [i] =t [i]) != \0)
i++;
}
sszehasonltsul me az strcpy mutatval rt vltozata:
strcpy (s, t)

/*t msolsa s-be;

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


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

/*t msolsa s-be;

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


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

/*t msolsa s-be;

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


{
while (*s++ = *t++)

115

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

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


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

char s [], t [];


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

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


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

char *s, *t;


{
for (; *s == *t; s++,t++)
if (*s == \0)
return (0); return (*s - *t);
}
Mivel ++ s
-- akr prefix, akr postfix opertorok lehetnek,
ritkbban
ugyan,
de
a
*
s
++,
ill.ms
kombincii
is
elfordulhatnak. Pl.
*++p p-t mg azeltt inkrementlja, hogy
karakterhez val hozzfrs megtrtnne.

ltal

megcmzett

*--p elszr dekrementlja p-t.


5.2. Gyakorlat. rjuk t a 2. fejezetben bemutatott strcat fggvnyt
mutat alkalmazsval (strcat(s, t) a t karakterlncot az s
karakterlnc vgre msolja)!
5.3. Gyakorlat. rjunk makrt strcpy-ra!
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

116

ez oda vezetett, hogy sokan szabadosan kezeltk a mutatkat


visszaad rutinokat, s a kapott mutatkat egyszeren ms
rutinoknak
adtk
t
gyakran
elmulasztva
a
szksges
mutatdeklarcikat. Tekintsk pl. az strsave(s) fggvnyt, amely
az
alloc
hvsval
kapott
biztos
helyre
msolja
az
s
karakterlncot, majd az azt megcmz mutatval tr vissza. E
program helyesen gy fest :
char *strsave (s)

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

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

/*Elmenti az s karakterlncot*/

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

117

};
day_of_year (year, month, day)
/*Az ven belli
napsorszm kiszmtsa
a hnapbl s napbl*/
int year, month, day;
{
int i, leap;
leap = year % 4 == 0 && year % 100 != 0
|| year % 400 == 0; for (i = 1; i < month; i++) day += day_tab
[leap][i]; return (day);
}
month_day (year, yerday, pmonth, pday)
/*Hnap s nap
kiszmtsa az*/
int year, yearday, *pmonth, *pday; /*v adott sorszm
napjbl*/
{
int i, leap;
leap = year % 4 == 0 && year % 100 != 0
|| year % 400 == 0; for (i = 1; yearday > day_tab [leap][i]; i++)
yearday -= day_tab [leap][i];
*pmonth = i;
*pday = yearday;
}
A day_tab tmbnek kvl kell lennie mind a day_of_year, mind pedig
a month_day fggvnyen, hogy mindketten hasznlhassk. A day_tab az
els
ktdimenzis tmb, amellyel eddig tallkoztunk. A C-ben
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

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

118

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

119

megbrkzni, valamifle nemltez sor-darabszmot, pl.


-1-et ad
vissza, ha tl sok szveg rkezett. A kimeneti rutinnak abban a
sorrendben kell kinyomtatnia a sorokat, amelyben azok a mutatk
tmbjben megjelennek.
#define NULL 0
#define LINES 100 /*A rendezend sorok max. szma*/
main ()
/*Beolvasott sorok rendezse*/
{
char * lineptr [LINES];
/*A szvegsorokatmegcmz
mutatk*/ int nlines; /*A beolvasott sorok szma*/ if ((nlines =
readlines (lineptr, LINES)) >= 0) { sort (lineptr, nlines);
writelines (lineptr, nlines);
}
else printf (a bemenet tl nagy a rendezshez \n);
}
#define MAXLEN 1000
readlines (lineptr, maxlines) /*Sorok beolvassa*/
char *lineptr []; /*Rendezshez*/
int maxlines;
{
int len, nlines;
char *p, *alloc (), line [MAXLEN];
nlines = 0;
while ((len = getline (line, MAXLEN)) > 0) if (nlines >= maxlines)
return (-1); else if ((p = alloc (len)) == NULL)
return(-1);
else {
line [len - 1] = \0;
lineptr [nlines++] = p;

/*Az jsort levgja*/ strcpy (p, line);

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

trldnek,

gy

nem

/*A kimenetre kerl

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


{
int i;
for (i = 0; i < nlines; i++)
printf (%s \n, lineptr [i]);
}
A legfontosabb j dolog lineptr deklarcija:
char *lineptr [LINES]; azt jelenti, hogy a lineptr egy LINES szm
elembl ll, mutatkat tartalmaz tmb, amelynek minden eleme egyegy char-ra mutat. Ms szval lineptr [i] karaktermutat, s *lineptr
[i] egy karakterhez fr hozz.

120

Mivel lineptr tmb, amelyet writelines-nak adunk t, pontosan


ugyangy kezelhetjk mutatknt, mint azt a korbbi pldkban lttuk.
A fggvny teht gy is rhat:
writelines (lineptr, nlines)

/*A kimenetre kerl

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


{
while (--nlines >= 0)
printf (%s \n, *lineptr++);
}
A *lineptr kezdetben az els sorra mutat; minden inkrementls a
kvetkez sorra lpteti, mikzben nlines-t leszmlljuk. Most, hogy
a be- s kimenet a keznkben van, rtrhetnk a rendezsre. A 3.
fejezetben ltott Shell rendezprogramot kismrtkben meg kell
vltoztatnunk: mdostani kell a deklarcikat, s az sszehasonlts
mvelett kln fggvnyben kell elhelyezni. Az alapvet algoritmus
vltozatlan, ezrt bzhatunk abban, hogy a program tovbbra is
mkdni fog.
sort (v, n) /*A v [0] ... v [n - 1] karakterlncok
rendezse nvekv sorrendben*/
char *v [];
int n;
{
int gap, i, j;
char *temp;
for (gap = n/2; gap > 0; gap /= 2)
for (i = gap; i < n; i++)
for (j = i - gap; j >= 0; j -= gap) { if (strcmp (v [j], v [j +
gap]) <=0)
break; temp = v [j]; v [j] = v [j + gap]; v [j + gap] = temp;
}
}
Mivel v (azaz lineptr) minden egyes eleme karaktermutat, temp-nek
is annak kell lennie, hogy az egyik a msikba msolhat legyen.
A programot a lehet legegyszerbbre rtuk meg, hogy minl gyorsabban
el tudjuk indtani. Lehetne azonban gyorsabb is, ha pl. a bejv
sorokat kzvetlenl a readlines ltal karbantartott tmbbe msolnnk,
nem pedig elszr a line-ba, majd az alloc ltal kezelt, rejtett
helyre. Az els vltozatot azonban blcsebb gy megrni, hogy minl
rthetbb legyen. A hatkonysggal rrnk ksbb foglalkozni.
Programunkon valsznleg nem sokat gyorstana, ha kikszblnnk a
bemeneti sorok szksgtelen tmsolst. Lnyeges javulst csak az
hozhat, ha a Shell sort programjt valami jobbal, pl. a quicksort
programmal cserljk fel.
Az 1. fejezetben rmutattunk, hogy mivel a while s a for ciklusok a
vgfelttelt
a
ciklustrzs els vgrehajtsa eltt vizsgljk,
hozzjrulnak ahhoz, hogy a programok a lehet leggyorsabban
mkdjenek, klnsen, ha nincs bemenet. Tanulsgos, ha vgigmegynk
a rendezprogram fggvnyein, s megvizsgljuk, mi trtnik, ha
egyltaln nincs bemeneti szveg.
5.5. Gyakorlat. rjuk jra a readlines fggvnyt oly mdon, hogy a
sorokat a main ltal adott tmbben hozzuk ltre s nem az alloc-ot
hvjuk a tr karbantartsa cljbl! Mennyivel gyorsabb gy a
program?

121

5.9.
Mutattmbk inicializlsa
rjuk meg a month_name(n) fggvnyt, amely egy olyan mutatt ad
vissza, amely az n-edik hnap nevt tartalmaz karakterlncra
mutat. Ez a bels static tmb idelis alkalmazsa. A month_name
a karakterlncok szmra kln tmbt tartalmaz, s hvs utn a
megfelel karakterlncot megcmz mutatt adja vissza. E szakasz
tmja az, hogy hogyan kell a nevek tmbjt inicializlni.
A szintaxis hasonlt a korbbi inicializlsokra:
char *month_name (n) /*Visszaadja az n-edik hnap nevt*/ int n;
{
static char *name [] = {
nem ltez hnap,
janur,
februr,
mrcius,
prilis,
mjus,
jnius,
jlius,
augusztus,
szeptember,
oktber,
november,
december
}
return ((n < 1 || n > 12) ? name [0] : name [n]);
}
A name karaktermutatkbl ll tmb. Deklarcija ugyanaz, mint
lineptr- a rendezsi pldban. A kezdeti rtk egyszeren a
karakterlncok listja; mindegyik hozz van rendelve a tmb megfelel
pozcijhoz. Pontosabban szlva az i-edik karakterlnc karakterei
valamilyen ms helyre kerlnek, s az ket megcmz mutat name [i]ben tallhat. Mivel a tmb mrete nincs megadva, maga a fordt
szmllja meg a kezdeti rtkeket s tlti be a helyes darabszmot.
5.10.
Mutatk s tbbdimenzis tmbk
A kezd C programozkat gyakran megzavarja a ktdimenzis
tmbk s az olyan mutattmbk kztti klnbsg, mint amilyen
a fenti pldban name volt. Pl. az
int a [10][10]; int *b [10];
deklarcikban a s b hasznlata ugyan hasonl, amennyiben a[5] [5]
s b[5]
[5] egyarnt egy bizonyos int-re trtn megengedett
hivatkozsok. a azonban igazi tmb : 100 trrekeszt foglaltunk le
szmra, egy adott elemt a hagyomnyos mtrixszer indexszmtssal
vlaszthatjuk ki. b esetben azonban a deklarci csupn 10 mutatt
foglal le: ezek mindegyikt gy kell belltani, hogy egy-egy
egszekbl ll tmbre mutasson. Feltve, hogy mindegyikk egy-egy
tzelem tmbre mutat, 100 trrekeszt foglaltunk le, ezenkvl
tovbbi tz rekeszre van szksg a mutatk szmra. gy a mutatkbl
ll
tmb
valamivel
tbb
terletet
foglal
el,
s
explicit
inicializlst ignyelhet. Van azonban kt elnye: egyrszt az
elemeket nem szorzssal s sszeadssal, hanem mutatn keresztl,
indirekt mdon rjk el, msrszt a tmb sorai klnbz hosszsgak
lehetnek. gy nem szksges, hogy b minden eleme egy-egy tzelem

122

vektorra mutasson: lehet kztk amelyik kt elemre, esetleg hszra,


st amelyik egyetlen elemre sem mutat.
Br az elbbi fejtegetsben egszekrl beszltnk, a mutattmbk
hasznlatnak messze leggyakoribb esete az, amelyet a month_name-ben
mutattunk be: klnbz hosszsg karakterlncok kezelse.
5.6. Gyakorlat. rjuk t a day_of_year s a month_day rutint oly
mdon, hogy indexels helyett mutatkat hasznljunk!
5.11.
Parancssor-argumentumok
A C nyelvet tmogat krnyezetekben lehetsg van arra, hogy a
vgrehajts megkezdsekor a programnak parancssor-argumentumokat
vagy paramtereket adjunk t. Amikor a vgrehajts megkezdsekor
main-t meghvjuk, a hvsban kt argumentum szerepel. Az els
(amit szoks szerint argc-nek neveznk) azoknak a parancssorargumentumoknak a darabszma, amelyekkel a programot meghvtuk.
A msodik argumentum (argv) egy mutat: ez arra a karakterlnctmbre mutat, amely az elbbi argumentumokat tartalmazza. Egy
karakterlnc egy argumentumnak felel meg. E karakterlncok
kezelse a tbbszrs mlysg mutathasznlat tipikus esete.
A tbbszint mutathasznlathoz szksges deklarciknak, a
mdszer alkalmazsnak legegyszerbb szemlltet pldja az echo
program, amely egyszeren megismtli (visszhangozza) az egy
sorban megjelen, szkzkkel elvlasztott
parancssor-argumentumokat. Vagyis, ha kiadjuk az
echo Figyelem, emberek
parancsot, akkor a kimeneten
Figyelem, emberek jelenik meg.
Megllapods szerint argv [0] az a nv, amellyel a programot hvtk,
gy argc legalbb 1 . Az elbbi pldban argc 3 s argv[0], argv [1],
ill. argv [2] sorra echo, Figyelem s emberek. Az els igazi
argumentum argv [1] s az utols argv[n-1]. Ha argc rtke 1, akkor
a program nevt nem kvetik parancssor-argumentumok. Mindezt az echo
programban mutatjuk be:
main (argc, argv)

/*Visszhangozza az argumentumokat

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


{
int i;
for (i = 1; i < argc; i++)
printf (%s %c, argv [i], (i < argc-1) ? : \n);
}
Mivel
argv
mutattmbt
megcmz
mutat,
tbbflekppen
is
megrhatjuk ezt a programot gy, hogy a tmb indexelse helyett a
mutatt kezeljk. Lssunk kt vltozatot :
main (argc, argv) /*Visszhangozza az argumentumokat ;
2. vltozat*/ int argc; char *argv [];
{
while (--argc > 0) printf (%s %c, *++argv,(argc > 1) ? :
\n);
}
Mivel argv az argumentum-karakterlncok tmbjnek kezdett megcmz
mutat, 1-gyel trtn inkrementlsnak (++argv) hatsra argv[0]

123

helyett az eredeti argv[1]-re


inkrementlsok hatsra mindig a
az illet argumentumot megcmz
dekrementldik: amikor nullv
argumentum.

fog mutatni. Az egymst kvet


kvetkez argumentumra lp; *argv
mutat.
Ezzel egyidejleg argc
vlik, nincs tbb kinyomtatand

Egy msik vltozat :


main (argc, argv)

/*Visszhangozza az argumentumokat

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


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

/*Megkeresi az 1. argumentum

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


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

124

2: for all good men kimenetet fogja eredmnyezni.


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

/*Megkeresi az 1. argumentum

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


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

125

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 sortnak. A sort viszont a mutatkon keresztl hvja a fggvnyeket. Az
argumentumokkal kapcsolatos hibafeldolgozst elhanyagoltuk, hogy a
f feladatokkal foglalkozhassunk.
#define LINES 100 /*A rendezend sorok
maximlis szma*/
main (argc, argv) /*Beolvasott sorok rendezse*/
int argc;
char *argv [];
{
char *lineptr [LINES];
/*Mutatk a szvegsorokra*/
int nlines;
/*A beolvasott sorok szma*/
int strcmp (), numcmp (); /*sszehasonlt
fggvnyek*/
int swap (); /*Felcserl fggvny*/
int numeric = 0;
/*1, ha a rendezs numerikus*/
if (argc > 1 && argv [1][0] == - && argv [1][1] == n) numeric
= 1; if ((nlines = readlines (lineptr, LINES)) >= 0) { if
(numeric)
sort(lineptr, nlines, numcmp, swap);

126

else
sort (nlineptr,
nlines);

lines,

strcmp,

swap);

writelines

(lineptr,

} else printf (a bemenet tl nagy a rendezshez \n);


}
Az strcmp, numcmp s swap - fggvnyek cmei; mivel ezek bizonyosan
fggvnyek, az & opertor ugyangy nem szksges, mint ahogy nincs r
szksg a tmbk neve eltt sem. A fordt gondoskodik a fggvny
cmnek tadsrl.
Msodik lpsben a sort-ot mdostjuk:
sort (v, n, comp, exch) /*A v[0] ... v[n-1] karakterlncok
rendezse nvekv sorrendbe*/
char *v [];
int n;
int (*comp) () , (*exch) ();
{
int gap, i, j;
for (gap = n / 2; gap > 0; gap /= 2)
for (i = gap; i < n; i++)
for (j = i - gap; j >= 0; j -= gap) { if ((*comp) (v [j], v [j +
gap]) <= 0)
break;
(*exch) (&v [j], &v [j + gap]);
}
}
Vizsgljuk meg a deklarcikat!
int (*comp) ()
azt fejezi ki, hogy a comp olyan fggvnyt megcmz mutat,
amely int-et ad vissza. Az els zrjelpr szksges, nlklk
int *comp ()
azt fejezn ki, hogy a comp olyan fggvny, amely int-et
megcmz mutatt ad vissza, ami egszen ms dolog. comp
hasznlata az
if ((*comp) (v [j],v [j + gap]) <= 0)
sorban sszhangban van a deklarcival: comp a fggvnyt
megcmz mutat, *comp a fggvny, s
(*comp) (v [j], v [j + gap]) annak hvsa. Ahhoz. hogy az sszetevk
helyesen kapcsoldjanak, szksg van a zrjelekre.
Korbban mr lttuk strcmp-t, amely kt karakterlncot hasonlt
ssze. me numcmp amely vezet numerikus rtkeik szerint hasonlt
ssze kt karakterlncot :
numcmp (s1, s2) /*s1 s s2 numerikus sszehasonltsa*/ char *s1 ,
*s2;
{
double atof (), v1 , v2;
v1 = atof (s1);
v2 = atof (s2);

127

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;
*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 PASCAL-ban
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.

128

Mintaprogramjaink a knyvnkben megszokottaknl


lesznek, de mg mindig elgszerny mretek.

terjedelmesebbek

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
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:

129

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:
d.yearday = day_of_year(d.year, d.month, d.day);
A msik lehetsg a mutattads. Ha a hiredate-et
struct date hiredate;
alakban deklarltuk s day_of_year-t trtuk, akkor
hiredate.yearday = day_of_year (&hiredate); segtsgvel a hiredateet
megcmz
mutatt
tadhatjuk
day_of_year-nek.
A
fggvnyt
mdostani kell, mivel argumentuma a korbbi vltozlista helyett
most mutat lett:
day_of_year (pd)

/*Az v napjnak ellltsa a

hnapbl s a napbl*/ struct date *pd;


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

130

|| pd->year % 400 == 0; for (i = 1; i < pd->month; i++) day +=


day_tab [leap][i]; return (day);
}
A
struct date *pd;
deklarci szerint pd olyan mutat, amely date tpus
struktrra mutat. A
pd->year
plda szerinti jellsmd j. Ha p struktrt megcmz mutat,
akkor
p->struktratag
az
adott
tagra
vonatkozik.
mnuszjelbl s az azt kvet >-bl ll.)

(A

->

opertor

Mivel pd a struktrra mutat, a year tagra a


(*pd).year
alakban is hivatkozhatunk, de struktrkat jell mutatkat
olyan gyakran hasznlunk, hogy knyelmes rvidtsknt a ->
jellsmd is rendelkezsre ll. A (*pd).year alakban a
zrjelek szksgesek, mivel a . struktratag opertor
precedencija magasabb, mint a * opertor. Mind ->, mind pedig
. balrl jobbra kt, gy
p->q->memb
emp.birthdate.month
rtelme :
(p->)->memb
(emp.birthdate).month
A teljessg kedvrt me a msik fggvny, month_day, amit szintn a
struktra hasznlatval runk t :
month_day (pd) /*Hnap s nap ellltsa az v napjbl*/ struct
date *pd;
{
int i, leap;
leap = pd->year % 4 == 0 && pd->year % 100 != 0
|| 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;

131

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
lehetsgnk
van
msfajta
kulcsszbejegyzs egy pr:

a tmbk prhuzamosak, jelzi, hogy


szervezsre
is.
Valjban
minden

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 [] = {
break, 0,
case, 0,
char, 0,
continue, 0,
default, 0,
/* ... */

132

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

133

Rvidesen sor kerl a getword fggvny bemutatsra; egyelre elg


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

134

begyjtse befejezdik, a getword mr a szksgesnl egy karakterrel


tbbet olvasott be. Az ungetch hvsval ezt a karaktert a getword
kvetkez hvsig visszarjuk a bemenetre.
A getword a type
hvsval llaptja meg az egyes bemeneti karakterek tpust. Az
albbi vltozat csak az ASCII karakterkszletben mkdik:
type

/*ASCII karakter tpusnak visszaadsa*/ int c;

{
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 nem-alfanumerikus 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;
{

135

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);
}
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 mainben, 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.

136

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
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,
lesz, amely ngy sszetevbl ll:

csompont

nyilvn

struktra

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.

137

Az egsz program meglepen rvid, mivel mr korbban megrt


segdrutinokat hasznl. Ezek: a getword, amellyel az egyes bemeneti
szavakat olvassuk be,
s az alloc, amellyel helyet biztostunk a
szavak arrbbcssztatshoz.
A frutin egyszeren a getword segtsgvel beolvassa a szavakat s a
tree hasznlatval elhelyezi azokat a fn.
#define MAXWORD 20
main ()

/*Szavak gyakorisgnak szmllsa*/

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

/*w elhelyezse p-nl

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


{
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

138

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 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.

139

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
(crossreferencing)
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 s-et 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 :

140

struct

nlist { /*Elemi tbla bejegyzs*/

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

/*Kvetkez bejegyzs a

lncban*/
}
A mutattmb:
#define HASHSIZE 100 static struct nlist *hashtab [HASHSIZE];
/*Mutattbla*/ A lookup s az install ltal egyarnt hasznlt hash
rtkkpz fggvny egyszeren sszeadja a lncbeli karakterrtkeket
s kpezi az sszegnek a tmbmrettel vett maradkt. (Ez nem a
lehet legjobb algoritmus, de megvan az az elnye, hogy rendkvl
egyszer.)
hash (s) /*Az s string hash rtknek kpzse*/ char *s;
{
int hashval;
for (hashval = 0; *s != \0; ;)
hashval += *s++;
return (hashval % HASHSIZE);
}
A hash-eljrs a hashtab _tmbben ltrehoz egy kezdindexet; ha a
karakterlnc
egyltaln
megtallhat,
akkor
az
itt
kezdd
blokklncban kell lennie.
A keresst a lookup vgzi. Ha lookup megtallja a bejegyzst, a
megfelel mutatt adja vissza; ha nem, akkor NULL-lal tr vissza.
struct nlist *lookup (s)

/*s keresse hashtab-ben*/ char *s;

{
struct nlist *np; for (np = hashtab [hash (s)]; np != NULL; np =
np->next) if (strcmp (s, np->name) == 0)
return (np);
return (NULL);

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

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

meg*/

np

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

141

return (NULL); hashval = hash( np->name);


[hashval]; hashtab [hashval] = np;

np->next

hashtab

} else /*Mr ott van*/


free (np->def); /*Felszabadtja az elz
defincit*/
if ((np->def (strsave (def))) == NULL) return (NULL); return (np);
}
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. getcht 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) . . .
nulla.

igaz, ha mindkt bit

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

142

mezdefinci s -elrs szintaxisa a struktrkon alapul.


Pl. az
elbbi #define sorok hrom mez definilsval helyettesthetk:
struct {
unsigned is_keyword
is_static : 1;

1;

unsigned

is_extern

1;

unsigned

} 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;
amely kinullzza, s
if (flags.is_extern == 0 && flags.is_static == 0) . . .
megvizsglja a biteket.

amely

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.

143

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
skatulyzott struktrk jellsmdjval. Pl. a
struct
{
char *name;
int flags;
int utype;
union {
int ival;
float fval;
char *pval ;
} uval;
} symtab [NSYM];
ltal definilt struktratmbben az ival vltozra a
symtab [i].uval.ival
alakban, mg a pval karakterlnc els karakterre a
*symtab [i].uval.pval alakban hivatkozhatunk.
Valjban a union olyan struktra, amelyben a tagok kztti eltols
nulla, s amely elg nagy ahhoz, hogy a legszlesebb tagot is
tartalmazhassa gy, hogy az illeszkeds a benne elfordul sszes
tpus szmra megfeleljen.

144

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*/
struct tnode *left;
/*Bal oldali
gyermek*/
struct tnode *right;
/*Jobb oldali
gyermek*/
} TREENODE, *TREEPTR;
Ezzel kt j tpuskulcssz, TREENODE (struktra) s TREEPTR (a
struktramutatja)jn ltre. Ekkor a talloc rutinbl
TREEPTR talloc ()
{
char *alloc (); return ((TREEPTR) alloc (sizeof (TREENODE)));
}
lesz.
Hangslyozzuk, hogy a typedef deklarci semmilyen rtelemben sem hoz
ltre j tpust; egyszeren j nevet ad valamilyen, mr ltez

145

tpusnak. Szemantikailag sincs benne semmi j : az ily mdon


deklarlt vltozk pontosan ugyanolyan tulajdonsgak, mint azok a
vltozk, amelyeknek deklarciit explicit mdon lertuk. Valjban
typedef olyan, mint #define, attl eltekintve, hogy mivel a fordt
rtelmezi, olyan szveges helyettestsekkel ismeg tud brkzni,
amelyek meghaladjk a C makroprocesszor kpessgeit. Pl.:
typedef int (*PFI) ();
ltrehozza a PFI tpust az int-et visszaad fggvnyt megcmz
mutat szmra, amely olyan sszefggsekben hasznlhat, mint
PFI strcmp, numcmp, swap; az 5. fejezet rendezprogramjban.
A typedef deklarcik hasznlatnak kt f oka van. Az els ok a
programok paramterezse a gpfggsgi problmk kivdsre.
Ha a
typede-feket olyan adattpusokra hasznljuk, amelyek gpfggek,
akkor
a
program
thelyezsekor
csupn
a
typedef-eket
kell
megvltoztatni. Az egyik szoksos eset az, amikor klnfle egsz
mennyisgek szmra hasznlunk typedef neveket, majd minden egyes
befogad gpre elksztjk a short, int s long vlasztkbl ll
megfelel kszletet.
A typedef-ek hasznlatnak msik clja a programdokumentls javtsa
- a TREEPTR-nek nevezett tpust knnyebb megrteni, mint azt,
amelyiket csupn egy bonyolult struktra mutatjaknt deklarltunk.
Vgezetl, mindig megvan annak a lehetsge, hogy a jvben a fordt
vagy valamelyik msik program, mint pl. a lint fel tudja hasznlni a
typedef deklarcikban trolt informcit a program valamilyen kln
ellenrzse cljbl.
_
7.

fejezet

Bevitel s kivitel
A be- s kiviteli (I/O) szolgltatsok nem rszei a C nyelvnek, ezrt
ezekre idig nem fordtottunk klnsebb figyelmet. Ktsgtelen
azonban, hogy a valdi programok sokkal bonyolultabb mdon llnak
kapcsolatban krnye-zetkkel, mint ahogy azt idig bemutattuk. Ebben
a fejezetben a szabvnyos (standard) be- s kiviteli knyvtrat
ismertetjk; ez a fggvnyeknek olyan kszlete, amelyek a C programok
szabvnyos be- s kiviteli rendszert kpezik. E fggvnyek feladata,
hogy knyelmes programozsi csatlakozst biztostsanak, ugyanakkor
csupn olyan mveleteket valstsanak meg, ame-lyek 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 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.
_

146

7.1.

Hozzfrs a szabvnyos knyvtrhoz

Minden
olyan
knyvtrbeli

forrsllomnynak,

amely

valamelyik

szabvnyos

fggvnyre hivatkozik, valahol az llomny elejn tartalmaznia kell


az
#include < stdio.h >
sort.Az stdio.h llomny bizonyos, a be- s kiviteli knyvtr ltal
hasznlt
makrkat
szoksos

vltozkat

definil.

<

>

knykzrjeleknek

idzjelek helyetti hasznlata hatsra a fordt az llomnyt abban


a katalgusban (directory-ban) fogja keresni, amely a szabvnyos fej (header)
infor(a UNIX-ban tipikusan usr include).
mcit tartalmaz
A program betltsekor szksges lehet tovbb a knyvtr explicit
megadsa, a PDP--11 UNIX rendszeren pl. a program fordtst elr
parancs
cc forrsllomnyook stb. ls
ahol ls jelzi a szabvnyos knyvtrbl
karakter az el bet, load = betlteni.)

7.2.

trtn

betltst.

(Az

Szabvnyos be- s kivitel; getchar s putchar

A
legegyszerbb
karakterenknt

beviteli

mechanizmus

az,

amikor

getchar-ral

olvasunk a szabvnyos bemenetrl (standard inputrl), ltalban a


felhasznli terminlrl. getchar() minden hvsa utn a kvetkez bemeneti
karaktert adja vissza.
tmogatja, a ter-

legtbb

olyan

krnyezetben,

amely

C-t

minlt egy llomnnyal helyettesthetjk a C konvenci segtsgvel:


ha a
prog program a getchar-t hasznlja, akkor a
prog C infile
parancssor hatsra
helyett. A be-

prog

az

infile-t

fogja

olvasni

terminl

menet tkapcsolsa oly mdon trtnik, hogy maga a prog rzketlen a


vltoztatsra; kzelebbrl, az Cinfile karakterlnc nem kerl be az
argv-beli
parancssor-argumentumok
parancsln-

kz.

Hasonl

helyzet,

ha

bemenet

147

con (pipe) keresztl valamelyik msik programtl rkezik; az


otherprog _ prog
parancssor kt programot futtat, mgpedig az otherprog-ot s a progot, s gy intzkedik, hogy a prog szabvnyos bemenete az otherprog
szabvnyos kimenetrl jjjn.
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
kimenetre
(standard outputra)
terminl. A ki-

illeti,
teszi,

putchar

ami

karaktert

alaprtelmezs

szerint

szabvnyos
szintn

menet > 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
teszi.

szabvnyos

kimenett

az

anotherprog

szabvnyos

bemenetre

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
programot hasznlhatunk, mint a UNIX cat segdprogramja:

olyan

148

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 knyvtrban a getchar s putchar fggvnyek valjban makrk lehetnek, gy
elkerl-het
a
karakterenknti
fggvnyhvs
miatti
terhels
(overhead). A 8. fejezet-ben fogjuk ennek tnyleges megvalstst
megmutatni.

7.3.

Formtumozott kimenet; printf

A kivitel cljbl hasznlt printf s a beolvasst vgz scanf rutin


(l.
a
kvet-kez
szakaszt)
numerikus
mennyisgek
karakteres
brzolsra s karakteres mennyisgek numerikus brzolsra trtn
talaktst, formtumozott sorok ltrehozst s rtelmezst teszi
lehetv. A printf fggvnyt az elz fejezetekben ktetlenl
hasznltuk, me a teljesebb s pontosabb lers:
printf(control, argl, arg2, . . .)
A printf az argumentumait konvertlja, formtumozza s a szabvnyos
kime-netre nyomtatja a control karakterlnc vezrlete alatt. A
vezrl karakterlnc ktfle tpus objektumot tartalmaz: kznsges
karaktereket, amelyeket egyszeren a kimeneti folyamra msol s
konverzi-specifikcikat,
amelyek
mindegyike
a
printf
soron
kvetkez argumentumnak konvertlst s ki-nyomtatst rja el.
Minden konverzi-specifikcit a % karakter vezet be, s konverzis
karakter zr le. A % s a konverzis karakter kztt a kvetkezk
llhatnak:
Mnuszjel,amely az ebbe a mezbe konvertlt argumentum balra
igaz-tst rja el.
Szmjegyekbl
ll
karakterlnc,amely
a
minimlis
mezszlessget hatrozza meg. Az talaktott szm legalbb
ilyen szles vagy szksg esetn szlesebb mezbe nyomtatdik
ki. Ha a konvertlt argumentum kevesebb karakterbl ll, mint a
mezszlessg, akkor bal oldalon (vagy, ha a balra igazts
jelz szerepel, akkor jobb oldalon) a mez kitltdik, hogy
ezltal az elrt mezszlessg meglegyen. A kitlt karakter
k-znsges esetben szkz, ill. amennyiben a mezszlessget
elnullval adtuk meg, akkor nulla (ez a zrus nem jelent
oktlisan rtelmezett mezszlessget).
Pont,amely a mezszlessget a rkvetkez szmjegysorozattl
v-lasztja el.
Szmjegysorozat (a pontossg),amely a lncbl kinyomtatsra
kerl
I
karakterek maximlis szmt vagy float s double esetben a
tizedesponttl jobbra kinyomtatand szmjegyek szmt hatrozza meg.
Az l (el bet) hosszmdost,amely arra utal,hogy a szban forg
adat int helyett long.
A konverzis karakterek s jelentsk:
d

Az argumentum decimlis jellsmdv alakul.

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

149

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

150

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 * hozzrendels-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
megcmzett

az

eredmny

megfelel

argumentum

ltal

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.

151

Lebegpontos szmot vr; a megfelel argumentum float-ot megcmz


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

szm

szkzzel,

tabbal

int i;
float x;
char name[50];
scanf(%,2d %f%*d %2s, &i, &x, name)
hvs az
56789 0123 45a72
bemenettel 56-ot rendel i-hez, 789.0-t az x-hez, tugorja a 0123-at
s a 45
karakterlncot a name-be teszi. Brmelyik bemeneti rutin kvetkez
hvsa
az a betnl trtn keresssel fog indulni. E kt pldban a name
mutat, s
nem elzheti meg az & szimblum.
Msik
pldaknt
a
4.
fejezetben
ismertetett
elemi
kalkultorprogramot
most gy rjuk t, hogy a scanf vgezze a bemeneti konverzit:
#include < stdio.h>
main()
/ *Elemi kalkultorprogram*/
double sum, v;
sum = 0;
while (scanf(%lf, &v) != EOF)
printf(\t%.2f\n, sum += v);

152

A scanf akkor fejezi be mkdst, amikor kimertette a vezrl


karakter-lnct, vagy amikor valamelyik bemenet nem illeszkedik a
vezrlsi specifi-kcira. A scanf visszatrsi rtke a sikeresen
illesztett
s
hozzrendelt
be-meneti
ttelek
szma.
Ebbl
meghatrozhat, hogy a scanf hny bemeneti ttelt tallt. Allomny
vge esetn a visszaadott rtk EOF; gyeljnk arra, hogy ez nulltl
eltr rtk, amely azt jelenti, hogy a kvetkez bemeneti karakter
nem illeszkedik a vezrl karakterlnc els specifikcijra! A scanf
kvetkez hvsakor a keress kzvetlenl az utoljra visszaadott
karakter utn folytatdik.
Mg egy utols figyelmeztets: a scanf argumentumainak mutatknak
kell lennik! A leggyakoribb hiba, amikor valaki azt rja, hogy
scanf(%d, n);
ahelyett, hogy
scanf(%d, &n) _
Ft rna.

7.5.

Formtumkonverzi a tron bell

A scanf s printf fggvnyekkel rokon az sscanf s sprintf, amelyek


ugyan-ezeket
a
konverzikat
vgzik,
de
llomny
helyett
karakterlncon dolgoznak.
Az ltalnos formtum:
sprintf(string, control, argl, arg2, . . .)
sscanf(string, control, argl, arg2, . . .)
Az elzekhez hasonlan az sprintf a control szerint formtumozza az
argl,
arg2 stb.-beli
kimenet

argumentumokat,

az

eredmnyt

azonban

szabvnyos

helyett a string-be teszi. A string-nek termszetesen elg nagynak


kell lennie
ahhoz, hogy befogadja az eredmnyt. Ha pl. string karaktertmb s n
egsz,
akkor
sprintf(name, temp%d, n); a name-ben ltrehoz egy tempNNN alak
karakterlncot, ahol NNN az n rtke.
Az sscanf az
control-ban

ellenttes

irny

konverzikat

hozza

ltre

megadott formtum szerint vgighalad a karakterlncon, s a kapott


eredmnyeket az
mutatk-

argl,

arg2

stb.-ben

helyezi

el.

Ezen

argumentumoknak

nak kell lennik. A


sscanf(name, temp%d, &n); hvs az n-et annak a szmjegyekbl ll
karakterlncnak az rtkre lltja be, amely a name-ban a temp-et
kveti.

153

7.2.
Gyakorlat. rjuk meg jra a 4. fejezetben ltott
kalkultorprogra-mot gy, hogy a bemenetre s a szmkonverzira
a scanf s/vagy sscanf fgg-vnyeket alkalmazzuk!
7.6.

llomny-hozzfrs

Az idig megrt programok mindegyike a szabvnyos bemenetet olvasta


s a szabvnyos kimenetre rt, amelyekrl mindeddig feltteleztk,
hogy valami-lyen varzslatos mdon a helyi opercis rendszer elre
definilta ket a sz-munkra.
A be- s kivitellel val ismerkedsnk kvetkez lpseknt olyan
programot runk, amellyel programhoz nem rendelt llomnyhoz frhetnk
hozz. Az ilyen mveletek szksgessgt vilgosan bizonyt program
a cat,
amely megnevezett
szabv-

llomnyok

halmazt

gyjti

ki

(konkatenlja)

nyos kimenetre. A cat feladata llomnyoknak a terminlra trtn


kinyomtatsa, valamint
programok

ltalnos

cl

bemeneti

informcigyjts

azon

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
lehetne, az fopen szabvnyos knyvtri fggvnnyel meg kell nyitni. Az
fopen
vesz egy kls nevet (mint x.c vagy y.c), bizonyos nyilvntartst
vgez, s prbeszdet folytat az opercis rendszerrel (aminek
rszleteivel nem kell trdnnk), s olyan bels nevet ad vissza,
amelyet az llomny ezutn kvetkez olvassai, ill. rsai sorn
hasznlnunk kell.
E bels nv valjban mutat, amelyet llomnymutatnak neveznk, s
amely egy, az llomnyrl klnbz informcikat tartalmaz struktrra mutat. Itt tallhat pl. a puffer cme, a pillanatnyi pufferbeli
karakter-pozci, annak jelzse, hogy az llomny ppen olvass vagy
rs alatt ll stb.
A felhasznlknak a rszleteket nem kell ismernik, mivel az stdio.htl
nyert szabvnyos be- s kiviteli defincik egyik rsze a FILE-nak
nevezett
struktradefinci.
dekla-

Az

llomnymutat

szmra

szksges

egyetlen

rcira nzve plda a

154

FILE *fopen(), *fp;


Eszerint fp FILE-t megcmz mutat, s fopen szintn ilyen mutatval
tr vissza. Figyeljk meg, hogy FILE, csakgy, mint int, tpusnv,
nem pedig struktracmke; typedef-knt valstottk meg. (Annak
rszleteit, hogy mindez miknt mkdik a UNIX opercis rendszerben,
a 8. fejezetben ismertetjk.)
Az fopen tnyleges hvsa a programon bell gy fest:
fp = fopen(name, mode);
Az fopen els argumentuma az llomny neve, amely egy karakterlnc. A
m-sodik argumentum, amely szintn karakterlnc, a md, amely azt
jelzi, hogy a felhasznl hogyan akarja hasznlni az llomnyt. A
megengedett mdok az olvass (r: read), az rs (w: write) s a
hozzfggeszts (a: append).
Ha rsra vagy hozzfggesztsre nem ltez llomnyt nyitunk meg,
akkor az illet llomny (ha lehet) ltrejn. Ltez llomny rsra
trtn megnyitsnak hatsra annak korbbi tartalma elvsz. Hibt
jelent, ha nem-ltez llomnyt olvasni akarunk. Ms hibaokok is
elfordulhatnak (pl. ha olyan llomnyt prblunk meg olvasni,
amelyre nincs engedlynk). Brmi-lyen hiba esetn az fopen a NULL
mutatrtkkel tr vissza (amelynek defi-ncija a knyelem kedvrt
szintn stdio.h-ban van).
A kvetkezkben azt kell tudnunk, hogyan olvashatjuk a mr megnyitott llomnyokat. Tbb lehetsg van, amelyek kzl a getc s putc
csupn
a legegyszerbb. getc az llomny soronkvetkez karaktervel tr
vissza;
llomnymutatval kell megadnunk, hogy melyik llomnyrl van sz.
Igy
c = getc(fp) az fp ltal hivatkozott llomnybl a kvetkez
karaktert c-be helyezi, ill EOF kerl c-be, ha elrtk az llomny
vgt.
A putc a getc inverze :
putc(c, fp)
a c karaktert az fp llomnyba helyezi s c-t adja vissza. A getchar
s putchar fggvnyekhez hasonlan a getc s putc is lehet fggvny
helyett makr.
Hrom llomny minden program indtsakor automatikusan megny-lik,
s a rendszer llomnymutatkat is rendelkezsre bocst szmukra.
Ezek az llomnyok : a szabvnyos bemenet, a szabvnyos kimenet s a
szab-vnyos hibakimenet; az ezeknek megfelel mutatk neve: stdin,
stdout s stderr. Kznsges esetben ezek mindegyike a terminlhoz
van rendelve, azonban az stdin s stderr mutatkat a 7.2. szakaszban
lert mdon llom-nyokba vagy parancslncokba lehet tirnytani. A
getchar s a putchar az albbi mdon definilhat a getc, a putc, az
stdin s az stdout segtsgvel:
#define getchar() getc(stdin)
#define putchar putc(c, stdout)
llomnyok formtumozott beolvassra vagy kiratsra az fscanf s
fprintf fggvnyeket hasznlhatjuk. Ezek azonosak a scanf s printf
fggvnyekkel,
eltekintve
attl,
hogy
az
els
argumentum

155

llomnymutat, amely az olva-sand vagy rand llomnyt hatrozza


meg; a vezrl karakterlnc a mso-dik argumentum.
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)
konkatenlsa*/ int argc; char * argv [] ;

/*

cat:

llomnyok

FILE *fp, * fopen();


if (argc == 1 ) /* Nincs arg., a szabvnyos bemenetet msolja*/
else
filecopy(stdin);
while (--argc _ 0)
if((fp = fopen(*++argv, r)) == NULL){
printf(cat: nem nyithat meg %cs\n, *argv);
break;
} else _
filecopy(fp);
fclose(fp);
filecopy(fp) /*llomny msolsa a szabvnyos kimenetre*/ FILE *fp;
int c;
while ((c = getc(fp)) != EOF)
putc(c, stdout);
Az stdin, ill. stdout llomnymutatk a be- s kiviteli knyvtrban
szab-vnyos
bemenetknt,
ill.
szabvnyos
kimenetknt
elredefiniltak;
min-dentt
hasznlhatk,
ahol
FILE
tpus
objektumokat hasznlni lehet. Ezek azonban llandk s nem vltozk,
teht ne prbljunk semmit sem hozzjuk rendelni !
Az fclose fggvny az fopen inverze: megszaktja az llomnymutat s
a kls nv kztt az fopen ltal ltrehozott kapcsolatot, s gy az
llomny-mutat egy msik llomny szmra szabadul fel. Mivel a
legtbb opercis rendszerben az egyidejleg megnyitott llomnyok
szma korltozott, cl-szer azokat felszabadtani, ha mr nincs
rjuk szksg, amint ezt a cat-ban is tettk. Az fclose kimeneti
llomnyra val alkalmazsnak msik oka is van: rti azt a puffert,
amelyben
a
putc
a
kimenetet
gyjti.
(A
program
normlis
befejezdsekor az fclose automatikusan meghvdik minden megnyitott
llomnyra. )

7.7.

Hibakezels; stderr s exit

A hibknak az a fajta kezelse, amit a cat-ban hasznltunk, nem


idelis. A baj az, hogy ha az llomnyok egyike valamely oknl fogva
hozzfrhetetlen,
a
hibajelzs
a
konkatenlt
kimenet
vgre
nyomtatdik. Ez elfogadhat, ha a kimenet a terminlra irnyul,
azonban rossz, ha egy llomnyba vagy pa-rancslncon keresztl egy
msik programba megy.

156

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)
konkatenlsa* / int argc; char * argv[ ];

/*

cat:

llomnyok

FILE *fp, *fopen();


if (argc ==1 )

/*Nincs arg., a szabvnyos bemenetet

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

7.8.

Szvegsorok beolvassa s kivitele

A szabvnyos knyvtrban rendelkezsre ll az fgets rutin, amely


meglehetsen hasonlt a knyvben vgig hasznlt getline fggvnyhez. Az
fgets(line,
MAXLINE,
fp)
hvs
az
fp
llomnybl
a
line
karaktertmbbe beolvassa a kvetkez beme-neti 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. llomny vge esetn a nullt adja vissza.)

157

Kivitelkor az fputs fggvny karaktersorozatot (amely nem kell, hogy


jsort tartalmazzon) r az llomnyra:
fputs(line, fp)
Annak rzkeltetsre, hogy az olyan fggvnyek krl, mint fgets s
fputs nincs semmi varzslatos, a szabvnyos be- s kiviteli
knyvtrbl kzvetlenl ide msoltuk e fggvnyek programkdjt:

#include < stdio.h>


char * fgets(s, n, iop) / * Legfeljebb n karakter olvassa ioprl* /
char * s;
int n;
register FILE *iop;
register int c;
register char * cs;
cs = s;
while ( --n > 0 && (c = getc(iop)) != EOF)
if ((*cs++ = c) =- \n)
break;
*cs = \0; return((c == EOF && cs == s) ? NULL : s);
fputs(s, iop)

j *Az s karakterlncot az iop llomnyra rja*/

register char *s;


register FILE *iop;
register int c;
while (c = *s++)
putc(c, iop);

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

7.9.

Nhny tovbbi fggvny

A szabvnyos knyvtr szmos fggvnyt bocst rendelkezsnkre,


amelyek kzl nhny klnsen hasznos. Mr emltettk az strlen,
strcpy, strcat s strcmp harakterlnc-kezel fggvnyeket. me nhny
tovbbi fggvny.

158

Karakterosztly-vizsglat s -talakts
Tbb makro vgez karaktervizsglatot s talaktst
isalpha
isupper
islower
isdigit
isspace
toupper
tolower

nemnulla,ha c
nemnulla,ha c
nemnulla,ha c
nemnulla,ha c
nemnulla,ha c
c talaktsa
c talaktsa

alfabetikus,0,ha nem.
nagybet,0,ha nem.
kisbet,0,ha nem.
szmjegy,0,ha nem.
szkz,tab vagy jsor,0,ha nem
nagybetss.
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
hajtja

az

karakterlncban

tartalmazott

parancsot

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


ersen
fgg a helyi opercis rendszertl.Trivilis pldaknt a UNIX-ban a
system(date); sor hatsra lefut a date nev
kinyomtatja a dtumot s a na-pon belli idpontot.

program;

amely

Trkezels
A calloc fggvny igen hasonlt a korbbi fejezetekben hasznlt alloc
fgg-vnyre.
calloc(n, sizeof(objektum)) egy mutatt szolgltat, amely olyan
helyre mutat, ahol elegend hely van n darab megadott mret objektum
szmra, ill. a NULL rtket adja vissza, ha a krs nem
teljesthet. A trterlet kezdeti nagysga nulla.
A mutat a szban forg objektum tpusnak megfelel helyre mutat,
azonban
tpusmdost
szerkezettel
a
megfelel
tpusv
kell
alaktani, pl.:
char * calloc() ;
int *ip;
ip = (int *) calloc(n, sizeof(int));

A cfree(p) felszabadtja a p ltal megcmzett helyet, ahol p-t


eredetileg calloc valamelyik hvsval nyertk. A helyfelszabadts
sorrendjre nincs megkts, azonban vgzetes hiba, ha olyasvalamit
szabadtunk fel, amit nem a calloc hvsval nyertnk.

159

A 8. fejezetben bemutatjuk a calloc-hoz hasonl trterlet-foglal


fgg-vny megvalstst, amelyben a lefoglalt blokkok tetszleges
sorrendben szabadthatk fel.

164

160

_
8.

fejezet

Csatlakozs a lJNIX opercis rendszerhez

E fejezet anyaga a C programok s a UNIX opercis rendszer kztti


kapcsolattal foglalkozik. Mivel a legtbb C programoz UNIX rendszer
alatt dolgozik, ezek az ismeretek az olvask tbbsge szmra
hasznosak lesznek. St, mg ha az olvas a C nyelvet ms gpen is
hasznlja, e pldk tanulm-nyozsa 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 bes 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
minderre van-e

ltrehozsra

is.

rendszer

ellenrzi,

hogy

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 bevagy kiviteli mveletet akarunk vgezni, az llomny azonostsa cljbl
annak

161

neve helyett az llomnylert hasznljuk (Ez nagyjbl hasonlt a


READ(5, . . .) s WRITE(6, . . .) hasznlatra a FORTRAN-ban.) A
megnyi165

162

8.3.

Open, creat, close, unlink

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

168

163

#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
open(argv[ 1 ], 0)) = -1 )
error(cp:
nem
nyithat
meg
creat(argv[2], PMODE)) = -1)

hov,
%s,

NULL);
argv[1

if
]);

((fl

if((f2

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 llomnyrendszerbl.
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

164

R.4.

Vletlen hozzfrs; seek s Iseek

llomnyok be- s kivitele ltalban soros: minden read s write az


llo-mnynak azon a pozcijn trtnik, amely kzvetlenl a megelz
be- vagy kivitel llomnybeli pozcijt kveti. Szksg esetn
azonban az llomny tetszleges sorrendben olvashat vagy rhat. Az
lseek rendszerhvs lehetv teszi, hogy tnyleges olvass vagy rs
nlkl mozoghassunk az llomnyban:
lseek(fd, offset, origin);
hatsra az fd lerj llomnyban az aktulis pozci az offset
pozcira mozdul, amelyet az origin ltal meghatrozott helyhez
kpest relatven rtel-meznk. Az ezt kvet olvass vagy rs ezen
az j pozcin fog kezddni.
Az offset long tpus: az fd s az
origin int tpusak. Az origin 0, 1 vagy 2 lehet, jelezve, hogy az
offset-et az llomny elejtl, a pillanatnyi pozcitl, vagy az
llomny vgtl kell szmtani. Ha pl. az llomnyhoz valamit hozz
akarunk fggeszteni, rs eltt keressk meg az llomny vgt :
lseek(fd, OL, 2);
Ha vissza akarunk trni az llomny elejre (visszatekercsels)
lseek(fd, OL, 0);
Figyeljk meg a OL argumentumot, ezt (long)0-nak is rhatnnk.
Az lseek hasznlatval lehetsgnk van arra, hogy az llomnyokat
lassbb hozzfrs rn nagy tmbkhz hasonlan kezeljk. Az albbi
egyszer fggvny pl. az llomny tetszleges pontjrl tetszleges
szm byte-ot olvas be:
get(fd, pos, buf, n)
/ * n byte olvassa a pos
pozcirl* / int fd, n; long pos; char * buf;
lseek(fd, pos, 0);
/*Elmegy pos-ra*/
return(read(fd, buf, n));
A UNlX rendszer 7-est megelz vltozataiban a be- s kiviteli
rendszer alap-vet belpsi pontjnak neve: seek. A seek s az lseek
azonosak, attl elte-kintve, hogy az elbbinek az offset argumentuma
nem long, hanem int. Ennek megfelelen, mivel a PDP I 1 int-ek 16
bitesek, a seek-nek megadhat offset fels korltja 65535; ezrt a 3,
4, 5 origin rtkek hatsra a seek a megadott offset rtket 512-vel
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!

165

8.5.
Plda; az fopen s a getc megvalstsa
Prbljuk meg egysgbe foglalva szemlltetni a mondottakat az
fopen
s
getc
szabvnyos
knyvtri
rutinok
egyik
megvalstsnak bemutatsval.
Emlkezznk
llo-

arra,

hogy

szabvnyos

knyvtr

llomny-ait

nem

_
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\

166

? *(p) - _ =ptr++ = (x) : -flushbuf((xj,p))


#define putehar(x)
putc(x,stdout)

167

A getc makr norml esetben egyszeren dekrementlja a darabszmot,


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

172

168

#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

169

#include < stdio.h>


fillbuf(fp)
/*Bemeneti
register FILE *fp;

puffer

lefoglalsa

feltltse*/

static char smallbuf [ NFILE]; _*Puffereletlen I/O-ra*/


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

174

170

FILE iob [ NFILEl ={


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

Plda; katalgusok kilistzsa

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

semmi klns nincs az olyan parancsokban, mint az ls: beolvas


egy llomnyt, s kiemeli belle a szmra fontos informcit. Ennek az
informcinak a formtumt ugyanakkor maga a rendszer hatrozza meg, nem
pedig
a felhasznli program, gy az ls-nek ismernie kell az opercis
rendszer brzolsmdjt.
E megjegyzsek kzl nhnyat az fsize program megrsval
fogunk
szemlltetni. Az fsize az ls olyan specilis formja,amely az
argumentumlistjban megnevezett sszes llomny mrett kinyomtatja. Ha az
llomnyok valamelyike katalgus, az fsize erre rekurzvan alkalmazza
nmagt.
Ha egyltaln nem adtunk meg argumentumot, az aktulis
katalgust dolgozza fel.
Indulsknt rviden tismteljk az llomnykezelssel
kapcsolatos

171

tudnivalkat. A katalgus (directory) olyan llomny, amely


llomnynevek
listjt tartalmazza, s utal arra, hogy a megfelel llomnyok
hol tallhatk.
175

172

Az llomnyok cime valjban egy msik tblzatba, az inode


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

_ * A katalgusbejegyzs struktrja* _

ino_t d ino; _ * Inode-szm* /


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

173

#define S_IFMT
#define S
IFDIR
#define S_IFCHR
#define S_IFBLK
#defineS
IFREG
#define S
ISUID
vgre-

0160000/* Az llomny tpusa* I


0040000 /*Katalgus* /
0020000/*Specilis karakter* /
0060000/* Specilis blokk* /
0100000/*Szablyos*/
04000
/ * Felhasznl azonost belltsa

#define S

ISGID

02000

#define S

ISVTX

01000

#define S
#define S
#define S

IREAD
0400
IWRITE 0200
IEXEC
0100

haj tsra* _
_* Csonortazonost belltsa vgrehajtsra* /
/*Az tvitt szveget hasznlat utn
menti* /
I *,Olvassi engedly* /
/*Irsi engedly* /
/,* 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 foglalkozik: 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:

174

fsize(name)

/* Kinyomtatja a megadott nev llomny


mrett* /

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

/*nmagt s a

for (i=0, nep=nbp; i C DIRSIZ; i++)


*nep++ = dirbuf.d name[i];
*nep++ = \0; fsize(name);
close(fd);
* - nbp = \0;

/*Nv helyrelltsa* _

175

Ha a katalgus adott rovata. ppen nincs hasznlatban (mivel az


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

Plda; trterlet lefoglalsa

Az 5. fejezetben az alloc egyszerstett vltozatt mutattuk,be. A


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

176

Az egyik problma, amit az 5. fejezetben rintettnk annak


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

/ * Ennek a szabad blokknak a mrete* _

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

180

177

static HEADER base; / * res lista az indulshoz* / static HEADER


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

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

/ * A hts felt foglalj a le* /

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


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

/* Nincs tbb* /

A base nev vltozt hasznljuk indulskor. Ha, mint alloc els


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

178

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

179

free(ap)

/ *Az ap blokkot a szabad listba teszi* / char * ap ;

register HEADER *p, *q;


p = (HEADER *) ap -1; _*A fejre mutat* /
for (q=allocp; !(p _ q && p C q-_ s.ptr); q=q-7 s.ptr) if (q _= q_ s.ptr && (p > q I_ p C q-> s.ptr))
break;

/*Egyik vagy msik vgn*/

if (p+p-_s.size == q->s.ptr){
szddal*
>s.ptr;

p-7s.size

+=

/*Egyesl a fels szom-

q-7s.ptr-_s.size;

p-7s.ptr

q-_s.ptr-

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

180

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

Direkt konzol I/O


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

header file

Lnyege, hogy minden billenty, illetve kperny mvelet pufferetlen,


s tirnythatatlan. Ezrt sokkal gyorsabb, mint a standard file-ok
kezelse. Lssuk a fggvnyeket!

1.

int getch()

Bekr egy karaktert a billentyzetrl. Echo nlkl, puffereletlen


beolvass.
Vissza: a beolvasott karakter kdja.

2.

/*Hibt nem ad vissza*/

int getche()

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

3.

int ungetch
int c;
/* karakterkd */

Visszateszi c karaktert a billentyzetpufferbe. Ksbb ezt ki lehet


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

4.

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

181

Visszateszi c karaktert az fptr file-ba. Pufferelt tvitelt kell


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

5.

int kbhit()

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


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

6.

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

Kzvetlenl a konzolrl olvas be egy stringet, s elhelyezi azt s+2


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

7.

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

Kir egy stringet /\0-al lezrva! / kzvetlen konzolra. Nem kezeli


a CR-LF kombincit! Ez azt jelenti, hogy a \n csak j sorba lp,
mg a sor elejre a \r-rel juthatunk.
Vissza: semmi.

8.

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

A printf megfelelje, de direkt konzol I/O-val mkdik. Hasznlja a


putch() fggvnyt. Figyeljnk itt is \n s a \r kztti
klmbsgre!
Vissza: sikeres konverzik szma.

182

9 int cscanf(...u.a....)
...u.a.... mint a scanf()-nl mr lttuk.
Kzvetlen a konzolrl valst meg formzott inputot. Httrben a
getche() fggvnyt hasznlja.
Vissza: sikeres konverzik szma
EOF=EOF esetn;
0 ha hiba volt.

10.
void putch
int c;
/* kirand karakter kdja */
Kir egy karaktert /c/ kzvetlen konzolra.
Vissza: semmi.
A file-kezels alapjai:
---------------------- standard file-ok
/ stdin, stdout, stdprn, stdaux, stderr /
lemezes llomnyok mint egy byte-halmaz jelenik meg
nincs file-tpus, mindg az adott alkalmazs dnti el, hogy milyen
tpusnak veszi a file-t.
Az stdio.h headerfile fontosabb rszei:
...
/* (ANSI / System V) # UNIX alatti fejlesztshez!
...
...
*/
#define
#define
#define
#define
#define
#define
#define
#define

BUFSIZ
_NFILE
EOF
FILE
P_tmpdir
SEEK_CUR
SEEK_END
SEEK_SET

#define SYS_OPEN

512
20
(-1)
/* mirt kell zrjel? */
struct_iobuf
//
1
2
0
20

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

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


defined(M_I86HM))
#define NULL

0L

#endif
Megjegyzs: V6.00 = ((void*)0)
/* file kontroll block */

183

# ifndef _IOB_DEFINED
extern FILE {
char *_prt;
/* rsi/olvassi pointer */
int
_cnt;
/* karakterek / helye a pufferbe / */
char *_base;
/* a puffer kezdcme */
char _flag;
/* a file llapota (hiba: EOF) */
char _file;
/* file handle */
} _NEAR _CDECL _iob[];
#define_OIB_DEFINED
#endif
#define
#define
#define
#define
#define
#define

fpos_t
stdin
stdout
stderr
stdaux
stdprn

long
/* file pozci */
(&_iob[0])
(&_iob[1])
(&_iob[2])
(&_iob[3])
(&_iob[4])

/* Fggvny ill. makrdefincik. */


#define getc(f) (--(f)->_cnt>=0 ? 0xff & *(f)->_ptr++ :_filbuf(f))
/* Beolvas
struktra;

egy

karaktert

f-el

azonostott

file-bl.

file

lsd fentebb! */
#define putch(c,f) (--(f)->_cnt >=0 ? 0xff & *(f)->_ptr++=\
(char)) :_flsbuf(,(f))
/* c vltozbl
azonostott

egy

karaktert

kir

(FILE*)

vltozval

file-ba. _filbuf(),_flsbuf() bels file-kezel fggvnyek. */


#define
#define
#define
#define
#define

getchar()
putchar()
feof(f)
ferror(f)
fileno(f)

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

/* elzekben */
#define
#define
#define
#define

_IOEOF
_IOERR
_IOREAD
_IOWRT

0x10
0x20
0x01
0x02

/*
/*
/*
/*

elrtk EOF-et */
hiba van */
olvassra nyit */
rsra nyitva */

File-kezels II. szint:


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

184

11.

FILE *fopen(fazon,md)
char *fazon;
/* file azonostja */
char *md;
/* hasznlati md */

Megnyitja fazon-nal azonostott nev file-t.


Vissza: file-pointer sikeressg esetn
NULL pointer hiba esetn.
Md:
r:

Ltez file megnyitsa olvassra.


/Nincs akkor hiba./
w:
res file nyitsa rsra.
/Ha ltezett, akkor trli az eredeti tartalmt./
a:
Ltez file megnyitsa hozzfzsre.
/Nem ltez file esetn ltrehozza./
r+: Ltez file-t megnyit rsra olvassra.
w+: res file-t megnyit rsra olvassra.
a+: Ltez file-t nyit olvassra s hozzrsra.
/Ltez adatoto nem rhat fell./
/* MSC-ben: */
t:
Text md.
b:
Binris md.
Text:

12.

input: CR+LF -> LF (\n)


output: LF
-> CR+LF

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


hasznlati mddal. Az jonnan nyitott file-t is fptr azonostja.

md

Vissza: lsd elbb.

13.
int fclose(f)
FILE *f;
Lezrja f-fel azonostott file-t. Minden puffert rt s trl.
Vissza: 0 - sikeres zrs
EOF - hiba esetn.

14.

int fcloseall()

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


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

185

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

16.
int fflush(f)
FILE *f;
Output: rti a puffereket melyek f-hez tartoznak.
Input:

Trli a puffert.

Vissza: 0 - sikeres
EOF - hiba volt.
Irs s olvass:

17.
int getc(f)
FILE *f;
Az f-fel azonostott
karaktert.

file-bl

beolvassa

soron

kvetkez

egy

Vissza: a beolvasott karakter kdja


EOF - hiba, vagy file-vg esetn.

18.

int putc(c,f)
char c;
/* Kirand karakter kdja */
FILE *f;
/* File-hoz tartoz pointer */

Az output file f aktulis pozcijba kirja c-t.


Vissza: a kirt karakter kdja
Hiba: EOF-et ad, hvjuk ferror()-t!

19.
int fgetc(f)
FILE *f;
U.a. mint getc(), de megvalstsa fggvny s nem makr!
[ Az fgetchar() - stdin-rl, szintn fggvny! ]

20.
int fputc(c,f)
char c;

186

FILE *f;
U.a. mint a putc(), csak fggvny.
[ Az fputchar() - stdout-ra, szintn fggvny! ]

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

22.
int fprintf((f,...u.a....)
FILE *f;
...u.a.... = mint a printf()-nl
Formtumozott adattvitelt hajt vgre az f-el megadott file-ra.
Vissza: az tvitt karakterek szma.

23.
int fscanf(f,...u.a....)
FILE *f;
...u.a.... = mint a scanf()-nl
Formtumozott adattvitelt hajt vgre f file-bl. Beolvas.
Vissza: sikeresen konvertlt s tvitt objektumok szma
EOF hiba, vagy file-vg esetn.
Tovbbi I/O lehetsgek:

24.

char *fgets(string,n,f)
char *string;
/* buffer az adatoknak */
int n;
/* max. beolv. karakter */
FILE *f;
/* file azonost */

Beolvas a file-bl / aktulis pozcitl / n -1 karaktert, ill. az


els \n-ig! Attl fggen, hogy melyik teljesl elbb.
Figyelem: a beolvasott\n-t is trolja. A vgre \0-t tesz! A
rokon gets() NEM trolja \n-t!

187

Vissza: Pointer a stringre


NULL: hiba vagy EOF esetn.

25.

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

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


A \0-t nem viszi t.
Vissza: az utoljra tvitt karakter
0, ha a string res
EOF hiba esetn.
3. plda / szvegfile olvassa C2P3.C, C2P3A.C, C2P3B.C /
4. plda / szvegfile kezelse C2P4.C /
File kezels binris mdon:
---------------------------

26.

int fwrite(puffer,mret,db,f)
unsigned char *puffer;
/* honnan */
unsigned int meret;
/* obj. mrete */
unsigned int db;
/* obj. darabszma */
FILE
*f;
/* file azonostja */

Kir a file-ba (aktulis


objektumot a pufferbl.

pozcitl)

db-nyi

mret

hosszsg

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.

188

28.
long ftell(f)
FILE *f;
Megadja az f file aktulis pozcijt a file elejhez kpest byteban.
Vissza: HIBA esetn -1L
hatrozatlan, ha nincs nyitott file-hoz rendelve f.
/ pl: stdprn /

29.

int fseek(f,eltols,honnan)
File *f;
/* file-pointer */
long eltols;
/* byte-ban mennyit */
int honnan;
/* pozci */

A file pointert az adott f file-ban a kvnt pozciba mozgatja.


honnan: SEEK_SET - file eleje
SEEK_CUR - aktulis pozci
SEEK_END - file vge
Vissza: 0 sikeres
nem 0 - hiba hatrozatlan, ha a mvelet rtelmetlen. (pl.: stdprn)
Figyelem: soremels (CR-LF)
5. plda / C2P5.C - megadott file utols 10 sornak listzsa /
6. plda / C2P6.C - nevek, s telefonok felrsa, visszaolvassa. /

30.
void rewind(f)
FILE *f;
Ujranyitja az f file-t! A file elejre pozcionl, puffert rt, ha
kell [ fseek(f,0l,SEEK_SET); ], de a rewind() trli az EOF-et s a
hibajelzket is.
Vissza: nincs.
Segdfggvnyek:
----------------

31.
int fileno(f)
FILE *f;
Visszaadja az f file file-handle szmt. Ha tbb is tartozik hozz,
akkor az els open-nek megfelelt.
Vissza: File-handle
hatrozatlan, ha nem tartozik nyitott file-hoz.

189

32.
long filelength(fh)
int fh;
/* file-handle szm */
Vissza: a file hossza byte-ban
1L rvnytelen fh esetn.

33.

int flushall()

Minden outputra nyitott file puffert lemezre rti; input file-nl


pedig trli.
Vissza: a file-ok szma amennyit rtett.
7. plda / C2P7.C - tmbk kirsa file-ba, filehossz kirsa /
File-kezels I. /alacsony szint/:
-------------------------------- file-handle szm
file, mint byte tmb
elssorban binris file-kezels (ekkor semmi konverzi nincs,
ellenttben a szvegmddal!)
Alapja: fcntl.h
io.h
types.h
stat.h

34.

}
}
}
}

header file-ok

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.

190

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.
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;
extern int _doserrno;
(stdlib.h vagy stddef.h-ban is van)

/* ltalnos I/O hiba */


/* DOS funkcik */

35.
int creat(nv,md)
char *nv; /* a file neve */
int md;
/* hasznlati md */
Nemltez file-t ltrehoz, vagy ltezt fellr. Md lsd open()-nl.
Vissza: file-handle
hiba: -1,kd az errno-ban.
Figyelem: ha MS/PC-DOS krnyezetben S_IWRITE-tal hozunk ltre egy
file-t, akkor mg rhatunk be, de lezrs utn mr csak olvashat
lesz. De azt aztn meg lehet szntetni.
Lehetsges hibk:
----------------/ alapja errno.h - mind #define.../
EACCESS = DOS 3.0 vagy magasabb verzik!
Nem osztott file elrse; read-only-t rsra probltak nyitni.
EEXIST
EMFILE
ENDENT

= Ltezik a file.
= Tl sok file van megnyitva.
= File, vagy az tvonal nem tallhat.

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

191

Lezrja az fh-val azonostott file-t.


Vissza: 0

- Ok

1 - hiba errno=EBADF

37.

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

Kir puffer kezdcmtl count-nyi byte-ot az fh-val azonostott file


aktulis pozcijtl kezdve.
Vissza: Kirt byte-ok szma
HIBA: -1 lsd errno-t
EACCESS
EBADF
ENOSPC - nincs hely
Figyelem: egyszerre maximum 65534 byte-ot lehet kirni!

38.

int read(fh,p,c)
int
fh;
/* file-handle szm */
char
*p;
/* mutat a pufferre */
unsigned int c;
/* olvasand byte-ok szma */

Beolvas s elhelyezi p cmtl kezdve c-nyi byte-ot.


Vissza: Beolvasott byte-ok szma
HIBA: -1 lsd errno-t
Figyelem: egyszerre maximum 65534 byte-ot lehet olvasni!
write/read ha O_TEXT-ben megy
CR-LF --> LF
(read)
LF
--> CR-LF (write)
MS-DOS alatt text md esetn file vge: ^Z, ekkor 0-t ad vissza.

39.
long tell(fh)
int fh;
/* file-handle szm */
Visszaadja a file aktulis pozcijt byte-ban.
HIBA: -1 lsd errno-t.

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

192

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


SEEK_SET
SEEK_CUR
SEEK_END hasznlhat.
Vissza: File pozci
HIBA: -1 lsd errno-t.

41.
int eof(fh)
int fh;
/* file-handle szm */
A fggvny EOF-et vizsgl alacsony szinten!
Vissza: 1 EOF esetn
0 ha nem EOF
1 hiba lsd errno-t.

42.

int sopen(nv,oflag,shflag[,md])
char *nv;
/* a file neve */
int oflag;
/* opercis kd */
int shflag;
/* osztott elrsi mdok */
int md;
/* hasznlati md */

Minden megegyezik az open()-nal, de osztott krnyezetben!


Fontos: share.h!
shflag:
------SH_COMPAT
SH_DENYRW
SH_DENYWR
SH_DENYRD
SH_DENYNO

=
=
=
=
=

kompatibilis md lltsa
rs s olvass tiltsa
rs tiltsa
olvass tiltsa
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!!

193

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
------------------------------LK_LOCK
LK_RLCK
LK_NBLCK

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


= u.a. mint az elbb.
= zrolja a byte-okat egyszer prblkozik, majd hibt ad.

LK_NBRLCK = u.a. mint az elbb.


LK_UNLCK

= felszabadtja a lock-olt (!!) byte-okat.

Figyelem: az sszes zrolst fel kell oldani mieltt lezrjuk a filet, vagy kilpnk a process-bl.
Vissza: 0 = O.K.
HIBA = -1 lsd errno:
EDEADLOCK = LK_LOCK sikertelensge esetn EINVAL
tartomnyt adtunk!

= rvnytelen

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


9. plda / C2P9.C - locking plda /
Egyb file-kezelst segt fggvnyek:
44. int chdir(path)
char *path;

/ dekl.: direct.h /
/* katalgus neve */

Knyvtrat vlt, mint az MS-DOS parancs.


Vissza: 0 = O.K.
HIBA = -1 - nem ltez path.

45.

int rename(rgi,j)
char *rgi;
/* a file rgi neve */
char *uj;
/* a file j neve */

File illetve katalgus tnevezse ( MS/PC-DOS szabvnyos nv )


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

46.

int unlink(file)
char *file;

/* a file neve */

A file nev file trlse.

/ lsd mg remove() /

194

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

47.
int remove(file)
char *file;
/* a file neve */
Trli a megadott file nev file-t.
Vissza: 0 = O.K.
HIBA = -1 - lsd errno-t.
48. int mkdir(path)
char *paht;

/ dekl.: direct.h /
/* az j katalgus neve */

Ltrehoz egy j alknyvtrat.


Vissza: 0 = O.K.
HIBA = -1 - lsd errno-t.
49. int rmdir(path)
char *paht;

/ dekl.: direct.h /
/* a trlend katalgus neve */

Trli az alknyvtrat,
katalgus sem lehet.

melynek

resnek

kell

lennie!

Aktulis

Vissza: 0 = O.K.
HIBA = -1 - lsd errno-t.
50. int setmode(fh,md)
int fh;
int md;

/* file-handle szm */
/* j tviteli md */

Belltja az fh-file tviteli mdjt: O_TEXT vagy O_BINARY.


Vissza: elz md rtke - O.K.
1: HIBA, lsd errno-t.
50.a. char *getcwd(path,n)
dekl.: direct.h
char *path;
/* puffer a katalgusnvnek */
int n;
/* a path nv maximlis hossza */
Felemeli
a
teljes
elrsi
utat,
ami
pp
az
aktulis
munkakatalgusunk.
Az n = buffer hossz-1, most a \0-nak is kell
hely! Ha path-nak NULL-t adok t, akkor automatikusan hvja malloc()ot s helyet foglal. Felszabadts free()-vel visszaadott ptr -rel!
Vissza: mutat a puffer kezdcmre
NULL : hiba, lsd errno-t
ERANGE: tvonalnv hosszabb, mint n byte
ENOMEN: nincs elg memria
13. plda / C2P13.C - knyvtrvlts + file trlse /

195

Memriakezels:
-------------- memria modellek
dinamikus trkezels
Memria modellek:
az Intel processzorok miatt
6 modell ltezik
8 illetve 16 bites pointerezs
a.) small:

max. 64 Kb kd

max. 64 Kb adatszegmens

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

max. 64 Kb adatszegmens

c.) compact:

1 Mb adatszegmens

max. 64 Kb kd

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


d.) large:

1 Mb kd

1 Mb adatszegmens

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

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

C-ben a stack szegmens mindg az adatszegmens rsze! Default


rtke 2 Kbyte. lltsa linker opci: link... /ST:bytes
Szegmensek:
----------Kd:

_TEXT; tbb forrs modul esetn modulnv\_TEXT

Stack:
STACK:
vltozk helye.
Adat:

_BSS:

visszatrsi cmek, loklis (auto)


el nem ksztett (inicializlatlan)

statikus (static) vltozk. Fordt mindent binris nullval tlt


fel.
C_COMMON:

inicializlatlan kls (globlis)

vltozk.
CONST:

konstans adatok, melyek elfordulnak

a programban, kivtel a
szvegkonstansok.
_DATA:

inicializlt globlis (kls) s a

statikus (static) vltozk. Tovbb a szvegkonstansok.


NULL:

az adatterlet fizikai szegmensnek


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

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


Default: 128. lltsi lehetsg linker opci: link... /SEG: number.

196

51. char *malloc(m)


unsigned int m;

dekl.: malloc.h
/* byte-ok szma */

Lefoglal m mret (byte) memriablokkot a near heap-ben. Eltr


tpus esetn hasznljuk a cast opertort.
Vissza: NULL: nincs elg memria
vagy pointer az alloklt blokk elejre.
52. void free(p)

dekl.: malloc.h

char *p;
Felszabadtja a korbban alloklt memrit. Fontos, hogy a p mutat a
felszabadtand memria kezdetre mutasson!
Hvhat: malloc(), calloc(), realloc() utn!
Vissza: nincs.

53.

char *calloc(n,mret)
unsigned int n;
unsigned int mret;

/* elemek szma */
/* 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;
unsigned int mret;

/* a lefoglalt terlet kezdcme */


/* j mret byte-ban */

A p-hez rendelt, mr elzleg lefoglalt memriablokk nagysgt mretnyire mdostja.


Vissza: NULL: nincs elg memria, vagy mret=0,
pointer a lefoglalt blokk elejre.
14.

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

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:

<0, ha mit < mivel


0, ha egyenl
>0, ha mit > mivel

197

56.
int memcmp(mit,mivel,hossz)
char *mit,*mivel;
unsigned int hossz;
sszehasonltja mit-et mivel-lel hossz-nyi hosszan.

57.

char *memcpy(vev,ad,db)
char *vev;
/* output kezdcm */
char *ad;
/* input kezdcm */
unsigned int db;
/* mennyit */

tmsol ad-bl vev-be db-nyi byte-ot.


Vissza: pointer vev-re.

58.

char *memset(puffer,kar,db)
char *puffer;
/* kezdcm */
int kar;
/* milyen karakterrel */
unsigned int db;
/* mennyit */

Puffer els db-nyi byte-jt kar karakterrel tlti fel.


Vissza: pointer puffer-re.

59.
char *memccpy(vev,ad,c,db)
char *vev,*ad;
int c;
unsigned int db;
Byte-okat msol ad-bl vev-be c-vel bezrlag, vagy(!) db-nyit.
Amelyik elbb teljesl.
Vissza: pointer c-t kvet byte-ra
NULL, ha nem msolta c karaktert.

60.

char *memchr(puffer,c,db)
char *puffer;
/* honnan kezdden */
int c;
/* mit */
unsigned int db;
/* milyen hosszan */

Megkeresi puffer-ben az els db-nyi byte kztt a c karaktert (els


elfordulst).
Vissza: pointer a megtallt c-re
NULL, ha nincs.

61.

void movedata(si,oi,so,oo,db)
unsigned int si,oi;
/* input segment+offset */
unsigned int so,oo;
/* output segment+offset */
unsigned int db;
/* mennyit */

198

Byte-ok msolsa / db-nyit /. Far tpus adatok msolsra small s


medium modelleknl. Persze ms modellekben is hasznlhat. Figyelem:
csak IBM PC-k esetben van implementlva!
Vissza: semmi.
unsigned int FP_OFF(adress)
unsigned int FP_SEG(adress)
char far *adress;

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

/* tvoli mutat a memriacmre */

Szegmens s offszet adat generlsa.


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

far *ptr;
= (char far *) 0xB800 0000;
cast
szegmens offszet
rtkek

[Ez a szvegmd -sznes monitor ltal hasznlt memria kezdcme.]


Orisi blokkok alloklsa:
62. char huge *halloc(n,meret)

dekl.: malloc.h

long n; unsigned int mret;


Trterletet allokl n elem mret nagysg huge tpus tmbknek.
A terlet 0-val lesz feltltve.
Ha n*mret > 128K, akkor
mret = 2k (k=pozitv egsz hatvnykitev!).
A terlet a far heap-bl lesz levgva.
Vissza: huge mutat a memriaterlet elejre
NULL: nincs elg memria.
63. void hfree(p)

dekl.: malloc.h

char huge *p;


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

dekl.: malloc.h
/* mennyit */

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


terleten.
Vissza: pointer a terlet kezdetre
NULL: nincs elg memria.
65. void _ffree(fp)

dekl.: malloc.h

199

char far *fp;

/* mutat a memriablok kezdetre */

Felszabadtja az fp ltal megcmzett memriablokkot.


Vissza: semmi.

15.

plda /C2P15.C - kpments /

16.

plda /C2P16.C - kpments - feltlts /

Process-kezels:
---------------Ebben a rszben azokkal a fggvnyekkel ismerkednk meg, amelyek
lehetv teszik, hogy egy C programbl egy msik C programot,
vagy akr brmilyen ms binris programot indtsunk.
66. int system(parancs)
dekl.: process.h vagy
stdlib.h
char *parancs;
/* az indtand program neve */
Vgrehajtja a parancs-ban megadott nev parancsot. PC/MS-DOS vagy
aktulis op. rendszer-beli parancs. A COMMAND.COM-on keresztl
dolgozik. (UNIX: subshell-t tlt!)
Vissza: 0 - O.K.
1 - hiba, lsd errno-t.
67. void exit(stat)
stdlib.h
int stat;

dekl.: process.h vagy


/* visszatrsi kd */

Befejezi a program futtatst. Ha van hv program, akkor a stat als


byte-jt (stat & 0xFF) megkapja. Futs eltt befejezi az onexit
fggvnyeket, minden puffert rt, lezrja a file-okat. Figyelem:
main() vgn automatikusan exit(0) hajtdik vgre!
Vissza: semmi.
68. void _exit(stat)
int stat;
Azonnali lells
fggvny.

/* visszatrsi kd */
trlsek,

zrsok

nlkl!

Egybknt

mint

exit()

Vissza: semmi.
69. void abort()

dekl.: stdlib.h

Azonnali lells minden zrs, rts nlkl!


termination zenetet r ki. exit sttusz: -3.
70. onexit_t onexit(func)
onexit_t func;
/* kilp fggvny */

Abnormal

program

dekl.: stdlib.h

200

A fut program befejezsekor az elzleg belltott (onexit()-tel)


fggvnyeket LIFO elv szerint vgrehajtja. Kivve abort() s _exit()!
Vissza: pointer a fggvnyre!
NULL, ha nincs tbb hely a fggvny szmra.

17.
plda /C2P17.C - C2P17A.C - onexit /
typedef int (_CDECL*CEDCL onexit_t)();
Process hv utastsok:
/ Alap : process.h /
71.
int execl(name,arg0,arg1,...,argn,NULL)
72.
int execle(name,arg0,arg1,...,argn,NULL,env)
73.
int execlp(name,arg0,arg1,...,argn,NULL)
74.
int execlpe(name,arg0,arg1,...,argn,NULL,env)
75.
int execv(name,argv)
76.
int execve(name,argv,env)
77.
int execvp(name,argv)
72. int execvpe(name,argv,env)
Deklarcik:
-----------char
*name;
*/
char
*arg0,*arg1,...
*/
char *argv[];
*/
char *env[];
tmbje */

/*
/*
/*

program

pointerek

paramterekre

paramterek

egy

pointertmbben

/* krnyezeti stringekre mutat pointerek

Betltenek, s vgrehajtanak egy j gyerekfolyamatot. Ha a


mechanizmus j, akkor a hv helyre tltdik az j process.
adunk meg kiterjesztst, gy EXE-nek veszi. Ha viszont a nv
teht ponttal r vget, akkor nem tallja meg. Nv lehet akr
elrsi ttal is megadva.
Az execlp(), execlpe(), execvp() esetben a DOS
keresi a programot, ha az aktulisban nem tallta!
Paramterek:

neve

PATH-ban

hvsi
Ha nem
XXX.
teljes
vgig

arg0 = prog.nv (hvand)

egyttes paramterhossz: 128 byte


NULL, mint lezr ktelez.
Vissza: siker esetn semmi
HIBA: -1, lsd errno-1.
HIBK:
-----EZBIG
= 128-nl hosszabb paramterek
EACCESS = osztott elrsi problma
EMFILE = tl sok file van nyitva

201

ENOMEM = nincs elg memria


ENOEXEC = nem futtathat program
ENOENT = file, vagy path nem tallhat
Megjegyzs: krnyezeti rklds van, de a nyitott file-ok tviteli
mdja nem rzdik meg. A setmode() fggvny hasznlhat ekkor.
79.
80.
81.
82.
83.
84.
85.

int
int
int
int
int
int
int

spawnl(md,
spawnle(md,
spawnlp(md,
spawnv(md,
spawnve(md,
spawnvp(md,
spawnvpe(md,

} u.a. mint az exec...- nl

)
)
)
)
)
)
)

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


mkdst.
Md: szl-gyerek process kapcsolat
---P_WAIT
P_NOWAIT
P_OVERLAY

= szl vr, mg a gyerek fut!


= konkurrens vgrehajts.
= ngyilkos szl esete; megegyezik exec...-el!

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


1 HIBA, lsd errno-t

18.

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

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

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

( time.h-ban: typedef long time_t, / const = megvltoztathatatlan


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

/* ide trolja az idt numerikusan */

202

Vissza: NULL, ha nem sikerlt az rtket kpeznie!

19.
plda
/
segtsgvel /

C2P19.C

dtum

kiratsa

88. char *asctime(time)

time()

ctime()

dekl.: time.h

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

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

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

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

A 26 karakteres stringg konvertlja a struktrban megadott idt!


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

dekl.: time.h
*/
HH/NN/ formban.

Vissza: mutat a memriaterlet kezdetre.


90. char *_strtime(time)
char *time;

/* memria az idnek

Leteszi time-ba a gp aktulis idejt:

*/
/pp/mm formban.

Vissza: mutat a memriaterlet kezdetre.

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

Nhny rdekes beptett fggvny:


---------------------------------91. void qsort(base,num,width,comp)
dekl.: search.h
char *base;
/* rendezend adatok kezdcme
*/
unsigned int num;
/* rendezend adatok db. szma
*/
unsigned
int
width;
/*
egy
adat
hossza
*/
int (*comp)();
/* int-tel visszatr - hasonlt fggvnyre

203

mutat pointer
Rendezi az
hasznlja.

adatokat

memriban.

*/
A

QUICK-short

algoritmust

Vissza: semmi.
Hasonlt fggvny visszatrsi rtkei:
<0 -> elem1 < elem2
0 -> elem1 = elem2
>0 -> elem1 > elem2

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

92.
93.

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

char *lsearch(key,base,num,width,comp)
char *lfind(key,base,num,width,comp)
char *key;
/* keresend kulcs
char *base;
/* adathalmaz cme
unsigned int num;
/* adatok darabszma
unsigned int width; /* egy adat hossza
int (*comp)();
/* pointer a hasonlt fggvnyre

*/
*/
*/
*/
*/

Mindkt fggvny lineris keresst valst meg base adathalmazban


gy, hogy key kulcsot keresi.
Hasonlt fggvny visszatrsi rtkei:
0, akkor azonos az aktulis elem a keresend kulccsal (meg van!)
nem 0, akkor nem azonos
Sok kzl az elst adja vissza, ha nincs: NULL pointert ad.
Klmbsg: ha nincs a keresett kulcs, akkor a lsearch() fggvny az
adathalmaz vgre beilleszti a keresett kulcsot, s mdostja a num
pointer ltal mutatott db. szm rtket.
94.

char *bsearch(key,base,num,width,comp)
char *key;
/* keresend kulcs
char *base;
/* adathalmaz cme
unsigned int num;
/* adatok darabszma
unsigned int width; /* egy adat hossza
int (*comp)();
/* pointer a hasonlt fggvnyre

Binris
keresssel
keresi
rendezettnek kell lennie.

meg

key

kulcsot.

Az

*/
*/
*/
*/
*/
adatoknak

Hasonlt (comp) rutin visszatrsi rtkei:


<0 -> elem1 < elem2
0 -> elem1 = elem2
>0 -> elem1 > elem2

23.

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

204

24.

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

Rendszerkzeli programozs MS-DOS-ban:


-------------------------------------Ez a leginkbb gpfgg rsze a C-nek.
Kzvetlen ROM-BIOS fggvnyek illetve DOS interruptok hvsa
Regiszterkonvencis paramtertads
Alap: dos.h;
struct

itt vannak a regiszterek is definilva.

WORDREGS {

unsigned int ax; unsigned int bx; unsigned int cx; unsigned int
dx; unsigned int si; unsigned int di; unsigned int cflag;
}
struct

BYTEREGS {

unsigned char al,ah; unsigned char bl,bh; unsigned char cl,ch;


unsigned char dl,dh;
}
union

REGS

{
struct WORDREGS x;
struct BYTEREGS h;
}

Elfordulhat, hogy az ltalnos regiszterek mellett a szegmens


regisztereket is mdostani kell. Emiatt van deklarlva az albbi
struktra:
struct

SREGS

unsigned int es; unsigned int cs; unsigned int ss; unsigned int
ds;
}
Lssunk nhny fggvnyt:
------------------------95.

int int86(intn,inregs,outregs)
int intn;
/* az interrupt sorszma */
union REGS *inregs;
/* bemen regiszterek
*/
union REGS *outregs;
/* kimen regiszterek
*/

Vgrehajt egy 8086-os szoftver megszaktst, amelyet az intn hatroz


meg.
A megfelel regisztereket be kell lltani; hibakdokat a
megfelelekben
adja
vissza.
Ezeket
az
aktulis
DOS
verzi
kziknyvbl kell kinzni.
Vissza: AX tartalma hibakd
_doserrno (stdlib.h-ban) szintn hibakd
96. int intdos(inregs,outregs)

dekl.: dos.h

205

union REGS *inregs,*outregs;


A
DOS
0x21-es
rendszerhvst
aktivizl,
a
belltott
input
regisztereknek megfelelen. Az inregs.h.ah-ba a DOS funkci sorszma
tltend.
Vissza: AX tartalma hibakd
_doserrno (stdlib.h-ban) szintn hibakd
97.
int int86x(intn,inregs,outregs,segregs)
int intn;
union REGS *inregs,*outregs;
union SREGS *segregs;
/* szegmens
hvskor */
Hasonl
az
int86()-hoz,
szegmensregiszterek rtkt.

de

llthatjuk

regiszterek
az

ES

rtke
s

DS

Visszatrskor visszatlti DS eredeti rtkt s lltja cflag-et az


outregs-ben.
Vissza: AX regiszter
_doserrno-ban

rtke.

Ha

cflag

nem

egyenl

0-val,

akkor

hibakd.
98.
int intdosx(inregs,outregs,segregs)
union REGS *inregs,*outregs;
union SREGS *segregs;
DOS rendszerhvs hasonlan intdos()-hoz, de DS s ES regiszterek is
bellthatk. Egyebekben teljesen megegyeznek.

25.

plda / C2P25.C - interrupt kezels - kpernytrls /

26.

plda / C2P26.C
lekrdezse /

Van mg
nlkl.

nhny

lehetsg

interrupt

DOS

kezels

funkcik

elrsre,

DOS

rjnak

de

interrupt

Ezek:
_dos ....fggvnyek:
_dosallocmem
_dos_close
_dos_creat /0x3C/
_dos_creatnew /0x5B/
_dos_finfirst
_dos_findnext
_dos_freemem
_dos_getdate
_dos_getdiskfree

27.
_

_dos_getdrive
_dos_getfileattr
_dos_getftime
_dos_gettime
_dos_getvect
_dos_keep(!)
_dos_open
_dos_setdate
_dos_setdrive
stb...

plda / C2P27.C file-ok keresse /

206

fggvnyargumentumoknak lennik. Ha message-et


char *message;

207

You might also like