Professional Documents
Culture Documents
Kernighan Ritchie - C Könyv
Kernighan Ritchie - C Könyv
Kernighan Ritchie - C Könyv
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
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
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
\
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
termszetes
mretk
kielgtsre szolgl.
van;
tbbi
mret
specilis
ignyek
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
ki, s az eredmnyt
az eljrst szoksos
operandus
int-t
10
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
12
13
14
15
16
17
18
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
azonost
strukt._vagy_union:
struct
union
21
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
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
26
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
A continue utasts
continue;
utasts hatsra a vezrls a continue-t krlvev legbels
while, do vagy for utasts
ciklusfolytat
rszre addik
t,
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
29
30
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
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
34
35
csoportostsra
szavak
egszek
mrete,
osztsa
a
a
36
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
38
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
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
szavakat.
42
program
futtatsnak
43
zeneteket
fog
kldeni
bizonyos
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
is valamivel
/ * 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
48
while
(a
beolvasott
karakter
nem
az
{
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
{
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
kis
mdostsval
{
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()
{
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
51
kvetelmny kielgtse
feltnbb legyen.
miatt
szerepel.
Kln
sorba
rtuk,
hogy
{
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
{
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
56
{
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
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
sorokat
olvas
be
kzlk
{
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)
60
kivlasztsa;
{
int len; /*A pillanatnyi sor hossza*/
extern int max;
61
/* 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
63
(Ezt
programot
teljes
_
2.
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
65
/* 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
akkor
folytatjuk,
amikor
tovbbi
67
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
{
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
70
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++
amikor a program
az
s karakterlncban
72
bithalmaz
73
{
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
{
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
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) */
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
77
printf(.
.)
utastss
78
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
elgazst
(dntst)
meg. A gp sorban
ltalban
kirtkeli
ilyen
if-sorozattal
a kifejezseket. Ha
79
tiltott
felttel
figyelsvel
/*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
81
while
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
82
{
gap,
(gap
(i =
(j =
i , j, temp;
= n / 2; gap > 0; gap /= 2)
gap; i < n; i++)
i - gap; j >= 0
83
{
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;
{
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*/
{
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
pozitv
}
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
87
feladat
alapstruktrja
88
{
char line [MAXLINE];
while (getline (line, MAXLINE) > 0)
if (index (line, the) >= 0)
printf(%s, line);
}
getline (s, lim)
visszatrsi rtk a
sorhosszsg*/
char s []; int lim;
{
int c, i;
i = 0;
while (--lim > 0 && (c = getchar ()) != EOF && c != \n) s [i++]
= c; if (c == \n) s [i++] = c; s [i] = \0; return (i);
}
index (s, t)
1 , ha t nincs s-ben*/
char s [], t [];
{
int i, j, k;
for (i = 0; s [i] != \0; i++) {
for (j = i , k = 0; t [k] != \0
&& s [j] == t [k];j++ , k++)
;
if (t [k] == \0)
return (i);
}
return (-1);
}
Minden fggvny az albbi alak :
nv (argumentumlista, ha van)
argumentumdeklarcik, ha vannak
{
deklarcik s utastsok, ha vannak
}
Mint lthat,
fggvny :
dummy ()
fggvny
foglalni
tpusnv
rtkkel
klnfle
rszek
hinyozhatnak;
legrvidebb
89
90
esetek
tbbsgt
lefedtk,
belertve
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
92
93
94
{
if (sp < MAXVAL)
return (val [sp++] = f);
else {
printf (hiba: a verem megtelt\n);
clear ();
return (0);
}
}
double pop ()
{
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
97
98
99
azonban
definilhatunk
blokkstruktrlt
mdon.
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
{
int c, i, nwhite, nother;
int ndigit [10];
nwhite = nother = 0;
for (i = 0; i < 10; i++)
ndigit [i] = 0;
. . .
}
volt, ehelyett gy is rhat:
int nwhite = 0;
int nother = 0;
int ndigit [10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } ;
main ()
{
int c, i;
. . .
}
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
{
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*/
minden
sszes
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
hasznlhatnak.
Idzjelek kz
fel
105
ltre.
Az &
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
107
/*ROSSZ*/
{
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
109
{
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
{
if (allocp + n <= allocbuf + ALLOCSIZE) {
/*Befr*/ allocp += n;
ms vltoz,
noha kznsges
112
113
strlen (s)
{
char *p = s;
while (*p != \0)
p++;
return (p - s);
}
A deklarciban p kezdeti rtkeknt s-et adtuk meg, vagyis p
kezdetben az s els karakterre mutat. A while ciklusban addig
vizsgljuk az egymst kvet karaktereket, amg a vget jelz \0 el
nem kerl. Mivel \0 rtke nulla, s mivel a while csupn azt
vizsglja, hogy a kifejezs nulla-e, elhagyhat az explicit
vizsglat. Az ilyen ciklusokat gyakran az albbi alakban rjk:
while (*p) p++;
Minthogy p karakterekre mutat, p++ minden alkalommal a kvetkez
karakterre lpteti p-t, s p - s
az tlpett karakterek szmt,
vagyis
a
karakterlnc
hosszt
adja
meg.
A
mutataritmetika
kvetkezetes: ha float mennyisgekkel dolgoznnk, amelyek a 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
a
nem
114
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)
ltal
megcmzett
116
{
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
118
119
}
return (nlines);
}
A sorok vgn tallhat jsor karakterek
befolysoljk a rendezsi sorrendet.
writelines (lineptr, nlines)
trldnek,
gy
nem
120
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
/*Visszhangozza az argumentumokat
123
/*Visszhangozza az argumentumokat
/*Megkeresi az 1. argumentum
124
/*Megkeresi az 1. argumentum
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,
127
{
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
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
person {
130
(A
->
opertor
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:
key {
key {
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
134
{
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 ()
{
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
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
{
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)
138
{
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
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)
{
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
141
np->next
hashtab
142
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
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
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
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.
Minden
olyan
knyvtrbeli
forrsllomnynak,
amely
valamelyik
szabvnyos
vltozkat
definil.
<
>
knykzrjeleknek
7.2.
trtn
betltst.
(Az
A
legegyszerbb
karakterenknt
beviteli
mechanizmus
az,
amikor
getchar-ral
legtbb
olyan
krnyezetben,
amely
C-t
prog
az
infile-t
fogja
olvasni
terminl
kz.
Hasonl
helyzet,
ha
bemenet
147
illeti,
teszi,
putchar
ami
karaktert
alaprtelmezs
szerint
szabvnyos
szintn
szabvnyos
kimenett
az
anotherprog
szabvnyos
bemenetre
olyan
148
7.3.
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
az
eredmny
megfelel
argumentum
ltal
151
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
7.5.
argumentumokat,
az
eredmnyt
azonban
szabvnyos
ellenttes
irny
konverzikat
hozza
ltre
argl,
arg2
stb.-ben
helyezi
el.
Ezen
argumentumoknak
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
llomnyok
halmazt
gyjti
ki
(konkatenlja)
ltalnos
cl
bemeneti
informcigyjts
azon
Az
llomnymutat
szmra
szksges
egyetlen
154
155
/*
cat:
llomnyok
7.7.
156
/*
cat:
llomnyok
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.
157
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.
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
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));
159
164
160
_
8.
fejezet
8.1.
Allomnylerk
ltrehozsra
is.
rendszer
ellenrzi,
hogy
161
162
8.3.
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
164
R.4.
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
167
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
puffer
lefoglalsa
feltltse*/
174
170
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,
171
172
_ * A katalgusbejegyzs struktrja* _
173
#define S_IFMT
#define S
IFDIR
#define S_IFCHR
#define S_IFBLK
#defineS
IFREG
#define S
ISUID
vgre-
#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* _
174
fsize(name)
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
/*Nv helyrelltsa* _
175
176
}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
/*Elg nagy* I
/*Pontosan akkora* I
/* Nincs tbb* /
178
182
179
free(ap)
if (p+p-_s.size == q->s.ptr){
szddal*
>s.ptr;
p-7s.size
+=
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.
header file
1.
int getch()
2.
int getche()
3.
int ungetch
int c;
/* karakterkd */
4.
int ungetch(c,fptr)
int c;
/* karakter */
FILE *fptr; /* file-pointer */
181
5.
int kbhit()
6.
char *cgets(s)
char *s;
/* trcm az input adatok szmra */
7.
void cputs(s)
char *s;
/* a string kezdcme */
8.
int cprintf(...u.a....)
...u.a.... mint printf()-nl mr lttuk.
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
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])
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
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 */
184
11.
FILE *fopen(fazon,md)
char *fazon;
/* file azonostja */
char *md;
/* hasznlati md */
12.
FILE *freopen(fazon,md,fptr)
char *fazon;
/* j file azonostja */
char *md;
/* hasznlati md */
FILE *fptr;
/* rgi file pointer-re */
md
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()
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
18.
int putc(c,f)
char c;
/* Kirand karakter kdja */
FILE *f;
/* File-hoz tartoz pointer */
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 */
187
25.
int fputs(s,f)
char *s;
/* kirand string */
FILE *f;
/* file-t azonost pointer */
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 */
pozcitl)
db-nyi
mret
hosszsg
CR-LF.
27.
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 */
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()
34.
}
}
}
}
header file-ok
int open(nv,oflag[,md])
char *nv;
/* a file neve */
int oflag;
/* opercis kd */
int md;
/* hasznlati md */
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
190
Megjegyzsek:
O_TEXT default
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
- 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 */
38.
int read(fh,p,c)
int
fh;
/* file-handle szm */
char
*p;
/* mutat a pufferre */
unsigned int c;
/* olvasand byte-ok szma */
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
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 */
=
=
=
=
=
kompatibilis md lltsa
rs s olvass tiltsa
rs tiltsa
olvass tiltsa
rs/olvass is engedve
193
43.
int locking(fh,md,byte)
int fh;
/* file-handle szm */
int md;
/* zrolsi md */
long byte; /* lock-olt byte-ok szma */
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
/ dekl.: direct.h /
/* katalgus neve */
45.
int rename(rgi,j)
char *rgi;
/* a file rgi neve */
char *uj;
/* a file j neve */
46.
int unlink(file)
char *file;
/* a file neve */
/ 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 */
/ 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 */
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
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:
Stack:
STACK:
vltozk helye.
Adat:
_BSS:
vltozk.
CONST:
a programban, kivtel a
szvegkonstansok.
_DATA:
196
dekl.: malloc.h
/* byte-ok szma */
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 */
char *realloc(p,mret)
char *p;
unsigned int mret;
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:
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 */
58.
char *memset(puffer,kar,db)
char *puffer;
/* kezdcm */
int kar;
/* milyen karakterrel */
unsigned int db;
/* mennyit */
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 */
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
dekl.: dos.h
dekl.: dos.h
far *ptr;
= (char far *) 0xB800 0000;
cast
szegmens offszet
rtkek
dekl.: malloc.h
dekl.: malloc.h
dekl.: malloc.h
/* mennyit */
dekl.: malloc.h
199
15.
16.
Process-kezels:
---------------Ebben a rszben azokkal a fggvnyekkel ismerkednk meg, amelyek
lehetv teszik, hogy egy C programbl egy msik C programot,
vagy akr brmilyen ms binris programot indtsunk.
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;
/* visszatrsi kd */
trlsek,
zrsok
nlkl!
Egybknt
mint
exit()
Vissza: semmi.
69. void abort()
dekl.: stdlib.h
Abnormal
program
dekl.: stdlib.h
200
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
neve
PATH-ban
hvsi
Ha nem
XXX.
teljes
vgig
201
int
int
int
int
int
int
int
spawnl(md,
spawnle(md,
spawnlp(md,
spawnv(md,
spawnve(md,
spawnvp(md,
spawnvpe(md,
)
)
)
)
)
)
)
18.
Rendszerid kezelse:
--------------------86. char *ctime(tsec)
const time_t tsec;
dekl.: time.h
/* numerikus idrtk */
202
19.
plda
/
segtsgvel /
C2P19.C
dtum
kiratsa
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
*/
*/
*/
*/
*/
*/
*/
*/
*/
dekl.: time.h
*/
HH/NN/ formban.
/* memria az idnek
*/
/pp/mm formban.
20.
plda / C2P20.C - alkalmazzuk az _strdate() s az _strtime()
fggvnyeket /
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.
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
*/
*/
*/
*/
*/
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
23.
204
24.
WORDREGS {
unsigned int ax; unsigned int bx; unsigned int cx; unsigned int
dx; unsigned int si; unsigned int di; unsigned int cflag;
}
struct
BYTEREGS {
REGS
{
struct WORDREGS x;
struct BYTEREGS h;
}
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
*/
dekl.: dos.h
205
de
llthatjuk
regiszterek
az
ES
rtke
s
DS
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.
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...
206
207