You are on page 1of 299

C programnyelv 1

1BEVEZETS.................................................................................................................... 5
2JELLSEK.....................................................................................................................7
3ALAPISMERETEK..........................................................................................................8
3.1Forrsprogram............................................................................................................8
3.2Fordts...................................................................................................................... 8
3.3Kapcsolszerkeszts (link).................................................................................... 12
3.4Futtats.....................................................................................................................12
3.5Tblzat ksztse.................................................................................................... 13
3.6Bemenet, kimenet.................................................................................................... 21
3.7Tmbk....................................................................................................................28
3.8Fggvnyek.............................................................................................................. 31
3.9Prodzsekt................................................................................................................. 35
3.10Karaktertmb s karakterlnc................................................................................ 37
3.11Loklis, globlis s bels, kls vltozk..............................................................41
3.12Inicializls............................................................................................................ 46
4TPUSOK S KONSTANSOK......................................................................................49
4.1Elvlaszt-jel........................................................................................................... 50
4.2Azonost................................................................................................................. 51
4.3Tpusok s konstansok a nyelvben...........................................................................52
4.3.1Egsz tpusok s konstansok............................................................................. 55
4.3.2Felsorols (enum) tpus s konstans................................................................. 58
4.3.3Vals tpusok s konstans................................................................................. 61
4.3.4Karakter tpus s konstans................................................................................ 63
4.4Karakterlnc (string literal):.....................................................................................68
4.5Deklarci ...............................................................................................................71
4.5.1Elemi tpusdefinci (typedef).......................................................................... 75
5MVELETEK S KIFEJEZSEK................................................................................ 77
5.1Aritmetikai mveletek (+, -, *, / s %).....................................................................79
5.1.1Multiplikatv opertorok (*, / s %)..................................................................80
5.1.2Additv opertorok (+ s -)............................................................................... 83
5.1.3Matematikai fggvnyek...................................................................................83
5.2Relci opertorok ( >, >=, <, <=, == s !=)........................................................... 85
5.3Logikai mveletek ( !, && s ||)...............................................................................86
5.4Implicit tpuskonverzi s egszellptets...........................................................87
5.5Tpusmdost szerkezet......................................................................................... 89
5.6sizeof opertor......................................................................................................... 90
5.7Inkrementls (++), dekrementls (--) s mellkhats........................................... 91
5.8Bit szint opertorok ( ~, <<, >>, &, ^ s |).............................................................92
5.9Feltteles kifejezs ( ? :).......................................................................................... 96
5.10Hozzrendels opertorok..................................................................................... 98
5.11Hozzrendelsi konverzi....................................................................................100
5.12Vessz opertor................................................................................................... 101
5.13Mveletek prioritsa ........................................................................................... 102
6UTASTSOK............................................................................................................. 106
6.1sszetett utasts.................................................................................................... 106
6.2Cmkzett utasts.................................................................................................. 107
6.3Kifejezs utasts................................................................................................... 107
6.4Szelekcis utastsok............................................................................................. 108
6.5Itercis utastsok.................................................................................................111
6.6Ugr utastsok...................................................................................................... 116
2 TARTALOMJEGYZK S ELSZ
7ELFELDOLGOZ (PREPROCESSOR).................................................................. 119
7.1res (null) direktva...............................................................................................120
7.2#include direktva.................................................................................................. 121
7.3Egyszer #define makr........................................................................................ 121
7.4Elredefinilt makrk............................................................................................ 123
7.5#undef direktva..................................................................................................... 123
7.6Paramteres #define direktva................................................................................124
7.7Karaktervizsgl fggvnyek (makrk).................................................................125
7.8Feltteles fordts................................................................................................... 128
7.8.1A defined opertor.......................................................................................... 130
7.8.2Az #ifdef s az #ifndef direktvk...................................................................130
7.9#line sorvezrl direktva...................................................................................... 130
7.10#error direktva.................................................................................................... 131
7.11#pragma direktvk.............................................................................................. 132
8OBJEKTUMOK S FGGVNYEK......................................................................... 133
8.1Objektumok attribtumai....................................................................................... 133
8.1.1Trolsi osztlyok........................................................................................... 134
8.1.1.1Automatikus (auto, register) trolsi osztly........................................... 134
8.1.1.2Statikus (static, extern) trolsi osztly................................................... 137
8.1.2lettartam (lifetime, duration)........................................................................ 140
8.1.2.1Statikus (static vagy extern) lettartam.................................................... 140
8.1.2.2Loklis (auto vagy register) lettartam.................................................... 141
8.1.2.3Dinamikus lettartam............................................................................... 141
8.1.3Hatskr (scope) s lthatsg (visibility)...................................................... 141
8.1.3.1Blokk (loklis, bels) hatskr................................................................ 142
8.1.3.2Fggvny hatskr................................................................................... 142
8.1.3.3Fggvny prototpus hatskr..................................................................142
8.1.3.4Fjl (globlis, kls) hatskr..................................................................143
8.1.3.5Lthatsg................................................................................................ 143
8.1.3.6Nvterlet (name space).......................................................................... 144
8.1.4Kapcsolds (linkage).................................................................................... 144
8.2Fggvnyek............................................................................................................ 145
8.2.1Fggvnydefinci.......................................................................................... 146
8.2.1.1Trolsi osztly........................................................................................ 148
8.2.1.2A visszatrsi rtk tpusa........................................................................149
8.2.1.3Formlis paramterdeklarcik................................................................149
8.2.1.4A fggvny teste...................................................................................... 151
8.2.2Fggvny prototpusok................................................................................... 152
8.2.3Fggvnyek hvsa s paramterkonverzik.................................................. 155
8.2.4Nem szabvnyos mdostk, hvsi konvenci.............................................. 157
8.2.5Rekurzv fggvnyhvs..................................................................................159
9MUTATK.................................................................................................................. 161
9.1Mutatdeklarcik................................................................................................. 161
9.1.1Cm opertor (&)............................................................................................ 162
9.1.2Indirekci opertor (*).................................................................................... 163
9.1.3void mutat..................................................................................................... 164
9.1.4Statikus s loklis cmek................................................................................. 164
9.1.5Mutatdeklartorok.........................................................................................165
9.1.6Konstans mutat............................................................................................. 166
9.2Mutatk s fggvnyparamterek.......................................................................... 167
C programnyelv 3
9.3Tmbk s mutatk............................................................................................... 168
9.3.1Index opertor................................................................................................. 169
9.3.2Tmbdeklartor s nem teljes tpus tmb..................................................... 172
9.4Mutataritmetika s konverzi.............................................................................. 173
9.4.1sszeads, kivons, inkrementls s dekrementls..................................... 174
9.4.2Relcik.......................................................................................................... 175
9.4.3Feltteles kifejezs.......................................................................................... 175
9.4.4Konverzi....................................................................................................... 176
9.5Karaktermutatk.................................................................................................... 178
9.5.1Karakterlnc kezel fggvnyek.....................................................................178
9.5.2Vltoz paramterlista.................................................................................... 184
9.6Mutattmbk........................................................................................................186
9.7Tbbdimenzis tmbk......................................................................................... 187
9.7.1Vletlenszm genertor...................................................................................190
9.7.2Dinamikus memriakezels............................................................................ 192
9.8Tmbk, mint fggvnyparamterek..................................................................... 196
9.9Parancssori paramterek........................................................................................ 198
9.9.1Programbefejezs............................................................................................202
9.10Fggvny (kd) mutatk...................................................................................... 203
9.10.1atexit fggvny..............................................................................................206
9.10.2Tpusnv....................................................................................................... 208
9.11Tpusdefinci (typedef)...................................................................................... 209
9.12Ellenrztt bemenet............................................................................................. 211
10STRUKTRK S UNIK...................................................................................... 216
10.1Struktradeklarci ............................................................................................. 217
10.1.1Tpusdefinci............................................................................................... 219
10.2Struktratag deklarcik...................................................................................... 220
10.3Struktrk inicializlsa.......................................................................................222
10.4Struktratagok elrse..........................................................................................223
10.5Struktrk s fggvnyek.....................................................................................227
10.6nhivatkoz struktrk s dinamikus adatszerkezetek .......................................234
10.7Struktra trillesztse...........................................................................................240
10.8UNIK................................................................................................................ 242
10.8.1Unideklarcik............................................................................................243
10.9Bitmezk (bit fields)............................................................................................ 245
10.10Balrtk jobbrtk...........................................................................................247
10.11Nvterletek.......................................................................................................248
11MAGAS SZINT BEMENET, KIMENET...............................................................251
11.1Folyamok megnyitsa.......................................................................................... 251
11.2Folyamok pufferezse.......................................................................................... 252
11.3Pozcionls a folyamokban................................................................................ 255
11.4Bemeneti mveletek ............................................................................................257
11.5Kimeneti mveletek............................................................................................. 259
11.6Folyamok lezrsa............................................................................................... 260
11.7Hibakezels.......................................................................................................... 260
11.8Elre definilt folyamok...................................................................................... 264
11.8.1Bemenet az stdin-rl..................................................................................... 266
11.8.2Kimenet az stdout-ra..................................................................................... 270
11.9Egyb fggvnyek................................................................................................278
12IRODALOMJEGYZK............................................................................................. 280
4 TARTALOMJEGYZK S ELSZ
13FGGELK............................................................................................................... 281
13.1CHDEL.C............................................................................................................ 281
13.2EGYESIT.C......................................................................................................... 281
13.3HEXA.C...............................................................................................................282
13.4IKSZ.C................................................................................................................. 283
13.5INDEXEU.C........................................................................................................ 284
13.6JANI.C................................................................................................................. 285
13.7KOZEPRE.C........................................................................................................285
13.8LAPOZ.C............................................................................................................. 286
13.9NEVREND.C.......................................................................................................287
13.10PELDA18X.C.................................................................................................... 288
13.11PELDA18Y.C.................................................................................................... 289
13.12PELDA28X.C.................................................................................................... 291
13.13PLUSSZ.C......................................................................................................... 293
13.14ROTL.C............................................................................................................. 293
13.15STRMAKRO.C................................................................................................. 293
13.16STRMIN.C........................................................................................................ 294
13.17STRRV.C...........................................................................................................295
13.18STRSTRXT.C....................................................................................................296
13.19TOBBOSZL.C................................................................................................... 297
13.20XPLUSZOR.C................................................................................................... 297
Kedves Kollegina, Kollga!
A jegyzetet nnek ksztettem azrt, hogy referencia anyaga legyen a
Programozs trgyhoz.
Szeretnm a segtsgt ignybe venni abbl a clbl, hogy a jegyzet mi-
nl pontosabb, megbzhatbb legyen. pp ezrt arra krem, ha az olvass
sorn valamilyen magyartalansgba, nem elgsges magyarzatba vagy
uram bocs' hibba tkzne, jelezze vissza nekem!
Tnykedst elre megksznm.
Gyr, 2004. jlius Bauer Pter
(B609) Tel.: (96) 503400/3254 e-mail: bauer@sze.hu
C programnyelv 5
1 BEVEZETS
A Szchenyi Istvn Egyetem klnfle informatika szakjai s szakir-
nyai C programnyelvi jegyzetignyt hivatott kielgteni ez a dokumen-
tum. Az olvasrl felttelezi, hogy tisztban van a szmtstechnikai alap-
fogalmakkal [1]. Alapos strukturlt programozsi ismereteket szerzett, s
jratos az alapvet algoritmikus elemekben [2]. Jratos mr egy program-
nyelvben s fejleszt krnyezetben. Magyarn ismer, s kezel ilyen fogal-
makat, mint:
- Adatok, adattpusok s adatstruktrk.
- Konstansok, vltozk s azonostk.
- Vezrlsi szerkezetek: szekvencia, szelekci s iterci. Utastsok.
- Tmbk s sztringek (karakterlncok).
- Programszerkezeti elemek: eljrsok, fggvnyek, blokkok s prog-
rammodulok.
- Lncolt adatszerkezetek: listk s fk.
- Elemi bemeneti s kimeneti eszkzk, fjlok stb.
A C nyelvet tervezje, Dennis
Ritchie, a Bell Laboratriumban
fejlesztette ki az 1970es vek
vgn [4], s a UNIX opercis
rendszer programnyelvnek
sznta. Ezt a vltozatot jelli az
brn a K&R. A C nyelv ezt k-
veten praktikussga miatt sz-
les krben elterjedt. Sokan k-
sztettek sokfle C fordtt sajt,
vagy krnyezetk ignyeinek
megfelelen. A soksznsgben
amerikai nemzeti szabvnnyal
(ANSI) teremtettek rendet az
1980as vek vgn [5]. Az
ANSI C szabvnyt aztn Eurpban (ISO) is elfogadtk nhny vvel k-
sbb. Az brbl ltszik, hogy az ANSI C bvtette a K&R C halmazt.
Tovbbi trtneti ttekintshez a [4] s az [5] bevezet rszeit ajnl-
juk!
fordt
ANSI C
K & R
6 BEVEZETS S ALAPISMERETEK
Az brn a legbvebb C halmaz a fordt. Ha valamikor is valami-
lyen gondunk lenne azzal, hogy egy konkrt C utasts, mdost stb.
megfelele az ANSI C szabvnynak, akkor fordts eltt kapcsoljuk be az
integrlt programfejleszt rendszer egy menpontjval az ANSI C kom-
patibilis fordtst!
A C ltalnos cl programnyelv, mely tmrsgrl, hatkonysgrl,
gazdasgossgrl s portabilitsrl (hordozhatsgrl) ismert. Nem
tartalmaz tl sok vezrlsi szerkezetet. Bsges viszont az opertorkszle-
te, s tbb adattpus meglte jellemzi. Jl hasznlhat teht mszakitu-
domnyos, vagy akr adatfeldolgozsi problmk megoldsra.
A C elg alacsony szint hardver kzeli programnyelv is egyben,
hisz tervezje a UNIX opercis rendszert e nyelv segtsgvel ksztette
el nhny szz gpi kd utasts felhasznlsval. A C programok gyak-
ran ugyanolyan gyorsak, mint az ASSEMBLER nyelven kszltek, de j-
val knnyebben olvashatk s tarthatk karban.
Jegyzetnkben nem kvnunk elmerlni konkrt integrlt programfej-
leszt rendszerek, opercis rendszerek s processzorok rszleteinek tag-
lalsban. Teljes ltalnossgban azonban mg sem clszer a dolgokrl
beszlni, mert akkor ilyeneket kne mondani, mint:
- Kpezzk az opercis rendszernek megfelel vgrehajthat fjlt!
- Futtassuk a vgrehajthat fjlt az opercis rendszerben!
Ehelyett rgztsk azt, hogy fogalmainkkal az IBM PC kompatibilis sze-
mlyi szmtgpek terletn maradunk! Erre a gpcsaldra is rengeteg
cg ksztett C fordtt (compiler). Itt llapodjunk meg kt f gyrtnl: a
Borlandnl s a Microsoftnl! Az integrlt programfejleszt keretrendszer
legyen menvel irnythat, s ne parancssori paramterknt megadott kap-
csolkkal kelljen vezrelni a fordtt s a kapcsolszerkesztt (linker).
Az opercis rendszer szmunkra jobbra csak olyan szempontbl rde-
kes, hogy legyen karakteres szabvnyos bemenete (standard input), s l-
tezzen karakteres szabvny kimenete (standard output), valamint szabv-
nyos hibakimenete (standard error output). A szabvny bemenet alaprtel-
mezs szerint a billentyzet, a kimenetek viszont a karakteres zemmd
kpernyre, vagy a karakteres konzol ablakba dolgoznak. A karakteres
kperny, vagy konzol ablak felbontsa termszetesen vltoztathat, de
mi minden pldnl felttelezzk a 25 sorszor 80 oszlopot! A szabvny
kimeneteken a mindenkori aktulis pozcit kurzor jelzi.
C programnyelv 7
2 JELLSEK
Figyelem felkelts. Valamely kvetkeztets levonsa az eddigiek-
bl. Esetleg: merre tallhatk tovbbi rszletek a krdses tmval kap-
csolatban.
Lexiklis ismeretek taglalsa. Valamely folyamat pontosabb rszle-
tei. Egy fogalom preczebb defincija.
e Valamilyen arnylag knnyedn elkvethet, de nehezen lokalizl-
hat hiba.
` Egy alapvet, gy nevezett kl szably.
Forrsprogramok s kperny tartalmak szvege.
Valamilyen konkrtummal helyettestend szintaktikai egysg.
Kulcssz vagy valamilyen azonost.
A fogalom els elfordulsnak jellsre szolgl.
A megoldand feladatokat gy jelltk. Ha a feladat lersnak vgn
{nv.C} fjlazonost ll, akkor a FGGELKben ugyanezen fejezetc-
men megtallhat egy megolds programlista is.
8 BEVEZETS S ALAPISMERETEK
3 ALAPISMERETEK
3.1 Forrsprogram
Els kzeltsben induljunk ki abbl, hogy a C program (a forrsprog-
ram) fjlazonostjban C kiterjesztssel rendelkez, ASCII kd szveg-
fjl, mely elllthat, ill. mdosthat
- akrmilyen ASCII kd szvegszerkesztvel, vagy
- a programfejleszt rendszer beptett szvegszerkesztjvel.
Az ASCII kd szvegfjl sorokbl ll. Egy sorban a szveg sorbeli
karaktereinek ASCII kdjai kvetkeznek rendre az egyms utni bjtok-
ban. A sorhoz vgl mg kt, a soremelst ler bjt tartozik, melyekben
egy soremels (Line Feed 10) s egy kocsi vissza (Carriage Return 13)
vezrl karakter van.
e Vigyzni kell ASCII kd szvegfjlban a decimlisan 31 rtk
bjt hasznlatval, mert ez fjlvg jelzs a legtbb opercis rendszerben!
Ksztsk el els C programunkat, s mentsk el PELDA1.C nven!
/* PELDA1.C */
#include <stdio.h>
void main(void){
printf(Ez egy C program!\n); }
Fordtsuk le a programot, szerkesszk meg a vgrehajthat fjlt, s fut-
tassuk le!
A mindenki ltal gyantott vgeredmny az a kpernyn, hogy megjele-
nik a szveg, s a kvetkez sor elejn villog a kurzor:
Ez egy C program!
_
3.2 Fordts
A fordt sikeres esetben a forrsprogrambl egy vele azonos nev
(OBJ kiterjeszts) trgymodult llt el,
PELDA1.C

fordt

PELDA1.OBJ
1. bra: Fordts
s zeneteket jelentet meg tbbek kzt a hibkrl. A hibazenetek leg-
albb ktszintek:
- (fatlis) hibazenetek s
C programnyelv 9
- figyelmeztet zenetek.
e A (fatlis) hibkat, melyek jobbra szintaktikai jellegek, mindig ki-
javtja a programoz, mert korrekcijuk nlkl nem kszti el a trgymo-
dult a fordt. A figyelmeztet zenetekkel azonban, melyek sok esetben a
legslyosabb problmkat jelzik, nem szokott trdni, mert a fordt ltre-
hozza a trgymodult, ha csak figyelmeztet zenetekkel zrul a fordts.
A PELDA1.C programunk els sora megjegyzs (comment). A meg-
jegyzs rsszablya ltszik a sorbl, azaz:
- /* karakter prral kezddik s
- */ karakter prral vgzdik.
A megjegyzs tbb forrssoron t is tarthat, minden sorba is rhat egy,
st akr egy soron bell tbb is megadhat a szintaktikai egysgek kztt.
e Egyetlen tilos dolog van: a megjegyzsek nem gyazhatk egyms-
ba!
/* Ez a befoglal megjegyzs eleje.
/* Itt a begyazott megjegyzs. */
Ez meg a befoglal megjegyzs vge. */
Vegyk szre, hogy brmely hibs program rgtn hibtlann vlik,
ha /*ot tesznk az elejre, s a zr */t elfelejtjk megadni a tovbbi
forrsszvegben!
A fordtt egybeptettk egy specilis elfeldolgozval (preprocessor),
mely az igazi fordts eltt
- elhagyja a forrsszvegbl a megjegyzseket,
- vgrehajtja a neki szl direktvkat, s
- ezeket is elhagyja a forrsszvegbl.
PELDA1.C

elfeldolgoz
+
fordt

PELDA1.OBJ
2. bra: Fordts pontosabban
Az elfeldolgoz direktvk egy sorban helyezkednek el, s #tel kez-
ddnek. Pontosabban # kell, legyen a sor els nem fehr karaktere.
Fehr karakterek a szkz, a soremels, a lapdobs karakter, a vz-
szintes s a fggleges tabultor karakter. Meg kell emlteni, hogy a meg-
jegyzs is fehr karakternek minsl. A fehr karakterek szolglhatnak
10 BEVEZETS S ALAPISMERETEK
szintaktikai egysgek elvlasztsra, de a felesleges fehr karaktereket el-
veti a fordt.
A PELDA1.C programunk msodik sora egy #include direktva, mely-
nek hatsra az elfeldolgoz megkeresi s betlti a paramter szvegfjlt
a forrsszvegbe, s elhagyja belle ezt a direktvt.
A pillanatnyilag betltend szvegfjl, az stdio.h, H kiterjeszts. Az
ilyen kiterjeszts szvegfjlokat C krnyezetben fejfjloknak (header)
nevezik. A fejfjl egy tmval kapcsolatos adattpusok, konstansok defin-
ciit s a vonatkoz fggvnyek jellemzit tartalmazza.
Fedezzk fel, hogy az stdio a standard input output rvidtsbl
szrmazik, s gy lnyegben a szabvny kimenetet s bemenetet kapcsol-
tuk programunkhoz.
Nem volt mg sz arrl, hogy a paramter fjlazonost <> jelek k-
ztt ll! A <> jel pr tjkoztatja az elfeldolgozt, hogy milyen knyvt-
rakban keresse a szvegfjlt. A programfejleszt rendszer menpontjai
kzt van egy, melynek segtsgvel megadhatk a fejfjlok (include fj-
lok) keressi tjai. <fjlazonost> alak paramter hatsra az #include
direktva csak a programfejleszt rendszerben elrt utakon keresi a fjlt,
s sehol msutt.
PELDA1.C programunk harmadik s negyedik sora a main (f) fgg-
vny defincija. A fggvnydefinci szintaktikai alakja:
tpus fggvnynv(formlisparamterlista) { fggvnytest }
- A visszatrsi rtk tpusa void, mely kulcssz ppen azt jelzi, hogy
a fggvnynek nincs visszaadott rtke.
- A fggvnynv main. C krnyezetben a main az indt program.
- A formlisparamterlista mindig ()ben van. Pillanatnyilag itt is a
void kulcssz lthat, ami e helyt azt rgzti, hogy nincs formlis
paramter.
- A fggvnytestet mindig {}ben, gy nevezett blokk zrjelek-
ben, kell elhelyezni.
A { nyitja, a } zrja a blokkot (BEGIN s END). A { } prok ssze-
tartoznak. A } mindig a forrsszvegben t megelz {t zrja.
A forrsprogram tbb forrsmodulban (forrsfjlban) is elhelyezhe-
t. Vgrehajthat program ltrehozshoz azonban valamelyik forrsmo-
dulnak tartalmaznia kell a maint. Az indt program a vgrehajthat
C programnyelv 11
program belpsi pontja is egyben. Ez az a hely, ahova a memriba tr-
tnt betlts utn tadja a vezrlst az opercis rendszer.
Az indt programnak termszetesen a vgrehajthat program iga-
zi indtsa eltt el kell ltnia nhny ms feladatot is, s a programoz l-
tal rt mainbeli fggvnytest csak ezutn kvetkezik. A gyrtk az indt
programot rendszerint trgymodul (OBJ) alakjban szoktk rendelkezsre
bocstani.
A PELDA1.C programban a main fggvny teste egyetlen fggvnyh-
vs. A fggvnyhvs szintaktikja:
fggvnynv(aktulisparamterlista)
- A fggvnynv a printf, mely fggvny az aktulis paramtert
megjelenteti a szabvny kimeneten.
- A ()ben ll aktulisparamterlista egytag, s momentn egy
karakterlnc konstans.
A karakterlnc konstans rsszablya ltszik: idzjelek kz zrt
karaktersorozat. A karakterlnc konstanst a memriban meg kpzeljk
gy el, hogy a fordt a szveg karaktereinek ASCII kdjait rendre elhe-
lyezi egymst kvet bjtokban, majd vgl egy tiszta zrustartalm (min-
den bitje zrus) bjttal jelzi a karakterlnc vgt!
A pldabeli karakterlnc konstans vgn azonban van egy kis fur-
csasg: a \n!
Ha valaki ttanulmnyozza az ASCII kdtblt, akkor lthatja, hogy a
lehetsges 256 kdpozci nem mindegyikhez tartozik karakterkp. Em-
ltsk csak meg a szkz (32) alatti kdpozcikat, ahol az gy nevezett
vezrl karakterek is elhelyezkednek! Valahogyan azt is biztostania kell a
programnyelvnek, hogy ezek a karakterek, ill. a karakterkp nlkli kd-
pozcik is megadhatk legyenek. A C programnyelvben erre a clra az
gynevezett escape szekvencia (escape jelsorozat) szolgl.
Remlhetleg vilgoss vlt az elz okfejtsbl, hogy az escape
szekvencia helyfoglalsa a memriban egyetlen bjt!
Az escape szekvencia \ jellel kezddik, s ezutn egy karakter kvet-
kezik. A teljessg ignye nlkl felsorolunk itt nhnyat!
Escape szekvencia Jelents
\b visszatrls (back space)
\n soremels vagy j sor (line feed)
\r kocsi vissza (carriage return)
\t vzszintes tabultor (horizontal tab)
12 BEVEZETS S ALAPISMERETEK
\ egyetlen karakter
\\ egyetlen \ karakter
\0 karakterlnc zr bjt, melynek
minden bitje zrus
\ooo
az ok oktlis szmok
Vegyk szre, hogy ha idzjelet kvnunk a karakterlnc konstans-
ba rni, akkor azt csak \ mdon tehetjk meg! Ugyanez a helyzet az esca-
pe szekvencia kezdkaraktervel, mert az meg csak megkettzve kpez
egy karaktert! Lssuk mg be, hogy a \ooo alakkal az ASCII kdtbla br-
mely karaktere lerhat! Pldul a \012 azonos a \nnel, vagy a \060 a 0
szmjegy karakter.
A printf fggvnyhvs utn ll ; utastsvg jelzs.
PELDA1.C programunk utols fehr foltja a printf, mely egyike
a szabvnyos bemenet s kimenet fggvnyeinek.
3.3 Kapcsolszerkeszts (link)
A gyrtk a szabvny bemenet, kimenet s ms tmacsoportok fggv-
nyeinek trgykdjt statikus knyvtrakban (LIB kiterjeszts fjlokban)
helyezik el. Nevezik ezeket a knyvtrakat futsidej knyvtraknak (run
time libraries), vagy szabvny knyvtraknak (standard libraries) is. A
knyvtrfjlokbl a szksges trgykdot a kapcsolszerkeszt msolja
hozz a vgrehajthat fjlhoz. Lssuk brn is a szerkesztst!
PELDA1.OBJ
indt program
(OBJ)
knyvtrak (LIB)

kapcsol
szerkeszt

PELDA1.EXE
3. bra: Kapcsolszerkeszts
e A programfejleszt keretrendszerben a sikeres mkdshez bizo-
nyosan be kell lltani a statikus knyvtrfjlok (library) keressi tjait.
Azt is meg kell adni termszetesen, hogy hova kerljenek a fordts s a
kapcsolszerkeszts sorn keletkez kimeneti fjlok.
3.4 Futtats
A vgrehajthat fjl a parancssorbl azonostjnak begpelsvel indt-
hat. Valsznleg a programfejleszt rendszer menjben is van egy
pont, mellyel az aktulis vgrehajthat fjl futtathat.
Tbbnyire ltezik a hrom lpst (fordts, kapcsolszerkeszts s fut-
tats) egyms utn megvalst egyetlen menpont is.
C programnyelv 13
e Ha programunk kimenete nem lthat a kpernyn, akkor egy msik
menpont segtsgvel t kell vltani a felhasznli kpernyre (user scre-
en), vagy aktuliss kell tenni a futtatott vgrehajthat fjl programabla-
kt.
3.5 Tblzat ksztse
Ksztsk el a kvetkez forinteur tszmtsi tblzatot! Egy eur
pillanatnyilag legyen 244 forint 50 fillr!
Adatstruktra:
- A vltozk a vals tpus euron
kvl, mind egszek. also lesz a tar-
tomny als hatra, felso a tarto-
mny fels rtke, lepes a lpskz, s ft a ciklusvltoz.
Algoritmus:
- Deklarljuk a vltozkat!
- Elltjuk ket az eurotl eltekintve kezdrtkkel.
- Megjelentetjk a tblzat fejlc sort s az alhzst.
- Mkdtetjk a ciklust, mg ft <= felso.
- A ciklusmagban kiszmtjuk az aktulis euro rtket, megjelentet-
jk az sszetartoz ft euro rtkprt, s vgl lptetjk az ft cik-
lusvltozt.
Ksztsk el a programot!
/* PELDA2.C: Forint-eur tszmtsi tblzat */
#include <stdio.h>
void main(void){
int also, felso, lepes, ft; /* Deklarcik */
float euro;
also = 100; /* Vgrehajthat utastsok */
felso = 1000;
lepes = 100;
ft = also;
printf(" Forint| Eur\n"
"---------+---------\n");
while(ft <= felso){ /* Begyazott (bels) blokk */
euro = ft / 244.5;
printf("%9d|%9.2f\n", ft, euro);
ft = ft + lepes; } }
A PELDA2.Cbl kitnen ltszik a C fggvny szerkezete, azaz az
gy nevezett blokkszerkezet:
Forint Eur
100 0.41
200 0.82
300 1.23
. . . . . .
1000 4.09
14 BEVEZETS S ALAPISMERETEK
- Elbb a deklarcis utastsok jnnek a blokkbeli vltozkra. A C
szigor szintaktikj nyelv:
- elzetes deklarci nlkl nem hasznlhatk benne a vltozk, s
- kivtel nlkl deklarlni kell minden hasznlatos vltozt!
- Aztn a vgrehajthat utastsok kvetkeznek.
e A blokkszerkezet deklarcis s vgrehajthat rszre bontsa a C
ben szigor szintaktikai szably, azaz egyetlen vgrehajthat utasts sem
keveredhet a deklarcis utastsok kz, ill. a vgrehajthat utastsok
kztt nem helyezkedhet el deklarcis utasts. Termszetesen a vgre-
hajthat utastsok kz begyazott (bels) blokkban a szably jra kez-
ddik.
Vegyk szre a pldaprogramunk vgn elhelyezked begyazott
vagy bels blokkot! Figyeljk meg a main kt els sorban, hogy a dekla-
rcis utasts szintaktikja:
tpus azonostlista;
Az azonostlista azonostk sorozata egymstl vesszvel elvlasztva.
Megfigyelhet mg, hogy az azonostk kpzshez az angol bc
beti hasznlhatk fel!
Foglalkozzunk kicsit a tpusokkal!
Az int (integer) 16, vagy 32 bites, alaprtelmezs szerint eljeles (sig-
ned), fixpontos belsbrzols egsz tpus. Vegyk, mondjuk, a 16 bites
esetet! A legnagyobb, mg brzolhat pozitv egsz binrisan s decim-
lisan:
0111 1111 1111 1111
2
= 2
15
1 = 32767
A negatv rtkek kettes komplemens alakjban troltak. A legkisebb,
mg brzolhat rtk gy:
1000 0000 0000 0000
2
= 2
15
= 32768
Eljeltelen (unsigned) esetben nincsenek negatv rtkek. A szmbrzo-
lsi hatrok zrus s
1111 1111 1111 1111
2
= 2
16
1 = 65535
kzttiek.
Az elzk 32 bites esetre ugyanilyen knnyedn levezethetek!
C programnyelv 15
A float (floating point) 4 bjtos, lebegpontos belsbrzols vals t-
pus, ahol a mantissza s eljele 3 bjtot, s a karakterisztika eljelvel egy
bjtot foglal el. Az brzolsi hatrok: 3.4*10
-38
3.4*10
+38
. Ez a man-
tissza mret 6 7 decimlis jegy pontossgot tesz lehetv.
Nhny programfejleszt rendszer a lebegpontos knyvtrakat
(LIB) csak akkor kapcsolja be a kapcsolszerkeszt ltal keressnek al-
vethet knyvtrak kz, ha a programban egyltaln igny jelentkezik
valamilyen lebegpontos brzols, vagy mvelet elvgeztetsre.
A PELDA2.C vgrehajthat rsznek els ngy utastsa rtkads.
e Ki kell azonban hangslyozni, hogy a Cben nincs rtkad utas-
ts, csak hozzrendels opertor, s a hozzrendelsekbl azrt lesz utas-
ts, mert ;t rtunk utnuk.
A hozzrendelsre rgtn visszatrnk! Vegyk szre elbb az
egsz konstans rsszablyt! Elhagyhat eljellel kezddik, s ilyenkor
pozitv, s ezutn az egsz szm jegyei kvetkeznek.
A fejlc sort s az alhzst egyetlen printf fggvnyhvssal valstot-
tuk meg. Ltszik, hogy a tblzat oszlopait 9 karakter szlessgre vlasz-
tottuk.
Figyeljk meg, hogy a pontos pozcionlst segtend a fejlc sort
s az alhzst a printfben kt egyms al rt karakterlnc konstansknt
adtuk meg!
A C fordt a csak fehr karakterekkel elvlasztott karakterlnc
konstansokat egyesti egyetlen karakterlnc konstanss, s gy a pldabeli
printfnek vgl is egyetlen paramtere van.
A PELDA2.Cben az elltesztel ciklusutasts kvetkezik, melynek
szintaktikja:
while(kifejezs) utasts
A kifejezs aritmetikai, azaz szmrtk. Az elltesztel ciklusutasts ha-
tsra lpsenknt a kvetkez trtnik:
1. Kirtkeli a fordt a kifejezst. Ha hamis (zrus), akkor vge a cik-
lusnak, s a while-t kvet utasts jn a programban.
2. Ha a kifejezs igaz (nem zrus), akkor az utasts vgrehajtsa, s
aztn jbl az 1. pont kvetkezik.
Vilgos, hogy a kifejezs rtknek valahogyan vltoznia kell az
utastsban, klnben a ciklusnak soha sincs vge. Az utasts llhat tbb
utastsbl is, csak {}be kell tenni ket. A {}ben ll tbb utastst
16 BEVEZETS S ALAPISMERETEK
sszetett utastsnak nevezik. Az sszetett utasts szintaktikailag egyet-
len utastsnak minsl.
A PELDA2.Cben a while kifejezse relci. A relcijelek a szokso-
sak: kisebb (<), kisebb egyenl (<=), nagyobb (>) s nagyobb egyenl
(>=). A relci kt lehetsges rtke: az igaz s a hamis logikai rtk. A
Cben azonban nincsen logikai adattpus, gy az igaz az 1 egsz rtk, s
a zrus a hamis.
A pldabeli bels blokk els s utols utastsa hozzrendels, melynek
szintaktikai alakja:
objektum = kifejezs
A hozzrendels opertor (mveleti jel) bal oldaln valami olyan objek-
tumnak kell llnia, ami rtket kpes felvenni. A szaknyelv ezt mdost-
hat balrtknek nevezi. Pldnkban az sszes hozzrendels bal oldaln
egy vltoz azonostja ll. Az = jobb oldaln meghatrozhat rtk ki-
fejezsnek (jobbrtknek) kell helyet foglalnia. A hozzrendels hatsra a
kifejezs rtke - esetlegesen az objektum tpusra trtnt konverzi utn -
fellrja az objektum rtkt. Az egsz konstrukci rtke az objektum
j rtke, s tpusa az objektum tpusa.
A legutbbi mondat azt clozza, hogy ha a hozzrendels kifejezs
rsze, akkor ez az rtk s tpus vesz rszt a kifejezs tovbbi kirtkel-
sben.
A begyazott blokkbeli kt hozzrendels kifejezse aritmetikai. Az arit-
metikai mveleti jelek a szoksosak: sszeads (+), kivons (), szorzs
(*) s az oszts (/).
Vegyk szre, hogy az eddigi printf fggvnyhvsainknak egyetlen
karakterlnc konstans paramtere volt, mely vltozatlan tartalommal je-
lent meg a karakteres kpernyn! A bels blokkbeli printfben viszont
hrom aktulis paramter van: egy karakterlnc konstans, egy int s egy
float. A gond ugye az, hogy az int s a float paramter rtkt megjelen-
tets eltt karakterlncc kne konvertlni, hisz binris bjtok kpernyre
vitelnek semmifle rtelme nincs!
A printf els karakterlnc paramtere
- karakterekbl s
- formtumspecifikci kbl
ll. A karakterek vltozatlanul jelennek meg a kpernyn, a formtumspe-
cifikcik viszont meghatrozzk, hogy a printf tovbbi paramtereinek
C programnyelv 17
rtkeit milyen mdon kell karakterlncc alaktani, s aztn ezt hogyan
kell megjelentetni.
A formtumspecifikci % jellel indul s tpuskarakterrel zrul. A for-
mtumspecifikcik s a printf tovbbi paramterei balrl jobbra haladva
rendre sszetartoznak. St ugyanannyi formtumspecifikci lehet csak,
mint ahny tovbbi paramter van.
Felsorolunk nhny tpuskaraktert a kvetkez tblzatban:
Tpuskarakter A hozztartoz
paramter tpusa
Megjelents
d egsz tpus decimlis egszknt
f lebegpontos tizedes trt alakjban
c egy karakter karakterknt
s karakterlnc karakterlncknt
A formtumspecifikci pontosabb alakja:
%<szlessg><.pontossg>tpuskarakter
A <>be ttel az elhagyhatsgot hivatott jelezni. A szlessg annak a
meznek a karakteres szlessgt rgzti, amiben a karakterlncc konver-
tlt rtket alaprtelmezs szerint jobbra igaztva, s balrl szkzfeltl-
tssel kell megjelentetni. Ha a szlessget elhagyjuk a formtumspecifi-
kcibl, akkor az adat a szksges szlessgben jelenik meg. Maradjunk
annyiban pillanatnyilag, hogy a pontossg lebegpontos esetben a tizedes
jegyek szmt hatrozza meg!
Lssuk be, hogy a "%9d|%9.2f\n" karakterlnc konstansbl a %
9d s a %9.2f formtumspecifikcik, mg a | s a \n sima karakterek!
Vegyk szre, hogy a nagy pozcionlgats helyett tblzatunk fejlc
sornak s alhzsnak megjelentetst gy is rhattuk volna:
printf("%9s|%9s\n---------+---------\n",
"Forint", "Eur");
Foglalkoznunk kell mg egy kicsit a mveletekkel! Vannak
- egyoperandusos (opertor operandus) s
- ktoperandusos (operandus opertor operandus)
mveletek. Az egyoperandusos opertorokkal kevs problma van. Az
eredmny tpusa tbbnyire egyezik az operandus tpusval, s az rtke az
operandus rtkn vgrehajtva az opertort. Pldul: vltoz. Az ered-
mny tpusa a vltoz tpusa, s az eredmny rtke a vltoz rtknek
1szerese.
18 BEVEZETS S ALAPISMERETEK
Problmk a ktoperandusos mveleteknl jelentkezhetnek, s ha-
nyagoljuk el a tovbbiakban az eredmny rtkt! Ha ktoperandusos m-
veletnl a kt operandus tpusa azonos, akkor az eredmny tpusa is a k-
zs tpus lesz. Ha a kt operandus tpusa eltr, akkor a fordt a rvidebb,
pontatlanabb operandus rtkt a hosszabb, pontosabb operandus tpusra
konvertlja, s csak ezutn vgzi el a mveletet. Az eredmny tpusa ter-
mszetesen a hosszabb, pontosabb tpus. A ft/244.5 osztsban a ft
egsz tpus s a 244.5 konstans lebegpontos. A mvelet elvgzse
eltt a ft rtkt lebegpontoss alaktja a fordt, s csak ezutn hajtja
vgre az osztst. Az eredmny teht ugyancsak lebegpontos lesz. Ezt
implicit tpuskonverzinak nevezik.
Vegyk szre kzben a vals konstans rsszablyt is! Elhagyhat
eljellel kezddik, amikor is pozitv, s aztn az egsz rsz jegyei jnnek.
Aztn egy tizedespont utn a trt rsz szmjegyei kvetkeznek.
e A problma a ms nyelv programoz szmra egszek osztsnl
jelentkezik, hisz egszek osztsnak eredmnye is egsz, s nincs semmi-
fle maradkmegrzs, lebegpontos talakts!
Ttelezzk fel, hogy 50 fillrrel cskkent az eur rfolyama! Alakt-
suk csak t az euro=ft/244.5 hozzrendelst euro=ft/244re, s
rgtn lthatjuk, hogy az eredmnyekben sehol sincs trt rsz!
Felvetdik a krds, hogyan lehetne ilyenkor a helyes rtket meg-
hatrozni? A vlasz: explicit tpusmdosts segtsgvel, melynek szin-
taktikai alakja:
(tpus)kifejezs
Hatsra a kifejezs rtkt tpus tpusv alaktja a fordt. A konkrt
esetben az oszts legalbb egyik operandust floatt kne mdostani, s
ugye akkor a ktoperandusos mveletekre megismert szably szerint a
msik operandus rtkt is azz alaktan a fordt a mvelet tnyleges el-
vgzse eltt, azaz:
euro = (float)ft / 244;
Megoldand feladatok:
Ksztsen programot, mely a kperny 21 sorszor 21 oszlopos terletn
a csillag karakter felhasznlsval megjelentet:
- Egy keresztet a 11. sor s 11. oszlop feltltsvel! {PLUSSZ.C}
- A ftlt (bal fels sarokbl a jobb alsba ment)!
- A mellktlt (a msik tlt)!
C programnyelv 19
- Egyszerre mindkt tlt, azaz egy X-et! {IKSZ.C}
A forinteur tszmtsi tblzatot elkszt PELDA2.C megold-
sunkkal az a baj, hogy tl sok vltozt hasznlunk. Knnyen belthat-
juk, hogy az fttl eltekintve a tbbi vltoz nem is az, hisz a program fu-
tsa alatt nem vltoztatja meg egyik sem az rtkt!
Ksztsnk PELDA3.C nven egy jobb megoldst!
/* PELDA3.C: Forint-eur tszmtsi tblzat */
#include <stdio.h>
void main(void){
int ft;
printf("%9s|%9s\n---------+---------\n",
"Forint", "Eur");
for(ft=100; ft<=1000; ft=ft+100)
printf("%9d|%9.2f\n", ft, ft/244.5); }
PELDA3.C programunkban kt j dolog lthat. Az egyik a
for(<initkifejezs>; <kifejezs>; <lptetkifejezs>) utasts
elltesztel, iteratv ciklusutasts, melynek vgrehajtsa a kvetkez l-
psek szerint trtnik meg:
1. A fordt vgrehajtja az initkifejezst, ha van. Az elhagyhatsgot
most is <> jelekkel szemlltetjk!
2. Kirtkeli a kifejezst. Ha hamis (zrus), akkor vge a ciklusnak, s a
for-t kvet utasts jn a programban. Lthat, hogy a szintaktika
szerint ez a kifejezs is elhagyhat. Ilyenkor 1nek (igaznak) min-
sl.
3. Ha a kifejezs igaz (nem zrus), akkor az utasts vgrehajtsa jn.
Az utasts most is lehetne sszetett utasts is!
4. Vgl az ugyancsak elhagyhat lptetkifejezs, majd jbl a 2.
pont kvetkezik.
Ha a for utastst while-lal szeretnnk felrni, akkor azt gy tehetjk
meg:
<initkifejezs>;
while(kifejezs) { utasts; <lptetkifejezs>; }
A szintaktikai szablyt sszefoglalva: a for-bl akr mindegyik kife-
jezs is elhagyhat, de az els kettt zr pontosvesszk nem!
A PELDA3.C programbeli msik j dolog az, hogy a printf aktulis
paramtereknt kifejezs is megadhat.
20 BEVEZETS S ALAPISMERETEK
A PELDA3.C ugyan sokat rvidlt, de ezzel a megoldssal meg az
a problma, hogy tele van varzskonstansokkal. Ha megvltoztatnnk t-
szmtsi tblzatunkban a tartomny als, ill. fels hatrt, mdostannk
a lpskzt, vagy az eur rfolyamot, akkor ennek megfelelen t kellene
rnunk varzskonstansainkat is. Az ilyen trogats 8 soros programnl
knnyen, s remlhetleg hibamentesen megvalsthat. Belthat azon-
ban, hogy nagymret, esetleg tbb forrsfjlbl ll szoftver esetben,
amikor is a varzskonstansok rengeteg helyen elfordulhatnak, ez a
mdszer megbzhatatlan, vagy legalbb is nagyon hibagyans.
A C a problma megoldsra a szimbolikus konstansok, vagy ms meg-
nevezssel: egyszer makrk, hasznlatt javasolja. A metdus a kvetke-
z:
1. Definilni kell a benne hasznlatos szimbolikus llandkat egy he-
lyen, egyszer, a forrsfjl elejn.
2. Aztn a programban vgig a konstansok helyett szisztematikusan a
szimbolikus konstansokat kell hasznlni.
A vltoztats is nagyon egyszerv vlik gy:
- a megvltozott konstans rtkt egy helyen t kell rni, s
- a tbbi felhasznlsa automatikusan mdosul a kvetkez fordts-
nl.
A szimbolikus lland a
#define azonost helyettestszveg
elfeldolgoz direktvval definilhat. A szimbolikus lland tulajdon-
kppen az azonost a direktva helytl a forrsszveg vgig van r-
vnyben. Az elfeldolgoz kihagyja a direktvt a forrsszvegbl, majd
vgigmegy rajta, s az azonost minden elfordulst helyettestszveg-
re cserli.
Lssuk a medvt!
/* PELDA4.C: Forint-eur tszmtsi tblzat */
#include <stdio.h>
#define ALSO 100 /* A tartomny als hatra */
#define FELSO 1000 /* A tartomny fels rtke */
#define LEPES 100 /* A lpskz */
#define ARFOLYAM 244.5 /* Ft/eur rfolyam */
void main(void){
int ft;
printf( "%9s|%9s\n---------+---------\n",
"Forint", "Eur");
for(ft=ALSO; ft<=FELSO; ft=ft+LEPES)
printf("%9d|%9.2f\n", ft, ft/ARFOLYAM); }
C programnyelv 21
Szoks mg klnsen tbb forrsmodulos esetben a #define direk-
tvkat (s mg ms dolgokat) kln fejfjlban elhelyezni, s aztn ezt min-
den forrsfjl elejn #include direktvval bekapcsolni.
Ksztsk csak el ezt a varicit is!
/* BEGEND.H: Fejfjl az tszmtsi tblhoz */
#include <stdio.h>
#define ALSO 100 /* A tartomny als hatra */
#define FELSO 1000 /* A tartomny fels rtke */
#define LEPES 100 /* A lpskz */
#define ARFOLYAM 244.5 /* Ft/eur rfolyam */
#define begin { /* {} helyett begin-end! */
#define end }
#define then /* if utastsban then! */
#define LACI for /* Kulcsszavak tdefinilsa
nem javasolt! */
/* PELDA5.C: Forint-eur tszmtsi tblzat */
#include "BEGEND.H"
void main(void)
begin
int ft;
printf("%9s|%9s\n---------+---------\n",
"Forint", "Eur");
LACI(ft=ALSO; ft<=FELSO; ft=ft+LEPES)
printf("%9d|%9.2f\n", ft, ft/ARFOLYAM);
end
Vegyk szre, hogy az #include direktva fjlazonostja nem <>k,
hanem k kztt ll! Ennek hatsra az elfeldolgoz a megadott azo-
nostj fjlt elszr az aktulis mappban abban a knyvtrban, ahol az
a .C fjl is elhelyezkedik, melyben a #include direktva volt keresi. Ha
itt nem tallja, akkor tovbbkeresi a programfejleszt rendszerben bell-
tott utakon.
3.6 Bemenet, kimenet
A kiss lergott csont forinteur tszmtsi tblzatos pldnkban
nem volt bemenet. Megtanultuk mr, hogy a szabvny bemenet s kime-
net hasznlathoz be kell kapcsolni az STDIO.H fejfjlt:
#include <stdio.h>
Alaprtelmezs szerint szabvny bemenet (stdin) a billentyzet, s
szabvny kimenet (stdout) a kperny. A legtbb opercis rendszerben
azonban mindkett tirnythat szvegfjlba is.
Egy karaktert olvas be a szabvny bemenetrl az
int getchar(void);
22 BEVEZETS S ALAPISMERETEK
fggvny. Ezt aztn balrl zrus feltltssel intt tpusmdostja, s
visszaadja a hvnak.
Azt, ahogyan az elbb a getchart lertuk, fggvny prototpusnak
nevezik. A fggvny prototpus teljes formai informcit szolgltat a
szubrutinrl, azaz rgzti:
- a fggvny visszatrsi rtknek tpust,
- a fggvny nevt,
- paramtereinek szmt, sorrendjt s tpust.
A getchar fjl vgn, vagy hiba esetn EOFot szolgltat.
Az EOF az STDIO.H fejfjlban definilt szimbolikus lland:
#define EOF (1)
Tekintsk csak meg az STDIO.H fejfjlban! Nzegets kzben vegyk
azt is szre, hogy a fejfjl tele van fggvny prototpusokkal.
Mr csak az a krds maradt, hogy mi a fjlvg a szabvny bemene-
ten, ha az a billentyzet? Egy opercis rendszertl fgg billentykombi-
nci: Ctrl+Z vagy Ctrl+D.
A paramter karaktert kiviszi a szabvny kimenet aktulis pozcijra az
int putchar(int k);
s sikeres esetben vissza is adja ezt az rtket. A hibt pp az jelzi, ha a
putchar szolgltatta rtk eltr ktl.
Ksztsnk programot, ami a szabvny bemenetet tmsolja a szabvny
kimenetre!
/* PELDA6.C: Bemenet msolsa a kimenetre */
#include <stdio.h>
void main(void){
int k;
printf("Bemenet msolsa a kimenetre:\n"
"Gpeljen Ctrl+Z-ig sorokat!\n\n");
k=getchar();
while(k!=EOF){
if(k!=putchar(k))
printf("Hiba a kimeneten!\n");
k=getchar(); } }
Fogalmazzuk meg minimlis elvrsainkat egy programmal szemben!
` A szoftver indulsakor jelezze ki, hogy mit csinl!
C programnyelv 23
Ha valamilyen eredmnyt kzl, akkor azt lssa el tjkoztat szveg-
gel, mrtkegysggel stb.!
Ha valamit bekr, akkor tjkoztasson rla, hogy mit kell megadni, mi-
lyen egysgben stb.!
A bemenet ellenrzend! A hibs adat helyett a hiba okt esetleg kije-
lezve azonnal krjen jat a program!
A <, <=, >, >= relcijelekrl mr sz volt! A Cben != a nem egyenl
opertor s == az egyenl mveleti jel. Az == s a != radsul a tbbi re-
lcinl eggyel alacsonyabb prioritsi szinten foglal helyet. Kifejezs kir-
tkelse kzben elbb a magasabb priorits mveletet vgzi el a fordt,
s csak aztn kvetkezik az alacsonyabb.
eVigyzat! Az egyenl relcit az egyms utn rt, kt egyenlsg jel
jelzi. Az egyetlen egyenlsg jel a hozzrendels opertor!
A ktirny szelekci szintaktikai alakja:
if(kifejezs) utasts1
<else utasts2>
Az elhagyhatsgot most is a <> jelzi. Ha a kifejezs igaz (nem zrus), ak-
kor utasts1 vgrehajtsa kvetkezik. Ha a kifejezs hamis (zrus) s van
else rsz, akkor az utasts2 kvetkezik. Mindkt utasts sszetett utas-
ts is lehet.
A PELDA6.C megoldsunk tlzottan nem C z. Cben programunk
utols 5 sort gy kne megrni:
while((k=getchar())!=EOF)
if(k!=putchar(k))
printf("Hiba a kimeneten!\n");
A while kifejezse egy nem egyenl relci, melynek bal oldali ope-
randusa egy kln zrjelben ll hozzrendels. Elbb a hozzrendels
jobb oldalt kell kirtkelni. Lssuk csak sorban a kirtkels lpseit!
1. Meghvja a getchar fggvnyt a fordt.
2. A visszakapott rtkkel fellrja k vltoz rtkt.
3. A getchartl kapott rtket hasonltja EOFhoz.
eA kifejezsbl a hozzrendels krli kln zrjel nem hagyhat el,
mert a hozzrendels alacsonyabb priorits mvelet a relcinl. Ha
mgis elhagynnk, akkor a kirtkels sorn a fordt:
1. Meghvn elbb a getchar fggvnyt.
24 BEVEZETS S ALAPISMERETEK
2. A visszatrsi rtket hasonltan EOFhoz. Teht kapna egy logi-
kai igaz (1), vagy hamis (0) rtket!
3. A k vltoz felvenn ezt az 1, vagy 0 rtket.
Figyeljk meg a PELDA6.C futtatsakor, hogy a getchar a beme-
netrl olvasott karaktereket az opercis rendszer billentyzet pufferbl
kapja! Emlkezznk csak vissza! A parancssorban a begpelt szveget
szerkeszthetjk mindaddig, mg Entert nem nyomunk. A billentyzet
pufferben lev karakterek teht csak akkor llnak a getchar rendelkezs-
re, ha a felhasznl lettte az Enter billentyt.
Ksztsnk programot, mely fjlvgig leszmllja, hogy hny
- numerikus karakter,
- fehr karakter,
- ms egyb karakter s
- sszesen hny karakter
rkezett a szabvny bemenetrl!
Megoldsunkban az sszes vltoz egsz tpus. k tartalmazza a beolva-
sott karaktert. A num, a feher s az egyeb szmllk. Az algoritmus:
- Deklarljuk a vltozkat, s az sszes szmllt lssuk el zrus kez-
drtkkel!
- Jelentessk meg a program cmt, s tjkoztassunk a hasznlatrl!
- Mkdtessk addig a ciklust, mg EOF nem rkezik a bemenetrl!
- A ciklusmagban hromirny szelekci segtsgvel el kell gazni a
hrom kategria fel, s ott meg kell nvelni eggyel a megfelel
szmllt!
- A ciklus befejezdse utn megjelentetendk a szmllk rtkei
megfelel tjkoztat szvegekkel, s az is, hogy sszesen hny ka-
rakter rkezett a bemenetrl!
/* PELDA7.C: A bemenet karaktereinek
leszmllsa kategrinknt */
#include <stdio.h>
void main(void){
short k, num, feher, egyeb;
num=feher=egyeb=0;
printf("Bemeneti karakterek leszmllsa\n"
"kategrinknt EOF-ig, vagy Ctrl+Z-ig.\n");
while((k=getchar())!=EOF)
C programnyelv 25
if(k>='0'&&k<='9')++num;
else if(k==' '||k=='\n'||k=='\t')++feher;
else ++egyeb;
printf("Karakter szmok:\n"
"----------------\n"
"numerikus: %5hd\n"
"fehr: %5hd\n"
"egyb: %5hd\n"
"----------------\n"
"ssz: %10ld\n",
num, feher, egyeb,
(long)num+feher+egyeb); }
Pontostani kell a deklarcis utasts eddig megismert szintaktikjt!
<tpusmdostk> <alaptpus> azonostlista;
Az elhagyhat alaptpus alaprtelmezs szerint int. Az ugyancsak elhagy-
hat tpusmdostk az alaptpus valamilyen jellemzjt vltoztatjk meg.
int tpus esetn:
- Az egsz alaprtelmezs szerint eljeles (signed), s lehetne mg
eljeltelen (unsigned). A signed s az unsigned mdostk egy-
mst kizrak.
- Kt, egymst kizr hosszmdostval az egsz belsbrzolsa
- bizonyosan 16 bites (short), ill.
- biztos 32 bites (long).
Vgl is a klnfle int tpusok mretei gy sszegezhetk:
short <= int <= long
Vegyk szre, hogy az ismertetett szablyok szerint a short, a short
int s a signed short int azonos tpusok. A short s a short int rsmd-
nl figyelembe vettk, hogy signed az alaprtelmezs. A short felrsakor
mg arra is tekintettel voltunk, hogy a meg nem adott alaptpus alaprtel-
mezse int. Ugyanezek mondhatk el a long, a long int s a signed long
int vonatkozsban is.
e Ugyan a szintaktika azt mutatja, de a deklarcis utastsban a t-
pusmdostk s az alaptpus egyszerre nem hagyhatk el!
Feltve, hogy a, b s c balrtkek, az
a=b=c=kifejezs
rtelmezse megint abbl fakad, hogy a hozzrendels a Cben opertor,
azaz:
a=(b=(c=kifejezs))
26 BEVEZETS S ALAPISMERETEK
A fordt jobbrl balra halad, azaz kirtkeli a kifejezst, s vissza-
fel jvet berja az eredmnyt a balrtkekbe.
A konstrukci hatsra a fordt gyorsabb kdot is hoz ltre. Ugyan-
is a
c=kifejezs;
b=kifejezs;
a=kifejezs;
rsmdnl hromszor kell kirtkelni ugyanazt a kifejezst.
Cben a tbbg (N) szelekcira az egyik kdolsi lehetsg:
if(kifejezs1)utasts1
else if(kifejezs2)utasts2
else if(kifejezs3)utasts3
/* . . . */
else utastsN
Ha valamelyik if kifejezse igaz (nem zrus) a konstrukciban, akkor a
vele azonos sorszm utasts vgrehajtsa kvetkezik, majd a konstruk-
cit kvet utasts jn. Ha minden kifejezs hamis (zrus), akkor viszont
utastsN hajtand vgre.
Fedezzk fel a karakter konstans rsszablyt: aposztrfok kztt
karakter, vagy escape szekvencia.
A karakter konstans belsbrzolsa int, gy az ASCII kd egsz r-
tknek is minsl kifejezsekben.
A PELDA7.Cbl lthat, hogy a logikai s mveletet && jelli, s
a logikai vagy opertor a ||.
A ktoperandusos logikai opertorok prioritsa alacsonyabb a rel-
ciknl, s az && magasabb priorits, mint a ||. Ha a ktoperandusos lo-
gikai mvelet eredmnye eldl a bal oldali operandus kirtkelsvel, ak-
kor a C bele sem kezd a msik operandus rtkelsbe. Az s mvelet
eredmnye eldlt, ha a bal oldali operandus hamis. A vagy pedig akkor
ksz, ha az els operandus igaz.
A Cben van inkrementls (++) s dekrementls () egsz rtkekre.
Mindkt mvelet egyoperandusos, teht nagyon magas priorits. A ++
operandusa rtkt eggyel nveli meg, s a pedig eggyel cskkenti,
azaz:
++vltoz vltoz=vltoz+1
--vltoz vltoz=vltoz1
C programnyelv 27
e A problmk ott kezddnek azonban, hogy mindkt mvelet ltezik
eltag (prefix) s uttag (postfix) opertorknt is!
Foglalkozzunk csak a ++ opertorral! A ++vltoz s a vltoz++
hatsra a vltoz rtke eggyel mindenkpp megnvekedik. Kifejezs r-
szeknt eltag opertor esetn azonban a vltoz j rtke vesz rszt a to-
vbbi kirtkelsben, mg uttag mveletnl a vltoz eredeti rtke sz-
mt be. Feltve, hogy a s b egsz tpus vltozk, s b rtke 6:
a = ++b; /* a=7 s b=7 */
a = b++; /* a=7 s b=8 */
Figyeljnk fel r, hogy a PELDA7.C utols printf utastsban
hosszmdostk llnak a d tpuskarakterek eltt a formtumspecifikcik-
ban! Ltszik, hogy a h jelzi a printfnek, hogy a formtumspecifikci-
hoz tartoz aktulis paramter short tpus (2 bjtos), ill. l tudatja vele,
hogy a hozztartoz aktulis paramter long (4 bjtos).
e A megfelel hosszmdostk megadsa a formtumspecifikcik-
ban elengedhetetlen, hisz nem mindegy, hogy a fggvny a verem kvet-
kez hny bjtjt tekinti a formtumspecifikcihoz tartoznak!
Vegyk azt is szre, hogy a tpusokhoz a mezszlessggel is felk-
szltnk: a maximlis pozitv short rtk bizonyosan elfr 5 pozcin, s
long pedig 10en!
Lthat mg, hogy arra is vigyztunk, hogy a hrom maximlis
short rtk sszege rszeredmnyknt se csonkuljon! Ezrt az explicit
longg mdosts a printf utols paramterben:
(long)num+feher+egyeb
Megoldand feladatok:
Ksztsen programokat a PELDA4.C alapjn a kvetkezkppen:
- A forint 1000-tl 100ig cskkenjen 100asval!
- Az eur nvekedjk 1tl 10ig egyesvel!
- A forint 100tl 2000ig nvekedjen 100asval! Az eredmnyt a
kpernyn fejlccl elltva kt oszlop prban oszlopfolytonosan ha-
ladva kell megjelentetni. A bal oldali oszlop pr 100zal, a jobb ol-
dali viszont 1100zal kezddjk!
- A feladat maradjon ugyanaz, mint az elbb, de a megjelentets le-
gyen sorfolytonos. A bal oldali oszlop pr kezddjk 100zal, a
jobb oldali viszont 200zal, s mindegyik oszlop prban 200 legyen
a lpskz!
28 BEVEZETS S ALAPISMERETEK
- Maradva a sorfolytonos megjelentetsnl, krjk be elbb a kijel-
zend oszlop prok szmt ellenrztt inputtal! Az oszlop prok
szma 1, 2, 3 vagy 4 lehet. A mg kijelzend fels rtk ennek meg-
felelen 1000, 2000, 3000 vagy 4000. Az eredmny a kpernyn
fejlccl elltva az elrt szm oszlop prban jelenjen meg gy,
hogy 100 tovbbra is a lpskz! {TOBBOSZL.C}
- A forint 100tl 10000ig nvekedjen 100asval! A lista nem fut-
hat el a kpernyrl, azaz fejlccl elltva lapozhatan kell megje-
lentetni! Ez azt jelenti, hogy elszr kiratjuk a lista egy kperny
lapnyi darabjt, majd vrunk egy gombnyomsra. A gomb letse-
kor produkljuk a lista kvetkez lapjt, s jbl vrunk egy gomb-
nyomsra, s gy tovbb. {LAPOZ.C}
- Legyen ugyanaz a feladat, mint az elz pontban, de a lista a kper-
nyn fejlccl elltva nem csak elre, hanem elrehtra lapozhat-
an jelenjen meg!
Ksztsen programokat, melyek a szabvny bemenetet EOFig olvas-
sk, s kzben megllaptjk, hogy:
- Hny sor volt a bemeneten? A bemenet karakterei kzt a \neket
kell leszmllni. Az utols sor persze lehet, hogy nem \nnel vg-
zdik, hanem EOFfal.
- Hny sz volt a bemeneten? A sz nem fehr karakterekbl ll. A
szavakat viszont egymstl fehr karakterek vlasztjk el. Az utols
sz lehet, hogy nem fehr karakterrel zrul, hanem EOFfal.
3.7 Tmbk
Ksztsnk programot, mely a szabvny bemenetet olvassa EOF-ig!
Megllaptand s kijelzend, hogy hny A, B, C stb. karakter rkezett! A
kis s nagybetk kztt nem tesznk klnbsget! A betkn kvli tb-
bi karaktert tekintsk egy kategrinak, s ezek darabszmt is jelezzk ki!
Megoldsunkban az elvalaszto karakteres vltoz, a k, a tobbi s a betu
viszont egsz tpus. A k tartalmazza a beolvasott karaktert, s ciklusvl-
tozi funkcikat is ellt. A tobbi s a betu szmllk. A betu annyi ele-
m tmb, mint ahny bet az angol bcben van. A tobbi a betkn k-
vli tbbi karakter szmllja. Az elvalaszto karakteres vltozra azrt
van szksg, mert az eredmny csak kt oszlop pros listaknt kzlhet
egy kpernyn. Az algoritmus:
C programnyelv 29
- Deklarljuk a vltozkat, s a tmbt! A szmllk nullzandk!
Az elvalaszto induljon szkz kezdrtkkel!
- Jelentessk meg a program cmt, s tjkoztassunk a hasznlatrl!
- Mkdtessk addig a ciklust, mg EOF nem rkezik a bemenetrl!
- A ciklusmagban hromirny szelekcival el kell gazni hrom ka-
tegria fel: nagybet, kisbet s ms karakter. Megnvelend
eggyel termszetesen a megfelel szmll!
- A ciklus befejezdse utn kt oszlop pros tblzatban megjelente-
tendk a betszmllk rtkei, s vgl egy kln sorban a tbbi
karakter kategria szmllja!
/* PELDA8.C: Betszmlls a bemeneten */
#include <stdio.h>
#define BETUK 26 /* Az angol bc betszma */
void main(void){
char elvalaszto; /* Listelvlaszt karakter. */
int k, /* Bemeneti kar. s ciklusvltoz. */
tobbi, /* Nem betk szmllja. */
betu[BETUK]; /* Betszmllk. */
tobbi=0; /* Kezdrtk ads. */
for(k=0; k<BETUK; ++k) betu[k]=0;
elvalaszto=' ';
printf("Bemenet betinek leszmllsa\n"
"EOF-ig, vagy Ctrl+Z-ig.\n");
while((k=getchar())!=EOF)
/* Nagybetk: */
if(k>='A'&&k<='Z')++betu[k-'A'];
/* Kisbetk: */
else if(k>='a'&&k<='z')++betu[k-'a'];
/* Ms karakterek: */
else ++tobbi;
/* Eredmnyek kzlse: */
printf("\nBet|Darab Bet|Darab\n"
"----+----- ----+-----\n");
for(k=0; k<BETUK; ++k){
printf("%4c|%5d%c", k+'A', betu[k], elvalaszto);
if(elvalaszto==' ') elvalaszto='\n';
else elvalaszto=' '; }
printf("\nTbbi karakter: %5d\n", tobbi); }
A char tpus vltoz egyetlen karakter trolsra alkalmas. A char
ugyanakkor 8 bites, alaprtelmezs szerint eljeles (signed), fixpontos
belsbrzols egsz tpus is 0111 1111
2
= 2
7
1 = 127 s 1000 0000
2
=
2
7
= 128 brzolsi hatrokkal. Az unsigned char 0 s 255 kztti b-
rzolsi lehetsgekkel rendelkezik.
30 BEVEZETS S ALAPISMERETEK
A legtbb programfejleszt rendszerben az unsigned char alaprtelme-
zsknt is bellthat karakter tpus.
A PELDA8.Cbl kitnen ltszik, hogy a tmb defincija
tpus tmbazonost[mret];
alak. Pontosabban a deklarcis utasts azonostlistja nem csak egy-
szer vltozk azonostibl llhat, hanem tmbazonost[mret] konst-
rukcik is lehetnek kztk. A tmbdefinciban a mret pozitv, egsz r-
tk lland kifejezs, s a tmb elemszmt hatrozza meg.
lland kifejezs az, aminek fordtsi idben kiszmthat az rt-
ke.
A tmb egy elemnek helyfoglalsa tpustl fgg. Az egsz tmb a me-
mriban sszesen
sizeof(tmbazonost) mret*sizeof(tpus)
bjtot ignyel. Pldul 16 bites intet felttelezve a sizeof(betu) 26*si-
zeof(int) pontosan 52.
A magas priorits, egyoperandusos sizeof opertor megadja a m-
gtte zrjelben ll objektum, vagy tpus ltal elfoglalt bjtok szmt.
A tmb egy elemre val hivatkozst indexes vltoznak is nevezik s
szintaktikailag a kvetkez:
tmbazonost[index]
ahol az index nem negatv rtk egsz kifejezs
0 <= index <= mret1
rtkhatrokkal.
e A tmbindexels Cben mindig zrustl indul, s a legnagyobb mg
ltez indexrtk a mret1! Pldul a betu tmbnek ltezik betu[0],
betu[1], betu[2], s vgl betu[BETUK1] eleme, s ezek gy helyezked-
nek el a memriban:
betu[0] betu[1] betu[2] . . . betu[24] betu[25]
Vegyk szre, hogy a betu[0]ban a program az A, a betu[1]ben a
B, , s a betu[25]ben a Z karaktereket szmllja! Ttelezzk fel, hogy
k rtke 68! Ez ugyebr a D bet ASCII kdja. Ilyenkor a betu[kA]
szmll n eggyel. Az A ASCII kdja 65. Teht betu[6865]rl, azaz
betu[3] nvelsrl van sz!
Figyeljnk fel mg arra, hogy az eredmnyeket kzl ciklusbeli
printfben a k+A egsz kifejezs rtkt %c formtumspecifikcival
C programnyelv 31
jelentetjk meg, azaz rendre 65t, 66ot, 67et stb. ratunk ki karaktere-
sen, teht At, Bt, Ct stb. ltunk majd.
Lssuk mg be, hogy az elvalaszto vltoz rtke szkz s sor-
emels karakter kzt vltakozik, s gy kt betdarab pr kpes megjelen-
ni egy sorban. Teht az elvalaszto vltoz segtsgvel produkljuk a kt
oszlop pros eredmnylistt.
` Listzni csak azt rdemes, ami valamilyen informcit hordoz!
Teht a zrus darabszm betk kijelzse teljesen felesleges! Magyarn
a for ciklusbeli printfet gy kne mdostani:
if(betu[k]>0) printf("%4c|%5d%c", k+'A',
betu[k], elvalaszto);
Megoldand feladatok:
Fokozza gy a PELDA8.Cben megoldott feladatot, hogy megszmll-
ja a magyar kezetes kis s nagybetket is!
Ksztsen programot, mely a szabvny bemenetet EOFig olvassa!
Szmllja meg s jelezze ki, hogy hny 0, 1, 2 stb. karakter rkezik! A
nem numerikus karaktereket tekintse egy kategrinak, s ezek szmt is
kzlje!
3.8 Fggvnyek
A fggvnyeket tbbflekppen csoportosthatnnk, de a legpraktiku-
sabb gy, hogy:
- Vannak elre megrtak. Knyvtrakban (.LIB), vagy trgymodulok-
ban (.OBJ) tallhatk, s a kapcsol-szerkeszt kapcsolja be ket a
vgrehajthat fjlba. Pldul: a printf, a getchar, a putchar, vagy a
main stb. Minden vgrehajthat programban kell lennie egy fgg-
vnynek, az indt programnak (a main-nek), mely az egsz prog-
ram belpsi pontjt kpezi.
- Mi rjuk ket. Forrsfjlokban helyezkednek el, s kdjukat a fordt
generlja.
A nyelv kzponti eleme a fggvny. A ms programozsi nyelvekben
szoksos eljrs (procedure) itt explicit mdon nem ltezik, mert a C szel-
lemben az egy olyan fggvny, aminek nincs visszaadott rtke:
void eljrs();
Jelezzk ki egy tblzatban az 1001 s 1010 kztti egsz szmok k-
bt!
32 BEVEZETS S ALAPISMERETEK
/* PELDA9.C: Kbtblzat */
#include <stdio.h>
#define TOL 1001 /* A tartomny kezdete. */
#define IG 1010 /* A tartomny vge. */
long kob(int); /* Fggvny prototpus. */
void main(void){
int i;
printf(" Szm|%11s\n-----+-----------\n", "Kbe");
for(i=TOL; i<=IG; ++i) /* Fggvnyhvs. */
printf("%5d|%11ld\n", i, kob(i)); }
long kob(int a){ /* Fggvnydefinci. */
return (long)a*a*a; }
A fggvnydefinci s a fggvnyhvs fogalmval megismerkedtnk
mr a Kapcsolszerkeszts fejezetben. A fggvnydefinciban van
meg a fggvny teste, azaz az a kd, amit a fggvny meghvsakor vg-
rehajt a processzor.
e Egy fggvnyre a programban csak egyetlen definci ltezhet, s
ennek nem mondhatnak ellent a prototpusok (deklarcik)!
A fggvnydefinciban elrt visszaadott rtk tpusnak egyeznie kell
ebbl kvetkezleg a programban brhol elfordul, e fggvnyre vonat-
koz prototpusokban (deklarcikban) megadott visszatrsi rtk tpus-
sal. A meghvott fggvny akkor ad vissza rtket a hv fggvnynek a
hvs pontjra, ha a processzor kifejezssel elltott return utastst hajt
vgre benne. A valamit szolgltat fggvnyben teht lennie kell leg-
albb egy return kifejezs; utastsnak, s r is kell, hogy kerljn a ve-
zrls. A visszaadott rtk meghatrozatlan, ha a processzor nem hajt vg-
re return utastst, vagy a return utastshoz nem tartozott kifejezs.
e A visszaadott rtk tpusa brmi lehet vgl is eltekintve a tmbtl
s a fggvnytl. Lehet valamilyen alaptpus, de el is hagyhat, amikor is
az alaprtelmezs lesz rvnyben, ami viszont int.
Nzzk a return szintaktikjt!
return <kifejezs>;
A fordt kirtkeli a kifejezst. Ha a fggvny visszatrsi tpusa tpus,
akkor a kifejezs tpusnak is ennek kell lennie, vagy implicit konverzi-
val ilyen tpusv alaktja a kifejezs rtkt a fordt, s csak azutn adja
vissza.
Lssuk be, hogy a PELDA9.Cbeli returnben az explicit (long)
tpusmdosts nem azrt van, hogy megtakartsuk a kifejezs rtknek
visszaads eltti implicit konverzijt! Az igazi ok az, hogy egy 16 bites
int kbe nem biztos, hogy elfr az intben! Gondoljunk 1000 kbre, ami
1000000000! Ez jval meghaladja a 32767es felsbrzolsi korltot.
C programnyelv 33
e Cben az egsz tpusok terletn nincs sem tlcsorduls, sem alul-
csorduls! Pontosabban ami tlcsordul, vagy alulcsordul, az mindenfle
zenet nlkl elveszik.
A fggvnyhvs truhzza a vezrlst a hv fggvnybl a hvottba
gy, hogy az aktulis paramtereket is tadja ha vannak rtk szerint.
A vezrlst a fggvnytest els vgrehajthat utastsa kapja meg. void
visszatrs fggvny blokkjban aztn a vgrehajts addig folytatdik,
mg kifejezs nlkli return utasts nem kvetkezik, vagy a fggvny
blokkjt zr }-re nem kerl a vezrls. Ezutn a hvsi ponttl folytat-
dik a vgrehajts.
Vegyk szre, hogy a return utasts szintaktikjban az elhagyhat
kifejezs a paramter nlkli returnt kvnta jellni!
Belthat, hogy a fggvny prototpusnak mindig meg kell elznie a h-
vst a forrsszvegben. A fordt gy tisztban van a hvs helyn a fgg-
vny paramtereinek szmval, sorrendjvel s tpusval, ill. ismeri a
fggvny visszatrsi rtknek tpust is.
A fordt a prototpus ismeretben implicit tpuskonverzit is vgrehajt
az aktulis paramter rtkn a fggvnynek trtn tads eltt, ha az ak-
tulis paramter tpusa eltr.
e Ha nincs prototpus, akkor nincs implicit konverzi, s csak a cso-
da tudja, hogy mi trtnik az tadott nem megfelel tpus rtkkel. Pl-
dul a kob(3.0) hvs eredmnye zrus, ami remlhetleg kellen szem-
llteti a prototpus megadsnak szksgessgt.
e Ha nincs prototpus, akkor a fordt azt felttelezi (teht olyan hv-
si kdot generl), hogy a fggvnynek az alaprtelmezs miatt int vissza-
adott rtke van. Ez ugyebr elgg rdekes eredmnyre vezet void, vagy
lebegpontos visszatrs fggvnyek esetben.
A nem int visszaadott rtk fggvnyt legalbb deklarni kell a
hv fggvnyben!
A fggvnydeklarci bemutatshoz trjuk a PELDA9.Ct:
/* PELDA9.C: Kbtblzat */
#include <stdio.h>
#define TOL 1001 /* A tartomny kezdete. */
#define IG 1010 /* A tartomny vge. */
void main(void){
int i;
long kob(); /* Fggvnydeklarci. */
printf(" Szm|%11s\n-----+-----------\n", "Kbe");
for(i=TOL; i<=IG; ++i) /* Fggvnyhvs: */
printf("%5d|%11ld\n", i, kob(i)); }
34 BEVEZETS S ALAPISMERETEK
long kob(int a){ /* Fggvnydefinci. */
return (long)a*a*a; }
Vegyk szre rgtn, hogy deklarcis utastsunk szintaktikja is-
mt mdosult! Az azonostlista nem csak egyszer vltozk azonosti-
bl s tmbazonost[mret] konstrukcikbl llhat, hanem tartalmazhat
fggvnynv()
alakzatokat is.
Termszetesen a teljes fggvny prototpus is berhat a deklrcis uta-
stsba,
long kob(int); /* Fggvnydeklarci. */
de ilyenkor a fggvny prototpus csak ebben a blokkban lesz rvnyben.
Lssuk be, hogy az utbbi mdszer nem ajnlhat olyan tbb fgg-
vnydefincibl ll forrsfjlra, ahol a krdses fggvnyt tbb helyrl
is meghvjk! Sokkal egyszerbb a forrsszveg elejn megadni egyszer a
prototpust, mint minden t hv fggvnyben kln deklarlni a fgg-
vnyt.
A fggvny defincija prototpusnak is minsl, ha megelzi a for-
rsszvegben a fggvnyhvst.
/* PELDA9.C: Kbtblzat */
#include <stdio.h>
#define TOL 1001 /* A tartomny kezdete. */
#define IG 1010 /* A tartomny vge. */
long kob(int a){ /* Fggvnydefinci. */
return (long)a*a*a; }
void main(void){
int i;
printf(" Szm|%11s\n-----+-----------\n", "Kbe");
for(i=TOL; i<=IG; ++i) /* Fggvnyhvs: */
printf("%5d|%11ld\n", i, kob(i)); }
e Cben tilos fggvnydefincin bell egy msikat kezdeni, azaz a
fggvnydefincik nem gyazhatk egymsba!
Ugyan a Tblzat ksztse fejezetben mr rgztettk a fggvny
szerkezett, vagyis a blokkszerkezetet, de itt jra kihangslyozzuk, hogy a
fggvnydefinciban
- elbb a deklarcis utastsok jnnek, s
- a vgrehajthat utastsok csak ezutn kvetkeznek, s
- a kt rsz nem keveredhet egymssal.
C programnyelv 35
Ebben a fejezetben csak az rtk szerinti hvsrl szltunk, vagyis
amikor a formlis paramterek rtkt kapja meg a meghvott fggvny.
Van termszetesen nv (cm) szerinti hvs is a Cben, de ezt most mg
nem trgyaljuk!
3.9 Prodzsekt
Ha a vgrehajthat program forrsszvegt tmnknt, vagy funkcin-
knt klnkln forrsfjlokban kvnjuk elhelyezni, akkor Cs prog-
ramfejleszt rendszerekben ennek semmifle akadly sincs. Be kell azon-
ban tartani a kvetkez szablyokat:
- Egy s csak egy forrsmodulban szerepelnie kell az indt program-
nak (main).
- Prodzsektfjl t kell kszteni, melyben felsorolandk a program tel-
jes szvegt alkot forrsfjlok.
Szedjk szt kt forrsmodulra: FOPROG.Cre s FUGGV.Cre, a
PELDA9.C programunkat!
/* FOPROG.C: Kbtblzat */
#include <stdio.h>
#define TOL 1001 /* A tartomny kezdete. */
#define IG 1010 /* A tartomny vge. */
long kob(int); /* Fggvny prototpus. */
void main(void){
int i;
printf(" Szm|%11s\n-----+-----------\n", "Kbe");
for(i=TOL; i<=IG; ++i) /* Fggvnyhvs: */
printf("%5d|%11ld\n", i, kob(i)); }
/* FUGGV.C: A fggvnydefinci. */
long kob(int a){return (long)a*a*a; }
Hozzunk ltre egy j prodzsektet! Soroljuk fel benne, vagy szrjuk bele
a kt forrsfjlt, s mentsk el, mondjuk, PRODZSI fjlazonostval! A
prodzsektfjl nvadsnl csak arra vigyzzunk, hogy egyetlen benne fel-
sorolt fjl azonostjval se egyezzen meg a neve!
Azrt nem konkretizljuk a prodzsektfjl kiterjesztst, mert az
programfejleszt rendszerenknt msms lehet!
A programfejleszt rendszerben kell lennie olyan menpontoknak,
melyekkel j prodzsektet hozhatunk ltre, meglvt tlthetnk be, nyitha-
tunk meg, menthetnk el, trlhetnk, zrhatunk le stb.
e Betlttt, vagy megnyitott prodzsekt esetn azonban a fejleszt
rendszer mindaddig a prodzsekt fordtsval, kapcsolszerkesztsvel s
futtatsval foglalkozik, mg nem trljk, nem zrjuk be. Akrmilyen
36 BEVEZETS S ALAPISMERETEK
ms forrsfjlokat is nyitogatnnk meg klnfle ablakokban, a program-
fejleszt rendszer az aktulis prodzsekt bezrsig nem ezek fordtsval,
szerkesztsvel, vagy futtatsval foglalkozik.
Lssuk a prodzsekt fordtst s kapcsolszerkesztst!
FOPROG.C
FUGGV.C

fordts

FOPROG.OBJ
FUGGV.OBJ
4. bra: A PRODZSI prodzsekt fordtsa
FOPROG.OBJ
FUGGV.OBJ
indt program
(OBJ)
knyvtrak (LIB)

kapcsol
szerkeszts

PRODZSI.EXE
5. bra: A PRODZSI prodzsekt kapcsolszerkesztse
Fedezzk fel, hogy a vgrehajthat fjl a prodzsekt nevt kapja
meg!
A prodzsektet alkot fjlok kztt implicit fggsg van. Ez azt je-
lenti, hogy a prodzsekt futtatsakor csak akkor trtnik meg a trgymodul
alakjban is rendelkezsre ll forrsfjl fordtsa, ha a forrsfjl utols
mdostsnak ideje (dtuma s idpontja) ksbbi, mint a vonatkoz
trgymodul. A kapcsolszerkeszts vgrehajtshoz az szksges, hogy
a trgymodulok, ill. a knyvtrak valamelyiknek ideje ksbbi legyen a
vgrehajthat fjlnl. Az implicit fggsg fennll a forrsfjl s a bele
#include direktvval bekapcsolt fjlok kztt is. A trgymodult akkor is
jra kell fordtani, ha valamelyik forrsfjlba behozott fjl ideje ksbbi a
trgymodulnl.
Bizonyos programfejleszt rendszereknl elfordulhat, hogy az
implicit fggsgi mechanizmust gy kell kln aktivlni (menpont), ill.
hogy a forrsfjlok, s a beljk behozott fjlok kzti fggsget explicit
mdon kell biztostani.
C programnyelv 37
stdio.h
PRODZSI.EXE
foprog.obj
fuggv.obj
indt prog.
knyvtrak
foprog.c
fuggv.c
6. bra: Implicit fggsg a PRODZSI prodzsektnl
A prodzsektfjlban a forrsmodulokon kvl megadhatk trgymo-
dulok (OBJ) s knyvtrak (LIB) fjlazonosti is. A kapcsolszerkesz-
t a trgymodulokat beszerkeszti a vgrehajthat fjlba. A knyvtrakban
pedig fggvnyek trgykdjait fogja keresni.
A prodzsektfjlban tulajdonkppen a gyri indt program s a szabvny
knyvtrak is kicserlhetek, de ennek pontos megvalstsa mr
igazn a programfejleszt rendszertl fgg.
3.10 Karaktertmb s karakterlnc
A karaktertmbk defincija a Tmbk fejezetben ismertetettek sze-
rint:
char tmbazonost[mret];
Az egsz tmb helyfoglalsa:
mret*sizeof(char) mret
bjt. A tmbindexels ebben az esetben is zrustl indul s mret1ig
tart.
A Cben nincs kln karakterlnc (sztring) adattpus. A karakter-
lncokat a fordtnak s a programoznak karaktertmbkben kell elhe-
lyeznie. A karakterlnc vgt az t tartalmaz tmbben egy zrusrtk
bjttal (\0) kell jelezni. Pldul a Karakterlnc karakterlncot gy kell
letrolni a tomb karaktertmbben:
tomb K a r a k t e r l n c \0
0 1 2 3 4 5 6 7 8 9 10 11 12
Vegyk szre, hogy a karakterlnc els jele a tomb[0]ban, a mso-
dik a tomb[1]ben, s a legutols a tomb[11]ben helyezkedik el, s az ezt
kvet tomb[12] tartalmazza a lnczr zrust!
Figyeljnk fel arra is, hogy a karakterlnc hossza (12) megegyezik a
lezr \0 karaktert magba foglal tmbelem indexvel!
Fedezzk mg rgtn fel, hogy a zrus egsz konstans (0) s a
lnczr \0 karakter rtke ugyanaz: zrus int tpusban! Hiszen a karak-
ter konstans belsbrzolsa int.
38 BEVEZETS S ALAPISMERETEK
e A Cben nincs kln karakterlnc adattpus, s ebbl kvetkezleg
nem lteznek olyan sztring mveletek sem, mint a karakterlncok
- egyestse,
- sszehasonltsa,
- hozzrendelse stb.
Ezeket a mveleteket bjtrlbjtra haladva kell kdolni, vagy fggvnyt
kell rni rjuk, mint ahogyan azt a kvetkez pldban bemutatjuk.
Ksztsen programot, mely neveket olvas a szabvny bemenetrl EOF
ig vagy res sorig! Megllaptand egy fordtsi idben megadott nvrl,
hogy hnyszor fordult el a bemeneten! A feladat megoldshoz kszten-
d
- Egy int strcmp(char s1[], char s2[]) fggvny, mely sszehasonlt-
ja kt karakterlnc paramtert! Ha egyeznek, zrust ad vissza. Ha
az els htrbb van a nvsorban (nagyobb), akkor pozitv, egyb-
knt meg negatv rtket szolgltat.
- Egy int getline(char s[], int n) fggvny, mely behoz a szabvny
bemenetrl egy sort! A sor karaktereit rendre elhelyezi az s karak-
tertmbben. A befejez soremels karaktert nem viszi t a tmbbe,
hanem helyette lnczr \0t r a karakterlnc vgre. A getline
msodik paramtere az s karaktertmb mretnl eggyel kisebb
egsz rtk, azaz a lnczr zrus nlkl legfeljebb n karaktert trol
a tmbben a fggvny. A getline visszatrsi rtke az s tmbben
vgl is elhelyezett karakterlnc hossza.
/* PELDA10.C: Nvszmlls */
#include <stdio.h>
#define NEV "Jani" /* A szmllt nv. */
#define MAX 29 /* A bemeneti sor maximlis mrete.
Most egyben a leghosszabb nv is. */
int getline(char s[],int n); /* Fggvny prototpusok. */
int strcmp(char s1[], char s2[]);
void main(void){
int db; /* Nvszmll. */
char s[MAX+1]; /* Az aktulis nv. */
db=0; /* A szmll nullzsa. */
printf("A(z) %s nv leszmllsa a bemeneten.\nAdjon\
meg soronknt egy nevet!\nProgramvg: res sor.\n",NEV);
/* Sorok olvassa res sorig a bemenetrl: */
while(getline(s,MAX)>0)
/* Ha a sor pp a NEV: */
if(strcmp(s,NEV)==0) ++db;
/* Az eredmny kzlse: */
printf("A nevek kzt %d darab %s volt.\n",db,NEV); }
C programnyelv 39
int strcmp(char s1[], char s2[]){
int i;
for(i=0; s1[i]!=0&&s1[i]==s2[i]; ++i);
return(s1[i]-s2[i]);}
int getline(char s[],int n){
int c,i;
for(i=0;i<n&&(c=getchar())!=EOF&&c!='\n';++i) s[i]=c;
s[i]='\0';
return(i); }
Ha a forrskd egy sort lezr soremels karaktert kzvetlenl \ jel
elzi meg, akkor mindkt karaktert elveti a fordt, s a kt fizikai sort
egyesti, s egynek tekinti. Az ilyen rtelemben egyestett sorokat mr a
msodiktl kezdve folytatssornak nevezik.
A main els printfjt folytatssorral ksztettk el.
A kt elksztett fggvny prototpusbl s defincijbl vegyk
szre, hogy a formlis paramter karaktertmb (s persze ms tpus tmb
is) mret nlkli!
Az strcmp megrsakor abbl indultunk ki, hogy kt karakterlnc akkor
egyenl egymssal, ha ugyanazon pozciikon azonos karakterek llnak,
s radsul a lnczr zrus is ugyanott helyezkedik el. Az i ciklusvlto-
zt zrusrl indtva, s egyesvel haladva, vgigindexeljk az s1 karakter-
tmbt egszen a lnczr nullig (s1[i]!=0) akkor, ha kzben minden i
re az s1[i]==s2[i] is teljeslt. Ebbl a ciklusbl teht csak kt esetben van
kilps:
- Ha elrtnk s1 karaktertmb lnczr zrusig (s1[i]==0).
- Ha a kt karakterlnc egyazon pozcijn nem egyforma rtk ll
(s1[i]!=s2[i]).
A visszaadott s1[i]s2[i] klnbsg csak akkor:
- Zrus, ha s1[i] zrus s s2[i] is az, azaz a kt karakterlnc egyenl.
- Negatv, ha s1 kisebb (elbbre van a nvsorban), mint s2.
- Pozitv, ha s1 nagyobb (htrbb van a nvsorban), mint s2.
Az strcmpt mr megrtk. Trgykdja benne van a szabvny
knyvtrban. Nem fradtunk azonban feleslegesen, mert a szabvny
knyvtri vltozat ugyangy funkcionl, mint a PELDA10.Cbeli. Hasz-
nlathoz azonban be kell kapcsolni a prototpust tartalmaz STRING.H
fejfjlt.
rjuk be a PELDA10.C #include direktvja utn a
40 BEVEZETS S ALAPISMERETEK
#include <string.h>
, s trljk ki a forrsszvegbl az strcmp prototpust s defincijt!
Vgl prbljuk ki!
e Feltve, hogy s1 s s2 karaktertmbk, lssuk be, hogy C program-
ban, ugyan szintaktikailag nem helytelen, semmi rtelme sincs az ilyen
kdolsnak, hogy:
s1==s2, s1!=s2, s1>=s2, s1>s2, s1<=s2, s1<s2
E mdon ugyanis s1 s s2 memriabeli elhelyezkedst hasonltjuk ssze,
azaz bizton llthatjuk, hogy az s1==s2 mindig hamis, s az s1!=s2 pedig
mindig igaz.
A getline ciklusvltozja ugyancsak zrusrl indul, s a ciklus vgig
egyesvel halad. A ciklusmagbl ltszik, hogy a szabvny bemenetrl r-
kez karakterekkel tlti fel az s karaktertmbt. A ciklus akkor ll le,
- ha az s tmb kimerlt, s nem tlthet tovbb (i>=n), vagy
- ha a beolvasott karakter EOF jelzs (c==EOF), vagy
- ha a bejv karakter soremels (c==\n).
Ezutn kitesszk a tmb iik elemre a lnczr zrust, s visszaadjuk it,
azaz a behozott karakterlnc hosszt.
getline fggvnynk j prblkozs az egy sor behozatalra a szabvny
bemenetrl, de van nhny problmja, ha a bemenet a billentyzet:
1. A bemeneti pufferben lev karakterek csak soremels (Enter) utn
llnak rendelkezsre, s addig nem.
2. Az EOF karakter (Ctrl+Z) rkezse nem jelenti tulajdonkppen a
bemenet vgt, mert utna mg egy soremelst is vgre kell hajtani,
hogy szlelni tudjuk.
3. Ha a bemeneti pufferben az Enter megnyomsakor nnl tbb ka-
rakter van, akkor a puffer (az egy sor) csak tbb getline hvssal ol-
vashat ki.
rjuk csak t a PELDA10.C mainjben a
while(getline(s,MAX)>0)
sort a kvetkezre
while(getline(s,4)>0)
, s a program indtsa utn gpeljk be a
JenJaniJojJani
C programnyelv 41

sorokat!
Az els kt problma az opercis rendszer viselkedse miatt van, s je-
lenleg sajnos nem tudunk rajta segteni. A msodik gondhoz mg azt is
hozz kell fznnk, hogy fjlvget a billentyzet szabvny bemeneten a
getlinenak csak res sor megadsval tudunk elidzni.
A harmadik problma viszont knnyedn orvosolhat, csak ki kell ol-
vasni a bemeneti puffert vgig a getlinebl val visszatrs eltt. Teht:
int getline(char s[],int n){
int c,i;
for(i=0;i<n&&(c=getchar())!=EOF&&c!='\n';++i)s[i=c;
s[i]='\0';
while(c!=EOF&&c!='\n') c=getchar();
return(i); }
Megoldand feladatok:
Ksztse el a kvetkez fggvnyeket, s prblja is ki ket egy rvid
programmal!
- A void strcopy(char cl[], char forrs[]) tmsolja a cl karakter-
tmbbe a forrs karakterlncot a lezr nulljval egyetemben.
- A void strct(char s1[], char s2[]) egyesti s1be a kt paramter
karakterlncot. Javasoljuk, hogy az algoritmus indexeljen elre s1
lnczr zrusig, s ettl kezdve csak ide kell msolni s2t!
- Az unsigned strlen(char s[]) visszaadja az s karakterlnc hosszt.
Emlkezznk r, hogy a lnczr zrus indexe a karaktertmbben
egyben a karakterlnc hossza is!
- A void strrv(char s[]) megfordtja a sajt helyn a paramter karak-
terlncot. Pldul a Janibl inaJnak kell szletnie.
rjon programot, mely a getline segtsgvel sorokat olvas res sorig a
szabvny bemenetrl, s megkeresi a legrvidebbet, s persze ki is jelzi a
hosszval egytt! Javasoljuk, hogy a pillanatnyi minimum mentshez
hasznlja fel az strcopy fggvnyt! {STRMIN.C}
3.11 Loklis, globlis s bels, kls vltozk
Ha alaposan ttanulmnyozzuk a PELDA10.Ct, akkor szrevehetjk,
hogy mind az strcmpben, mind a getlineban van egyegy, int tpus i
vltoz. Feltehetnnk azt a krdst, hogy mi kzk van egymshoz? A r-
vid vlasz nagyon egyszer: semmi. A hosszabb viszont kicsit bonyolul-
tabb:
42 BEVEZETS S ALAPISMERETEK
- Mindkt i vltoz loklis a sajt fggvnyblokkjra.
- A loklis vltoz hatskre az a blokk, amiben definiltk.
- A loklis vltoz lettartama az az id, mg sajt fggvnyblokkja
aktv, azaz benne van a vezrls.
Teht a kt i vltoznak a nvegyezsen tl nincs semmi kze sem egy-
mshoz.
A vltoz hatskre az a programterlet, ahol rvnyesen hivat-
kozni lehet r, el lehet rni. Nevezik ezt ezrt rvnyessgi tartomnynak
is.
A loklis vltoz hatskre az a blokk, s annak minden begya-
zott blokkja, amiben definiltk. A blokkon bellisge miatt a loklis vl-
tozt bels vltoznak is nevezik.
A vltoz lettartama az az idszak, amg memrit foglal.
A loklis vltoz akkor jn ltre (rendszerint a veremben), amikor
a vezrls bejut az t definil blokkba. Ha a vezrls kikerl onnt, ak-
kor a memriafoglalsa megsznik, helye felszabadul (a veremmutat
helyrejn).
A fggvnyekben, gy a mainben is, definilt vltozk mind loklisak
arra a fggvnyre, amelyben deklarltk ket. Csak az adott fggvnyen
bell lehet hozzjuk frni. Ez a loklis hatskr. Futsi idben a fgg-
vnybe val belpskor jnnek ltre, s kilpskor meg is semmislnek.
Ez a loklis lettartam. A loklis vltoz kezdrtke ebbl kvetkezleg
szemt. Pontosabban az a bitkombinci, ami azokban a memriabj-
tokban volt, amit most ltrejvetelekor a rendszer rendelkezsre bocs-
tott. Teht a bels vltoznak nincs alaprtelmezett kezdrtke. Az alap-
rtelmezett kezdrtket implicit kezdrtknek is szoktk nevezni.
Mi dnti el, hogy a bels vltoz melyik blokkra lesz loklis?
Nyilvnvalan az, hogy az t definil deklarcis utastst melyik blokk
elejn helyezik el.
Tisztzzuk valamennyire a vltoz deklarcija s defincija kz-
ti klnbsget! Mindkt deklarcis utastsban megadjk a vltoz n-
hny tulajdonsgt, de memriafoglalsra csak definci esetn kerl sor.
A loklis vltoz az elzekben ismertetetteken kvl auto trol-
si osztly is.
Egsztsk ki jbl a deklarcis utasts szintaktikjt!
<trolsiosztly><tpusmdostk> <alaptpus> azonostlista;
C programnyelv 43
A trolsiosztly a kvetkez kulcsszavak egyike lehet: auto, register,
static, vagy extern. E fejezet keretben nem foglalkozunk a register s a
static trolsi osztllyal!
A szintaktikt betartva most felrhat, hogy
auto i;
, ami az auto signed int tpus, i azonostj vltoz defincija.
Hogyan lehet auto trolsi osztly a loklis vltoz? Nyilvn
gy, hogy a loklis helyzet deklarcis utastsban az auto trolsi osz-
tly alaprtelmezs. Az auto kulcssz kirsa ezekben az utastsokban
teljesen felesleges.
Foglaljuk ssze a loklis vltozval, vagy ms nven bels vltozval,
kapcsolatos ismereteinket!
Neve: Brmilyen azonost.
Tpusa: Valamilyen tpus.
Hatskre: Az a blokk, ahol definiltk.
lettartama: Amg a blokk aktv, azaz a vezr-
ls benne van.
Alaprtelmezett trolsi osztlya: auto
Alaprtelmezett kezdrtke: Nincs.
Deklarcis utastsnak helye: Annak a blokknak a deklarcis
rsze, ahol a vltozt hasznlni k-
vnjuk.
Memriafoglals: Futsi idben, tbbnyire a verem-
ben.
Meg kell emlteni, hogy a fggvnyek formlis paramterei is lok-
lis vltozknak minslnek, de
- deklarcijuk a fggvnydefinci fej rszben s nem a blokkjban
helyezkedik el, s
- rtkk az aktulis paramter rtke.
Az elfeldolgozson tesett forrsmodult fordtsi egysgnek neve-
zik. A fordtsi egysg fggvnydefincikbl s kls deklarcikbl ll.
Kls deklarci alatt a minden fggvny testn kvli deklarcit rt-
jk. Az gy definilt vltozt kls vltoznak, vagy globlis vltoznak
nevezik. Az ilyen vltoz:
- Hatskre a fordtsi egysgben a deklarcis utastsnak pozci-
jtl az n. deklarcis ponttl indul, s a modul vgig tart. Ezt
a hatskrt fjl hatskrnek, vagy globlis hatskrnek nevezik.
44 BEVEZETS S ALAPISMERETEK
- lettartama a program teljes futsi ideje. A memria hozzrendels
mr fordtsi idben megtrtnik. Rendszerint az elsdleges adatte-
rleten helyezkedik el, s biztos, hogy nem a veremben. Ez a stati-
kus lettartam.
- Alaprtelmezett (implicit) kezdrtke: minden bitje zrus. Ez az
aritmetikai tpusoknl zrus. Karaktertmb esetben ez az res ka-
rakterlnc, hisz rgtn a lnczr nullval indul.
- Alaprtelmezett trolsi osztlya extern.
e Bnjunk csnjn az extern kulcssz explicit hasznlatval, mert
deklarcis utastsban val megadsa ppen azt jelenti, hogy az utasts
nem definci, hanem csak deklarci! Ms fordtsi egysgben definilt
kls vltozt kell ebben a forrsmodulban gy deklarlni a r val hivat-
kozs eltt.
/* Forrsmodul 1 */
extern int i;
extern char t[];
/* . . . */
/* Forrsmodul 2 */
int i;
char t[10];
/* . . . */
7. bra: extern deklarci
Prodzsektnk lljon e kt forrsmodulbl! Az int tpus i vltozt s a t
karaktertmbt Forrsmodul 2ben definiltk. Itt trtnt teht meg a
helyfoglalsuk. Ezek a vltozk Forrsmodul 1ben csak akkor rhetk
el, ha a rjuk trtn hivatkozs eltt extern kulcsszval deklarljk ket.
Vegyk szre, hogy a Forrsmodul 1 elejn elhelyezett deklarcis
utastsok egyrszt globlis szinten vannak, msrszt valban csak dekla-
rcik, hisz a tmb deklarcijban mret sincs!
e Persze azt, hogy a tmb mekkora, valahonnt a Forrsmodul 1ben
is tudni kell!
rjuk t gy a PELDA10.Ct, hogy a beolvasott sor trolsra hasznla-
tos tmbt globliss tesszk, majd nevezzk t PELDA11.Cre!
/* PELDA11.C: Nvszmlls */
#include <stdio.h>
#define NEV "Jani" /* A szmllt nv. */
#define MAX 29 /* A bemeneti sor maximlis mrete.
Most egyben a leghosszabb nv is. */
int getline(void); /* A fggvny prototpusok. */
int strcmp(char s2[]);
void main(void){
C programnyelv 45
int db; /* Nvszmll. */
db=0; /* A szmll nullzsa. */
printf("A(z) %s nv leszmllsa a bemeneten.\nAdjon\
meg soronknt egy nevet!\nProgramvg: res sor.\n",NEV);
/* Sorok olvassa res sorig a bemenetrl: */
while(getline()>0)
/* Ha a sor pp a NEV: */
if(strcmp(NEV)==0) ++db;
/* Az eredmny kzlse: */
printf("A nevek kzt %d darab %s volt.\n",db,NEV); }
char s[MAX+1]; /* Az aktulis nv */
int strcmp(char s2[]){
int i;
for(i=0; s[i]!=0&&s[i]==s2[i]; ++i);
return(s[i]-s2[i]);}
int getline(void){
int c,i;
for(i=0;i<MAX&&(c=getchar())!=EOF&&c!='\n';++i)
s[i]=c;
s[i]='\0';
while(c!=EOF&&c!='\n') c=getchar();
return(i); }
Vegyk szre, hogy a PELDA10.Cs verzihoz kpest a getline pa-
ramter nlkliv vlt, s az strcmpnek meg egyetlen paramtere ma-
radt! Miutn a globlis s karaktertmb deklarcis pontja megelzi a kt
fggvny defincijt, a fggvnyblokkok s hatskrben vannak. Bellk
teht a tmb egyszer hivatkozssal elrhet, s nem kell paramterknt t-
adni. A getline msodik paramtere tulajdonkppen a MAX szimbolikus
konstans volt, s ezt beptettk a for ciklusba.
Elemezgessk egy kicsit a kls vltoz, vagy paramter problmt!
- Globlis vltozkat hasznlva megtakarthat fggvnyhvskor a
paramterek tadsa, vagyis kevesebb paramterrel oldhat meg a
feladat.
- Kls vltozkat manipull fggvnyek msik programba viszont
csak akkor msolhatk t s hvhatk meg vltoztats nlkl, ha
ezeket a vltozkat is velk visszk. Ltszik, hogy az ilyen fggv-
nyek mobilitst, jrafelhasznlhatsgt cskkentik a jrulkos,
globlis vltozk.
- A csak paramtereket s loklis vltozkat alkalmaz fggvnyek
tmsols utn vltoztats nlkl hasznlhatk ms programokban.
Legfeljebb az aktulis paramterek lesznek msok a hvsban.
Vilgos, hogy nincs egyrtelmen s ltalnosan ajnlhat megolds
a problmra. A feladat konkrt sajtossgai dntik el, hogy mikor milyen
fggvnyeket kell rni, kelleneke kls vltozk stb.
46 BEVEZETS S ALAPISMERETEK
Summzzuk a globlis vltozval, vagy ms nven kls vltozval,
kapcsolatos ismereteinket!
Neve: Brmilyen azonost.
Tpusa: Valamilyen tpus.
Hatskre: Globlis, vagy fjl. A deklarcis
ponttl a forrsmodul vgig tart.
lettartama: Statikus. A program teljes futsi
ideje alatt l.
Alaprtelmezett trolsi osztlya: extern
Alaprtelmezett kezdrtke: Minden bitje zrus.
Deklarcis utastsnak helye: A forrsmodul minden fggvny-
defincijn kvl.
Memriafoglals: Fordtsi idben, vagy legalbb is
az indt program kezddse eltt.
3.12 Inicializls
Az inicializls kezdrtk adst jelent a deklarciban, azaz az inicia-
liztorok kezdrtkkel ltjk el az objektumokat (vltozkat, tmbket
stb.).
A statikus lettartam objektumok egyszer a program indulsakor inici-
alizlhatk. Implicit (alaprtelmezett) kezdrtkk tiszta zrus, ami:
- Zrus az aritmetikai tpusoknl.
- res karakterlnc karaktertmb esetn.
A loklis lettartam objektumok inicializlsa minden ltrejvetelk-
kor megvalsul, de nincs implicit kezdrtkk, azaz szemt van ben-
nk.
Mdostsuk jra a deklarcis utasts szintaktikjt vltozkra s tm-
bkre!
tpus azonost<=inicializtor>;
tpus tmbazonost[<mret>]<={inicializtorlista}>;
, ahol az inicializtorlista inicializtorok egymstl vesszvel elvlasztott
sorozata, s a tpus a <trolsiosztly><tpusmdostk> <alaptpus>t
helyettesti.
A vltozkat egyszeren egy kifejezssel inicializlhatjuk, mely kifeje-
zs opcionlisan {}-be is tehet. Az objektum kezdeti rtke a kifejezs
rtke lesz. Ugyanolyan korltozsok vannak a tpusra, s ugyanazok a
konverzik valsulnak meg, mint a hozzrendels opertornl. Magyarn
az inicializtor hozzrendels-kifejezs. Pldul:
C programnyelv 47
char y = z, k; /* y z rtk, s a knak meg */
/* nincs kezdrtke. */
int a = 10000; /* a 10000 kezdrtk. */
C-ben a statikus lettartam vltozk inicializtora csak konstans kifeje-
zs lehet, ill. csak ilyen kifejezsek lehetnek tmbk inicializtorlistj-
ban. A loklis objektumok inicializtoraknt viszont brmilyen leglis ki-
fejezs megengedett, mely hozzrendels kompatibilis rtkk rtkelhet
ki a vltoz tpusra.
#define N 20
int n = N*2; /* Statikus objektum inicializtora
csak konstans kifejezs lehet. */
/* . . . */
void fv(int par){
int i = N/par; /* A loklis objektum viszont
brmilyen leglis kifejezs.
. . . */ }
Emlkezznk vissza, hogy globlis vltozk csak egyszer kapnak
kezdrtket: a program indulsakor. A loklis objektumok viszont mind-
annyiszor, valahnyszor blokkjuk aktvv vlik.
A szvegben hasznlatos objektum fogalom nem objektumorien-
tlt rtelm, hanem egy azonosthat memria terletet takar, mely kons-
tans vagy vltoz rtk(ek)et tartalmaz. Minden objektumnak van azono-
stja (neve) s adattpusa. Az adattpus rgzti az objektumnak
- lefoglaland memria mennyisgt s
- a benne trolt informci belsbrzolsi formjt.
Tmbk esetn az inicializtorlista elemeinek szma nem haladhatja
meg az inicializland elemek szmt!
float tomb[3] = {0., 1., 2., 3.}; /* HIBS: tbb
inicializtor van, mint tmbelem. */
Ha az inicializtorlista kevesebb elem, mint az inicializland objektu-
mok szma, akkor a maradk objektumok a statikus lettartam implicit
kezdrtk ads szablyai szerint kapnak rtket, azaz nullzdnak:
float tmb[3] = {0., 1.}; /* tmb[0]==0.0, tmb[1]==1.0 s
tmb[2]==0.0. */
Az inicializland objektum lehet ismeretlen mret is, ha az inicializ-
torlistbl megllapthat a nagysg. Pldul:
int itmb[] = { 1, 2, 3}; /* Az itmb hrom elem lesz. */
char nev[] = Lali, /* A lezr \0 karakter */
csaladnev[] = Kiss; /* miatt 5 elemek a tmbk.*/
Megoldand feladatok:
48 BEVEZETS S ALAPISMERETEK
rja t az eddig elksztett PELDAn.Cket, s a megoldott feladatok
programjait gy, hogy a vltozk kezdrtket mindig inicializlssal
kapjanak!
C programnyelv 49
4 TPUSOK S KONSTANSOK
A fordt a forrskdot szintaktikai egysgekre, vagy ms elnevezssel
szimblumokra, s fehr karakterekre trdeli. A tbb egymst kvet fe-
hr karakterbl csak egyet tart meg. Ebbl kvetkezleg:
- Egyetlen C utasts akr szimblumonknt klnkln sorba rha-
t.
- Egy sorban azonban tbb C utasts is megadhat.
Pontosan hat szimblum (int i ; float f ;) lesz a kvetkezkbl:
int
i
;
float f ;
vagy
int i; float f;
A karakter, vagy karakterlnc konstansokban elfordul, akrhny
fehr karaktert vltozatlanul hagyja azonban a fordt.
Emltettk mr, hogy a programnyelv szimblumokbl (token) ll. Most
ismertetjk a szimblum defincijt mdostott BackusNaur, metanyel-
vi lerssal:
szimblum (token):
opertor
kulcssz
elvlaszt-jel
azonost
konstans
karakterlnc (string literal)
Az rtelmezs nagyon egyszer: a felsorolt hat fogalom mindegyike
szimblum.
Az opertorokkal nem ebben a szakaszban foglalkozunk, hanem a M-
VELETEK S KIFEJEZSEKben!
A kulcsszavak:
auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
50 TPUSOK S KONSTANSOK
default goto sizeof volatile
do if static while
Vannak ezeken kvl mg nem szabvnyos kulcsszavak s ms vdett
azonostk, de ezek mindig megtudhatk a programfejleszt rendszer se-
gtsgbl!
Ilyenekre kell gondolni, mint a cdecl, a pascal, az stdcall, vagy
egykt alhzs karakterrel kezddkre, mint pldul az __STDC__ stb.
ANSI C kompatibilis fordtst elrva mindig kiderthet, hogy az
illet fordt mely kulcsszavai, opertorai, vagy elvlasztjelei nem
szabvnyosak.
4.1 Elvlaszt-jel
A szintaktikai egysgeket (a szimblumokat) egymstl legalbb egy fe-
hr karakterrel el kell vlasztani. Nincs szksg azonban az elvlaszt fe-
hr karakterre, ha a kt nyelvi egysg kz a szintaktikai szablyok szerint
egybknt is valamilyen elvlaszt-jelet kell rni. Az opertorok is elv-
lasztjelnek minslnek kifejezsekben.
elvlaszt-jel: (a kvetkezk egyike!)
[ ] ( ) { } * , : = ; #
Nzzk meg nhny elvlasztjel funkcijt!
Az utastst zr pontosvessz minden pldban benne van.
A kerek zrjeleknek csoportost funkcija van kifejezsekben. Van,
amikor a szintaktika rsze. Fggvnyhvsnl az aktulis paramtereket,
fggvnydeklarciban s definciban a formlis paramtereket ebbe kell
tenni.
d = c*(a+b);
if(d==z) ++x;
fv(akt, par);
void fv2(int n);
A szgletes zrjelek tmbk deklarcijban s indexel opertorknt
hasznlatosak.
char kar, lanc[] = Sztan s Pan.;
kar = lanc[3];
A kapcsos zrjelekbe tett tbb utasts szintaktikailag egyetlen utasts-
nak minsl. A dolgot sszetett utastsnak, blokknak nevezzk.
e Az sszetett utasts (blokk) zr kapcsos zrjele utn tilos pontos-
vesszt tenni!
if(a<b){ /* Illeglis pontosvessz hasznlat. */
C programnyelv 51
a=2; z=b+6; };
A csillag elvlaszt-jelnek tbbfle szerepe van a nyelvben. Eddig csak
a szorzs opertor funkcijt ismerjk!
a = 3.14*b;
Az egyenlsg jel hozzrendels opertor, s deklarcis utastsban el-
vlasztja a vltozt az inicializtortl, vagy inicializtorlisttl.
char tomb[5] = {0, 1, 2, 3, 4};
int x=5, b, c=4;
b = x+c;
A ketts kereszt elfeldolgoz (preprocessor) direktva kezdete. A sor-
beli els nem fehr karakternek kell annak lennie.
#include <stdio.h>
#define TRUE 1
#define FALSE 0
4.2 Azonost
azonost:
nem-szmjegy
azonost nem-szmjegy
azonost szmjegy
nem-szmjegy: (a kvetkezk egyike!)
a ... z A ... Z _
szmjegy: (a kvetkezk egyike!)
0 1 2 3 4 5 6 7 8 9
Az azonost vltozknak, fggvnyeknek, felhasznl definilta adatt-
pusoknak stb. adott, a kvetkez pontokban pontostott nv:
- Kisbetvel, nagybetvel vagy alhzs (_) karakterrel kteles kez-
ddni.
- A tovbbi karakterek lehetnek szmjegyek is.
- Az azonost nem lehet kulcssz vagy valamilyen elredefinilt, v-
dett azonost.
- Az azonostk kis- s nagybet rzkenyek, azaz az Osszeg, az
osszeg vagy az osszeG hrom klnbz azonost.
- Kerlni kell a kt s az egy alhzs karakterrel kezdd nevek
hasznlatt is!
- Az azonostk els, mondjuk, 31 karaktere szignifikns. Ez azt je-
lenti, hogy hosszabb nevek is hasznlhatk, de az els 31 karakte-
rkben nem klnbz azonostk ugyanannak minslnek.
52 TPUSOK S KONSTANSOK
Az, hogy az azonost els hny karaktere szignifikns, a fordttl
fgg. Msrszt a programfejleszt rendszerben egy s ezen rtk kztt
vltoztathat is!
Bizonyos kls kapcsolds azonostkra, melyeket a kapcsol
szerkeszt illeszt, eltr megszortsok lehetnek rvnyben. Pldul keve-
sebb karakterbl llhatnak, vagy nem kis s nagybet rzkenyek stb.
Megoldand feladat:
A felsorolt pldaazonostk kzl az els hrom hibs. Magyarzza
meg, hogy mi a problma velk!
- 6os_villamos
- Moszer Aranka
- Nagy_Jnos
- Nagy_Jani
- puffer
4.3 Tpusok s konstansok a nyelvben
A nyelvben sszesen ngy tpuskategria van:
- A fggvny a nyelv kdgenerl egysge. Az sszes tbbi kategria
csak memrit foglal az adatoknak.
- A void tpus tbbnyire valaminek a meg nem ltt jelzi. Pldul
nincs paramtere s visszaadott rtke a void main(void) fggvny-
nek.
- Skalr az aritmetikai tpus, mely tovbb bonthat fixpontos egsz s
lebegpontos vals brzols tpusokra. Ilyen a felsorols (enum)
tpus s a mutat is.
- Aggregtum a tmb, a struktra s az uni.
A mutatkkal, a struktrkkal s az unikkal ksbbi szakaszokban
foglalkozunk!
A tpusokat gy is csoportosthatnnk, hogy vannak
- alaptpusok s
- szrmaztatott tpusok
Az alaptpusok a void, a char, az int, a float s a double. A szrmaztats
pedig a short, a long, a signed s az unsigned n. tpusmdostkkal tr-
C programnyelv 53
tnhet. A short s a long, valamint a signed s az unsigned egymst ki-
zr mdost prok, de a kt pr egyazon alaptpusra egyszerre is alkal-
mazhat, azaz ltezik
- unsigned long int vagy
- signed short int stb.
A signed s az unsigned mdost azonban csak egsz tpusokra (char s
int) alkalmazhat, lebegpontos vals s a void alaptpusra nem.
A szrmaztatott tpusokba mindig belertendk az ilyen tpus rtkkel
visszatr fggvnyek, az ilyen tpust paramterknt fogad fggvnyek,
a tmbk stb. Ha programunkban valamilyen azonostt hasznlni kv-
nunk, akkor elbb deklarlni (definilni) kell. A deklarci teremti meg a
kapcsolatot az azonost s az objektum kztt, s rgzti legalbb az ob-
jektum adattpust. A szrmaztatott tpust is szoks egyszeren tpusnak
nevezni.
Kszpnzre vltva az elz bekezdsben mondottakat: ha a tpus vala-
milyen nem void adattpus, akkor a deklarcik kvetkezkpp szemll-
tethetk:
tpus t, t1, t2; /* Hrom tpus tpus objektum. */
tpus f(void); /* Tpus tpus rtket visszaad,
paramter nlkli fggvny. */
void fv(tpus i); /*Tpus tpus paramtert fogad
eljrs. */
tpus tt[10]; /* 10 elem, tpus tpus tmb. Az
elemek rendre: tt[0], ..., tt[9]. */
Felttlenl emltst kell tennnk mg kt, definciban hasznlhat
mdostrl, melyek alaposan megvltoztatjk a deklarlt objektum tulaj-
donsgait. E kulcsszavakat minstk megnevezssel is illetik.
A const nem mdosthat objektumot definil, azaz meggtolja a hozz-
rendelst az objektumhoz, s az olyan mellkhatsokat, mint az inkremen-
tls, dekrementls stb. Magyarn: nem engedi meg az azonost elrst
balrtkknt. A const a deklarci elejn brmilyen alaptpussal, aggreg-
tum tpussal stb. llhat, de tilos tbbtteles deklarci els vesszje utn
kirni:
float f = 4.5, const cf = 5.6; /* HIBS. */
Ha a const objektum nem lehet balrtk, akkor hogyan lehet valami-
lyen rtkkel elltni?
54 TPUSOK S KONSTANSOK
A const tpus objektum rtkkel val elltsnak egyetlen mdja
az inicializls. Teht az ilyen objektum defincijban ktelez neki kez-
drtket adni, mert ez ksbb mr nem tehet meg. Pldul:
const float pi = 3.1415926;
const max2int = 32767;
Az el nem rt alaptpus miatt a deklarci specifiktorknt egyedl
ll const tulajdonkppen const int, s ezrt a max2int is az. E deklarci-
k utn botor dolgok a kvetkez utastsok:
pi = 3.; /* Szintaktikai hiba. */
int i = max2int++; /* Szintaktikai hiba. */
A volatile sz jelentse elprolg, illkony, llhatatlan. Mdostknt
azt jelzi, hogy az illet vltoz rtke program vgrehajtson kvli okbl
is megvltozhat.
Mi lehet a program vgrehajtsn kvli ok? Pldul megszakts,
B/K port, konkurensen fut vgrehajtsi szl stb.
A volatile kulcssz deklarcin belli elhelyezsnek szablyai
egyeznek a constival. A fordt az ilyen vltozt nem helyezheti el re-
giszterben, ill. az ilyen objektumot is tartalmaz kifejezs kirtkelse so-
rn nem indulhat ki abbl, hogy az rtk kzben nem vltozik meg. Sz-
val az ilyen vltoz minden hivatkozshoz elrsi kdot kell generlnia
akkor is, ha az ltszlag hatstalannak tnik. Pldul:
volatile ticks; /* volatile int a tpus. */
void interrupt timer(void) {++ticks;}
void varj(int ennyit){
ticks =0;
while( ticks < ennyit ); } /* Ne tegyen semmit. */
A while-beli felttel kirtkelsekor a ciklus minden temben tl-
teni kell ticks rtkt.
Lttuk, hogy egy objektumot egsz lettartamra volatilel tehe-
tnk deklarcival, de explicit tpusmdost szerkezettel a vltoz egyet-
len hivatkozst is volatilel minsthetjk.
int ticks;
void interrupt timer(void) {++ticks;}
void varj(int ennyit){
ticks =0;
while( (volatile)ticks < ennyit ); }
Egy objektum egyszerre lehet const s volatile, amikor is az t bir-
tokl program nem mdosthatja, de megvltoztathatja az rtkt brmely
aszinkron program vagy vgrehajtsi szl.
C programnyelv 55
Az adattpusok s konstansok trgyalsnak megkezdse eltt lssuk a
konstans defincijt!
konstans:
egsz-konstans
enum-konstans
lebegpontos-konstans
karakter-konstans
Tudjuk, hogy az objektum is lehet konstans, de itt most nem ilyen llan-
drl van sz. Az igazi konstans nem azonosthat memria terletet
takar, mely fix, a program futsa alatt meg nem vltoztathat rtket tar-
talmaz. A konstansnak nincs szoftveresen is hasznlhat cme, de van
adattpusa, mely meghatrozza az llandnak
- lefoglaland memria mennyisgt s
- a benne trolt rtk belsbrzolsi formjt.
4.3.1 Egsz tpusok s konstansok
Mr emltettk, hogy az egsz tpusok a char s az int alaptpusbl a
signed - unsigned, valamint a short - long mdost prok alkalmazs-
val llthatk el, azaz a deklarci rsszablya eltekintve a trolsi osz-
tlytl s az inicializlstl:
<tpusmdostk> <alaptpus> azonostlista;
A tpusmdostk alaptpus prost azonban a tovbbiakban is tpusnak
fogjuk nevezni. A szablyok a kvetkezk:
- Mind az alaptpus, mind a tpusmdostk elhagyhat. A kett
egytt azonban nem.
- Ha elhagyjuk az alaptpust, alaprtelmezs az int.
- A short - long mdostk elhagysakor nincs rjuk vonatkoz alap-
rtelmezs.
- Ha elhagyjuk a signed - unsigned mdostt, alaprtelmezs a sig-
ned.
Tpus Mret
bjtban
Minimlis rtk Maximlis rtk
char, signed char 1 -128 127
unsigned char 1 0 255
short, short int,
signed short int
2 -32768 +32767
56 TPUSOK S KONSTANSOK
unsigned short,
unsigned short
int
2 0 65535
int, signed int 2 vagy 4 short vagy long short vagy long
unsigned,
unsigned int
2 vagy 4 ugyangy, de un-
signed
ugyangy, de un-
signed
long, long int,
signed long int
4 -2147483648 +2147483647
unsigned long,
unsigned long int
4 0 4294967295
8. bra: Egsz tpusok
- A char alaptpussal kapcsolatban kiegsztsre szorul a signed char
alaprtelmezs! A programfejleszt rendszerben ugyanis unsigned
char is bellthat a char tpus alaprtelmezseknt. A lehetsges
karaktertpusok ilyenkor gy vltoznak:
Tpus Mret
bjtban
Minimlis rtk Maximlis rtk
char,
unsigned char
1 0 255
signed char 1 128 127
- A tblzatbl (8. bra) is jl ltszik, hogy az ANSI szabvny nem r
el pontos mretet az int tpusra, csupn csak annyit, hogy:
short <= int <= long.
- A belsbrzols fixpontos, binris egsz, ezrt signed tpusokra a
negatv szmokat kettes komplemensk alakjban trolja a fordt.
- A szabvnyos LIMITS.H fejfjlban tallunk szimbolikus lland-
kat (CHAR_MIN, UCHAR_MAX, SHRT_MIN, stb.) az brzo-
lsi korltokra!
e A nyelv szerint nincs sem egsz tlcsorduls, sem alulcsorduls. Az
egsz konstansnl lthatunk erre is egy rvid pldt!
egsz-konstans:
decimlis-konstans <egsz-uttag>
oktlis-konstans <egsz-uttag>
hexadecimlis-konstans <egsz-uttag>
A metanyelvben a < ... > az elhagyhatsgot jelli!
C programnyelv 57
egsz-konstans:
decimlis-konstans<egsz-uttag>
oktlis-konstans<egsz-uttag>
hexadecimlis-konstans<egsz-uttag>
decimlis-konstans:
nemzrus-szmjegy
decimlis-konstans szmjegy
oktlis-konstans:
0
oktlis-konstans oktlis-szmjegy
hexadecimlis-konstans:
0xhexadecimlis-szmjegy
0Xhexadecimlis-szmjegy
hexadecimlis-konstans hexadecimlis-szmjegy
nemzrus-szmjegy: (a kvetkezk egyike!)
1 2 3 4 5 6 7 8 9
oktlis-szmjegy: (a kvetkezk egyike!)
0 1 2 3 4 5 6 7
hexadecimlis-szmjegy: (a kvetkezk egyike!)
0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
egsz-uttag:
unsigned-uttag<long-uttag>
long-uttag<unsigned-uttag>
unsigned-uttag: (a kvetkezk egyike!)
u U
long-uttag: (a kvetkezk egyike!)
l L
A definci szerint:
- Az egsz konstans lehet decimlis, oktlis s hexadecimlis.
- Az egsz konstansnak nincs eljele (pozitv), azaz a negatv egsz
konstans eltt egy egyoperandusos mnusz opertor ll.
- A decimlis egsz konstans int, long int, vagy unsigned long int
belsbrzols a konstans rtktl fggen alaprtelmezs sze-
rint. Az oktlis s hexadecimlis egsz konstans az rtktl fgg-
en int, unsigned int, long int, vagy unsigned long int belsbrzo-
ls.
Decimlis Oktlis Hexadecimlis Tpus
032767 0077777 0X00X7FFF int
0100000
01777777
0X80000XFFFF unsigned
32767
2147483647
02000000
017777777777
0X10000
0X7FFFFFFF
long
58 TPUSOK S KONSTANSOK
2147483648
4294967295
020000000000
037777777777
0X80000000
0XFFFFFFFF
unsigned long
9. bra: Egsz konstansok belsbrzolsa
Lssunk nhny pldt a decimlis, az oktlis s a hexadecimlis egsz
konstansokra!
int i = 10;
int j = 010; /* j kezdetben decimlisan 8. */
int k = 0; /* k decimlisan s oktlisan is 0. */
int l = 0XFF; /* k decimlisan 255. */
- Explicit egsz uttagot a konstans utna rva megvltoztathatjuk az
alaprtelmezett belsbrzolst.
Az inicializtor konstansok tpusegyeztetsvel elkerlhet a szk-
sgtelen kzbens konverzi. Pldul:
unsigned ui=2u;
long li=16l;
unsigned long uli=17lu;
e Az egsz konstans 0 s 4294967295 rtkhatrok kzt megengedett.
Ez azonban a programoz felelssge, mert a 4294967295-nl nagyobb
rtk egyszeren csonkul. Legfeljebb egy halk figyelmeztet zenet j-
het a fordttl. Pldul a
#include <stdio.h>
void main(void){
unsigned long pipipp;
pipipp = 4300000000;
printf(Pipipp = %ld\n, pipipp); }
hatsra 5032704 jelenik meg, ami egy hjn 4300000000 - 4294967295.
4.3.2 Felsorols (enum) tpus s konstans
Az enum (enumerate) adattpus mnemonikuss tesz egy sorozat egsz
rtkre val hivatkozst. Pldul az
enum napok{
vasar, hetfo, kedd, szerda, csut, pentek, szomb} nap;
deklarci ltrehoz egy egyedi enum napok egsz tpust. Helyet foglal
egy ilyen tpus, nap azonostj vltoznak, s definil ht, konstans
egsz rtket reprezentl enumertort: az enumertor kszletet.
Felsorols tpus vltozban a tpushoz definilt enumertor kszlet
egyik rtkt tarthatjuk. Az enumertort enum konstansnak is nevezik.
Felsorols tpus vltozkat hasznlhatunk index kifejezsben, minden
C programnyelv 59
aritmetikai s relcis opertor operandusaknt, stb. Tulajdonkppen az
enum a #define direktva alternatvjnak is tekinthet.
ANSI Cben az enumertor rtkt definil kifejezs csak egszr-
tk konstans kifejezs lehet, s tpusa mindig int. Az enum vltoz tro-
lshoz hasznlt memria is annyi, mint az int tpushoz hasznlt. enum
tpus konstans vagy rtk a Cben ott hasznlhat, ahol egsz kifejezs
is. Lssuk a szintaktikt!
enum-specifiktor:
enum <azonost> {enumertorlista}
enum azonost
enumertorlista:
enumertor
enumertorlista, enumertor
enumertor:
enum-konstans
enum-konstans = konstans-kifejezs
enum-konstans:
azonost
Az enum-specifiktor defincijban az enumertorlistval definilt
enum tpus opcionlis azonostjt enum cmknek (tag) nevezzk. Ha
ezt elhagyjuk a defincibl, nvtelen enum tpust kapunk. Ennek az az
diuma, hogy ksbb nincs lehetsgnk ilyen felsorols tpus vltozk
defincijra, hisz nem tudunk a nvtelen enumra hivatkozni. Nvtelen
enum tpus vltozk teht csak a nvtelen enum deklarcijban defini-
lhatk, mshol nem. Az
enum {jan, feb, marc, apr, maj, jun, jul, aug, szep, okt,
nov, dec};
gy teljesen hasznlhatatlan, hisz kptelensg ilyen tpus vltozt dekla-
rlni. A problma az azonostlista megadsval elkerlhet:
enum {jan, feb, marc, apr, maj, jun, jul, aug, szep, okt,
nov, dec} ho=jan, honap;
Foglaljuk ssze az enum deklarcival kapcsolatos tapasztalatainkat:
enum <enum cmke> <{enumertorlista}> <azonostlista>;
, ahol a < > most is az elhagyhatsgot jelli. Az enum cmke megadsa
teht azt biztostja, hogy az "enum enum cmke" utn azonostlistt rva
ksbb ilyen felsorols tpus vltozkat definilhatunk. A fejezet elejn
emltett deklarcis pldban a napok azonost az opcionlisan megad-
hat enum cmke, mely ksbb enum napok tpus vltozk defincii-
ban hasznlhat fel. Pldul:
enum napok fizetes_nap, unnepnap;
60 TPUSOK S KONSTANSOK
Trjnk egy kicsit vissza az enumertorokhoz! Lttuk, hogy az enum
konstans a felsorols tpus deklarcijban definilt azonost. Miutn az
enumertor egsz adattpus, kifejezsekben ott hasznlhat, ahol egyb-
knt egsz konstans is megadhat. Az enumertor azonostjnak egyedi-
nek kell lennie az enum deklarci hatskrben belertve a norml vl-
tozk neveit s ms enumertorlistk azonostit. Az enum konstansok az
egyszer vltozk nvterletn helyezkednek el teht. Az enum cmkk-
nek viszont az enum, a struktra s az unicmkk nvterletn kell egye-
dinek lennik.
A nvterlet olyan azonost csoport, melyen bell az azonostk-
nak egyedieknek kell lennik. A Cben tbb nvterlet van, amibl itt
kettt meg is emltettnk. Kt klnbz nvterleten ltez, ugyanazon
azonostnak semmi kze nincs egymshoz. A nvterleteket majd egy
ksbbi fejezetben trgyaljuk!
Lssunk pldkat ezen kzbevets utn!
int hetfo = 11; /* A hetfo egyszer int tpus vltoz.*/
{ enum napok{
vasar, hetfo, kedd, szerda, csut, pentek, szomb};
/* A hetfo enumertor ebben a blokkban elrejti a hetfo
int tpus vltozt. */
double csut; /* HIBS, mert ezen a nvterleten van
mr egy csut enumertor.
/* . . . */ }
hetfo+=2; /* OK, mert itt mr csak a hetfo int
vltoz ltezik. */
Az enum napok deklarciban szerepl enum konstansok implicit m-
don kaptak rtket zrustl indulva s mindig eggyel nvekedve. A vasar
gy 0, a hetfo 1, ..., s a pentek 6. Az enum konstansok azonban explici-
ten is inicializlhatk. Akr negatvak is lehetnek, ill. tbb enumertor le-
het azonos rtk is. Pldul:
enum ermek{ egyes=1, kettes, otos=5, tizes=2*otos,
huszas=kettes*tizes, szazas=otos*huszas};
Vegyk szre, hogy az enumertor definilt mr az enumertorlista
kvetkez tagjhoz rve!
Mondottuk, hogy a felsorols tpusok mindentt feltnhetnek, ahol
egybknt az egsz tpusok megengedettek. Pldul:
enum napok{
vasar, hetfo, kedd, szerda, csut, pentek, szomb};
enum napok fizetes_nap = szerda, nap;
int i = kedd; /* OK */
nap = hetfo; /* OK */
hetfo = kedd; /* HIBS, mert a hetfo konstans. */
C programnyelv 61
enum tpus vltozhoz egsz rtk hozzrendelse megengedett,
de explicit tpusmdost szerkezet hasznlata javallott. Teht a
fizetes_nap = 5;
helyett
fizetes_nap = (enum napok) 5;
rand.
e A fordtban nincs mechanizmus a konvertland egsz rtk rv-
nyessgnek ellenrzsre! Pontosabban a kvetkez lehetetlensg elke-
rlse a programoz felelssge:
n = (napok) 958;
Az enum tpus egsz (integral) tpus. Implicit mdon konvertl gy
egssz brmely enumertort a fordt, de a msik irnyban az explicit t-
pusmdosts javasolt:
int i;
enum napok n = szomb; /* OK */
i = n; /* OK */
n = 5; /* Nem javasolt! */
n = (napok) 5; /* OK */
Egsz tpusnak az egsz rtkek trolsra alkalmas, aritmetikai
adattpusokat (char, short, int, long s enum) nevezzk.
4.3.3 Vals tpusok s konstans
Az IEEE lebegpontos belsbrzols vals alaptpusok a float s a
double. Egyedl a long mdost hasznlata megengedett, s az is csak a
double eltt, azaz van mg long double szrmaztatott tpus. A float tpu-
s, egyszeres pontossg lebegpontos brzols 4 bjtot foglal, melybl
8 bit a 128 tbbletes, binris exponens, 1 bit a mantissza eljele (1 a nega-
tv!) s 23 bit a mantissza. A mantissza 1.0 s 2.0 kztti szm. Miutn a
mantissza legnagyobb helyirtk bitje mindig egy, az brzols ezt nem
trolja.
eljel eltrtett karakterisztika mantissza
31. bit 30 23 bitek 22 - 0 bitek
A double exponens 11-, s a mantissza 52 bites.
eljel eltrtett karakterisztika mantissza
63. bit 62 52 bitek 51 - 0 bitek
A lebegpontos belsbrzols mretei, megkzelt hatrai s decim-
lis jegyben mrt pontossga a kvetkez tblzatban lthat:
62 TPUSOK S KONSTANSOK
Tpus Mret
bjtban
Hatrok: Pontossg:
float 4
3.4*10
-38 -
3.4*10
+38
67 decimlis jegy
double 8
1.7*10
-308 -
1.7*10
+308
1516 decimlis jegy
long
double
10
1.2*10
-4932 -
1.2*10
+4932
19 decimlis jegy
10. bra: Lebegpontos tpusok
Ehhez mr csak annyit kell hozzfzni, hogy lebegpontos zrus az,
amikor a belsbrzols minden bitje zrus.
e A lers az IEEE szabvnyos lebegpontos brzolsrl szl, de el-
kpzelhet, hogy a konkrt fordt ms formval dolgozik. A szabvnyos
FLOAT.H fejfjlban azonban mindig megtallhatk szimbolikus llan-
dk (FLT_MIN, DBL_MAX stb.) alakjban az brzolsi hatrok s ms
konkrtumok az aktulis belsbrzolsrl.
lebegpontos-konstans:
trt-konstans <exponens-rsz> <float-uttag>
szmjegy-sor exponens-rsz <float-uttag>
trt-konstans:
<szmjegy-sor> . szmjegy-sor
szmjegy-sor .
exponens-rsz:
e <eljel> szmjegy-sor
E <eljel> szmjegy-sor
eljel: (a kvetkezk egyike!)
+ -
szmjegy-sor:
szmjegy
szmjegy-sor szmjegy
float-uttag: (a kvetkezk egyike!)
f l F L
- A mantisszbl elhagyhat a decimlis egsz rsz vagy a trt rsz,
de a kett egytt nem.
- Elhagyhat a tizedes pont vagy az exponens rsz, de mindkett
nem.
- A lebegpontos konstans eljeltelen (pozitv). A negatv lebegpon-
tos konstans eltt egy egyoperandusos mnusz opertor ll.
- Float uttag nlkl a lebegpontos konstans double belsbrzol-
s. Az uttag megadsval kiknyszerthetjk a float (f vagy F), ill.
a long double (l vagy L) belsbrzolst.
C programnyelv 63
double belsbrzols lebegpontos konstansok:
-.5e35, 5., 5E-4, 3.4
Ugyanezek float s long double belsbrzolsban:
-.5e35f, 5.L, 5E-4F, 3.4l
Az egyszeri programoz berta a forrsszvegbe a
float v=143736120;
/* . . . */
printf(%9.0f\n, v);
sorokat, s meglepdtt a 143736128as eredmnyen. Ha v rtkt eggyel
cskkentette, akkor meg 143736112t kapott. Mi lehet a problma?
A 143736120 (0X8913D38) binrisan
1000 1001 0001 0011 1101 00111000
, de csak 24 bit fr el a belsbrzols mantisszjban. A fordt a legma-
gasabb helyirtk, lecsordul bit rtkvel megnveli a mantisszt.
Most, a karakterisztikval nem foglalkozva, az j rtk:
1000 1001 0001 0011 1101 01000000
, ami ppen 143736128 (0X8913D40).
A 143736119 (0X8913D37) binrisan
1000 1001 0001 0011 1101 00110111
esetben az eredmny
1000 1001 0001 0011 1101 00110000
lesz, ami143736112 (0X8913D30).
e Komolyan kell teht venni a lebegpontos brzolsok decimlis
jegyben mrt pontossgt, s az brzolsi hatrokat. Mg kt dologra fel-
ttlenl oda kell figyelni:
- A decimlis vges tizedes trt tbbnyire nem vges binris trt,
azaz az talakts odavissza nem teljesen pontos.
- Matematikai itercit, ami addig tart, mg kt, szmolt, vals rtk
klnbsge zrus nem lesz, nem szabad egy az egyben megvalsta-
ni, mert az esetek tbbsgben vgtelen ciklushoz vezet.
4.3.4 Karakter tpus s konstans
A karakter tpusrl mr sz esett az egsz tpusok trgyalsnl. Tudjuk,
hogy hrom karakter tpus van: char, signed char s unsigned char.
64 TPUSOK S KONSTANSOK
A karakter tpus objektum helyfoglalsa 1 bjt mindenkpp. A karakter
konstans tpusra s helyfoglalsra rgtn kitrnk defincija utn!
karakter-konstans:
'c-karakter-sor'
c-karakter-sor:
c-karakter
c-karakter-sor c-karakter
c-karakter:
brmilyen karakter aposztrf ('), fordtott per jel (\) s soremels (\n) kvtelvel
escape-szekvencia
Szekvencia rtk Karakter Funkci
\0 0X00 NUL karakterlnc vge
\a 0X07 BEL ftty
\b 0X08 BS visszatrls
\t 0X09 HT vzszintes tab
\n 0X0A LF soremels
\v 0X0B VT fggleges tab
\f 0X0C FF lapdobs
\r 0X0D CR kocsi vissza
\ 0X22 macskakrm
\ 0X27 aposztrf
\? 0X3F ? krdjel
\\ 0X5C \ fordtott per jel
\ooo brmi brmi max. 3 oktlis szmjegy
\xhh brmi brmi max. 3 hexadec. jegy
\Xhh brmi brmi max. 3 hexadec. jegy
11. bra: Escape szekvencik
A defincibl kvetkezleg a karakter konstans aposztrfok kzt ll
egy vagy tbb karakter, ill. escape szekvencia. Ezen az elven beszlhetnk
egykarakteres s tbbkarakteres karakter konstansrl.
- A karakter konstans adattpusa mindenkppen int. Tudjuk, hogy az
int helyfoglalsa 2 vagy 4 bjt, gy maximum ngy karakteres ka-
rakter konstans ltezhet. Pldul:
An, \n\r, Alfi, tag, \007\007\007
e Tudjuk, hogy az int belsbrzols karakter konstans esetben is
rvnyben van a signed char alaprtelmezs. Ennek kvetkeztben az int
mretnl kevesebb karakterbl ll karakter konstansok eljel kiterjesz-
tssel alakulnak int belsbrzolsv. Konkrt pldaknt tekintsk a 2
bjtos int-et, s a 852es kdlapot! Az bet kdja 130 (0X82) s az a
C programnyelv 65
bet 97 (0X61). Az -bl gy 0XFF82 s az a-bl 0X0061 lesz a me-
mriban, s gy igaz lesz a kvetkez relci:
< a
Ha unsigned char az alaprtelmezs, akkor a fels bjt(ok)at bizonyosan
0X00-val tlti fel a fordt (az -bl 0X0082 lesz), s nem jn el az
elbb taglalt problma.
A kvetkez kis plda szemllteti a trgyalt karakter tpus s karakter
konstans mreteket!
#include <stdio.h>
#include <stdlib.h>
#define CH 'x' /* Egykarakteres karakter konstans. */
void main(void) {
char ch = CH; /* Karakter tpus vltoz. */
printf("Az int mrete:\t\t\t%d\n", sizeof(int));
printf("A char mrete:\t\t\t%d\n", sizeof(char));
printf("A karakter konstans mrete:\t %d\n",
sizeof(CH));
printf("A karakter vltoz mrete:\t%d\n",
sizeof(ch)); }
Szlnunk kell mg nhny szt a pontosts kedvrt az escape szekven-
cirl! A \ jelet kvetheti egy a tblzatban (11. bra) ismertetett karakter,
vagy egy legfeljebb hromjegy oktlis szm, vagy x utn hexadecimlis
szmjegyek. Pldul a \03 a Ctrl+C, a \x3F a ? karakter, stb. Szval az
escape szekvencia lerhat vezrl s igazi karaktereket egyarnt. Nz-
zk mg a szablyokat!
- Ha az escape szekvencia fordtott per jelt nem leglis karakter k-
veti, akkor legfeljebb figyelmeztet zenetet kapunk, s a fordt el-
hagyja a \ jelet, de megtartja az illeglis karaktert. Pldul a \zbl a
z marad meg.
- Az oktlisan vagy hexadecimlisan adott escape szekvencia vgt
az els nem oktlis, ill. hexadecimlis karakter is jelzi. Pldul a
\518-bl kt karakteres karakter konstans lesz, ahol a karakterek
rendre a \51 s a 8, azaz )8.
- Vigyzzunk a nem egyrtelm megadsra is! Pldul a \712 km-
ves. karakterlncbl ltszik a programoz trekvse, azaz hogy a
BEL karakter utn a 12 kmves szveg kvetkezne. Ez azonban
gy szintaktikai hiba. A helyes eredmnyhez pldul \7 12 km-
ves. mdon juthatunk.
66 TPUSOK S KONSTANSOK
Miutn az escape szekvencival tulajdonkppen egyetlen karaktert
adunk meg, a \ jelet kvet oktlis szmrtk nem haladhatja meg a 0377
et, a hexadecimlis a 0XFFet, vagyis a 255t!
Igazbl a karakter a vgrehajtskor rvnyes gpi karakterkszlet-
bl vett rtk. A knyvben vgig bjtos (char) kdkszletet (ASCII) tte-
leznk fel, s nem foglalkozunk a szles karaktertpussal (wchar_t) s az
Unicode kdkszlettel!
Az eddig trgyalt adattpusokat sszefoglal nvvel aritmetikai
adattpusoknak is nevezhetjk. Az aritmetikai adattpusok zavarba ejt
bsge a nyelvben azonban nem arra szolgl, hogy a programoz
- csak gy ukk-mukk-fukk kivlasszon valamilyen adattpust adatai
s (rsz)eredmnyei trolsra, hanem arra, hogy
- a szmbrzolsi korltokat tekintetbe vve alaposan vgiggondolja,
hogy rtk s pontossg veszts nlkl milyen adattpust kell hasz-
nlnia az egyes adataihoz, (rsz)eredmnyeihez. Esetleg milyen exp-
licit konverzikat kell elrnia a rszletszmtsok vgzse sorn a
pontossg veszts elkerlshez.
Ksztsen szorzat piramist! A piramis als sora 16 darab 100tl 115ig
terjed egsz szm! A kvetkez sorokat gy kapjuk, hogy az alattuk lev
sor elemeit pronknt sszeszorozzuk. A msodik sor gy nz ki teht:
100*101 = 10100, 102*103 = 10506, , 114*115 = 13110. A harmadik
sorban a kvetkezk llnak: 10100*10506 = 106110600, 10920*11342 =
126854640, , 12656*13110 = 165920160, s gy tovbb.
Figyeljnk arra, hogy az eredmnyl kapott szmokat mindig a lehet
legkisebb helyen troljuk, de az rtkeknek nem szabad csonkulniuk!
/* PELDA12.C: Szorzat piramis */
#include <stdio.h>
#define N 16
void main(void){
int i; /* Az als sor: 100-s nagysgrend. */
char n[N]={100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115};
short n1[N/2]; /* 2. sor: 10000-s nagysgrend. */
long n2[N/4]; /* 3. sor: 100000000 kb. */
long double n3[N/8]; /* 4. sor: 10 a 16-n kb. */
printf("Szorzat piramis: els szint\n");
for(i=0; i<N; i=i+2){
n1[i/2]=(short)n[i]*(short)n[i+1];
printf("%3d*%3d = %5hd\n", n[i], n[i+1], n1[i/2]); }
printf("Szorzat piramis: msodik szint\n");
for(i=0; i<N/2; i=i+2){
n2[i/2]=(long)n1[i]*(long)n1[i+1];
C programnyelv 67
printf("%5hd*%5hd = %9ld\n", n1[i], n1[i+1],
n2[i/2]); }
printf("Szorzat piramis: harmadik szint\n");
for(i=0; i<N/4; i=i+2){
n3[i/2]=(long double)n2[i]*(long double)n2[i+1];
printf("%9ld*%9ld = %17.0Lf\n", n2[i], n2[i+1],
n3[i/2]); }
printf("Szorzat piramis: cscs\n");
printf("%17.0Lf*%17.0Lf ~ %33.0Lf\n", n3[0], n3[1],
n3[0]*n3[1]);}
Mr a PELDA7.C pldban tallkoztunk az egszekre vonatkoz h
s l hosszmdostkkal a formtumspecifikcikban. Most a long double
tpus paramter jelzsre val L hosszmdostt ismerhettk meg.
e Ha a szorzat piramis msodik szintjnek kiszmtst vgz
n2[i/2]=(long)n1[i]*(long)n1[i+1];
kifejezsbl elhagyjuk a kt, explicit (long) tpusmdostt, akkor a lista-
rsz a kvetkezkpp mdosul:
Szorzat piramis: msodik szint
10100*10506 = 7816
10920*11342 = -8400
. . .
Ez vitathatatlanul rossz, de mirt?
- Az n1 tmb short tpus.
- A ktoperandusos szorzsi mvelet operandusai azonos tpusak,
teht semmifle implicit konverzi nem trtnik, s az eredmny t-
pusa is short.
- A 32 bites regiszterben a 10100*10506os szorzs vgrehajtsa
utn ugyan ott van a helyes eredmny, a 106110600 (0X6531E88)
0000 0110 0101 0011 0001 1110 1000 1000
, de a 16 bites short tpus miatt csak az als kt bjt kpezi az ered-
mnyt. Az meg 0X1E88, vagyis 7816.
Megemltjk mg, hogy a cscs rtknek (n3[0]*n3[1]) pontos-
sg veszts nlkli trolshoz mg a long double tpus is kevs!
Megoldand feladatok:
Ksztsnk programot, mely megllaptja az :PP:MM alak karak-
terlncrl, hogy rvnyes ide! Az ra zrus s 23, a perc, valamint a
msodperc 0 s 59 kztti rtk lehet csak. Jelezze ki a szoftver, ha a ka-
rakterlnc formailag hibs, s krjen msikat! Ha rvnyes az id, akkor
hatrozza meg s jelezze ki rtkt msodpercben!
68 TPUSOK S KONSTANSOK
Egy msik szoftver fogadjon a szabvny bemenetrl egsz szmokat
mindaddig, mg res sort nem adnak meg! Kpezze rendre az egsz sz-
mok s kt szomszdjuk ngyzetsszegt! A szm szomszdja a nlnl
eggyel kisebb s eggyel nagyobb rtk. A kpernyn jelentse meg fejlc-
cel elltva, tblzatos formban a szmhrmasokat (a bevitt rtkek llja-
nak kzpen) s a ngyzetsszegeket! Legvgl adja meg a ngyzetssze-
gek sszegt is. A szmok legyenek jobbra igaztottak!
4.4 Karakterlnc (string literal):
A karakterlncokrl mr sz volt a BEVEZETS S ALAPISMERE-
TEK szakaszban! A definci:
karakterlnc:
"<s-karakter-sor>"
s-karakter-sor:
s-karakter
s-karakter-sor s-karakter
s-karakter:
brmilyen karakter idzjel ("), fordtott per jel (\) s a soremels (\n) kivtelvel
escape-szekvencia (11. bra)
A karakterlnc adattpusa char tmb. A tmb mrete mindig eggyel
hosszabb, mint ahny karakterbl a karakterlnc ll, mert a nyelv a lnc
vgt \0 karakterrel jelzi. A karakterlnc konstansokat mindig a statikus
adatterleten helyezi el a fordt.
Pldul a Lali karakterlnc egy-
mst kvet, nvekv cm memria
bjtokon gy helyezkedik el.
A karakterlnc karaktereiknt hasznlhat az escape szekvencia is. Pl-
dul a
\t\t\Nv\\\\tCm\n\n
karakterlncot printf fggvny paramtereknt megadva
Nv\ Cm
jelenik meg utna kt soremelssel.
A csak fehr karakterekkel elvlasztott karakterlnc konstansokat a for-
dt elemzsi fzisa alatt egyetlen karakterlncc egyesti:
Egy kett, hrom... Egy kett, hrom...
Tudjuk, hogy a karakterlnc konstans a folytatssor (\) jelet hasznlva
tbb sorba is rhat:
printf(Ez igazbl egyetlen \
L a l i \0
0 1 2 3 4
C programnyelv 69
karakterlnc lesz.\n);
rjunk meg nhny karakterlncot kezel fggvnyt!
Az unsigned strlen(char s[]) a paramter karakterlnc hosszt szolgl-
tatja.
Indtsunk egy vltozt zrustl, s indexeljnk elre vele a karakterln-
con, mg a lnczr nullt el nem rjk! Ez az index a karakterlnc hossza
is egyben.
unsigned strlen(char s[]){
unsigned i=0u;
while(s[i]!=\0) ++i;
return i; }
A void strcopy(char cl[], char forrs[]) a hozzrendelst valstja
meg a karakterlncok krben azzal, hogy a forrs karakterlncot tm-
solja a cl karaktertmbbe.
Indexeljnk most is vgig egy vltozval a forrs karakterlncon a lez-
r zrusig! Kzben minden indexre rendeljk hozz a forrs tmbelemet
a cl tmbelemhez! Vigyzzunk, hogy a lnczr nulla is tkerljn!
void strcopy(char cl[], char forrs[]){
int i=0;
while((cl[i]=forrs[i])!=0) ++i; }
Javtsunk kicsit ezen a megoldson! A whilebeli relci elhagyhat,
hisz a hozzrendels is mindig igaz (nem zrus), mg a forrs[i] nem
lnczr zrus. Belthat, hogy a \0 karakter is tkerl, mert a while
csak a hozzrendels vgrehajtsa utn veszi csak szre, hogy kifejezse
hamiss (zruss) vlt. Teht:
while(cl[i]=forrs[i]) ++i;
Lssuk be, hogy a
while(cl[i++]=forrs[i]);
is tkletesen funkcionl, hisz
- Ellltja a forrs tmb iik elemt.
- Ezt hozzrendeli cl tmb iik elemhez.
- Az uttag ++ miatt mellkhatsknt kzben i rtke is n egyet.
A legjobb megoldsunk teht:
void strcopy(char cl[], char forrs[]){
int i=0;
while(cl[i++]=forrs[i]); }
70 TPUSOK S KONSTANSOK
A void strct(char s1[], char s2[]) egyesti a kt paramter karakterln-
cot s1be.
Indexeljnk elre az s1en a lnczr nullig, s ezutn ide kell msolni
az s2 karakterlncot!
Belthat, hogy a helyes megoldshoz kt indexvltoz szksges,
mert a msolsnl az egyiknek s1 lnczr nulljnak indextl kell in-
dulnia, mg a msiknak s2n zrustl.
void strct(char s1[], char s2[]){
int i=0, j=0;
while(s1[i]) ++i;
while(s1[i++]=s2[j++]); }
A void strup(char s[]) nagybetss alaktja sajt helyn az s karakter-
lncot.
Indexeljnk vgig az s karaktertmbn a lnczr zrusig! Egyegy po-
zcin meg kell vizsglni a tmbelem rtkt. Ha nem kisbet, akkor nem
kell tenni semmit. Ha kisbet, t kell rni nagybetv. Ha csak az angol
bc betivel foglalkozunk, akkor meg kell hatrozni a kisbet tmbe-
lem eltolst ahoz kpest, s ezt az eltolst hozz kell adni Ahoz.
void strup(char s[]){
int i;
for(i=0; s[i]; ++i)
if(s[i]>=a&&s[i]<=z)s[i]=s[i]-a+A; }
Felttlenl meg kell emlteni, hogy a most megrt karakterlnc keze-
l fggvnyek kicsit ms nvvel, de azonos funkcival, s paramterezs-
sel lteznek a szabvny knyvtrban. Hasznlatukhoz azonban a
STRING.H fejfjlt be kell kapcsolni. A nvlista:
strlen strlen
strcopy strcpy
strct strcat
strup strupr
Prbljuk ki a megrt fggvnyeinket egy rvid programmal! Krjnk be
egy sort a szabvny bemenetrl! Alaktsuk t nagybetss! Tegyk el az
ELEJE:, s mg a :VGE szveget! Jelentessk meg az eredmnyt! rjuk
mg ki az eredeti s az egyestett karakterlnc hosszt!
Helyszke miatt a fggvnyek teste helyett csak /* */eket kz-
lnk. A valsgban oda kell msolni a fggvnydefinci forrsszvegt
is.
/* PELDA13.C: Karakterlnc kezelse */
#include <stdio.h>
#define SOR 80 /* Bemeneti sor max. hossza. */
C programnyelv 71
int getline(char s[],int n){ /* ... */ }
unsigned strlen(char s[]){ /* ... */ }
void strcopy(char cl[], char forrs[]){ /* ... */ }
void strct(char s1[], char s2[]){ /* ... */ }
void strup(char s[]){/* ... */ }
void main(void){
int n; /* A bemeneti sor hossza. */
char sor[SOR+1], /* A bemeneti sor. */
egy[SOR*2]; /* Az egyestett karakterlnc. */
printf("Adjon meg egy sort!\n"
"Nagybetss alaktva megjelentetjk\n"
"ELEJE: :VGE szvegekbe zrva.\n"
"Kzljk az eredeti s a vgs hosszt is.\n");
n=getline(sor,SOR);
strcopy(egy, "ELEJE:");
strct(egy, sor);
strup(egy);
strct(egy, ":VGE");
printf("%s\nEredeti hossz:%3d\nMostani hossz:%3d\n",
egy, n, strlen(egy)); }
Megoldand feladatok:
Ksztse el a kvetkez fggvnyeket, s prblja is ki ket egy rvid
programmal!
- A void strlw(char s[]) kisbetss alaktja sajt helyn az s karakter-
lncot.
- Az int toup(int c) nagybetss alaktva visszaadja c rtkt.
- Az int tolw(int c) visszatrsi rtke c kisbetss alaktva.
- A void chdel(char s[], int c) kitrli az s karakterlncbl a sajt he-
lyn a benne elfordul c karaktereket. Msoljuk t az s karakterln-
cot egy segd tmbbe gy, hogy az aktulis karakter csak akkor ke-
rljn t, ha nem c! Az eredmny karakterlnc aztn visszamsolan-
d sbe! Sokkal jobb, ha a feladatot segd tmb nlkl oldjuk meg,
s a msolst a ck kihagysval rgtn az s tmbbe vgezzk. {CH-
DEL.C}
4.5 Deklarci
A deklarci megteremti a kapcsolatot az azonost s az objektum k-
ztt, ill. rgzti pldul tbbek kztt az objektum adattpust. Ktfle
deklarcirl beszlhetnk:
72 TPUSOK S KONSTANSOK
- A defincis deklarcival (definci) helyet foglaltatunk az objek-
tumnak a memriban, s esetleg kezdrtkkel is inicializljuk.
Ilyen deklarci egy azonostra csak egyetlen egy ltezhet az egsz
forrsprogramban.
- A referencia deklarci (deklarci) nem foglal memrit az objek-
tumnak, de tudatja a fordtval, hogy van egy ilyen azonostj,
adattpus, stb. objektum a programban. Ebbl a deklarcibl -
egymsnak ellent nem mondan - tbb is ltezhet ugyanarra az ob-
jektumra.
- Szlnunk kell mg deklarcis pontrl! Ez az azonost deklarci-
jnak helye a forrsprogramban. Az azonost deklarcis pontja
eltt leglisan nem rhet el a forrskdban.
Tudjuk azt is, hogy a deklarci elhelyezse s maga a deklarci meg-
hatrozza az objektum attribtumait:
- tpus,
- trolsi osztly,
- hatskr,
- lettartam stb.
A ksrleti definci fogalmt az ANSI szabvny vezette be. Brmely
kls adatdeklarci, melynek nincs trolsi osztly specifiktora s nincs
explicit inicializtora, ksrleti defincinak tekintend. Ha a deklarlt
azonost aztn feltnik egy ksbbi definciban, akkor a ksrleti defin-
cit extern trolsi osztlynak kell venni. Ms szval, a ksrleti defin-
ci egyszer referencia deklarci.
Ha a fordtsi egysg vgig sem tallkozunk defincival a ksrleti de-
fincis azonostra, akkor a ksrleti definci teljes definciv vlik
tiszta zrus kezdrtk objektummal.
int x;
int x; /* OK leglis, hisz nem mondtunk jat. */
int y;
int y = 4; /* OK. Most specifikltuk, hogy y-t 4-re kell
inicializlni. */
int z = 4;
int z = 6; /* HIBS, mert mindkett inicializlna. */
A deklarlhat objektumok a kvetkezk:
- vltozk,
C programnyelv 73
- fggvnyek,
- tpusok,
- tpusok tmbjei,
- enum konstansok s cmkk.
Deklarlhatk mg a kvetkez ksbbi fejezetekben trgyalt objek-
tumok is: struktra, uni s utasts cmkk, struktra s unitagok, vala-
mint elfeldolgoz makrk.
A deklartor szintaktika rekurzivitsa miatt egszen komplex deklarto-
rok is megengedettek. Ezt el szoks kerlni tpusdefincival (typedef). A
deklarci metanyelvi lersa a kvetkez:
deklarci:
deklarci-specifiktorok<init-deklartorlista>
deklarci-specifiktorok:
trolsi-osztly-specifiktor<deklarci-specifiktorok>
tpusspecifiktor<deklarci-specifiktorok>
init-deklartorlista:
init-deklartor
init-deklartorlista, init-deklartor
init-deklartor:
deklartor
deklartor=inicializtor
inicializtor:
hozzrendels-kifejezs
{inicializtorlista}
{inicializtorlista ,}
inicializtorlista:
inicializtor
inicializtorlista, inicializtor
trolsi-osztly-specifiktor:
auto
register
extern
static
typedef
tpusspecifiktor:
void
char
short
int
long
float
double
signed
74 TPUSOK S KONSTANSOK
unsigned
const
volatile
struktra-vagy-uni-specifiktor
enum-specifiktor
typedef-nv
typedef-nv:
azonost
deklartor:
<mutat>direkt-deklartor
direkt-deklartor:
azonost
(deklartor)
direkt-deklartor [<konstans-kifejezs>]
direkt-deklartor (paramter-tpus-lista)
direkt-deklartor (<azonostlista>)
konstans-kifejezs:
feltteles-kifejezs
azonostlista:
azonost
azonostlista, azonost
A mutatkkal, a struktrval, az unival, a fggvnyekkel, az utas-
ts cmkkkel s a makrkkal ksbbi szakaszokban s fejezetekben fog-
lalkozunk, gy a vonatkoz metanyelvi lersok is ott tallhatk.
A trolsi-osztly-specifiktorokat teljes rszletessggel majd egy k-
sbbi fejezetben taglaljuk, de kzlk kettrl (auto s extern) mr sz
volt a BEVEZETS S ALAPISMERETEK szakaszban. A kvetkez
fejezet nmi elzetes kpet ad a typedefrl.
A tpusspecifiktorokat alaptpusokra s tpusmdostkra bontottuk ko-
rbban. A tpusmdostk s alaptpusok megengedett, egyttes hasznla-
tt e szakasz elz fejezeteiben tisztztuk. A const s a volatile viszont
brmely alaptpussal s tpusmdostval egytt szinte korltozs nlkl
hasznlhat.
A deklartor egyedi azonostt hatroz meg. Mikor az azonost megje-
lenik egy vele egyeztpus kifejezsben, akkor a vele elnevezett objek-
tum rtkt eredmnyezi.
A konstans-kifejezs mindig fordtsi idben is meghatrozhat kons-
tans rtkk rtkelhet ki, azaz rtke bele kell hogy frjen a tpus br-
zolsi hatraiba. A konstans kifejezs brhol alkalmazhat, ahol konstans
egybknt hasznlhat. A konstans kifejezs operandusai lehetnek egsz
konstansok, karakter konstansok, lebegpontos konstansok, enumerto-
rok, tpusmdost szerkezetek, sizeof kifejezsek, stb. A konstans kifeje-
C programnyelv 75
zs azonban a sizeof opertor operandustl eltekintve nem tartalmazhatja
a kvetkez opertorok egyikt sem:
- hozzrendels,
- vessz,
- dekrementls,
- inkrementls s
- fggvnyhvs.
4.5.1 Elemi tpusdefinci (typedef)
Nem tartozik igazn ide a tpusdefinci trgyalsa, de miutn a typedef
kulcsszt a trolsi osztly specifiktor helyre kell rni, itt adunk rla egy
rvid ismertetst.
A typedef kulcsszval nem j adattpust, hanem j adattpus specifik-
tort definilunk. Legyen sz pldul az
auto long int brigi;
defincirl, mely szerint a brigi egy 32 bites, signed long int tpus, lo-
klis lettartam objektum azonostja. Hasznljuk most az auto kulcssz
helyett a typedef-et, s az azonostt rjuk t nagybetsre!
typedef long int BRIGI;
, ahol a BRIGI azonost nem kpez futsidej objektumot, hanem egy j
tpusspecifiktor csak. A programban ezutn a BRIGI tpusspecifiktor-
knt alkalmazhat deklarcikban. Pldul az
extern BRIGI fizetni;
ugyanolyan hats, mint az
extern long int fizetni;
Ez az egyszer plda megoldhat lenne a
#define BRIGI long
mdon is, a typedef-fel azonban az egyszer szveghelyettestsnl
komplexebb alkalmazsok is thidalhatk.
A typedef nem hoz ltre j tpust tulajdonkppen, csak ltez tpusokra
krelhat vele j kulcssz. Komplexebb deklarcik egyszerstsre va-
l.
76 TPUSOK S KONSTANSOK
e A tpusdefinci megbonyoltsra a ksbbiekben mg visszat-
rnk! Meg kell jegyeznnk azonban annyit, hogy a typedef-fel ltrehozott
tpusspecifiktor nem hasznlhat a deklarciban ms tpusspecifikto-
rokkal egytt! Legfeljebb a const s a volatile mdostk alkalmazhatk
r! Pldul
unsigned BRIGI keresni; /* HIBS. */
const BRIGI kaba = 2; /* OK */
C programnyelv 77
5 MVELETEK S KIFEJEZSEK
A mveleteket a nyelv opertorokkal (mveleti jelekkel) valstja meg.
A mveletek lehetnek:
- Egyoperandusos ak. Alakjuk opertor operandus, ahol az operan-
dus az a kifejezs, melyen az egyoperandusos mveletet el kell v-
gezni. Pldul: 6, vagy a sizeof(int) stb.
- Ktoperandusos ak, azaz operandus1 opertor operandus2 form-
jak. Pldul: a + b.
- Hromoperandusos ak: A C-ben egyetlen ilyen mvelet van, az n.
feltteles kifejezs. Pldul: (a > b) ? a : b rtke a, ha a > b s b
msklnben.
opertor: (a kvetkezk egyike!)
[ ] ( ) . -> ++ -- & * + - ~ ! sizeof / % << >> < > <= >= == != = ^ | && || ?: *= /= +=
-= %= <<= >>= &= ^= |= ,
A kifejezs opertorok, operandusok (s elvlaszt-jelek) sorozata, mely
az albbi tevkenysgek valamilyen kombincijt valstja meg:
- rtket szmt ki.
- Objektumot vagy fggvnyt r el.
- Mellkhatst generl.
A kifejezsbeli operandusokat elsdleges kifejezsnek nevezik.
elsdleges-kifejezs:
azonost
konstans
karakterlnc
(kifejezs)
kifejezs:
hozzrendels-kifejezs
kifejezs, hozzrendels-kifejezs
A konstansokat, a karakterlncot trgyaltuk a TPUSOK S KONS-
TANSOK szakaszban, a hozzrendels-kifejezst definilni fogjuk a hoz-
zrendels opertoroknl. Az azonost lehet brmilyen egsz vagy lebe-
gpontos tpus. Lehet enum, tmb, mutat, struktra, uni, vagy fgg-
vny tpus. Lehet teht:
- vltoz azonost belertve az indexel opertort is, azaz az azono-
st[kifejezs]-t is, s az uni, ill. a struktratagokat, vagy
78 MVELETEK S KIFEJEZSEK
- fggvnyhvs, azaz azonost a fggvnyhvs opertorral ( azono-
st() ), melynek tpusa mindig a fggvny ltal visszaadott rtk t-
pusa lesz.
sszestve: az azonostnak balrtknek vagy fggvnyhvsnak
kell lennie.
A kifejezs kirtkelse bizonyos
- konverzis,
- csoportost,
- asszociatv s
- prioritsi (precedencia)
szablyokat kvet, mely fgg
- a hasznlt opertoroktl,
- a ( ) prok jelenlttl s
- az operandusok adattpustl.
A kifejezsek klnflk lehetnek:
- elsdleges kifejezs (primary),
- uttag kifejezs (postfix),
- egyoperandusos kifejezs (unary),
- eltag kifejezs (cast),
- hozzrendels kifejezs stb.
Figyeljk meg, hogy a kifejezsek elnevezse - az elsdleges kifeje-
zstl eltekintve - a vele hasznlatos opertorok szerint trtnik!
uttag-kifejezs:
elsdleges-kifejezs
uttag-kifejezs[kifejezs]
uttag-kifejezs(<kifejezslista>)
uttag-kifejezs.azonost
uttag-kifejezs->azonost
uttag-kifejezs++
uttag-kifejezs
kifejezslista:
hozzrendels-kifejezs
kifejezslista , hozzrendels-kifejezs
C programnyelv 79
egyoperandusos-kifejezs:
uttag-kifejezs
++ egyoperandusos-kifejezs
-- egyoperandusos-kifejezs
egyoperandusos-opertor eltag-kifejezs
sizeof(egyoperandusos-kifejezs)
sizeof(tpusnv)
egyoperandusos-opertor: ( a kvetkezk egyike!)
& * + - ~ !
eltag-kifejezs:
egyoperandusos-kifejezs
(tpusnv) eltag-kifejezs
tpusnv:
tpusspecifiktor-lista<absztrakt-deklartor>
absztrakt-deklartor:
mutat
<mutat><direkt-absztrakt-deklartor>
direkt-absztrakt-deklartor:
(absztrakt-deklartor)
<direkt-absztrakt-deklartor>[<konstans-kifejezs>]
<direkt-absztrakt-deklartor>(<paramter-tpus-lista>)
A tpusnv az adattpus tpusneve. Szintaktikailag az adott tpus objek-
tum olyan deklarcija, melybl hinyzik az objektum neve.
A hozzrendels-kifejezst, melyrl most csak annyit jegyznk meg,
hogy nem balrtk, majd a hozzrendelsi mveleteknl ismertetjk!
5.1 Aritmetikai mveletek (+, -, *, / s %)
Kzlk a legmagasabb prioritsi szinten az egyoperandusos, jobbrl
balra kt eljel opertorok vannak. Ltezik a
- eltag-kifejezs
s a szimmetria kedvrt a
+ eltag-kifejezs.
Az eljel opertort kvet eltag kifejezsnek aritmetikai tpusnak kell
lennie, s az eredmny az operandus rtke (+), ill. annak -1-szerese (-). A
+ mvelet egsz operandust egszellptetsnek (integral promotion)
veti al a fordt, s gy az eredmny tpusa az egszellptets vgrehaj-
tsa utn kpzett tpus. A mveletet megelzheti implicit tpuskonver-
zi, s egsz operandus esetn az eredmny az operandus rtknek kettes
komplemense.
Az egszellptetssel az implicit tpuskonverzi kapcsn rgtn
foglalkozunk!
80 MVELETEK S KIFEJEZSEK
A tbbi aritmetikai opertor mind ktoperandusos, melyek kzl a szor-
zs (*), az oszts (/) s a modulus (%) magasabb prioritsi szinten van,
mint az sszeads (+) s a kivons (-). A szorzst, az osztst s a modu-
lust multiplikatv opertoroknak, az sszeadst s a kivonst additv ope-
rtoroknak is szoks nevezni.
5.1.1 Multiplikatv opertorok (*, / s %)
multiplikatv-kifejezs:
eltag-kifejezs
multiplikatv-kifejezs * eltag-kifejezs
multiplikatv-kifejezs / eltag-kifejezs
multiplikatv-kifejezs % eltag-kifejezs
Nzzk a mveletek pontos szablyait!
- A multiplikatv opertorok mind balrl jobbra csoportostanak.
- Mindhrom opertor operandusainak aritmetikai tpusaknak kell
lennik. A % opertor operandusai radsul csak egsz tpusak le-
hetnek.
- Ha az operandusok klnbz aritmetikai tpusak, akkor a mvelet
elvgzse eltt implicit konverzit hajt vgre a fordt. Az ered-
mny tpusa ilyenkor a konvertlt tpus. Miutn a konverzinak nin-
csenek tl vagy alulcsordulsi felttelei, rtkveszts kvetkezhet
be, ha az eredmny nem fr el a konverzi utni tpusban.
- A / s a % msodik operandusa nem lehet zrusrtk, mert ez for-
dtsi vagy futsidej hibhoz vezet.
- Ha a / s a % mindkt operandusa egsz, de a hnyados nem lenne
az, akkor:
- Ha a kt operandus - mondjuk op1 s op2 - rtke azonos eljel
vagy unsigned, akkor az op1/op2 hnyados az a legnagyobb
egsz, ami kisebb, mint az igazi hnyados s az op1%op2 osztsi
maradk op1 eljelt rkli meg:
3 / 2 1 3 % 2 1
(-3) / (-2) 1 (-3) % (-2) -1
- Ha op1 s op2 ellenkez eljel, akkor az op1/op2 hnyados az a
legkisebb egsz, ami nagyobb az igazi hnyadosnl. Az op1%op2
osztsi maradk most is op1 eljelt rkli meg:
(-3) / 2 -1 (-3) % 2 -1
3 / (-2) -1 3 % (-2) 1
C programnyelv 81
Ksztsnk programot, ami beolvas egy ngyjegy vszmot, s eldnti
rla, hogy szkve, vagy sem!
A Gergelynaptr szerint szkv minden, nggyel maradk nlkl
oszthat v. Nem szkv a kerek vszzad, de a 400zal maradk nlkl
oszthatk mgis azok.
1. Olvassunk be a szabvny bemenetrl egy maximlisan ngy karak-
teres sort!
2. Ha a bejtt karakterlnc hossza nem pontosan ngy, akkor krjk be
jra!
3. Ellenrizzk le, hogy a karakterlnc minden pozcija numerikuse!
Ha nem, jra bekrend.
rjunk int nume(char s[]) fggvnyt, mely 1et (igazat) ad vissza, ha a
paramter karakterlnc tiszta numerikus, s zrust (hamisat), ha nem!
int nume(char s[]){
int i;
for(i=0; s[i]; ++i) if(s[i]<0||s[i]>9) return 0;
return 1; }
4. t kne konvertlni a numerikus karakterlncot fixpontos belsb-
rzols egssz (int nn)! A mdszer a kvetkez:
n=(s[0]-0)*1000+(s[1]-0)*100+(s[2]-0)*10+
(s[3]-0);
Ezt ugye ciklusban, ahol i s n zrustl indul, s i egyesvel haladva
vgigjrja a numerikus karakterlncot, gy kne csinlni:
n=n*10+(s[i]-0);
rjunk int atoi(char s[]) fggvnyt, mely megvalstja ezt a konverzit,
s n lesz a visszaadott rtke! Az talaktst vgezze az els nem konver-
tlhat karakterig! Engedjk meg, hogy a numerikus karakterlnc elejn
fehr karakterek s eljel is lehessen! Ha az eljelet elhagyjk, akkor le-
gyen a szm pozitv!
int atoi(char s[]){
int i=0, n=0;
int elojel=1; /* Alaprtelmezs: pozitv. */
/* A karakterlnc eleji fehr karakterek tlpse: */
while(s[i]== ||s[i]==\n||s[i]==\t) ++i;
/* Eljel: */
if(s[i]=='+'||s[i]=='-') if(s[i++]=='-') elojel=-1;
/* Konverzi: */
for(;s[i]>='0'&&s[i]<='9';++i) n=10*n+s[i]-'0';
return(elojel*n); }
82 MVELETEK S KIFEJEZSEK
Megemltend, hogy pontosan ilyen prototpus, nev s funkcij
fggvny ltezik a szabvny knyvtrban is, de bekapcsoland hozz a
szabvnyos STDLIB.H fejfjl. A knyvtrban van atol rutin, mely long
g, s van atof, mely doublel alaktja numerikus karakterlnc param-
tert.
Jhet a program, de helyszke miatt a fggvnyek definciit nem
ismteljk meg!
/* PELDA14.C: A ngyjegy vszm szkv-e? */
#include <stdio.h>
#define MAX 80
int getline(char s[], int n);
int nume(char s[]);
int atoi(char s[]);
void main(void){
int ev = 0; /* Elfogadhatatlan rtkrl indul. */
char s[MAX+1]; /* Az input puffer. */
printf("A ngyjegy vszm szkv-e?\n");
while(ev<1000 || ev>9999){
printf("Adjon meg egy vszmot!\n");
if(getline(s,4)==4&&nume(s)) ev=atoi(s);
else printf(Formailag hibs bemenet!\n); }
if(ev%4==0&&ev%100!=0||ev%400==0)
printf("%4d szkv.\n", ev);
else printf("%4d nem szkv.\n", ev); }
Megoldand feladatok:
Ksztsen szmot ler karakterlncok formai ellenrzst vgz fgg-
vnyeket az atoi alapjn, melyek helyes esetben 1et (igaz) adnak vissza,
s a hibt zrussal (hamis) jelzik! A lnc eleji fehr karaktereket t kell
lpni. A szm vgt a karakterlnc vge, vagy jabb fehr karakter kvet-
kezse mutatja.
- Az int egesze(char s[]) a decimlis egsz konstans rsszablyt el-
lenrzi a paramter karaktertmbn.
- Az int hexae(char s[]) megvizsglja, hogy paramtere hexadecim-
lis szme. {HEXA.C}
- Az int ell210e(char s[]) teszteli, hogy s 2 s 10 kztti alap szm
e. A szmrendszer alapjt fordtsi idben vltoztatni (#define) le-
het!
- Az int ellae(char s[], int alap) ugyanazt teszi, mint az ell210e, de a
2 s 10 kztti alapot futsi idben paramterknt kapja meg.
- Az int ella36e(char s[], int alap) egyezik ellaevel, de az alap 2 s
36 kztti lehet.
C programnyelv 83
A tznl nagyobb alap szmrendszerek esetben a szmjegyeket az
angol bc betivel jelljk rendre, vagyis 10=A, 11=B stb. A 36os
korltozs ebbl fakad.
Ksztsen konverzis fggvnyeket is a leellenrztt karakterlncokra
az atoi mintjra, s a konvertlt rtk legyen a rutinok visszatrsi rt-
ke!
- A double atofix(char s[]) az eljeles, legfeljebb egsz s trt rsz-
bl ll vals rtket alaktja doublel.
- A long atoh(char s[]) hexadecimlis karakterlncot alakt egssz.
{HEXA.C}
- A long ato36(char s[], int alap) a legfeljebb 36 alap szmrend-
szerbeli lncot konvertlja egssz.
5.1.2 Additv opertorok (+ s -)
additv-kifejezs:
multiplikatv-kifejezs
additv-kifejezs + multiplikatv-kifejezs
additv-kifejezs - multiplikatv-kifejezs
Az additv opertorok csoportostsa is balrl jobbra trtnik. Operan-
dusaik az aritmetikai rtkeken tl mutatk is lehetnek.
A mutataritmetikt majd a mutatk kapcsn ismertetjk!
Aritmetikai operandusok esetn az eredmny a kt operandus rtknek
sszege (+), ill. klnbsge (). Egsz vagy lebegpontos operanduson a
mvelet implicit tpuskonverzit is vgezhet, ha szksges. Ilyenkor az
eredmny tpusa a konvertlt tpus. Miutn a konverzinak nincsenek tl
vagy alulcsordulsi felttelei, rtkveszts kvetkezhet be, ha az ered-
mny nem fr el a konverzi utni tpusban.
5.1.3 Matematikai fggvnyek
A matematikai fggvnyek nem rszei a C nyelvnek. Nyilvnval vi-
szont, hogy kifejezsek kpzsekor szksg lehet rjuk. A C filozfija
szerint a matematikai fggvnyek csaldjt is a szabvny knyvtrban kell
elhelyezni, mint ahogyan a szabvny bemenet s kimenet kezelst vgz
rutinokat.
Az ANSI szabvny pontosan rgzti ezeket a knyvtri funkcikat, gy
brmilyen szabvnyos C fordt s opercis rendszer szmra kompatibi-
lis formban lteznik kell. Magyarn: azok a programok, melyek az ope-
rcis rendszerrel val kapcsolatukat a szabvny knyvtron t valstjk
84 MVELETEK S KIFEJEZSEK
meg, minden vltoztats nlkl tvihetk az egyik szmtgprl a msik-
ra, az egyik opercis rendszerbl a msikba. Ezek az gy nevezett port-
bilis programok.
A szabvny knyvtr fggvnyeit, tpusait s makrit szabvnyos fejfj-
lokban deklarltk. Ezek kzl nhnnyal mr tallkoztunk, msokkal
meg mg nem:
ASSERT.H CTYPE.H ERRNO.H FLOAT.H ISO646.H
LIMITS.H LOCALE.H MATH.H SETJMP.H SIGNAL.H
STDARG.H STDDEF.H STDIO.H STDLIB.H STRING.H
TIME.H WCHAR.H WCTYPE.H
A matematikai fggvnyek prototpusai a MATH.H fejfjlban helyez-
kednek el, gy hasznlatuk eltt ez a fejfjl bekapcsoland!
#include <math.h>
Nem kvnjuk felsorolni s rszletezni az sszes fejfjlt, az sszes
fggvnyt, csak nhny fontosabbat emltnk meg kzlk. Az olvastl
azonban elvrjuk, hogy a programfejleszt rendszere segtsgbl a tovb-
bi fejfjlokrl s rutinokrl is tjkozdjk.
A matematikai fggvnyek double rtket szolgltatnak, s nhny kiv-
teltl eltekintve, paramtereik is double tpusak. A matematikbl isme-
retes korltozsok termszetesen rvnyben maradnak rjuk. A trigono-
metrikus fggvnyek paramtere, ill. inverzeik visszaadott rtke radin-
ban rtend.
Nhnyat felsorolunk a teljessg ignye nlkl!
sin(x) x szinusza.
cos(x) x koszinusza.
tan(x) x tangense.
asin(x) 1<=x<=1 rkusz szinusza. Az rtkkszlet: [/2, /2].
acos(x) 1<=x<=1 rkusz koszinusza. Az rtkkszlet: [0, ].
atan(x) x rkusz tangense. Az rtkkszlet: [/2, /2].
exp(x) Az e
x
exponencilis fggvny.
log(x) x>0 termszetes alap logaritmusa. (ln(x)).
log10(x) x>0 tzes alap logaritmusa. (lg(x)).
pow(x, y) Az x
y
hatvnyfggvny. Hiba, ha x=0 s y<=0, ill. ha x<0
s y rtke nem egsz.
sqrt(x) x>=0 ngyzetgyke.
floor(x) Az xnl nem nagyobb, legnagyobb egsz szm.
fabs(x) Az x abszolt rtke.
C programnyelv 85
fmod(x, y) y!=0 estn x/y oszts lebegpontos maradka, mely xszel
egyez eljel.
A szabvny knyvtri fggvnyek, gy a matematikaiak is, a hibt gy
jelzik, hogy valamilyen specilis rtket (HUGE_VAL, zrus stb.) adnak
vissza, s belltjk a UNIXtl rklt, globlis
extern int errno;
(hibaszm) vltozt a hiba kdjra. A hibakdok az ERRNO.H fejfjlban
definilt, egsz, nem zrusrtk szimbolikus llandk. A HUGE_VAL a
legnagyobb, pozitv, mg brzolhat double rtk.
A matematikai rutinok az rtelmezsi tartomny hibt EDOM rtk
errnoval, s a fordttl is fgg fggvny visszatrsi rtkkel jelzik.
rtkkszlet problma esetn az errno ERANGE. A fggvny visszatr-
si rtk tlcsordulskor eljel helyes HUGE_VAL, ill. alulcsordulskor
zrus.
Az rtelmezsi tartomny hiba akkor fordul el, ha a fggvny aktu-
lis paramternek rtke nincs benn az rtelmezsi tartomnyban. rtk-
kszlet hiba egyrtelmen az, ha az eredmny nem brzolhat double r-
tkknt.
Pldul az sqrt(1.) hatsra az errno EDOM, s a visszakapott rtk
negatv HUGE_VAL.
Megoldand feladatok:
Ksztend a kzpiskols fggvnytblzatok mintjra lapozhatan:
- egy logaritmustbla s
- egy szinusztbla.
5.2 Relci opertorok ( >, >=, <, <=, == s !=)
A relci opertorok prioritsa - eltekintve az egyoperandusos mvele-
tektl - az aritmetikai s a logikai opertorok kztt helyezkedik el. A re-
lci opertorok kt prioritsi szintet kpeznek, ahol az igazi relcik
(>, >=, < s <=) prioritsa magasabb az egyenlsgi relciknl (== s !
=). Az sszes relci az els operandus rtkt hasonltja a msodikhoz,
s a relci rvnyessgt vizsglja. Az eredmny logikai rtk (int tpu-
s), mely 1, ha a relci igaz s 0, ha nem. A defincik:
relcis-kifejezs:
eltols-kifejezs
relcis-kifejezs < eltols-kifejezs
relcis-kifejezs > eltols-kifejezs
86 MVELETEK S KIFEJEZSEK
relcis-kifejezs <= eltols-kifejezs
relcis-kifejezs >= eltols-kifejezs
egyenlsgi-kifejezs:
relcis-kifejezs
egyenlsgi-kifejezs == relcis-kifejezs
egyenlsgi-kifejezs != relcis-kifejezs
Az eltols-kifejezst a bitenknti eltols opertoroknl definiljuk!
A relcik operandusai egsz, lebegpontos, vagy mutat tpusak. Az
operandusok tpusa klnbzhet. Az opertorok implicit tpuskonverzit
is vgrehajthatnak aritmetikai operandusaikon a mvelet elvgzse eltt.
Ne feledjk, hogy a
kifejezs != 0
relci mindig rvidthet
kifejezs
mdon, mert a nyelvben a nem zrus rtk logikai igaznak minsl.
Pldaknt tekintsk meg jra a korbbi szakaszokban ismertetett
atoi s getline fggvnyeket!
5.3 Logikai mveletek ( !, && s ||)
Kzlk a legmagasabb prioritsi szinten az egyoperandusos, jobbrl
balra kt, logikai nem opertor van, melynek alakja:
! eltag-kifejezs
, ahol az eltag-kifejezs operandusnak egsz, lebegpontos, vagy mutat
tpusnak kell lennie. Az eredmny mindenkppen int tpus, s az operan-
dus logikai negcija. Az eredmny 0, ha az operandus rtke nem zrus,
ill. 1, ha az operandus rtke zrus. Ez utbbi mondatrsz biztostja, hogy
a
kifejezs == 0
mindenkor rvidthet
! kifejezs
mdon. Pldul a multiplikatv opertoroknl ismertetett program rszlet
if( ev%4 == 0 && ev%100 != 0 || ev%400 == 0)
utastsa gy rvidthet:
if( !(ev%4) && ev%100 || !(ev%400))
Kt ktoperandusos logikai mvelet van a nyelvben a logikai s (&&) s
a logikai vagy (||), melyek prioritsa alacsonyabb a relciknl s a bit
C programnyelv 87
szint mveleteknl. A logikai s prioritsa radsul magasabb, mint a lo-
gikai vagy. Mindkt mvelet balrl jobbra csoportost. Egyik opertor
sem hajt vgre implicit tpuskonverzit operandusain, ehelyett zrushoz
viszonytva rtkeli ki ket. Az eredmny int tpus (1 - igaz s 0 -
hamis).
logikai-s-kifejezs:
vagy-kifejezs
logikai-s-kifejezs && vagy-kifejezs
logikai-vagy-kifejezs:
logikai-s-kifejezs
logikai-vagy-kifejezs || logikai-s-kifejezs
A vagy-kifejezs defincijt a bit szint mveleteknl talljuk meg!
A K1&&K2 kifejezs eredmnye igaz (1), ha K1 s K2 egyike sem z-
rus. A K1||K2 kifejezs igaz (1), ha K1 s K2 valamelyike is nem zrus.
Msklnben K1&&K2 s K1||K2 eredmnye hamis (0).
e Mindkt opertor esetben garantlt a balrl jobbra trtn vgre-
hajts. Elszr K1et rtkeli ki a fordt az esetleges sszes mellkhat-
sval egytt, de:
- K1&&K2 esetn, ha K1 zrus, az eredmny hamis (0), s K2 kirt-
kelse nem trtnik meg.
- K1||K2 kifejezsnl, ha K1 nem zrus, az eredmny igaz (1) lesz, s
K2 kirtkelse itt sem zajlik le.
Ha valami elbbre val, vagy mindenkpp szeretnnk, hogy megtr-
tnjen, akkor azt a bal oldali operandusba kell bepteni. Pldul a PEL-
DA10.Cben megrt getline for ciklusnak felttele nem vletlenl
i<n && (c=getchar())!=EOF && c!=\n
sorrend, hisz elszr azt kell biztostani, hogy a paramter karaktertm-
bt ne rhassa tl a fggvny. Ez nem kerlhet htrbb a kifejezsben. Az-
tn a kvetkez karaktert elbb be kell olvasni a bemenetrl, de minden-
nek vge van fjlvg esetn. Itt sincs rtelme a felcserlsnek, mert feles-
leges vizsglgatni a fjlvget, hogy soremelse. A relcik kzti s m-
veletek miatt ltszik, hogy balrl jobbra trtnik az operandusok kirtke-
lse, s ha ekzben az egyik hamis lesz, teljesen felesleges lenne tovbb-
folytatni a kirtkelst.
5.4 Implicit tpuskonverzi s egszellptets
Ha ktoperandusos (pldul aritmetikai) mveleteknl klnbzik a kt
operandus tpusa, akkor a mvelet elvgzse eltt a fordt bels konver-
zit (talaktst) hajt vgre. ltalban a pontosabb operandus tpusra
88 MVELETEK S KIFEJEZSEK
konvertlja a msikat. A ktoperandusos mvelet eredmnynek tpusa a
konvertlt tpus lesz. Ezt a fajta konverzit szabvnyosnak, szoksosnak
is nevezik. A szablyok nem prioritsi sorrendben a kvetkezk:
1. Ha az egyik operandus tpusa long double, akkor a msikat is long
double tpusv konvertlja a fordt.
2. Ha az elz pont nem teljesedik, s az egyik operandus double, ak-
kor a msik is az lesz.
3. Ha az elz kt felttel egyike sem valsul meg, s az egyik operan-
dus float, akkor a msikat is azz konvertlja a fordt.
4. Ha az elz hrom felttel egyike sem teljesl (egyik operandus sem
lebegpontos!), akkor egszellptetst hajt vgre a fordt az ope-
randusok rtkn, ha szksges, s aztn:
- Ha az egyik operandus unsigned long, akkor a msik is azz alakul.
- Ha az elz pont nem teljesl, s az egyik operandus long, a msik
pedig unsigned int, akkor mindkt operandus rtkt long, vagy
unsigned long tpusv konvertlja a fordt. Ha az unsigned int
teljes rtktartomnya brzolhat longknt, akkor a vlaszts
long, msklnben pedig unsigned long.
Ha az int 16, s a long 32 bites, akkor 1L<1U. Hisz az elmondot-
tak szerint az unsigned int longg alakul, s 1L<1L. Ha az int 32 bites,
akkor 1L>1UL, mert a 1L 11111111111111111111111111111111
2
bi-
nrisan, unsigned longg alaktva ugyanez marad, s ez sokkal nagyobb
00000000000000000000000000000001
2
nl.
- Ha az elz pontok nem teljeslnek, s az egyik operandus long,
akkor a msik is az lesz.
- Ha nem teljeslnek az elz pontok, s az egyik operandus unsig-
ned int, akkor a msik is azz alakul.
- Ha az elz pontok nem teljeslnek, akkor minkt operandus int az
rvnybe lpett az egszellptets (integral promotion) miatt. A
signed vagy unsigned char, short int, vagy bitmez objektumok,
ill. az enum tpusak hasznlhatk kifejezsben ott, ahol bennk
egsz llhat. Ha az eredeti tpus minden lehetsges rtkt int kpes
reprezentlni, akkor az rtket int tpusv konvertlja a fordt,
msklnben unsigned int-t. Az egszellptetsi folyamat ga-
rantlja, hogy a konverzi eltti s utni rtk ugyanaz marad. A
C programnyelv 89
konvertlt rtk unsigned eredeti tpusbl 0X00 feltltssel, signed
eredeti tpusbl viszont eljel kiterjesztssel kszl a fels bjtokba.
Tpus Konvertlva Mdszer
char int Az alaprtelmezett char tpustl fgg-
en eljel kiterjeszts van (signed) vagy
0X00 kerl a magasabb helyirtk bjt
(ok)ba (unsigned).
unsigned char int A fels bjt(ok) 0X00 feltltsek.
signed char int Eljel kiterjeszts van a fels bjt(ok)-
ba.
short int int Ugyanaz az rtk eljel kiterjesztssel.
unsigned short unsigned int Ugyanaz az rtk 0X00 feltltssel.
enum int Ugyanaz az rtk.
12. bra: Egszellptets
e Ne feledjk azonban el, hogy a konverzi mindig fggvnyhvst
jelent (gpid!), azaz szksgtelenl ne alkalmazzuk! Csak rtelmes t-
puskonverzikat valst meg a fordt. Pldul az f + i sszeads vgre-
hajtsa eltt - feltve, hogy f float s i int tpus - i rtke (s nem i
maga!) float-t alakul.
Az rtelmetlen lebegpontos kifejezs indexben mg csak megvalsul
gy, hogy a kifejezs rtke trt rszt levgja a fordt
#include <stdio.h>
void main(void){
int t[] = {2,3,4,5,6,7};
float f=1.75;
printf("%d\n",t[f]); }
, azaz 3 lesz az eredmny.
e Numerikus karakterlnc azonban sohasem alakul automatikusan a-
ritmetikai rtkk. Ehhez valamilyen konverzis fggvnyt kell hasznlni.
Az STDLIB.Hbeli atoirl, atolrl s atofrl volt mr sz!
5.5 Tpusmdost szerkezet
Az implicit (szoksos, szabvnyos stb.) konverzikon tl magunk is ki-
knyszerthetnk (explicit) tpuskonverzit a
(tpusnv) eltag-kifejezs
alak, a BEVEZETS S ALAPISMERETEK szakaszban megismert
tpusmdost szerkezet alkalmazsval. Ltjuk, hogy a tpusmdost
szerkezet egyoperandusos, s ez ltal magas priorits mvelet. A definci-
ban a tpusnv a cltpus, s az eltag-kifejezs rtkt erre a tpusra kell
90 MVELETEK S KIFEJEZSEK
konvertlni. Az eltag-kifejezst gy konvertlja a fordt, mintha az rt-
ket egy tpusnv tpus vltoz venn fel. Az explicit tpuskonverzi teht
a hozzrendelsi konverzi szablyait kveti. A leglis tpusmdostsok:
Cltpus Potencilis forrsok
egsz brmilyen egsz vagy lebegpontos tpus, vagy mutat
lebegpontos brmilyen aritmetikai tpus
void brmilyen tpus
Pldaknt vegyk a matematikai fggvnyek kzl a ngyzetgykt,
azaz:
#include <math.h>
double sqrt(double x);
Programunkban van egy int tpus n vltoz, akkor az n+26 pozitv gy-
kt az
sqrt(double(n+26))
fggvnyhvssal kaphatjuk meg.
e Brmilyen azonost, vagy kifejezs tpusa mdosthat voidd.
A tpusmdostsnak alvetett azonost, vagy kifejezs nem lehet azon-
ban void. A void fggvny hvst pldul hiba tpusmdostjuk int-re, a
semmibl nem lehet egszet csinlni.
e A voidd mdostott kifejezs rtke nem kpezheti hozzrende-
ls trgyt. Hasonlan az explicit tpusmdosts eredmnye nem fogad-
hat el balrtkknt hozzrendelsben.
Kifejezst csak olyan helyen mdosthatunk void-d, ahol az rtkre
nincs szksg. Pldul nincs szksg a bejv gombnyomsra:
printf(A folytatshoz ssn Entert-t! ); (void)getchar();
5.6 sizeof opertor
A BEVEZETS S ALAPISMERETEK szakaszbl ismert sizeof
egyoperandusos, jobbrl balra kt, magas priorits mvelet, mely min-
dig az operandusa trolshoz szksges memria mennyisgt szolgltat-
ja bjtban. Az eredmny size_t tpus egsz rtk. Az STDDEF.H fejfjl-
ban megtekintve a tpust tbbnyire azt ltjuk, hogy unsigned int.
A size_t tpus rtelmezse fordttl fgg tulajdonkppen!
Kt klnbz alakja van az opertornak:
sizeof(egyoperandusos-kifejezs)
sizeof(tpusnv)
C programnyelv 91
sizeof(egyoperandusos-kifejezs) esetn az egyoperandusos kifejezs tpu-
st a fordt a kifejezs kirtkelse nlkl hatrozza meg, azaz ha az ope-
randus tmbazonost, az egsz tmb bjtokban mrt helyfoglalshoz ju-
tunk. Pldul a tomb tmb elemszma a kvetkez konstrukcival llapt-
hat meg:
sizeof(tomb) / sizeof(tomb[0])
e A sizeof nem hasznlhat fggvnyre, vagy nem teljes tpus kife-
jezsre, ilyen tpusok zrjelbe tett nevre, vagy olyan balrtkre, mely
bitmez objektumot jell ki.
A sizeof azonban btran alkalmazhat elfeldolgoz direktvkban
is!
#define MERET sizeof(int)*3
5.7 Inkrementls (++), dekrementls (--) s mellkhats
Ezek az opertorok mind egyoperandusosak, s ezrt magas prioritsak.
Mindkt opertor ltezik uttag
uttag-kifejezs++
uttag-kifejezs--
s eltag mveletknt:
++ egyoperandusos-kifejezs
-- egyoperandusos-kifejezs
Az inkrementl s dekrementl kifejezsben az uttag- vagy az egy-
operandusos-kifejezsnek skalr (aritmetikai vagy mutat) tpusnak s
mdosthat balrtknek kell lennik, de az eredmny nem balrtk.
Az inkrementlsnl (++) a balrtk eggyel nagyobb, dekrementlsnl
(--) viszont eggyel kisebb lesz. Eltag opertornl a konstrukci rtke
egyezik az j balrtkkel, mg uttag opertornl a konstrukci rtke
az inkrementls vagy dekrementls vgrehajtsa eltti rtk. Az ered-
mny tpust az operandus tpusa hatrozza meg. Pldul:
int x, i = 3, j = 4, n = 5;
x = n++; /* x == 5 s n ==
6 */
x = ++n; /* x == 7 s n ==
7 */
x = --( n - j + i +6); /* x == 11 */
A kifejezs produklhat
- balrtket,
- jobbrtket vagy
92 MVELETEK S KIFEJEZSEK
- nem szolgltat rtket.
A kifejezsnek ezen kvl lehet mellkhatsa is. Pldul a TPUSOK
S KONSTANSOK szakaszban megrt strcopy zr sorban
while(cl[i++]=forrs[i])
a hozzrendels mellkhatsaknt az i vgrehajts utni rtke is eggyel
nagyobb lesz. A mellkhatst a kifejezs kirtkelse okozza, s akkor k-
vetkezik be, ha megvltozik egy vltoz rtke. Minden hozzrendels o-
pertornak van mellkhatsa. Lttuk, hogy a balrtkre alkalmazott inkre-
mentlsi s dekrementlsi mveletnek is van. Fggvnyhvsnak is le-
het azonban mellkhatsa, ha globlis hatskr objektum rtkt vltoz-
tatja meg.
rjuk meg a void chdel(char s[], int c)t, mely sajt helyen trli a benne
elfordul c karaktereket az s karakterlncbl!
Itt is msolni kell a forrsbl a clba bjtrlbjtra haladva, de a c rt-
k karaktereket ki kell ebbl hagyni. Kt indexre van szksg. Az egyik
az i, mely vgigjrja a forrst. A msik a j, mely a clban mindig a kvet-
kez szabad helyet ri el. A nem c rtk karaktert a kvetkez szabad
helyre kell msolni, s a clbeli indexnek az ezutn kvetkez szabad hely-
re kell mutatnia.
void chdel(char s[], int c){
int i, j;
for(i=j=0; s[i]; ++i) if(s[i] != c) s[j++] = s[i];
s[j] = 0; }
5.8 Bit szint opertorok ( ~, <<, >>, &, ^ s |)
e A bit szint opertorok csak signed s unsigned egsz tpus ada-
tokra: char, short, int s long hasznlhatk.
Legmagasabb prioritsi szinten az egyoperandusos, jobbrl balra kt
egyes komplemens opertor (~) van, melynek defincija:
~ eltag-kifejezs
Az opertor elbb vgrehajtja az egszellptetst, ha szksges. Az
eredmny tpusa az operandus konverzi utni tpusa. Az eredmny maga
a bit szint egyes komplemens, azaz ahol az operandus bit 1 volt, ott az
eredmny bit 0 lesz, s ahol az operandus bit 0 volt, ott az eredmny bit 1
lesz. Feltve, hogy az egszellptets 16 bites, s hogy:
unsigned short x = 0XF872, /* 1111100001110010 */
maszk = 0XF0F0;/* 1111000011110000 */
, akkor a ~x 0000011110001101
2
, s a ~maszk 0000111100001111
2
.
C programnyelv 93
A balrl jobbra csoportost eltols opertorok (<< s >>) prioritsa ala-
csonyabb az aritmetikai mveleteknl, de magasabb, mint a relci ope-
rtorok. Az eltols opertorok els operandusuk rtkt balra (<<) vagy
jobbra (>>) toljk annyi bitpozcival, mint amennyit a msodik operan-
dus meghatroz. A definci a kvetkez:
eltols-kifejezs:
additv-kifejezs
eltols-kifejezs << additv-kifejezs
eltols-kifejezs >> additv-kifejezs
A K1<<K2 s a K1>>K2 kifejezsek esetben minkt operandus egsz
tpus kell, legyen. Az opertorok egszellptetst is megvalsthatnak.
Az eredmny tpust K1 konvertlt tpusa hatrozza meg. Ha K2 negatv
vagy rtke nem kisebb K1 bitszlessgnl, akkor az eltolsi mvelet
eredmnye hatrozatlan.
e Miutn a Cben nincs egsz alul vagy tlcsorduls, a mveletek
rtkvesztst is okozhatnak, ha az eltolt eredmny nem fr el az els ope-
randus konvertlt tpusban.
A K1<<K2 balra tolja K1 rtkt K2 bitpozcival gy, hogy jobbrl 0
bitek jnnek be. K1 tlcsorduls nlkli balra tolsa ekvivalens K1*2
K2

vel. Ilyen rtelemben aztn az eltols aritmetikai mveletnek is tekinthet.


Ez a gondolatsor igaz persze az sszes bit szint mveletre is! Ha K1 va-
lamilyen signed tpus, akkor az eltols eredmnye csak gonddal szem-
llhet az eljel bit esetleges kitolsa miatt.
A K1>>K2 mvelet K1 rtkt K2 bitpozcival tolja jobbra. Ha K1 va-
lamilyen unsigned tpus, akkor balrl 0 bitek jnnek be. Ha K1 signed,
akkor az opertor az eljel bitet sokszorozza. unsigned, nem negatv K1
esetn a jobbra tols K1/2
K2
hnyados egsz rszeknt is interpretlhat.
Folytatva az egyes komplemenskpzsnl megkezdett pldt, az x<<2
1110000111001000
2
, ill. a maszk>>5 0000011110000111
2
.
A bit szint logikai opertorok prioritsuk cskken sorrendjben az s
(&), a kizr vagy (^), valamint a vagy (|). A tbbi mveletre val tekin-
tettel prioritsuk magasabb a ktoperandusos logikai opertoroknl, de
alacsonyabb a relciknl. Lssuk a defincit!
s-kifejezs:
egyenlsgi-kifejezs
s-kifejezs & egyenlsgi-kifejezs
kizr-vagy-kifejezs:
s-kifejezs
kizr-vagy-kifejezs ^ s-kifejezs
94 MVELETEK S KIFEJEZSEK
vagy-kifejezs:
kizr-vagy-kifejezs
vagy-kifejezs | kizr-vagy-kifejezs
Az egyenlsgi-kifejezs defincija a relciknl megtallhat!
Ha szksges, akkor a mvelet elvgzse eltt a fordt implicit tpus-
konverzit hajt vgre az egsz tpus operandusok rtkn. Az eredmny
tpusa az operandusok konverzi utni tpusa. A mvelet bitrl-bitre val-
sul meg az operandusok rtkn, s egy bitre vonatkoztatva az eredmny
gy nz ki:
K1 K2 K1 & K2 K1 ^ K2 K1 | K2
0 0 0 0 0
1 0 0 1 1
0 1 0 1 1
1 1 1 0 1
Befejezve az egyes komplemensnl megkezdett pldt, az x|maszk rt-
ke 1111100011110010
2
. llthatjuk, hogy az eredmnyben minden olyan
bit egy, ami a maszkban az volt. Az x^x eredmnye biztosan tiszta z-
rus. Az x&~maszk rtke 0000100000000010
2
. Megemltjk, hogy az
eredmny minden olyan bitpozcijn 0 van, ahol a maszk bitje 1. Teht a
kifejezs azokat a biteket bizonyosan trlte, ahol a maszk bit 1 volt.
e Nem szabad sszekeverni a logikai vagy (||) s a bitenknt vagy (|),
ill. a logikai s (&&) s a bit szint s (&) mveleteket! Feltve, hogy kt,
egsz tpus vltoz rtke: a=2 s b=4, akkor az
a && b 1 (igaz)
de az
a & b 0
Az ANSI szabvny szerint a bit szint mveletek signed egsze-
ken implementcifggk. A legtbb C fordt azonban signed egszeken
ugyangy dolgozik, mint unsignedeken. Pldul short intben gondol-
kodva a 16 & 99 eredmnye 96, mert:
1111111111110000&0000000001100011 0000000001100000
A fjl utols mdostsnak dtumt s idejt egy-egy szban, azaz C
nyelvi fogalmakkal: egy-egy unsigned short int-ben troljuk. A kt sz
bitfelosztsa legyen a kvetkez:
dtum v 1980 hnap nap
id ra perc 2 msodperc
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
C programnyelv 95
A kt sz azonostja legyen datum s ido! Ttelezzk fel, hogy az id
rszeit az ora, a perc s az mp unsigned short vltozkban troljuk! Az
ugyanilyen unsigned short vltozk a dtum rszeire: ev, ho s nap. Ak-
kor az odavisszaalakts a kvetkez:
/* Rszeibl az id sz ellltsa: */
ido = ora << 11 | perc << 5 | mp >> 1;
/* Az id szbl a rszei: */
ora = ido >> 11;
perc = ido >> 5 & 0X3F;
mp = (ido & 0X1F) << 1;
/* Rszeibl a dtum sz ellltsa: */
datum = ev - 1980 << 9 | ho << 5 | nap;
/* A datum szbl a rszei: */
ev = (datum >> 9) + 1980;
ho = datum >> 5 & 0XF;
nap = datum & 0X1F;
rjunk unsigned long invertal(unsigned long x, int p, int n) fggvnyt
egy rvid kiprbl programmal, mely az x paramtere rtkt a p.ik bit-
pozcijtl n hosszban invertlja (az 1eseket 0kra, s a 0kat 1esekre
cserli)! A nem emltett bitpozcik rtke maradjon vltozatlan! Az in-
vertlt eredmny a fggvny visszatrsi rtke.
n
31 29 27 25 23
21|p
19 17 15 13 11 9 7 5 3 1 0
Az bra x paramtert, a zrustl indul, 20 rtk p bitpozcit s az
n=5 bitszlessget szemllteti.
Ksztsnk elbb egy ugyancsak unsigned long maszkot, mely p poz-
citl n szlessgben 1es biteket tartalmaz, s az ezen kvli pozcik
mind nullk!
~0: 1111111111111111111111111111111
~0<<n: 1111111111111111111111111100000
~(~0<<n): 0000000000000000000000000011111
~(~0<<n)<<(p+1-n): 0000000000011111000000000000000
Ezutn x egyes komplemensbl bitenknti ssel kivgjuk a krdses in-
vertlt bitpozcikat, azaz: ~x&maszk. Ezt aztn bitenknti vagy kapcso-
latba hozzuk az eredeti x egy olyan vltozatval, melyben kinullztuk az
rdekes biteket, azaz: x&~maszk. Teht:
/* PELDA15.C: Bitpozcik invertlsa. */
#include <stdio.h>
unsigned long invertal(unsigned long x, int p, int n){
unsigned long maszk=~(~0<<n)<<(p+1-n);
return ~x&maszk|x&~maszk; }
void binaris(unsigned long x){
unsigned long maszk;
for(maszk=0X80000000; maszk; maszk=maszk>>1)
96 MVELETEK S KIFEJEZSEK
if(maszk&x) putchar(1); else putchar(0); }
void main(void){
unsigned long x=0X4C59E9FA;
int p=20, n=5;
printf("Az eredeti rtket: ");
binaris(x);
printf("\nEzt invertljuk %d bitpozcitl %d
bitszlessgben.\n", p, n);
printf("Az invertlt rtk: ");
binaris(invertal(x, p, n));
putchar(\n); }
Vegyk szre, hogy a binaris fggvny segtsgvel unsigned long
rtket jelentetnk meg binrisan! A maszk vltoz 31es bitpozcijtl
indtunk egy 1est, s a ciklusmag vgrehajtsa utn mindig eggyel jobbra
toljuk. A maszk s az rtk bit szint s kapcsolata akkor szolgltat nem
zrust (igazat), ha a krdses bitpozcin az rtkben 1 van.
Megoldand feladatok:
Ksztse el a kvetkez fggvnyeket, s prblja is ki ket egy rvid
programmal!
- Az unsigned long getbits(unsigned long x, int p, int n) x rtkt
szolgltatja a p.ik bitpozcitl n bitszlessgben.
- Az unsigned long rotl(unsigned long x) 1 bittel balra forgatja para-
mtere rtkt. Teht a 31. pozcirl kicsorg bit lesz az eredmny
0. bitje. {ROTL.C}
- Az unsigned long rotr(unsigned long x) 1 bittel jobbra forgat.
- Az unsigned long tobbrotl(unsigned long x, int n) n bittel forgat
krbe balra.
- Az unsigned long tobbrotr(unsigned long x, int n) n bittel forgat
krbe jobbra.
5.9 Feltteles kifejezs ( ? :)
Ez a nyelvben az egyetlen hrom operandusos mvelet, melynek priori-
tsa alacsonyabb a ktoperandusos logikai opertoroknl. A definci:
feltteles-kifejezs:
logikai-vagy-kifejezs
logikai-vagy-kifejezs ? kifejezs : feltteles-kifejezs
kifejezs:
hozzrendels-kifejezs
kifejezs , hozzrendels-kifejezs
C programnyelv 97
A logikai-vagy-kifejezsnek egsz, lebegpontos vagy mutat tpusnak
kell lennie, s kirtkelse zrushoz val hasonltst jelenti:
- Ha logikai-vagy-kifejezs nem zrus, a kifejezst rtkeli ki a ford-
t. Ez azt jelenti, hogy a kifejezs kirtkelse csak akkor trtnik
meg, ha a logikai-vagy-kifejezs igaz.
- Ha logikai-vagy-kifejezs zrus, a feltteles-kifejezst hatrozza meg
a fordt, azaz a feltteles-kifejezs kirtkelse csak akkor trtnik
meg, ha a logikai-vagy-kifejezs hamis.
e A logikai-vagy-kifejezst mindenkppen kirtkeli a kd, de a kife-
jezs s a feltteles-kifejezs kzl csak az egyik kiszmtsa trtnik
meg.
A K1 ? K2 : K3 feltteles kifejezsben K1 rtktl fggen K2t vagy
K3at rtkeli ki a fordt. A konstrukci eredmnynek tpusa ilyen ala-
pon K2 vagy K3 operandusok tpustl fgg a kvetkezkpp:
- Ha mindkett aritmetikai tpus, akkor az esetleg szksges implicit
tpuskonverzi utn az eredmny tpusa a konvertlt tpus.
- Ha a kt operandus ugyanolyan struktra, uni, vagy mutat tpus,
akkor az eredmny is a kzs tpus.
- Ha mindkett void tpus, akkor az eredmny is az.
Pldul az
if( a > b ) z = a;
else z = b;
utasts helyettesthet a
z = a > b ? a : b;
feltteles kifejezssel. Ha pldul egy int tpus a tmb els N elemt
szeretnnk megjelentetni gy, hogy egy sorba egymstl szkzzel elv-
lasztva 10 elem kerljn, akkor ezt tmr kdot alkalmazva gy is meg-
tehetjk:
for(i=0; i<N; ++i)
printf(%6d%c, a[i], (i%10==9|| i==N-1) ? \n: );
Javtsunk ki nhny eddig megrt fggvnyt a feltteles kifejezs fel-
hasznlsval!
- A PELDA15.C binaris fggvnyben az
if(maszk&x) putchar(1); else putchar(0);
most gy is rhat:
98 MVELETEK S KIFEJEZSEK
putchar((maszk&x)? 1: 0);
- A PELDA14.C atoi rutinjban az
if(s[i]==+||s[i]==-) if(s[i++]==-) elojel=-1;
sor trhat a kvetkezre:
if(s[i]==+||s[i]==-) elojel=(s[i++]==-)? -1: 1;
Mindkt pldban a feltteles kifejezs logikai-vagy-kifejezse kr
zrjelet tettnk. Lssuk azonban be, hogy erre semmi szksg sincs, hisz
ennl alacsonyabb priorits mvelet mr csak kett van: a hozzrendels
s a vessz opertor! A felesleges zrjel legfeljebb a jobban olvashats-
got biztostja.
5.10 Hozzrendels opertorok
A jobbrl balra csoportost hozzrendels prioritsa alacsonyabb, mint
a feltteles kifejezs, s ennl alacsonyabb priorits mvelet mr csak a
vessz opertor. A mvelet a jobb oldali operandus rtkt rendeli a bal
oldali operandushoz, melybl kvetkezleg a bal oldali operandusnak m-
dosthat balrtknek kell lennie. A hozzrendels kifejezs rtke ugyan
egyezik a bal oldali operandus hozzrendels vgrehajtsa utni rtkvel,
de nem balrtk. A jobb oldali operandus rtkt a fordt a bal oldali
operandus tpusra konvertlja a bal operandusba val letrols eltt a
hozzrendelsi konverzi szablyai szerint. A bal oldali operandus nem
lehet tmb, fggvny vagy konstans. Nem lehet termszetesen nem teljes
(mg nem teljesen deklarlt) tpus sem. A definci:
hozzrendels-kifejezs:
feltteles-kifejezs
egyoperandusos-kifejezs hozzrendels-opertor hozzrendels-kifejzs
hozzrendels-opertor: ( a kvetkezk egyike!)
= *= /= %= += -= &= ^= |= <<= >>=
Van teht egyszer hozzrendels opertor (=) s vannak sszetettek
vagy kombinltak (ezek a tbbiek).
Foglalkozzunk elbb az egyszer hozzrendelssel!
A K1 = K2 kifejezsben K1-nek mdosthat balrtknek kell lennie.
K2 rtke - esetlegesen a K1 tpusra trtnt konverzi utn - fellrja a
K1 ltal kijellt objektum rtkt. Az egsz konstrukci rtke K2 rt-
ke az esetleg a K1 tpusra szksgess vlt hozzrendelsi konverzi
vgrehajtsa utn.
Remljk, hogy nem felejtettk mg el, hogy a balrtk (K1) s
jobbrtk (K2) fogalom ppen az egyszer hozzrendelsbl szrmazik. A
C programnyelv 99
balrtk a hozzrendels opertor bal oldaln, a jobbrtk pedig a jobb ol-
daln llhat.
Tudjuk, ha egy kifejezsben hozzrendels opertor is van, akkor
annak a kifejezsnek bizonyosan van mellkhatsa.
Emlkezznk vissza, hogy a definci megengedi a hozzrendels
opertor
K1 = K2 = K3 = ... = Kn = kifejezs
formj hasznlatt is, amikor is a kifejezs kirtkelse utn jobbrl balra
haladva az operandusok felveszik a kifejezs rtkt. Az egsz konstruk-
ci rtke most is a kifejezs rtke lesz. Pldul
a = b= c = d + 6;
A kombinlt hozzrendels opertorok a
K1 = K1 opertor K2
kifejezst
K1 opertor = K2
mdon rvidtik, s K1 kirtkelse csak egyszer trtnik meg. A megen-
gedett opertorok a definciban lthatk! Mindegyik megvalstja azt a
mveletet, konverzit s korltozst, amit a ktoperandusos opertor
egybknt realizl, s vgrehajtja a hozzrendelst is. A kombinlt hozz-
rendels opertor operandusai egsz vagy lebegpontos tpusak lehetnek
ltalban. A += s = bal oldali operandusa mutat is lehet, amikor is a
jobb oldali operandus kteles egsz tpus lenni.
Pldul:
x = x * ( y + 6); x *= y + 6;
Az sszetett opertorokat hasznlva kevesebbet kell rni. Pldul:
t[ t1[i3 + i4] + t2[i1 - i2]] += 56;
Hasznljunk kombinlt hozzrendels opertorokat nhny eddig mr
megrt fggvnyben!
- A PELDA15.C binaris rutinja:
void binaris(unsigned long x){
unsigned long maszk;
for(maszk=0X80000000; maszk; maszk>>=1)
putchar((maszk&x)? 1: 0); }
- A PELDA4.Cbeli
for(ft=ALSO; ft<=FELSO; ft=ft+LEPES)
100 MVELETEK S KIFEJEZSEK
most gy rhat:
for(ft=ALSO; ft<=FELSO; ft+=LEPES)
5.11 Hozzrendelsi konverzi
Hozzrendelsnl a hozzrendelend rtk tpust a hozzrendelst fo-
gad vltoz tpusra konvertlja a fordt. A C megengedi a hozzrende-
lsi konverzit lebegpontos s egsz tpusok kztt azzal, hogy a kon-
verzinl rtkveszts trtnhet. A hasznlatos konverzis mdszer kveti
az implicit tpuskonverzi szablyait s ezen tl mg a kvetkezket:
- Konverzi signed egsz tpusokrl: Nem negatv signed egsz nem
kisebb mret unsigned egssz alaktsakor az rtk vltozatlan.
Pldul signed char unsigned charr vlsakor a bitminta vlto-
zatlan, de a legmagasabb helyirtk bit elveszti az eljelbit funkci-
jt. A konverzi klnben a signed egsz eljel kiterjesztsvel
trtnik. Pldul signed char unsigned longg gy vlik, hogy
eljel kiterjesztssel elbb long lesz belle, s aztn ez a bitminta
megtartsval, s eljelbit funkcivesztssel lesz unsigned long.
Hosszabb egsz tpus rvidebb alakulsakor az egsz tpus marad
als bitjei vltozatlanok, s a flsleg egyszeren levgdik mg ak-
kor is, ha rtkveszts trtnne. long int rtk float lebegpontoss
alaktsakor nincs rtkveszts, de pontossgveszts lehet. Ilyen t-
alaktskor a rvidebb signed egszbl elbb long lesz eljel kiter-
jesztssel, s csak ezutn jn a lebegpontos konverzi.
Miutn az enum tpus int definci szerint, a felsorols tpusra s t-
pusrl val konverzi egyezik az intvel.
- Konverzi unsigned egsz tpusokrl: Rvidebb unsigned vagy
signed egssz alaktskor a marad als bitek vltozatlanok, s a f-
lsleg egyszeren levgdik mg akkor is, ha rtkveszts trtnik.
Az eredmny legfels bitje felveszi az eljelbit funkcit, ha signed
d konvertls volt. Hosszabb unsigned vagy signed egssz alak-
tskor a bejv magasabb helyirtk bitek nulla feltltsek. Lebe-
gpontos konverzinl a rvidebb unsigned egszbl elbb long
lesz nulla feltltssel, s csak ezutn jn az igazi konverzi. Meglla-
pthatjuk itt is, hogy lehet pontossgveszts floatt alaktskor.
- Konverzi lebegpontos tpusokrl: A rvidebb lebegpontos br-
zols hosszabb konvertlsakor nem vltozik meg az rtk. A
hosszabb lebegpontos brzols floatt alaktsa is pontos, ha
csak lehetsges. Pontossgveszts is bekvetkezhet, ha rtkes je-
C programnyelv 101
gyek vesznek el a mantisszbl. Ha azonban az eredmny a float
brzolsi korltain kvl esne, akkor a viselkeds definilatlan.
Ez a definilatlansg tulajdonkppen a fordttl fgg viselkedst
takar!
A lebegpontos rtket gy konvertl egssz a fordt, hogy levg-
ja a trtrszt. Az eredmny elre megjsolhatatlan, ha a lebegpon-
tos rtk nem fr be az egsz brzolsi korltaiba. Klnsen defi-
nilatlan a negatv lebegpontos rtk unsignedd alaktsa.
Konverzi ms tpusokrl: Nincs konverzi a struktra s az uni t-
pusok kztt. Explicit tpusmdostssal brmilyen rtk konvertlhat
void tpusv, de csak abban az rtelemben, hogy a kifejezs rtkt el-
vetjk. A void tpusnak definci szerint nincs rtke. Ebbl kvetkezleg
nem konvertlhat ms tpusra, s ms tpus sem konvertlhat voidra
hozzrendelssel.
5.12 Vessz opertor
Ez a legalacsonyabb priorits mvelet.
kifejezs:
hozzrendels-kifejezs
kifejezs , hozzrendels-kifejezs
A K1, K2, ..., Kn esetn balrl jobbra haladva kirtkeli a fordt a kife-
jezseket gy, hogy a bennk foglalt minden mellkhats is megvalsul.
Az els n - 1 kifejezs voidnak tekinthet, mert az egsz konstrukci
tpust s rtkt a legjobboldalibb kifejezs tpusa s rtke hatrozza
meg. Pldul a
regikar = kar, kar = getchar()
esetn regikar felveszi kar pillanatnyi rtkt, aztn kar s az egsz kife-
jezs rtke a szabvny bemenetrl beolvasott karakter lesz. Tipikus plda
mg a tbb kezdrtk ads s lptets a for utastsban:
rjuk meg egy rvid kiprbl programmal a void strrv(char s[]) fgg-
vnyt, mely sajt helyn megfordtja a paramter karakterlncot!
Az algoritmusrl annyit, hogy a karakterlnc els karaktert meg kell
cserlni az utolsval, a msodikat az utols elttivel, s gy tovbb. Kt
indexet kell indtani a karaktertmbben: egyet alulrl s egyet fellrl. Az
alst minden csere utn meg kell nvelni eggyel, a felst pedig ugyan-
ennyivel kell cskkenteni. A ciklus teht addig mehet, mg az als index
kisebb a felsnl.
/* PELDA16.C: Karakterlnc megfordtsa. */
102 MVELETEK S KIFEJEZSEK
#include <stdio.h>
#include <string.h> /* Az strlen miatt! */
#define INP 66 /* Az input puffer mrete. */
void strrv(char s[]){
int also, felso, csere;
for(also=0, felso=strlen(s)-1; also<felso;
++also, --felso){
csere=s[also]; s[also]=s[felso]; s[felso]=csere; } }
int getline(char s[],int n){
int c,i;
for(i=0;i<n&&(c=getchar())!=EOF&&c!='\n';++i) s[i]=c;
s[i]='\0';
while(c!=EOF&&c!='\n') c=getchar();
return(i); }
void main(void){
char s[INP+1]; /* Az input puffer. */
printf("A szabvny bemenet sorainak megfordtsa.\n"
"Programvg: res sor.\n\n");
while(printf("Jhet a sor! "), getline(s,INP)){
strrv(s);
printf("Megfordtva: %s\n", s); } }
A STRING.H fejfjlt bekapcsolva rendelkezsre ll az strrv szab-
vny knyvtri vltozata, mely ugyanilyen paramterezs s funkcij,
de strrev a neve, s ms egy kicsit a visszatrsi rtknek a tpusa.
Vegyk szre, hogy a mainbeli whileban is vesszs kifejezst
hasznltunk!
Olyan szvegkrnyezetben, ahol a vessz szintaktikai jelents, a
vessz opertort csak zrjelbe tett csoporton bell szabad hasznlni.
Ilyen helyek: az inicializtorlista pldul, vagy a fggvny paramterlist-
ja. A
fv(b, (a = 2, t += 3), 4);
kitnen mutatja, hogy az fv fggvny hrom paramterrel rendelkezik. A
hvsban a msodik paramter vesszs kifejezs, ahol a elbb 2 rtk
lesz, aztn t megn hrommal, s ezt az rtket kapja meg a fggvny is
msodik aktulis paramterknt. Ha a fggvny prototpusa mst nem
mond, akkor a msodik paramter tpusa t tpusa.
5.13 Mveletek prioritsa
A mveletek prioritst nevezik precedencinak, vagy rendsgnek is.
Mindhrom esetben arrl van sz, hogy zrjel nlkli helyzetben melyik
mveletet kell vgrehajtani elbb a kifejezs kirtkelse sorn.
A kvetkez tblzat cskken prioritssal haladva mutatja az egyes
opertorok asszociativitst. A tbbszr is elfordul opertorok kzl
mindig az egyoperandusos a magasabb priorits. Abban a rovatban, ahol
C programnyelv 103
tbb opertor van egytt, a mveletek azonos prioritsak, s asszociativi-
tsuknak megfelelen hajtja ket vgre a fordt. Minden opertor kateg-
rinak megvan a maga asszociativitsa (balrl jobbra vagy jobbrl balra
kt), mely meghatrozza zrjel nlkli helyzetben a kifejezs csoportos-
tst azonos priorits mveletek esetn.
Opertorok Asszociativits
() [] -> . balrl jobbra
! ~ + - ++ -- & * sizeof jobbrl balra
* / % balrl jobbra
+ - balrl jobbra
<< >> balrl jobbra
< <= > >= balrl jobbra
== != balrl jobbra
& balrl jobbra
^ balrl jobbra
| balrl jobbra
&& balrl jobbra
|| balrl jobbra
?: jobbrl balra
= *= /= %= += -= &= ^= |= <<= >>= jobbrl balra
, balrl jobbra
13. bra: Mveletek prioritsa
A tblzatban felsoroltakon kvl van mg a # s a ## opertor, me-
lyek az elfeldolgoznak szlnak.
A prioritsi tblzat (13. bra) termszetesen tartalmaz eddig mg
nem ismertetett mveleteket is.
Vannak tbbjelents opertorok is, melyek rtelmezse a helyzettl
fgg. Pldul:
cimke: /* utasts cmke */
a?x:y /* feltteles kifejezs */
a=(b+c)*d; /* zrjeles kifejezs */
void fv(int n); /* fggvnydeklarci */
a, b, c; /* vesszs kifejezs */
fv(a, b, c); /* fggvnyhvs */
A kifejezs kirtkelsi sorrendje nem meghatrozott ott, ahol a nyelvi
szintaktika errl nem gondoskodik. A fordt a generlt kd hatkonys-
gnak javtsa rdekben trendezheti a kifejezst klnsen az asszocia-
tv s kommutatv opertorok (*, +, &, ^ s |) esetn, hisz azt felttelezi,
hogy a kirtkels irnya nem hat a kifejezs rtkre.
104 MVELETEK S KIFEJEZSEK
Fedezzk fel, hogy itt nem arrl van sz, hogy a fordt a kvetkez
fordtskor msknt rendezi t a kifejezst, hisz a fordts determiniszti-
kus dolog, hanem arrl, hogy klnbz C fordtk msms eredmnyre
juthatnak!
Problma lehet az olyan kifejezssel,
- melyben ugyanazt az objektumot egynl tbbszr mdostjuk, ill.
- melyben ugyanazon objektum rtkt vltoztatjuk s felhasznljuk.
Pldul:
i = v[i++]; /* Dntsk el, mit is akarunk i-vel! */
i = a+++b[a]; /* b indexe attl fgg, hogy az sszeads
melyik tagjt rtkeli ki elbb a fordt. */
A fentiek akkor is igazak, ha kifejezsnket jl sszezrjelezzk:
int osszeg=0;
sum = (osszeg=3)+(++osszeg);/* sum == 4 vagy 7 ? */
Segdvltozk bevezetsvel a dolgok midig egyrtelmsthetk:
int seged, osszeg=0;
seged = ++osszeg; /* seged == 1, osszeg == 1. */
sum = (osszeg=3)+seged; /* sum == 4. */
Ha a szintaktika rgzti a kirtkelsi sorrendet (az &&, a ||, a ?: s a
vessz opertor esetben ez gy van), akkor ott brmit megtehetnk.
Pldul:
sum = (i=3, i++, i++); /* OK, sum == 4 s i == 5. */
A kifejezs kirtkelsi sorrendjt ugyan () prokkal befolysolhatjuk:
f = a*(b+c);
, de asszociatv s kommutatv opertorok operandusait mg agyonzr-
jelezve is sszecserlheti a fordt, hisz felttelezheti, hogy a kifejezs
rtkt ez nem befolysolja:
f = (a+b) + (c+d);
Hatrozatlan a fggvny aktulis paramtereinek kirtkelsi sorrendje
is:
printf(%d %d\n, ++n, fv(n));
A bitenknti opertorok prioritsa alacsonyabb a relciknl, gy a
c & 0XF == 8
mindig hamis, mert az elbb kirtkelsre kerl egyenlsgi relci so-
hasem lehet igaz. A kifejezs helyesen:
C programnyelv 105
(c & 0XF) == 8.
Vigyzzunk a hozzrendels (=) s az egyenl relci (==) opertor fel-
cserlsre, mert pldul az
if( i = 2 ) utasts1; else utasts2;
else gra sohasem jut el a vezrls tekintettel arra, hogy a 2 hozzrende-
lse ebben az letben sem vlik hamiss.
gyeljnk azokkal a kifejezsekkel is, melyekben csak logikai s (&&)
vagy csak logikai vagy (||) mveletek vannak, mert ezeket balrl jobbra
haladva
- && esetn csak az els hamis tagig, ill.
- || opertornl csak az els igaz tagig
fogja kirtkelni a fordt! Az
x && y++
kifejezsben y nvelse csak akkor trtnik meg, ha x nem zrus.
e Kifejezs kirtkelse kzben addhatnak thidalhatatlan szitu-
cik. Ilyenek
- a zrussal val oszts s
- a lebegpontos tl vagy alulcsorduls.
e jra felhvjuk azonban a figyelmet arra, hogy a nyelvben nem lte-
zik sem egsz tl, sem alulcsorduls!
106 UTASTSOK
6 UTASTSOK
Az utastsokat ha mst nem mondanak megadsuk sorrendjben
hajtja vgre a processzor. Az utastsoknak nincs rtke. Vgrehajtsuk
hatssal van bizonyos adatokra, vagy programelgazst valstanak meg
stb. Defincijuk a kvetkez:
utasts:
sszetett-utasts
cmkzett-utasts
kifejezs-utasts
szelekcis-utasts
itercis-utasts
ugr-utasts
6.1 sszetett utasts
sszetett-utasts:
{ <deklarcilista><utastslista> }
deklarcilista:
deklarci
deklarcilista deklarci
utastslista:
utasts
utastslista utasts
Az sszetett utasts utastsok (lehet, hogy res) listja { }-be tve. Az
sszetett utastst blokknak is nevezik, mely szintaktikailag egy utasts-
nak minsl, s szerepet jtszik az azonostk hatskrben s lthats-
gban.
Ha a deklarcilistban elfordul azonostt mr korbban az
sszetett utastson kvl is deklarltk, akkor a blokkra loklis azonost
elfedi a blokkon kvlit a blokk teljes hatskrben. Teht az ilyen blok-
kon kvli azonost a blokkban nem lthat.
C blokkban elbb a deklarcis, s csak aztn a vgrehajthat utastsok
kvetkeznek.
Az sszetett utastsok akrmilyen mly szinten egymsba gyazhatk, s
az elbbi szerkezet a begyazott blokkra is vonatkozik.
e Tudjuk, hogy az auto trolsi osztly objektumok inicializlsa
mindannyiszor megtrtnik, valahnyszor a vezrls a fejen t kerl be
az sszetett utastsba. Ez az inicializls azonban elmarad, ha a vezrls
ugr utastssal rkezik a blokk kzepre.
e Tilos ;t rni az sszetett utasts zr }e utn!
C programnyelv 107
6.2 Cmkzett utasts
cmkzett-utasts:
azonost : utasts
case konstans-kifejezs : utasts
default : utasts
A case s a default formk csak switch utastsban hasznlatosak. Ezek
ismertetsvel majd ott foglalkozunk! Az
azonost : utasts
alakban az azonost (cmke) clja lehet pldul egy felttlen elgaztat
goto azonost;
utastsnak. A cmkk hatskre mindig az ket tartalmaz fggvny.
Nem deklarlhatk jra, de kln nvterletk van, s nmagukban nem
mdostjk az utastsok vgrehajtsi sorrendjt.
e C-ben csak vgrehajthat utasts cmkzhet meg, azaz
{
/* . . .
cimke: /* HIBS */
}
A megolds helyess vlik, ha legalbb egy res utastst tesznk a cimke
utn:
{
/* . . .
cimke: ; /* OK */
}
6.3 Kifejezs utasts
kifejezs-utasts:
<kifejezs>;
Ha a kifejezst pontosvessz kveti, kifejezs utastsnak minsl. A
fordt kirtkeli a kifejezst, s ekzben minden mellkhats rvnyre jut,
mieltt a kvetkez utasts vgrehajtsa elkezddne. Pldul az
x = 0, i++, printf(Hah!\n)
kifejezsek, s gy vlnak kifejezs-utastsokk:
x = 0; i++; printf(Hah!\n);
A legtbb kifejezs utasts hozzrendels vagy fggvnyhvs.
res utastst (null statement) gy kapunk, hogy kifejezs nlkl pontos-
vesszt tesznk. Hatsra termszetesen nem trtnik semmi, de ez is uta-
stsnak minsl, azaz szintaktikailag llhat ott, ahol egybknt utasts
llhat.
108 UTASTSOK
6.4 Szelekcis utastsok
szelekcis-utasts:
if(kifejezs) utasts
if(kifejezs) utasts else utasts
switch(kifejezs) utasts
Ltszik, hogy kt szelekcis utasts van: az if s a switch. A felttele-
sen elgaztat
if(kifejezs) utasts1 else utasts2
utastsban a kifejezsnek aritmetikai, vagy mutat tpusnak kell lennie.
Ha rtke zrus, akkor a logikai kifejezs hamis, msklnben viszont
igaz. Ha a kifejezs igaz, utasts1 kvetkezik. Ha hamis, s az else g l-
tezik, akkor utasts2 jn.
Mind utasts1, mind utasts2 lehet sszetett utasts is!
A nyelvben nincs logikai adattpus, de cserben minden egsz s mutat
tpus annak minsl. Pldul:
if(ptr == 0) /* Rvidthet if(!ptr)-nek. */
if(ptr != 0) /* Rvidthet if(ptr)-nek. */
Az else g elhagyhatsga nha problmkhoz vezethet. Pldul a
if( x == 1)
if( y == 1 ) puts( x = 1 s y = 1\n);
else
puts( x != 1\n);
forrsszvegbl a programoz elkpzelse teljesen vilgos. Sajnos
azonban egyet elfelejtett. Az else mindig az ugyanazon blokk szinten
lev, forrsszvegben megelz, else g nlkli if-hez tartozik. A megol-
ds helyesen:
if( x == 1)
{ if( y == 1 ) puts( x = 1 s y = 1\n); }
else
puts( x != 1\n);
Az if utastsok tetszleges mlysgben egymsba gyazhatk, azaz
mind az if, mind az else utastsa lehet jabb if utasts is. Pldul:
if( x == 1)
{ if( y == 1 ) puts( x = 1 s y = 1\n);
else puts( x = 1 s y != 1\n);}
else
{ if( y == 1 ) puts( x != 1 s y = 1\n);
else puts( x != 1 s y != 1\n);}
Tbbirny elgazst (szelekcit) valst meg a kvetkez konstrukci:
if( kifejezs1 ) utasts1
C programnyelv 109
else if( kifejezs2 ) utasts2
else if ( kifejezs3 ) utasts3
/* . . . */
else utastsN
Ha valamelyik if kifejezse igaz, akkor az azonos sorszm utastst hajt-
ja vgre a processzor, majd a konstrukcit kvet utasts jn. Ha egyik if
kifejezse sem igaz, akkor viszont utastsN kvetkezik.
Ha egy n elem, nvekvleg rendezett t tmbben keresnk egy x rt-
ket, akkor ezt binris keressi algoritmust alkalmazva gy interpretlhat-
juk:
int binker(int x, int t[], int n){
int also=0, felso=n-1, kozep;
while(also<=felso){
kozep=(also+felso)/2;
if(x<t[kozep]) felso=kozep-1;
else if(x>t[kozep]) also=kozep+1;
else return kozep; } /* Megvan. */
return (-1); } /* Nincs meg. */
A binker hromirny elgazst realizl. x t tmbbeli elforduls-
nak indext szolgltatja, ill. 1et, ha nincs is x rtk elem a tmbben.
A binris keress nvekvleg rendezett tmbben gy trtnik, hogy el-
szr megllaptjuk, hogy a keresett rtk a tmb als, vagy fels felbe
esik. A mdszert aztn jraalkalmazzuk az aktulis flre, s gy tovbb. A
dolognak akkor van vge, ha a keres tartomny semmiv szkl (ilyen-
kor nincs meg a keresett rtk), vagy a felez tmbelem egyezik a keresett
rtkkel.
` Rendezett sorozatban egy rtk keressnek ez a mdja, s nem a
minden elemhez trtn hasonltgats!
Megoldand feladatok:
Ksztsen olyan binker fggvnyt, mely:
- cskkenleg rendezett tmbben keres!
- ptllagos paramterben kapja meg, hogy cskken vagy nvekv a
rendezettsg!
- plusz paramter nlkl is eldnti, hogy cskkenleg, vagy nvekv-
leg keressen a tmbben!
A tbbirny programelgaztats msik eszkze a
switch(kifejezs) utasts
110 UTASTSOK
, melyben a kifejezsnek egsz tpusnak kell lennie. Az utasts egy
olyan specilis sszetett utasts, mely tbb case cmkt
case konstans-kifejezs : utasts
s egy elhagyhat default cmkt
default : utasts
tartalmazhat. A vezrlst azon case cmkt kvet utasts kapja meg,
mely konstans-kifejezsnek rtke egyezik a switchbeli kifejezs rtk-
vel. A vgrehajts aztn itt addig folytatdik, mg break utasts nem k-
vetkezik, vagy vge nincs a switch blokkjnak.
A case cmkebeli konstans-kifejezsnek is egsz tpusnak kell lennie.
Ez a TPUSOK S KONSTANSOK szakasz Deklarci fejezetben
rottakon tl tovbbi korltozsokat r a konstans kifejezsre. Operandu-
sai csak egsz, felsorols, karakteres s lebegpontos llandk lehetnek,
de a lebegpontos konstanst explicit tpuskonverzival egssz kell alak-
tani. Operandus lehet mg a sizeof opertor is, aminek operandusra ter-
mszetesen nincsenek ilyen korltozsok.
A vgrehajts sorn a kifejezs s a case konstans-kifejezsek rtkn is
vgbemegy az egszellptets. A kifejezs az sszes esetleges mellk-
hatsval egyetemben valsul meg, mieltt az rtkhasonlts megkezdd-
ne.
Ha nincs a switch kifejezs rtkvel egyez case cmke, akkor a vezr-
lst a default cmke utastsa kapja meg. Ha nincs default cmke sem, ak-
kor vge van a switchnek.
Az utasts hasznlathoz mg kt megjegyzst kell fzni:
- Tbb case cmke is cmkzhet egy utastst.
- Egyazon switch utastsban viszont nem fordulhat el kt azonos
rtk case konstans-kifejezs.
A switch utastsok egymsba is gyazhatk, s ilyenkor a case s a de-
fault cmkk mindig az ket kzvetlenl tartalmaz switchhez tartoz-
nak.
A switch utastst szemlltetend rjuk t a szabvny bemenet karakte-
reit kategrinknt leszmll PELDA7.Ct!
/* PELDA17.C: A bemenet karaktereinek
leszmllsa kategrinknt */
#include <stdio.h>
void main(void){
short k, num=0, feher=0, egyeb=0;
C programnyelv 111
printf("Bemeneti karakterek leszmllsa\n"
"kategrinknt EOF-ig, vagy Ctrl+Z-ig.\n");
while((k=getchar())!=EOF) switch(k){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
++num;
break;
case ' ':
case '\n':
case '\t':
++feher;
break;
default:
++egyeb; }
printf("Karakter szmok:\n----------------\n"
"numerikus: %5hd\nfehr: %5hd\n"
"egyb: %5hd\n----------------\n"
"ssz: %10ld\n", num, feher, egyeb,
(long)num+feher+egyeb); }
Belthat, hogy a switch utasts hasznlhatsgt szegnyti, hogy
a kifejezs csak egsz tpus lehet s, hogy a case cmkk csak egszrt-
k konstans-kifejezsek lehetnek. Az ifnl emltett tbbirny elgaztat-
si konstrukci gy jval ltalnosabban hasznlhat.
6.5 Itercis utastsok
itercis-utasts:
while(kifejezs) utasts
do utasts while(kifejezs);
for(<kifejezs>; <kifejezs>; <kifejezs>) utasts
Szemmel lthatan hromfle itercis utasts van, amibl kett ell-
tesztel ciklusutasts. A
while(kifejezs) utasts
kifejezsrl ugyanaz mondhat el, mint az if utasts kifejezsrl. Lp-
senknt a kvetkez trtnik:
1. Kirtkeli a fordt a kifejezst, melynek sorn minden esetleges
mellkhats is megvalsul. Ha hamis (zrus) az rtke, akkor vge a
ciklusnak, s a while-t kvet utasts jn a programban.
112 UTASTSOK
2. Ha a kifejezs igaz (nem zrus), akkor az utasts vgrehajtsa, s
jbl az 1. pont kvetkezik.
Vilgos, hogy a kifejezs rtknek valahogyan vltoznia kell az
utastsban, klnben a ciklusnak soha sincs vge. Az utasts llhat tbb
utastsbl is, azaz sszetett utasts is lehet. Ha az utastsok kzt ugr
utasts is van, akkor ezen md is kilphetnk a ciklusbl.
A
for(<init-kifejezs>; <kifejezs>; <lptet-kifejezs>) utasts
elltesztel, iteratv ciklusutasts, melynek megvalsulsa a kvetkez
lpsekbl ll:
1. A fordt vgrehajtja az init-kifejezst, ha van. Tbbnyire egy vagy
tbb vltoz rtkadsrl lehet itt sz.
3. Kirtkeli a kifejezst. Ha hamis (zrus), akkor vge a ciklusnak, s a
for-t kvet utasts jn a programban. Lthat, hogy a szintaktika
szerint ez a kifejezs is elhagyhat. Ilyenkor 1 (igaz) kerl a helyre,
azaz a vgtelen ciklus knnyedn felrhat:
for( ; ; ); for( ; 1; );
4. Ha a kifejezs igaz (nem zrus), akkor az utasts jn,
5. aztn a lptet-kifejezs, majd jbl a 2. pont kvetkezik.
Ha a for utastst while-lal szeretnnk felrni, akkor azt gy tehetjk
meg, ha a ciklusmagban nincs continue:
<init-kifejezs>;
while(<kifejezs>) { utasts; <lptet-kifejezs>; }
A szintaktikai szablyt sszefoglalva: a for-bl akr mindegyik ki-
fejezs is elhagyhat, de az els kettt zr pontosvesszk nem!
A vessz opertor alkalmazsval mind az init-, mind a lptet-kife-
jezs tbb kifejezs is lehet. Ezt szemllteti az elz szakaszban a PEL-
DA16.Cben megrt strrv fggvny.
rjunk void rendez(int a[], int n) fggvnyt, mely nvekvleg rendezi
sajt helyn az n elem a tmbt!
- Indulva az els elemtl megkeressk a tmb minimlis elemt, s
kicserljk az els elemmel.
- A 2. elemtl kezdve a htra lev tmbrszben keressk meg a legki-
sebb elemet, s ezt kicserljk a 2. elemmel, s gy tovbb.
C programnyelv 113
- Ltszik, hogy minimumkeresst utoljra a tmb utols eltti s utol-
s elemn kell elvgezni, s az itteni esetleges csere utn rendezett is
az egsz tmb.
void rendez(int a[],int n){
int i, j, m, cs;
for(i=0; i<n-1; ++i){
for(j=i+1, m=i; j<n; ++j) if(a[j]<a[m]) m=j;
if(i!=m){ cs=a[i]; a[i]=a[m]; a[m]=cs;} } }
Ez ugyebr plda az egymsba gyazott ciklusokra!
Ksztsk el az int egesze(char s[]) rutint, mely ellenrzi a decimlis
egsz konstans rsszablyt a paramter karaktertmbn. 1et szolgltat,
ha a dolog rendben van, s zrust, ha nem!
/* A decimlis szmjegyek szma maximlisan: */
#define HSZ sizeof(int)/sizeof(short)*5
int egesze(char s[]){
int i = 0, kezd;
/* A karakterlnc eleji fehr karakterek tlpse: */
while(s[i]==' ' || s[i]=='\n' || s[i]=='\t') ++i;
/* Az eljel tlpse: */
if(s[i]=='+' || s[i]=='-') ++i;
kezd=i; /* A szmjegyek itt kezddnek. */
/* Elre a kvetkez nem numerikus karakterre: */
while(s[i]>='0' && s[i]<='9' && i-kezd<HSZ) ++i;
/* Dnts: */
if(kezd==i || s[i]!='\n' && s[i]!='\t' &&
s[i]!=' ' && s[i]!=0) return 0;
else return 1; }
Ltszik, hogy HSZ 16 bites int esetn 5 (32767), s 32 bitesnl 10
(2147483647). Arra val, hogy ennl tbb decimlis szmjegyet ne fogad-
jon el a rutin.
Vegyk szre, hogy a fggvny visszautastja, ha egyetlen szmjegy ka-
raktert sem tartalmaz a numerikus karakterlnc! Elveti azt is, ha a numeri-
kus lnc rsz nem fehr karakterrel, vagy lnczr zrussal vgzdik. Az
ellenrzs persze nem tkletes, hisz a numerikus karakterlnc brzolsi
hatrok kz frst nem biztostja. Pldul 16 bites intnl minden tje-
gy szmot rvnyesnek tekint, holott a 99999 s 32769, valamint a
32768 s 99999 kztti szmok brzolhatatlanok. Ez az ellenrzs azon-
ban csak akkor lenne knnyen megvalsthat, ha tesztels kzben kon-
vertlnnk is a szmot. Ekkor azonban mr tbbe kerlne a leves, mint a
hs.
Ksztsk programot, mely egsz szmokat kr be. Meghatrozza az t-
lagukat, a minimumukat, maximumukat, s nvekvleg rendezi is ket!
Az egszek darabszma csak futs kzben dl el.
114 UTASTSOK
/* PELDA18.C: Egsz szmok tlaga, minimuma, maximuma s
rendezse */
#include <stdio.h>
#include <stdlib.h> /* Az atoi miatt! */
#include <limits.h> /* INT_MIN s INT_MAX vgett! */
#define MAX 100 /* A tmb max. elemszma. */
#define INP 20 /* Az input puffer mrete. */
int getline(char s[],int lim);
/* A decimlis szmjegyek szma maximlisan: */
#define HSZ sizeof(int)/sizeof(short)*5
int egesze(char s[]);
void rendez(int a[],int n);
void main(void){
int n=0; /* A rendezend elemek szma. */
char sor[INP+1]; /* Az input puffer. */
int a[MAX]; /* A egszeket trol tmb. */
int min, max; /* Minimum, maximum. */
double osszeg=0.;/* Az sszeg */
int i;
while(n<1||n>MAX){
printf("\nHny egsz szmot rendeznk(1-%d)? ",MAX);
getline(sor,INP);
if(egesze(sor)) n=atoi(sor);}
printf("\n\nKrem a rendezend szmokat %d s +%d
kztt!\n", INT_MIN, INT_MAX);
for(i=0;i<n;++i){
printf("%3d: ",i+1);
if(getline(sor,INP)>0 && egesze(sor))
a[i]=atoi(sor);
else --i; }
min=max=a[0];
for(i=0;i<n;osszeg+=a[i],++i)
if(a[i]<min) min=a[i];
else if(a[i]>max) max=a[i];
printf("\nA szmsorozat\tminimuma:%14d.\n"
"\t\tmaximuma:%14d.\n"
"\t\ttlaga: %17.2f\n",
min, max, osszeg/n);
printf("\nA rendezett szmok:\n");
rendez(a, n);
for(i=0; i<n; i++){
printf("%13d",a[i]);
if(!((i+1)%6)) putchar('\n'); }
putchar('\n'); }
` Nem rendezett sorozatban a minimum, vagy maximum megkeres-
snek az a mdja, hogy vesszk a sorozat egy ltez elemt (tbbnyire az
elst), s aztn hasonltgatjuk a tbbiekhez, hogy vajon vane nlnl ki-
sebb, ill. nagyobb. Ha van, akkor attl kezdve azzal folytatjuk a hasonl-
tst.
C programnyelv 115
El kell ismerni termszetesen, hogy a minimum s maximum meg-
keresse teljesen felesleges volt, mert a rendezs utn ezeket az rtkeket
a[0] s a[n1] amgy is tartalmazza.
Vegyk mg szre, hogy az egszek sszegt a for ciklus lptet-ki-
fejezsben szmtjuk ki!
Megoldand feladatok:
Alaktsa t a PELDA18.Cben megvalstott programot a kvetkez-
kpp:
- Ne krje be elre a rendezend szmok darabszmt, hanem az r-
tk bekrsekor jelentse res sor a bemenet vgt! {PELDA18X.C}
- Dolgozzk nem egsz, hanem vals szmokkal a program!
A
do utasts while(kifejezs);
htultesztel ciklusutasts. A kifejezsre ugyanazon megktsek rvnye-
sek, mint a whilenl. A dolog lnyege az, hogy fordt a kifejezs rtk-
tl fggetlenl egyszer biztosan
1. vgrehajtja az utastst.
2. Kirtkeli a kifejezst. Ha hamis (zrus), akkor vge a ciklusnak, s a
while-t kvet utasts jn a programban. Ha viszont igaz, akkor az
1. pont kvetkezik.
sszestve: Az utastst egyszer mindenkpp vgrehajtja a pro-
cesszor, s ezt kveten mindaddig ismtli, mg a kifejezs hamis nem lesz.
A szemlltet pldban az itoa fggvny az int n paramtert karakter-
lncc konvertlja, s elhelyezi a paramter s karaktertmbben:
#include <stdio.h>
#include <string.h>
#include <limits.h>
void itoa(int n, char s[]){
int i=0, elojel, j=0;
if(n==INT_MIN) { ++n; ++j; }
if((elojel=n)<0) n=-n;
do s[i++]=n%10+0; while(n/=10);
if(elojel<0) s[i++]=-;
s[i]=0;
s[0]+=j;
strrev(s); }
A belsbrzolsi formbl karakterlncc alakt itoa rutinban az i cik-
lusvltoz. A j logikai vltoz, s indul rtke 0. Egyetlen egy esetben
116 UTASTSOK
egyrtk, ha n ppen INT_MIN. A problma az ugye, hogy mindenkpp
pozitv rtket kvnunk konvertlni az esetleges negatv eljelet megje-
gyezve, de az INT_MIN 1szerese nem brzolhat intknt, hisz p-
pen eggyel nagyobb INT_MAXnl. Ha ilyenkor megnveljk eggyel n
rtkt, akkor 1szerese pp a fels brzolsi korlt lesz, amivel mr
nincs problma. A j logikai vltoz teht akkor 1, ha volt nvels. Az elo-
jel vltozra n eredeti eljelnek megtartsa vgett van szksg, s azrt,
hogy negatv n esetn a keletkez karakterlnc vgre ki lehessen tenni a
mnuszjelet.
Az algoritmus ppen megfordtva lltja el a karakterlncot. Nzzk
csak asztali teszttel a 16 bites int esett! Tegyk fel, hogy n rtke az o-
minzus 32768!
Amig a dowhile utastsig nem rnk, j 1 lesz, n 32767 s i zrus ma-
rad. Lejtszva a ciklust a kvetkez trtnik:
j: 1
n: 32767 3276 327 32 3 0 0
i: 0 1 2 3 4 5 6
s: 7 6 7 2 3 \0
A tblzatban az az llapot ltszik, amikor a dowhilet kvet kt uta-
sts is lezajlott. Az s[0]bl, vagyis 7bl, 8 lesz, s aztn a szabvny
knyvtri strrev megfordtja a sajt helyn az eredmny karakterlncot.
6.6 Ugr utastsok
ugr-utasts:
break;
continue;
goto azonost;
return <kifejezs>;
Csak itercis (while, do-while s for) vagy switch utastson bell
hasznlhat a
break;
, mely befejezi ezeket az utastsokat, azaz hatsra a vezrls felttel nl-
kl kilp bellk. Tbb egymsba gyazott itercis utasts esetn a bre-
ak csak abbl a ciklusbl lptet ki, amelyben elhelyeztk, azaz a break
csak egyszint kilptetsre kpes.
Ksztend egy int trim(char s[]) fggvny, mely a paramter karakter-
tmb elejrl s vgrl eltvoltja a fehr karaktereket a sajt helyn, s
visszatr az gy letiszttott karakterlnc hosszval!
#include <string.h>
C programnyelv 117
int trim(char s[]){
int i=0, n;
/* A fehr karakterek eltvoltsa a lnc vgrl: */
for(n=strlen(s)-1; n>=0; --n)
if(s[n]!= &&s[n]!=\n&&s[n]!=\t) break;
s[++n]='\0';
/* A fehr karakterek eltvoltsa a lnc elejrl: */
while(s[i]== ||s[i]==\n||s[i]==\t) ++i;
if(i) { n=0; while(s[n++]=s[i++]); --n;}
return(n); }
Csak itercis utastsokban (while, do-while s for) alkalmazhat a
continue;
, mely a vezrlst a kifejezs kirtkelsre viszi while s do-while estn,
ill. hatsra a lptet-kifejezs kirtkelse kvetkezik for utastsnl.
Egymsba gyazott itercis utastsok esetn ez is mindig csak az t ma-
gba foglal itercis utastsra vonatkozik.
eUgyebr switchben csak itercis utastson bell hasznlhat a
continue!
Felttlen vezrlstadst hajt vgre az azonostval cmkzett utastsra
a
goto azonost;
Az utastst brmilyen mly blokk szintrl is vgrehajtja a processzor, de
a cl cmkzett utastsnak ugyanabban a fggvnyben kell lennie, ahol a
goto is van.
A void visszatrsektl eltekintve a fggvny testben lennie kell lega-
lbb egy
return <kifejezs>;
utastsnak. Ha a rutin visszatrsi tpusa tpus, akkor a kifejezs tpus-
nak is ennek kell lennie, vagy hozzrendelsi konverzival ilyen tpusv
alaktja a kifejezs rtkt a fordt. A return hatsra visszakapja a ve-
zrlst a hv fggvny, s tveszi a visszatrsi rtket is.
A tpus visszatrs fggvnyt hv kifejezs
fv(aktulis-paramterlista)
tpus tpus jobbrtk, s nem balrtk:
tpus t;
t=fv(aktulis-paramterlista); /* OK */
t=++fv(aktulis-paramterlista); /* OK */
118 UTASTSOK
A fggvnyhvs hatsra beindult vgrehajts a return utasts bek-
vetkeztekor befejezdik. Ha nincs return, akkor a fggvny testt
zr }-ig megy a vgrehajts.
Ha a fggvny ltal visszaadott rtk tpusa void, s a fggvnyt nem a
testt zr }-nl szeretnnk befejezni, akkor a fggvny belsejbe a kvnt
helyre return utastst kell rni.
C programnyelv 119
7 ELFELDOLGOZ (PREPROCESSOR)
A fordt els menete sorn mindig meghvja az elfeldolgozt a forrs-
fjlra.
Ha szeretnnk tudni, hogy fest az elfeldolgozson tesett forrsfjl
(a fordtsi egysg), akkor a programfejleszt rendszerben utna kell nz-
ni, hogy tehetjk lthatv az elfeldolgozs eredmnyt. Az elfeldolgo-
zott forrsfjlban aztn megtekinthetjk:
- a makrk kifejtst,
- a behozott (include) fjlokat,
- a feltteles fordtst,
- a szomszdos karakterlnc konstansok egyestst,
- a direktvk elhagyst s
- a megjegyzsek kimaradst (helyettestst egyetlen szkz karak-
terrel).
A nem karakter, vagy karakterlnc konstansban elfordul, egymst
kvet, tbb fehr karaktert mindig eggyel helyettesti az elfeldolgoz.
Az elfeldolgoz direktvk rsszablya, mely fggetlen a C nyelv tb-
bi rsztl, a kvetkez:
- A sor els, nem fehr karakternek #-nek kell lennie.
- A #-et kvetheti aztn fehr karakter a soremelst kivve. A sorokra
trdels nagyon lnyeges elem, mert az elfeldolgoz sorokra bont-
va elemzi a forrsszveget.
- A karakter konstansban, a karakterlnc konstansban s a megjegy-
zsben lev # karakter nem minsl elfeldolgoz direktva kezde-
tnek.
eA direktvkat - miutn nem C utastsok - tilos pontosvesszvel le-
zrni!
- Ha a direktvban a soremelst \ karakter elzi meg, akkor a kvet-
kez sor folytatssornak minsl, azaz az elfeldolgoz elhagyja a
\t s a soremelst, s egyesti a kt sort.
- Az elfeldolgoz direktvkba megjegyzs is rhat.
120 ELFELDOLGOZ DIREKTVK
- Az elfeldolgoz direktvk brhol elhelyezkedhetnek a forrsfjl-
ban, de csak a forrsfjl ezt kvet rszre hatnak, egszen a fjl v-
gig.
A teljes szintaktika az elfeldolgoz direktvkra a feltteles fordtstl
eltekintve gy, hogy a mr megismert fogalmakat jra nem definiljuk, a
kvetkez:
csoport:
csoport-rsz
csoport csoport-rsz
csoport-rsz:
elfeldolgoz-szimblumok jsor
feltteles-fordts
vezrl-sor
elfeldolgoz-szimblumok:
elfeldolgoz-szimblum
elfeldolgoz-szimblumok elfeldolgoz-szimblum
elfeldolgoz-szimblum:
<fjlazonost> (csak #include direktvban)
fjlazonost (csak #include direktvban)
azonost (nincs kulcssz megklnbztets)
konstans
karakterlnc-konstans
opertor
elvlaszt-jel
brmilyen nem fehr karakter, mely az elzek egyike sem
vezrl-sor:
#include elfeldolgoz-szimblumok jsor
#define azonost <elfeldolgoz-szimblumok> jsor
#define azonost(azonostlista) elfeldolgoz-szimblumok jsor
#undef azonost jsor
#line elfeldolgoz-szimblumok jsor
#error <elfeldolgoz-szimblumok> jsor
#pragma <elfeldolgoz-szimblumok> jsor
# jsor
jsor:
soremels
Az elfeldolgoz-szimblum defincijban a fjlazonost krli <> a
szintaktika rsze, s nem az elhagyhatsgot jelli, mint mskor. Ltszik,
hogy a feldolgozsban brmely karakter, ami nem foglalt az elfeldolgo-
znak, szintn szintaktikai egysget kpez.
7.1 res (null) direktva
A csak egy # karaktert tartalmaz sor. Ezt a direktvt elhagyja az el-
feldolgoz, azaz hatsra nem trtnik semmi.
C programnyelv 121
7.2 #include direktva
Az #include direktva lehetsges alakjait:
#include <fjlazonost> jsor
#include fjlazonost jsor
mr a BEVEZETS S ALAPISMERETEK szakaszban rszleteztk.
Tudjuk, hogy a vezrl-sort az elfeldolgoz a megadott fjl teljes tartal-
mval helyettesti. Magt a fjlt fjlazonost esetn elbb az aktulis
knyvtrban (abban, ahonnt azt a fjlt tlttte, amelyikben ez az #inc-
lude direktva volt), majd s <fjlazonost>s esetben a programfejleszt
rendszerben elrt utakon keresi.
A <> s az idzjelek kztt nincs makrhelyettests.
eHa a fjlazonostban >, , , \, vagy /* karakterek vannak, az el-
feldolgozs eredmnye meghatrozatlan.
eHa macskakrms esetben a fjlazonost elrsi utat is tartalmaz,
akkor a fjlt a preprocesszor csak abban a knyvtrban keresi, s sehol
msutt.
A direktva
#include elfeldolgoz-szimblum jsor
formjt elbb feldolgozza az elfeldolgoz, de a helyettestsnek itt is
<>, vagy alakot kell eredmnyeznie, s a hats ennek megfelel. Pld-
ul:
#define ENYIM \Cfajlok\Munka16\Pipo.h
/* . . . */
#include ENYIM
Az #include direktvk egymsba gyazhatk, azaz a behozott fjl
jabb #includeokat tartalmazhat, s azok megint jabbakat, s gy tovbb.
eAz egymsba gyazgatsokkal azonban vigyzni kell, mert egyes
programfejleszt rendszerek ezek szintjt pldul 10ben korltozhat-
jk!
7.3 Egyszer #define makr
A #define direktva makrt definil (makrdefinci). A makr szimb-
lumhelyettest mechanizmus fggvnyszer formlis paramterlistval
vagy anlkl.
Elbb a paramter nlkli esettel foglalkozunk! Ilyenkor a direktva a-
lakja:
#define azonost <elfeldolgoz-szimblumok> jsor
122 ELFELDOLGOZ DIREKTVK
Hatsra az elfeldolgoz a forrskdban ez utn kvetkez minden mak-
razonost elfordulst helyettest a lehet, hogy res elfeldolgoz-szim-
blumokkal. Ha res elfeldolgoz-szimblumokkal trtnik a helyettes-
ts, a makrazonost akkor is definilt, azaz #if defined vagy #ifdef di-
rektvval "rkrdezhetnk" az azonostra, de a makrazonost minden
forrsszvegbeli elfordulsnak eltvoltst jelenti tulajdonkpp. Nem
trtnik meg a helyettests, ha a makrazonost karakter vagy karakter-
lnc konstansban, vagy megjegyzsben, vagy ms makrazonost rsze-
knt tallhat meg. Ezt a folyamatot makrkifejtsnek (expansion) neve-
zik. A elfeldolgoz-szimblumokat szoks makrtest nvvel is illetni.
Pldul:
#define HI J napot!
#define begin {
#define end }
#define then
#define NIL
#define EGY 1
int main(void)
begin /* Helyettests {-re. */
int i=8, k=i+EGY;/* Csere k=i+1-re.*/
puts(HI); /* puts(J napot!); lesz belle */
puts(NIL); /* puts(); lesz a sorbl. */
puts(then); /* Nincs helyettests, mert a makra-
zonost karakterlnc konstansban van. */
if(++i<k)
/* A sor eleji then semmire helyettestse, de a */
then puts(Ez a then-g!\n); /* msik marad.*/
else puts(Ez az else-g!\n);
return 0;
end /* Csere }-re. */
A makrkifejts utni makrazonostkat is helyettesti a preprocesszor,
azaz a makrk is egymsba gyazhatk.
eA makrazonost jradefinilsa csak akkor nem hiba, ha az elfel-
dolgoz-szimblumok tkletesen, pozcihelyesen azonosak. Ettl elt-
r jradefinils csak a rvonatkoz #undef direktva utn lehetsges.
A nyelv kulcsszavait is alkalmazhatjuk makrdefincikban, legfel-
jebb kiss rtelmetlennek tekinthet az eljrsunk:
#define LACI for
#define PAPI while
#define int long
, de a kvetkez fejezetben ismertetett, szabvnyos, elredefinilt makrk
nem jelenhetnek meg sem #define, sem #undef direktvkban.
C programnyelv 123
A programfejleszt rendszer segtsgben clszer utna nzni, hogy
mg milyen ms, vdett makrazonostk hasznlata tiltott!
7.4 Elredefinilt makrk
Nhny makr elredefinilt az elfeldolgoz rendszerben, s kifejtet-
skkel specilis informci kpezhet. Ezek a makrk mind defined tpu-
sak. Nem tehetk definilatlann, s nem definilhatk jra. A szabv-
nyos, elredefinilt makrk s jelentsk a kvetkez:
__DATE__: HHH NN alak karakterlnc, s az aktulis forrs-
fjl elfeldolgozsa kezdetnek dtuma. A HHH hrombets hnapnv
rvidts (Jan, Feb stb.). Az NN 1 s 31 kztti napszm, s gy tovbb.
__FILE__: Karakterlncknt a feldolgozs alatt ll forrsfjl azonos-
tjt tartalmazza. A makr vltozik #include s #line direktva hatsra,
valamint ha a forrsfjl fordtsa befejezdik.
__LINE__: Decimlis rtkknt a feldolgozs alatti forrsfjl aktulis
sornak sorszma. A sorszmozs 1-tl indul. Mdosthatja pldul a
#line direktva is.
__STDC__:Definilt s 1, ha ANSI kompatibilis fordts van, msk-
lnben definilatlan.
__TIME__:OO:PP:MM alak karakterlnc, s a forrsfjl feldolgozsa
megkezdsnek idejt tartalmazza.
7.5 #undef direktva
#undef azonost jsor
A direktva definilatlann teszi a makrazonostt, azaz a tovbbiakban
nem vesz rszt a makrkifejtsben.
Azt, hogy egy makrazonost definilt-e vagy sem a forrskdban,
megtudhatjuk a
#ifdef azonost
#ifndef azonost
direktvk segtsgvel, azaz a makrdefincinl ajnlhat a kvetkez
stratgia:
#ifndef MAKROKA
#define MAKROKA 162
#endif
Az ismeretlen makrazonostra kiadott #undef direktvt nem te-
kinti hibnak az elfeldolgoz.
124 ELFELDOLGOZ DIREKTVK
A definilatlann tett makrazonost ksbb jradefinilhat akr ms
elfeldolgoz-szimblumokkal. A #define-nal definilt s kzben #un-
def-fel definilatlann nem tett makrazonost definilt marad a forrs-
fjl vgig. Pldul:
#define BLOKK_MERET 512
/* . . . */
puff = BLOKK_MERET*blkszam; /* Kifejts: 512*blkszam. */
/* . . . */
#undef BLOKK_MERET
/* Innt a BLOKK_MERET ismeretlen makrazonost. */
/* . . . */
#define BLOKK_MERET 128
/* . . . */
puff = BLOKK_MERET*blkszam; /* Kifejts: 128*blkszam. */
7.6 Paramteres #define direktva
A direktva alakja ilyenkor:
#define azonost(azonostlista) elfeldolgoz-szimblumok jsor
Az azonostlista egymstl vesszvel elvlasztott formlis paramter-
azonostkbl ll. A makrt hv aktulis paramterlistban ugyanannyi
paramternek kell lennie, mint amennyi a formlis paramterlistban volt,
mert klnben hibazenetet kapunk.
Ugyan a makrra is a fggvnnyel kapcsolatos fogalmakat hasznl-
juk kpszersgk vgett, de ki kell hangslyozni, hogy a makr nem
fggvny!
eA makrazonost s a paramterlistt nyit kerek zrjel kz sem-
milyen karakter sem rhat, hisz rgtn egyszer #define-n tenn a para-
mteres direktvt!
Az elfeldolgoz elbb a makrazonostt helyettesti, s csak aztn a z-
rjelbe tett paramtereket:
Definci: #define KOB(x) ((x)*(x)*(x))
Forrssor: n = KOB(y);
Kifejtve: n = ((y)*(y)*(y));
A ltszlag redundns zrjeleknek nagyon fontos szerepk van:
Definci: #define KOB(x) (x*x*x)
Forrssor: n = KOB(y + 1);
Kifejtve: n = (y + 1*y + 1*y + 1);
A kls zrjel pr a kifejezsekben val felhasznlhatsgot biztostja:
Definci: #define SUM(a,b) (a)+(b)
Forrssor: n = 14.5 * SUM(x*y, z-8);
Kifejtve: n = 14.5 * (x*y)+(z-8);
C programnyelv 125
A zrjelbe, vagy aposztrfok, idzjelek kz tett vesszk nem min-
slnek a listban azonost elvlasztnak:
Definci: #define SUM(a,b) ((a)+(b))
Forrssor: return SUM(f(i,j), g(k,l));
Kifejtve: return ((f(i,j))+(g(k,l)));
Definci: #define HIBA(x,lanc) hibaki(Hiba: ,x,lanc)
Forrssor: HIBA(2,ssn Enter-t, s Esc-t!);
Kifejtve: hibaki(Hiba: ,2,ssn Enter-t, s Esc-t!);
j azonost generlsi cllal a szimblum1##szimblum2 alakbl szim-
blum1szimblum2-t llt el az elfeldolgoz:
Definci: #define VAR(i,j) (i##j)
Forrssor: VAR(a,8)
Kifejtve: (a8)
A formlis paramter el rt # (gy nevezett karakterlncost opertor)
az aktulis paramtert karakterlnc konstanss konvertlja:
Definci: #define NYOM(jel) printf(#jel =%d\n, jel)
Forrssor: int kilo = 100; NYOM(kilo);
Kifejtve: int kilo = 100; printf(kilo =%d\n, kilo);
Folytatssor most is sorvgi \ jellel kpezhet:
Definci: #define FIGYU Ez igazbl egyetlen \
sornak minsl!
Forrssor: puts(FIGYU);
Kifejtve: puts(Ez igazbl egyetlen sornak minsl!);
eA makr nem fggvny, teht semmilyen ellenrzs sincs a param-
terek adattpusra! Ha az aktulis paramter kifejezs, akkor kirtkelse
tbbszr is megtrtnik:
int kob(int x){ return x*x*x;}
#define KOB(x) ((x)*(x)*(x))
/* . . . */
int b = 0, a = 3;
b = kob(a++); /* b == 27 s a == 4. */
a = 3;
b = KOB(a++); /* Kifejtve: ((a++)*(a++)*(a++)),
azaz b == 60 s a == 6. */
7.7 Karaktervizsgl fggvnyek (makrk)
Megismerkedtnk az elz fejezetekben a makrk elnys, s persze
htrnyos tulajdonsgaival. Mindezek dacra a makrk hasznlata a C
ben elg szleskr.
Nzzk csak meg a szabvnyos STDIO.H fejfjlt, s ltni fogjuk,
hogy a szabvny bemenetet s kimenetet kezel getchar s putchar ruti-
nok makrk.
126 ELFELDOLGOZ DIREKTVK
A szabvnyos STDIO.H fejfjlban deklarlt fggvnyek karakter osz t -
lyo zs t vgeznek. A rutinok c paramtere int ugyan, de az rtknek un-
signed char tpusban brzolhatnak, vagy EOFnak kell lennie. A
visszatrsi rtkk ugyancsak int logikai jelleggel, azaz nem zrus
(igaz), ha a feltett krdsre adott vlasz igen, ill. zrus (hamis), ha nem.
A teljessg ignye nlkl felsorolunk nhny karakterosztlyoz fgg-
vnyt!
Fggvny Krds
islower(c) c kisbete?
isupper(c) c nagybete?
isalpha(c) islower(c) | isupper(c)
isdigit(c) c decimlis szmjegye?
isalnum(c) isalpha(c) | isdigit(c)
isxdigit(c) c hexadecimlis szmjegye?
isspace(c) c fehr karaktere? (szkz, soremels, lapemels, ko-
csi vissza, fggleges vagy vzszintes tabultor)
isprint(c) c nyomtathat karaktere?
Meg kell mg emlteni kt konverzis rutin is:
int tolower(c);
int toupper(c);
, melyek c rtkt kisbetv (tolower), ill. nagybetv (toupper) alaktva
szolgltatjk, ha c bet karakter, de vltozatlanul adjk vissza, ha nem az.
rjuk t PELDA17.Ct gy, hogy karaktervizsgl fggvnyeket hasz-
nljon!
/* PELDA19.C: A bemenet karaktereinek leszmllsa kateg-
rinknt az is fggvnyek segtsgvel. */
#include <stdio.h>
#include <ctype.h>
void main(void){
short k, num=0, feher=0, egyeb=0;
printf("Bemeneti karakterek leszmllsa\n"
"kategrinknt EOF-ig, vagy Ctrl+Z-ig.\n");
while((k=getchar())!=EOF)
if(isdigit(k)) ++num;
else if (isspace(k)) ++feher;
else ++egyeb;
printf("Karakter szmok:\n----------------\n"
"numerikus: %5hd\nfehr: %5hd\n"
"egyb: %5hd\n----------------\n"
"ssz: %10ld\n", num, feher, egyeb,
(long)num+feher+egyeb); }
C programnyelv 127
rjuk mg t ugyanebben a szellemben a PELDA18.C egesze fggv-
nyt is!
#include <ctype.h>
#define HSZ sizeof(int)/sizeof(short)*5
int egesze(char s[]){
int i = 0, kezd;
while(isspace(s[i])) ++i;
if(s[i]=='+' || s[i]=='-') ++i;
kezd=i; /* A szmjegyek itt kezddnek. */
while(isdigit(s[i]) && i-kezd<HSZ) ++i;
if(kezd==i || !isspace(s[i]) && s[i]!=0) return 0;
else return 1; }
A PELDA13.Cbeli strup rutin gy mdosulna:
#include <ctype.h>
void strup(char s[]){
int i;
for(i=0; s[i]; ++i) s[i]=toupper(s[i]); }
Milyen elnyei vannak a karakterosztlyoz fggvnyek hasznlatnak?
- A kd rvidebb, s ez ltal gyorsabb is.
- A program portbilis lesz, hisz fggetlenedik az ASCII (vagy ms)
kdtbla sajtossgaitl.
Az olvas utols logikus krdse mr csak az lehet, hogy mirt pont
a makrk kztt trgyaljuk a karaktervizsgl rutinokat?
Tbb C implementci makrknt valstja meg ezeket a fggvnyeket.
Erre mutatunk itt be egy szintn nem teljes kr pldt azzal a felttellel,
hogy a CHAR_BIT (bitek szma a char tpusban lsd LIMITS.Ht!)
makr rtke 8.
/* Bitmaszk rtkek a lehetsges karaktertpusokra: */
#define _UPPER 0x1 /* Nagybet. */
#define _LOWER 0x2 /* Kisbet. */
#define _DIGIT 0x4 /* Decimlis szmjegy. */
#define _SPACE 0x8 /* \t,\r,\n,\v,\f */
#define _PUNCT 0x10 /* Elvlaszt-jel. */
#define _CONTROL 0x20 /* Vezrl karakter. */
#define _BLANK 0x40 /* Szkz. */
#define _HEX 0x80 /* Hexadecimlis szmjegy. */
/* Globlis tmb, melyben a rendszer mindenegyes kdtbla
pozcira belltotta ezeket a biteket: */
extern unsigned char _ctype[];
/* Nhny makr: */
#define islower(_c) (_ctype[_c]&_LOWER)
#define isupper(_c) (_ctype[_c]&_UPPER)
#define isalpha(_c) (_ctype[_c]&(_UPPER|_LOWER))
#define isdigit(_c) (_ctype[_c]&_DIGIT)
#define isalnum(_c) (_ctype[_c]&(_UPPER|_LOWER|_DIGIT))
128 ELFELDOLGOZ DIREKTVK
#define isxdigit(_c) (_ctype[_c]&_HEX)
#define isspace(_c) (_ctype[_c]&(_SPACE|_BLANK))
#define isprint(_c) (_ctype[_c]&(_BLANK|_PUNCT|_UPPER|\
_LOWER|_DIGIT))
Megoldand feladatok:
Ksztse el a kvetkez fggvnyek makr vltozatt!
- A fejezetben emltett tolowert s touppert.
- A TPUSOK S KONSTANSOK szakaszban megrt strcopyt,
s ms karakterlnc kezelkt. {STRMAKRO.C}
Ha az olvasban felmerlt volna az a gondolat, hogy mi van akkor,
ha ugyanolyan nev makr s fggvny is ltezik, akkor arra szeretnnk
emlkeztetni, hogy:
- Az elfeldolgozs mindig a fordts eltt trtnik meg, s gy min-
denbl makr lesz.
- Ha #undef direktvval definilatlann tesszk a makrt, akkor attl
kezdve csak fggvny lesz a forrsszvegben.
- Ha a hvsban redundns zrjelbe zrjuk a makr vagy a fggvny
nevt, akkor az elfeldolgoz ezt nem fejti ki, teht bizonyosan
fggvnyhvs lesz belle.
...(makrnv)(paramterek)...
7.8 Feltteles fordts
feltteles-fordts:
if-csoport <elif-csoportok> <else-csoport> endif-sor
if-csoport:
#if konstans-kifejezs jsor <csoport>
#ifdef azonost jsor <csoport>
#ifndef azonost jsor <csoport>
elif-csoportok:
elif-csoport
elif-csoportok elif-csoport
elif-csoport:
#elif konstans-kifejezs jsor <csoport>
else-csoport:
#else jsor <csoport>
endif-sor:
#endif jsor
jsor:
soremels
C programnyelv 129
A feltteles direktvk szerint kihagyand forrssorokat az elfeldolgoz
trli a forrsszvegbl, s a feltteles direktvk sorai maguk pedig kima-
radnak az eredmny fordtsi egysgbl. A feltteles direktvk ltal kp-
zett konstrukcit - melyet rgtn bemutatunk egy ltalnos pldn - min-
denkppen be kell fejezni abban a forrsfjlban, amelyben elkezdtk.
#if konstans-kifejezs1
<szekci1>
<#elif konstans-kifejezs2
<szekci2>>
/* . . . */
<#elif konstans-kifejezsN
<szekciN>>
<#else
<vgs-szekci>>
#endif
Lssuk a kirtkelst!
1. Ha a konstans-kifejezs1 rtke nem zrus (igaz), akkor a prepro-
cesszor a szekci1 sorait feldolgozza, s az eredmnyt tadja a ford-
tnak. A szekci1 termszetesen res is lehet. Ezutn az ezen
#if-hez tartoz sszes tbbi sort a vonatkoz #endif-fel bezrlag
kihagyja, s az #endif-t kvet sorral folytatja a munkt az elfeldol-
goz.
2. Ha a konstans-kifejezs1 rtke zrus (hamis), akkor a preprocesszor
a szekci1-t teljes egszben elhagyja. Teht nincs makrkifejts, s
nem adja t a feldolgozott darabot a fordtnak! Ezutn viszont a
kvetkez #elif konstans-kifejezse kirtkelsbe fog, s gy tovbb.
3. sszestve az #if-en s az #elif-eken lefel haladva az a szekci ke-
rl elfeldolgozsra, s ennek eredmnye fordtsra, melynek kons-
tans-kifejezse igaznak bizonyul. Ha egyik ilyen konstans-kifejezs
sem igaz, akkor az #else vgs-szekcijra vonatkoznak az elbbi-
ekben mondottak.
Az #if . . . #endif konstrukcik tetszleges mlysgben egymsba
gyazhatk.
e Az #if . . . #endif szerkezetbeli konstans-kifejezseknek korltozott,
egsz tpusaknak kell lennik! Konkrtabban egsz konstanst, karakter
llandt tartalmazhat a kifejezs, s benne lehet a defined opertor is. Ti-
los hasznlni viszont benne explicit tpuskonverzit, sizeof kifejezst,
enumertort s lebegpontos konstanst, mint norml egsz tpus kons-
130 ELFELDOLGOZ DIREKTVK
tans kifejezsekben! Az elfeldolgoz kznsges makrhelyettestsi
menettel dolgozza fel a konstans-kifejezseket.
7.8.1 A defined opertor
Makrazonostk definiltsgnak ellenrzsre val, s csak #if s #elif
konstans-kifejezseiben szerepelhet. A
defined(azonost)
vagy a
defined azonost
alak a makrazonost definiltsgra krdez r. Miutn a vlasz logikai
rtk a defined szerkezetek logikai mveletekkel is kombinlhatk a
konstans-kifejezsekben. Pldul:
#if defined(makro1) && !defined(makro2)
Ha biztostani szeretnnk azt, hogy a fordtsi egysgbe egy bizonyos
fejfjl (legyen HEADER.H) csak egyszer pljn be, akkor a fejfjl sz-
vegt kvetkezkpp kell direktvkba foglalni:
#if !defined(_HEADERH)
#define _HEADERH
/* Itt van a fejfjl szvege. */
#endif
Ilyenkor akrhny #include is jn a forrsfjlban a HEADER.H fejfjlra,
a behozatala csak elszr trtnik meg, mert a tovbbi bekapcsolsokat az
_HEADERH makr definiltsga megakadlyozza.
Nzznk csak bele nhny szabvnyos fejfjlba, ott is alkalmazzk
ezt a konstrukcit!
7.8.2 Az #ifdef s az #ifndef direktvk
Az #ifdef direktva egy makrazonost definiltsgra, s az #ifndef vi-
szont a definilatlansgra krdez r, azaz:
#ifdef azonost #if defined(azonost)
#ifndef azonost #if !defined(azonost)
7.9 #line sorvezrl direktva
#line egsz-konstans <fjlazonost> jsor
Jelzi az elfeldolgoznak, hogy a kvetkez forrssor egsz-konstans
sorszm, s a fjlazonost nev fjlbl szrmazik. Miutn az aktulisan
feldolgozs alatt ll forrsfjlnak is van azonostja a fjlazonost para-
mter elhagysakor a #line az aktulis fjlra vonatkozik.
C programnyelv 131
A makrkifejts a #line paramtereiben is megtrtnik.
Vegynk egy pldt!
/* PELDA.C: a #line direktvra: */
#include <stdio.h>
#line 4 PIPI.C
void main(void) {
printf(\nA(z) %s fjl %d sorban vagyunk!, __FILE__,
__LINE__);
#line 12 PELDA.C
printf(\n);
printf(A(z) %s fjl %d sorban vagyunk!, __FILE__,
__LINE__);
#line 8
printf(\n);
printf(A(z) %s fjl %d sorban vagyunk!\n, __FILE__,
__LINE__); }
Az ellltott standard kimenet a kvetkez lehet:
#line 1 "pelda.c"
#line 1 "c:\\msdev\\include\\stdio.h"
. . .
#line 524 "c:\\msdev\\include\\stdio.h"
#line 3 "pelda.c"
#line 4 "PIPI.C"
void main(void) {
printf(\nA(z) %s fjl %d sorban vagyunk!, PIPI.C,
6);
#line 12 "PELDA.C
printf(\n);
printf(A(z) %s fjl %d sorban vagyunk!, PELDA.C,
13);
#line 8 "PELDA.C"
printf(\n);
printf(A(z) %s fjl %d sorban vagyunk!\n,PELDA.C,
9); }
A #line direktva tulajdonkppen a __FILE__ s a __LINE__ el-
redefinilt makrk rtkt lltja. Ezek a makrrtkek a fordt hibaze-
neteiben jelennek meg. Szval a direktva diagnosztikai clokat szolgl.
7.10 #error direktva
#error <hibazenet> jsor
direktva zenetet generl, s befejezdik a fordts. Az zenet alakja le-
het a kvetkez:
Error: fjlazonost sorszm: Error directive: hibazenet
Rendszerint #if direktvban hasznlatos. Pldul:
#if (SAJAT!=0 && SAJAT!=1)
132 ELFELDOLGOZ DIREKTVK
#error A SAJAT 0-nak vagy 1-nek definiland!
#endif
7.11 #pragma direktvk
#pragma <elfeldolgoz-szimblumok> jsor
A direktvk gp s opercis rendszerfggk. Bennk a #pragma
kulcsszt kvet szimblumok mindig objektumai a makrkifejtsnek, s
tulajdonkppen specilis fordti utastsok, s ezek paramterei. Az el-
feldolgoz a fel nem ismert #pragma direktvt figyelmen kvl hagyja.
C programnyelv 133
8 OBJEKTUMOK S FGGVNYEK
Az azonostk rtelmt a deklarcik rgztik. Tudjuk, hogy a dekla-
rci nem jelent szksgkppen memriafoglalst. Csak a defincis dek-
larci ilyen.
deklarci:
deklarci-specifiktorok<init-deklartorlista>
init-deklartorlista:
init-deklartor
init-deklartorlista, init-deklartor
init-deklartor:
deklartor
deklartor=inicializtor
Az inicializtorokkal s inicializtorlistkkal a BEVEZETS S A-
LAPISMERETEK szakasz Inicializls fejezetben foglalkoztunk. A
deklartorok a deklarland neveket tartalmazzk. A deklarci-specifi-
ktorok tpus s trolsi osztly specifiktorokbl llnak:
deklarci-specifiktorok:
trolsi-osztly-specifiktor<deklarci-specifiktorok>
tpusspecifiktor<deklarci-specifiktorok>
tpusmdost<deklarci-specifiktorok>
A tpusspecifiktorokat a TPUSOK S KONSTANSOK szakaszban
trgyaltuk, s ezek kzl kivettk a const s a volatile tpusmdostkat.
8.1 Objektumok attribtumai
Az objektum egy azonosthat memria terletet, mely konstans vagy
vltoz rtk(ek)et tartalmaz. Az objektum egyik attribtuma (tulajdons-
ga) az adattpusa. Tudjuk, hogy van ezen kvl azonostja (neve) is. Az
objektum adattpus attribtuma rgzti az objektumnak
- allokland (lefoglaland) memria mennyisgt s
- a benne trolt informci belsbrzolsi formjt.
Az objektum neve nem attribtum, hisz klnfle hatskrben tbb k-
lnbz objektumnak is lehet ugyanaz az azonostja. Az objektum to-
vbbi attribtumait (trolsi osztly, hatskr, lthatsg, lettartam, stb.)
a deklarcija s annak a forrskdban elfoglalt helye hatrozza meg.
Emlkeztetl: a loklis, globlis s a bels, kls vltozkat taglal-
tuk mr a BEVEZETS S ALAPISMERETEK szakaszban!
134 OBJEKTUMOK S FGGVNYEK
8.1.1 Trolsi osztlyok
Az objektumokhoz rendelt azonostknak van legalbb
- trolsi osztly s
- adattpus
attribtuma. Szoks e kettt egytt is adattpusnak nevezni. A trolsi
osztly specifiktor defincija:
trolsi-osztly-specifiktor:
auto
register
extern
static
typedef
A trolsi osztly meghatrozza az objektum lettartamt, hatskrt s
kapcsoldst. Egy adott objektumnak csak egy trolsi osztly specifik-
tora lehet egy deklarciban. A trolsi osztlyt a deklarci forrskdbeli
elhelyezse implicit mdon rgzti, de a megfelel trolsi osztly kulcs-
sz expliciten is belerhat a deklarciba.
A kapcsoldssal kln fejezetben foglalkozunk.
Trolsi osztly kulcssz nlkli deklarcik esetben a blokkon bell
deklarlt
- objektum mindig auto definci, s
- a fggvny pedig extern deklarci.
A fggvnydefincik s az ezeken kvli objektum s fggvnydeklar-
cik mind extern, statikus trolsi osztlyak.
Ktfle trolsi osztly van.
8.1.1.1 Automatikus (auto, register) trolsi osztly
Az ilyen objektumok loklis lettartamak, s loklisak a blokk egy
adott pldnyra. Az ilyen deklarcik defincik is egyben, azaz megtr-
tnik a memriafoglals is. Ismeretes, hogy a fggvnyparamterek is au-
tomatikus trolsi osztlyaknak minslnek. Rekurzv kd esetn az au-
tomatikus objektumok garantltan klnbz memria terleten helyez-
kednek el mindenegyes blokkpldnyra.
A C az automatikus objektumokat a program vermben trolja, s gy
alaprtelmezett kezdrtkk "szemt". Expliciten inicializlt, loklis au-
tomatikus objektum esetben a kezdrtk ads viszont mindannyiszor
C programnyelv 135
megtrtnik, valahnyszor bekerl a vezrls a blokkba. A blokkon bell
definilt objektumok auto trolsi osztlyak, hacsak ki nem rtk expli-
citen az extern vagy a static kulcsszt a deklarcijukban. Csak loklis
hatskr objektumok deklarcijban hasznlhat az auto trolsi osz-
tly specifiktor.
e Az auto kulcsszt tilos kls deklarciban vagy definciban al-
kalmazni!
Az automatikus trolsi osztly objektumok loklis lettartamak s
nincs kapcsoldsuk. Miutn ez az alaprtelmezs az sszes loklis hats-
kr objektum deklarcijra, nem szoks s szksgtelen expliciten kir-
ni.
e Az auto trolsi osztly specifiktor fggvnyre nem alkalmazhat!
Az automatikus trolsi osztly specilis vlfaja a regiszteres. A regis-
ter kulcssz a deklarciban azt jelzi a fordtnak, hogy
- a vltozt nagyon gyakran fogjuk hasznlni, s
- krjk, hogy az illet objektumot regiszterben helyezze el, ha lehet-
sges.
A regiszteres trols rvidebb gpi kd programot eredmnyez,
hisz elmarad a memribl regiszterbe (s vissza) tltgets. Emiatt, s
mert a regiszter a memrinl jval kisebb elrsi idej, a szoftver futsa
is gyorsul.
A hardvertl fgg ugyan, de valjban csak kevs objektum helyezked-
het el regiszterben, s csak meghatrozott tpus vltozk kerlhetnek
oda. A fordt elhagyja a register kulcsszt a felesleges s a nem megfe-
lel tpus deklarcikbl, azaz az ilyen vltozk csak norml, automati-
kus trolsi osztlyak lesznek.
A regiszteres objektumok loklis lettartamak, s ekvivalensek az au-
tomatikus vltozkkal. Csak loklis vltozk s fggvnyparamterek
deklarcijban alkalmazhat a register kulcssz.
e Kls deklarciban vagy definciban a register kulcsszt tilos al-
kalmazni!
e Fggetlenl attl, hogy a register vltoz igazn regiszterben he-
lyezkedik el, vagy sem, tilos a cmre hivatkozni!
A globlis optimalizlst bekapcsolva a fordt figyelmen kvl
hagyja a programoz register ignyeit, s sajt maga vlaszt regiszter ki-
136 OBJEKTUMOK S FGGVNYEK
osztst, de minden ms a register kulcsszhoz kapcsold szemantikt te-
kintetbe vesz.
rjunk int prime(int x) fggvny, mely eldnti pozitv egsz paramte-
rrl, hogy prmszme!
A prmszm csak 1gyel s nmagval oszthat maradk nlkl. Prbl-
juk meg teht egsz szmok szorzataknt ellltani. Ha sikerl, akkor
nem trzsszmrl van sz. A szm prm viszont, ha ez nem megy. Ind-
tunk teht 2rl mindig nvelgetve egy osz vltozt, s megprbljuk,
hogy oszthate vele maradk nlkl az x.
Meddig nvekedhet az osz? x ngyzetgykig, mert a kt szorztnye-
zre bontsnl fordtott arnyossg van a kt tnyez kztt.
int prime(register x){
register osz = 2;
if(x < 4) return 1;
while(osz*osz <= x){
if(!(x%osz)) return 0;
++osz;
if(!(osz&1)) ++osz; }
return 1; }
A prime paramtere s az osz loklis vltoz register int tpus
programgyorstsi cllal. A fggvny utols eltti sorbl ltszik, hogy
legalbb a pros szmokat nem prbljuk ki osztknt, miutn 2vel nem
volt maradk nlkl oszthat az x.
Az olvasra bzzuk, hogy ksrje meg mg gyorstani az algoritmust!
Ksztsnk programot, mely megllaptja egy vals szmsorozat tlagt
s azt, hogy hny tlagnl kisebb s nagyobb eleme van a sorozatnak! A
vals szmokat a szabvny bemenetrl kell beolvasni! Egy sorban egyet!
A sorozat megadsnak vgt jelentse res sor rkezse a bemenetrl!
Kezdjk a kdolst az int lebege(char s[]) fggvnnyel, mely meglla-
ptja karakterlnc paramterrl, hogy formlisan helyes lebegpontos
szme! A karaktertmb elejn lev fehr karaktereket t kell lpni, s a
numerikus rsz ugyancsak fehr, vagy lnczr zrus karakterrel zrul. A
lebegpontos szmnak ki kell egybknt elgtenie a lebegpontos kons-
tans rsszablyt!
#include <ctype.h>
int lebege(char s[]){
int i=0, kezd;
/* Fehr karakterek tlpse a lnc elejn: */
while(isspace(s[i])) ++i;
/* A mantissza eljele: */
if(s[i]=='+'||s[i]=='-') ++i;
C programnyelv 137
kezd=i; /* A szjegyek itt kezddnek. */
/* A mantissza egsz rsze: */
while(isdigit(s[i])) ++i;
/* A mantissza trt rsze: */
if(s[i]=='.') ++i;
while(isdigit(s[i])) ++i;
/* Nincs szmjegy, vagy csak egy . van: */
if(i==kezd||kezd+1==i&&s[kezd]=='.') return 0;
/* Kitev rsz: */
if(toupper(s[i])=='E'){
++i;
if(s[i]=='+'||s[i]=='-')++i;
/* Egy szmjegynek lennie kell a kitevben! */
if(!isdigit(s[i])) return 0;
while(isdigit(s[i])) ++i;}
/* Vge: */
if(isspace(s[i])||!s[i]) return 1;
else return 0; }
8.1.1.2 Statikus (static, extern) trolsi osztly
A statikus trolsi osztly objektumok ktflk:
- blokkra loklisak, vagy
- blokkokon t klsk.
Az ilyen trolsi osztly objektumok statikus lettartamak. Brhogyan
is: megrzik rtkket az egsz program vgrehajtsa sorn, akrhnyszor
is hagyja el a vezrls az ket tartalmaz blokkot, s tr oda vissza. Fgg-
vnyen, blokkon bell gy definilhat statikus trolsi osztly vltoz,
hogy a deklarcijba ki kell expliciten rni a static kulcsszt. A static
kulcsszavas deklarci definci.
Ksztsnk double gyujto(double a) fggvnyt, mely gyjti aktulis pa-
ramterei rtkt! Mindig az eddig megllaptott sszeget adja vissza. Ne
legyen bamba, azaz ne lehessen vele ttrni az brzolsi hatrokat!
A lebegpontos tl, vagy alulcsorduls futsidej hiba!
#include <float.h>
double gyujto(double a){
static double ossz=0.0;
if(a<0.0&&-(DBL_MAX+a)<ossz || DBL_MAX-a>ossz)
ossz+=a;
return ossz; }
Ltszik, hogy nincs sszegzs, ha az ossz DBL_MAXhoz, vagy
+DBL_MAXhoz a tvolsgon bellre kerl.
Rekurzv kdban a statikus objektum llapota garantltan ugyanaz min-
den fggvnypldnyra.
138 OBJEKTUMOK S FGGVNYEK
Explicit inicializtorok nlkl a statikus vltozk minden bitje zrus
kezdrtket kap. Az implicit s az explicit inicializls mg loklis stati-
kus objektum esetn is csak egyszer trtnik meg, a program indulsakor.
A gyujtoben teljesen felesleges zrussal inicializlni a statikus
ossz vltozt, hisz implicit mdon is ez lenne a kezdrtke.
A fggvnydefincikon kvl elhelyezett, trolsi osztly kulcssz nl-
kli deklarcik kls, statikus trolsi osztly objektumokat definil-
nak, melyek globlisak az egsz programra nzve.
A kls objektumok statikus lettartamak. Az explicit mdon extern
trolsi osztlynak deklarltak olyan objektumokat deklarlnak, melyek
defincija nem ebben a fordtsi egysgben van, vagy befoglal hatskr-
ben tallhat.
extern int MasholDefinialt; /* Ms ford. egysgben */
void main(){
int IttDefinilt;
{
extern int IttDefinilt;
/* A befoglal hatskrbeli IttDefinilt-ra val
hivatkozs. */ } }
A kls kapcsoldst jellend az extern fggvny s objektum fjl s
loklis hatskr deklarciiban hasznlhat. Fjl hatskr vltozk s
fggvnyek esetben ez az alaprtelmezs, teht expliciten nem szoks ki-
rni.
e Az extern kulcssz explicit kirsa tilos a vltoz definil deklar-
cijban!
A kls objektumok s a fggvnyek is deklarlhatk staticnek, ami-
kor is lokliss vlnak az ket tartalmaz fordtsi egysgre, s minden
ilyen deklarci definci is egyben.
Folytatva a pldnkat: a szabvny bemenetrl rkez, vals szmokat
valahol trolni kne, mert az tlag csak az sszes elem beolvassa utn l-
lapthat meg. Ez utn jra vgig kell jrni a szmokat, hogy kiderthes-
sk, hny tlag alatti s feletti van kztk.
A vltozatossg kedvrt, s mert a clnak tkletesen megfelel, hasz-
nljunk vermet a letrolshoz, melyet s kezel fggvnyeinek definciit
helyezzk el a DVEREM.C forrsfjlban, s a ms fordtsi egysgbl is
hvhat fggvnyek prototpusait tegyk be a DVEREM.H fejfjlba!
C programnyelv 139
` Egy tmakr adatait s kezel fggvnyeit egybknt is szoks a C
ben kln forrsfjlban (gy nevezett implementcis fjlban) elhelyezni,
vagy a lefordtott vltozatot kln knyvtrfjlba tenni.
A dologhoz mindig tartozik egy fejfjl is, mely tartalmazza legalbb a
tmakr ms forrsmodulbl is elrhet adatainak deklarciit, s kezel
fggvnyeinek prototpusait. Implementcis fjl esetn a fejfjlban mg
tpusdefincik, szimbolikus llandk, makrk, stb. szoktak lenni.
/* DVEREM.H: double verem push, pop s clear
fggvnyenek prototpusai. */
int clear(void);
double push(double x);
double pop(void);
/* DVEREM.C: double verem push, pop s clear
fggvnyekkel. */
#define MERET 128 /* A verem mrete. */
static int vmut; /* A veremmutat. */
static double v[MERET]; /* A verem. */
int clear(void){
vmut=0;
return MERET; }
double push(double x){
if(vmut<MERET) return v[vmut++]=x;
else return x+1.; }
double pop(void){
if(vmut>0) return v[--vmut];
else return 0.; }
A vmut veremmutat, s a v verem statikus ugyan, de loklis a
DVEREM.C fordtsi egysgre. Ltszik, hogy a push x paramtervel
tlti a vermet, s sikeres esetben ezt is adja vissza. Ha a verem betelt, ms
rtk jn vissza tle. A pop visszaszolgltatja a legutbb betett rtket,
ill. az res verembl mindig zrussal tr vissza. A clear trli a veremmu-
tatt, s ez ltal a vermet, s visszaadja a verem maximlis mrett.
Kdoljuk le vgre az eredetileg kitztt feladatot!
/* PELDA20.C: Vals szmok tlaga, s az ez alatti, ill.
feletti elemek szma. */
#include <stdio.h>
#include <stdlib.h> /* Az atof miatt! */
#define INP 60 /* Az input puffer mrete. */
int getline(char s[],int lim);
#include <ctype.h>
int lebege(char s[]);
#include <float.h>
double gyujto(double a);
#include "DVEREM.H"
void main(void){
int max=clear(), /* A verem max. mrete. */
140 OBJEKTUMOK S FGGVNYEK
i=0, alatt, felett;
char s[INP+1]; /* Az input puffer. */
double a;
printf("Szmsorozat tlaga alatti s feletti "
"elemeinek szma.\nA megadst res "
"sorral kell befejezni!\n\n");
while( printf("%4d. elem: ", i+1), i<max &&
getline(s,INP)>0)
if(lebege(s)){
push(a=atof(s));
printf("Az sszeg:%30.6f\n\n", a=gyujto(a));
++i;}
printf("\nAz tlag: %30.6f\n", a/=i);
for(max=alatt=felett=0; max<i; ++max){
double b=pop();
if(b<a) ++alatt;
else if(b>a) ++felett; }
printf("Az tlag alattiak szma: %8d.\n"
"Az tlag felettiek szma:%8d.\n",
alatt, felett); }
e Vigyzat: a plda a PELDA20.Cbl s a DVEREM.Cbl kpzett
prodzsekt segtsgvel futtathat csak!
8.1.2 lettartam (lifetime, duration)
Az lettartam attribtum szorosan ktdik a trolsi osztlyhoz, s az a
peridus a program vgrehajtsa kzben, mg a deklarlt azonosthoz ob-
jektumot allokl a fordt a memriban, azaz amg a vltoz vagy a fgg-
vny ltezik. Megklnbztethetnk
- fordtsi idej s
- futsidej objektumokat.
A vltozk pldul a tpusoktl s a tpusdefinciktl eltren futs
idben vals, alloklt memrival rendelkeznek. Hrom fajta lettartam
van.
8.1.2.1 Statikus (static vagy extern) lettartam
Az ilyen objektumokhoz a memria hozzrendels a program futsnak
megkezddsekor trtnik meg, s az allokci marad is a program befeje-
zdsig. Minden fggvny statikus lettartam objektum brhol is defi-
niljk ket. Az sszes fjl hatskr vltoz is ilyen lettartam. Ms
vltozk a static vagy az extern trolsi osztly specifiktorok explicit
megadsval tehetk ilyenn. A statikus lettartam objektumok minden
memria bitje (a fggvnyektl eltekintve) zrus kezdrtket kap explicit
inicializls hinyban.
C programnyelv 141
e Ne keverjk ssze a statikus lettartamot a fjl (globlis) hatskr-
rel, ui. egy objektum loklis hatskrrel is lehet statikus lettartam, csak
deklarcijban meg kell adni expliciten a static trolsi osztly kulcs-
szt.
8.1.2.2 Loklis (auto vagy register) lettartam
Ezek az objektumok akkor jnnek ltre (allokci) a veremben vagy re-
giszterben, amikor a vezrls belp az ket magba foglal blokkba vagy
fggvnybe, s meg is semmislnek (deallokci), mihelyt kikerl a vezr-
ls innt. A loklis lettartam objektumok loklis hatskrek, s mindig
explicit inicializlsra szorulnak, hisz ltrejvetelk helyn szemt van.
Ne feledjk, hogy a fggvnyparamterek is loklis lettartamak!
Az auto trolsi osztly specifiktor deklarciban val kirsval expli-
citen loklis lettartamv tehetnk egy vltozt, de erre tbbnyire semmi
szksg sincs, mert blokkon vagy fggvnyen bell deklarlt vltozk
esetben az alaprtelmezett trolsi osztly amgy is az auto.
A loklis lettartam objektum egyben loklis hatskr is, hisz az t
magba foglal blokkon kvl nem ltezik. A dolog megfordtsa nem
igaz, mert loklis hatskr objektum is lehet statikus lettartam.
Ha egy regiszterben is elfr vltozt (pldul char, short, stb. tpust)
expliciten register trolsi osztlynak deklarlunk, akkor a fordt ehhez
hozzrti automatikusan az auto kulcsszt is, hisz a vltozkat csak addig
tudja regiszterben elhelyezni, mg azok el nem fogynak, s ezutn a verem-
ben allokl nekik memrit.
8.1.2.3 Dinamikus lettartam
Az ilyen objektumokhoz a Cben pldul a malloc fggvnnyel rendel-
hetnk memrit a heapen, amit aztn a freevel felszabadthatunk. Mi-
utn a memriaalloklshoz knyvtri fggvnyeket hasznlunk, s ezek
nem rszei a nyelvnek, gy a Cben nincs is dinamikus lettartam igaz-
bl.
A C++ban ugyanezen funkcikra megalkottk a new s a delete
opertorokat, melyek rszei a nyelvnek.
8.1.3 Hatskr (scope) s lthatsg (visibility)
A hatskr rvnyessgi tartomnynak is nevezik az azonost azon
tulajdonsga, hogy vele az objektumot a program mely rszbl rhetjk
142 OBJEKTUMOK S FGGVNYEK
el. Ez is a deklarci helytl s magtl a deklarcitl fgg attribtum.
Felsoroljuk ket!
8.1.3.1 Blokk (loklis, bels) hatskr
A deklarcis ponttl indul s a deklarcit magba foglal blokk vg-
ig tart. Az ilyen hatskr vltozkat szoks bels vltozknak is nevezni.
Loklis hatskrek a fggvnyek formlis paramterei is, s hatskrk a
fggvnydefinci teljes blokkja. A blokk hatskr azonost hatskre
minden a krdses blokkba begyazott blokkra is kiterjed. Pldul:
int fv(float lo){
double szamar; /* A loklis hatskr itt indul. */
/* . . . */
long double oszver; /* Az oszver hatskre innt
(deklarcis pont) indul s a fggvnydefinci
vgig tart. Szval nem lehetne a szamar vltozt
az oszver-rel inicializlni. */
if (/* felttel */){
char lodarazs = l; /* A lodarazs hatskre
ez a bels blokk. */
/* . . . */
} /* A lodarazs hatskrnek vge. */
/* . . . */
} /* A lo, szamar s oszver hatskrnek vge. */
8.1.3.2 Fggvny hatskr
Ilyen hatskre csak az utasts cmknek van. Az utasts cmke ezen
az alapon: fggvnyen belli egyedi azonost, melyet egy olyan vgre-
hajthat utasts el kell rni kettspontot kzbeszrva, melyre el kv-
nunk gazni. Pldul:
int fv(float k){
int i, j;
/* . . . */
cimke: utasts;
/* . . . */
if (/* felttel */) goto cimke;
/* . . . */ }
8.1.3.3 Fggvny prototpus hatskr
Ilyen hatskre a prototpusban deklarlt paramterlista azonostinak
van, melyek teht a fggvny prototpussal be is fejezdnek. Pldul a k-
vetkez fggvnydefinciban az i, j s k azonostknak van fggvny
prototpus hatskre:
void fv(int i, char j, float k);
C programnyelv 143
Az i, j s k ilyen megadsnak semmi rtelme sincs. Az azonostk
teljesen feleslegesek. A
void fv(int, char, float);
ugyanennyit mondott volna. Fggvny prototpusban neveket akkor cl-
szer hasznlni, ha azok lernak valamit. Pldul a
double KamatOsszeg(double osszeg, double kamat, int evek);
az osszeg kamatos kamatt kzli evek vre.
8.1.3.4 Fjl (globlis, kls) hatskr
A minden fggvny testn kvl deklarlt azonostk rendelkeznek ilyen
hatskrrel, mely a deklarcis pontban indul s a forrsfjl vgig tart.
Ez persze azt is jelenti, hogy a fjl hatskr objektumok a deklarcis
pontjuktl kezdve minden fggvnybl s blokkbl elrhetk. A globlis
vltozkat szoks kls vltozknak is nevezni. Pldul a g1, g2 s g3
vltozk ilyenek:
int g1 = 7; /* g1 fjl hatskre innt indul. */
void main(void) { /* ... */ }
float g2; /* g2 fjl hatskre itt startol. */
void fv1(void) { /* ... */ }
double g3 = .52E-40;/* Itt kezddik g3 hatskre */
void fv2(void) { /* ... */ }
/* Itt van vge a forrsfjlnak s a g1, g2 s g3 kls
vltozk hatskrnek. */
8.1.3.5 Lthatsg
A forrskd azon rgija egy azonostra vonatkozan, melyben leglis
mdon elrhet az azonosthoz kapcsolt objektum. A hatskr s a ltha-
tsg tbbnyire fedik egymst, de bizonyos krlmnyek kztt egy ob-
jektum ideiglenesen rejtett vlhat egy msik ugyanilyen nev azonost
feltnse miatt. A rejtett objektum tovbbra is ltezik, de egyszeren az
azonostjval hivatkozva nem rhet el, mg a msik ugyanilyen nev
azonost hatskre le nem jr. Pldul:
{ int i; char c = z; /* Az i s c hatskre indul. */
i = 3; /* int i-t rtk el. */
/* . . . */
{ double i = 3.5e3; /* double i hatskre itt kezd-
dik, s elrejti int i-t, br */
/* . . . */ /* hatskre nem sznik meg. */
c = A; /* char c lthat s hatskre
itt is tart. */
} /* A double i hatskrnek vge */
/* int i s c hatskrben s lthatk. */
++i;
144 OBJEKTUMOK S FGGVNYEK
} /* int i s char c hatskrnek vge. */
8.1.3.6 Nvterlet (name space)
Az a hatskr, melyen bell az azonostnak egyedinek kell lennie.
Ms nvterleten konfliktus nlkl ltezhet ugyanilyen azonost, a ford-
t kpes megklnbztetni ket.
A nvterlet fajtkat a STRUKTRK S UNIK trgyalsa utn
tisztzzuk majd!
8.1.4 Kapcsolds (linkage)
A kapcsoldst csatolsnak is nevezik. A vgrehajthat program gy jn
ltre, hogy
- tbb, klnll fordtsi egysget fordtunk,
- aztn a kapcsol-szerkesztvel (linker) sszekapcsoltatjuk az ered-
mny .OBJ fjlokat, ms meglv trgymodulokat s a knyvtrak-
bl szrmaz trgykdokat.
Problma akkor van, ha ugyanaz az azonost klnbz hatskrkkel
deklarlt - pldul ms-ms forrsfjlban - vagy ugyanolyan hatskrrel
egynl tbbszr is deklarlt.
A kapcsol-szerkeszts az a folyamat, mely az azonost minden elfor-
dulst korrekt mdon egy bizonyos objektumhoz vagy fggvnyhez ren-
deli. E folyamat sorn minden azonost kap egy kapcsoldsi attribtu-
mot a kvetkez lehetsgesek kzl:
- kls (external) kapcsolds,
- bels (internal) kapcsolds vagy
- nincs (no) kapcsolds.
Ezt az attribtumot a deklarcik elhelyezsvel s formjval, ill. a t-
rolsi osztly (static vagy extern) explicit vagy implicit megadsval ha-
trozzuk meg.
Lssuk a klnfle kapcsoldsok rszleteit!
A kls kapcsolds azonost minden pldnya ugyanazt az objektu-
mot vagy fggvnyt reprezentlja a programot alkot minden forrsfjl-
ban s knyvtrban. A bels kapcsolds azonost ugyanazt az objektu-
mot vagy fggvnyt jelenti egy s csak egy fordtsi egysgben (forrsfjl-
ban). A bels kapcsolds azonostk a fordtsi egysgre, a kls kap-
C programnyelv 145
csoldsak viszont az egsz programra egyediek. A kls s bels kap-
csoldsi szablyok a kvetkezk:
- Brmely objektum vagy fggvnyazonost fjl hatskrrel bels
kapcsolds, ha deklarcijban expliciten elrtk a static trolsi
osztlyt.
- Az explicit mdon extern trolsi osztly objektum vagy fgg-
vnyazonostnak ugyanaz a kapcsoldsa, mint brmely lthat fjl
hatskr deklarcijnak. Ha nincs ilyen lthat fjl hatskr dek-
larci, akkor az azonost kls kapcsolds lesz.
- Ha fggvnyt explicit trolsi osztly specifiktor nlkl deklarl-
nak, akkor kapcsoldsa olyan lesz, mintha kirtk volna az extern
kulcsszt.
- Ha fjl hatskr objektumazonostt deklarlnak trolsi osztly
specifiktor nlkl, akkor az azonost kls kapcsolds lesz.
e A fordtsi egysg bels kapcsoldsnak deklarlt azonostjhoz
egy s csak egy kls definci adhat meg. A kls definci olyan kls
deklarci, mely az objektumhoz vagy fggvnyhez memrit is rendel.
Ha kls kapcsolds azonostt hasznlunk kifejezsben (a sizeof ope-
randustl eltekintve), akkor az azonostnak csak egyetlen kls defin-
cija ltezhet az egsz programban.
A kapcsolds nlkli azonost egyedi entits. Ha a blokkban az azo-
nost deklarcija nem vonja maga utn az extern trolsi osztly speci-
fiktort, akkor az azonostnak nincs kapcsoldsa, s egyedi a fggvny-
re. A kvetkez azonostknak nincs kapcsoldsa:
- Brmely nem objektum vagy fggvnynvvel deklarlt azonost-
nak. Ilyen pldul a tpusdefincis (typedef) azonost.
- A fggvnyparamtereknek.
- Explicit extern trolsi osztly specifiktor nlkl deklarlt, blokk
hatskr objektumazonostknak.
8.2 Fggvnyek
A fggvnyekkel kapcsolatos alapfogalmakat tisztztuk mr a BEVE-
ZETS S ALAPISMERETEK szakaszban, de fussunk t rajtuk mg
egyszer!
A fggvnynek kell legyen defincija, s lehetnek deklarcii. A fgg-
vny defincija deklarcinak is minsl, ha megelzi a forrsszvegben
146 OBJEKTUMOK S FGGVNYEK
a fggvnyhvst. A fggvnydefinciban van a fggvny teste, azaz az a
kd, amit a fggvny meghvsakor vgrehajt a processzor.
A fggvnydefinci rgzti a fggvny nevt, visszatrsi rtknek t-
pust, trolsi osztlyt s ms attribtumait. Ha a fggvnydefinciban a
formlis paramterek tpust, sorrendjt s szmt is elrjk, fggvny
prototpusnak nevezzk. A fggvny deklarcijnak meg kell elznie a
fggvnyhvst, melyben aktulis paramterek vannak. Ez az oka annak,
hogy a forrsfjlban a szabvny fggvnyek hvsa eltt behozzuk a pro-
totpusaikat tartalmaz fejfjlokat (#include).
A fggvnyparamtereket argumentumoknak is szoktk nevezni.
A fggvnyeket a forrsfjlokban szoks definilni, vagy elrefordtott
knyvtrakbl lehet bekapcsoltatni (linkage). Egy fggvny a programban
tbbszr is deklarlhat, feltve, hogy a deklarcik kompatibilisek. A
fggvny prototpusok hasznlata a C-ben ajnlatos (a C++ meg gy is
ktelezen elrja), mert a fordtt gy ltjuk el elegend informcival
ahhoz, hogy ellenrizhesse
- a fggvny nevt (a fggvnyek adott azonost),
- a paramterek szmt, tpust s sorrendjt (tpuskonverzi lehets-
ges), valamint
- a fggvny ltal visszaadott rtk tpust (tpuskonverzi itt is
lehet).
A fggvnyhvs truhzza a vezrlst a hv fggvnybl a hvott fgg-
vnybe gy, hogy az aktulis paramtereket is ha vannak tadja rtk
szerint. Ha a hvott fggvnyben return utastsra r a vgrehajts, akkor
visszakapja a vezrlst a hv fggvny egy visszaadott rtkkel egytt
(ha megadtak ilyet!).
e Egy fggvnyre a programban csak egyetlen definci lehetsges. A
deklarcik (prototpusok) ktelesek egyezni a defincival.
8.2.1 Fggvnydefinci
A fggvnydefinci specifiklja a fggvny nevt, a formlis paramte-
rek tpust, sorrendjt s szmt, valamint a visszatrsi rtk tpust, a
fggvny trolsi osztlyt s ms attribtumait. A fggvnydefinciban
van a fggvny teste is, azaz a hasznlatos loklis vltozk deklarcija,
s a fggvny tevkenysgt megszab utastsok. A szintaktika:
C programnyelv 147
fordtsi-egysg:
kls-deklarci
fordtsi-egysg kls-deklarci
kls-deklarci:
fggvnydefinci
deklarci
fggvnydefinci:
<deklarci-specifiktorok> deklartor <deklarcilista> sszetett-utasts
deklartor:
<mutat> direkt-deklartor
direkt-deklartor:
direkt-deklartor(paramter-tpus-lista)
direkt-deklartor(<azonostlista>)
deklarcilista:
deklarci
deklarcilista deklarci
A kls-deklarcik hatskre a fordtsi egysg vgig tart. A kls-
deklarci szintaktikja egyezik a tbbi deklarcival, de fggvnyeket
csak ezen a szinten szabad definilni, azaz:
e tilos fggvnyben msik fggvnyt definilni!
A deklarci s az azonostlista defincik a TPUSOK S
KONSTANSOK szakasz Deklarci fejezetben megtallhatk. A muta-
tkat a kvetkez szakasz tartalmazza.
A fggvnydefincibeli sszetett-utasts a fggvny teste, mely tartal-
mazza a hasznlatos loklis vltozk deklarciit, a klsleg deklarlt t-
telekre val hivatkozsokat, s a fggvny tevkenysgt megvalst uta-
stsokat.
Az opcionlis deklarci-specifiktorok s a ktelezen megadand
deklartor egytt rgztik a fggvny visszatrsi rtk tpust s nevt. A
deklartor termszetesen fggvnydeklartor, azaz a fggvnynv s az t
kvet zrjel pr. Az els direkt-deklartor(paramter-tpus-lista) alak a
fggvny j (modern) stlus defincijt teszi lehetv. A deklartor
szintaktikban szerepl direkt-deklartor a modern stlus szerint a defini-
ls alatt ll fggvny nevt rgzti, s a kerek zrjelben ll param-
ter-tpus-lista specifiklja az sszes paramter tpust. Ilyen deklartor tu-
lajdonkppen a fggvny prototpus is. Pldul:
char fv(int i, double d){
/* . . . */ }
A msodik direkt-deklartor(<azonostlista>) forma a rgi stlus defi-
nci:
char fv(i, d)
148 OBJEKTUMOK S FGGVNYEK
int i;
double d; {
/* . . . */ }
A tovbbiakban csak az j stlus fggvnydefincival foglalkozunk, s
nem emlegetjk tovbb a rgit!
deklarci-specifiktorok:
trolsi-osztly-specifiktor <deklarci-specifiktorok>
tpusspecifiktor <deklarci-specifiktorok>
tpusmdost <deklarci-specifiktorok>
tpusmdost: (a kvetkezk egyike!)
const
volatile
A trolsi-osztly-specifiktorok s a tpuspecifiktorok defincii a
TPUSOK S KONSTANSOK szakasz Deklarci fejezetben megte-
kinthetk!
8.2.1.1 Trolsi osztly
Fggvnydefinciban kt trolsi osztly kulcssz hasznlhat: az ex-
tern vagy a static. A fggvnyek alaprtelmezs szerint extern trolsi
osztlyak, azaz normlisan a program minden forrsfjljbl elrhetk,
de explicit mdon is deklarlhatk externnek.
Ha a fggvny deklarcija tartalmazza az extern trolsi osztly speci-
fiktort, akkor az azonostnak ugyanaz a kapcsoldsa, mint brmely lt-
hat, fjl hatskr ugyanilyen kls deklarcinak, s ugyanazt a fgg-
vnyt jelenti. Ha nincs ilyen fjl hatskr, lthat deklarci, akkor az
azonost kls kapcsolds. A fjl hatskr, trolsi osztly specifik-
tor nlkli azonost mindig kls kapcsolds. A kls kapcsolds azt
jelenti, hogy az azonost minden pldnya ugyanarra a fggvnyre hivat-
kozik, azaz az explicit vagy implicit mdon extern trolsi osztly fgg-
vny a program minden forrsfjljban lthat.
e Az externtl klnbz trolsi osztly, blokk hatskr fgg-
vnydeklarci hibt generl.
A fggvny explicit mdon deklarlhat azonban static-nek is, amikor
is a r val hivatkozst az t tartalmaz forrsfjlra korltozzuk, azaz a
fggvny bels kapcsolds, s csak a defincijt tartalmaz forrsmo-
dulban lthat. Az ilyen fggvny legels bekvetkez deklarcijban
(ha van ilyen!) s defincijban is ki kell rni a static kulcsszt.
Akrmilyen esetrl is van sz azonban, a fggvny mindig a defincis
vagy deklarcis pontjtl a forrsfjl vgig lthat magtl.
C programnyelv 149
8.2.1.2 A visszatrsi rtk tpusa
A visszatrsi rtk tpusa meghatrozza a fggvny ltal szolgltatott
rtk mrett s tpust. A fggvnydefinci metanyelvi meghatrozsa
az elhagyhat deklarci-specifiktorokkal kezddik. Ezek kzl tulaj-
donkppen a tpusspecifiktor felel meg a visszatrsi rtk tpusnak.
E meghatrozsokat nzegetve lthat, hogy a visszaadott rtk tpusa
brmi lehet eltekintve a tmbtl s a fggvnytl (az ezekre mutat muta-
t persze megengedett). Lehet valamilyen aritmetikai tpus, lehet void
(nincs visszaadott rtk), de el is hagyhat, amikor is alaprtelmezs az
int. Lehet struktra, uni vagy mutat is, melyekrl majd ksbbi szaka-
szokban lesz sz.
A fggvnydefinciban elrt visszaadott rtk tpusnak egyeznie kell
a programban brhol elfordul, e fggvnyre vonatkoz deklarcikban
megadott visszatrsi rtk tpussal. A meghvott fggvny akkor ad
vissza rtket a hv fggvnynek a hvs pontjra, ha a processzor kifeje-
zssel elltott return utastst hajt vgre. A fordt termszetesen elbb
kirtkeli a kifejezst, s konvertlja ha szksges az rtket a vissza-
adott rtk tpusra. A void visszatrsnek deklarlt fggvnybeli kifeje-
zssel elltott return figyelmeztet zenetet eredmnyez, s a fordt nem
rtkeli ki a kifejezst.
e Vigyzat! A fggvny tpusa nem azonos a visszatrsi rtk tpus-
val. A fggvny tpusban ezen kvl benne van mg a paramterek
- szma,
- tpusai s
- sorrendje is!
8.2.1.3 Formlis paramterdeklarcik
A fggvnydefinci metanyelvi meghatrozsbl kvetkezen a mo-
dern stlus direkt-deklartor(paramter-tpus-lista) alakban, a zrjelben
ll paramter-tpus-lista vesszvel elvlasztott paramterdeklarcik so-
rozata.
paramter-tpus-lista:
paramterlista
paramterlista, ...
paramterlista:
paramterdeklarci
paramterlista, paramterdeklarci
150 OBJEKTUMOK S FGGVNYEK
paramterdeklarci:
deklarci-specifiktor deklartor
deklarci-specifiktor <absztrakt-deklartor>
absztrakt-deklartor:
mutat
<mutat><direkt-absztrakt-deklartor>
direkt-absztrakt-deklartor:
(absztrakt-deklartor)
<direkt-absztrakt-deklartor>[<konstans-kifejezs>]
<direkt-absztrakt-deklartor>(<paramter-tpus-lista>)
A paramterdeklarci nem tartalmazhat ms trolsi-osztly-specifi-
ktort, mint a registert. A deklarci-specifiktor szintaktikabeli tpus-
specifiktor elhagyhat, ha a tpus int, s egybknt megadjk a register
trolsi osztly specifiktort. sszestve a formlis paramterlista egy ele-
mnek formja a kvetkez:
<register> tpusspecifiktor <deklartor>
e Az autonak deklarlt fggvnyparamter fordtsi hiba!
A C szablyai szerint a paramter lehet brmilyen aritmetikai tpus. Le-
het akr tmb is, de fggvny nem (az erre mutat mutat persze megen-
gedett). A paramter lehet termszetesen struktra, uni vagy mutat is,
melyekrl majd ksbbi szakaszokban lesz sz. A paramterlista lehet
void is, ami nincs paramter jelents.
A formlis paramterazonostk nem definilhatk t a fggvny
testnek kls blokkjban, csak egy ebbe begyazott bels blokkban, azaz
a formlis paramterek hatskre s lettartama a fggvnytest teljes leg-
kls blokkja. Az egyetlen rjuk is leglisan alkalmazhat trolsi osztly
specifiktor a register. Pldul:
int f1(register int i){/* ... */}/* Igny regiszteres
paramter tadsra. */
A const s a volatile mdostk hasznlhatk a formlis paramter dek-
lartorokkal. Pldul a
void f0(double p1, const char s[]){
/* . . . */
s[0]=A;
/* Szintaktikai hiba. */}
constnak deklarlt formlis paramtere nem lehet balrtk a fggvny
testben, mert hibazenetet okoz.
Ha nincs tadand paramter, akkor a paramterlista helyre a definci-
ban s a prototpusban a void kulcssz rand:
int f2(void){/* ... */} /* Nincs paramter. */
C programnyelv 151
Ha van legalbb egy formlis paramter a listban, akkor az ,...-ra is
vgzdhet:
int f3(char str[], ...){/* ... */}/* Vltoz szm vagy
tpus paramter. */
Az ilyen fggvny hvsban legalbb annyi aktulis paramtert meg kell
adni, mint amennyi formlis paramter a ,... eltt van, de termszetesen
ezeken tl tovbbi aktulis paramterek is elrhatk. A ,... eltti param-
terek tpusnak s sorrendjnek ugyanannak kell lennie a fggvny dekla-
rciiban (ha egyltaln vannak), mint a defincijban.
A fggvny aktulis paramterei tpusnak az esetleges szoksos kon-
verzi utn hozzrendels kompatibilisnek kell lennie a megfelel form-
lis paramter tpusokra. A ,... helyn ll aktulis paramtereket nem el-
lenrzi a fordt.
Az STGARG.H fejfjlban vannak olyan makrk, melyek segtik a
felhasznli, vltoz szm paramteres fggvnyek megalkotst! A t-
mra visszatrnk mg a MUTATK kapcsn!
8.2.1.4 A fggvny teste
A fggvny teste elhagyhat deklarcis s vgrehajthat utastsokbl
ll sszetett utasts, azaz az a kd, amit a fggvny meghvsakor vg-
rehajt a processzor.
sszetett-utasts:
{<deklarcilista> <utastslista>}
A fggvnytestben deklarlt vltozk loklisak, auto trolsi osztly-
ak, ha msknt nem specifikltk ket. Ezek a loklis vltozk akkor jn-
nek ltre, mikor a fggvnyt meghvjk, s loklis inicializlst hajt rajtuk
vgre a fordt. A fggvny meghvsakor a vezrlst a fggvnytest els
vgrehajthat utastsa kapja meg. void-ot visszaad fggvny blokkjban
aztn a vgrehajts addig folytatdik, mg return utasts nem kvetkezik
vagy a fggvny blokkjt zr }-re nem kerl a vezrls. Ezutn a hvsi
ponttl folytatdik a program vgrehajtsa.
A valamit szolgltat fggvnyben viszont lennie kell legalbb egy
return kifejezs utastsnak, s visszatrs eltt r is kell, hogy kerljn a
vezrls. A visszaadott rtk meghatrozatlan, ha a processzor nem hajt
vgre return utastst, vagy a return utastshoz nem tartozott kifejezs.
A kifejezs rtkt szksges esetben hozzrendelsi konverzinak veti
al a fordt, ha a visszaadand rtk tpusa eltr a kifejezstl.
152 OBJEKTUMOK S FGGVNYEK
8.2.2 Fggvny prototpusok
A fggvnydeklarci megelzi a defincit, s specifiklja a fggvny
nevt, a visszatrsi rtk tpust, trolsi osztlyt s a fggvny ms att-
ribtumait. A fggvnydeklarci akkor vlik prototpuss, ha benne
megadjk az elvrt paramterek tpust, sorrendjt s szmt is.
sszegezve: a fggvny prototpus csak abban klnbzik a defin-
citl, hogy a fggvny teste helyn egy ; van.
` Cben ugyan nem ktelez, de tegyk magunknak ktelezv a
fggvny prototpus hasznlatt, mert ez a kvetkezket rgzti:
- A fggvny inttl klnbz visszatrsi rtk tpust.
- Ezt az informcit a fordt a fggvnyhvsok paramtertpus s
szm megfeleltets ellenrzsn tl konverzik elvgzsre is fel-
hasznlja.
A paramterek konvertlt tpusa hatrozza meg azokat az aktulis para-
mter rtkeket, melyek msolatait a fggvnyhvs teszi ki a verembe.
Gondoljuk csak meg, hogyha az intknt kirakott aktulis paramter rt-
ket a fggvny doublenek tekinten, akkor nem csak e paramter flrer-
telmezsrl van sz, hanem az sszes tbbi ezt kvet is "elcsszik"!
A prototpussal a fordt nem csak a visszatrsi rtk s a paramterek
tpusegyezst tudja ellenrizni, hanem az attribtumokat is. Pldul a
static trolsi osztly prototpus hatsra a fggvnydefincinak is
ilyennek kell lennie.
A fggvnydefinci mdostinak egyeznie kell a fggvnydeklar-
cik mdostival!
A prototpusbeli azonost hatskre a prototpus. Prototpus adhat vl-
toz szm paramterre, ill. akkor is, ha paramter egyltaln nincs.
A komplett paramterdeklarcik (int a) vegythetk az absztrakt-dek-
lartorokkal (int) ugyanabban a deklarciban. Pldul:
int add(int a, int);
A paramter tpusnak deklarlsakor szksg lehet az adattpus nev-
nek feltntetsre, mely a tpusnv segtsgvel rhet el. A tpusnv az
objektum olyan deklarcija, melybl hinyzik az azonost. A metanyel-
vi lers:
tpusnv:
tpusspecifiktor-lista<absztrakt-deklartor>
C programnyelv 153
absztrakt-deklartor:
mutat
<mutat><direkt-absztrakt-deklartor>
direkt-absztrakt-deklartor:
(absztrakt-deklartor)
<direkt-absztrakt-deklartor>[<konstans-kifejezs>]
<direkt-absztrakt-deklartor>(<paramter-tpus-lista>)
Az absztrakt-deklartorban mindig megllapthat az a hely, ahol az azo-
nostnak lennie kellene, ha a konstrukci deklarcin belli deklartor
lenne. A kvetkez tpusnevek jelentse: int, 10 elem int tmb s nem
meghatrozott elemszm int tmb:
int, int [10], int []
Lssuk be, hogy a fggvny prototpus a kd dokumentlsra is j!
Szinte rgtn tudunk mindent a fggvnyrl:
void strcopy(char cel[], char forras[]);
A
<tpus> fv(void);
olyan fggvny prototpusa, melynek nincsenek paramterei.
Norml esetben a fggvny prototpus olyan fggvnyt deklarl, mely
fix szm paramtert fogad. Lehetsg van azonban vltoz szm vagy
tpus paramter tadsra is. Az ilyen fggvny prototpus paramterlis-
tja ...-tal vgzdik:
<tpus> fv(int, long, ...);
A fixen megadott paramtereket fordtsi idben ellenrzi a fordt, s a
vltoz szm vagy tpus paramtert viszont a fggvny hvsakor tpus-
ellenrzs nlkl adja t a veremben.
Az STGARG.H fejfjlban vannak olyan makrk, melyek segtik a
felhasznli, vltoz szm paramteres fggvnyek megalkotst! A t-
mra visszatrnk mg a MUTATK kapcsn!
Nzznk nhny plda prototpust!
int f(); /* int-et visszaad fggvny, melynek
paramtereirl nincs informcink. */
int f1(void); /* Olyan int-et szolgltat fggvny,
melynek nincsenek paramterei. */
int f2(int, long);/* int-et visszaad fggvny, mely
elsnek egy int, s aztn egy long
paramtert fogad. */
int pascal f3(void);/*Paramter nlkli, int-et
szolgltat pascal fggvny. */
int printf(const char [], ...);/* int-tel visszatr
fggvny egy fix, s nem meghatrozott
154 OBJEKTUMOK S FGGVNYEK
szm vagy tpus paramterrel. */
Ksztsnk programot, mely megllaptja az .HH.NN alak ka-
rakterlncrl, hogy rvnyes dtume!
/* PELDA21.C: Dtumellenrzs. */
#include <stdio.h>
#include <stdlib.h> /* Az atoi miatt! */
#define INP 11 /* Az input puffer mrete. */
#include <ctype.h> /* Az isdigit miatt! */
int getline(char [], int);
int datume(const char []);
void main(void){
char s[INP+1]; /* Az input puffer. */
printf("Dtumellenrzs.\nBefejezs res sorral!\n");
while( printf("\nDtum (.HH.NN)? "),
getline(s,INP)>0)
if(datume(s)) printf("rvnyes!\n");
else printf("rvnytelen!\n"); }
Az .HH.NN alak dtum rvnyessgt a krdsre logikai rtk
vlaszt szolgltat, int datume(const char s[]) fggvny segtsgvel r-
demes eldntetni.
Kvetelmnyek:
- A karakterlncnak 10 hosszsgnak kell lennie.
- A hnapot az vtl elvlaszt karakter nem lehet numerikus, s azo-
nosnak kell lennie a hnapot a naptl elvlasztval.
- A lncbeli sszes tbbi karakter csak numerikus lehet.
- Csak 0001 s 9999 kztti vet fogadunk el.
- Az vszm alapjn megllaptjuk a februr hnap napszmt.
- A hnapszm csak 01 s 12 kztti lehet.
- A napszm megengedett rtke 01 s a hnapszm maximlis nap-
szma kztt van.
int datume(const char s[]){
static int honap[ ] =
{ 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int i, ho;
if(!s[10] && !isdigit(s[4]) && s[4]==s[7]){
for(i=0; i<10; ++i){
if(i==4||i==7) ++i;
if(!isdigit(s[i])) return 0; }
if((i=atoi(s))>=1){
honap[2]=28+(!(i%4)&&i%100 || !(i%400));
if((ho=10*(s[5]-'0')+s[6]-'0')>=1&&ho<=12&&
(i=10*(s[8]-'0')+s[9]-'0')>=1&&
C programnyelv 155
i<=honap[ho]) return 1; } }
return 0; }
Megoldand feladatok:
Vltoztasson gy az int datume(const char s[]) fggvnyen, hogy akr
egyjegy is lehessen:
- az vszm, majd
- a hnap s a napszm is!
int indexe(char s[], char t[]) s int indexu(char s[], char t[]) fggv-
nyek ksztendk, melyek meghatrozzk s visszaadjk a t paramter ka-
rakterlnc s karaktertmbbeli els, illetve utols elfordulsnak indext!
Prblja is ki egy rvid tesztprogrammal a fggvnyeket! {INDEXEU.C}
rjon olyan szoftvert, mely megkeresi egy prba karakterlnc sszes el-
fordulst a szabvny bemenetrl rkez sorokban!
8.2.3 Fggvnyek hvsa s paramterkonverzik
A fggvnyt aktulis paramterekkel hvjuk meg. Ezek sorrendjt s t-
pust a formlis paramterek hatrozzk meg. A fggvnyhvs opertor
alakja
uttag-kifejezs(<kifejezslista>)
kifejezslista:
hozzrendels-kifejezs
kifejezslista, hozzrendels-kifejezs
, ahol az uttag-kifejezs egy fggvny neve, vagy fggvnycmm rtke-
li ki a fordt, s ezt hvja meg. A zrjelben ll, elhagyhat kifejezslista
tagjait egymstl vessz vlasztja el, s tudjuk, hogy ezek azok az aktu-
lis paramter kifejezsek, melyek rtkmsolatait a hvott fggvny kapja
meg.
e Ha az uttag-kifejezs nem deklarlt azonost az aktulis hatskr-
ben, akkor a fordt implicit mdon a fggvnyhvs blokkjban
extern int azonost();
mdon tekinti deklarltnak.
A fggvnyhvs kifejezs rtke s tpusa a fggvny visszatrsi rt-
ke s tpusa. Az rtket vissza nem ad fggvnyt voidnak kell deklarl-
ni, ill. void rand a kifejezslista helyre, ha a fggvnynek nincs para-
mtere.
156 OBJEKTUMOK S FGGVNYEK
e Ha a prototpus paramterlistja void, akkor a fordt zrus param-
tert vr mind a fggvnyhvsban, mind a definciban. E szably megsr-
tse hibazenethez vezet.
e Az aktulis paramter kifejezslista kirtkelsi sorrendje nem meg-
hatrozott, pontosabban a konkrt fordttl fgg. A ms paramter mel-
lkhatstl fgg paramter rtke gy ugyancsak definilatlan. A fgg-
vnyhvs opertor egyedl azt garantlja, hogy a fordt a paramterlista
minden mellkhatst realizlja, mieltt a vezrlst a fggvnyre adn.
e Fggvnynek tmb s fggvny nem adhat t paramterknt, de
ezekre mutat mutat persze igen.
A paramter lehet aritmetikai tpus. Lehet struktra, uni vagy mutat
is, de ezekkel ksbbi szakaszokban foglalkozunk. A paramter tadsa
rtk szerinti, azaz a fggvny az rtkmsolatot kapja meg, melyet ter-
mszetesen el is ronthat a hvs helyn lev eredeti rtkre gyakorolt br-
mifle hats nlkl. Szval a fggvny mdosthatja a formlis paramte-
rek rtkt.
A fordt kirtkeli a fggvnyhvs kifejezslistjt, s szoksos kon-
verzit (egszellptetst) hajt vgre minden aktulis paramteren. Ez
azt jelenti, hogy a float rtkbl double lesz, a char s a short rtkbl
int, valamint az unsigned char s az unsigned short rtkbl unsigned
int vlik.
Ha van vonatkoz deklarci a fggvnyhvs eltt, de nincs benne in-
formci a paramterekre, akkor a fordt ksz az aktulis paramterek r-
tkvel.
Ha deklarltak elzetesen fggvny prototpust, akkor az eredmny ak-
tulis paramter tpust hasonltja a fordt a prototpusbeli megfelel pa-
ramter tpusval. Ha nem egyeznek, akkor a deklarlt formlis paramter
tpusra alaktja az aktulis paramter rtkt hozzrendelsi konverzi-
val, s jra a szoksos konverzi kvetkezik. A nem egyezs msik lehet-
sges vgkifejlete diagnosztikai zenet.
A hvsnl a kifejezslistabeli paramterek szmnak egyeznie kell a
fggvny prototpus vagy definci paramtereinek szmval. Kivtel az,
ha a prototpus ,...-tal vgzdik, amikor is a fordt a fix paramtereket az
elz pontban ismertetett mdon kezeli, s a ,... helyn lev aktulis para-
mtereket gy manipullja, mintha nem deklarltak volna fggvny proto-
tpust.
C programnyelv 157
8.2.4 Nem szabvnyos mdostk, hvsi konvenci
A deklarci deklartorlistjban a megismert szabvnyos alaptpuso-
kon, tpusmdostkon kvl minden fordtprogram rendelkezik mg
specilis clokat szolgl, a deklarlt objektum tulajdonsgait vltoztat,
nem szabvnyos mdostkkal is.
Az olvasnak javasoljuk, hogy nzzen utna ezeknek a programfej-
leszt rendszere segtsgben!
Teljessgre val trekvs nlkl felsorolunk itt nhny ilyen mdostt,
melyek kzl egyikmsik ki is zrja egymst!
mdost:
cdecl
pascal
interrupt
fastcall
stdcall
export
near
far
huge
Az els nhny mdost a fggvny hvsi konvencijt hatrozza
meg. Az alaprtelmezett hvsi konvenci C programokra cdecl.
Tekintsnk csak bele brmelyik szabvnyos fejfjlba, mindegyik
fggvny prototpusa elejn ott talljuk a cdecl mdostt!
Ha egy azonost esetben biztostani kvnjuk a kis-nagybet rzkeny-
sget, az alhzs karakter (_) nv el kerlst, ill. fggvnynvnl a pa-
ramterek jobbrl balra val verembe rakst, akkor az azonost deklar-
cijban rjuk ki expliciten a cdecl mdostt! Ez a hvsi konvenci biz-
tostja az igazi vltoz paramteres fggvnyek rst, hisz a vermet a
hv fggvnynek kell rendbe tennie.
Vltoz paramteres fggvnyek rsval majd a MUTATK kap-
csn foglalkozunk, most vegynk egy pldt az elmondottakra!
void fv(short s, int i, double d){}
void main(void){
static short s=5;
static int i=7;
static float f=3.14f;
/* . . . */
fv(s, i, f);
/* . . . */ }
158 OBJEKTUMOK S FGGVNYEK
Hvs A hvott fggvny Verem helyrellts
A paramter rtkeket
jobbrl balra haladva
rakja ki a verembe a
kd a konverzik el-
vgzse utn, majd
meghvja az fvt. A
veremmutat SP!
SP+12: 3.14 (double)
SP+8: 7 (int)
SP+4: 5 (int)
SP: visszatrsi cm
Hozzfr az rtkm-
solatokhoz a verem-
ben, de kzben az SP
nem vltozik meg.
Elvgzi a dolgt a
fggvny, s visszatr
a hv fggvnybe.
SP+8: 3.14 (double)
SP+4: 7 (int)
SP: 5 (int)
A hv fggvnyben 16
tal cskkenti a kd az
SP rtkt.
SP:
Vltoz szm para-
mter tadsa knnyen
lehetsges, hiszen ha
mg a hvs helyn sem
ismerjk az aktulis pa-
ramterek szmt, akkor
nem fogjuk megtudni
sohasem.
Az stdcall kisnagybet rzkeny. Standard hvsi konvencival kell
hvni a WIN32 API fggvnyek tbbsgt. A fastcall mdost azt jelenti,
hogy a fordt regiszterekben igyekszik tadni a paramtereket a hvott
fggvnynek a verembe raks sorrendjben. Ha nincs elg regiszter, akkor
a maradkot vermen t juttatja el a hvhoz. A visszatrsi rtk tadsa
ugyancsak regiszteren t trtnik, ha lehetsges stb.
A cdecl nagyobb vgrehajthat kdot generl, mint a fastcall, vagy az
stdcall, hisz a hvsit, vermet rendbe tev kdnak kell kvetnie a hv
fggvnyben. Mr mondottuk, hogy cdecl az alaprtelmezett hvsi kon-
venci C programokra. A mainnek mindenkpp cdecl-nek kell lennie,
mert az indt kd C hvsi konvencik szerint hvja meg.
A legtbb programfejleszt rendszerben bellthat az ltalnosan
hasznland hvsi konvenci, mely mindig fellbrlhat a kvnt mdo-
st explicit kirsval.
Ha pldul nem cdecl hvsi sorrend programban szeretnnk hasznlni
a printf fggvnyt, akkor:
extern cdecl printf(const char format[], ...);
void egeszekki(int i, int j, int k);
void cdecl main(void){ egeszekki( 1, 4, 9); }
void egeszekki(int i, int j, int k){
printf(%d %d %d\n, i, j, k); }
mdon kell dolgozni. Elismerjk, hogy #include <stdio.h>-t alkalmazva
semmi szksg sincs az
extern cdecl printf(const char format[], ...);
kirsra, hisz ez a prototpus amgy is benne van az STDIO.H fejfjlban.
C programnyelv 159
8.2.5 Rekurzv fggvnyhvs
Brmely fggvny meghvhatja nmagt kzvetlenl vagy kzvetve. A
rekurzv fggvnyhvsoknak egyedl a verem mrete szab hatrt.
A verem mrett befolysol, pldul kapcsol-szerkeszt opci,
belltst megtudhatjuk programfejleszt rendszernk segtsgbl.
Valahnyszor meghvjk a fggvnyt, j trol terletet allokl a rend-
szer az aktulis paramtereknek, az auto s a nem regiszterben trolt reg-
ister vltozknak. A paramterek s a loklis vltozk teht a veremben
jnnek ltre a fggvnybe val belpskor, s megsznnek, mihelyt a ve-
zrls tvozik a fggvnybl, azaz:
- valahnyszor meghvjuk a fggvnyt, sajt loklis vltoz s aktu-
lis paramter msolatokkal rendelkezik, ami
- biztostja, hogy a fggvny baj nlkl meghvhatja nmagt kz-
vetlenl vagy kzvetetten (ms fggvnyeken t).
A rekurzvan hvott fggvnyek tulajdonkppen dolgozhatnak dina-
mikusan kezelt, globlis vagy static trolsi osztly loklis vltozkkal
is. Azt azonban ilyenkor ne felejtsk el, hogy a fggvny sszes hvspl-
dnya ugyanazt a vltozt ri el.
Ha az lenne a feladatunk, hogy rjunk egy olyan fggvnyt, mely megha-
trozza n faktorilist, akkor valsznleg gy jrnnk el:
long double faktor(int n){
long double N = n<1? 1.L: n;
while(--n) N*=n;
return N; }
Lthat, hogy a long double brzolsi formt vlasztottuk, hogy a
lehet legnagyobb szm faktorilist legynk kpesek meghatrozni a C
szmbrzolsi lehetsgeivel. Az algoritmus az egynl kisebb egszek
faktorilist egynek tekinti, s az ismtelt szorzst fordtott sorrendben
hajtja vgre, vagyis: N=n*(n1)*(n2)**3*2*1.
rjunk egy rvid keretprogramot, mely bekri azt az 1 s MAXN (ford-
tsi idben vltoztathat) kzti egsz szmot, melynek megllapttatjuk a
faktorilist!
/* PELDA22.C: Rekurzis pldaprogram: faktorilis. */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAX 40 /* Az input puffer mrete. */
#define MAXN 40 /* A max. szm. */
long double faktor(int n);
160 OBJEKTUMOK S FGGVNYEK
int getline(char s[],int n);
/* A decimlis szmjegyek szma maximlisan: */
#define HSZ sizeof(int)/sizeof(short)*5
int egesze(char s[]);
void main(void){
int n=0; /* A szm. */
char sor[MAX+1]; /* A bemeneti puffer. */
printf("\n\t\tEgsz szm faktorilisa.\n");
while(n<1||n>MAXN){
printf("\nMelyik egsz faktorilist szmtjuk
(1-%d)? ",MAXN);
getline(sor,MAX);
if(egesze(sor)) n=atoi(sor); }
printf("%d! = %-20.0Lf \n",n, faktor(n)); }
Ismeretes, hogyha a formtumspecifikciban elrjuk a mezsz-
lessget, akkor a kijelzs alaprtelmezs szerint jobbra igaztott. A balra
igazts a szlessg el rt jellel rhet el.
A faktorilisszmts rekurzv megoldsa a kvetkez lehetne:
long double faktor(int n){
if(n <= 1) return 1.L;
else return (n*faktor(n-1)); }
Lthat, hogy a faktor egynl nem nagyobb n paramter esetn
azonnal long double 1gyel tr vissza. Ms esetben viszont meghvja n-
magt nnl eggyel kisebb paramterrel. Az itt visszakapott rtket meg-
szorozza nnel, s ez lesz a majdani visszaadott rtke. Nzzk meg asz-
tali teszttel, hogyan trtnnek a hvsok, feltve, hogy a main a 0s hvsi
szint faktor(5)tel indult!
n: 5 4 3 2 1
Hvsi szint:
1 2 3 4 5 +
Hvs: faktor(4) faktor(3) faktor(2) faktor(1) +
Visszatrsi szint: 0
1 2 3 4
Visszatrsi rtk: 120 24 6 2 1
Cserljk ki a keretprogramban a faktor fggvnyt a rekurzv vlto-
zatra, s prbljuk ki!
Megoldand feladatok:
rja meg a kvetkez fggvnyek rekurzv vltozatai:
- void strrv(char s[]), mely megfordtja a sajt helyn a paramter
karakterlncot. {STRRV.C}
- Az itoa fggvny, mely az int paramtert karakterlncc konvertl-
ja, s elhelyezi az ugyancsak paramter karaktertmbben.
C programnyelv 161
9 MUTATK
A nyelvben a mutatknak kt fajtja van:
- (adat) objektumra mutat mutatk s
- fggvny re (kd) mutat mutatk.
Brmilyenek is legyenek, a mutatk memria cmek trolsra szolglnak.
Elbb az adatmutatkkal fogunk foglalkozni. A mutat mindaddig, mg
errl kln nem szlunk, jelentsen adatmutatt!
A tpus tpus mutat tpus tpus objektum cmt tartalmazhatja. A mu-
tatk unsigned egszek, de sajt szablyaik s korltozsaik vannak a
hozzrendelsre, a konverzira s az aritmetikra.
Miutn a mutat is skalr objektum, ltezik a mutatra mutat mutat
is. A mutatk azonban tbbnyire ms skalr vagy void objektumokra (vl-
tozkra), ill. aggregtumokra (tmbkre, struktrkra s unikra) mutat-
nak.
9.1 Mutatdeklarcik
A mutatdeklarci elnevezi a mutat vltozt, s rgzti annak az ob-
jektumnak a tpust, melyre ez a vltoz mutathat.
Teht csak egy bizonyos tpusra (elredefiniltra - belertve a void-ot is
- vagy felhasznl definiltra) mutat mutat deklarlhat
tpus *azonost;
mdon, amikor is az azonost nev mutat tpus tpus objektum cmt
veheti fel.
Vegyk szre, hogy tpus * az azonost tpusa! Pldul az
int *imut;
int *fv(char *);
deklarcik alapjn: imut int tpus objektumra mutat mutat, fv int t-
pus cmet visszaad, s egy char objektumra mutat paramtert fogad
fggvny.
Ha a definilt mutat statikus lettartam, akkor tiszta zrus kezdrt-
ket kap implicit mdon. A fordt tiszta zrus cmen nem helyez el sem
objektumot, sem fggvnyt, s gy a zrus cm (az n. NULL mutat ) spe-
cilis felhasznls. Magt a NULL mutatt a szabvnyos fejfjlokban
(pldul az STDIO.Hban) definilja a nyelv.
162 MUTATK
Brmilyen tpus mutat NULL-hoz hasonltsa mindenkor helyes ered-
mnyre vezet, ill. brmilyen tpus mutathoz hozzrendelhetjk a NULL
mutatt.
Ha loklis a definilt mutat, akkor a definci hatsra a fordt akkora
memriaterletet foglal, hogy abban egy cm elfrjen, de a lefoglalt bjtok
szemetet tartalmaznak.
e Az ilyen mutat teht nem hasznlhat mindaddig rtelmesen
semmire, mg valamilyen mdon rvnyes cmet nem tesznk bele.
Hogy lehet elrni valamilyen objektum cmt?
9.1.1 Cm opertor (&)
Egyoperandusos, magas priorits mvelet, mely definci szerint:
& eltag-kifejezs
alak. Az eltag-kifejezs operandusnak vagy fggvnyt kell kijellnie,
vagy olyan objektumot elr balrtknek kell lennie, mely nem register
trolsi osztly, s nem bitmez. Lehet teht pldul vltoz, vagy tm-
belem.
A bitmezkkel a struktrk kapcsn ksbb foglalkozunk!
Ha az operandus tpusa tpus, akkor az eredmny mutat a tpus tpusra.
Cm csak mutatnak adhat t. A lehetsges mdszerek szerint vagy
hozzrendeljk, vagy inicializtort alkalmazunk a deklarciban. Pldul:
tpus val1, val2, *ptr = &val1; /* A ptr mutatnak van
kezdrtke, de a vele elrt objektumnak nincs. */
ptr = &val2; /* Hozzrendeljk a msik vltoz
cmt a mutathoz. */
Ha
T1 *ptr1; T2 *ptr2;
klnbz tpus objektumokra mutat mutatk, akkor a
ptr1 = ptr2;
vagy a
ptr2 = ptr1;
hozzrendels figyelmeztet vagy hibazenetet okoz. Explicit tpusmdo-
st szerkezetet alkalmazva viszont gond nlkl mehet a dolog:
ptr1 = (T1 *) ptr2;
ptr2 = (T2 *) ptr1;
C programnyelv 163
e Teljesen illeglis dolog azonban a fggvny s az adatmutatk
sszerendelse!
Ha a mutat mr rvnyes cmet tartalmaz, az
9.1.2 Indirekci opertor (*)
segtsgvel elrhetjk a mutatott rtket. Az indirekci opertor ugyan-
csak egyoperandusos, magas priorits mvelet, melynek defincija:
* eltag-kifejezs
Az eltag-kifejezs operandusnak tpus tpusra mutat mutatnak kell
lennie, ahol a tpus brmilyen lehet. Az indirekci eredmnye az eltag-
kifejezs mutatta cmen lev, tpus tpus rtk. Az indirekci eredmnye
egyben balrtk is. Pldul:
tpus t1, t2;
/* . . . */
tpus *ptr = &t1; /* A mutatt inicializltuk is. */
*ptr = t2; /* Ekvivalens a t1 = t2-vel. */
e Ne ksreljk meg azonban a cm opertorral kifejezs vagy kons-
tans cmt ellltani, vagy indirekci opertort nem cmm kirtkelhet
operandus el odarni,
ptr = &(t1 + 6); /* HIBS */
ptr = &8; /* HIBS */
t2 = *t1; /* HIBS */
mert hibazenethez jutunk!
Meghatrozatlan az indirekci eredmnye akkor is, ha a mutat:
- NULL mutat,
- vagy olyan loklis objektum cmt tartalmazza, mely a program
adott pontjn nem lthat,
- vagy a vgrehajthat program ltal nem hasznlhat cmet tartal-
maz.
` A mutatkkal vgzett munka sorn kl-szablyunk szerint: ahol
objektum lehet egy kifejezsben, ott kerek zrjelbe tve az indirekci
mvelett kveten ilyen tpus objektumra mutat mutat is llhat. Ha:
tpus val, *ptr = &val;
, akkor ahol val szerepelhet egy kifejezsben, ott llhat (*ptr) is.
Pldul:
int y, val=0, *ptr = &val;
164 MUTATK
/* . . . */
printf("val cme (%p) van ptr-ben (%p).\n", &val, ptr);
y = *ptr + 3; /* y = val +3 tulajdonkppen. */
y = sqrt((double) ptr);/* y = sqrt(val). */
*ptr += 6; /* val += 6. */
(*ptr)++; /* Zrjel nlkl a ptr-t
inkrementltatnnk. */
printf("val rtke %d.\n", val);
printf("A ptr cmen lev rtk %d.\n", *ptr); }
Fedezzk fel, hogy a cm, vagy mutattartalom kijelzshez haszn-
latos tpuskarakter a p a formtumspecifikciban, s hogy a printf para-
mterlistjban cm rtk kifejezs is llhat, persze akr indirekcival is!
e Vigyzzunk nagyon! Ha egy vltoznak nem adunk kezdrtket, s
mondjuk, hozzadogatjuk egy tmb elemeit, akkor a vgeredmny zld-
sg, s a dolog szarvashiba. Ha mutatnak nem adunk kezdrtket, s a
benne lev szemtre, mint cmre, runk ki rtket indirekcival, akkor
az dupln szarvashiba. A szemttel, mint cmmel valahol pancsolunk
a memriban, s fellrjuk valami egszen ms objektum rtkt, s a hiba
is egszen ms helyen jelentkezik, mint ahol elkvettk.
9.1.3 void mutat
Kln kell emltennk a
void *vptr;
mutat tpust, ami nem semmire, hanem meghatrozatlan tpusra mutat
mutat. Explicit tpusmdost szerkezet alkalmazsa nlkl brmilyen t-
pus mutat vagy cm hozzrendelhet a void mutathoz. A dolog meg-
fordtva is igaz, azaz brmilyen tpus mutathoz hozzrendelhetnk void
mutatt. Pldul:
tpus ertek, *ptr=&ertek;
vptr=ptr; /* OK */
vptr=&ertek; /* OK */
ptr=vptr; /* OK */
e void mutatval egyetlen mvelet nem vgezhet csak: az indirekci-
, hisz meghatrozatlan a tpus, s a fordt nem tudja, hogy hny bjtot
s milyen rtelmezsben kell elrnie.
ertek=*vptr; /* HIBS */
9.1.4 Statikus s loklis cmek
Miutn a statikus lettartam objektum minden bitjt zrusra inicializl-
ja alaprtelmezs szerint a fordt, de cme nem vltozik, kezdrtke le-
het akr statikus mutatnak is. Az auto vltozk cme viszont nem lehet
C programnyelv 165
statikus inicializtor, hisz a cm msms lehet a blokk klnbz vgre-
hajtsakor.
int GLOBALIS;
int fv(void){
int LOKALIS;
static int *slp = &LOKALIS; /* HIBS. */
static int *sgp = &GLOBALIS; /* OK. */
register int *rlp = &LOKALIS;/* OK. */
long a = 1000000l, *lp = &a;/* a kezdrtke
1000000 s lp kezdetben r mutat. */
register int *pi = 0; /* pi regiszteres mutat
rtke NULL. */
const int i = 26; /* Ez az egyetlen hely, ahol
i rtket kaphatott. */
/* . . . */ }
9.1.5 Mutatdeklartorok
deklartor:
<mutat>direkt-deklartor
direkt-deklartor:
azonost
(deklartor)
direkt-deklartor [<konstans-kifejezs>]
direkt-deklartor (paramter-tpus-lista)
direkt-deklartor (<azonostlista>)
mutat:
*<tpusmdost-lista>
*<tpusmdost-lista>mutat
tpusmdost-lista:
tpusmdost
tpusmdost-lista tpusmdost
tpusmdost: (a kvetkezk egyike!)
const
volatile
A deklartorok szerkezetileg az indirekcihoz, a fggvnyhez s a
tmbkifejezshez hasonltanak, s csoportostsuk is azonos. A deklartort
kvetheti egyenlsgjel utn inicializtor, de mindig deklarci-specifi-
ktorok elzik meg. A deklarci-specifiktorok trolsi-osztly-specifi-
ktor s tpusspecifiktor sorozat tulajdonkpp, s igazbl nem csak
egyetlen deklartorra vonatkoznak, hanem ezek listjra.
Megkrjk az olvast, hogy lapozzon vissza egy pillanatra a TPU-
SOK S KONSTANSOK Deklarci fejezethez!
A direkt-deklartor definci els lehetsge szerint a deklartor egy
egyedi azonostt deklarl, melyre a trolsi osztly egy az egyben vonat-
166 MUTATK
kozik, de a tpus rtelmezse kicsit fgghet a deklartor alakjtl is. A
deklartor teht egyedi azonostt hatroz meg, s mikor az azonost fel-
tnik egy tle tpusban nem eltr kifejezsben, akkor a vele elnevezett
objektum rtkt eredmnyezi.
sszestve, s csak a lnyeget tekintve a deklarci
tpus deklartor
alak. Ezt nem vltoztatja meg az sem, ha a direkt-deklartor msodik al-
ternatvjt tekintjk, mert a zrjelezs nem mdostja a tpust, csak
sszetettebb deklartorok ktsre lehet hatssal.
A fggvnydeklartorokat mr trgyaltuk, s a tmbdeklartorokra
mg ebben a szakaszban visszatrnk!
A mutatdeklarci gy mdosul:
tpus * <tpusmdost-lista> deklartor
, ahol a * <tpusmdost-list>val vltoztatott tpus a deklartor tpusa.
A * opertor utn ll tpusmdost magra a mutatra, s nem a vele
megcmezhet objektumra vonatkozik.
Foglalkozzunk pldul a const mdostval!
9.1.6 Konstans mutat
Mind a mutat, mind a mutatott objektum deklarlhat const-nak. Br-
mely const-nak deklarlt valami ugyebr nem vltoztathatja meg az r-
tkt. Az sem mehet persze, hogy olyan mutatt kreljunk, mellyel meg-
srthetnnk a const objektum rtk megvltoztathatatlansgt.
int i;
int *pi; /* pi int objektumra mutat
inicializlatlan mutat. */
int * const cp = &i; /* cp konstans mutat int-re, de
amire mutat, az nem konstans. */
const int ci = 7; /* ci 7 rtk konstans int. */
const int *pci; /* pci konstans int-re mutat. A
mutat teht nem konstans. */
const int * const cpc = &ci; /* cpc konstans int-re
mutat konstans mutat. */
A kvetkez hozzrendelsek leglisak:
i = ci; /* const int hozzrendelse int-hez. */
*cp = ci;/* const int hozzrendelse konstans mutat
mutatta nem konstans int-hez. */
++pci; /* const int-re mutat mutat inkrementlsa.*/
pci = cpc;/*Konstans int-re mutat, konstans mutat hoz-
zrendelse const int-re mutat mutathoz.*/
C programnyelv 167
A kvetkez hozzrendelsek illeglisak:
ci = 0; /* rtkhozzrendelsi ksrlet const int-hez.*/
ci--; /* const int dekrementlsi ksrlete. */
*pci = 3;/* rtkadsi ksrlet a const int-re mutat
mutatval megcmzett objektumnak. */
cp = &ci;/* rtkadsi ksrlet konstans mutatnak. */
cpc++; /* Konstans mutat inkrementlsi ksrlete. */
pi = pci;/* Ha ez a hozzrendels leglis lenne, akkor
*pi = ... mdon mdosthatnnk azt a const
int-et, amire pci mutat. */
Ahhoz, hogy a kgy megharapja a farkt kell, hogy const objek-
tumra mutat mutatt ne lehessen hozzrendelni nem const-ra mutat
mutathoz. Ha ez menne, akkor ugyan kerl ton, de a mutatott const
rtk megvltoztathat lenne.
9.2 Mutatk s fggvnyparamterek
Eddig kiemelten csak az n. rtk szerinti paramter tadssal foglal-
koztunk a fggvnyhvs kapcsn. Ezt gy interpretlhatjuk, hogy a ford-
t fggvnyhvskor az aktulis paramterek (esetleg tpuskonverzin t-
esett) rtkt helyezi el, pldul a veremben, s a meghvott fggvny nem
az aktulis paramterek rtkhez, hanem annak csak egy msolathoz fr
hozz.
Rvidsge s tallsga miatt tvesszk [4] vonatkoz mintapld-
jt!
Tegyk fel, hogy a programoz azt a feladatot kapta, hogy rjon olyan
fggvnyt, mely megcserli kt, int paramtere rtkt!
csere(paramter1, paramter2);
mdon hvhat els ksrlete a kvetkez volt:
void csere(int x, int y){
int seged = x;
x = y;
y = seged; }
Bartunk prblkozsa professzionlis olyan rtelemben, hogy gon-
dolt arra, hogy a csere vgrehajtshoz szksge van segdvltozra, de a
fggvnyt hv programjban meglepetten tapasztalta, hogy semmifle
rtkcsere nem trtnt.
A csere tulajdonkppen lezajlott az aktulis paramterek msolatain
a veremben, de ennek semmilyen hatsa sincs az aktulis paramterek
hv programbeli rtkeire. A fggvny visszatrse miatt a veremmutat
is visszallt a hvs eltti rtkre, s gy a verembeli, felcserlt rtkmso-
latok is elrhetetlenn vltak.
168 MUTATK
A megolds a cm szerinti paramter tadsban rejlik, azaz a csere fgg-
vnyt
csere(&paramter1, &paramter2);
mdon kell meghvni, s a fggvnydefinci pedig gy mdosul:
void csere(int *x, int *y){
int seged = *x;
*x = *y;
*y = seged; }
A rutin most az aktulis paramterek cmmsolatait kapja meg a ve-
remben, s az indirekci mvelett alkalmazva gy az aktulis paramterek
rtkn dolgozik.
Megoldand feladatok:
rja t a kvetkez, formai rvnyessget ellenrz fggvnyeket gy,
hogy igaz (1) visszatrsi rtk mellett a vizsglt karakterlnc konvertlt
eredmnyt is szolgltassk! Ha az rvnyessgellenrzs viszont hibval
zrul, akkor a visszaadott hamis (0) rtken kvl semmifle rtkvlto-
zst nem okozhat a fggvny.
- A PELDA18.Cben definilt egesze legyen int egesze(const char
s[], int *ertek) prototpus! {PELDA18Y.C}
- A PELDA20.Cbeli lebege talaktand int lebege(const char s[],
double *ertek)k!
- A PELDA21.C datume fggvnybl vljk int datume(const
char s[], int *ev, int *ho, int *nap)!
9.3 Tmbk s mutatk
A BEVEZETS S ALAPISMERETEK szakaszban kln feje-
zet foglalkozik a tmbkkel, s az Inicializls rsz trgyalja az egydi-
menzis tmbk kezdrtk adst is.
Tmb ltesthet aritmetikai tpusokbl, de definilhat
- mutatbl (kln ksbbi fejezet),
- struktrbl s unibl (a kvetkez szakasz), valamint
- tmbbl (nll fejezete van a tbbdimenzis tmbknek).
e Brmilyen tpusbl is hozzuk azonban ltre a(z egydimenzis) tm-
bt, a tpusnak teljesnek kell lennie. Nem lehet flig ksz, nem teljesen
definilt, felhasznli tpusbl tmbt krelni.
C programnyelv 169
A tmbk s a mutatk kztt nagyon szoros kapcsolat van. Ha ki-
fejezs, vagy annak rsze tpus tmbje, akkor a (rsz)kifejezs rtkt a
tmb els elemt megcmz, konstans mutatv alaktja a fordt, s a
(rsz)kifejezs tpusa tpus * const lesz. Nem hajtja vgre a fordt ezt a
konverzit, ha a (rsz)kifejezs cm opertor (&), ++, , vagy a pont (.)
szelekcis opertor, vagy a sizeof operandusa, vagy hozzrendelsi mve-
let bal oldaln ll.
A . opertorral a kvetkez szakasz foglalkozik. Elemezzk az el-
z bekezdsben mondottakat egy plda tkrben!
Legyen a kvetkez tmb s mutat!
#define MERET 20 /* Tmbmret. */
/* . . . */
float tomb[MERET], *pt;
/* . . . */
A tmbt a fordt, mondjuk, a 100as cmtl kezdve helyezte el a me-
mriban. Egy tmbelem helyfoglalsa sizeof(tomb[0]) sizeof(float)
4, ltalnossgban sizeof(tpus). Az elemek
tomb[0], tomb[1], ..., tomb[MERET - 1]
sorrendben, nvekv cmeken helyezkednek el a trban. Teht a tomb[0]
a 100as, a tomb[1] a 104es, a tomb[2] a 108as s gy tovbb cmen
van. A 180as memriacm mr nem tartozik a tmbhz.
Ha valamilyen kifejezsben megltja a fordt a tomb azonostt, akkor
rgtn helyettesteni fogja a float * const 100as cmmel. Teht, ha a ptt
fel kvnjuk tlteni tomb kezdcmvel, akkor nem kell ilyen
pt = &tomb[0];
hosszadalmasan kdolni, tkletesen elg a
pt = tomb;
9.3.1 Index opertor
A MVELETEK S KIFEJEZSEK szakasz elejn definilt uttag-
kifejezs msodik alternatvja az
uttag-kifejezs[kifejezs]
az indexel opertor. Nevezik ezt indexes vltoznak is, vagyis minden-
kppen hivatkozs ez a tmb egy meghatrozott elemre.
A szablyok szerint az uttag-kifejezs s a kifejezs kzl az egyik-
nek mutatnak, a msiknak egsz tpusnak kell lennie, s hatsukra a
fordt a
170 MUTATK
*((uttag-kifejezs) + (kifejezs))
mveletet valstja meg. A fordt alkalmazza a kvetkez fejezetben tr-
gyalt konverzis szablyokat a + mveletre s a tmbre. Ha az uttag-ki-
fejezs a tmb s a kifejezs az egsz tpus, akkor a konstrukci a tmb
kifejezsedik elemre hivatkozik.
Mi van a tpussal? A kls zrjel prban mg mutat tpus (tpus *)
van, s ezen hajtja vgre a fordt az indirekcit. Teht az eredmny tpust
a mutat dnti el.
Vegyk a tomb[6] indexes vltozt! A mondottak szerint ebbl
*((tomb) + (6))
lesz, ami nem 6, hanem 6nak, mint indexnek, a hozzadst jelenti a
tomb kezdcmhez, azaz:
*((float *)100 + 6*sizeof(float))
Az sszeads elvgzse utn
*((float *)124)
, ami az indirekci vgrehajtsa utn a tomb 6os index elemt eredm-
nyezi.
A + kommutatv mvelet, gy az indexels is az. Egydimenzis tm-
bkre a kvetkez ngy kifejezs teljesen ekvivalens feltve, hogy p mu-
tat s i egsz:
p[i] i[p] *(p + i) *(i + p)
Folytassuk az index opertor ismertetsnek megkezdse eltt elkezdett
gondolatmenetet, azaz a pt mutat legyen tomb rtk!
pt = tomb;
Ilyenkor:
*pt tomb[0],
*(pt + 1) tomb[1]
s ltalban
*(pt + i) tomb[i].
Vegyk szre, hogy a pt-re szksg sincs a tmbelemek s cmeik
ellltshoz, hisz:
tomb[i] *(tomb + i)
s
&tomb[i] tomb + i.
C programnyelv 171
e Fontos klnbsg van azonban a tomb s a pt kztt. A pt mutat
vltoz. A tomb pedig mutat konstans. Ebbl kvetkezleg nem megen-
gedettek a kvetkezk:
tomb = pt; /* Mintha 3=i-t rtunk volna fel. */
tomb++; /* Mint 3++. */
pt = &tomb; /* Mintha &3-at akarnnk ellltani. */
A mutat vltozra termszetesen megengedettek ezek a mveletek:
pt = tomb;
pt++;
Ha pt mutat, akkor azt kifejezs indexelheti a tanultak szerint, azaz
pt[i] *(pt + i)
Meg kell emlteni mg, hogy amikor egy fggvnyt tmbazonost
aktulis paramterrel hvtunk meg, akkor is cm szerinti paramter tads
trtnt, azaz a fggvny a tmb kezdcm konstans msolatt kapta meg,
pldul, a veremben. Ez a cmmsolat aztn persze a fggvnyben mr
nem konstans, el is lehet rontani stb.
Vegyk szre, hogy a cm szerinti paramter tadst szinte minden
pldnkban, mr a kezdetek ta hasznljuk! Eddig a fggvnyparamter
tmbt mindig
tpus azonost[]
alakban adtuk meg, de legjabb ismereteink szerint a
tpus * azonost
forma hasznland, hisz ez egyrtelmen mutatja, hogy a paramter muta-
t. A fggvny testn bell ettl fggetlenl szabadon dnthet a progra-
moz, hogy
- tmbknt,
- mutatknt, vagy
- vegyesen
kezeli az ilyen paramtert.
` A gpi kd utastsok operandusai tbbnyire memria cmek. Eb-
bl kvetkezleg minl inkbb mutatkat hasznlva rjuk meg programja-
inkat, annl kzelebb kerlnk a gpi kdhoz, s ez ltal annl gyorsabb
lesz a szoftvernk.
rjuk t ennek szellemben a PELDA21.C datume fggvnyt!
int datume(const char *s){
172 MUTATK
static int honap[ ] =
{ 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int i, ho;
if(!*(s+10) && !isdigit(*(s+4)) && *(s+4)==*(s+7)){
for(i=0; i<10; ++i){
if(i==4||i==7) ++i;
if(!isdigit(*(s+i))) return 0; }
if((i=atoi(s))>=1){
*(honap+2)=28+(!(i%4)&&i%100 || !(i%400));
if((ho=atoi(&s[5])>=1&&ho<=12&&(i=atoi(&s[8])>=1&&
i<=*(honap+ho)) return 1; } }
return 0; }
Lssuk be, hogy az ilyen fajta fggvny trsnak, amikor s[i]bl *
(s+i)t csinlgatunk, semmi rtelme sincs, hisz ezt a fordt magtl is
megteszi. Az talakts egyetlen elnye, hogy a formlis paramter jobban
szemllteti, hogy const karakterlncra mutat, ill. az szre vehet, hogy az
atoi fggvnyt nem csak a karaktertmb kezdetvel szabad meghvni.
Foglalkozzunk mg egy kicsit a tmbdeklartorokkal!
9.3.2 Tmbdeklartor s nem teljes tpus tmb
A Mutatdeklartorok fejezetben a direkt-deklartor definci harma-
dik vltozata
direkt-deklartor [<konstans-kifejezs>]
a tmbdeklartor. A tmbdeklarci teht
tpus deklartor [<konstans-kifejezs>]<={inicializtorlista<,>}>
, ahol az elhagyhat konstans-kifejezsnek egsz tpusnak s zrusnl na-
gyobb rtknek kell lennie, s ez a tmb mrete. Ez a TPUSOK S
KONSTANSOK szakasz Deklarci fejezetben rottakon tl tovbbi
korltozsokat r a konstans kifejezsre, hogy egsz tpusnak kell lennie.
Operandusai ebben az esetben csak egsz, felsorols, karakteres s lebe-
gpontos llandk lehetnek, de a lebegpontos konstanst explicit tpus-
konverzival egssz kell alaktani. Operandus lehet mg a sizeof oper-
tor is, aminek operandusra termszetesen nincsenek ilyen korltozsok.
Tudjuk, hogyha elmarad a tmbmret, akkor a fordt az inicializtor-
lista elemszmnak megllaptsval rgzti azt, s a tpus gy vlik teljes-
s. Megadott mret tmb esetben a lista inicializtorainak szma nem
haladhatja meg a tmb elemeinek szmt. Ha az inicializtorok keveseb-
ben vannak a tmbmretnl, akkor a magasabb index, fennmarad tmb-
elemek zrus kezdrtket kapnak. Tudjuk azt is, hogy tmb inicializto-
rai csak lland kifejezsek lehetnek.
C programnyelv 173
e Ne felejtkezznk meg rla, hogy ugyan a karaktertmb inicializ-
torlistja karakterlnc konstans, de az elbb felsorolt korltozsok ugyan-
gy vonatkoznak r is! Vagyis rgztett mret tmb esetn a karakterlnc
hossza sem haladhatja meg a mretet. Ha a lnchossz s a tmbmret e-
gyezik, nem lesz lnczr zrus a karaktertmb vgn.
Ha a tmbdeklarcibl hinyzik a tmbmret s inicializtorlista sincs,
akkor a deklarci nem teljes tpus tmbt hatroz meg. Lssuk a lehet-
sges eseteket!
- Ez csak elzetes deklarci s a tmb mrett majd egy ksbbi de-
finci rgzti. Pldul:
float t[];
/* . . . */
float t[20];
- Ez csak elzetes deklarci s a tmbmretet egy ksbbi inicializ-
torlists deklarci tisztzza. Pldul:
char lanc[];
/* . . . */
char lanc[]=Ne tudd ki!;
Termszetesen az egytt tmbmretes s inicializtorlists definil
deklarci is megengedett!
- A globlis tmbt nem ebben a forrsmodulban definiltk, itt csak
egyszeren a r val hivatkozs eltt deklarltk. Pldul:
extern double dtomb[];
Persze a dtomb mrett valamilyen mdon ebben a forrsmodulban
is ismernnk kell!
- A tmb fggvny paramtere. Pldul:
void fv(float t[], int n) { /* . . . */ }
A tmb mrett valahonnan a fggvnyben is tudni kne! Pldul
gy, hogy tovbbi paramterknt tadjk neki.
9.4 Mutataritmetika s konverzi
A mutat vagy cmaritmetika az inkrementlsra, a dekrementlsra, az
sszeadsra, a kivonsra s az sszehasonltsra szortkozik. A tpus tpu-
s objektumra mutat mutatn vgrehajtott aritmetikai mveletek auto-
matikusan figyelembe veszik a tpus mrett, azaz az objektum trolsra
elhasznlt bjtok szmt. A mutataritmetika ezen kvl felttelezi, hogy
a mutat a tpus tpus objektumok tmbjre mutat, azaz pldul:
174 MUTATK
int i = 6;
float ftomb[50], *fptr = ftomb;
esetn
fptr += i;
hatsra az fptr-beli cm
sizeof(float)*i
-vel (ltalnossgban sizeof(tpus)*egsz-szel) n, azaz a plda szerint
ftomb[6]-ra mutat.
Ha ptr1 a tpus tpus tmb msodik s ptr2 a tizedik elemre mutat,
akkor a kt mutat klnbsge
ptr2 - ptr1 8.
Figyeljk meg, hogy a mutatkhoz indexrtket adunk hozz vagy
vonunk ki belle s a mutatk klnbsge is indexrtk! Igazbl a kt
mutat klnbsge ptrdiff_t tpus egsz indexklnbsg. A ptrdiff_t az
STDDEF.H fejfjlban definilt, s tbbnyire signed int.
9.4.1 sszeads, kivons, inkrementls s dekrementls
- sszeads egyik operandusa lehet mutat, ha a msik operandus
egsz tpus. Az eredmny ilyenkor a cmaritmetika szablyait k-
vet mutat, azaz olyan cm, mely egsz*sizeof(tpus)sal nagyobb,
mint az eredeti. A tpus a mutat ltal mutatott nem void tpus.
- Kivonsnl az els operandus lehet valamilyen objektumra mutat
mutat, ha ilyenkor a msodik egsz tpus. Az eredmny most is a
mutataritmetika szablyait kvet mutat, azaz olyan cm, mely
egsz*sizeof(tpus)sal kisebb, mint az eredeti. A tpus a mutat l-
tal mutatott nem void tpus.
- Kivonsnl mindkt operandus lehet ugyanazon objektum rszeire
mutat mutat. Az eredmny az elz kt pont szellemben a muta-
taritmetika szablyainak megfelel egsz (indexklnbsg). Az
egsz tpusa a szabvny STDDEF.H fejfjlban definilt ptrdiff_t
(signed int).
Ha az operandus mutat, akkor az eggyel nvelsben (++) vagy csk-
kentsben () a cmaritmetika szablyai rvnyesek, azaz az eredmny
mutat a kvetkez, vagy a megelz elemre fog mutatni.
e Ha p mutat a tmb utols elemre mutat, akkor a ++p mg leglis
rtk: a tmb utols utni elemnek cme, de minden ezutn kvetkez
C programnyelv 175
mutatnvels definilatlan eredmnyre vezet. Hasonl problma van ak-
kor is, ha p a tmb kezdetre mutat. Ilyenkor a mutatcskkents - mr a
--p is - definilatlan eredmnyt okoz.
Vegyk szre, hogy az egsz mutataritmetiknak csak akkor van
rtelme, ha a mutatk egyazon tmb elemeire mutatnak!
e Minden nem tmbre alkalmazott cmaritmetikai mvelet eredmnye
definilatlan. Ugyanez mondhat el akkor is, ha a tmbre alkalmazott mu-
tataritmetikai mvelet eredmnye a tmb legels eleme el, vagy a legu-
tols utnin tlra mutat.
9.4.2 Relcik
A kvetkez operandus tpuskombincik hasznlhatk relcikban:
- Mindkt operandus lehet ugyanazon tpus objektumra mutat mu-
tat, amikor is a kt objektum memria cmnek sszehasonltsrl
lesz sz.
- A mutat sszehasonlts csak egyazon objektum rszeire definilt,
s a mutatk nem tartalmazhatnak ezen objektumon kvlre irnyul
cmet sem egyetlen kivtellel, tmb esetn megengedett az utols
ltez elem utni cmre val hivatkozs. Ha a mutatk tmb ele-
mekre hivatkoznak, akkor az sszehasonlts az indexek sszeha-
sonltsval ekvivalens. A nagyobb index elem cme magasabb.
- Az egyenlsgi relcikat hasznlva a mutat hasonlthat a kons-
tans 0 rtkhez, azaz a NULL mutathoz is.
- Csak az egyenlsgi relcik esetben a mutat hasonlthat a kons-
tans, 0 rtk, egsz kifejezshez, vagy voidra mutat mutathoz.
Ha mindkt mutat NULL mutat, akkor egyenlk.
9.4.3 Feltteles kifejezs
Ha a K1 ? K2 : K3ban K2, K3 egyikemsika mutat, akkor a K2 vagy
K3 operandusok tpustl fgg konstrukci eredmnynek tpusa a k-
vetkez:
- Ha az egyik operandus valamilyen tpus objektumra mutat s a
msik void mutat, akkor az eredmny (esetleges konverzi utn)
ugyancsak void mutat.
- Ha az egyik operandus mutat, s a msik operandus 0 rtk kons-
tans kifejezs, akkor az eredmny tpusa a mutat tpusa lesz.
176 MUTATK
Mutatk tpusnak sszehasonltsakor a const vagy volatile tpusm-
dostk nem szignifiknsak, de az eredmny tpusa megrkli mindkt ol-
dal mdostit.
rjuk t a cmaritmetika alkalmazsval a PELDA20.Cben hasznlt
DVEREM.Ct!
/* DVEREMUT.C: double verem push, pop s clear
fggvnyekkel. */
#define MERET 128 /* A verem mrete. */
static double v[MERET]; /* A verem. */
static double *vmut=v; /* A veremmutat. */
int clear(void){
vmut=v;
return MERET; }
double push(double x){
if(vmut<v+MERET) return *vmut++=x;
else return x+1.; }
double pop(void){
if(vmut>v) return *--vmut;
else return 0.; }
A vmut most valban veremmutat a double veremben (s nem a
processzorban). v kezdrtkkel indul, s mindig a kvetkez szabad
helyre irnyul. Ha kisebb, mint a veremhez mr nem tartoz cm (v+ME-
RET), akkor a push kiteszi r a paramtert, s mellkhatsknt elbbre
is lpteti eggyel a veremmutatt a kvetkez szabad helyre. A pop csak
akkor olvas a verembl, ha van benne valami (vmut>v). Kiszedskor
elbb vissza kell lltani a veremmutatt (az eltag ), s csak aztn rhe-
t el indirekcival a legutoljra kitett rtk, s most ez lesz a kvetkez
szabad hely is egyben a kvetkez push szmra.
9.4.4 Konverzi
A fordt ltal automatikusan elvgzett, implicit konverzikat mr meg-
ismertk a cmaritmetika mveleteinl.
Az explicit tpuskonverzis
(tpusnv) eltag-kifejezs
szerkezetben a (tpusnv) tbbnyire (tpus *) alak lesz, s ilyen tpus
objektumra mutat mutatv konvertlja az eltag-kifejezs rtkt. Pl-
dul:
char *lanc;
int *ip;
/* . . . */
lanc = (char *) ip;
C programnyelv 177
Nullartk konstans, egsz kifejezs, vagy ilyen (void *)gal tpusm-
dostva konvertlhat explicit tpusmdostssal, hozzrendelssel vagy
sszehasonltssal akrmilyen tpus mutatv. Ez NULL mutatt ered-
mnyez, mely megegyezik az ugyanilyen tpus NULL mutatval, de el-
tr brmely ms objektumra vagy fggvnyre mutat mutattl.
Egy bizonyos tpus mutat konvertlhat ms tpus mutatv. Az
eredmny azonban cmzs hibs lehet, ha nem megfelel trilleszts ob-
jektumot rne el. Csak azonos, vagy kisebb szigorsg trillesztsi felt-
telekkel br adattpus mutatjv konvertlhat az adott mutat, s onnt
vissza.
A trilleszts hardver sajtossg, s azt jelenti, hogy a processzor bi-
zonyos tpus adatokat csak bizonyos hatron lev cmeken helyezhet el.
A legkevsb megszort a char tpus szokott lenni. A short csak szha-
tron (2vel maradk nlkl oszthat cmen) kezddhet, a long viszont
dupla szhatron (4gyel maradk nlkl oszthat cmen) helyezkedhet
el, s gy tovbb.
Felkrjk az olvast, hogy programfejleszt rendszere segtsgben
felttlenl nzzen utna a konkrtumoknak!
void mutat kszthet akrmilyen tpus mutatbl, s megfordtva
korltozs s informciveszts nlkl. Ha az eredmnyt visszakonvertl-
juk az eredeti tpusra, akkor az eredeti mutatt lltjuk jra el.
Ha ugyanolyan, de ms, const vagy volatile mdostj tpusra konver-
tlunk, akkor az eredmny ugyanaz a mutat a mdost ltal elidzett
megszortsokkal. Ha a mdostt aztn elhagyjuk, akkor a tovbbi mve-
letek sorn az eredetileg az objektum deklarcijban szerepl const vagy
volatile mdostk maradnak rvnyben.
A mutat mindig konvertlhat a trolshoz elegenden nagy, egsz t-
puss. A mutat mrete, s az talakt fggvny persze nem gpfgget-
len. Lerunk egy, tbb fejleszt rendszerben is hasznlatos mutategsz
s egszmutat konverzit.
A mutategsz konverzi mdszere fgg a mutat s az egsz tpus
mrettl, valamint a kvetkez szablyoktl:
- Ha a mutat mrete nem kisebb az egsz tpusnl, akkor a mutat
rtk unsignedknt viselkedik azzal a megktssel, hogy nem kon-
vertlhat lebegpontoss.
178 MUTATK
- Ha a mutat mrete kisebb az egsz tpusnl, akkor a mutatt
elbb az egsszel megegyez mretv alaktja a fordt, s aztn
konvertlja egssz.
Az egszmutat talakts sem portbilis, de a kvetkez szablyok
szerint mehet pldul:
- Ha az egsz tpus ugyanolyan mret, mint a mutat, akkor az egsz
rtket unsignedknt mutatnak tekinti a fordt.
- Ha az egsz tpus mrete klnbzik a mutattl, akkor az egsz
tpust az elz pontokban ismertetett mdon konvertlja elbb mu-
tat mret, egsz tpusv, majd unsignedknt mutatnak tekinti.
9.5 Karaktermutatk
Tudjuk, hogy a karakterlnc konstans karaktertmb tpus, s ebbl k-
vetkezleg mgtte ugyancsak egy cm konstans van, hisz pldul a
printf(Ez egy karakterlnc konstans.);
kitnen mkdik, holott a printf fggvny els paramtere const char *
tpus. Ez a konstans mutat azonban a tmbtl eltren nem rendelkezik
azonostval sem, teht ksbb nincs mdunk hivatkozni r. Ennek elke-
rlsre, azaz a cm konstans rtknek megrzsre, a kvetkez md-
szerek ajnlhatk:
char *uzenet;
uzenet = Ksz a kv!\n;
vagy
const char *uzenet = Ksz a kv!\n;
9.5.1 Karakterlnc kezel fggvnyek
A rutinok prototpusai a szabvnyos STRING.H fejfjlban helyezked-
nek el. Egyik rszknek strrel, msik csoportjuknak memmel kezddik
a neve. Az str kezdetek karakterlncokkal (char *), mg a mem nevek
memriaterletekkel bjtonknt haladva (void * s nincs felttlenl
lnczr zrus a bjtsorozat vgn) foglalkoznak. A char *, vagy void *
visszaadott rtk fggvnyek mindig az eredmny lnc kezdcmt szol-
gltatjk.
e A memmovetl eltekintve, a tbbi rutin viselkedse definilatlan,
ha egymst a memriban tfed karaktertmbkre hasznljk ket.
Nhnyat teljessgre val trekvs nlkl felsorolunk kzlk!
char *strcat(char *cel, const char *forras);
C programnyelv 179
char *strncat(char *cel, const char *forras, size_t n);
A fggvnyek a cel karakterlnchoz fzik a forrast (strcat), vagy a
forras legfeljebb els, n karaktert (strncat), s visszatrnek az egyestett
cel karakterlnc cmvel. Nincs hibt jelz visszaadott rtk! Nincs tl-
csorduls vizsglat a karakterlncok msolsakor s hozzfzsekor.
A size_t tbbnyire az unsigned int tpusneve.
rjuk csak meg a sajt strncat fggvnynket!
char *strncat(char *cel, const char *forras, size_t n){
char *seged = cel;
/* Pozcionls a cel lezr \0 karakterre: */
while(*cel ) ++cel;
/* forras cel vgre msolsa a zr \0-ig, vagy
legfeljebb n karakterig: */
while(n-- && (*cel++ = *forras++));
/* Vissza az egyestett karakterlnc kezdcme: */
return seged; }
char *strchr(const char *string, int c);
void *memchr(const void *string, int c, size_t n);
A rutinok a c karaktert keresik stringben, ill. string els n bjtjban, s
az els elforduls cmvel trnek vissza, ill. NULL mutatval, ha nincs
is c a stringben, vagy az els n bjtjban. A lnczr zrus is lehet c pa-
ramter. Az
char *strrchr(const char *string, int c);
ugyanazt teszi, mint az strchr, csak c stringbeli utols elfordulsnak
cmvel tr vissza, ill. NULL mutatval, ha nincs is c a stringben.
int strcmp(const char *string1, const char *string2);
int strncmp(const char *string1, const char *string2, size_t n);
int memcmp(const void *string1, const void *string2, size_t n);
A fggvnyek unsigned char tpus tmbkknt sszehasonltjk
string1 s string2 karakterlncokat, s negatv rtket szolgltatnak, ha
string1 < string2. Pozitv rtk jn, ha string1 > string2. Az egyenlsget
viszont a visszaadott zrus jelzi.
Az strncmp s a memcmp a hasonltst legfljebb az els n karakterig,
ill. bjtig vgzik.
A legtbb fejleszt rendszerben nem szabvnyos stricmp s str-
nicmp is szokott lenni, melyek nem kisnagybet rzkenyen hasonltjk
ssze a karakterlncokat.
180 MUTATK
A sajt strcmp:
int strcmp(const char *s1, const char *s2 ){
for( ; *s1 == *s2; ++s1, ++s2)
if(!(*s1)) return 0; /* s1 == s2 */
return(*s1 - *s2); } /* s1 < s2 vagy s1 > s2 */
char *strcpy(char *cel, const char *forras);
char *strncpy(char *cel, const char *forras, size_t n);
void *memcpy(void *cel, const void *forras, size_t n);
void *memmove(void *cel, const void *forras, size_t n);
Az strcpy a forras karakterlncot msolja lnczr karaktervel egytt a
cel karaktertmbbe, s visszatr a cel cmmel. Nincs hibt jelz visszat-
rsi rtk. Nincs tlcsorduls ellenrzs a karakterlncok msolsnl.
Az strncpy a forras legfeljebb els n karaktert msolja. Ha a forras n
karakternl rvidebb, akkor cel vgt \0zza n hosszig a rutin. Ha az n
nem kisebb, mint a forras mrete, akkor nincs zrus a msolt karakterlnc
vgn.
A memcpy s a memmove mindenkppen n bjtot msolnak. Egyetlen-
knt a karakterlnc kezel fggvnyek kzl, a memmove akkor is bizto-
stja az tlapol memriaterleteken lev, eredeti forras bjtok fellrs
eltti tmsolst, ha a forras s a cel tfedn egymst.
A sajt strcpy:
char *strcpy(char *cel, const char *forras ){
char *seged = cel;
/* forras cel-ba msolsa lezr \0 karaktervel: */
while(*cel++ = *forras++);
/* Vissza a msolat karakterlnc kezdcme: */
return seged; }
size_t strlen(const char *string);
A rutin a string karakterlnc karaktereinek szmval tr vissza a lncz-
rt nem beszmtva. Nincs hibt jelz visszaadott rtk!
char *strpbrk(const char *string, const char *strCharSet);
A fggvnyek az strCharSetbeli karakterek valamelyikt keresik a
stringben, s visszaadjk az els elforduls cmt, ill. NULL mutatt,
ha a kt paramternek kzs karaktere sincs. A keressbe nem rtendk
bele a lnczr zrusok.
A pldban szmokat keresnk az s karakterlncban.
#include <string.h>
C programnyelv 181
#include <stdio.h>
void main(void){
char s[100] = "3 frfi s 2 fiu 5 disznt ettek.\n";
char *er = s;
int i=1;
while(er = strpbrk(er, "0123456789"))
printf("%d: %s\n", i++, er++); }
A kimenet a kvetkez:
1: 3 frfi s 2 fiu 5 disznt ettek.
2: 2 fiu 5 disznt ettek.
3: 5 disznt ettek.
char *strset(char *string, int c);
char *strnset(char *string, int c, size_t n);
void *memset(void *string, int c, size_t n);
A memset feltlti string els n bjtjt c karakterrel, s visszaadja string
kezdcmt.
A legtbb fejleszt rendszerben ltez, nem ANSI szabvnyos str-
set s strnset a string minden karaktert a lnczr zrus kivtelvel c
karakterre lltjk t, s visszaadjk a string kezdcmt. Nincs hibt jelz
visszatrsi rtk. Az strnset azonban a string legfeljebb els n karaktert
inicializlja cre.
size_t strspn(const char *string, const char *strCharSet);
size_t strcspn(const char *string, const char *strCharSet);
Az strspn annak a string elejn lev, maximlis alkarakterlncnak a
mrett szolgltatja, mely teljes egszben csak az strCharSetbeli karak-
terekbl ll. Ha a string nem strCharSetbeli karakterrel kezddik, akkor
zrust kapunk. Nincs hibt jelz visszatrsi rtk. A keressbe nem r-
tendk bele a lnczr zrus karakterek.
A fggvny visszaadja tulajdonkppen az els olyan karakter indext
a stringben, mely nincs benn az strCharSet karakterlnccal definilt ka-
rakterkszletben.
Az strcspn viszont annak a string elejn lev, maximlis alkarakter-
lncnak a mrett szolgltatja, mely egyetlen karaktert sem tartalmaz az
strCharSetben megadott karakterekbl. Ha a string strCharSetbeli ka-
rakterrel kezddik, akkor zrust kapunk. Pldul a:
#include <string.h>
#include <stdio.h>
void main(void){
char string[] = "xyzabc";
182 MUTATK
printf("%s lncban az els a, b vagy c indexe %d\n",
string, strcspn(string, "abc")); }
eredmnye:
xyzabc lncban az els a, b vagy c indexe 3
char *strstr(const char *string1, const char *string2);
A fggvny string2 karakterlnc els elfordulsnak cmt szolgltat-
jk string1ben, ill. NULL mutatt kapunk, ha string2 nincs meg
string1ben. Ha string2 res karakterlnc, akkor a rutin string1gyel tr
vissza. A keressbe nem rtendk bele a lnczr zrus karakterek.
char *strtok(char *strToken, const char *strDelimit);
A fggvny a kvetkezleg megtallt, strTokenbeli szimblum cmvel
tr vissza, ill. NULL mutatval, ha nincs mr tovbbi szimblum az str-
Token karakterlncban. Mindenegyes hvs mdostja az strToken karak-
terlncot, gy hogy \0 karaktert tesz a bekvetkezett elvlasztjel hely-
re. Az strDelimit karakterlnc az strTokenbeli szimblumok lehetsges
elvlaszt karaktereit tartalmazza.
Az els strtok hvs tlpi a vezet elvlasztjeleket, visszatr az strTo-
kenbeli els szimblum cmvel, s ezeltt a szimblumot \0 karakter-
rel zrja. Az strToken maradk rsze tovbbi szimblumokra bonthat
jabb strtok hvsokkal. Mindenegyes strtok hvs mdostja az strTo-
ken karakterlncot, gy hogy \0 karaktert tesz az aktulisan visszaadott
szimblum vgre. Az strToken kvetkez szimblumt az strToken para-
mter helyn NULL mutats strtok hvssal lehet elrni. A NULL muta-
t els paramter hatsra az strtok megkeresi a kvetkez szimblumot
a mdostott strTokenben. A lehetsges elvlasztjeleket tartalmaz str-
Delimit paramter, s gy maguk az elvlaszt karakterek is, vltozhatnak
hvsrlhvsra.
A pldaprogramban ciklusban hvjuk az strtok fggvnyt, hogy megje-
lentethessk az s karakterlnc sszes szkzzel, vesszvel, stb. elvlasz-
tott szimblumt:
#include <string.h>
#include <stdio.h>
void main( void ){
char s[] = "Szimblumok\tkarakterlnca\n ,, s nhny
tovbbi szimblum";
char selv[] = " ,\t\n", *token;
printf("%s\nSzimblumok:\n", s);
/* Mg vannak szimblumok a karakterlncban, */
token = strtok(string, selv);
while(token != NULL){
C programnyelv 183
/* addig megjelentetjk ket, s */
printf("\t%s\n", token);
/* vesszk a kvetkezket: */
token=strtok(NULL, selv); } }
A kimenet a kvetkez:
Szimblumok karakterlnca
,, s nhny tovbbi szimblum
Szimblumok:
Szimblumok
karakterlnca
s
nhny
tovbbi
szimblum
Megoldand feladatok:
Ksztse el az albb felsorolt, ismert C fggvnyek mutatkat hasznl
vltozatt! A char * visszatrs rutinok az eredmny cmvel trnek
vissza.
- int getline(char *, int): sor beolvassa a szabvny bemenetrl.
{STRSTRXT.C}
- char *squeeze(char *s, int c): c karakter trlse az s karakterlnc-
bl a sajt helyn.
- int *binker(int x, int *t, int n): a nvekvleg rendezett, n elem, t
tmbben megkeresend x csak mutatkat hasznl, binris keressi
algoritmussal! Ha megvan, vissza kell adni a tbeli elforduls c-
mt. Ha nincs, NULL mutatt kell szolgltatni.
- int atoi(char *): karakterlnc egssz konvertlsa.
- char *strupr(char *): karakterlnc nagybetss alaktsa a sajt he-
lyn.
- char *strrev(char *): karakterlnc megfordtsa a sajt helyn.
- char *strset(char *s, int c): s karakterlnc feltltse c karakterrel.
- char *strstr(const char *, const char *): a msodik karakterlnc
keresse az elsben. A pontos ismertets kicsit elbbre megtallha-
t! {STRSTRXT.C}
Ksztsen char *strstrnext(const char *, const char *) fggvnyt is,
mely ugyanazt teszi, mint az strstr, de static mutat segtsgvel az els
hvs utn a msodik karakterlnc kvetkez elsbeli elfordulsnak c-
184 MUTATK
mvel tr vissza, s ezt mindaddig teszi, mg NULL mutatt nem kell
szolgltatnia. {STRSTRXT.C}
9.5.2 Vltoz paramterlista
Az OBJEKTUMOK S FGGVNYEK szakaszbl tudjuk, hogy a
fggvny paramterlistja tal is vgzdhet, amikor is a fordt a ,
eltti fix paramtereket a szoksos mdon kezeli, de a ,.. helyn ll aktu-
lis paramtereket gy manipullja, mintha nem adtak volna meg fgg-
vny prototpust.
A szabvnyos STDARG.H fejfjlban definilt tpus s fggvnyek
(makrk) segtsget nyjtanak az ismeretlen paramterszm s tpus pa-
ramterlista feldolgozsban. A tpus s az ANSI kompatibilis makrdefi-
ncik a kvetkezk lehetnek pldul:
typedef char *va_list;
#define _INTSIZEOF(x) ((sizeof(x)+sizeof(int)-1)&\
~(sizeof(int) -1))
#define va_start(ap, utsofix) (ap=(va_list)&utsofix+\
_INTSIZEOF(utsofix))
#define va_arg(ap, tipus) (*(tipus *)((ap+=_INTSIZEOF\
(tipus)) - _INTSIZEOF(tipus)))
#define va_end(ap) ap = (va_list)0
A va_... szerkezettel csak olyan vltoz paramteres fggvnyek rha-
tk, ahol a vltoz paramterek a paramterlista vgn helyezkednek el. A
va_... makrkat a kvetkezkpp kell hasznlni:
1. A szerkezetet hasznl fggvnyben deklarlni kell egy va_list tpu-
s, mondjuk, param nev vltozt:
va_list param;
, ami a va_arg s a va_end ltal ignyelt informcit hordoz muta-
t.
6. Meg kell hvni a va_start fggvnyt:
va_start(param, utsofix);
a va_arg s a va_end fggvnyek hasznlata eltt. A va_start a pa-
ram mutatt a vltoz paramterlistval meghvott fggvny els
vltoz paramterre lltja. Az utsofix paramterben el kell rni a
vltoz paramterlistval meghvott fggvny azon utols formlis
paramternek nevt, amely mg rgztett. A va_startnak nincs
visszaadott rtke. A va_start els paramternek va_list tpusnak
kell lennie. Ha a msodik paramter register trolsi osztly, ak-
kor a makr viselkedse nem meghatrozott.
C programnyelv 185
7. Eztn va_arg hvsok kvetkeznek:
(tipus) va_arg(param, tipus);
, melyek rendre szolgltatjk a vltoz paramterlista kvetkez ak-
tulis paramternek rtkt. A makrbl ltszik, hogy a tipus meg-
adsa fontos, hisz eszerint lpteti a param a mutatt elre, ill. ilyen
tpus rtket szolgltat a vltoz paramterlistban soron kvetke-
z paramterbl.
l Azt aztn, hogy a vltoz paramterlistnak mikor van vge, a prog-
ramoznak kell tudnia!
8. Ha a va_arg kiolvasta a vltoz paramterlista minden elemt, vagy
ms miatt kell abbahagynunk a tovbbi feldolgozst, akkor meg kell
hvni a
va_end(param);
makrt, hogy a vltoz paramterlistval meghvott fggvnybl
biztostsuk a normlis visszatrst. A va_endnek nincs visszaadott
rtke, s a makrdefincibl ltszik, hogy NULLzza a param
mutatt.
Tekintsnk meg a kvetkez egyszer pldt, melyben zrus jelzi a pa-
ramterlista vgt!
#include <stdio.h>
#include <stdarg.h>
void sum(char *uzen, ...) {
int osszeg = 0, tag;
va_list param;
va_start(param, uzen);
while(tag = va_arg(param, int)) osszeg += tag;
printf(uzen, osszeg); }
void main(void) {
sum("1+2+3+4 = %d\n", 1, 2, 3, 4, 0); }
A param char * tpus. Ttelezzk fel a 32 bites int s cm esett! Ak-
kor a va_start(param, uzen) hatsra az
_INTSIZEOF(uzen)=
(sizeof(uzen)+sizeof(int)-1)&~(sizeof(int) -1)=
(4+4-1)&~(4-1)=7&~3=4
s gy a
param=(char *)&uzen+4
, ami azt jelenti ugye, hogy param az els vltoz paramter cmt fogja
tartalmazni.
A tag=va_arg(param, int) kvetkeztben
186 MUTATK
tag=(*(int *)((param+=_INTSIZEOF(int))-_INTSIZEOF(int)))
, azaz:
tag=*(int *)((param+=4)-4)
Teht a tag vltoz felveszi a kvetkez, int, aktulis paramter rtkt,
s ekzben param mr a kvetkez aktulis paramterre mutat.
A kvetkez fggvnyek a parlist vltoz paramterlisttl eltekint-
ve ugyangy dolgoznak, mint nevkben v nlkli prjaik. A felsorolt
printf fggvnyek a 3. pont va_arg hvsait maguk intzik, s a format
karakterlnc alapjn a vltoz paramterlista vgt is ltjk. A parlist az
aktulis vltoz paramterlista els elemre mutat mutat.
int vfprintf(FILE *stream, const char *format, va_list parlist);
int vprintf(const char *format, va_list parlist);
int vsprintf(char * puffer, const char * format, va_list parlist);
9.6 Mutattmbk
Mutattmb a
tpus *azonost[<konstans-kifejezs>] <={inicializtorlista}>;
deklarcival hozhat ltre. Az azonost a mutattmb neve: konstans
mutat, melynek tpusa (tpus **), vagyis tpus tpus objektumra mutat
mutatra mutat mutat. Teht olyan konstans mutat, mely (tpus *) mu-
tatra mutat.
Vegyk szre a * mutatkpz opertor rekurzv hasznlatt!
A tmb egy eleme viszont (tpus *) tpus vltoz mutat.
Kezdjnk el egy pldt magyar krtyval!
A szneket kdoljuk a kvetkezkpp: makk (0), piros (1), tk (2) s
zld (3). A krtykat egy sznen bell jelljk gy: hetes (0), nyolcas (1),
kilences (2), tzes (3), als (4), fels (5), kirly (6) s sz (7). A konkrt
krtya kdja gy keletkezik, hogy a sznkd utn lerjuk a krtya kdjt.
Ilyen alapon a 17 pldul piros sz.
Ksztsnk char *KartyaNev(int kod) fggvnyt, mely visszaadja a pa-
ramter kod krtya megnevezst!
/* KARTYA.H fejfjl. */
/* Szimbolikus llandk: */
#define SZINDB 4 /* Sznek szma. */
#define KTYDB 8 /* Krtyk szma egy sznen bell. */
#define OSZTO 10 /* Szn s krtyakd sztvlasztshoz*/
#define PAKLI SZINDB*KTYDB /* Krtyaszm a pakliban. */
C programnyelv 187
#define MAXKOD (SZINDB-1)*OSZTO+KTYDB /* Max. krtykd.*/
/* Prototpusok: */
char * KartyaNev(int);
void UjPakli(void);
int Mennyi(void);
int UjLap(void);
/* KARTYA.C: Adat s fggvnydefincik. */
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "KARTYA.H"
static char *szin[SZINDB]={"makk ", "piros ", "tk ",
"zld "};
static char *kartya[KTYDB]={"VII", "VIII", "IX", "X",
"als", "fels", "kirly", "sz"};
char * KartyaNev(int kod){
static char szoveg[20];
if(kod>=0 && kod/OSZTO<SZINDB && kod%OSZTO<KTYDB){
strcpy(szoveg, szin[kod/OSZTO]);
strcat(szoveg, kartya[kod%OSZTO]); }
else strcpy(szoveg, "zldsg");
return szoveg; }
e Vigyzzunk nagyon a tpusokkal! A szin s a kartya statikus let-
tartam, bels kapcsolds, fjl hatskr, karakterlncokra mutatk
tmbjeinek kezdeteire mutat mutat (char **) konstansok nevei. A szin
[1] a piros karakterlnc kezdetnek cmt tartalmaz, karakteres mutat-
tmb elem (char *). Igazak pldul a kvetkezk:
*szin szin[0]
**szin *szin[0] m
A szoveg statikus lettartam karaktertmb, gy nem sznik meg a
memriafoglalsa a fggvnybl val visszatrskor, csak loklis hats-
kr azonostjval nem rhet el!
rjunk rvid, kiprbl programot!
/* PELDA23.C: Krtya megnevezsek kiratsa. */
#include <stdio.h>
#include "KARTYA.H"
void main(void){
int i;
printf("Magyar krtya megnevezsek rendre:\n");
for(i=-1; i<=MAXKOD; ++i)
printf("%-40s", KartyaNev(i)); }
9.7 Tbbdimenzis tmbk
A tbbdimenzis tmbket a tmb tpus tmbjeiknt konstrulja meg a
fordt. A deklarci
188 MUTATK
tpus azonost[<mret1>][mret2]. . .[mretN] <={inicializtorlista}>;
alak. Az elhelyezsrl egyelre annyit, hogy sorfolytonos, azaz a jobbra
ll index vltozik gyorsabban. Pldul a
double matrix[2][3];
sorfolytonosan a kvetkez sorrendben helyezkedik el a trban:
matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0],
matrix[1][1], matrix[1][2]
Egy elem elrse pldul
azonost[index1][index2]. . .[indexN]
mdon megy, ahol az indexekre igazak a kvetkezk:
0 <= index1 < mret1
0 <= index2 < mret2
. . .
0 <= indexN < mretN
e Vigyzzunk az indexek klnkln []be rsra is! Vve mondjuk
a matrix[i][j]t, a matrix[i,j] kifejezs is rtelmes a Cben. Persze
nem matrix[i][j]t jelenti, hanem a vessz opertor vgrehajtsa utn a
matrix[j] tmbt.
A BEVEZETS S ALAPISMERETEK szakasz Inicializls feje-
zetben a tmbk inicializlsrl mondottak most is rvnyben vannak,
de a tbbdimenzis tmb tovbbi tmbkbl ll, s gy az inicializlsi
szablyok is rekurzvan alkalmazandk. Az inicializtorlista egymsba
gyazott, egymstl vesszvel elvlasztott inicializtorok s inicializtor-
listk sorozata a sorfolytonos elhelyezsi rend betartsval. Pldul a
4x3as t tmb els sornak minden eleme 1 rtk, msodik sornak min-
den eleme 2 rtk, s gy tovbb.
int t[4][3]={{1, 1, 1}, {2, 2, 2}, {3, 3, 3}, {4, 4, 4}};
Ha az inicializtorlistban nincs begyazott inicializtorlista, akkor az
ott felsorolt rtkek az alaggregtumok, s azon bell az elemek sorrendj-
ben veszik fel az aggregtum elemei. Az elz pldval azonos eredmny-
re vezetne a kvetkez inicializls is:
int t[4][3] = {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};
Kapcsos zrjelek akr az egyes inicializtorok kr is tehetk, de
ha a fordtt nem kvnjuk becsapni, akkor clszer ket az aggregtum
szerkezett pontosan kvetve hasznlni! Az
int t[4][3]={{1, 1, 1}, {2, 2, 2}, {3, 3, 3}};
C programnyelv 189
hatsra a t mtrix utols sorra (a t[3] tmbre) nem jut inicializtor, gy a
t[3][0], t[3][1] s t[3][2] elemek mind zrus kezdrtket kapnak. Az
int t[4][3]={{1}, {2}, {3}};
eredmnyeknt a t[0][0] 1, a t[1][0] 2, a t[2][0] 3 lesz, s a tmb sszes
tbbi eleme zrus.
e Tudjuk, hogyha nem adjuk meg, akkor az inicializtorlista elemsz-
mbl llaptja meg a tmbmretet a fordt. Tbbdimenzis tmb dekla-
rcijban ez azonban csak az els mretre vonatkozik, a tovbbi mrete-
ket mind ktelez elrni.
int a[][]={{1, 1}, {2, 2}, {3, 3}}; /* HIBS */
int t[][3]={{1, 1, 1}, {2, 2, 2}, {3, 3, 3}}; /* OK */
Folytassuk tovbb a PELDA23.Cben megkezdett magyar krtys pl-
dnkat! jabb programunknak legyen az a feladata, hogy megkeveri a
paklit, s kioszt t lapot! Aztn jra kioszt t lapot, s gy tovbb mindad-
dig, mg a krtya el nem fogy. jabb kevers kvetkezik s jabb oszt-
sok. A szoftvernek akkor van vge, ha mr nem krnek tbb lapot.
Azt, hogy milyen krtykat osztott mr ki a paklibl, statikus lettarta-
m, csak a KARTYA.C forrsfjlban elrhet, ktdimenzis, SZINDB*
KTYDBs, kty tmbben tartja nyilvn a program. A megfelel tmbelem
zrus, ha mg pakliban van a lap, s 1gy vlik, ha kiosztjk. A statikus,
a KARTYA.C forrsmodulra ugyancsak loklis, ktydb vltozban a pak-
li aktulis krtyaszmt rzi a szoftver.
A kvetkez sorokkal mindig a KARTYA.C bvtend!
static int kty[SZINDB][KTYDB];
static int ktydb=SZINDB*KTYDB;
Az UjPakli fggvny ugyanezt az llapotot lltja el.
void UjPakli(void){
int i, j;
for(i=0; i<SZINDB; ++i)
for(j=0; j<KTYDB; ++j) kty[i][j]=0;
ktydb=SZINDB*KTYDB; }
A Mennyi rutinnal lekrdezhet, hogy mg hny krtya van a pakliban.
int Mennyi(void){
return ktydb; }
Az int UjLap(void) fggvny egy lapot ad a paklibl, azonban ezt v-
letlenszeren teszi a kvetkez technikval:
- Ha nincs krtya a pakliban, 1et szolgltat.
190 MUTATK
- Ha egyetlen lapbl ll a pakli, akkor azt adja.
- Ha ktydb<KTYDB, akkor elllt egy 1 s ktydb kzti vletlensz-
mot. Vgigjrja a paklit, s visszaadja a vletlenszmadik, mg nem
kiosztott krtyt.
- Ha ktydb>=KTYDB, akkor vletlen sznt s vletlen krtyt v-
laszt. Kiadja a lapot, ha mg eddig nem osztotta ki. Ha a krtya mr
nincs a pakliban, jat vlaszt, s gy tovbb.
Ltszik, hogy szksgnk lesz vletlenszm genertorra!
9.7.1 Vletlenszm genertor
Hasznlathoz az STDLIB.H fejfjlt kell bekapcsolni. Egsz szmok
pszeudvletlen sorozatt generlja 0 s RAND_MAX kztt az
int rand(void);
fggvny. A rutinnak nincs hibs visszatrse. A vletlenszm generls
kezdrtkt lehet belltani a
void srand(unsigned int kezd);
fggvnnyel. Az alaprtelmezett indul rtk 1, gy ilyen rtk kezd pa-
ramterrel mindig jrainicializltathatjuk a vletlenszm genertort, azaz
a rand hvsok ugyanazt a vletlenszm sorozatot produkljk srand(1)
utn, mintha mindenfle srand megidzs nlkl hasznltuk volna a
randot.
Az srandot a vletlenszer indulst is biztostand rendszerint a TI-
ME.Hban helyet foglal
time_t time(time_t *timer);
fggvny kezd paramterrel szoktk meghvni. A time rutin az aktulis
rendszer idt 1970. janur elseje jfl ta eltelt msodpercek szmban,
time_t (long) tpusban szolgltatja. Nincs hibs visszatrs. A visszatrsi
rtket a timer cmen is elhelyezi, ha a paramter nem NULL mutat.
NULL mutat aktulis paramter esetn viszont nem tesz ilyet.
Az srand fggvny szoksos hvsa teht:
srand(time(NULL))
Vletlenszm genertorral kockadobs rtket a kvetkezkpp produ-
klhatunk:
rand()%6 + 1
C programnyelv 191
Ha a fejleszt rendszerben nincs lebegpontos vletlenszmot generl
fggvny, akkor 0 s 1 kztti vletlenszmokat a kvetkez kifejezssel
llthatunk el:
(double)rand()/RAND_MAX
Folytassuk az UjLap fggvnyt!
int UjLap(void){
int i, j, db;
if(ktydb==SZINDB*KTYDB) srand(time(NULL));
if(ktydb){
if(ktydb>=KTYDB)
while(kty[i=rand()%SZINDB][j=rand()%KTYDB]);
else{
db=ktydb>1?rand()%ktydb+1:1;
for(i=0; i<SZINDB; ++i){
for(j=0; db&&j<KTYDB; ++j)
if(!kty[i][j]&&!(--db)) break;
if(!db) break; } }
--ktydb;
kty[i][j]=1;
return i*OSZTO+j; }
else return (-1); }
Elkszltnk a kibvtett KARTYA.Cvel, s most rjuk meg a mkd-
tet PELDA24.C programot!
/* PELDA24.C: t lap osztsa. */
#include <stdio.h>
#include <ctype.h>
#include "KARTYA.H"
#define LAPDB 5
void main(void){
int i, c;
printf("Zsugzs: %d lap leosztsa:\n", LAPDB);
while(printf("Ossza mr (I/N)? "),
(c=toupper(getchar()))!='N'){
if(c=='I'){
putchar('\n');
if(Mennyi()<LAPDB) UjPakli();
for(i=0; i<LAPDB; ++i)
printf("%-15s", KartyaNev(UjLap()));
printf("\n\n"); }
while(c!=EOF&&c!='\n') c=getchar(); } }
Megoldand feladatok:
Javtson a kzlt programon a kvetkez mdon:
- A leosztott t lap megjelentetse trtnjk sznek szerint, s azon
bell krtyk szerint rendezetten!
- A kapott t lapbl legyen legfeljebb 3 cserlhet!
192 MUTATK
- A jtk mkdjk francia krtyval!
9.7.2 Dinamikus memriakezels
A C a memrit hrom rszre osztja. Az elsdleges adatterleten helyezi el a fordt a
konstansokat s a statikus objektumokat. A loklis objektumokat s a fggvnypara-
mtereket a verembe (stack) teszi. A harmadik memriaterletet nevezzk heapnek,
br ms nvvel is szoktk illetni futs kzben ri el a C program, s vltoz mret
memria blokkok dinamikus alloklsra val. Pldul fk, listk, tmbk vagy brmi
ms helyezhet el rajta. Az ismertetett, ANSI szabvnyos fggvnyek prototpusai az
STDLIB.H fejfjlban tallhatk.
void *calloc(size_t tetelek, size_t meret);
A calloc tetelek*meret mret memria blokkot foglal, feltlti 0X00-val s visszaadja
kezdcmt. Tulajdonkppen tetelek elemszm tmbnek foglal helyet, ahol egy elem
mrete meret bjt.
Ha nincs elg hely, vagy a tetelek*meret szorzat rtke zrus, NULL mutatt kapunk vis-
sza.
void *malloc(size_t meret);
A malloc legalbb meret bjtos memria blokkot foglal, nem tlti fel semmivel s vissz-
aadja kezdcmt. A blokk nagyobb lehet meret bjtnl a trillesztshez ignyelt, plusz
terlet s a karbantartsi informci elhelyezse miatt.
Ha nincs elg hely a heap-en, NULL mutatt kapunk vissza a fggvnytl. Ha a meret 0,
a malloc zrusmret blokkot allokl, s rvnyes mutatt ad vissza erre a terletre.
J nhny szabvnyos fggvny is hvja a mallocot. Pldul a calloc, a getchar stb.
A callockal, a mallockal lefoglalt, vagy a rgtn ismertetend reallockal jra-
foglalt terlet trillesztse olyan, hogy brmilyen tpus objektum elhelyezsre alkal-
mas. A fggvnyektl visszakapott cm explicit tpusmdost szerkezettel brmilyen
tpusv talakthat.
Tegyk fel, hogy a program futsa kzben derl ki egy double tmb mrete! Ezt az
rtket az int tpus, N vltoz tartalmazza. Hogyan lehet ltrehozni, kezelni, s vgl
felszabadtani egy ilyen tmbt?
/* . . . */
int N;
double *dtomb;
/* . . . */
/* Itt kiderl, hogy mennyi N. */
/* . . . */
/* Ettl kezdve szksg van a tmbre. */
if((dtomb=(double *)malloc(N*sizeof(double)))!=NULL){
/* Sikeres a memriafoglals, azaz hasznlhat a tmb.
C programnyelv 193
Pldul a 6. eleme dtomb[5] mdon is elrhet. */
/* . . . */
/* Nincs szksg a tovbbiakban a tmbre. */
free(dtomb);
/* . . . */ }
else /* Hibakezels. */
/* . . . */
void *realloc(void *blokk, size_t meret);
A realloc meret mretre szkti vagy bvti a korbban malloc, calloc vagy realloc
hvssal alloklt memria blokkot, melynek kezdcmt megkapja a blokk paramterben.
Sikeres esetben visszaadja az tmretezett memria blokk kezdcmt. Ez a cm nem
felttlenl egyezik meg a blokk paramterben tadottal. Cmeltrs esetn a fggvny a
korbbi memria blokk tartalmt tmozgatja az jba. Az esetleges rvidlstl eltekintve
elmondhat, hogy az j blokk megrzi a rgi tartalmt.
Ha az jraallokls sikertelen memria hiny miatt, ugyancsak NULL mutatt kapunk,
de az eredeti blokk vltozatlan marad.
void free(void *blokk);
A free dealloklja vagy felszabadtja a korbban malloc, calloc vagy realloc hvssal al-
loklt memriaterletet, melynek kezdcmt megkapja a blokk paramterben. A felsza-
badtott bjtok szma egyezik az allokcikor (vagy a realloc esetn) ignyelttel. Ha a
blokk NULL, a mutatt elhagyja a free, s rgtn visszatr.
e Az rvnytelen mutats (nem calloc, malloc, vagy realloc fggvnnyel foglalt
memria terlet cmnek tadsa) felszabadtsi ksrlet befolysolhatja a rkvetkez
allokcis krseket, s fatlis hibt is okozhat.
A tbbdimenzis tmbk bels szerkezetnek megrtshez hozzunk ltre dinamikusan
egy tmbt, a pldban most egy mtrixot!
/* PELDA25.C: Ktdimenzis tmb ltrehozsa dinamikusan.*/
#include <stdio.h>
#include <stdlib.h>
typedef long double TIPUS;
typedef TIPUS **OBJEKTUM;
int m=3, n=5; /* Sorok s oszlopok szma. */
int main(void) {
OBJEKTUM matrix;
int i, j;
/* A sorok ltrehozsa: */
printf("%d*%d-s, ktdimenzis tmb ltrehozsa
194 MUTATK
dinamikusan.\n", m, n);
if(!(matrix=(OBJEKTUM)calloc(m, sizeof(TIPUS *)))){
printf("Ltrehozhatatlanok a mtrix sorai!\n");
return 1; }
/* Az oszlopok ltrehozsa: */
for(i = 0; i < m; ++i)
if(!(matrix[i]=(TIPUS *)malloc(n*sizeof(TIPUS)))){
printf("Ltrehozhatatlan a mtrix %d. sora!\n",
i);
while(--i>=0) free(matrix[i]);
free(matrix);
return 1; }
/* Mestersges inicializls: */
for(i = 0; i < m; ++i)
for(j = 0; j < n; ++j)
matrix[i][j] = rand();
/* Kirs: */
printf("A mtrix tartalma:\n");
for(i = 0; i < m; ++i) {
for(j = 0; j < n; ++j)
printf("%10.0Lf", matrix[i][j]);
printf("\n"); }
/* Az oszlopok felszabadtsa: */
for(i = 0; i < m; ++i) free(matrix[i]);
/* Sorok felszabadtsa: */
free(matrix);
return 0; }
Vegyk szre, hogy a mainnek van visszaadott rtke, mely zrus, ha minden rend-
ben megy, s 1, ha memriafoglalsi problma lp fel!
Figyeljk meg azt is, hogy a memria felszabadtsa foglalsval ppen ellenkez
sorrendben trtnik, hogy a heapen ne maradjanak foglalt szigetek!
A heap C konstrukci, s ha a program befejezdik, akkor maga is felszabadul, meg-
sznik ltezni.
C programnyelv 195
sszestve: A matrix azonost a tmb kezdetre mutat, vltoz mutat. A tmb kez-
dete viszont m vltoz mutatbl ll mutattmb. A mutattmb egy-egy eleme n
elem, long double tpus tmb kezdetre mutat. A plda a rszek memriabeli el-
helyezkedst is szemllteti, azaz:
elbb az m elem mutattmbt allokljuk, aztn
a mtrix els sora (0-s index) n elemnek foglalunk helyet.
A mtrix msodik sora (1-s index) n elemnek helyfoglalsa kvetkezik.
. . .
Legvgl a mtrix utols (m-1 index) sornak n elemt helyezzk el a
memriban.
32 bites cmeket felttelezve, 1000rl indulva, m=3 s n=5 esetn, a matrix a
kvetkezkppen helyezkedhet el a memriban:
matrix[0] matrix[1] matrix[2]
matrix:
1012 1062 1112

1000 1004 1008
matrix[0]:
matrix[0][0] matrix[0][1] matrix[0][2] matrix[0][3] matrix[0][4]
1012 1022 1032 1042 1052
matrix[1]:
matrix[1][0] matrix[1][1] matrix[1][2] matrix[1][3] matrix[1][4]
1062 1072 1082 1092 1102
matrix[2]:
matrix[2][0] matrix[2][1] matrix[2][2] matrix[2][3] matrix[2][4]
1112 1122 1132 1142 1152
Hromdimenzis tmbt gy valsthatunk meg, hogy ltrehozunk elbb egy
mutattmbt, melynek mindenegyes eleme egy, az elzekben ismertetett szerkezet
mtrixra mutat.
Nhny sz mg a tbbszrsen alkalmazott index opertorrl! A kifejezs1[kife-
jezs2][kifejezs3]...ban az index opertorok balrl jobbra ktnek, gy a fordt elszr
a legbaloldalibb kifejezs1[kifejezs2] kifejezst rtkeli ki. A szletett mutat rtkhez
aztn hozzadva kifejezs3 rtkt j mutat kifejezst kpez, s ezt a folyamatot a legjob-
boldalibb index kifejezs sszegzsig vgzi. Ha a vgs mutat rtk nem tmb tpust
cmez, akkor az indirekci mvelete kvetkezik. Teht pldul:
matrix[2][3] (*(matrix+2))[3] *(*(matrix+2)+3)
e A fordt hasonl mdszerrel dolgozik, de az ltala ltrehozott mtrixszal kapcsolat-
ban az sszes mutat idertve a mtrix azonostjt is konstans.
A tbbdimenzis tmbk tbbflekppen is szemllhetk. A fordt ltal ltrehozott
mtrix (.n. statikus tmb) pldjnl maradva:
long double matrix[m][n];
A matrix egy m elem vektor (tmb) azonostja. E vektor minden eleme egy n
elem, long double tpus vektor.
A matrix[i] (i = 0, 1, ..., m-1) az iedik, n long double elem vektor azono-
stja.
196 MUTATK
A matrix[i][j] (i = 0, 1, ..., m-1 s j = 0, 1, ..., n-1) a mtrix egy long double
tpus eleme.
A dolgokat ms oldalrl tekintve!
A matrix konstans mutat, mely a mtrix kezdcmt teht matrix[0], n darab
long double elembl ll tmb kezdcmt - tartalmazza.
A matrix+i a matrix[i], n darab long double elem tmb cme. A matrix+i
matrix+i+1tl pp n darab long double tpus vltoz mretvel tr el.
A matrix+i cm tartalma ugye *(matrix+i) vagy matrix[i].
A matrix[i] teht az i-edik, n darab long double elembl ll tmb azonostja:
konstans mutat, mely az i-edik, n long double elem tmb kezdetre mutat.
A matrix[i]+j vagy *(matrix+i)+j az iedik, n long double elem tmb j-edik
elemnek cme. E cm tartalma elrhet a kvetkez hivatkozsokkal:
matrix[i][j], *(matrix[i]+j) vagy *(*(matrix+i)+j).
A &matrix[0][0], a matrix[0], a &matrix[0] s a matrix ugyanaz az rtk, azaz
a mtrix kezdetnek cme, de a matrix[0][0] egy long double azonostja, a mat-
rix[0] egy n long double elem tmb azonostja, s a matrix a tmbkbl ll
tmb azonostja. gy:
&matrix[0][0] + 1 &matrix[0][1],
matrix[0] + 1 *matrix + 1 &matrix[0][1],
&matrix[0] + 1 matrix + 1 s
matrix + 1 &matrix[1] &matrix[1][0].
Tbbdimenzis, statikus tmbk esetn a fordt nem generl mutattmbket a
memriba, csak a puszta tmbelemeket helyezi el a trban a dinamikus tmbnl trgyalt
mdon s sorrendben. A kd azonban elllt konstans mutatknt minden, a dinamikus
tmbnl megszokott mutathivatkozst. E szmtsokba a fordt fixen bepti a tbbdi-
menzis tmb mreteit (az elstl eltekintve). Az indexels is mdosul kicsit ebben az
rtelemben. Pldul a matrix[i][j] elrse a kvetkez:
*((long double *)matrix + i*n + j)
Leegyszerstve: A fordt a tbbdimenzis, statikus tmbt egy akkora egydimen-
zis tmbben helyezi el, melyben annak minden eleme elfr. A tbbdimenzis tmb
mretei, s az indexek segtsgvel ez utn meghatrozza, hogy melyik egydimenzis
tmbelemet jelenti a tbbdimenzis tmbhivatkozs.
9.8 Tmbk, mint fggvnyparamterek
Ha van egy
float vektor[100];
tmbnk, s kezdcmvel meghvjuk az
Fv(vektor)
fggvnyt, akkor a fggvny defincijnak
C programnyelv 197
void Fv(float *v) { /* . . . */ }
vagy
void Fv(float v[]){ /* . . . */ }
mdon kell kinznie.
Az utbbi alakrl tudjuk, hogy a fordt rgtn s automatikusan tkonvertlja az
elz (a mutats) formra.
Ne feledjk, hogy ugyan a vektor konstans mutat a hv fggvnyben, de v (cm-
msolat) mr vltoz mutat a meghvott fggvnyben. Vele teht elvgezhet pldul a
v++ mvelet. A *v, a *(v+i) vagy a v[i] balrtk alkalmazsval a vektor tmb brme-
lyik eleme mdosthat a meghvott fggvnyben.
e Emlkezznk arra is, hogy a meghvott fggvnynek is tudnia kell valahonnt a tmb
mrett! Pldul gy, hogy a mretet is tadjuk paramterknt neki. Az itt elmondottak
tbbdimenzis tmbk vonatkozsban is igazak legalbb is az els mretre, de ott mr
nem tesznk emltst errl!
Ha van egy
float matrix[10][20];
defincink, s az azonostval meghvjuk
Fvm(matrix)
mdon az Fvm fggvnyt, akkor hogyan kell az Fvm defincijnak kinznie? A
void Fvm(float **m) { /* . . . */ }
prblkozs rossz, mert a formlis paramter float mutatra mutat mutat. A
void Fvm(float *m[20]) { /* . . . */ }
vltozat sem j, mert gy a formlis paramter 20 elem, float tpus objektumokra
mutat mutattmb. Ennl a ksrletnl az az igazi problma, hogy a [] opertor prior-
itsa nagyobb, mint *-. Neknk formlis paramterknt 20 float elem tmbre mutat
mutatt kne tadni. Teht a helyes megolds:
void Fvm(float (*m)[20]) { /* . . . */ }
vagy a tradicionlis mdszer szerint:
void Fvm(float m[][20]) { /* . . . */ }
, amibl rgtn s automatikusan ellltja a fordt az elz (a mutats) alakot.
e Meg kell mg emltennk, hogyha a tbbdimenzis tmbt dinamikusan hozzuk
ltre, akkor az elzleg ajnlott megolds nyilvnvalan helytelen. A mtrix hor-
gonypontjt ebben az esetben
float **matrix;
mdon definiljuk, ami ugye float mutatra mutat mutat. Teht ilyenkor a
Fvmd(matrix)
mdon hvott Fvmd fggvny helyes formlis paramtere:
198 MUTATK
void Fvmd(float **m) { /* . . . */ }
Megoldand feladatok:
Ksztsen programot kt mtrix sszeadsra! A mtrixoknak ne dina-
mikusan foglaljon helyet a memriban! A mtrixok mrete azonban csak
futs idben vlik konkrtt.
rjon szoftvert kt mtrix sszeadsra s szorzsra! A mtrixok mrete
itt is futs kzben dl el! A programban hasznljon fggvnyeket
- a mtrix mretnek
- s elemeinek bekrshez, valamint
- a kt mtrix sszeszorzshoz!
A kt utbbi fggvny paramterknt kapja meg a mtrixokat! {XPLU-
SZOR.C}
9.9 Parancssori paramterek
Minden C programban kell lennie egy a programot elindt fggvny-
nek, mely konzol bzis alkalmazsok esetben a main fggvny.
Most s itt csak a main paramtereivel s visszatrsi rtkvel szeret-
nnk foglalkozni! A paramterekrl llthatjuk, hogy:
- elhagyhatak s
- nem ANSI szabvnyosak.
A main legltalnosabb alakja:
int main(int argc, char *argv[]);
A paramterek azonosti bizonyos, C nyelvet tmogat krnyeze-
tekben ettl el is trhetnek, de funkcijuk akkor is vltozatlan marad.
Az argc a main-nek tadott parancssori paramterek szma, melyben az
indtott vgrehajtand program azonostja is benne van, s rtke gy leg-
albb 1.
Az argv a paramter karakterlncokra mutat mutattmb, ahol az e-
gyes elemek rendre:
- argv[0]: A fut program (meghajtnvvel s) ttal elltott azonos-
tjra mutat mutat.
- argv[1]: Az els parancssori paramter karakterlncra mutat mu-
tat.
C programnyelv 199
- argv[2]: Az msodik paramter karakterlnc kezdcme.
- . . .
- argv[argc - 1]: Az utols parancssori paramter karakterlncra
mutat mutat.
- argv[argc]: NULL mutat.
Megjegyezzk, hogy az argc s az argv main paramterek elrhe-
tk az
extern int _argc;
extern char **_argv;
globlis vltozkon t is (STDLIB.H)!
A main lehetsges alakjai a kvetkezk:
void main(void);
int main(void);
int main(int argc);
int main(int argc, char *argv[]);
Vegynk egy pldt!
/* PELDA26.C: Parancssori paramterek. */
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]){
int i=0;
printf("Parancssori paramterek:\n");
printf(Argc rtke %d.\n, argc);
printf(Az tadott parancssori paramterek:\n);
for(i=0; i<argc; ++i)
printf("\targv[%d]: %s\n", i, *argv++);
return 0; }
Ttelezzk fel, hogy a programot a kvetkez parancssorral indtottuk:
PELDA26 elso_par sodik par 3 4 stop!
Ekkor a megjelen kimenet a kvetkez lehet:
Parancssori paramterek:
Argc rtke 6.
Az tadott parancssori paramterek:
argv[0]: C:\C\PELDA26.EXE
argv[1]: elso_par
argv[2]: sodik par
argv[3]: 3
argv[4]: 4
argv[5]: stop!
Beszljnk kicsit a printf utols, *argv++ kifejezsrl! Az argvt
a main paramterknt kapja, teht csak cmmsolat, vagyis a mainben
200 MUTATK
akr el is ronthat. Az argv tpusa char **, s funkcionlisan a parancs-
sori paramter karakterlncok kezdcmeit tartalmaz mutattmb kezde-
tnek cme. A rajta vgrehajtott indirekcival a tpus char * lesz, s pp a
mutattmb els elemt (argv[0]) rjk el. Az uttag ++ opertor miatt
ekzben az argv mr a msodik mutattmb elemre (argv[1]) mutat. El-
rjk ezt is, s mellkhatsknt az argv megint elbbre mutat egy tmbe-
lemmel. Teht a ciklusban rendre vgigjrjuk az sszes parancssori para-
mtert.
e Jusson esznkbe, hogy a main-nek tadott parancssor maximlis
hosszt korltozhatja az opercis rendszer!
A legtbb opercis rendszerben lteznek
vltoz=rtk
alak, n. krnyezeti vltozk, melyek definiljk a krnyezetet (inform-
cit szolgltatnak) az opercis rendszer s a benne fut programok sz-
mra. Pldul a PATH krnyezeti vltoz szokta tartalmazni az alaprtel-
mezett keressi utakat a vgrehajthat programokhoz, a parancsinterpreter
helyt rja el a COMSPEC, s gy tovbb. Az opercis rendszer term-
szetesen lehetsget biztost ilyen krnyezeti vltozk trlsre, megad-
sra, s rtkk mdostsra.
Cbl a krnyezeti vltozk ltalban az STDLIB.Hban deklarlt,
nem ANSI szabvnyos
extern char **_environ;
globlis vltozval rhetk el. Ez karakterlncokra mutat mutattmb, s
a mutatott karakterlncok a vltoz=rtk alak krnyezeti vltozkat r-
jk le. Az utols utni krnyezeti vltoz karakterlncra mutat tmbe-
lem itt is NULL mutat, mint az argvnl.
A globlis vltoz nevt azrt nem rt pontostani a programfejlesz-
t rendszer segtsgbl!
A msik lehetsg az STDLIB.Hban deklarlt, szabvnyos, nem kis
nagybet rzkeny
char *getenv(const char *valtozo);
fggvny, mely visszaad az aktulis krnyezet alapjn a valtozo nev kr-
nyezeti vltoz rtkre mutat mutatt. Ha nincs ilyen vltoz az aktu-
lis krnyezeti tblban, NULL mutatt kapunk. A visszakapott nem
NULL mutatval azonban nem clszer s nem biztonsgos dolog a kr-
nyezeti vltoz rtkt mdostani. Ehhez a nem szabvnyos putenv rutin
hasznlata ajnlott.
C programnyelv 201
e A krnyezeti vltoz nevnek a vgre nem kell kitenni az = jelet,
azaz pldul a PATH krnyezeti vltozt a getenv("PATH") hvssal kr-
dezhetjk le!
Megoldand feladatok:
Ksztsen programot, mely a JANI, fordtsi idben vltoztathat azo-
nostj, krnyezeti vltozrl megllaptja, hogy ltezike! Ha ltezik,
akkor eldnti, hogy rtke kicsi, nagy, vagy ms. A feladat fokozhat
egyrszt gy, hogy a vltoz lehetsges rtkei is legyenek fordtsi id-
ben mdosthatk, msrszt gy, hogy ne rgztsk kettben a lehetsges
rtkek darabszmt! {JANI.C}
rjon szoftvert, mely a krnyezeti vltoz azonostjt s lehetsges rt-
keit parancssori paramterekknt kapja meg, s megllaptsai az elz
pldban megfogalmazottakkal azonosak! Ha a programot paramter nl-
kl indtjk, akkor tjkoztasson hasznlatrl!
Ha expliciten nem deklarljuk void-nak, akkor a main-nek int tpus
sttuszkddal kell visszatrnie az t indt programhoz (process), rend-
szerint az opercis rendszerhez. Konvenci szerint a zrus visszaadott
rtk (EXIT_SUCCESS) hibtlan futst, s a nem zrus sttuszkd
(EXIT_FAILURE 1) valamilyen hibt jelez. Magt a main-bl val
visszatrst (mondjuk 1es sttuszkddal) megoldhatjuk a kvetkez m-
dok egyikvel:
return 1;
exit(1);
Foglalkozzunk kicsit a programbefejezssel is!
9.9.1 Programbefejezs
A return 1 csak a mainben kiadva fejezi be a program futst. Az
STDLIB.H bekapcsolsakor rendelkezsre ll, mindegyik opercis
rendszerben hasznlhat
void exit(int statusz);
void abort(void);
fggvnyek mind befejezik annak a programnak a futst, amiben meg-
hvjk ket akrmilyen mly rutin szintrl is. A statusz paramter rtkt
visszakapja a befejezettet indt (vrakoz szl) program, mint kilpsi
llapotot (exit status). A statusz rtket tveszi persze az opercis rend-
szer is, ha volt a befejezett program indtja. Zrus (EXIT_SUCCESS)
202 MUTATK
llapottal szoks jelezni a norml befejezst. A nem zrus llapot valami-
lyen hibt kzl (EXIT_FAILURE 1).
Az exit fggvny a program befejezse eltt meghv minden regisztrlt
(lsd atexit!) kilpsi fggvnyt, kirti a kimeneti puffereket, s lezrja a
nyitott fjlokat.
Az abort alaprtelmezs szerint befejezi az aktulis programot. Megje-
lenteti pldul az
Abnormal program termination
zenetet az stderren, s aztn SIGABRT (abnormlis programbefeje-
zs) jelet generl. Ha nem rtak kezelt (signal) a SIGABRT szmra, ak-
kor az alaprtelmezett tevkenysg szerint az abort 3as sttuszkddal
visszaadja a vezrlst a szl programnak. Szval nem rti a puffereket,
s nem hv meg semmilyen kilpsi fggvnyt (atexit) sem.
Az stderr a szabvny hibakimenet. Az atexit s a signal fggv-
nyekrl rgtn sz lesz a kvetkez fejezetben!
Megoldand feladatok:
Ksztsen programot, mely neveket olvas a szabvny bemenetrl! Egy
sorban egy nv rkezik, s az res sor a bemenet vgt jelzi. A nv nagybe-
tvel kezddik, s a tbbi karaktere kisbet. A feltteleket ki nem elgt
nv helyett azonnal msikat kell krni a problma kijelzse utn! A neve-
ket rendezze nvsorba, s listzza ki ket lapokra bontva! A feladat a k-
vetkezkpp fokozhat:
- Ha a nvben az angol bcbelieken kvl az kezetes kis s nagy-
betk is megengedettek.
- Ha a neveket kzl listn elrehtra lehet lapozni.
- Ha egy nevet csak egyszer lehet megadni, azaz a msodik bevitelt
elutastja hibaknt a szoftver.
- Ha a programot v parancssori paramterrel indtjk, akkor a ren-
dezs visszafel halad a nvsoron.
- Ha a neveknek dinamikusan foglal helyet, kezdcmeiket mutat-
tmbben helyezi el, s a rendezsnl a mutattmb elemeket cserl-
geti, s nem a nv karakterlncokat a szoftver. {NEVREND.C}
9.10 Fggvny (kd) mutatk
A mutatk fggvnyek n. belpsi pontjnak cmt is tartalmazhatjk,
s ilyenkor fggvny vagy kdmutatkrl beszlnk.
C programnyelv 203
Ha van egy
int fv(double, int);
prototpus fggvnynk, akkor erre mutat mutatt
int (*pfv)(double, int);
mdon deklarlhatunk. A pfv azonost ezek utn olyan vltozt deklarl,
melyben egy double, s egy int paramtert fogad s int-tel visszatr
fggvnyek cmeit tarthatjuk. A pfv teht vltoz kdmutat. Kdmutat
konstans is ltezik azonban, s ez a fggvnynv (a pldban az fv).
e Vigyzzunk a deklarciban a fggvnymutat krli kerek zrjel
pr el nem hagyhatsgra, mert az
int *pfv(double, int);
olyan pfv azonostj fggvnyt deklarl, mely egy double, s egy int pa-
ramtert fogad, s int tpus objektumra mutat mutatval tr vissza. A
problma az, hogy a mutatkpz opertor (*) prioritsa alacsonyabb a
fggvnykpznl (()).
Hogyan lehet rtket adni a fggvnymutatnak?
Termszetesen a szoksos mdokon, azaz hozzrendelssel:
pfv = fv;
, ill. a deklarciban inicializtor alkalmazsval:
int fv(double, int);
int (*pfv)(double, int) = fv;
e Vigyzzunk nagyon a tpussal, mert az most bonyoldott! Csak
olyan fggvny cme tehet be a pfv-be, mely a fggvnymutatval egye-
z tpus, azaz int-et ad vissza, egy double s egy int paramtert fogad
ebben a sorrendben. A
void (*mfv)();
szerint az mfv meg nem hatrozott szm s tpus paramtert fogad
olyan fggvnyre mutat mutat, melynek nincs visszatrsi rtke.
Vegyk szre, hogy a krdses fggvnyek defincija eltt fgg-
vnymutatk inicializlsra is hasznlhat a megadott fggvny protot-
pus!
Hogyan hvhatjuk meg azt a fggvnyt, melynek cmt a kdmutat tar-
talmazza?
204 MUTATK
Alkalmaznunk kell a mutatkra vonatkoz klszablyunkat, ami azt
mondja ki, hogy ahol llhat azonost a kifejezsben, ott llhat (*mutata-
zonost) is. Vegyk el jra az elz pldt! Ha
int a = fv(0.65, 8);
az fv fggvny hvsa, s valamilyen mdon lezajlott a pfv = fv hozzren-
dels is, akkor az
a = (*pfv)(0.65, 8);
ugyanaz a fggvnyhvs.
Itt a pfv-re alkalmaztuk az indirekci opertort (*), de mivel ennek
prioritsa alacsonyabb a fggvnyhvs opertornl (()), ezrt a *pfv-t
kln zrjelbe kellett tenni!
A kdmutatval kapcsolatos alapismeretek letrgyalsa utn felttlenl
ismertetni kell a C fordt fggvnyekkel kapcsolatos fontos viselkedst:
implicit konverzijt!
Ha a kifejezs tpussal visszatr fggvny tpus, akkor hacsak
nem cm opertor (&) mgtt ll, tpussal visszatr fggvnymutat tpu-
sv konvertlja automatikusan s azonnal a fordt.
Ez az implicit konverzi mindenek eltt megvalsul a
uttag-kifejezs(<kifejezslista>)
fggvnyhvsban, ahol az uttag-kifejezsnek kell tpussal visszatr
fggvnycmm kirtkelhetnek lennie. A tpus a fggvnyhvs rtk-
nek tpusa. A dolog praktikusan azt jelenti, hogy a fggvny brmilyen
fggvnyre mutat kifejezssel meghvhat.
Milyen mveletek vgezhetk a kdmutatkkal?
- Kpezhet a cmk.
- sizeof opertor operandusai lehetnek.
- Vgrehajthat rajtuk az indirekci mvelete is, mint lttuk.
- rtket kaphatnak, ahogyan azt az elzekben ismertettk.
- Meghvhatk velk fggvnyek. Ezt is ttekintettk.
- tadhatk paramterknt fggvnyeknek.
- Kdmutattmbk is ltrehozhatk.
- Fggvny visszaadott rtke is lehet.
C programnyelv 205
- Explicit tpuskonverzival ms tpus fggvnymutatkk alaktha-
tk.
e Kdmutatkra azonban nem alkalmazhat a mutataritmetika az e-
gyenlsgi relci opertoroktl (== s !=) eltekintve.
Foglalkozzunk a kdmutat paramterrel!
A fggvnyekre rvnyes implicit tpuskonverzi a fggvnypara-
mterekre is vonatkozik. Ha a paramter tpussal visszatr fggvny, ak-
kor a fordt automatikusan s rgtn tpus tpus rtket szolgltat
fggvnyre mutat mutatv alaktja t.
A kvetkez, kiss elvonatkoztatott pldban kitnen megszemll-
het a kdmutat paramter fggvny prototpusban, ill. fggvny aktu-
lis s formlis paramtereknt.
/* . . . */
long Emel(int);
long Lep(int);
long Letesz(int);
void Munka(int n, long (* fv)(int));
/* . . . */
void main(void){
int valaszt=1, n;
/* . . . */
switch(valaszt){
case 1: Munka(n, Emel); break;
case 2: Munka(n, Lep); break;
case 3: Munka(n, Letesz); }
/* . . . */ }
void Munka(int n, long (* fv)(int)){
int i;
long j;
for(i=j=0; i<n; ++i) j+=(*fv)(i); }
A kdmutat tpusa szerint az ilyen fggvny egy int paramtert fo-
gad, s long rtket szolgltat.
Kdmutatk paramterknt val tadst a Programbefejezs fejezet-
ben mr megemltett, de ott nem trgyalt
9.10.1 atexit fggvny
lersval is szemlltetjk!
#include <STDLIB.H>
int atexit(void (cdecl * fv)(void));
206 MUTATK
Az atexit regisztrlja a paramter fggvnycmet, s norml programbe-
fejezskor az exit meghvja az fv-t a szl programhoz val visszatrs
eltt.
Az fv fggvnymutat paramterbl ltszik, hogy a kilpsi fggv-
nyeknek nincs paramterk, s nem adnak vissza rtket.
Az atexit mindenegyes hvsval ms-ms kilpsi fggvnyt regisztrl-
tathatunk. A regisztrls veremszer, azaz a legutoljra regisztrlt fgg-
vnyt hajtja vgre elszr a rendszer, s aztn gy tovbb visszafel. Az
atexit a heapet hasznlja a fggvnyek regisztrlshoz, s gy a regiszt-
rlhat kilpsi fggvnyek szmt csak a heap mrete korltozza.
Az atexit sikeres hvskor zrust ad vissza, s nem zrust csak akkor ka-
punk tle, ha mr nem tud tbb fggvnyt feljegyezni. Pldul:
#include <stdio.h>
#include <stdlib.h>
void cdecl exitfv1(void){
printf("Exitfv1 vgrehajtva!\n"); }
void cdecl exitfv2(void){
printf("Exitfv2 vgrehajtva!\n"); }
int main(void){
atexit(exitfv1);
atexit(exitfv2);
printf("A main befejezdtt.\n");
return 0; }
A szabvny kimenet a kvetkez:
A main befejezdtt.
Exitfv2 vgrehajtva!
Exitfv1 vgrehajtva!
Folytassuk tovbb a kdmutatk trgyalst!
Azt mondottuk, hogy kdmutatk tmbkben is elhelyezhetk. Vissza-
trve az els pfv-s pldnkhoz! Az
int (*pfvt[])(double, int) = {fv1, fv2, fv3, fv4, fv5};
deklarcival ltrehoztunk egy pfvt azonostj, olyan telem tmbt,
mely int-et visszaad, egy double, s egy int paramtert fogad fggv-
nyek cmeit tartalmazhatja. Feltve, hogy fv1, fv2, fv3, fv4 s fv5 ilyen
prototpus fggvnyek, a pfvt tmb elemeit kezdrtkkel is ellttuk eb-
ben a deklarciban.
Hvjuk mg meg, mondjuk, a tmb 3. elemt!
a = (*pfvt[2])(0.65, 8);
C programnyelv 207
Alaktsuk t fggvnymutat tmbt hasznlv a kdmutat param-
ternl ismertetett pldt!
Az j megoldsunk mainen kvli rsze vltozatlan, a main viszont:
void main(void){
int valaszt=1, n;
long (*fvmt[])(int) = {Emel, Lep, Letesz};
/* . . . */
Munka(n, fvmt[valaszt]);
/* . . . */ }
A kdmutat visszatrsi rtkhez elemezzk ki a kvetkez fggvny
prototpust!
void (*signal(int jel, void (* kezelo)(int)))(int);
A signal els paramtere int, a msodik (void (* kezelo)(int)) viszont
rtket vissza nem ad, egy int paramtert fogad fggvnymutat tpus.
Kitnen ltszik ezek utn, hogy a visszatrsi rtk void (*)(int), azaz
rtket nem szolgltat, egy int paramtert fogad fggvnymutat. A
visszaadott rtk tpusa teht a signal msodik paramternek tpusval
egyezik.
A SIGNAL.H fejfjlban elhelyezett prototpus signal fggvnnyel
klnben a program vgrehajtsa sorn bekvetkez, vratlan esemnye-
ket (megszakts, kivtel, hiba stb.), n. jeleket lehet lekezeltetni. Tbbf-
le tpus jel ltezik. A void (*)(int) tpus kezelfggvnyt a manipullni
kvnt jelre kln meg kell rni. A signal rutinnal hozzrendeltetjk a ke-
zelt (2. paramter) az els paramter tpus jelhez, s a signal az eddigi
kezel cmvel tr vissza.
Egy bizonyos tpus fggvnymutat explicit tpuskonverzival
(tpusnv) eltag-kifejezs
talakthat ms tpus kdmutatv. Ha az e mdon tkonvertlt mutat-
val fggvnyt hvunk, akkor a hats a programfejleszt rendszertl, a
hardvertl fgg. Viszont, ha visszakonvertljuk az talaktott mutatt az
eredeti tpusra, akkor az eredmny azonos lesz a kiindulsi fggvnymu-
tatval.
Szedjk csak megint el az
int fv(double, int), a;
int (*pfv)(double, int) = fv;
pldnkat, s legyen a
void (*vpfv)(double);
vpfv=(void (*)(double))pfv;
208 MUTATK
A
(*vpfv)(0.65);
eredmnyessge elgg megkrdjelezhet, de a
pfv=(int (*)(double, int))vpfv;
utn teljesen rendben lesz a dolog:
a=(*pfv)(0.65, 8);
Emlkezznk csak! Explicit tpusmdostott kifejezs nem lehet
balrtk.
Foglalkozzunk csak jra egy kicsit a tpusnevekkel!
9.10.2 Tpusnv
Explicit tpusmdostsban, fggvnydeklartorban a paramtertpus
rgztsekor, sizeof operandusaknt stb. szksg lehet a tpus nevnek
megadsra. Ehhez kell a tpusnv, mely szintaktikailag a krdses tpus
objektum olyan deklarcija, melybl elhagytk az objektum azonostjt.
tpusnv:
tpusspecifiktor-lista<absztrakt-deklartor>
absztrakt-deklartor:
mutat
<mutat><direkt-absztrakt-deklartor>
direkt-absztrakt-deklartor:
(absztrakt-deklartor)
<direkt-absztrakt-deklartor>[<konstans-kifejezs>]
<direkt-absztrakt-deklartor>(<paramter-tpus-lista>)
Az absztrak-deklartorban mindig lokalizlhat az a hely, ahol az azo-
nostnak kne lennie, ha a konstrukci deklarcin belli deklartor len-
ne.
Lssunk nhny konkrt pldt!
int *
int tpus objektumra mutat mutat.
int **
int tpus objektumra mutat mutatra mutat mutat.
int *[]
Nem meghatrozott elemszm, int tpus mutattmb.
int *()
C programnyelv 209
Ismeretlen paramterlistj, intre mutat mutatval visszatr fgg-
vny.
int (*[])(int)
int tpussal visszatr, egy int paramteres, meghatrozatlan elemszm
fggvnymutat tmb.
int (*(*())[])(void)
Ismeretlen paramterezs, int tpussal visszatr fggvnymutatkbl
kpzett, meghatrozatlan mret tmbre mutat mutatt szolgltat, para-
mterrel nem rendelkez fggvny.
A problmn: a sok zrjelen, a nehezen rthetsgen typedef alkalma-
zsval lehet segteni.
9.11 Tpusdefinci (typedef)
Az elemi tpusdefincirl sz volt mr a TPUSOK S KONSTAN-
SOK szakasz vgn. Az ott elmondottakat nem ismteljk meg, viszont
annyit jra szeretnnk tisztzni, hogy:
A tpusdefinci nem vezet be j tpust, csak ms mdon megadott
tpusok szinonimit lltja el. A typedef nv, ami egy azonost, szintak-
tikailag egyenrtk a tpust ler kulcsszavakkal, vagy tpusnvvel.
A tpusdefinci bonyoltshoz elszr azt emltjk meg, hogy a
typedef tpus azonost;
szerkezetben az azonost a priorits sorrendjben lehet:
- azonost(): fggvny tpust kpz, uttag opertor. Pldul:
typedef double dfvdi(double, int);
dfvdi hatvany;
, ahol a hatvany egy double, s egy int paramtert fogad s doub-
le-t visszaad fggvny azonostja.
- azonost[]: tmb tpust kpz, uttag opertor. Pldul:
typedef double dtomb[20];
dtomb t;
, ahol a t 20 double elembl ll tmb azonostja.
- *azonost: mutat tpust kpz, eltag opertor. Pldul:
typedef short *shptr;
shptr sptr;
, ahol az sptr short tpus objektumra mutat mutat azonostja.
210 MUTATK
- Ezek az opertorok egyszerre is elfordulhatnak az azonost-val.
Pldul:
typedef int *itb[10];
itb tomb;
, ahol a tomb 10 elem int objektumokra mutat mutattmb azo-
nostja.
Megemltend mg, hogy az elzek alkalmazsval csnjn kell
bnni, hisz az gy tpusdefinilt azonostknak ppen a jellege (fggvny,
tmb, mutat) veszik el.
A tpusdefinci tovbbi komplexitsa abbl fakad, hogy a
typedef tpus azonost;
szerkezetbeli tpus korbbi typedef tpus azonost;-ban definilt azono-
st is lehet. Teht a tpusdefincival ltrehozott tpuspecifiktor tpus le-
het egy msik tpusdefinciban.
Nzznk nhny pldt!
typedef int *iptr;
typedef char nev[30];
typedef enum {no, ferfi, egyeb} sex;
typedef long double *ldptr;
ldptr ptr2; /* long double objektumra mutat mutat.*/
ldptr fv2(nev);/*30 elem karaktertmb paramtert fogad,
long double objektumra mutat mutatval
visszatr fggvny. */
typedef iptr (*ipfvi)(sex);
ipfvi fvp1; /* int-re mutat mutatt visszaad, egy
sex tpus enum paramtert fogad
fggvnyre mutat mutat. */
typedef ipfvi ptomb[5];
ptomb tomb; /* 5 elem, int-re mutat mutatt
szolgltat, egy sex tpus paramtert
fogad fggvnyre mutat mutattmb. */
iptr fugg(ptomb);/*int-re mutat mutatt visszaad, 5
elem, int-re mutat mutatval
visszatr, egy sex enum paramteres
fggvnyre mutat mutattmbt
paramterknt fogad fggvny. */
A tpusdefincival a program tpusai parametrizlhatk, azaz a
program portbilisabb lesz, hisz az egyetlen typedef mdostsval a t-
pus megvltoztathat. A komplex tpusokra megadott typedef nevek ezen
kvl javtjk a program olvashatsgt is.
e Loklis szinten megadott tpusdefinci loklis hatskr is. Az l-
talnosan hasznlt tpusdefincikat globlisan, a feladathoz tartoz fej-
fjlban szoktk elrni.
C programnyelv 211
Egy utols krds: Mikor ekvivalens kt tpus?
- Ha a kt tpusspecifiktor-lista egyezik, belertve azt is, hogy
ugyanaz a tpusspecifiktor tbbflekppen is megadhat. Pldul: a
long, a long int s a signed long int azonosak.
- Ha az absztrakt-deklartoraik a typedef tpusok kifejtse, s br-
mely fggvnyparamter azonost trlse utn ekvivalens tpusspe-
cifiktor-listkat eredmnyeznek.
e A tpusekvivalencia meghatrozsnl a tmbmretek s a fgg-
vnyparamter tpusok is lnyegesek.
9.12 Ellenrztt bemenet
Jegyzetnkben minden feladat megoldsban azt sugalltuk, hogy:
` A programnak ellenriznie kell a bemenett. Ez a vizsglat term-
szetesen csak a konkrt adatok ismerete nlkl a lehetetlensgek, s a
problmt okoz rtkk kiszrsre szortkozhat. Pldul: Ne etessnk
kt tonns kutyt! Ne folystsunk nyugdjat 300 ves embernek!
Nem tekinthet, csak legfeljebb mkedvel, programnak az, ami egy v-
letlenl elgpelt informci miatt feldobja a talpt!
rjon int getint(int *) fggvnyt, mely ellenrztten beolvas egy egsz
szmot a billentyzetrl gy, hogy a nem megengedett karaktereket nem
is echzza a karakteres kpernyn (ablakban). A szm eltti fehr karakte-
rek kzl az Entert soremelssel, s minden ms fehr karakter szkz-
zel echzand! Ezutn egy opcionlis eljelet kveten mr csak szm-
jegy karakterek kvetkezhetnek. Ha az els szmjegy zrus, akkor tovbbi
szm karakterek sem jhetnek. A fggvny legyen portbilis, azaz m-
kdjn 16 s 32 bites intre egyarnt! Ez azt jelenti 16 bites esetre, hogy
legfeljebb t szmjegyet echzhat, de legyen tekintettel az brzolsi kor-
ltokra is! Ha az els 4 szmjegy 3276nl nagyobb, akkor tbb szmje-
gyet mr nem fogadhat. Ha az els 4 szmjegy pontosan 3276, akkor t-
dik szmjegyknt nem fogadhatja a fggvny a 9et, s a 8at is csak nega-
tv egsz szm esetn. A szm megadst fehr karakterrel, Ctrl+Zvel
vagy F6tal kell lezrni. A fehr karaktert a mr lert mdostott ech utn
vissza kell adni a hvnak. Ctrl+Z vagy F6 esetn viszont EOF szolglta-
tand. A beolvasott egsz rtk konvertland s elhelyezend a param-
ter cmen! A cmen lev rtk azonban nem vltozhat meg, ha nem adtak
meg egyetlen szmjegy karaktert sem.
A rutin persze rvid programmal ki is prbland!
212 MUTATK
A feladat megoldshoz szksgnk van kt konzolkezel fggvnyre.
Az
int putch(int c);
rutin a c karaktert rja ki kzvetlenl (pufferezs nlkl) a konzol kper-
nyre (ablakba) az aktulis pozcitl, aktulis sznben s megjelensi att-
ribtumokkal, s a kurzort eggyel elbbre lltja. Sikeres esetben a vissza-
kapott rtk maga a c karakter. A sikertelensget viszont EOF-fal jelzi a
fggvny.
Kivitelkor nincs transzlci, azaz a fggvny az LF ('\n') karakterbl
nem llt el CR-LF ("\r\n") karakter prt.
Megoldsunkban nem foglalkozunk majd a putch hibakezelsvel,
mert felttelezzk, hogyha az opercis rendszer mkdik, akkor a konzol
megy.
int getch(void);
Ech nlkl beolvas egyetlen karaktert a konzolrl (billentyzet), s ezt
szolgltatja a hvnak. A bejv karakter rgtn rendelkezsre ll, s nincs
pufferezs soremels karakterig. Funkci vagy nyl billenty letsekor a
fggvnyt ktszer kell hvni, mert az els hvs zrussal tr vissza, s a m-
sodik szolgltatja az aktulis gomb kdjt. A rutinnak nincs hibs vissza-
trse.
E fggvnyek nem szabvnyosak, de szinte minden opercis rend-
szerben rendelkezsre llnak kisebbnagyobb eltrsekkel a CONIO.H
fejfjl bekapcsolsa utn.
/* PELDA27.C: Egszek beolvassa s visszarsa gy, hogy
az rvnytelen karakterek echja meg sem trtnik.*/
#include <stdio.h>
#include <conio.h>
#include <limits.h>
#if SHRT_MAX == INT_MAX
#define HOSSZ 4
#else
#define HOSSZ 9
#endif
#define F6 64
#define CTRLZ 26
#define MAX INT_MAX/10
#define HATAR INT_MAX%10+'0'+1
A HOSSZ makr azt a szmjegy mennyisget rgzti 16, s 32 bites
intre, ameddig mg nem kell foglalkozni a megadott szm karakter rt-
kvel.
C programnyelv 213
A MAX maga az a HOSSZ szmjegy rtk, amihez mg egy jegyet
tve elrhet, de tl nem lphet a fels, vagy az als brzolsi korlt. 16
bites intnl ez az rtk 3276, amihez pozitv irnyban legfeljebb 7, s ne-
gatv irnyban maximum 8 jhet.
A HATAR az a szmjegy karakter, ami mg negatv egsz esetben el-
fordulhat MAXot kveten megadhat karakterknt a HOSSZ+1. poz-
cin. 16 bites int szmra ez az rtk 8.
int getint(int *pn){/* Egsz beolvassa a bemenetrl. */
int c, /* A beolvasott karakter. */
sign=1, /* Eljel: pozitv +1, negatv -1. Alapr-
telmezs a pozitv, a kezdrtk miatt. */
elojel=0, /* Volt-e mr eljel? */
hossz=0, /* A beolvasott szmjegy karakterek szma. */
null=0; /* A beolvasott szm zrus-e? */
while(!hossz) switch(c=getch()){
case ' ':
case '\t':
case '\r': if(!elojel)
if(c!='\r')putch(' ');
else {putch('\n'); putch('\r'); }
break;
case '+':
case '-': if(!elojel){
putch(c); sign=(c=='+')?1:-1; ++elojel; }
break;
case '0': if(!elojel){
putch(c); *pn=0; ++hossz; null=1;}
break;
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
putch(c); *pn=c-'0'; ++hossz;
break;
default: if(!c)c=getch();
if(c==CTRLZ||c==F6) return EOF; }
A getint lnyegben kt while ciklusra bonthat, melyek mindegyike
egyegy switch. Az els addig tart, mg
- egy szmjegy karaktert meg nem adnak, vagy
- Ctrl+Zvel, ill. F6tal le nem zrjk a bemenetet.
Az els switch:
- Vgrehajtja a fehr karakterekre elrt echt, de csak akkor, ha el-
jel karakter mg nem volt. Magyarn eljel utn nincs mr ech a
fehr karakterekre.
214 MUTATK
- Az eljelet echzza a rutin, ha korbban mg nem rkezett, s rt-
kt megjegyzi a sign vltozban. Bejelli azt is, hogy volt mr el-
jel, hogy mg egyet ne tudjanak megadni.
- Az els szm karaktert echzza a fggvny, konvertlva kiteszi a
paramter cmre, s a hossz vltozban szmllja is. Eljel utn
nem enged mr meg zrust gpelni, ill. ha megadhat volt a nulla,
akkor bejelzi bejvetelt a null vltozba.
- A default gon jabb olvass kveti az elz zrus berkezst. Az
F6 msknt vizsglhat sem lenne.
while(1) switch(c=getch()){
case ' ':
case '\t':
case '\r':if(c!='\r')putch(' ');
else {putch('\n'); putch('\r'); }
*pn*=sign; return c;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
if(!null&&(hossz<HOSSZ||
(hossz==HOSSZ&&(*pn<MAX||*pn==MAX&&
(sign==1&&c<HATAR||sign!=1&&c<=HATAR))))){
putch(c);
*pn=*pn*10+c-'0';
++hossz; }
break;
default: if(!c)c=getch();
if(c==CTRLZ||c==F6){
*pn*=sign;
return EOF;} } }
void main(void){
int i;
printf("Egszek beolvassa CTRL+Z-ig.\n");
while(getint(&i)!=EOF) printf("%20d\n\r", i); }
A msodik while
- fehr karakterrel, vagy
- Ctrl+Zvel, ill. F6tal
zrul. A paramter cmen lev konvertlt rtket eljelhelyess teszi a
rutin, majd visszatr a ki is echzott, fehr karakterrel, vagy az EOFfal.
A szmjegy karakter echja, konverzija s szmllsa csak akkor trt-
nik meg, ha az els szm nem zrus volt s:
- HOSSZnl kevesebb karaktert adtak meg eddig, vagy
C programnyelv 215
- pp annyit, de a paramter cmre konvertlt rtk kisebb MAXnl,
ill. pont MAX s az utols szmjegy karakter megfelel az elrt, szi-
gor feltteleknek.
Megoldand feladat:
rja gy t a getint fggvnyt, hogy a visszatrls (backspace) gombot
funkcija szerinti mdon kezelni tudja!
Remlhetleg mindenki el tudja kpzelni, hogy tovbb bonyoldna
a dolog, ha tovbbi szerkeszt billentyk (Delete, Insert, balra nyl s
jobbra nyl) hasznlatt is megengednnk, vagy Uram, bocs lebeg-
pontos rtk bekrst vgeznnk s nem egszt.
Magyarn: kitnen ltszik, hogy tbbe kerlne a leves, mint a hs.
sszefoglalva: A bemenet ellenrzst sem szabad tlzsba vinni, de az
klszablynl rott elveket a j programnak be kell tartania.
216 STRUKTRK S UNIK
10 STRUKTRK S UNIK
A struktra s az uni aggregtum. Egy vagy tbb, esetleg klnbz t-
pus vltoz (elnevezett tag) egyttese, melynek nll azonostja van.
A struktrt ms nyelvben rekordnak nevezik. Azt teszi lehetv, hogy a
valamilyen mdon sszetartoz vltozk egsz csoportjra egyetlen nv-
vel hivatkozhassunk, azaz hogy a vltozcsoport kezelse egyszerbb le-
gyen.
Tulajdonkppen minden struktrval s unival j, sszetett, fel-
hasznli adattpust hozunk ltre.
Az ANSI szabvny megengedi, hogy a struktrkat t lehessen msolni
egymsba, hozz lehessen rendelni, s tadhatk legyenek fggvnyek-
nek, ill. rutinok visszatrsi rtke is lehessen struktra. Kpezhet term-
szetesen a struktra cme (&), mrete (sizeof), s benne lehet explicit t-
pusmdost szerkezetben is, de
e a struktrk nem hasonlthatk ssze.
A struktrban felsorolt vltozkat struktratagoknak (member) neve-
zik. Struktratag kis megszortsokkal - melyre ksbb kitrnk - akrmi-
lyen tpus lehet. Lehet alap s szrmaztatott tpus brmilyen sorrend-
ben.
A deklarcibeli tpusspecifiktor egyik alternatvja a
struktra-vagy-uni-specifiktor:
struktra-vagy-uni<azonost>{struktratag-deklarcilista}
struktra-vagy-uni azonost
struktra-vagy-uni:
struct
union
A struktratag-deklarcilista struktra, ill. unitag deklarcik soroza-
ta:
struktratag-deklarcilista:
struktratag-deklarci
struktratag-deklarcilista struktratag-deklarci
struktratag-deklarci:
tpusspecifiktor-lista struktra-deklartorlista
tpusspecifiktor-lista:
tpusspecifiktor
tpusspecifiktor-lista tpusspecifiktor
struktra-deklartorlista:
struktra-deklartor
struktra-deklartorlista, struktra-deklartor
C programnyelv 217
A struktra-deklartor tbbnyire a struktra, ill. az uni egy tagjnak
deklartora. A struktratag azonban meghatrozott szm bitbl is llhat,
azaz lehet n. bitmez (bit field) is, mely a nyelvben struktrkon kvl
nem is hasznlhat msutt. A mez bitszlessgt a kettspontot kvet,
egsz rtk konstans-kifejezs hatrozza meg.
struktra-deklartor:
deklartor
<deklartor>: konstans-kifejezs
A bitmezvel s az unival mg ebben a szakaszban foglalkozunk!
10.1 Struktradeklarci
Alakja teht a kvetkez:
<trolsi-osztly-specifiktor> struct <struktracmke> <{
struktratag-deklarcilista }> <azonostlista>;
Pldul:
struct datum{
int ev, ho, nap, evnap;
long datumssz; /* Dtumsorszm. */
char datumlanc[11]; }
d, dptr, dt[10]; /* Azonostlista. */
, ahol:
- A trolsi-osztly-specifiktor elhagysval, megadsval s ennek
rtelmezsvel nem foglalkozunk jra!
- A datum azonost ennek a struktrnak a cmkje (struktracm-
ke), mely azt biztostja, hogy ksbb struct datum mdon hivatkoz-
ni tudjunk a felhasznli tpusra. Pldul:
struct datum *sptr =
(struct datum *)malloc(sizeof(struct datum));
- Az ev, a ho, a nap s az evnap a struct datum tpus struktra int
tpus tagjainak, a datumssz a long tpus tagjnak s a datumlanc
a struktra char* tpus tagjnak az azonosti. A tagneveknek csak
a struktrn bell kell egyedieknek lennik, azaz a tagazonostk
nyugodtan egyezhetnek pldul ms kznsges vltozk neveivel,
vagy a struktracmkkkel.
- A d struct datum tpus vltoz, a dptr s az sptr struct datum t-
pus objektumra mutat mutatk, s a dt tz, struct datum tpus
elembl ll tmb azonostja, azaz a dt struktratmb.
- A fordt a struktrnak ppen annyi helyet foglal a memriban,
hogy benne a struktra minden tagja elfrjen. A struktratagok a
218 STRUKTRK S UNIK
deklarci sorrendjben, folyamatosan nvekv cmeken helyezked-
nek el, s gy a struktradefinciban ksbb deklarlt tag cme min-
dig nagyobb.
Az azonostlista nlkli struktradeklarcit, ahol van struktra-
tag-deklarcilista, azaz megadott vlik a struktra szerkezete, szoks
struktradefincinak is nevezni, ugyan nincs memriafoglalsa.
- Minden struktradeklarci egyedi struktra tpust hoz ltre, s gy
struct A {
int i, j;
double d; } a, a1;
struct B {
int i, j;
double d; } b;
az a s az a1 objektumok struct A tpus struktrk, de az a s a b
objektumok klnbz struktra tpusak annak ellenre is, hogy a
kt struktra szerkezete azonos.
- Az azonostlista nlkli, de struktracmkvel s tag-deklarci-
listval elltott struktradefinci nem foglal ugyan helyet a mem-
riban, de biztostja azt a lehetsget, hogy a struktradeklarci ha-
tskrben ksbb ilyen tpus struktrval azonostlistt is meg-
adva helyet foglalhassunk vltozinknak, mutatinknak s tmbje-
inknek. Pldul:
struct datum{
int ev, ho, nap, evnap;
long datumssz; /* Dtumsor-
szm. */
char datumlanc[11]; };
/* . . . */
struct datum d, *dptr=&d, dt[10];
Fedezzk fel, hogy a felhasznl definilta tpusnv struct datum.
Hasonltsul:
double d, *dptr=&d, dt[10];
e Struktra, uni, enum deklarcit, defincit zr kapcsos zrjel
utn ktelez pontosvesszt tenni, mert ez zrja az azonostlistt!
struct struki{
int a, b;
float matrix[20][10];
char nev[26]; }; /* Itt nem elhagyhat a ; a } utn! */
- A struktracmknek egyedinek kell lennie a struktra, uni s
enum cmke nvterleten!
C programnyelv 219
- Mint a tmbknl, struktrknl is megadhat nem teljes tpusdek-
larci. Pldul a
struct datum;
mg akkor is ltrehozza az aktulis hatskrben a struct datum
nem teljes tpust, ha ilyen befoglal, vagy kls hatskrben is l-
tezne. Knnyen belthat, hogy ez struct datum tpus struktra
objektum defincijra nem hasznlhat a struktra szerkezetnek
kzbens, ugyanezen hatskrbeli definilsa nlkl, hisz ismeret-
len a memriaigny. Arra azonban ez is alkalmas, hogy deklarci-
ban, typedefben hasznljuk a tpusnevet, vagy hogy struct datum
tpus objektumokra mutat mutatkat hozzunk ltre:
struct datum *dptr1, *dptr2, *dptrt[20];
Az ilyen mutatk akr ms struktra tagjai is lehetnek:
struct A; /* Nem teljes tpusdeklarci. */
struct B{ /* Itt tag a nem tejes tpusra */
struct A *pa;};/* mutat mutat. */
struct A{
struct B *pb;};/* Ez most mr teljes tpus
lesz.*/
e Vigyzat! Struktradefinciban a struktra tpusa a struktra-tag-
deklarcilistban csak akkor vlik teljess, ha elrjk a specifiktor be-
zr kapcsos zrjelt (}).
- A struktradeklarci ltalnos alakjbl lthat volt, hogy belle a
struktracmke is elhagyhat. Ha ezt megtesszk, n. nv nlkli,
vagy cmkzetlen struktrhoz jutunk. Vilgos, hogy ebben az eset-
ben a nem teljes tpusdeklarcinak
struct;
semmi rtelme (szintaktikai hiba is) sincs, de az olyan deklarci-
nak sincs, amiben csak a struktra szerkezett adjuk meg:
struct {int tag1, tag2; /* ... */};
hiszen ksbb nem tudunk a tpusra hivatkozni, s ebbl kvetkez-
leg ilyen tpus objektumokat deklarlni. Nv nlkli struktradek-
larciban nem hagyhat el teht az azonostlista, azaz:
struct {int tag1, tag2; /* ... */} az1, az2[14];
10.1.1 Tpusdefinci
- Az elbb vzolt problma tpusdefinci alkalmazsval thidalha-
t:
220 STRUKTRK S UNIK
typedef struct{ int tag1, tag2; /* ... */} CIMKETLEN;
/* Most sincs cmke. */
CIMKETLEN y, *y, ytomb[12];
- A tpusdefinci a cmkzett struktrval is hasznlhat lett volna:
typedef struct datum{
int ev, ho, nap, evnap;
long datumssz; /* Dtumsor-
szm. */
char datumlanc[11]; } DATUM;
/* . . . */
DATUM d, *dptr, dt[10];
e sszestve: A typedef cmke nlkli struktrk, unik s enum-ok
tpusdefincijra is alkalmas. Struktrk esetben hasznljunk azonban
struktracmkt, vagy typedef-es szerkezetet, de a kettt egytt nem java-
soljuk!
- Egy kicsit sszetettebb pldt vve:
typedef char nev[30];
typedef enum{no, ferfi, egyeb} sex;
typedef struct{
nev csalad, kereszt; /* Kt 30 elem karak-
tertmb.*/
sex fino; /* no vagy ferfi rtk
enum.*/
/* . . . */
double osztondij; } hallgato;
typedef hallgato evf[100];/* 100 elem, fenti szerke-
zet struktratmb. */
evf evf1, evf2, evf3; /* Hrom darab,100 elem, fenti
szerkezet struktratmb.
*/
10.2 Struktratag deklarcik
A { }-ben ll struktratag-deklarcilista a deklartor szintaktikt k-
vetve meghatrozza a struktratagok neveit s tpusait.
- A struktratag brmilyen tpus lehet a void, a nem teljes, vagy a
fggvny tpustl eltekintve.
e A struktratag deklarci nem tartalmazhat azonban trolsi osztly
specifiktort vagy inicializtort. Struktratag nem lehet az ppen definci
alatt ll struktra sem:
struct szoszlo{
static char *szo; /* HIBS */
int szlo=0; /* HIBS */
struct szoszlo elozo, kovetkezo; }; /* HIBS */
C programnyelv 221
- Struktratag lehet azonban nem teljes tpus struktrra, gy akr az
ppen deklarci alatt llra mutat mutat:
struct szoszlo{
char *szo;
int szlo;
struct szoszlo *elozo, *kovetkezo; }; /* OK
*/
- Struktratag lehet tmb, st mr definilt szerkezet struktra is:
struct sor_lanc{
int sorszam;
char megjegyzes[32];
struct sor_lanc *kovetkezo; };
struct kereszthivatkozas{
char *szo;
int szlo;
struct kereszthivatkozas *elozo, *kovetkezo;
struct sor_lanc elso; };
- A struktrnak nem lehet fggvny tagja, de fggvnyre mutat mu-
tat persze lehet tag:
struct pelda{
char *szoveg;
int (*hasonlit)(const char *, const char *);};
- A struktratag azonostjnak egy struktrn bell kell egyedinek
lennie, vagyis msik struktrban nyugodtan ltezhet ugyanilyen
nev tag.
- A begyazott struktra ugyangy elrhet, mint a fjl hatskrben
deklarlt, azaz a kvetkez plda helyes:
struct a{
int x;
struct b{
int y; } v2;
} v1;
/* . . . */
struct a v3;
struct b v4;
- A begyazott struktra gyakran nvtelen:
struct struki{
struct { int x, y; } pont;
int tipus; } v;
222 STRUKTRK S UNIK
10.3 Struktrk inicializlsa
A struktrt konstans kifejezsekbl ll inicializtorlistval lthatjuk el
kezd rtkkel. Az inicializtorlista elemek rtkt a struktratagok a dek-
larcibeli elhelyezkeds sorrendjben veszik fel:
struct struki {
int i;
char lanc[25];
double d; } s = {20, Jancsika, 3.14};
Pontostsunk mg nhny dolgot!
- Loklis lettartam struktrk esetn az inicializtor inicializtorlis-
ta, vagy kompatibilis struktra tpus egyszer kifejezs lehet:
struct struki s = {20, Juliska, 3.14}, s1 = s;
- Loklis (auto) struktra persze akr ilyen tpus struktrt vissza-
ad fggvny hvsval is inicializlhat:
struct struki fv(int, char *, double);
struct struki s2=fv(2, Boszi, 1.4);
- Ha a struktrnak struktra vagy tmb tagja is van, akkor azt egy-
msba gyazott { }-kel lehet inicializlni.
struct struki {
int i;
long darab[3];
double d; } s = { 20, { 1l, 2l, 3l}, 3.14};
- Tudjuk, hogy az inicializtorlista elemeinek szma nem haladhatja
meg az inicializland struktratagok szmt! Ha az inicializtorlis-
ta kevesebb elem, mint az inicializland objektumok szma, ak-
kor a maradk struktratagok a statikus lettartam implicit kezd-
rtk ads szablyai szerint tlti fel a fordt, azaz nullzza:
struct struki{
int cipomeret, /* s.cipomeret==42 */
magassag; /* s.magassag==180 */
char nev[26]; /* az s.nev Magas Lajos */
char cim[40]; /* s.cim res karakterlnc ()
kezdrtk. */
double fizetes;/* s.fizetes==0.0. */
} s = { 42, 180, Magas Lajos};
- Nvtelen bitmez tag nem inicializlhat!
Ha az inicializtorlistban nincs begyazott inicializtorlista, akkor
az ott felsorolt rtkek az alaggregtumok, s ket a deklarci sorrendj-
ben veszik fel az aggregtum elemei. Kapcsos zrjelek ugyanakkor akr
az egyes inicializtorok kr is tehetk, de ha a fordtt nem kvnjuk "be-
C programnyelv 223
csapni", akkor clszer ket az aggregtum szerkezett pontosan kvetve
hasznlni!
typedef struct { int n1, n2, n3; } triplet;
triplet nlist1[2][3] = { /* Helyes megolds: */
{{11, 12, 13}, {4, 5, 6}, {7, 18, 9}},/* Els sor. */
{{1, 2, 3}, {14, 15, 16}, {7, 8, 9}} /* 2. sor. */ };
triplet nlist2[2][3] = { /* Hibs megolds: */
{11, 12, 13}, {4, 5, 6}, {7, 18, 9}, /* Els sor. */
{1, 2, 3}, {14, 15, 16}, {7, 8, 9} /* 2. sor. */ };
A sizeof-ot struktrkra alkalmazva mindig teljes mretet kapunk akr a
tpust adjuk meg operandusknt, akr az ilyen tpus objektumot. Pldul:
#include <stdio.h>
struct st{
char *nev; /* A mutat mrete bjtban. */
short kor; /* + 2 bjt. */
double magassag; }; /* + 8 bjt. */
struct st St_Tomb[ ] = {
{Jancsika, 18, 165.4}, /* St_Tomb[0] */
{Juliska, 116, 65.4}}; /* St_Tomb[1] */
int main(void){
printf(\nSt_Tomb elemeinek szma = %d\n,
sizeof(St_Tomb)/sizeof(struct st);
printf(\nSt_Tomb egy elemnek mrete = %d\n,
sizeof(St_Tomb[0]));
return 0; }
10.4 Struktratagok elrse
A struktra s az unitagok elrshez ugyanazokat a tagelrs oper-
torokat alkalmazza a nyelv. A tagelrs opertort szelekcis opertornak,
tagszelektornak is szoks nevezni. Prioritsuk magasabb az egyoperandu-
sos mveleteknl, s kzvetlenl a () s a [] utn kvetkezik. Ktfajta tag-
elrs opertor van:
- az egyik a kzvetlen szelekcis opertor (.) s
- a msik a kzvetett (->).
A kzvetlen tagelrs opertor alakja:
uttag-kifejezs.azonost
Az uttag-kifejezsnek struktra tpusnak, s az azonostnak e struktra
tpus egy tagja nevnek kell lennie. A konstrukci tpusa az elrt tag tpu-
sa, rtke az elrt tag rtke, s balrtk akkor s csak akkor, ha az uttag-
kifejezs az, s az azonost nem tmb.
A kzvetett tagelrs opertor formja:
uttag-kifejezs->azonost
224 STRUKTRK S UNIK
Az uttag-kifejezsnek struktra tpusra mutat mutatnak, s az azonost-
nak e struktra tpus egy tagja nevnek kell lennie. A konstrukci tpusa
s rtke az elrt tag tpusa s rtke. Balrtk, ha az elrt tag nem tmb.
Feltve, hogy s struct S tpus struktra objektum, s sptr struct S t-
pus struktrra mutat mutat, akkor ha t az struct S struktrban dekla-
rlt, tpus tpus tag, az
s.t
s az
sptr->t
kifejezsek tpusa tpus, s mindkett a struct S struktra t tagjt ri el. A
kvetkezk pedig szinonimk, ill. azt is mondhatjuk, hogy a > szelekci
opertoros kifejezs a msik rvidtse:
sptr->t (*sptr).t
Az s.t s az sptr->t balrtkek, feltve, hogy t nem tmb tpus. Pldul:
struct S{
int t;
char lanc[23];
double d; } s, *sptr = &s, Stomb[20]={
{ 0, nulla, 0.}, { 1, egy, 1.}};
/* . . . */
s.t = 3;
sptr->d = 4.56;
- Az Stomb 20 elem, struct S struktrbl ll struktratmb,
melynek els (Stomb[0]) s msodik (Stomb[1]) elemt kivve
nincs explicit kezdrtke, azaz Stomb[2], . . ., Stomb[19] { 0, ,
0,} rtk. A kvetkez pldk a struktratmb tagelrst szemll-
tetik:
Stomb[3].t=3;
strcpy(Stomb[3].lanc, hrom);
Stomb[3].d=3.3;
vagy:
sptr=Stomb+5;
sptr->t=5; /* Stomb[5].t */
strcpy(sptr->lanc, t); /* Stomb[5].lanc */
sptr->d=5.5; /* Stomb[5].d */
- Ha struct B struktrnak van struct A struktra tpus tagja, akkor
az ilyen struct A tagokat csak a tagszelekcis opertorok ktszeri
alkalmazsval lehet elrni:
struct A {
C programnyelv 225
int j;
double x; };
struct B {
int i;
char *nev;
struct A a;
double d; } s, *sptr = &s;
/* . . . */
s.i = 3;
s.a.j = 2;
sptr->d = 3.14;
(sptr->a).x = 6.28;
- A szelekcis opertorok balrl jobbra ktnek, teht a kvetkezk
teljesen azonosak:
(sptr->a).x sptr->a.x;
(s.a).x s.a.x;
- Emltettk mr, hogy a tagszelektorok prioritsa magasabb az egy-
operandusos mveleteknl. Ezrt a
++sptr->i ++(sptr->i)
, azaz a kifejezs struct B i tagjt inkrementlja, s nem sptrt. Ha
mgis ezt szeretnnk (br a konkrt pldnl ennek semmi rtelme
sincs), akkor a ++sptr kifejezs rszt zrjelbe kell tenni, azaz:
(++sptr)->i
A
++(sptr++)->i
ugyancsak s.it inkrementlja, de a kifejezs mellkhatsaknt sptr
is megn eggyel. Ha a zrjeleket elhagyjuk, persze akkor is ideju-
tunk:
++sptr++->i ++(sptr++)->i
- Ugyangy a nev cmen lev karaktert ri el a
*sptr->nev
, hisz az indirekcit az elbbiekbl kvetkezleg az sptrrel elrt
nev cmen hajtja vgre a fordt. Vegyk mg a
*sptr++->nev++
kifejezst, aminek ugyanaz az rtke, mint az elz kifejezs, de
mellkhatsknt sptr s nev inkrementlsa is megtrtnik.
226 STRUKTRK S UNIK
e Ha mr mindig hozzrendelsi pldkat hoztunk, akkor itt kell meg-
emltennk, hogy struktrkat csak akkor lehet egymshoz rendelni, ha a
forrs s a cl struktra azonos tpus.
struct A {
int i, j;
double d; } a, a1;
struct B {
int i, j;
double d; } b;
/* . . . */
a = a1; /* OK, a hozzrendels megy tagrl-tagra. */
a = b; /* HIBS, mert eltr a kt struktra tpusa.*/
a.i = b.i; /* Tagrl-tagra persze most is megy a dolog. */
a.j = b.j;
a.d = b.d;
Vegynk valamilyen pldt a struktratmbkre!
Keressk meg a megadott, skbeli pontok kzt a kt, egymstl legtvo-
labbit! A pontok szma csak futs kzben dl el (n), de nem lehetnek tb-
ben egy fordtsi idben vltoztathat rtknl (N). Az x koordinta bevi-
telekor res sort megadva, a bemenet elbb is befejezhet, de legalbb kt
pont elvrand! Az input ellenrzend, s minden hibs rtk helyett azon-
nal jat kell krni. Az eredmny kzlsekor meg kell jelentetni a kt pont
indexeit, koordintit s persze a tvolsgot is.
/* PELDA28.C: A kt, egymstl legtvolabbi pont
megkeresse. */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#define INP 28 /* Az input puffer mrete. */
#define N 128 /* Pontok maximlis szma. */
A feladatot skbeli pontot ler struktra segtsgvel fogjuk megoldani:
struct Pont{ /* A Pont struktra. */
double x, y; };
int getline(char s[],int n){ /* . . . */ }
int lebege(char s[]){ /* . . . */ }
A kt fggvny forrsszvege idemsoland!
int main(void){
char sor[INP+1]; /* Input puffer. */
A struktratmb defincija:
struct Pont p[N]; /* Struktratmb. */
int n=0; /* Pontok szma. */
double max=-1., d; /* Pillanatnyi maximum s */
int i, j, tavi, tavj;/* segdvltozk. */
C programnyelv 227
printf("A kt egymstl legtvolabbi pont a skban.\n"
"Adja meg a pontok koordintaprjait rendre!\n"
"Vge: res sor az X koordinta megadsnl.\n\n");
for(n=0; n<N; ++n){
printf("A(z) %d pont koordinti:\n", n+1);
if(printf("X: "), getline(sor, INP)<=0) break;
if(lebege(sor)) p[n].x=atof(sor);
else { --n; continue;}
while(printf("Y: "), getline(sor, INP),
!lebege(sor));
p[n].y=atof(sor); }
if(n<2){
printf("Legalbb kt pontot meg kne adni!\n");
return(1);}
for(i=0; i<n-1; ++i)
for(j=i+1; j<n; ++j)
Kitnen ltszik, hogyan kell elrni a struktra tmbelem tagjait!
if((d=sqrt((p[j].x-p[i].x)*(p[j].x-p[i].x)+
(p[j].y-p[i].y)*(p[j].y-p[i].y))) > max){
max=d;
tavi=i;
tavj=j; }
printf("A maximlis tvolsg kt pont:\n"
"P[%d]: (%10.1f, %10.1f) s\n"
"P[%d]: (%10.1f, %10.1f),\n"
"s a tvolsg: %15.2f\n",
tavi+1, p[tavi].x, p[tavi].y,
tavj+1, p[tavj].x, p[tavj].y, max);
return(0); }
Megoldand feladatok:
Ha fokozni kvnja a feladatot, akkor
- Dolgozzon trbeli pontokkal!
- Rendezze a pontokat az origtl val tvolsguk cskken sorrend-
jben, s jelentesse meg a pontokat s a tvolsgot fejlccel elltva,
tblzatosan s lapozhatan! {PELDA28X.C}
- Esetleg oldja meg, hogy ne lehessen ktszer ugyanazt a pontot meg-
adni!
10.5 Struktrk s fggvnyek
Emltettk mr, hogy a struktra msolhat, hozzrendelhet, elrhetk
a tagjai, kpezhet a cme, ill. tmb is elllthat belle, de fggvny is
visszaadhat struktrt vagy erre mutat mutatt. Az fv1 visszaadott rtke
struct struki struktra.
struct struki fv1(void);
228 STRUKTRK S UNIK
Az fv2 viszont struct struki struktrra mutat mutatt szolgltat.
struct struki *fv2(void);
A fggvny paramtere is lehet struktra e kt mdon. Az fv3 struct
struki struktrt fogad paramterknt.
void fv3(struct struki s);
Az fv4 viszont struct struki struktrra mutat mutatt fogad.
void fv4(struct struki *sp);
e A kvetkez plda a helytelen gyakorlatot szemllteti. A fgg-
vny paramterei s visszaadott rtke egyarnt struktra. Struktra per-
sze akrmekkora is elkpzelhet.
typedef struct{
char nev[20];
int az;
long oszt; } STUDENT;
STUDENT strurend(STUDENT a, STUDENT b){
return((a.az < b.az) ? a : b); }
/* . . . */
STUDENT a, b, c;
/* . . . */
c = strurend(a, b);
Amg a strurend fut, hat darab STUDENT struktra ltezik: a, b, c, az-
tn a s b msolata s a fggvny visszaadott rtke a veremben. Clszer
teht nem a struktrt, hanem arra mutat mutatt tadni a fggvnynek,
ill. vissza is kapni tle, ha lehet, azaz:
STUDENT *strurnd(STUDENT *a, STUDENT *b){
return((a>az < b->az) ? a : b); }
/* . . . */
STUDENT *z;
/* . . . */
z = strurnd(&a, &b);
e Prototpus hatskre ellenre a benne megadott struct hatskre
globlis, azaz figyelmeztet zenet nlkl nem hvhatjuk meg a kvetke-
z fggvnyt:
void fv(struct S *);
A problma elhrtshoz deklarlni vagy definilni kell a struktrt
prototpus elrsa eltt:
struct S;
/* . . . */
void fv(struct S *);
C programnyelv 229
Ksztsnk struktrt s kezel fggvnycsaldot dtumok manipull-
sra!
A datum struktrban nyilvntartjuk a dtum vt (ev), hnapjt (ho),
napjt (nap), a Krisztus szletse ta a dtumig eltelt napok szmt: az
n. dtumsorszmot (datumssz), a dtum karakterlnc alakjt (datum-
lanc) s azt, hogy a dtum az v hnyadik napja (evnap). Az egszet gy
kpzeljk el, hogy
- vagy megadjk a dtumot v, h s nap alakban, s a DatumEHN
fggvnnyel meghatrozzuk a struktra sszes tbbi adatt (a main-
ben d1 objektum gy kap rtket),
- vagy karakterlnc alak dtumbl a DatumKARral lltjuk el a
datum struktra tagjainak rtkeit (a fprogramban d2 e mdon jut
rtkhez).
- Mindkt struct datum objektumnak rtket ad rutin vgl dtum-
ellenrzst vgez a Datume fggvnnyel, s ezt a logikai rtket
szolgltatja.
- A NapNev visszaadja a dtum hten belli napjnak nevt. Ponto-
sabban a nv karakterlncnak cmt.
- A tovbbi rutinok mveleteket vgeznek a dtum struktrkkal. A
DatumKul megllaptja kt dtum klnbsgt, s szolgltatja ezt a
napszmot. A DatumMegEgy inkrementlja, s visszaadja a dtum
objektumot. A DatumMegint pozitv, egsz rtket ad hozz.
- A dtumfggvnyek mind a MINDATUM s MAXDATUM k-
ztti tartomnyban dolgoznak.
- A main ki is prblja az sszes dtumfggvnyt.
Figyeljk meg, hogy mindegyik fggvny struct datum objektumra
mutat paramterknt kapja meg a manipullt dtum struktr(ka)t! A
DatumMegEgy s a DatumMegint visszatrsi rtke struct datum
struktra.
Fedezzk fel, hogy a globlis MAXDATUM, a hnapi napszmo-
kat tartalmaz honap tmb, s a Datume fggvny static trolsi osztlya
miatt loklis a DATUM.C modulra! Nincs is prototpus a Datumere a
DATUM.H fejfjlban. Az rtkket nem vltoztat, de csak a rutin
blokkjbl elrend oszto vltoz, s a napnv karakterlncokra mutatk-
bl ll hetnev mutattmb statikus lettartamak, de hatskrk loklis.
230 STRUKTRK S UNIK
Vegyk mg szre a DATUM.Hban, hogy a _DATUMH makr
egyetlen struct datum defincit tesz lehetv akkor is, ha a fordtsi egy-
sgben tbbszr kapcsolnk be a fejfjlt.
/* DATUM.H: Dtumok kezelse. */
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#if !defined(_DATUMH)
#define _DATUMH
struct datum{
int ev, ho, nap, evnap;
long datumssz; /* Dtumsorszm. */
char datumlanc[11]; };
#endif
const char *NapNev(struct datum *);
int DatumEHN(int, int, int, struct datum *);
int DatumKAR(const char *, struct datum *);
long DatumKul(struct datum *, struct datum *);
struct datum DatumMegEgy(struct datum *);
struct datum DatumMegint(struct datum *, int);
/* DATUM.C: Dtumok kezelse. */
#include "DATUM.H"
#define MINDATUM 366
static const long MAXDATUM=9999*365l + 9999/4
9999/100+9999/400;
static int honap[]={0, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
const char *NapNev(struct datum *pd){
static char *hetnev[]={"vasrnap", "htf", "kedd",
"szerda", "cstrtk","pntek","szombat"};
return hetnev[(pd->datumssz)%7l]; }
A dtumsorszmbl 7tel kpzett modulus alapjn llaptja meg a hten
belli napindexet a NapNev rutin.
static int Datume(struct datum *pd){
int i;
honap[2]=28+(!(pd->ev%4)&&pd->ev%100||(!pd->ev%400));
if(pd->ev<1 || pd->ev>9999 || pd->ho<1 || pd->ho>12 ||
pd->nap<1 || pd->nap>honap[pd->ho]){
pd->evnap=0; pd->datumssz=0l; return 0;}
else {
sprintf(pd->datumlanc, "%04d.%02d.%02d",
pd->ev, pd->ho, pd->nap);
pd->evnap=pd->nap;
for(i=1; i<pd->ho; ++i)pd->evnap+=honap[i];
pd->datumssz=(pd->ev-1)*365l+pd->evnap+
pd->ev/4-pd->ev/100+pd->ev/400;
return 1; } }
C programnyelv 231
A Datume ugyangy a dtumot ellenrzi, s logikai vlaszt ad a form-
lisan je a dtum? krdsre, mint a korbbi datume fggvnyek. Nem
karakterlncbl dolgozik azonban, hanem a struktra ev, ho, nap tagjai-
bl, melyeket a DatumEHN, ill. a DatumKAR ksztettek oda. Ha hibs
a dtum, akkor nullzza a rutin az evnap s a datumssz tagokat.
Ha j a dtum, akkor a Datume kpezi a datumlancba a dtum karak-
terlnc alakjt, s meghatrozza az evnap s a datumssz rtkt. Az evnap
a dtum napszmrl indul, s a rutin hozzadogatja a megelz hnapok
maximlis napszmait. A dtumsorszm megllaptshoz a szkv
vizsglathoz hasznlatos kifejezst alkalmazza a fggvny.
Az STDIO.H bekapcsolsval rendelkezsre ll sprintf ugyangy
mkdik, mint printf trsa, de nem a szabvny kimenetre, hanem az els
paramtereknt kapott karaktertmbbe dolgozik.
A formtumspecifikcikban a mezszlessg eltt ll 0 hatsra a
jobbra igaztott szmok balrl nem szkz, hanem 0 feltltst kapnak.
Magyarn a 932.2.3. dtumbl 0900.02.03 karakterlnc lesz.
Szltunk mr rla, hogy a Datume nem hvhat ms forrsmodulbl. A
DATUM.Cben is csak a DatumEHN s a DatumKAR idzi meg utols
lpseknt.
int DatumEHN(int e, int h, int n, struct datum *pd){
pd->ev=e;
pd->ho=h;
pd->nap=n;
if(e>=0&&h>=0&&n>=0&&e<10000&&h<100&&n<100)
sprintf(pd->datumlanc, "%04d.%02d.%02d", e, h, n);
else *pd->datumlanc=0;
return Datume(pd);}
int DatumKAR(const char *lanc, struct datum *pd){
pd->ho=pd->nap=0;
strncpy(pd->datumlanc, lanc, 10);
pd->datumlanc[10] = 0;
pd->ev=atoi(lanc);
while(isdigit(*lanc))++lanc;
if(*lanc!=0){
++lanc;
pd->ho=atoi(lanc);
while(isdigit(*lanc))++lanc;
if(*lanc){
++lanc;
pd->nap=atoi(lanc);}}
return Datume(pd); }
A DatumEHN a kapott, int tpus v, h, nap segtsgvel tlti fel az
utols paramterknt elrt dtum struktrt.
232 STRUKTRK S UNIK
Az sprintf hvs eltti vizsglatra azrt van szksg, hogy a rutin ne
tudja tlrni a 11 elem karaktertmb, datumlanc tagot a memriban va-
lamilyen egszen zldsg v, h, nap paramter miatt. Ilyenkor res
lesz a datumlanc.
A DatumKAR tmsolja a karakterlnc alakban kapott dtum els 10
karaktert a datumlancba. Nullzza a honapot s napot. Ltszik, hogy a
fggvny nem kti meg olyan szigoran sem az v, sem a hnap s nap
jegyszmt, mint a korbbi datume, ill. elvlaszt karakterknt csak vala-
milyen nem numerikust vr el. A karakterlnc egssz konvertlt elejt
vnek, az els elvlaszt karakter utni rszt hnapnak, s a msodik elv-
laszt karakter mgttieket napnak tekinti a rutin, hacsak idkzben vge
nem lesz a karakterlncnak.
Vgl mindkt fggvny meghvja a Datumet, s ennek visszatrsi r-
tkt szolgltatja.
long DatumKul(struct datum *pd1, struct datum *pd2){
if(pd1->datumssz>pd2->datumssz)
return pd1->datumssz-pd2->datumssz;
else return pd2->datumssz-pd1->datumssz; }
A DatumKul kpzi a kt paramter dtum struktra dtumsorszm tag-
jainak klnbsge abszolt rtkt.
struct datum DatumMegEgy(struct datum *pd){
int e=pd->ev, h=pd->ho, n=pd->nap;
struct datum d;
honap[2]=28+(e%4==0 && e%100 || e%400==0);
if(++n>honap[h]){
n=1;
++h;
if(h>12){
h=1;
++e; }}
if(!DatumEHN(e, h, n, &d)) d=*pd;
return d; }
A paramtere dtumot inkrementl DatumMegEgy munkavltozkba
rakja az vet, a hnapot s a napot. Meghatrozza az v szerinti februr
pontos napszmt. Nveli eggyel a napot. Ha ez tlmenne a hnap szerinti
maximlis napszmon, akkor 1 lesz, s a hnapszm nvelse jn. Ha ez
13 lenne, akkor 1 lesz, s az vszm nvelse kvetkezik.
A megllaptott, j v, h, nap alapjn a DatumEHN feltlti a loklis, d
dtum objektumot. Ha az j dtum rvnytelen volt, akkor a vltozatlan-
sgot jelzend a rutin hozzrendeli dhez a paramter cmen lev, eredeti
dtumot.
C programnyelv 233
A hozzrendels a paramter cmen lev (ezrt kell el az indirek-
ci) struct datum minden tagjt egy az egyben tmsolja a balrtk, d,
loklis dtum objektum tagjaiba rendre.
A visszatrs sorn a DatumMegEgy ltrehoz a veremben egy ideigle-
nes dtum objektumot, melybe tagrltagra bemsolja a d loklis dtum
vltozt. Visszatrs utn aztn a main hozzrendeli az ideiglenes dtum
objektumot a mainben loklis dhez.
struct datum DatumMegint(struct datum *pd, int np){
int e=pd->ev, h=pd->ho, n=pd->nap;
long dpd = pd->datumssz + np + 365;
/* A tiszta j konstans 365.24223 lenne kzi
szmts szerint!!!! */
static double oszto=365.24225;
struct datum d=*pd;
if(np <= 0) return d;
if(dpd > MAXDATUM){
e=9999;
h=12;
n=31; }
else {
e= (int)dpd/oszto;
n=dpd-e*365l-e/4+e/100-e/400;
honap[2]=28+(e%4==0 && e%100 || e%400==0);
for(h=1; n > honap[h]; ++h)n-=honap[h]; }
if(!DatumEHN(e, h, n, &d)) d=*pd;
return d; }
Csak a kezdett s a vgt tekintve a pozitv napszmot a dtumhoz ad
DatumMegint a DatumMegEgygyel megegyezen dolgozik.
Ltszik, hogy negatv, hozzadand napszmot, vagy a mvelet v-
gn rvnytelen dtumot kapva, az eredeti dtum objektumot szolgltatja
a rutin vltozatlanul.
A dtumsorszmot megnveli a napszmmal s mg 365tel. Ha gy
meghaladn a 9999.12.31et, akkor ezt adn vissza. Ha nem, akkor az j
dtumsorszmot elosztja a tapasztalati alapon a [MINDATUM, MAX-
DATUM] tartomnyban rvnyes venknti tlagos napszmmal, s ez
lesz az j vszm. Visszaszmolja belle az j v pontos napszmt, s a
kt rtk klnbsgbl hnap s napszmot kpez.
/* PELDA29.C: A dtumok kezelsnek kiprblsa. */
#include "DATUM.H"
void main(void) {
long kul;
struct datum d1, d2, d;
printf("Dtum mveletek:\n\n");
DatumEHN(2003, 12, 31, &d1);
DatumKAR("2003-2-13", &d2);
234 STRUKTRK S UNIK
printf("A(z) %s. s a(z) %s. klnbsge %ld nap!\n",
d1.datumlanc, d2.datumlanc,
(kul=DatumKul(&d1, &d2)));
d=DatumMegEgy(&d1);
printf("A(z) %s. + 1 a(z) %s.\n", d1.datumlanc,
d.datumlanc);
d=DatumMegint(&d2, (int)kul);
printf("A(z) %s. + %ld a(z) %s.\n", d2.datumlanc,
kul, d.datumlanc);
printf("A(z) %s. %s.\n", d2.datumlanc, NapNev(&d2)); }
Megoldand feladatok:
Bvtse a DATUM.H s DATUM.C fjlokat a kvetkez funkcikat el-
lt fggvnyekkel! Persze prblja is ki ket!
- A hnapnv karakterlnc ellltsa a hnapszm alapjn.
- Olyan karakterlnc alak dtum ltrehozsa, melyben a hnap meg-
nevezse szerepel a hnap szma helyett.
- A DatumMegint olyan trsa, hogy a napszm paramter negatv
is lehessen.
Ksztsen ugyanilyen szellemben struktrt s kezel fggvnycsaldot
az idre is!
10.6 nhivatkoz struktrk s dinamikus adatszerkezetek
Tudjuk, hogy a struktrnak nem lehet
- void,
- nem teljes s
- fggvny
tpus tagja, de nem lehet tag
- az ppen definci alatt ll struktra
sem. Lehet viszont tag nem teljes tpus struktrra, gy akr a definci
alatt llra, mutat mutat.
Azt a struktrt, melynek legalbb egy nmagra mutat tagja van, n-
hivatkoz struktrnak nevezik.
A dinamikus adatszerkezeteket [3]: listkat, fkat stb. ler adatkonst-
rukcik a Cben nhivatkoz struktrk. Nzznk nhnyat!
Egyirny listhoz pldul a kvetekez struktra lenne hasznlhat:
struct List1{
C programnyelv 235
ADAT adat;
struct List1 *kov; };
, ahol az ADAT tpus adat tagon valamilyen, a lista egy elemben tro-
land adatokat ler struktrt kell rteni. A kov az egyirny lista kvet-
kez struct List1 tpus elemre mutat, ill. a lista vgt NULL mutat
jelzi. A lista kezelhetsghez ezen tl mr csak egy horgonypontra, s
esetleg egy seged mutatra
struct List1 *KezdoPont = NULL, *seged;
van szksg a listt manipull programban.
Tegyk fel, hogy ismertek az ADATok, s vegyk fel a lista els elemt!
if(!(KezdoPont=seged=(struct List1*)malloc(
sizeof(struct List1)))){
printf("Elfogyott a memria!\n");
exit(1); }
else{
/* seged->adat vegye fel az ADATok rtkt! */
seged->kov=NULL; }
A lista kvetkez eleme:
if(!(seged->kov=(struct List1*)malloc(
sizeof(struct List1)))){
printf("Elfogyott a memria!\n");
exit(1); }
else{
/* seged->adat vegye fel az ADATok rtkt! */
seged->kov=NULL; }
/* . . . */
Elg! rjunk Beszur1 fggvnyt, mely paramterknt megkapja a be-
szrand ADATokat, s annak a listaelemnek a cmt, mely utnra az j
listaelem kell, hogy kerljn! Ha mg nincs is lista, akkor ezen a pozcin
kapjon NULL mutatt a rutin! A visszatrsi rtk legyen a most ltestett
listaelem cme, ill. NULL mutat, ha elfogyott a memria!
struct List1 *BeSzur1(ADAT a, struct List1 *elozo){
struct List1 *p;
if(p=(struct List1 *)malloc(sizeof(struct List1))){
p->adat=a;
if(elozo){
p->kov=elozo->kov;
elozo->kov=p; }
else p->kov=NULL; }
return p; }
Ekkor a lista ltrehozsa a kvetkez:
KezdoPont=seged=BeSzur1(adatok, NULL);
while(/* Vannak kvetkez adatok? */&&seged!=NULL)
236 STRUKTRK S UNIK
seged=BeSzur1(adatok, seged);
if(!seged){
printf("Elfogyott a memria!\n");
exit(1); }
A ltrehozott egyirny lista felhasznls utn a kvetkez kddal sem-
misthet meg:
while(KezdoPont){
seged=KezdoPont->kov;
free(KezdoPont);
KezdoPont=seged; }
Az egyirny listban lehet j elemet brhov beszrni (BeSzur1), br-
honnt trlni, de a listt ahogyan a megsemmist kd is mutatja
csak elrehaladva lehet elrni, visszafel lpkedve nem. Az odavisszaha-
ladshoz ktirny lista kell:
struct List2{
ADAT adat;
struct List2 *kov, *elo; };
struct List2 *KezdoPont = NULL, *seged;
A visszalpegets lehetsgt a megelz listaelemre mutat, elo muta-
ttag biztostja. A lista vgt mindkt irnyban NULL mutat jelzi. A be-
szrs:
struct List2 *BeSzur2(ADAT a, struct List2 *elozo){
struct List2 *p;
if(p=(struct List2 *)malloc(sizeof(struct List2))){
p->adat=a;
if(elozo){
p->elo=elozo;
p->kov=elozo->kov;
elozo->kov=p;
if(p->kov) p->kov->elo=p; }
else p->elo=p->kov=NULL; }
return p; }
A BeSzur2 csak egyet nem tud: a ltez els elem el beszrni. Ezen
gy segthetnk:
seged=BeSzur2(adatok, NULL);
seged->kov=KezdoPont;
KezdoPont=seged;
A trls:
struct List2 *Torol2(struct List2 *ezt){
struct List2 *p=NULL;
if(ezt){
p=ezt->kov;
if(ezt->elo) ezt->elo->kov=ezt->kov;
if(ezt->kov) ezt->kov->elo=ezt->elo;
C programnyelv 237
free(ezt); }
return p; }
A Torol2 fggvnynek is csak a ltez, legels elem trlsekor kell se-
gteni, hisz vltozik a
KezdoPont=Torol2(KezdoPont);
Felhasznls utn a ktirny lista is ugyangy semmisthet meg, mint
az egyirny.
A fk kzl vlasszuk ki a binris keresft! Ennek pontjaiban legfel-
jebb kett az elgazsok szma, s a pontokban helyet foglal struktrk
ADAT rsze alapjn a fa, mondjuk, nvekvleg rendezett. Ltezik teht
egy
int Hasonlit(ADAT a1, ADAT a2);
rutin, mely zrust szolgltat, ha a1==a2, pozitv rtket, ha a1>a2, ill. ne-
gatvat egybknt. A binris keresfban a mindenkori aktulis pont bal
gn lev pontok kzl egy sem nagyobb, s a jobb gn helyet foglalk
kzl viszont egyik sem kisebb az aktulis pontnl. Az adatstruktra:
struct BinFa{
ADAT adat;
struct BinFa *bal, *jobb; };
struct BinFa *KezdoPont = NULL;
A beszrst vgz rekurzv fggvny a kvetkez:
struct BinFa *BeSzurBF(ADAT a, struct BinFa *p){
int fel;
if(!p){ /* j pont kszl. */
if(p=(struct BinFa *)malloc(sizeof(struct BinFa))){
p->adat=a;
p->bal=p->jobb=NULL; }
else printf("Elfogyott a memria!\n"); }
else if((fel=Hasonlit(a, p->adat))==0)
/* Volt mr ilyen ADAT, s itt ez a kd van. */
else if(fel<0) /* A bal oldali rszfba val. */
p->bal=BeSzurBF(a, p->bal);
else /* A jobb oldali rszfba val. */
p->jobb=BeSzurBF(a, p->jobb);
return(p); }
A kvetkez rekurzv fggvny nvekvleg rendezett sorrendben vgez
el minden ponton valamilyen tevkenysget:
void Tevekeny(struct BinFa *p){
if(p){
Tevekeny(p->bal);
/* Itt van a tevkenysg kdja. */
Tevekeny(p->jobb); } }
238 STRUKTRK S UNIK
Keressk meg egy szvegfjlban a benne elfordul szavakat! llapt-
suk meg ezen kvl, hogy a szavak a szvegfjl mely sorszm soraiban
fordulnak el! Ha ugyanaz a sz egy sorban tbbszr is megtallhat, a
sor sorszmt ekkor is csak egyszer kell kzlni. Vgl kzlendk a sza-
vak, s az elfordulsi sor sorszmok nvsorban!
A megoldsban a szavak trolshoz binris keresft hasznlunk, s a
szhoz tartoz elfordulsi sor sorszmokat minden ponthoz tartozan
egyirny listban tartjuk nyilvn.
A PELDA30 programot a parancssorbl
PELDA30 < PELDA30.C > EREDMENY.TXT
mdon indthatjuk, s a kszlt lista az EREDMENY.TXT fjlban tanul-
mnyozhat.
/* PELDA30.C: Kirja a szvegben elfordul szavak listjt
s megadja azt is, hogy a szavak milyen sorszm sorok-
ban fordultak el! */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXSOR 256 /* A beolvasott sor max. hossza. */
/* A sorok sorszmainak egyirny listja: */
struct List1{
int sorsz;
struct List1 *kov; };
/* A binris keres fa: */
struct BinFa{ /* Alapcsompont. */
char *szo; /* A szra mutat. */
struct List1 *sorok; /* A sorok sorszmai. */
struct BinFa *bal; /* A bal oldali g. */
struct BinFa *jobb;}; /* A jobb oldali g. */
/* Fggvny prototpusok: */
struct BinFa *BeSzurBF(char *, int, struct BinFa *);
void SorMeg(struct BinFa *, int);
void Kiir(struct BinFa *);
int main(void){
static char szoelv[]=" \t\n\r\f\"\'\\\a\?"
":;,.()[]{}*/%+-&|^~!<>=#";
struct BinFa *KezdoPont=NULL;
char sor[MAXSOR], *szo;
int sorszam=1;
printf("Szavak keresztreferencija szvegben:\n");
while(sor[MAXSOR-1]=2, fgets(sor, MAXSOR, stdin)){
if(!sor[MAXSOR-1]&&sor[MAXSOR-2]!='\n')
printf("Lehet kis elsorszmozs!\n");
szo=strtok(sor, szoelv);
while(szo){
KezdoPont=BeSzurBF(szo, sorszam, KezdoPont);
szo=strtok(NULL, szoelv); }
C programnyelv 239
++sorszam; }
Kiir(KezdoPont);
return 0; }
A fgets fggvny a getlinehoz nagyon hasonlan dolgozik. Karak-
terlncot olvas be a szabvny bemenetrl (stdin), melyet az els param-
ter cmtl kezdve letrol a memriban. Az olvass lell, ha a fggvny a
msodik paramternl eggyel kevesebb (MAXSOR 1), vagy \n ka-
raktert olvasott. A getlinetl eltren azonban a rutin a \nt is elhelyezi
a lncban, s a lnc vghez mg egy \0t is hozzilleszt. Sikeres eset-
ben az fgets az els paramter mutatval tr vissza. Fjlvgen, vagy hiba
esetn viszont NULLt kapunk tle.
Ha a sor tmb utols pozcijn van a lnczr zrus, de eltte
nincs ott a soremels karakter, akkor az aktulisan olvasott sor nem frt el
egy menetben a bemeneti pufferben, s ebbl kvetkezleg elsorszmozs
trtnik.
Az strtok lersa megtallhat a MUTATK szakasz Karakter-
lnc kezel fggvnyek fejezetben!
struct BinFa *BeSzurBF(char *a,int sorszam,struct BinFa *p)
{ int fel;
if(!p){ /* j sz rkezett */
p=(struct BinFa *)malloc(sizeof(struct BinFa));
if(p&&(p->szo=(char *)malloc(strlen(a)+1))){
strcpy(p->szo, a);
if(p->sorok=(struct List1 *)malloc(
sizeof(struct List1))){
p->sorok->sorsz=sorszam;
p->sorok->kov=NULL; }
p->bal=p->jobb=NULL; }
if(!p||!p->szo||!p->sorok){
printf("Elfogyott a memria!\n");
exit(1); } }
else if((fel=strcmp(a, p->szo))==0)
SorMeg(p, sorszam);
else if(fel<0)
p->bal=BeSzurBF(a, sorszam, p->bal);
else p->jobb=BeSzurBF(a, sorszam, p->jobb);
return(p); }
/* Sorszm hozzadsa az egyirny lista vghez: */
void SorMeg(struct BinFa *p, int sorszam){
struct List1 *seged=p->sorok;
while(seged->kov!=NULL && seged->sorsz!=sorszam)
seged=seged->kov;
if(seged->sorsz!=sorszam){
if(seged->kov=(struct List1 *)malloc(
sizeof(struct List1))){
seged->kov->sorsz=sorszam;
seged->kov->kov=NULL; }
240 STRUKTRK S UNIK
else{
printf("Elfogyott a memria!\n");
exit(1); } } }
/* A fa kirsa: */
void Kiir(struct BinFa *p){
struct List1 *seged;
int i;
if(p){
Kiir(p->bal);
printf("%s:\n", p->szo);
for(seged=p->sorok, i=0; seged; seged=seged->kov,
++i)
printf("%7d|", seged->sorsz);
if(i%10!=9) printf("\n");
Kiir(p->jobb); } }
Megoldand feladatok:
Fejlessze tovbb a PELDA30.Cben megoldott feladatot a kvetkez-
kpp, s persze prblja is ki!
- C parancssori paramterrel indtva a program ne gyjtse a szabv-
nyos C kulcsszavak elfordulsait.
- Ha a szabvny kimenet (stdout) nem fjl, akkor bontsa lapokra a
listt a szoftver.
- N parancssori paramterrel startolva jelentesse meg a program
megsorszmozva, de egybknt vltozatlanul a bemenetet.
10.7 Struktra trillesztse
A fordt a struktratagokat deklarcijuk sorrendjben nvekv mem-
ria cmeken helyezi el. Minden adatobjektum rendelkezik trillesztsi
ignnyel is. A fordt olyan eltolssal helyezi el az adatobjektumot, hogy
az
eltols % trillesztsi-igny == 0
zrus legyen. Struktrk esetn ez a szably a tagok elhelyezsre vonat-
kozik. Ha pldnak vesszk a
struct struki {
int i;
char lanc[3];
double d; } s;
struktrt, akkor tudjuk, hogy az s objektumot nvekv memria cmeken
gy helyezi el a fordt, hogy
1. ngy bjtot (32 bites esetben) foglal az int tagnak,
2. aztn a 3 bjtos karakterlnc kvetkezik, s
C programnyelv 241
3. vgl 8 bjtot rezervl a double taghoz.
Bizonyos fordt opcik, vagy valamilyen #pragma direktva segt-
sgvel vezrelhetjk a struktra adatok memriabeli illeszkedst. Ez azt
jelenti, hogy az adatokat 1gyel, 2vel, 4gyel stb. maradk nlkl oszt-
hat cmeken: bjthatron, szhatron, dupla szhatron stb. kell elhe-
lyezni. Felkrjk az olvast, hogy nzzen utna a dolognak a programfej-
leszt rendszere segtsgben! Brhogyan is, eme belltsok hatsra a
fordt minden struktratagot, az elst kveten, olyan hatron trol, mely
megfelel a tag trillesztsi ignynek.
A bjthatrra igazts azt jelenti, hogy
- a struktra objektum elhelyezse brmilyen cmen kezddhet, s
- a struktratagok ugyancsak brmilyen cmen elhelyezhetk tpusuk-
tl fggetlenl.
A plda s objektum sszesen 15 bjtot foglal el ilyenkor, s a memria
trkp a kvetkez:
i lanc d
4 bjt 3 bjt 8 bjt
A szhatrra igazts azt jelenti, hogy
- a struktra objektum kezdcme pros kell, hogy legyen, s
- a struktratagok - a char tpustl eltekintve - ugyancsak pros cme-
ken helyezkednek el.
A plda s objektum gy sszesen 16 bjtot foglal el. Egy bjt elveszik, s
a memria trkp a kvetkez:
i lanc g d
4 bjt 3 bjt 1 b 8 bjt
A dupla szhatrra igazts azt jelenti, hogy
- a struktra objektum elhelyezse nggyel maradk nlkl oszthat
cmen (dupla szhatron) trtnik meg,
- a char tpus struktratagok bjthatron kezddnek,
- a short tpus tagok szhatron indulnak s
- a tbbi tpus tag dupla szhatron (nggyel maradk nlkl osztha-
t cmen) kezddik.
Dupla szhatrra igaztva az s objektum megegyezik az elzvel. A ha-
trra igaztsi jtk folytathat rtelemszeren tovbb.
242 STRUKTRK S UNIK
Persze a struktrt nem ilyen butn definilva igaztstl fggetle-
nl elrhetjk, hogy egyetlen bjt elvesztse se kvetkezzk be:
struct struki {
double d;
int i;
char lanc[3]; } s;
10.8 UNIK
Az uni tpus a struktrbl szrmazik, de a tagok kztt zrus a cmel-
tols. Az uni azt biztostja, hogy ugyanazon a memria terleten tbb,
klnfle tpus adatot trolhassunk. Az
union unio{
int i;
double d;
char t[5]; } u, *pu = &u, tu[23];
definciban az u union unio tpus objektum, a pu ilyen tpus objek-
tumra mutat mutat, s a tu egy 23 ilyen tpus elembl ll tmb azo-
nostja. Az u objektum - pldul - egyazon memria terleten biztostja
az i nev int, a d azonostj double s a t nev karaktertmb tpus tag-
jainak elhelyezst, azaz:
&u &u.i &u.d ...
Ennek szellemben aztn igaz, hogy az uni objektumra mutat mutat
annak egyben minden tagjra is mutat.
(pu=&u) &u.i &u.d ...
Termszetesen a dolog csak a mutatk rtkre igaz, mert az &u
(union unio *), az &u.i (int *) s az &u.d (double *), azaz tpusban el-
trnek. Ha azonban unit megcmz mutatt explicit tpusmdostssal
tagjra irnyul mutatv alaktjuk, akkor az eredmny mutat magra a
tagra mutat:
u.d=3.14;
printf(*(&u.d) = %f\n, *(double *)pu);
Az uni helyfoglalsa a trban akkora, hogy benne a legnagyobb bjtig-
ny tagja is elfr, azaz:
sizeof(union unio) sizeof(u) 8.
Teht 4 bjt felhasznlatlan, ha int adatot tartunk benne, ill. 3 bjt elrhe-
tetlen, ha karaktertmbt rakunk bele. Az uni egy idben csak egyetlen
tagjt tartalmazhatja.
C programnyelv 243
Lttuk mr, hogy az unitagokat ugyanazokkal a tagszelektor operto-
rokkal rhetjk el, mint a struktratagokat:
u.d = 3.15;
printf(u.d=%f\n, u.d); /* OK: u.d=3.15 jelenik meg. */
printf(u.i=%d\n, u.i); /* Furcsa eredmny szletik. */
printf(u.t[0]=%c\n, u.t[0]);/* Valami csak megjelenik,
vagy sem. */
printf(u.t=%s\n, u.t); /* Csoda karakterlnc ltszik.
Ki tudja, hol van a lnc vge!*/
strcpy(pu->t, Hoh);
printf(u.t=%s\n, pu->t);/* OK: a Hoh ltszik. */
printf(u.i=%d\n, pu->i);/* Furcsa eredmny szletik. */
printf(u.d=%f\n, pu->d);/* Nagyon szortsunk, hogy ne
legyen lebegpontos tl vagy
alulcsorduls! */
eValahonnan teht clszer tudni - pldul gy, hogy nyilvntartjuk -
milyen tpus adat is tallhat pillanatnyilag az uni objektumban, s azt
szabad csak elrni.
Ha egy uni tbbfle, de azonos kezd szerkezet struktrval indul, s
az uni tartalma e struktrk egyike, akkor lehetsg van az uni kzs
kezdeti rszre hivatkozni. Pldul:
union{
struct{ int tipus;} t;
struct{ int tipus; int iadat;} ti;
struct{ int tipus; double dadat;} td;
/* . . . */ } u;
/* . . . */
u.td.tipus = DOUBLE;
u.td.dadat = 3.14;
/* . . . */
if(u.t.tipus == DOUBLE) printf(%f\n, u.td.dadat);
else if(u.t.tipus == INT) printf(%d\n, u.ti.iadat);
else /* . . . */
Unikkal pontosan ugyanazok a mveletek vgezhetk, mint a struk-
trkkal. Hozzrendelhetk, msolhatk, hozzfrhetnk a tagjaikhoz, k-
pezhet a cmk, tadhatk fggvnyeknek s rutinok visszatrsi rtkei
is lehetnek.
10.8.1 Unideklarcik
Az ltalnos deklarcis szably azonos a struktrval. Az eltrsek a
kvetkezk:
- Az unik tartalmazhatnak bitmezket. Mindegyik bitmez azonban
az uni kezdettl indul, s gy kzlk csak egy lehet aktv.
244 STRUKTRK S UNIK
eA kvetkez fejezetben trgyalt bitmezk gpfgg brzolsra itt
is fel szeretnnk hvni kln a figyelmet!
- Az uni tagja nem lehet void, nem teljes, vagy fggvny tpus.
Nem lehet a definci alatt ll uni egy pldnya, de ilyenre mutat
mutat persze lehet.
- Unik esetben a deklarciban csak az elsnek deklarlt tagnak ad-
hat explicit kezdrtk. Pldul:
union unika{
int i;
double d;
char t[6]; } u = { 24 };
Csak az u.i kaphatott, s kapott is 24 kezdrtket. Ha kicsit bonyo-
lultabb esetet nznk:
union{
char x[2][3];
int i, j ,k; } y = {{{'1'}, {'4'}}};
Az y uni vltoz inicializlsakor aggregtum inicializtort hasz-
nlunk, mert az uni els tagja ktdimenzis tmb. Az 1 iniciali-
ztor a tmb els sorhoz tartozik, gy az y.x[0][0] felveszi az 1
rtket, s a sor tovbbi elemei tiszta zrusok lesznek az implicit kez-
drtk ads szablyai szerint. A 4 a msodik sor els elemnek
inicializtora, azaz y.x[1][0] = 4, y.x[1][1] = 0 s y.x[1][2] = 0.
- Loklis lettartam unik esetn az inicializtor kompatibilis uni
tpus egyszer kifejezs is lehet:
union unika{
int i;
double d;
char t[6]; } u = { 24 }, u1 = u;
- Az unideklarciban is elhagyhat az unicmke. Az unik elfor-
dulhatnak struktrkban, tmbkben, s tmbk, ill. struktrk is
lehetnek tagok unikban:
#define MERET 20
struct {
char *nev;
int adat;
int u_tipus; /* Az uniban aktulisan trolt */
union{ /* tpus nyilvntartshoz. */
int i;
float f;
char *mutato; } u;
} tomb[MERET];
C programnyelv 245
Ilyenkor a tomb i-edik eleme i unitagjhoz val hozzfrs alakja:
tomb[i].u.i
s a mutato tag mutatta els karakter elrsnek formja:
*tomb[i].u.mutato
10.9 Bitmezk (bit fields)
Bitmezk csak struktra vagy uni tagjaknt definilhatk, de a strukt-
rban s az uniban akr keverten is elfordulhatnak bitmez s nem bit-
mez tagok. A bitmez struktratag deklarcis szintaktikja kicsit eltr a
norml tagoktl:
tpusspecifiktor <deklartor> : konstans-kifejezs;
, ahol a tpusspecifiktor csak
- signed int,
- unsigned int vagy
- int
lehet az ANSI C szabvny szerint. Az int tulajdonkppen signed int. A
deklartor a bitmez azonostja, mely el is maradhat. Ilyenkor a nvtelen
bitmez specifiklta bitekre nem tudunk hivatkozni, s a bitek futsidej
tartalma elre megjsolhatatlan. A konstans-kifejezs csak egszrtk le-
het. Zrus s sizeof(int)*8 kzttinek kell lennie, s a bitmez szlessgt
hatrozza meg.
e Bitmez csak struktra vagy uni tagjaknt deklarlhat. Nem k-
pezhet azonban bitmezk tmbje. Fggvnynek sem lehet visszaadott r-
tke a bitmez. Nem megengedett a bitmezre mutat mutat s tilos hi-
vatkozni a bitmez tag cmre, azaz nem alkalmazhat r a cm (&) ope-
rtor sem.
A bitmezk az int terleten (dupla szban, vagy szban) deklarcijuk
sorrendjben az alacsonyabb helyirtk bitpozciktl a magasabbak fel
haladva foglaljk el helyket.
Az int pontos mrete, bitmezvel val feltltsnek szablyai s
sorrendje a programfejleszt rendszertl fgg. Clszer teht a segtsg-
ben utnanzni a dolognak. Maradjunk meg azonban az elz bekezds-
ben emltett szablynl, s a knnyebb szemlltethetsg vgett mg azt is
ttelezzk fel, hogy az int 16 bites! Ilyenkor pldul a:
struct bitmezo{
int i: 2;
unsigned j: 5;
246 STRUKTRK S UNIK
int : 4, k: 1;
unsigned m: 4; } b, *pb = &b;
ltal elfoglalt sz bittrkpe a kvetkez:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
m k g j i
Ha az m bitmez tag szlessge 4-nl nagyobb lett volna, akkor j szt
kezdett volna a fordt, s az elz sz fels ngy bitje kihasznlatlan ma-
radt volna. ltalnossgban: a (dupla)szn tllg bitmez j (dupla)szt
kezd, s az elz (dupla)szban a fels bitek kihasznlatlanok maradnak.
Ha a deklarciban valamely (nvtelen) bitmeznl zrus szless-
get adunk meg, akkor mestersgesen knyszertjk ki ezt a kvetkez
(dupla) szhatrra llst.
e A bitmeznek elg szlesnek kell lennie ahhoz, hogy a rgztett
bitminta elfrjen benne! Pldul a kvetkez tagdeklarcik illeglisak:
int alfa : 17;
unsigned beta : 32
A bitmezk ugyanazokkal a tagszelektor opertorokkal (. s ->) rhetk
el, mint a nem bitmez tagok:
b.i vagy pb->k
A bitmezk kis signed vagy unsigned egsz rtkekknt viselkednek
(rgtn tesnek az egszellptetsen), azaz kifejezsekben ott fordul-
hatnak el, ahol egybknt aritmetikai (egsz) rtkek lehetnek. signed
esetben a legmagasabb helyirtk bit (MSB - most significant bit) eljel-
bitknt viselkedik, azaz az int i : 2 lehetsges rtkei pldul:
00: 0, 01: +1, 10: -2, 11: -1
Az unsigned m : 4 lehetsges rtkei:
0000: 0, 0001: 1, . . ., 1111: 15
ltalnossgban:
unsigned x : szlessg; /* 0 <= x <= 2
szlessg
-1 */
signed y : szlessg; /* -2
szlessg-1
<= y <=+2
szlessg-1
-1 */
e A nyelvben nincs sem egsz alul, sem tlcsorduls. Ha gy a bitme-
znek brzolsi hatrain kvli rtket adunk, akkor abbl is lesz vala-
mi. Mghozz az rtk annyi als bitje, mint amilyen szles a bitmez.
Pldul:
b.i = 6; /* 110 10, azaz -2 lesz az rtke! */
C programnyelv 247
A bitmezk brzolsa gpfgg, mint mr mondottuk, azaz port-
bilis programokban kerljk el hasznlatukat!
Vegyk el ismt a Bit szint opertorok fejezetben trgyalt dtum s
idtrolsi problmt! Hogyan tudnnk ugyanazt a feladatot bitmezkkel
megoldani?
Dtum: Bitpozci: Id: Bitpozci:
v 1980 9 - 15 ra 11 15
hnap 5 - 8 perc 5 10
nap 0 - 4 kt msodperc 0 4
A dtum s az id adatot egy-egy szban, azaz C nyelvi fogalmakkal
egy-egy unsigned short int-ben tartjuk. A kt sz bitfelosztsa az brn
lthat!
A bitmezs megolds pldul a kvetkez is lehetne:
struct datum{
unsigned short nap: 5, ho: 4, ev: 7; }
d = { 8, 3, 1996-1980 };
struct ido{
unsigned short mp2: 5, perc: 6, ora: 5; }
i = { 2, 59, 11 };
/* . . . */
int ev=1996, ho=3, nap=8, ora=11, perc=59, mp=4;
/* Rszeibl a dtum s az id ellltsa: */
d.ev = ev -1980;
d.ho = ho;
d.nap = nap;
i.ora = ora;
i.perc = perc;
i.mp2 = mp >> 1;
/* Ugyanez visszafel: */
ev = d.ev +1980;
ho = d.ho;
nap = d.nap;
ora = i.ora;
perc = i.perc;
mp = i.mp2 << 1;
10.10Balrtk jobbrtk
Most mr tkletesen pontosthatjuk a balrtk kifejezst a Cben,
mely:
- Egsz, lebegpontos, mutat, struktra vagy uni tpus azonost.
- Indexes kifejezs, mely nem tmbb (hanem elemm) rtkelhet
ki.
248 STRUKTRK S UNIK
- Tagszelektoros kifejezs (->, .).
- Nem tmbre hivatkoz, indirekcis kifejezs.
- Balrtk kifejezs zrjelben.
e A const objektum nem mdosthat balrtk, hisz csak a deklarci-
ban kaphat kezdrtket.
A jobbrtk (rvalue) olyan kirtkelhet kifejezs, melynek rtkt bal-
rtk veheti fel. Pldul:
a = c + d; /* OK */
c + d = a; /* HIBS */
A balrtk (lvalue) olyan kifejezs, mely elri az objektumot (a hozz
alloklt memria terletet). Trivilis pldul egy vltoz azonostja. Le-
het azonban *P alak is, ahol a P kifejezst nem NULL mutatra rtkeli
ki a fordt. Onnt is szrmaztathat a kt fogalom, hogy a balrtk llhat
a hozzrendels opertor bal oldaln, s a jobbrtk pedig a jobb oldaln.
Beszlhetnk mdosthat balrtkrl is! Mdosthat balrtk nem le-
het tmb tpus (a tmbazonost praktikusan cm konstans), nem teljes
tpus, vagy const tpusmdostval elltott objektum. Mdosthat balr-
tk pldul a konstans objektumra mutat mutat maga, mikzben a mu-
tatott konstans objektum nem vltoztathat. Pldul
int tomb[20];
esetn balrtkek:
tomb[3] = 3; *(tomb+4) = 4;
A kvetkez deklarciban viszont a kar nem balrtk, hisz konstanss-
gra val tekintettel rtket egyedl a defincijban kaphat:
const char kar = k;
Azonban ha van egy
char *pozicio(int index);
fggvny, akkor balrtk lehet a kvetkez is:
*pozicio(5) = z;
10.11Nvterletek
A nvterlet az a hatskr, melyen bell egy azonostnak egyedinek
kell lennie, azaz msms nvterleten konfliktus nlkl hasznlhat
ugyanaz az azonost, s a fordt meg tudja klnbztetni ket. A nvte-
rleteknek a kvetkez fajti vannak:
C programnyelv 249
- Utasts cmke nvterlet: Az utasts cmkknek abban a fggvny-
ben kell egyedinek lennik, amelyben definiltk ket.
- Struktra, uni s enum cmke nvterlet: A struktra, az uni s az
enum cmkk ugyanazon a nvterleten osztoznak. Deklarlsuk
blokkjban kell egyedinek bizonyulniuk. Ha minden fggvny tes-
tn kvl adjk meg ket, akkor viszont fjl hatskrben kell egyedi-
nek lennik.
- Struktra s unitag ok (member) nvterlete: A tagneveknek abban
a struktrban vagy uniban kell egyedinek lennik, amelyben dek-
larltk ket. Klnbz struktrkban s unikban elfordulhatnak
ugyanazon tagazonostk akr ms tpussal, s eltolssal. sszestve:
mindenegyes struktra s uni kln nvterlettel rendelkezik.
- Norml azonost k nvterlete: Idetartozik minden ms nv, ami
nem frt be az elz hrom nvterletbe, azaz a vltoz, a fggvny
(belertve a formlis paramtereket, s a loklis vltozkat) s az
enumertorazonostk. Abban a hatskrben kell egyedinek bizo-
nyulniuk, ahol definiljk ket. Pldul a fjl hatskr azonostk-
nak ugyanebben a hatskrben kell egyedinek lennik.
- Tpusdefinci (typedef) nevek: Nem hasznlhatk azonostknt
ugyanabban a hatskrben. Magyarn a tpusdefincis nevek a nor-
ml azonostk nvterletn vannak, de nem futsidej azonostk!
Teht, ha a helyzetbl eldnthet, akkor lehet a tpusdefincis nv,
s pldul egy loklis hatskr vltoz azonostja egyforma is:
typedef char FT;
int fv(int lo){
int FT; /* Ez az FT egy int tpus loklis
vltoz
azonostja. */
/* . . . */ }
Nzznk nhny pldt!
struct s{
int s; /* OK: a struktratag jabb nvterleten
helyezkedik el. */
float s;/*HIBS: gy mr kt azonos tagnv lenne egy
struktrn bell. */
} s; /* OK: a norml vltozk nvterlete klnbzik
minden eddig hasznlttl. */
union s{ /* HIBA: az s struktracmke is ezen a
nvterleten van. */
int s; /* OK: hisz j tag nvterlet kezddtt. */
float f;/*OK: ms azonostj tag. */
} f; /* OK: hisz ez az f az norml vltozk
250 STRUKTRK S UNIK
nvterletn tallhat. */
struct t{
int s; /* OK: hiszen megint jabb tag nvterlet
kezddtt. */
/* . . . */
} s; /* HIBA: s azonost most mr minden
nvterleten van. */
goto s; /* OK: az utasts cmke s a struktracmke
ms-ms nvterleten vannak. */
/* . . . */
s: ; /* Utasts cmke. */
C programnyelv 251
11 MAGAS SZINT BEMENET, KIMENET
A magas szint bemeneten s kimeneten olyan folyam, ram (stream)
jelleg fjl, ill. eszkz (nyomtat, billentyzet, kperny stb.) kezelst r-
tnk, ami a felhasznl szempontjbl nzve szinte nincs tekintettel a m-
gttes hardverre, s gy a lehet legflexibilisebb kimenetet, bemenetet biz-
tostja.
A valsgban a folyamot egy FILE tpus struktrra mutat mutat val
manipulljuk. Ezt a struktrt, a folyamkezel fggvnyek prototpusait
stb. az STDIO.H fejfjlban definiltk. A struktra pldul legyen a k-
vetkez!
typedef struct{
short level; /* Puffer teltettsgi szint. */
unsigned short flags;/* Fjl llapotjelzk. */
char fd; /* Fjl ler. */
unsigned char hold; /* ungetc kar., ha nincs puffer. */
int bsize; /* A puffer mrete. */
unsigned char *buffer;/* A puffer cme. */
unsigned char *curp; /* Aktulis pozci a pufferben. */
/* . . . */
} FILE;
A programunkban
FILE *fp;
deklarcis utastssal FILE tpus struktrra mutat mutatt kell dekla-
rlni, mely rtket a folyamot megnyit fopen, freopen fggvnyektl
kap. Teht hasznlat eltt a folyamot meg kell nyitni. Megnyitsa a folya-
mot egy fjlhoz, vagy egy eszkzhz kapcsolja. Jelezni kell azt is ilyen-
kor, hogy a folyamot csak olvassra, vagy rsra, vagy mind kettre kvn-
juk hasznlni stb. Ezutn elvgezhetjk a kvnt bemenetet, kimenetet a
folyamon, majd legvgl le kell zrni.
11.1 Folyamok megnyitsa
FILE *fopen(const char *fajlazonosito, const char *mod);
A fggvny megnyitja a fajlazonositoval megnevezett fjlt, s folyamot
kapcsol hozz. Visszaadja a fjlinformcit tartalmaz FILE struktrra
mutat mutatt, mely a rkvetkez mveletekben azonostani fogja a fo-
lyamot, ill. NULL mutatt kapunk tle, ha a megnyitsi ksrlet sikertelen
volt.
A fajlazonosito termszetesen tartalmazhat (esetleg meghajt nevet)
utat is, de a maximlis sszhossza FILENAME_MAX karakter lehet.
252 SZABVNY, MAGAS SZINT BEMENET, KIMENET
A msodik paramter mod karakterlnc meghatrozza a ksbbi adatt-
vitel irnyt, helyt s a folyam tpust. Nzzk a lehetsgeket!
r Megnyits csak olvassra.
w Ltrehozs rsra. A mr ltez, ilyen azonostj fjl tartalma
megsemmisl.
a Hozzfzs: megnyits rsra a fjl vgn, vagy ltrehozs rs-
ra, ha a fjl eddig nem ltezett.
r+ Egy ltez fjl megnyitsa feljtsra (rsra s olvassra).
w+ j fjl ltrehozsa feljtsra. A ltez fjl tartalma elvsz.
a+ Megnyits hozzfzsre: a fjl vgn feljtsra, vagy j fjl lt-
rehozsa feljtsra, ha a fjl eddig nem ltezett.
A folyam tpusa szveges (text), vagy binris lehet. A szveges folyam a
bemenetet s a kimenetet sorokbl llknak kpzeli el. A sorok vgt egy
\n (LF) karakter jelzi. Lemezre trtn kimenet esetn a folyam a sorle-
zr \n karaktert \r\n karakter prral (CR-LF) helyettesti. Megfordt-
va: lemezes bemenetnl a CR-LF karakter prbl ismt LF karakter lesz.
Ezt a manipulcit transzlcinak nevezzk. Bemenet esetn a folyam a
0X1A rtk karaktert fjlvgnek tekinti. sszegezve: a szveges folyam
bizonyos, kitntetett karaktereket specilisan kezel, mg a binris folyam
ilyent egyetlen karakterrel sem tesz.
Elismerjk termszetesen, hogy nincs transzlci mindenegyes ope-
rcis rendszerben.
A mod karakterlncban expliciten megadhatjuk a folyam tpust. A sz-
vegest a t, a binrist a b jelli. A folyamtpus karakter a karakterlnc-
ban az els bet utn brhol elhelyezhet, azaz megengedettek az
rt+, r+t stb.
e Nem ktelez azonban a folyamtpust a mod karakterlncban expli-
citen megadni. Ha elhagyjuk, alaprtelmezs a szveges.
Ha a folyamot feljtsra (update) nyitottk meg, akkor megengedett
mind a bemenet, mind a kimenet. A kimenetet azonban fflush, vagy poz-
cionl (fseek, rewind stb.) fggvny hvsa nlkl nem kvetheti kz-
vetlenl bemenet. A fordtott adatirnyvlts is csak fjlvgen, vagy e
fggvnyek hvsnak kzbeiktatsval valsthat meg.
11.2 Folyamok pufferezse
A fjlokhoz kapcsolt folyamok szoksosan pufferezettek, s a puffer le-
foglalsa megnyitskor automatikusan megtrtnik malloc hvssal. Ez is
megengedi azonban az egy karakteres szint bemenetet, kimenetet
C programnyelv 253
(getc, putc), ami nagyon gyors. A pufferrel kapcsolatos informcikat a
FILE struktra tagjai rjk le:
curp
level
buffer 7
bsize
, ahol buffer a puffer kezdcme s bsize a mrete. A curp a pufferbeli
aktulis pozcira mutat, s level pedig szmllja, hogy mg hny karakter
van htra a pufferben. A teljes pufferezettsg azt jelenti, hogy kirs auto-
matikusan csak akkor trtnik, ha a puffer teljesen feltelt, ill. olvass csak
akkor kvetkezik be, ha a puffer teljesen kirlt. Egy karakter rsa, vagy
olvassa a curp pozcirl, ill. pozcira trtnik, s a mvelet mellkhat-
saknt a curp eggyel n, s a level eggyel cskken.
A pufferezetlensg azt jelenti, hogy a bjtok tvitele azonnal megtrt-
nik a fjlba (fjlbl), vagy az eszkzre (eszkzrl).
A mai opercis rendszerek legtbbje a kisebb fjlokat megnyitsuk
utn valamilyen rendszer terleten (cache) tartja, s a pufferek is csak a
memriabeli fjllal vannak kapcsolatban. Clszer teht, a programfej-
leszt rendszer segtsgben utnanzni, hogy az azonnali fjlba rs, vagy
olvass pontosan hogyan valsthat meg, ha igazn szksg van r.
A setbuf s a setvbuf fggvnyhvsokkal kijellhetnk sajt puffert,
mdosthatjuk a hasznlatos puffer mrett, vagy pufferezetlenn tehetjk
a bemenetet s a kimenetet.
void setbuf(FILE *stream, char *puff);
A fggvny az automatikusan alloklt (malloc) puffer helyett a puff puf-
fert hasznltatja a stream folyammal adattvitel esetn. Ha a puff param-
ter NULL mutat, akkor a folyam pufferezetlen lesz, msklnben a fo-
lyam teljesen pufferezett. A puffer klnben BUFSIZ mret.
A szabvny bemenet (stdin) sorpufferezett s a szabvny kimenet
(stdout) pufferezetlen, ha nincsenek az opercis rendszerben tirnytva,
mert ekkor mindkett teljesen pufferezett. A sorpufferezettsg azt jelenti,
hogy ha a puffer res, a kvetkez bemeneti mvelet megksrli a teljes
puffer feltltst. Kimenet esetn mindig kirl a puffer, ha teljesen felte-
lik, ill. amikor \n karaktert runk bele.
l Elre megjsolhatatlan hiba kvetkezik be, ha a setbuf fggvnyt
nem kzvetlenl a folyam megnyitsa utn hvjk meg. Leglis lehet mg
a pufferezetlen folyamra vonatkoz setbuf hvs, brhol is kvetkezik be.
254 SZABVNY, MAGAS SZINT BEMENET, KIMENET
l Vigyzzunk a puffer auto trolsi osztly deklarcijval, mert ak-
kor csak abbl a fggvnybl lesz elrhet, ahol deklarltuk! Mg szar-
vasabb a hiba, ha kilpnk a folyam lezrsa nlkl abbl a fggvnybl,
melyre nzve a puffernk loklis volt.
int setvbuf(FILE *stream, char *puff, int tipus, size_t meret);
A fggvny ugyanazt teszi, mint a setbuf. Lthat azonban, hogy expli-
citen megadhat a puffer tipusa s merete. A size_t tpusbl kvetkezleg
nagy mret puffer is elrhat. A pufferezetlensg ezzel a fggvnnyel a
tipus paramter megfelel megadsval rhet el, ugyanis ha az aktulis
puff paramtert NULL mutatnak vlasztjuk, akkor a rutin mallockal
foglal memrit a puffernek.
A tipus paramter lehetsges rtkei a kvetkezk:
- _IOFBF: A fjl teljesen pufferezett. Ha kirl, a kvetkez beme-
neti mvelet megksrli teljesen feltlteni a puffert. Kimenet esetn
fjlba rs automatikusan csak akkor trtnik, ha a puffer teljesen
feltelt.
- _IOLBF: A fjl sorpufferezett.
- _IONBF: A fjl pufferezetlen. A puff s a meret paramter figyel-
men kvl marad. Minden bemeneti s kimeneti mvelet kzvetlen
adattvitelt jelent a fjlba.
A setvbuf zrust ad vissza sikeres esetben, s nem zrust kapunk, ha a
megadott tipus, vagy a meret paramter rvnytelen, vagy nincs elg me-
mria a puffer alloklshoz.
Nzznk egy pldt!
#include <stdio.h>
char puff[BUFSIZ];
void main(void) {
FILE *input, *output;
if((input=fopen("file.in","r"))!=NULL){
if(output=fopen("file.out","w")){
if(setvbuf(input,puff,_IOFBF,BUFSIZ))
printf("Sikertelen a sajt input puffer
alloklsa!\n");
/* A bemeneti folyam sajt puffert hasznlva,
minimlis lemezhez fordulssal mveletre ksz. */
if(setvbuf(output,NULL,_IOLBF,128))
printf("Az output puffer alloklsa
sikertelen!\n");
else{
/* A kimeneti folyam sorpufferezetten, malloc
hvssal alloklt pufferrel mveletre ksz. */
C programnyelv 255
/* Itt intzhet a fjlkimenet s bemenet! */ }
/* Fjlok lezrsa. */
fclose(output); }
else printf("Az output fjl megnyithatatlan!\n");
fclose(input); }
else printf("Az input fjl megnyitsa sikertelen!\n"); }
Eddig csak a pufferek automatikus rtsrl beszltnk. Lehetsges
azonban a pufferek kzi rtse is. St, adattviteli irnyvlts eltt a ki-
meneti puffert ki is kell rteni. Lssuk a fggvnyt!
int fflush(FILE *stream);
Kimenetre nyitott folyam esetn a rutin kirja a puffer tartalmt a kap-
csolt fjlba.
Bemeneti folyamnl a fggvny eredmnye nem definilhat, de tbb-
nyire trli a puffer tartalmt.
Mindkt esetben nyitva marad a folyam.
Pufferezetlen folyamnl e fggvny hvsnak nincs hatsa.
Sikeres esetben zrust kapunk vissza. Hibs esetben a szolgltatott rtk
EOF.
Az fflush(NULL) rti az sszes kimeneti folyamot.
11.3 Pozcionls a folyamokban
A folyamokat rendszerint szekvencilis fjlok olvassra, rsra hasz-
nljk. A magas szint bemenet, kimenet a fjlt bjtfolyamnak tekinti,
mely a fjl elejtl (0 pozci) indul s a fjl vgig tart. A fjl utols po-
zcija a fjlmret - 1. Az adattvitel mindig az aktulis fjlpozcitl kez-
ddik, megtrtnte utn a fjlpozci a fjlban kvetkez, t nem vitt bjt-
ra mozdul. A fjlpozcit fjlmutatnak is szoks nevezni.
Eszkzhz kapcsolt folyam mindig csak szekvencilisan (zrustl indu-
l, monoton nvekv fjlpozcival) rhet el. Lemezes fjlhoz kapcsolt
folyam bjtjai azonban direkt (random) mdon is olvashatk s rhatk.
Lemezes fjlok esetn a fjlmutat adattvitel eltti belltst az
int fseek(FILE *stream, long offset, int ahonnet);
fggvnnyel vgezhetjk el, mely a stream folyam fjlmutatjt offset
bjttal az ahonnet paramterrel adott fjlpozcin tlra lltja be. Szveges
folyamokra az offset zrus lehet, vagy egy az ftell fggvny ltal vissza-
adott rtk.
Az ahonnet paramter a kvetkez rtkeket veheti fel:
256 SZABVNY, MAGAS SZINT BEMENET, KIMENET
- SEEK_SET: A fjl kezdettl.
- SEEK_CUR: Az aktulis fjlpozcitl.
- SEEK_END: A fjl vgtl.
A fggvny elvet minden a bemenetre ungetcvel visszarakott karak-
tert.
Az ungetcrl a kvetkez fejezetben lesz sz!
Feljtsra megnyitott fjl esetn az fseek utn mind bemenet, mind ki-
menet kvetkezhet.
A fggvny trli a fjlvg jelzt.
Lsd a fjl llapotjelzi kzt mg ebben a fejezetben!
A fggvny zrust ad vissza, ha a fjlpozcionls sikeres volt, ill. nem
zrust kapunk hiba esetn.
rjunk fjlmretet megllapt fggvnyt!
#include <stdio.h>
long fajlmeret(FILE *stream) {
long aktpoz, hossz;
aktpoz=ftell(stream);
fseek(stream, 0L, SEEK_END);
hossz=ftell(stream);
fseek(stream, aktpoz, SEEK_SET);
return(hossz); }
A fajlmeret elteszi a pillanatnyi pozcit az aktpoz vltozba, hogy
a fjl vgre llts utn helyre tudja hozni a fjlmutatt. A lekrdezett
fjlvg pozci ppen a fjlmret.
Nzzk a tovbbi fjlpozcival foglalkoz fggvnyeket!
long int ftell(FILE *stream);
A rutin visszaadja a stream folyam aktulis fjlpozcijt sikeres eset-
ben, msklnben -1L-t kapunk tle. A
void rewind(FILE *stream);
a stream folyam fjlmutatjt a fjl elejre lltja.
Feljtsra megnyitott fjl esetn a rewind utn mind bemenet, mind ki-
menet kvetkezhet.
A fggvny trli a fjlvg s a hibajelz biteket.
C programnyelv 257
A FILE struktra flags szava bitjei (llapotjelzi) a kvetkez jelent-
sek lehetnek!
#define _F_RDWR 0x0003 /* olvass s rsjelz */
#define _F_READ 0x0001 /* csak olvashat fjl */
#define _F_WRIT 0x0002 /* csak rhat fjl */
#define _F_BUF 0x0004 /* malloc pufferelt */
#define _F_LBUF 0x0008 /* sorpufferelt fjl */
#define _F_ERR 0x0010 /* hibajelz */
#define _F_EOF 0x0020 /* fjlvg jelz */
#define _F_BIN 0x0040 /* binris fjl jelz */
/* . . . */
A megadott stream folyam aktulis fjlpozcijt helyezi el az
int fgetpos(FILE *stream, fpos_t *pos);
a pos paramterrel adott cmen. Ez a rtk felhasznlhat az fsetposban.
A visszaadott rtk zrus hibtlan, s nem zrus sikertelen esetben. Az
int fsetpos(FILE *stream, const fpos_t *pos);
a stream folyam fjlmutatjt lltja be a pos paramterrel mutatott rtk-
re.
Feljtsra megnyitott fjl esetn az fsetpos utn mind bemenet, mind
kimenet kvetkezhet.
A fggvny trli a fjlvg jelz bitet, s elvet minden, e fjlra vonatkoz
ungetc karaktert.
A visszakapott rtk egyezik az fgetposnl rottakkal.
Vegyk szre, hogy az fseek s az ftell long rtkekkel dolgozik. A
maximlis fjlmret gy 2GB lehet. Az fpos_t adattpus e korlt ttrst
biztostja, hisz mgtte akr 64 bites egsz is lehet.
11.4 Bemeneti mveletek
int fgetc(FILE *stream);
A folyam kvetkez unsigned char karaktert adja vissza eljel kiter-
jeszts nlkl intt konvertltan, s eggyel elbbre lltja a fjlpozcit.
Sikertelen esetben, ill. fjl vgn EOFot kapunk. A
int getc(FILE *stream);
makr, mint ahogyan ez a lehetsges defincijbl is ltszik, ugyanezt te-
szi:
#define getc(f) \
((--((f)->level)>=0) ? (unsigned char)(*(f)->curp++) :\
258 SZABVNY, MAGAS SZINT BEMENET, KIMENET
_fgetc(f))
int ungetc(int c, FILE *stream);
A fggvny visszateszi a stream bemeneti folyamba a c paramter un-
signed char tpusv konvertlt rtkt gy, hogy a kvetkez olvasssal
ez legyen az els elrhet karakter. A szablyos mkds csak egyetlen
karakter visszahelyezse esetn garantlt, de a visszatett karakter nem le-
het az EOF.
Kt egymst kvet ungetc hvs hatsra mr csak a msodiknak
visszatett karakter rhet el, mondjuk, a kvetkez getcvel, azaz az els
elveszik. Gondoljuk csak meg, hogyha nincs puffer, akkor a visszattelhez
a FILE struktra egyetlen hold tagja ll rendelkezsre!
Az fflush, az fseek, az fsetpos, vagy a rewind trli a bemenetre vissza-
tett karaktert.
Sikeres hvskor az ungetc a visszatett karaktert adja vissza. Hiba ese-
tn viszont EOFot kapunk tle. Az
char *fgets(char *s, int n, FILE *stream);
karakterlncot hoz be a stream folyambl, melyet az s cmtl kezdve he-
lyez el a memriban. Az tvitel lell, ha a fggvny n - 1 karaktert, vagy
\nt olvasott. A rutin a \n karaktert is kiteszi a lncba, s a vghez
mg zr \0t is illeszt.
Sikeres esetben az fgets az s karakterlncra mutat mutatval tr vissza.
Fjlvgen, vagy hiba esetn viszont NULLt szolgltat.
Vegyk szre, hogy a jegyzet eleje ta hasznlt getline fggvny
csak annyiban tr el az fgetstl, hogy:
- A beolvasott karakterlnc mrett adja vissza.
- A szabvny bemenetrl (stdin) olvas, s nem ms folyambl, gy
eggyel kevesebb a paramtere.
- n karaktert hoz be legfeljebb, vagy \nig, de magt a soremels ka-
raktert nem teszi be az eredmny karakterlncba.
size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
A fggvny n * size bjtot olvas a stream folyambl, melyet a ptr para-
mterrel mutatott cmen helyez el. Visszaadott rtke nem a beolvasott
bjtok szma, hanem a
beolvasott bjtok szma / size
C programnyelv 259
sikeres esetben. Hiba, vagy fjlvg esetn ez persze nem egyezik nnel.
Az eddig ismertetett bemeneti fggvnyek nem konvertltk a beolva-
sott karakter(lnco)t. Az
int fscanf(FILE *stream, const char *format<, cim, ...>);
viszont a stream folyambl karakterenknt olvasva egy sor bemeneti me-
zt vizsgl. Aztn minden mezt a format karakterlncnak megfelelen
konvertl, s letrol rendre a paramter cimeken. A format karakterlnc-
ban ugyanannyi konverzit okoz formtumspecifikcinak kell lennie,
mint ahny bemeneti mez van.
A jellsben a <> az elhagyhatsgot, a ... a megelz paramter
tetszleges szm ismtelhetsgt jelenti. A bemeneti mez defincija,
a formzs s a konvertls rszletei a scanf fggvny lersban tallha-
tk meg!
Az fscanf a sikeresen vizsglt, konvertlt s letrolt bemeneti mezk
szmval tr vissza. Ha a fggvny az olvasst a fjl vgn ksreln meg,
vagy valamilyen hiba trtnne, akkor EOF-ot kapunk tle vissza. A rutin
zrussal is visszatrhet, ami azt jelenti, hogy egyetlen vizsglt mezt sem
trolt le.
11.5 Kimeneti mveletek
int fputc(int c, FILE *stream);
A fggvny a c unsigned char tpusv konvertlt rtkt rja ki a stre-
am folyamba. Sikeres esetben a c karaktert kapjuk vissza tle, hiba bek-
vetkeztekor viszont EOFot. A
int putc(int c, FILE *stream);
makr, mint ahogyan ez a lehetsges defincijbl is ltszik, ugyanezt te-
szi:
#define putc(c,f) \
((++((f)->level)<0) ? (unsigned char)(*(f)->curp++)=(c)) :\
_fputc((c),f))
int fputs(const char *s, FILE *stream);
A fggvny az s karakterlncot kirja a stream folyamba. Nem fz hozz
\n karaktert, s a lezr \0 karakter sem kerl t.
Sikeres esetben nem negatv rtkkel tr vissza. Hiba esetn viszont
EOFot kapunk tle. Az
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);
260 SZABVNY, MAGAS SZINT BEMENET, KIMENET
a ptr cmmel mutatott memria terletrl n * size bjtot r ki a stream fo-
lyamba. Visszaadott rtke nem a kirt bjtok szma, hanem a
kirt bjtok szma / size
sikeres esetben. Hiba bekvetkeztekor ez nem egyezik nnel.
Az eddigi kimeneti fggvnyek nem vgeztek konverzit. Az
int fprintf(FILE *stream, const char *format<, parameter, ...>);
fogad egy sor parametert, melyeket a format karakterlncnak megfelelen
formz (konvertl), s kivisz a stream folyamba. A format karakterlnc-
ban ugyanannyi konverzit okoz formtumspecifikcinak kell lennie,
mint ahny parameter van.
A jellsben a <> az elhagyhatsgot, a ... a megelz paramter
tetszleges szm ismtelhetsgt jelenti. A formzs s a konvertls
rszletei a printf fggvny lersban tallhatk meg!
Az fprintf a folyamba kivitt karakterek szmval tr vissza sikeres eset-
ben, ill. EOF-ot kapunk tle hiba bekvetkeztekor.
11.6 Folyamok lezrsa
int fclose(FILE *stream);
A rutin lezrja a stream folyamot. Ez eltt azonban rti a folyamhoz
tartoz puffert, s a pufferhez automatikusan alloklt memrit fel is sza-
badtja.
e Ez utbbi nem vonatkozik a setbuf, vagy a setvbuf fggvnyekkel
hozzrendelt pufferekre. Ezek gyei csak a felhasznlra tartoznak.
Sikeres esetben az fclose zrussal tr vissza. Hiba esetn viszont EOF
ot kapunk tle.
11.7 Hibakezels
Tudjuk, hogy a szabvny knyvtri fggvnyek gy a magas szint be-
menetet, kimenetet kezelk is a hibt, a kivteles esetet gy jelzik, hogy
valamilyen specilis rtket (EOF, NULL mutat, HUGE_VAL stb.) ad-
nak vissza, s az errno globlis hibavltozba belltjk a hiba kdjt. A
hibakdok az ERRNO.H fejfjlban definilt, egsz, nem zrusrtk
szimbolikus llandk.
Programunk indulsakor a szabvny bemeneten (stdin) s kimeneten
(stdout) tl a hibakimenet (stderr) is rendelkezsre ll, s a hibazeneteket
ez utbbin clszer megjelentetni. Az stderr a kperny (karakteres ab-
C programnyelv 261
lak) alaprtelmezs szerint, s nem is irnythat t fjlba a legtbb oper-
cis rendszerben, mint ahogyan a bemenettel (<) s a kimenettel (>) ez
megtehet volt a programot futtat parancssorban.
Mit jelentessnk meg hibazenetknt az stderren?
Termszetesen brmilyen szveget kirathatunk, de a hibakdokhoz
programfejlszt rendszertl fggen hibazenet karakterlncok is tartoz-
nak, s ezek is megjelentethetk. A hibakodhoz tartoz hibazenet karak-
terlnc kezdcmt szolgltatja a szabvnyos
#include <STRING.H>
char *strerror(int hibakod);
fggvny, s az zenet meg is jelentethet
fprintf(stderr, Hiba: %s\n, strerror(hibakod));
mdon. A
void perror(const char *s);
kirja az stderrre azt a hibazenetet, melyet a legutbbi hibt okoz,
knyvtri fggvny hvsa idzett el. Elszr megjelenteti az s karakter-
lncot a rutin, aztn kettspontot (:) tesz, majd az errno aktulis rtk-
nek megfelel zenet karakterlncot rja ki lezr \n-nel.
Teht pldul a perror(Hiba: ) megfelel a
fprintf(stderr, Hiba: %s\n, strerror(errno));
fggvnyhvsnak.
e Vigyzat! Az errno rtkt csak kzvetlenl a hibt okoz rutin h-
vsa utn szabad felhasznlni, mert a kvetkez knyvtri fggvny meg-
idzse fellrhatja e globlis vltoz rtkt. Ha a hibakddal mgis k-
sbb kvnnnk foglalkozni, akkor tegyk el az errno rtkt egy segd-
vltozba!
Folyamokkal kapcsolatban a perror s paramtere a fjlazonost
szokott lenni.
Meg kell trgyalnunk mg hrom, csak a folyamok hibakezelsvel fog-
lalkoz fggvnyt! A
void clearerr(FILE *stream);
262 SZABVNY, MAGAS SZINT BEMENET, KIMENET
nullzza a stream folyam fjlvg s hibajelzjt. Ha a folyam hibajelz
bitje egyszer bebillent, akkor minden a folyamon vgzett mvelet hibval
tr vissza mindaddig, mg a hibajelzt e fggvnnyel, vagy a rewinddal
nem trlik.
A fjlvg jelz bitet egybknt minden bemeneti mvelet nullzza. Az
int feof(FILE *stream);
tbbnyire makr, mely a kvetkez lehetsges
#define feof(f) ((f)->flags & _F_EOF)
defincija miatt, visszaadja a fjlvg jelz bit llapott, azaz vlaszt ad a
fjlvg van-e krdsre.
Az egyszer bebillent fjlvg jelz bit a kvetkez, e folyamra vonatkoz
bemeneti, pozcionl mveletig, vagy clearerrig 1 marad. Az
int ferror(FILE *stream);
makr ebben a szellemben
#define ferror(f) ((f)->flags & _F_ERR)
a hiba jelz bit llapott adja vissza.
Az egyszer bebillent hiba jelz bitet csak a clearerr s a rewind
fggvnyek trlik.
e Ha a krdses folyammal kapcsolatban a bebillent hiba jelz bit tr-
lsrl nem gondoskodunk, akkor minden e folyamra meghvott tovbbi
fggvny hibt jelezve fog visszatrni.
rjuk meg az fputc segtsgvel az fputs fggvnyt!
int fputs(const char *s, FILE *stream){
int c;
while(c=*s++)
if(c!=fputc(c, stream)) break;
return ferror(stream) ? EOF : 1; }
Ksztsnk szoftvert komplett hibakezelssel, mely az els parancssori
paramtere fjlt tmsolja a msodik paramtere azonostj fjlba! Ha a
programot nem elg parancssori paramterrel indtjk, akkor ismertesse
hasznlatt! A msolsi folyamat elrehaladsrl tjkoztasson felttle-
nl!
/* PELDA31.C: Els paramter fjl msolsa a msodikba. */
#include <stdio.h>
#include <string.h>/* strerror miatt! */
#include <errno.h> /* Az errno vgett! */
#define KENT 10 /* Hnyanknt jelenjen meg a szmll.*/
C programnyelv 263
#define SZELES 10 /* Mezszlessg a szml kzlshez. */
int main(int argc, char *argv[]){
FILE *be, *ki; /* A be s kimeneti fjlok. */
long szlo=0l; /* A szmll. */
int c; /* A kv. karakter s segdvltoz. */
printf("Az els paramter fjl msolsa a msodikba:\n");
if(argc<3){
fprintf(stderr, "Programindts:\n"
"PELDA30 forrsfjl clfjl\n");
return 1; }
if(!(be=fopen(argv[1],"rb"))){
perror(argv[1]);
return 1; }
if(!(ki=fopen(argv[2],"wb"))){
perror(argv[2]);
fclose(be);
return 1; }
printf("%s --> %s:\n%*ld",argv[1],argv[2], SZELES, szlo);
A formtumspecifikcibeli * SZELES mezszlessget eredm-
nyez.
while((c=fgetc(be))!=EOF){/* Olvass fjlvgig, vagy
hibig. */
if(c==fputc(c,ki)){ /* Kirs rendben. */
if(!(++szlo%KENT)){
for(c=0; c<SZELES; ++c) fputc('\b', stdout);
printf("%*ld", SZELES, szlo); } }
else{ /* Kirsnl hiba van. */
perror(argv[2]);
clearerr(ki);
if(!fclose(ki)) /* A flksz fjl trlse. */
remove(argv[2]);
else perror(argv[2]);
fclose(be);
return 1; } }
/* Az olvass EOF rtkkel fejezdtt be. */
c=errno; /* Hibakd mentse. */
fclose(ki);
/* A vgs mret kirsa: */
for(c=0; c<SZELES; ++c) fputc('\b', stdout);
printf("%*ld\n", SZELES, szlo);
if(ferror(be)){ /* Hiba volt. */
fprintf(stderr, "%s: %s\n", argv[1], strerror(c));
clearerr(be);
fclose(be);
remove(argv[2]);
return 1; }
fclose(be); /* Minden rendben ment. */
return 0; }
Az stdoutra irnyul mveletek hibakezelsvel azrt nem foglal-
koztunk, mert ahol az sem mkdik, ott az opercis rendszer sem megy.
264 SZABVNY, MAGAS SZINT BEMENET, KIMENET
Megoldand feladatok:
Fokozzuk kicsit a PELDA31.Cben megvalstott feladatot! A fjlba
rs norml esetben akkor nem megy, ha betelik a lemez. Ezen prbljunk
meg gy segteni, hogy a forrsfjl megnyitsa utn llaptsuk meg a m-
rett! A clfjlnak is foglaljunk helyet (fseek) ugyanekkora mretben,
majd feljtva rjuk ki r a forrs tartalmt!
Ksztsen szoftvert, mely eldnti az indt parancssorban megadott azo-
nostj fjl tpust, azaz hogy szveges, vagy binris! Ha parancssori pa-
ramter nlkl futtatjk a programot, akkor ismertesse a hasznlatt!
rjon szoftvert, mely az indt parancssorban megadott szvegfjlokat
egyesti a megads sorrendjben a parancssorban utolsknt elrt azono-
stj szvegfjlba! Ha parancssori paramter nlkl indtjk a programot,
akkor ismertesse a kpernyn, hogyan kell hasznlni! Ha csak egy fjlazo-
nost van a parancssorban, akkor a szabvny bemenet msoland bele. A
fjlok egyestse sorn a folyamat elrehaladsrl tjkoztatni kell a kp-
ernyn! A szabvny bemenet msolsa esetn vgl kzlend mg az
eredmnyfjl mrete! {EGYESIT.C}
11.8 Elre definilt folyamok
Egy idben legfeljebb FOPEN_MAX, vagy OPEN_MAX folyam (fjl)
lehet megnyitva. Ennek megfelel a globlis FILE struktratmb
extern FILE _streams[];
mrete is, melybl radsul mg az els hrom bizonyosan foglalt is:
#define stdin (&_streams[0])
#define stdout (&_streams[1])
#define stderr (&_streams[2])
A globlis FILE struktratmb neve persze lehet ettl eltr is.
Ezek az elre definilt folyamok, melyek programunk futsnak meg-
kezdsekor mr megnyitva rendelkezsre llnak.
Nv B/K Tpus Folyam Alapr-
telmezs
stdin bemenet szveges szabvnyos bemenet CON:
stdout kimenet szveges szabvnyos kimenet CON:
stderr kimenet szveges szabvny hibakimenet CON:
Az stdin s az stdout tirnythat a programot indt parancssorban
szvegfjlba.
program < bemenet.txt > kimenet.txt
C programnyelv 265
Ha nincsenek tirnytva, akkor az stdin sorpufferezett, s az stdout pedig
pufferezetlen. Ilyen az stderr is, teht pufferezetlen. A legtbb opercis
rendszerben cs (pipe) is hasznlhat. Pldul:
program1 | program2 | program3
program1 a rendszerben belltott szabvny bemenettel rendelkezik.
Szabvny kimenete szabvny bemenete lesz program2nek, aminek szab-
vny kimenete program3 szabvny bemenete. Vgl program3 szabvny
kimenete az, amit a rendszerben belltottak.
Mindhrom elre definilt folyam tirnythat a programban is, azaz ha
nem felelne meg az alaprtelmezs szerint a folyamhoz kapcsolt eszkz,
akkor ezt kicserlhetjk az
FILE *freopen(const char *fajlazonosito, const char *mod,
FILE *stream);
fggvnnyel a fajlazonositoj fjlra. A rutin els kt paramternek rtel-
mezse s visszaadott rtke egyezik az fopenvel. A harmadik viszont
az elre definilt folyam: stdin, stdout vagy stderr.
Az freopen persze nem csak elre definilt folyamokra hasznlhat,
hanem brmilyen mssal is, de ez a legjellemzbb alkalmazsa.
Ksztsnk programot, mely a szabvny bemenetrl rkez karaktereket
a parancssori paramterknt megadott szvegfjlba msolja! Ha indts-
kor nem adnak meg parancssori paramtert, akkor csak echzza a szoftver
a bementet a kimeneten!
A feladatot az stdout tirnytsval oldjuk meg.
/* PELDA32.C: Bemenet msolsa fjlba stdout-knt. */
#include <stdio.h>
#include <stdlib.h> /* A system rutin miatt! */
#define PUFF 257 /* A bemeneti puffer mrete. */
int main(int argc, char *argv[]){
char puff[PUFF]; /* Bemeneti puffer. */
if(system(NULL)) system("CLS");
printf("A szabvny bemenet fjlba msolsa "
"Ctrl+Z-ig:\n");
if(argc<2) printf("A program indthat gy is:\n"
"PELDA32 szvegfjl\n\n");
else if(!freopen(argv[1],"wt", stdout)){
perror(argv[1]);
return 1; }
while(fgets(puff, PUFF, stdin)){
if(fputs(puff, stdout)<0){
perror(argv[1]);
clearerr(stdout);
if(!fclose(stdout)) remove(argv[1]);
266 SZABVNY, MAGAS SZINT BEMENET, KIMENET
else perror(argv[1]);
return 1; } }
return 0; }
Az STDLIB.H bekapcsolsval rendelkezsre ll
int system(const char *parancs);
rutin parancs paramtert tadja vgrehajtsra az opercis rendszernek
(a parancsrtelmeznek), azaz vgrehajtatja a rendszerrel a parancsot. A
fggvny visszatrsi rtke a programfejleszt rendszertl fgg, de tbb-
nyire a parancsrtelmez ltal szolgltatott rtk az.
Ha a parancs NULL, akkor a rutin a parancsrtelmez ltezsrl sz-
mol be, azaz ha van, nem zrussal tr vissza, s zrust szolgltat, ha nincs.
11.8.1 Bemenet az stdin-rl
int getchar(void);
A fggvny makr, azaz:
#define getchar() getc(stdin)
A
char *gets(char *s);
az fgetshez hasonlan karaktereket olvas az stdinrl, melyeket rendre
elhelyez a paramter s karaktertmbben. A visszaadott rtke is egyezik
az fgetsvel, azaz norml esetben st szolgltatja, s fjlvg vagy hiba be-
kvetkeztekor NULLt. Az stdinrl val olvass azonban az els \n
karakterig tart. Magt az LF karaktert nem viszi t az s tmbbe, hanem
helyette a karakterlncot zr \0t r oda.
A konverzit is vgz
int scanf(const char *format<, cim, ...>);
fggvny az fscanfhoz hasonlan de az stdin folyambl olvasva egy
sor bemeneti mezt vizsgl. Aztn minden mezt a format karakterlnc-
nak megfelelen formz (konvertl), s letrol rendre a paramter cme-
ken.
A jellsben a <> az elhagyhatsgot, a ... a megelz paramter
tetszleges szm ismtelhetsgt jelenti. A bemeneti mez defincijra
rgtn kitrnk!
A scanf a sikeresen vizsglt, konvertlt s letrolt bemeneti mezk sz-
mval tr vissza. A vizsglt vagy akr konvertlt, de le nem trolt mezk
C programnyelv 267
ebbe a szmba nem rtendk bele. Ha a fggvny az olvasst a fjl vgn
ksreln meg, vagy valamilyen hiba kvetkezne be, akkor EOFot ka-
punk tle vissza. A fggvny zrussal is visszatrhet, ami azt jelenti, hogy
egyetlen vizsglt mezt sem trolt le.
l A format karakterlncban ugyanannyi formtumspecifikcinak kell
lennie, mint ahny bemeneti mez van, s ahny cim paramtert megadtak
a hvsban. Ha a formtumspecifikcik tbben vannak, mint a cimek, ak-
kor ez elre megjsolhatatlan hibhoz vezet. Ha a cim paramterek szma
tbb mint a formtumspecifikcik, akkor a felesleges cimeket egyszer-
en elhagyja a scanf.
A format karakterlnc hrom fle objektumbl ll:
- fehr karakterekbl,
- nem fehr karakterekbl s
- formtumspecifikcikbl.
Ha fehr karakter kvetkezik a format karakterlncban, akkor a scanf
olvassa, de nem trolja a bemenetrl rkez fehr karaktereket egszen a
kvetkez nem fehr karakterig.
Nem fehr karakter minden ms a % kivtelvel. Ha a format karakter-
lncban ilyen karakter kvetkezik, akkor a scanf olvas a bemenetrl, de
nem trol, hanem elvrja, hogy a beolvasott karakter egyezzen a format
karakterlncban levvel.
A formtumspecifikcik vezrlik a scanf fggvnyt az olvassban, a
bemeneti mezk konverzijban s a konverzi tpusban. A konvertlt
rtket aztn a rutin elhelyezi a soron kvetkez paramterrel adott cim
en. A formtumspecifikci ltalnos alakja:
% <*> <szlessg> <h|l|L> tpuskarakter
, ahol a <> az elhagyhatsgot s a | a vagylagossgot jelli. Nzzk a
rszleteket!
- Minden formtumspecifikci % karakterrel indul, s tpuskarakter-
rel vgzdik. Az ltalnos alakban elhagyhatnak jellt rszek csak
az ott megadott sorrendben kerlhetnek a % s a tpuskarakter kz.
- A * elnyomja a kvetkez bemeneti mez hozzrendelst. A scanf
a %*tpuskarakter hatsra olvassa, ellenrzi s konvertlja a vo-
natkoz bemeneti mezt, de nem helyezi el a kapott rtket az ide-
tartoz cim paramteren. Teht a bemeneti mez tartalmnak ilyen-
kor is meg kell felelnie a konverzis tpuskarakternek.
268 SZABVNY, MAGAS SZINT BEMENET, KIMENET
- A szlessg maximlis mezszlessget hatroz meg, azaz a scanf
legfeljebb ennyi karaktert olvashat, de olvashat ennl kevesebbet is,
ha fehr, vagy konvertlhatatlan karakter kvetkezik a bemeneten.
- A h, az l s az L a cim paramter alaprtelmezs szerinti tpust m-
dostja. A h short int. Az l long int, ha a tpuskarakter egsz kon-
verzit specifikl, ill. double, ha a tpuskarakter lebegpontos tala-
ktst r el. Az L pedig a long double mdostja.
A kvetkez tblzatban felsoroljuk az aritmetikai konverzit okoz t-
puskaraktereket:
Tpuska-
rakter
Az elvrt bemenet A paramter tpusa
d decimlis egsz int *
i decimlis, oktlis vagy hexadeci-
mlis egsz
int *
o oktlis egsz (vezet 0 nlkl is an-
nak minsl a szm)
int *
u eljel nlkli decimlis egsz unsigned int *
x hexadecimlis egsz (vezet 0x
vagy 0X nlkl is az a szm)
int *
e, E lebegpontos vals float *
f lebegpontos vals float *
g, G lebegpontos vals float *
- A %d, a %i, a %o, a %x, a %D, a %I, a%O, a %X, a %c s a %n
konverzik esetn unsigned charra, unsigned intre, vagy unsig-
ned longra mutat mutatk is hasznlhatk azoknl az talakt-
soknl, ahol a charra, az intre, vagy a longra mutat mutat
megengedett.
- A %e, a %E, a %f, a %g s a %G lebegpontos konverzik esetn a
bemeneti mezben lev vals szmnak ki kell elgtenie a kvetke-
z formt:
<+|-> ddddddddd <.> dddd <E|e> <+|-> ddd
ahol d decimlis, oktlis, vagy hexadecimlis szmjegyet, a <> el-
hagyhatsgot s a | vagylagossgot jell.
A mutat konverzi tpuskarakterei:
Tpuskarakter Az elvrt bemenet A paramter tpusa
C programnyelv 269
n Nincs. int *. A %n-ig sikeresen olva-
sott karakterek szmt trolja
ebben az int-ben a scanf.
p Megvalststl
fgg formban,
de ltalban hexa-
decimlisan.
void *
A karakteres konverzi tpuskarakterei:
Tpuskarakter Az elvrt bemenet A paramter tpusa
c karakter Mutat charra, ill. mutat
char tmbre, ha mezszless-
get is megadtak. Pl.: %7c.
% % karakter Nincs konverzi. Magt a %
karaktert trolja.
s karakterlnc Mutat char tmbre.
[kereskszlet] karakterlnc Mutat char tmbre.
[^kereskszlet] karakterlnc Mutat char tmbre.
- A %c hatsra a scanf a kvetkez karaktert (akr fehr, akr nem)
olvassa a bemenetrl. Ha a fehr karaktereket t kvnjuk lpni,
hasznljuk a %1s formtumspecifikcit!
- A %szlessgc specifikcihoz tartoz cim paramternek legalbb
szlessg elem karaktertmbre kell mutatnia.
- A %s specifikcihoz tartoz cim paramternek legalbb akkora ka-
raktertmbre kell mutatnia, melyben a vonatkoz bemeneti mez
minden karaktere, s a karakterlncot lezr \0 is elfr.
- A %[kereskszlet] s a %[^kereskszlet] alak specifikci teljes
mrtkben helyettesti az s tpuskaraktert. A vonatkoz cim param-
ternek karaktertmbre kell ekkor is mutatnia. A szgletes zrjelben
lev karaktereket kereskszletnek nevezzk.
- %[kereskszlet] esetben a scanf addig olvassa a bemenetet, mg a
bejv karakterek egyeznek a kereskszlet valamelyik karakter-
vel. A karaktereket kiteszi rendre a rutin \0val lezrtan a param-
ter karaktertmbbe. Pldul a %[abc]-vel az a, a b s a c karak-
terek valamelyikt kerestetjk a bemeneti mezben. A %[]xyz] vi-
szont a ], az x, a y s a z utn kutat.
270 SZABVNY, MAGAS SZINT BEMENET, KIMENET
- %[^kereskszlet] a scanf brmilyen olyan karaktert keres, ami
nincs benn a kereskszletben. Pldul a %[^]abc] hatsra addig
tart a bemenet olvassa, mg rla ], a, b vagy c nem rkezik.
Nhny programfejleszt rendszer esetn a kereskszletben tarto-
mny is megadhat, azaz pldul a %[0123456789]-et a %[0-9] teljes
mrtkben helyettesti. A tartomny kezd karaktere kdjnak azonban ki-
sebbnek kell lenni a tartomny vg karaktere kdjnl. Nzznk nhny
pldt!
- %[-+*/]: A ngy aritmetikai opertort keresi.
- %[0-9A-Za-z]: Alfanumerikus karaktert keres.
- %[+0-9-A-Z]: A +, a -, a szm s a nagybet karaktereket keresi.
- %[z-a]: A z, a - s az a karaktereket keresi.
Tisztzzuk vgre a bemeneti mez fogalmt!
- Minden karakter a kvetkez fehr karakterig, de a fehr karakter
maga mr nem tartozik bele.
- Minden karakter az els olyan karakterig, mely az aktulis tpuska-
rakter szerint nem konvertlhat.
- Minden karakter, mg a megadott mezszlessg ki nem merl.
- Kereskszlet esetn addig tart a bemeneti mez, mg a keresksz-
let feltteleinek meg nem felel karakter nem rkezik a bemenetrl.
A bemeneti mez msodik alternatvja miatt, nem javasoljuk a
scanf fggvny szleskr hasznlatt programokban. Helyette olvassuk
be a bemeneti karakterlncot, vgezzk el rajta az sszes formai ellenr-
zst! Ha aztn minden rendben volt, a konverzi megvalsthat egy me-
netben az
int sscanf(const char *puffer, const char *format<, cim, ...>);
fggvnnyel, mely ugyanazt teszi, mint a scanf, de bemeneti mezit nem
az stdinrl, hanem az els paramterknt kapott karakterlncbl veszi.
11.8.2 Kimenet az stdout-ra
int putchar(int c);
A fggvny makr, azaz:
#define putchar(c) putc((c), stdout)
C programnyelv 271
A
int puts(const char *s);
fggvny a \0 lezrs s karakterlncot az stdout folyamba rja a \0
nlkl, mely helyett viszont kitesz mg egy \n karaktert.
Sikeres esetben nem negatv rtkkel tr vissza. Hiba bekvetkeztekor
viszont EOF-ot kapunk tle.
A konverzit is vgz
int printf(const char *format<, parameter, ...>);
rutin fogad egy sor parametert, melyek mindegyikhez hozzrendel egy, a
format karakterlncban lv formtumspecifikcit, s az ezek szerint for-
mzott (konvertlt) adatokat kiviszi az stdout folyamba.
A jellsben a <> az elhagyhatsgot, a ... a megelz paramter
tetszleges szm ismtelhetsgt jelenti.
l A format karakterlncban ugyanannyi formtumspecifikcinak kell
lennie, mint ahny parameter van. Ha kevesebb a paramter, mint a for-
mtumspecifikci, akkor ez elre megjsolhatatlan hibhoz vezet. Ha
tbb a paramter, mint a formtumspecifikci, akkor a felesleges para-
mtereket egyszeren elhagyja a printf.
A rutin a folyamba kivitt bjtok szmval tr vissza sikeres esetben, ill.
EOFot kapunk tle hiba bekvetkeztekor.
A format karakterlnc ktfle objektumot tartalmaz:
- sima karaktereket s
- formtumspecifikcikat.
A sima karaktereket vltozatlanul kiviszi az stdout-ra a printf. A for-
mtumspecifikcihoz veszi a kvetkez parameter rtkt, konvertlja,
s csak ezutn teszi ki az stdout-ra.
A formtumspecifikci ltalnos alakja a kvetkez:
% <jelzk> <szlessg> <.pontossg> <h|l|L> tpuskarakter
- Minden formtumspecifikci % karakterrel kezddik, s tpuska-
rakterrel vgzdik.
- Ha a % karaktert szeretnnk az stdoutra vinni, akkor meg kell
duplzni (%%).
272 SZABVNY, MAGAS SZINT BEMENET, KIMENET
- Az ltalnos alakban elhagyhatnak jellt rszek csak az ott meg-
adott sorrendben kerlhetnek a % s a tpuskarakter kz.
A kvetkezkben lerjuk a tpuskarakterek rtelmezst arra az esetre,
ha a formtumspecifikciban a % jelet csak a tpuskarakter kveti. Nz-
zk elbb az aritmetikai konverzit okoz tpuskaraktereket:
Tpuska-
rakter
Elvrt pa-
ramter
A kimenet formja
d int Eljeles decimlis egsz.
i int Eljeles decimlis egsz.
o int Eljel nlkli oktlis egsz vezet 0 nlkl.
u int Eljel nlkli decimlis egsz.
x int Eljel nlkli hexadecimlis egsz (a, b, c, d,
e, f-fel), de vezet 0x nlkl.
X int Eljel nlkli hexadecimlis egsz (A, B, C,
D, E, F-fel), de vezet 0X nlkl.
f double <->dddd.dddd alak eljeles rtk.
e double <->d.ddd...e<+|->ddd alak eljeles rtk.
E double <->d.ddd...E<+|->ddd alak eljeles rtk.
g double Az adott rtktl s a pontossgtl fggen e,
vagy f alakban eljeles rtk.
G double Ugyanaz, mint a g forma, de az e alak haszn-
lata esetn az exponens rszben E van.
e vagy E tpuskarakter esetn a vonatkoz paramter rtkt a printf
<->d.ddd...e<+|->ddd
alakra konvertlja, ahol:
- Egy decimlis szmjegy (d) mindig megelzi a tizedes pontot.
- A tizedes pont utni szmjegyek szmt a pontossg hatrozza meg.
- A kitev rsz mindig legalbb kt szmjegyet tartalmaz.
f tpuskarakternl a vonatkoz paramter rtkt a printf
<->ddd.ddd...
alakra konvertlja, s a tizedes pont utn kirt szmjegyek szmt itt is a
pontossg hatrozza meg.
g vagy G tpuskarakter esetn a printf a vonatkoz paramter rtkt e,
E, vagy f alakra konvertlja
- Olyan pontossggal, melyet a szignifikns szmjegyek szma meg-
hatroz.
C programnyelv 273
- A kvet zrusokat levgja az eredmnyrl, s a tizedes pont is csak
akkor jelenik meg, ha szksges, azaz van mg utna rtkes trt
szmjegy.
- A g e, vagy f formj, a G pedig E, vagy f alak konverzit okoz.
- Az e, ill. az E formt akkor hasznlja a printf, ha a konverzi ered-
mnyben a kitev nagyobb a pontossgnl, vagy kisebb 4nl.
A karakteres konverzi tpuskarakterei:
Tpuska-
rakter
Elvrt pa-
ramter
A kimenet formja
% nincs Nincs konverzi. Maga a % karakter jelenik
meg.
c int Egyetlen karakter.
s char * A karakterlnc karakterei megjelennek a zr
\0t kivve. Ha megadtak pontossgot, akkor
legfeljebb annyi karaktert r ki a printf.
A mutat konverzi tpuskarakterei:
Tpuska-
rakter
Elvrt pa-
ramter
A kimenet formja
n int * A paramter ltal mutatott int-ben letrolja az
eddig kirt karakterek szmt. Nincs klnben
semmilyen konverzi.
p void * A paramtert mutatknt jelenteti meg. A ki-
jelzs formtuma programfejleszt rendszer
fgg, de ltalban hexadecimlis.
Lssuk a jelzket!
- Az eredmny balra igaztott, s jobbrl szkzzel prnzott.
Ha a - jelzt nem adjk meg, akkor az eredmny jobbra igaz-
tott, s balrl szkzkkel, vagy zrusokkal prnzott.
+ Eljeles konverzi eredmnye mindig plusz, vagy mnusz el-
jellel kezddik. Ha a + jelzvel egytt szkz jelzt is megad-
nak, akkor a + jelz van rvnyben.
szkz Ha az rtk nem negatv, a kimenet egy szkzzel kezddik a
plusz eljel helyett. A negatv rtk ilyenkor is mnusz elje-
let kap.
# Azt hatrozza meg, hogy a paramtert alternatv formt hasz-
nlva kell konvertlni.
274 SZABVNY, MAGAS SZINT BEMENET, KIMENET
Az alternatv formk a tpuskaraktertl fggnek:
Tp.kar. A # hatsa a paramterre
c,s,d,i,u Nincs hats.
e,E,f Az eredmnyben mindenkppen lesz tizedes pont mg akkor
is, ha azt egyetlen szmjegy sem kveti. Normlisan ilyen-
kor nem jelenik meg a tizedes pont.
g,G Ugyanaz, mint e s E, de az eredmnybl a kvet zrusokat
nem vgja le a printf.
o 0-t r a konvertlt, nem zrus paramter rtk el. Ez az ok-
tlis szm megjelentetse.
x, X 0x, 0X elzi meg a konvertlt, nem zrus paramter rtket.
A szlessg a kimeneti rtk minimlis mezszlessgt hatrozza meg,
azaz a megjelen eredmny legalbb ilyen szlessg. A szlessget kt
mdon adhatjuk meg:
- vagy expliciten berjuk a formtumspecifikciba,
- vagy a szlessg helyre * karaktert tesznk. Ilyenkor a printf h-
vsban a kvetkez parameter csak int tpus lehet, s ennek az rt-
ke definilja a kimeneti rtk mezszlessgt.
Brmilyen szlessget is runk el, a printf a konverzi eredmnyt nem
csonktja! A lehetsges szlessg specifikcik:
Szlessg Hatsa a kimenetre
n A printf legalbb n karaktert jelentet meg. Ha a kimeneti
rtk n karakternl kevesebb, akkor szkzzel n karakte-
resre prnzza (jobbrl, ha a jelzt megadtk, mskln-
ben balrl).
0n Legalbb n karakter jelenik meg ekkor is. Ha a kimeneti
rtk nnl kevesebb karakterbl ll, akkor balrl zrus
feltlts kvetkezik.
* A paramter lista szolgltatja a szlessg specifikcit, de
ennek a paramter listban meg kell elznie azt a param-
tert, amire az egsz formtumspecifikci vonatkozik.
A pontossg specifikci mindig ponttal (.) kezddik. A szlessghez
hasonlan ez is megadhat kzvetlenl, vagy kzvetve (*) a paramter
listban. Utbbi esetben egy int tpus paramternek meg kell elznie azt
a paramtert a printf hvsban, amire az egsz formtumspecifikci vo-
natkozik.
Megemltjk, hogy a szlessget s a pontossgot is megadhatjuk egy-
szerre kzvetetten. Ilyenkor a formtumspecifikciban *.* van. A printf
C programnyelv 275
hvs paramter listjban kt int tpus paramter elzi meg (az els a
szlessg, a msodik a pontossg) azt a paramtert, amire az egsz form-
tumspecifikci vonatkozik. Lssunk egy pldt!
printf("%*.*f", 6, 2, 6.2);
A 6.2et f tpuskarakterrel kvnjuk konvertltatni gy, hogy a mezsz-
lessg 6 s a pontossg 2 legyen.
A pontossg specifikcik a kvetkezk:
Pontossg Hatsa a kimenetre
.* Lsd elbbre!
nincs
megadva
rvnybe lpnek a tpuskaraktertl fgg alaprtelmezs
szerinti rtkek. Ezek:
- 1 : d, i, o, u, x, X esetn,
- 6 : e, E, f tpuskaraktereknl,
- minden szignifikns szmjegy g s Gnl,
- s tpuskarakternl a teljes karakterlnc megy a kime-
netre s
- a c tpuskarakterre nincs hatssal.
.0
- Az e, E, f tpuskaraktereknl nem jelenik meg a tizedes
pont.
- A d, i, o, u, x, X esetn pedig az alaprtelmezs szerin-
ti pontossg lp rvnybe (1). Ha ilyenkor a kirand
paramter rtke radsul zrus is, akkor csak egyetlen
szkz jelenik meg.
276 SZABVNY, MAGAS SZINT BEMENET, KIMENET
.n A printf legfeljebb n karaktert, vagy decimlis helyirtket
jelentet meg. Ha a kimenet n-nl tbb karakterbl ll, ak-
kor csonkul, vagy kerekti a rutin a vonatkoz tpuskarak-
tertl fggen:
- d, i, o, u, x s X esetn legalbb n szmjegy jelenik
meg. Ha a kimenet nnl kevesebb jegybl ll, akkor
balrl zrus feltlts trtnik. Ha a kimeneti nnl
tbbjegy, akkor sem csonkul.
- e, E, fnl a printf n szmjegyet jelentet meg a tizedes
ponttl jobbra. Ha szksges, a legalacsonyabb helyir-
tken kerekts lesz.
- g, G esetn legfeljebb n szignifikns jegy jelenik meg.
- A c tpuskarakterre nincs hatsa.
- Az s tpuskarakternl legfeljebb n karakter jelenik meg,
azaz a hosszabb karakterlnc csonkul.
Legvgl nzzk mg a h, l s L mretmdost karaktereket! A mret-
mdostk annak a paramternek a hosszt mdostjk, melyre az egsz
formtumspecifikci vonatkozik.
1 A d, i, o, u, x s X tpuskarakterekkel kapcsolatban csak a h s az l
mretmdostk megengedettek. Jelentsk: h esetn a vonatkoz pa-
ramtert a printf tekintse short intnek, l esetn pedig long intnek.
1 Az e, E, f, g, s G tpuskarakterekkel kapcsolatban csak az l s az L
mretmdostk megengedettek. Jelentsk: l esetn a vonatkoz pa-
ramtert a printf tekintse doublenek, Lnl pedig long doublenek.
Jelentessk meg a 2003. mrcius 2. dtumot HHNN alakban!
printf(%04d-%02d-%02d, 2003, 3, 2);
printf(%.4d-%.2d-%.2d, 2003, 3, 2);
Mindkt hvs 20030302t szolgltat.
Szemlltessk a 0, a #, a + s a jelzk hatst d, o, x, e s f tpuskarak-
terek esetn!
/* PELDA33.C: A printf jelzinek szemlltetse nhny
tpuskarakterre. */
#include <stdio.h>
#include <string.h>
#define E 555
#define V 5.5
int main(void){
int i,j,k,m;
C programnyelv 277
char prefix[7], format[100], jelzok[]=" 0# + -",
*tk[]={"6d", "6o", "8x", "10.2e", "10.2f"};
#define NJ (sizeof(jelzok)-2)*2
#define NTK sizeof(tk)/sizeof(tk[0])
printf("prefix 6d 6o 8x"
" 10.2e 10.2f\n"
"------+-------+-------+-----"
"----+-----------+-----------+\n");
for(i=NJ-1; i>=0; --i){
strcpy(prefix, "%");
for(j=k=1; k<NJ; k<<=1)
if(i&k) prefix[j++]=jelzok[k];
prefix[j]=0;
Az i 15rl indul, s zrusig cskken egyesvel, azaz ekzben lerja
az sszes lehetsges ngybites bitkombincit. A k felvett rtkei 1, 2, 4
s 8, s a jelzok tmb pp ezen index elemeiben tallhatk meg a jelz
karakterek.
strcpy(format, "%5s |");
for(m=0; m<NTK; ++m){
strcat(format, prefix);
strcat(format, tk[m]);
strcat(format, " |"); }
strcat(format, "\n");
printf(format, prefix, E, E, E, V, V); }
return(0); }
A program futtatsakor megjelen kimenet:
prefix 6d 6o 8x 10.2e 10.2f
------+-------+-------+---------+-----------+-----------+
%0#+- |+555 |01053 |0x22b |+5.50e+000 |+5.50 |
%#+- |+555 |01053 |0x22b |+5.50e+000 |+5.50 |
%0+- |+555 |1053 |22b |+5.50e+000 |+5.50 |
%+- |+555 |1053 |22b |+5.50e+000 |+5.50 |
%0#- |555 |01053 |0x22b |5.50e+000 |5.50 |
%#- |555 |01053 |0x22b |5.50e+000 |5.50 |
%0- |555 |1053 |22b |5.50e+000 |5.50 |
%- |555 |1053 |22b |5.50e+000 |5.50 |
%0#+ |+00555 |001053 |0x00022b |+5.50e+000 |+000005.50 |
%#+ | +555 | 01053 | 0x22b |+5.50e+000 | +5.50 |
%0+ |+00555 |001053 |0000022b |+5.50e+000 |+000005.50 |
%+ | +555 | 1053 | 22b |+5.50e+000 | +5.50 |
%0# |000555 |001053 |0x00022b |05.50e+000 |0000005.50 |
%# | 555 | 01053 | 0x22b | 5.50e+000 | 5.50 |
%0 |000555 |001053 |0000022b |05.50e+000 |0000005.50 |
% | 555 | 1053 | 22b | 5.50e+000 | 5.50 |
int sprintf(char *puffer, const char *format<, parameter, ...>);
A fggvny ugyanazt teszi, mint a printf, de a kimenett nem az stdout
ra kszti, hanem az els paramterknt megkapott karaktertmbbe \0
lal lezrva.
278 SZABVNY, MAGAS SZINT BEMENET, KIMENET
A vfprint, a vprintf s a vsprintf rutinokat mr megemltettk a
Vltoz paramterlista fejezetben!
Megoldand feladatok:
Ksztsen char * kozepre(char *mit, int szeles) fggvnyt, mely a sajt
helyn kzpre igaztja a mit karakterlncot szeles szlessgben, s vissza-
adja az eredmny lnc kezdcmt! A kzpre igaztst csak szelesnl r-
videbb lncok esetben kell elvgezni. A ktoldali prnz karakter indu-
lsknt lehet szkz, de lehessen ezt fordtsi idben vltoztatni! {KO-
ZEPRE.C}
rjon szoftvert, mely igaztott tblzatot hoz ltre az albbi tartalm
TABLA fjl
Szveg Forint Egsz
Papadopulosz 111222.3 1456
Sodik_sor 2.2 345
szabvny bemenetknti tirnytsval. Az eredmny tblzat:
+------------------------+-------------------+------------+
| Szveg | Forint | Egsz |
+------------------------+-------------------+------------+
| Papadopulosz | 111222.30Ft | 1456 |
+------------------------+-------------------+------------+
| Sodik_sor | 2.20Ft | 345 |
+------------------------+-------------------+------------+
, ahol az els oszlop balra-, a msodik jobbra-, s a harmadik kzpre iga-
ztott. A tbla egy sornak szerkezete:
| MEZO1| MEZO2Ft | MEZO3 |
, ahol MEZO1, MEZO2 s MEZO3 brutt adatszlessgek a mutatott
mdon.
Fokozhatja mg a feladatot gy, hogy az adatokat lehessen billentyzet-
rl is megadni!
11.9 Egyb fggvnyek
Csak lezrt fjlokkal foglalkozik a kvetkez kt fggvny. A
int remove(const char *fajlnev);
trli az akr komplett ttal megadott azonostj fjlt. Sikeres esetben z-
rust, msklnben -1-et szolgltat a rutin. A
int rename(const char *reginev, const char *ujnev);
a reginev azonostj fjlt tnevezi ujnevre. Ha az ujnev meghajtnevet
is tartalmaz, akkor az nem trhet el attl, ahol a reginev azonostj fjl
C programnyelv 279
elhelyezkedik. Ha viszont az ujnev a fjl eredeti helytl eltr utat tartal-
maz, akkor az tnevezsen tl megtrtnik a fjl tmozgatsa is.
e A fggvny egyik paramtere sem lehet globlis fjlazonost!
Sikeres esetben zrust szolgltat a rutin. A problmt a -1 visszaadott
rtk jelzi.
FILE *tmpfile(void);
A rutin wb+ mddal ideiglenes fjlt hoz ltre, melyet lezrsakor,
vagy normlis programbefejezdskor automatikusan trl a rendszer. A
visszaadott rtk az ideiglenes fjl FILE struktrjra mutat, ill. NULL
jn ltrehozsi problma esetn.
char *tmpnam(char s[L_tmpnam]);
tmpnam(NULL) mdon hvva olyan fjlazonostt kapunk, mely egyet-
len ltez fjl nevvel sem egyezik. A szolgltatott mutat bels, statikus
karaktertmbt cmez, ahol a fjlazonost karakterlnc tallhat.
A fjlazonost karakterlnc nem marad ott rkk, mert a kvetke-
z tmpnam hvs fellrja.
Nem NULL mutatval hvva a rutin kimsolja a fjlazonostt az s ka-
raktertmbbe, s ezzel is tr vissza. Az s tmb legalbb L_tmpnam mret
kell, legyen. Tbbszri hvssal legalbb TMP_MAX darab, klnbz
fjlazonost generlsa garantlt.
e Vigyzat! A fggvny fjlazonostkat generl s nem fjlokat!
280 IRODALOMJEGYZK S FGGELK
12 IRODALOMJEGYZK
[1] Kiss J. Raffai M. Szijrt M. Szrnyi M.: A szmtstechnika
alapjai
NOVADAT Bt., Gyr, 2001
[2] Marton L. Pukler A. Pusztai P.: Bevezets a programozsba
NOVADAT Bt., Gyr, 1993
[3] Marton Lszl: Bevezets a Pascal nyelv programozsba
NOVADAT Bt., Gyr, 1998
[4] B. W. Kernighan D. M. Ritchie: A C programozsi nyelv
Mszaki Knyvkiad, Budapest, 1985
[5] B. W. Kernighan D. M. Ritchie: A C programozsi nyelv, az ANSI
szerint szabvnyostott vltozat
Mszaki Knyvkiad, Budapest, 1996
[6] Benk Tiborn Benk Lszl Tth Bertalan: Programozzunk C
nyelven
ComputerBooks, Budapest, 1999
[7] Benk Tiborn Urbn Zoltn: IBM PC programozsa TURBO C
nyelven 2.0
BME Mrnktovbbkpz Intzet, Budapest, 1989
C programnyelv 281
13 FGGELK
A fggelkben nhny megoldand feladat programlistjt kzljk.
13.1 CHDEL.C
/* CHDEL.C: Az 'a' karakter trlse a sorokbl. */
#include <stdio.h>
#define MAX 128
#define KAR 'a' /* Itt az 'a' karakter. */
int getline(char s[], int n); /* Fggvny prototpusok. */
void chdel(char s[], int c);
void main(void){ /* Fggvnydefinci. */
char sor[MAX+1]; /* Az aktulis sor. */
printf("\n\n\n\n\n\n\'%c\' karakter trlse a sorbl:\n",
KAR);
printf("A sorokat zrja le Enter-rel!\n");
printf("Utoljra adjon meg egy res sort is!\n\n");
/* Sor olvass, KAR trlse s visszars res sorig: */
while(getline(sor, MAX)>0){
chdel(sor, KAR);
printf("%s\n\n", sor); } }
int getline(char s[],int n){
int c,i;
for(i=0;i<n&&(c=getchar())!=EOF&&c!='\n';++i) s[i]=c;
s[i]='\0';
while(c!=EOF&&c!='\n') c=getchar();
return(i); }
void chdel(char s[], int c){ /* c karakter minden elfor
dulsnak trlse az s karakterlncbl a sajt helyn. */
int i,j; /* Forrs s cl index. */
for(i=j=0; s[i]!='\0'; i++)
/* Kell msolni? */
if(s[i]!=c) s[j++]=s[i]; /* Igen. */
/* A lnczr '\0' kiraksa: */
s[j]='\0'; }
13.2 EGYESIT.C
/* EGYESIT.C: Szvegfjlok egyestse. */
#include <stdio.h>
#define SZELES 30 /* Kijelzsi szlessg. */
FILE *ofp; /* Az output fjl. */
void filecopy(FILE *p); /* A fjlmsol fv. */
int main(int argc, char *argv[]){
FILE *fp; /* Az aktulis input fjl. */
int i;
printf("Szvegfjlok egyestse:\n");
if(argc < 2){/* Nincs paramter: inf a hasznlatrl. */
282 FGGELK
fprintf(stderr,
"Az input szvegfjlok egyestse az utols "
"paramter szvegfjlba:\n\r"
"Indts: EGYESIT inputfjl inputfjl ... "
"outputfjl\n\r");
return 1; }
/* Az output fjl megnyitsa: */
if(!(ofp=fopen(argv[argc-1],"wt"))){
fprintf(stderr, "%s outputfjl nem nyithat meg!\n\r",
argv[argc-1]);
return 1; }
/* Egy paramter esetn, a szabvny bemenet msoland: */
if(argc==2) filecopy(stdin);
/* Tbb paramternl a fjlok rendre msolandk: */
else for(i=1; i < argc-1; ++i){
if(!(fp=fopen(argv[i],"rt"))) /* Inp.fjl nyitsa: */
fprintf(stderr,"%s inputfjl nem nyithat meg!\n\r",
argv[i]);
else {
printf("\n%*s -> %-*s: ", SZELES, argv[i], SZELES,
argv[argc-1]);
filecopy(fp); /* Inp.fjl msolsa az outputba.*/
fclose(fp); } } /* Az input fjl bezrsa. */
fclose(ofp); /* Az output fjl bezrsa. */
printf("\n");
return(0);}
void filecopy(FILE *fp){/* 1 fjl msolsa az outputba. */
int c;
long szlo=0l; /* A kirt bjtok szmllsra. */
while(!feof(fp)) /* Inputfjl olvassa fjlvgig. */
if((c=fgetc(fp))!=EOF){
if(c!=fputc(c,ofp)){/* Van hiba a kirsnl? */
fprintf(stderr, "Output fjlnl rshiba!\n\r");
fclose(ofp);
exit(1); }
++szlo; /* Bjtok szmllsa. */
if(c=='\n')++szlo; /* A transzlci miatt! */
if(fp!=stdin){ /* A szmll ki ugyanott. */
printf("%10ld", szlo);
printf("\b\b\b\b\b\b\b\b\b\b");}}
else{ /* Input fjl vge: */
if(fp==stdin)
printf("\nA ltrejtt fjl %ld bjtos.\n",szlo);}}
13.3 HEXA.C
/* HEXA.C: Hexadecimlis szmok vizsglata s konverzija
egssz. */
#include <stdio.h>
#define MAX 80 /* Input puffer mrete. */
int getline(char s[],int n){
int c,i;
for(i=0;i<n&&(c=getchar())!=EOF&&c!='\n';++i) s[i]=c;
C programnyelv 283
s[i]='\0';
while(c!=EOF&&c!='\n') c=getchar();
return(i); }
int hexae(char s[]){ /* A param. hexadec. karakterlnc-e?*/
int i=0; /* Index. */
/* A lnc eleji fehr karakterek tlpse: */
while(s[i]==' '|| s[i]=='\t'|| s[i]=='\n') ++i;
/* Eljel nem lehet. */
/* Mg fehr karakter nem kvetkezik, vagy vge nincs a
karakterlncnak: */
while(s[i]!=' '&& s[i]!='\t'&& s[i]!='\n'&& s[i]!='\0')
/* Hexadecimlis szmjegy-e? */
if(s[i]>='0'&&s[i]<='9'|| s[i]>='A'&&s[i]<='F'||
s[i]>='a'&&s[i]<='z') ++i;
else return 0; /* Rossz karakterlnc. */
return 1; /* J karakterlnc. */ }
long atoh(char s[]){ /* Hexa. karakterlnc konverzija. */
int i=0; /* Index. */
long n=0l; /* A konvertlt rtk. */
/* A karakterlnc eleji fehr karakterek tlpse: */
while(s[i]==' '|| s[i]=='\n'|| s[i]=='\t') ++i;
/* Eljel nincs. */
/* Konverzi, mg hexadec. szmjegyek kvetkeznek: */
for(;s[i]>='0'&&s[i]<='9'|| s[i]>='A'&&s[i]<='F'||
s[i]>='a'&&s[i]<='z';++i)
if(s[i]>='0'&&s[i]<='9') n=16*n+s[i]-'0'; /* 0-9 */
/* A-F */
else if(s[i]>='A'&&s[i]<='F') n=16*n+s[i]-'A'+10;
else n=16*n+s[i]-'a'+10; /* a-f */
return(n); }
void main(void){
char sor[MAX+1]; /* Az input puffer. */
printf("\n\n\n\n\n\nHexadecimlis konverzi:\n");
printf("Adjon meg soronknt egy-egy hexadec. szmot!\n");
printf("Utoljra adjon meg egy res sort is!\n\n");
/* Sor olvassa, ellenrzse, konverzija res sorig: */
while(getline(sor, MAX)>0)
if(hexae(sor)) printf("Konvertlva: %ld\n\n",
atoh(sor));
else printf("Formailag hibs hexadec. szm!\n\n"); }
13.4 IKSZ.C
/* IKSZ.C: 21x21-es X csillag karakterrel. */
#include <stdio.h>
void main(void){
int i, j; /* Ciklusvltozk deklarcija. */
for(i=0; i<21; i=i+1){/* 21 sor lesz. */
for(j=0; j<21; j=j+1)/* Soron bell 21 pozci van. */
/* A ftl (j==i) s a mellktl (j==20-i) mentn
csillagot, a tbbi pozcin viszont szkzt kell
megjelentetni. */
284 FGGELK
if(j==i || j==20-i) printf("*");
else printf(" ");
/* A sor vgn persze sort is kell emelni. */
printf("\n"); } }
13.5 INDEXEU.C
/* INDEXEU.C: Sorban egy adott szveg elfordulsa
indexnek megadsa elrl s htulrl. */
#include <stdio.h>
#include <string.h>
#define MAX 128 /* Az input puffer mrete. */
#define AZ "az" /* A keresett szveg. */
int getline(char s[],int lim){
int c,i=0;
while(--lim>0&&(c=getchar())!=EOF&&c!='\n')s[i++]=c;
s[i]='\0';
while(c!=EOF && c!='\n')c=getchar();
return(i); }
int indexe(char s[],char t[]){/* Visszaadja t s-beli els
elfordulsnak indext, ill. -1-et, ha t nincs s-ben. */
int i, /* Index az s karakterlncon. */
j=0, /* Index tn. Elrl indul. */
mx=strlen(s); /* Uts index s-ben, ameddig a t-vel
val hasonltssal el kell menni. */
for(i=0; i<=mx; ++i){/* s karakterlncon lpteti i-t. */
/* Ha a kt karakter egyezik, j-t is lptetjk t-n. */
if(s[i]==t[j]) ++j;
/* Ha a kt karakter eltr, visszalpnk t elejre
(j=0), s i indexet is visszalptetjk s-n oda, ahol
az elbb a kt lnc hasonltst kezdtk, hisz i-t
gy is megnveli a ciklus. */
else{ i=i-j; j=0; }
/* Ha a kt karakter egyezett, s t karakterlnc vget
rt, akkor visszaadhat a megtallsi index. */
if(!t[j]) return i-j+1; }
return(-1); }
int indexu(char s[],char t[]){/* Visszaadja t s-beli uts
elfordulsnak indext, ill. -1-et, ha t nincs s-ben. */
int i,j,k;
/* Htra fel haladunk s karakterlncon, de a
lnchasonltsok elre mennek. */
for(i=strlen(s)-strlen(t); i>=0; --i){
for(j=i,k=0; t[k]&&s[j]==t[k]; j++,k++);
/* Ha a lnchasonlts t karakterlnc vgn rt vget,
akkor visszaadhat a megtallsi index. */
if(!t[k]) return(i); }
return(-1); }
void main(void){
int n; /* Az index. */
char sor[MAX+1]; /* A beolvasott sor. */
C programnyelv 285
printf("Gpeljen be egy sort, melyben a(z) \"%s\" szveg"
" els s utols\nelfordulst keressk! Vge: "
" egy res sor.\n", AZ);
while(printf("\nJhet a sor! "), getline(sor,MAX)>0)
if((n=indexe(sor, AZ))>=0){
printf("Az els elforduls indexe:%d.\n",n);
printf("Az uts elforduls indexe:%d.\n",
indexu(sor, AZ)); }
else printf("Nincs benn!\n"); }
13.6 JANI.C
/* JANI.C: A jani krnyezeti vltoz kicsi, nagy, ms vagy
nincs. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define jani "JANI" /* A krnyezeti vltoz. */
char *ertek[] = /* A lehetsges rtkei. */
{"kicsi", "nagy"};
#define IG sizeof(ertek)/sizeof(ertek[0])/* Darabszm. */
int main(void){
char *p;
int i;
printf("%s krnyezeti vltoz rtk-lekrdezse:\n\n",
jani);
/* Vgigjrjuk a "vltoz=rtk" alak karaktertncokra
mutat mutattmbt. */
while(*environ!=NULL){
/* Ha a vltoz jani lenne, akkor p az '='-re mutatna
az aktulis "vltoz=rtk" alak kar.lncban. */
p=*environ+strlen(jani);
if(strstr(*environ, jani)==*environ&& *p=='='){
++p;
/* Ha megvan a jani vltoz, akkor p az "rtk"-re
mutat. Vgigjrva a lehetsges rtkeket,
megtalljuk jani krnyezeti vltoz rtkt is, */
for(i=0; i<IG; ++i)
if(strcmp(p, ertek[i])==0){
printf("A(z) %s %s!\n", jani, ertek[i]);
return 0; }
/* vagy sem: */
printf("A(z) %s ms!\n",jani);
return(0);}
++environ;}
/* Ide akkor kerl a vezrls, ha nincs jani a vltozk
kztt. */
printf("Nincs is %s!\n",jani);
return(1);}
13.7 KOZEPRE.C
#include <stdio.h>
286 FGGELK
#include <conio.h>
#include <string.h>
#include <ctype.h>
char *kozepre(char *, int);
void main(void){/* "Abc" karakterlnc kzpre igaztsa */
char puff[21] = "Abc"; /* 20-as mezszlessgben. */
printf("%s|\n12345678901234567890+\n",kozepre(puff,20));}
#define TOLT ' '/* A ktoldali prnz karakter. */
char *kozepre(char *s, int m){/* s karakterlnc kzpre */
int hsz=strlen(s), elo; /* igaztsa a sajt helyn, m
m szlessgben. */
char *pi, *pm=s+m;
if((elo=(m-hsz+1)/2) > 0){ /* Kell-e az igazts? */
/* Az igaztott karakterlnc vge: */
*pm-- = 0;
/* Jobbra TOLT karakteres feltlts: */
for(pi=s+hsz+elo; pi <= pm;) *pm-- = TOLT;
/* A szveg kzpre: */
for(pi=s+hsz-1; pi>=s; )*pm-- = *pi--;
/* Balra TOLT karakteres feltlts: */
while(pm>=s) *pm-- = TOLT;}
return s;}
13.8 LAPOZ.C
/* LAPOZ.C: Forint-eur tszmtsi tblzat lapozssal. */
#include <stdio.h>
#define ALSO 100 /* A tartomny als hatra. */
#define FELSO 10000 /* A tartomny fels rtke. */
#define LEPES 100 /* A lpskz. */
#define ARFOLYAM 253.5 /* Ft/eur rfolyam. */
#define LAPSOR 20 /* Max. sorok szma egy lapon. */
void main(void){
int ft, sor;
sor=LAPSOR+1; /* A lista induljon j lappal! */
for(ft=ALSO; ft<=FELSO; ft=ft+LEPES){
/* Ha elrtk a lap vgt, akkor meg kell jelentetni a
lista fejlct, s nullzni kell a sorszmllt. */
if(sor>=LAPSOR){
printf("\n\n%9s|%9s\n---------+---------\n",
"Forint", "Eur");
sor=0; }
/* Megjelentetnk egy sort, teht lptetni kell a
sorszmllt. */
++sor;
printf("%9d|%9.2f\n", ft, ft/ARFOLYAM);
/* A lap legutols sornak kirsa utn vrni kell egy
Enter letsre. */
if(sor==LAPSOR){
printf("\nA tovbblistzshoz nyomjon Enter-t! ");
while(getchar()!='\n');} } }
C programnyelv 287
13.9 NEVREND.C
/* NEVREND.C: Beolvasott, dinamikusan mutattmbben trolt
nevek rendezse. */
#include <stdio.h>
#include <string.h> /* A karakterlnc-kezels miatt! */
#include <stdlib.h> /* A dinamikus trols miatt! */
#include <ctype.h> /* A karaktervizsglatok miatt! */
#define SOROK 100 /* A trolhat nevek max.szma. */
#define LAPSOR 20 /* Egy lapra rhat nevek szma. */
int nevekbe(char *nevmutomb[], int maxnevdb);
void rendez(char *t[], int n);
void main(void){
char *nevmutomb[SOROK]; /* Neveket megcmz mutattmb.*/
int nevdb; /* A beolvasott nevek szma. */
printf("A beolvasott nevek rendezse:\n");
printf("A neveket Enter-rel kell lezrni!\n");
printf("A bemenet vgt res sor jelzi!\n\n");
if((nevdb=nevekbe(nevmutomb, SOROK))>=0){/* Beolvass. */
int i;
rendez(nevmutomb, nevdb); /* Rendezs. */
printf("\n");
for(i=0; i<nevdb; ++i){ /* Kirs lapozva. */
if(i%LAPSOR==0&&i!=0){
printf("A tovbblistzshoz ssn Enter-t! ");
while(getchar()!='\n');
printf("\n\n"); }
printf("%s\n", nevmutomb[i]); } }
else printf("\nTl sok nv, vagy elfogyott a "
"memria!\n"); }
#define MAXNEV 40 /* Egy nv max. hosszsga */
int getline(char *, int);
int nevekbe(char *nevmutomb[], int maxnevdb){ /* Nevek be-
olvassa s dinamikus elhelyezse a paramter mutattmb-
ben s a letrolt nevek szmnak visszaadsa. -1-et szol-
gltat, ha kimerl a mutattmb, vagy a heap elfogy. */
int hsz, /* A beolvasott nv hossza. */
nevdb=0; /* Az eddig beolvasott nevek szma. */
char *p, /* A dinamikus terlet cme. */
nev[MAXNEV+1];/* Az aktulisan beolvasott nv. */
while((hsz=getline(nev, MAXNEV))>0){
/* Nv ellenrzse: Els nagy, a tbbi kisbet. */
p=nev+1;
while(*p&& islower(*p++));
if(isupper(*nev)&&!(*p)){
/* Kimerlt-e mutattmb? */
if(nevdb>=maxnevdb) return(-1);
/* Van-e mg memria? */
else if((p=(char *)malloc(hsz+1))==NULL) return(-1);
/* Minden OK: nv a heapre, cme a mutattmbbe. */
else{
strcpy(p, nev);
288 FGGELK
nevmutomb[nevdb++]=p; } }
else printf("rvnytelen nv!\n"); }
return(nevdb); }
int getline(char *s, int n){ /* Sor beolvassa s-be. */
int c; /* A hosszt adja vissza. */
char *t=s; /* Indexels helyett a t mutatval
haladunk az s karaktertmbn. A t mindig a kvetkez
szabad helyre mutat a tmbben, melynek tlrst az n
elfogysa akadlyozza meg. */
while(n-->0&&(c=getchar())!=EOF&&c!='\n') *t++=c;
*t='\0';
while(c!=EOF&&c!='\n') c=getchar();
/* A karakterlcot zr '\0' cmbl a tmb kezdcmt
kivonva, ppen a karakterlnc hosszt kapjuk. */
return(t-s); }
void rendez(char *v[], int n){/* A v[0],v[1],..,v[n-1] */
int i, j, m; /* karakterlncok rendezse nvekv */
char *cs; /* sorrendben a mutatk cserjvel. */
for(i=0; i<n-1; ++i){
for(j=i+1, m=i; j<n; ++j) if(strcmp(v[j],v[m])<0) m=j;
if(i!=m){ cs=v[i]; v[i]=v[m]; v[m]=cs;} } }
13.10PELDA18X.C
/* PELDA18X.C: Egsz szmok tlaga, minimuma, maximuma s
rendezse. */
#include <stdio.h>
#include <stdlib.h> /* Az atoi miatt! */
#include <limits.h> /* INT_MIN s INT_MAX vgett! */
#define MAX 100 /* A tmb max. elemszma. */
#define INP 20 /* Az input puffer mrete. */
int getline(char s[],int lim){
int c,i;
for(i=0;i<lim&&(c=getchar())!=EOF&&c!='\n';++i)s[i]=c;
s[i]='\0';
while(c!=EOF && c!='\n') c=getchar();
return(i); }
/* A decimlis szmjegyek szma maximlisan: */
#define HSZ sizeof(int)/sizeof(short)*5
int egesze(char s[]){
int i = 0, kezd;
/* A karakterlnc eleji fehr karakterek tlpse: */
while(s[i]==' ' || s[i]=='\n' || s[i]=='\t') ++i;
/* Az eljel tlpse: */
if(s[i]=='+' || s[i]=='-') ++i;
kezd=i; /* A szmjegyek itt kezddnek. */
/* Elre a kvetkez nem numerikus karakterre: */
while(s[i]>='0' && s[i]<='9' && i-kezd<HSZ) ++i;
/* Dnts: */
if(kezd==i || s[i]!='\n' && s[i]!='\t' &&
s[i]!=' ' && s[i]!=0) return 0;
C programnyelv 289
else return 1; }
void rendez(int a[],int n){
int i, j, m, cs;
for(i=0; i<n-1; ++i){
for(j=i+1, m=i; j<n; ++j) if(a[j]<a[m]) m=j;
if(i!=m){ cs=a[i]; a[i]=a[m]; a[m]=cs;} } }
void main(void){
int n=0; /* A rendezend elemek szma 0-rl indul. */
char sor[INP+1]; /* Az input puffer. */
int a[MAX]; /* A egszeket trol tmb. */
int min, max; /* Minimum, maximum. */
double osszeg=0.; /* Az sszeg */
int i;
printf("\n\n\n\n\nKrem a rendezend szmokat %d s +%d"
" kztt!\n", INT_MIN, INT_MAX);
printf( "A befejezs res sorral trtnik!\n");
while(n<MAX){ /* Bekrs a tmb uts elemig tarthat. */
printf("%3d: ",n+1);
/* Ha megadnak sort, s az egsz szm, akkor ez lesz
a tmb kvetkez eleme, s nveljk az elemszmot. */
if(getline(sor,INP)>0)
{ if(egesze(sor)) a[n++]=atoi(sor); }
/* Ha res sort adnak meg, s van mr rendezend elem,
akkor befejezdtt a bekrs. */
else if(n) break; }
min=max=a[0];
for(i=0;i<n;osszeg+=a[i],++i)
if(a[i]<min) min=a[i];
else if(a[i]>max) max=a[i];
printf("\nA szmsorozat\tminimuma:%14d.\n"
"\t\tmaximuma:%14d.\n"
"\t\ttlaga: %17.2f\n",
min, max, osszeg/n);
printf("\nA rendezett szmok:\n");
rendez(a, n);
for(i=0; i<n; i++){
printf("%13d",a[i]);
if(!((i+1)%6)) putchar('\n'); }
putchar('\n'); }
13.11PELDA18Y.C
/* PELDA18Y.C: Egsz szmok tlaga, minimuma, maximuma s
rendezse. A mdosult programsorokat megcsillagoztuk:
********* */
#include <stdio.h>
#include <stdlib.h> /* Az atoi miatt! */
#include <limits.h> /* INT_MIN s INT_MAX vgett! */
#define MAX 100 /* A tmb max. elemszma. */
#define INP 20 /* Az input puffer mrete. */
int getline(char s[],int lim){
int c,i;
290 FGGELK
for(i=0;i<lim&&(c=getchar())!=EOF&&c!='\n';++i)s[i]=c;
s[i]='\0';
while(c!=EOF && c!='\n') c=getchar();
return(i); }
/* A decimlis szmjegyek szma maximlisan: */
#define HSZ sizeof(int)/sizeof(short)*5
int egesze(const char s[], int *ertek){ /* ********* */
int i = 0, kezd;
/* A karakterlnc eleji fehr karakterek tlpse: */
while(s[i]==' ' || s[i]=='\n' || s[i]=='\t') ++i;
/* Az eljel tlpse: */
if(s[i]=='+' || s[i]=='-') ++i;
kezd=i; /* A szmjegyek itt kezddnek. */
/* Elre a kvetkez nem numerikus karakterre: */
while(s[i]>='0' && s[i]<='9' && i-kezd<HSZ) ++i;
/* Dnts: */
if(kezd==i || s[i]!='\n' && s[i]!='\t' &&
s[i]!=' ' && s[i]!=0) return 0;
else { *ertek=atoi(s); /* ********* */
return 1; } }
void rendez(int a[],int n){
int i, j, m, cs;
for(i=0; i<n-1; ++i){
for(j=i+1, m=i; j<n; ++j) if(a[j]<a[m]) m=j;
if(i!=m){ cs=a[i]; a[i]=a[m]; a[m]=cs;} } }
void main(void){
int n=0; /* A rendezend elemek szma. */
char sor[INP+1]; /* Az input puffer. */
int a[MAX]; /* A egszeket trol tmb. */
int min, max; /* Minimum, maximum. */
double osszeg=0.; /* Az sszeg */
int i;
while(n<1||n>MAX){
printf("\nHny egsz szmot rendeznk(1-%d)? ",MAX);
getline(sor,INP);
egesze(sor, &n);} /* ********* */
printf("\n\n\n\n\nKrem a rendezend szmokat %d s +%d"
" kztt!\n", INT_MIN, INT_MAX);
for(i=0;i<n;++i){
printf("%3d: ", i+1); /* ********* */
if(!getline(sor,INP)||!egesze(sor,&a[i])) --i; }
min=max=a[0];
for(i=0;i<n;osszeg+=a[i],++i)
if(a[i]<min) min=a[i];
else if(a[i]>max) max=a[i];
printf("\nA szmsorozat\tminimuma:%14d.\n"
"\t\tmaximuma:%14d.\n"
"\t\ttlaga: %17.2f\n",
min, max, osszeg/n);
printf("\nA rendezett szmok:\n");
rendez(a, n);
C programnyelv 291
for(i=0; i<n; i++){
printf("%13d",a[i]);
if(!((i+1)%6)) putchar('\n'); }
putchar('\n'); }
13.12PELDA28X.C
/* PELDA28X.C: A kt, egymstl legtvolabbi pont keresse,
majd a pontok origtl mrt tvolsguk cskken sorrend-
jben rendezett listjnak lapozhat megjelentse. */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#define INP 28 /* Az input puffer mrete. */
#define N 128 /* Pontok maximlis szma. */
#define LAPSOR 20 /* Egy lapra kirhat sorok szma. */
struct Pont{ /* A Pont struktra. */
double x, y, tav; };/* tav tag=origtl mrt tvolsg. */
int getline(char *s, int n){ /* Sor beolvassa s-be. */
int c; /* A hosszt adja vissza. */
char *t=s; /* Indexels helyett a t mutatval
haladunk az s karaktertmbn. A t mindig a kvetkez
szabad helyre mutat a tmbben, melynek tlrst az n
elfogysa akadlyozza meg. */
while(n-->0&&(c=getchar())!=EOF&&c!='\n') *t++=c;
*t='\0';
while(c!=EOF&&c!='\n') c=getchar();
/* A karakterlcot zr '\0' cmbl a tmb kezdcmt
kivonva, ppen a karakterlnc hosszt kapjuk. */
return(t-s); }
int lebege(char *s){ /* trva mutatsra! */
char *i=s, *kezd;
/* Fehr karakterek tlpse a lnc elejn: */
while(isspace(*i)) ++i;
/* A mantissza eljele: */
if(*i=='+'||*i=='-') ++i;
kezd=i; /* A szmjegyek itt kezddnek. */
/* A mantissza egsz rsze: */
while(isdigit(*i)) ++i;
/* A mantissza trt rsze: */
if(*i=='.') ++i;
while(isdigit(*i)) ++i;
/* Nincs szmjegy, vagy csak egy . van: */
if(i==kezd||kezd+1==i&&*kezd=='.') return 0;
/* Kitev rsz: */
if(toupper(*i)=='E'){
++i;
if(*i=='+'||*i=='-')++i;
/* Egy szmjegynek lennie kell a kitevben! */
if(!isdigit(*i)) return 0;
while(isdigit(*i)) ++i;}
292 FGGELK
/* Vge: */
if(isspace(*i)||!*i) return 1;
else return 0; }
int main(void){
char sor[INP+1]; /* Input puffer. */
struct Pont p[N], /* Struktratmb. */
cs; /* Rendezsnl a cserhez. */
int n=0; /* Pontok szma. */
double max=-1., d; /* Pillanatnyi maximum s */
int i, j, tavi, tavj;/* segdvltozk. */
printf("A kt egymstl legtvolabbi pont a skban, "
"majd a\npontok listja origtl mrt tvolsguk "
"sorrendjben.\n\n"
"Adja meg a pontok koordintaprjait rendre!\n"
"Vge: res sor az X koordinta megadsnl.\n\n");
for(n=0;n<N;++n){
printf("A(z) %d pont koordinti:\n",n+1);
if(printf("X: "), getline(sor, INP)<=0)break;
if(lebege(sor)) p[n].x=atof(sor);
else { --n; continue;}
while(printf("Y: "), getline(sor,INP),
!lebege(sor));
p[n].y=atof(sor); /* A tvolsg! */
p[n].tav=sqrt(p[n].x*p[n].x + p[n].y*p[n].y); }
if(n<2){
printf("Legalbb kt pontot meg kne adni!\n");
return(1);}
/* A maximlis tvolsg kt pont megkeresse: */
for(i=0;i<n-1;++i)
for(j=i+1;j<n;++j)
if((d=sqrt((p[j].x-p[i].x)*(p[j].x-p[i].x)+
(p[j].y-p[i].y)*(p[j].y-p[i].y))) > max){
max=d;
tavi=i;
tavj=j; }
printf("A maximlis tvolsg kt pont:\n"
"P[%d]: (%10.1f, %10.1f) s\n"
"P[%d]: (%10.1f, %10.1f),\n"
"s a tvolsg: %15.2f\n",
tavi+1, p[tavi].x, p[tavi].y,
tavj+1, p[tavj].x, p[tavj].y, max);
/* Rendezs az origtl mrt tvolsg szerint
cskkenleg: */
for(i=0; i<n-1; ++i){
for(j=i+1, tavi=i; j<n; ++j) if(p[j].tav>p[tavi].tav)
tavi=j;
if(i!=tavi){ cs=p[i]; p[i]=p[tavi]; p[tavi]=cs;} }
/* Listzs: */
printf("\nA listz indtshoz ssn Enter-t! ");
while(getchar()!='\n');
for(i=0; i<n; ++i){
if(i%LAPSOR==0){ /* Lapvlts? */
if(i){ /* Vrakozs a lapvgen. */
C programnyelv 293
printf("A tovbblistzshoz ssn Enter-t! ");
while(getchar()!='\n'); }
/* Fejlc. */
printf("\n\n%10s%10s%10s\n", "X", "Y",
"Tvolsg");
printf("------------------------------\n"); }
/* Sorok: */
printf("%10.1f%10.1f%10.2f\n", p[i].x, p[i].y,
p[i].tav); }
return(0); }
13.13PLUSSZ.C
/* PLUSZ.C: 21x21-es plusz jel csillag karakterrel. */
#include <stdio.h>
void main(void){
int i; /* Ciklusvltoz deklarcija. */
/* A ciklus csak azrt van, hogy ne kelljen 10-szer
lerni ugyanazt a programsort. */
for(i=0; i<10; i=i+1) /* Vgrehajthat utastsok. */
printf(" *\n");/* 10 szkz s egy *. */
printf("*********************\n");/* 21 csillag. */
for(i=0; i<10; i=i+1) printf(" *\n"); }
13.14ROTL.C
/* ROTL.C: Balra forgats. */
#include <stdio.h>
#define HSZ sizeof(unsigned long)*8 /* A tpus bitszma. */
unsigned long rotl(unsigned long x){/* x balra forgatsa
eggyel. Eggyel balra toljuk, s az eredeti legfels bitet
berakjuk alulra: */
return (x<<1 | x>>HSZ-1); }
void binaris(unsigned long x){
unsigned long maszk;
for(maszk=0X80000000ul; maszk; maszk=maszk>>1)
if(maszk&x) putchar('1'); else putchar('0'); }
void main(void){
unsigned long x=0X4C59E9FAul;
int i=20;
printf("Balra forgats:\n\nAz eredeti rtk: ");
binaris(x);
while(i--){
printf("\nForgatva egyet: ");
x=rotl(x);
binaris(x); }
putchar('\n'); }
13.15STRMAKRO.C
/* STRMAKRO.C: Az STRMIN.C, azaz a legrvidebb szvegsor
kivlasztsa, trsa strcopy makrval. */
#include <stdio.h>
#define MAX 128
294 FGGELK
int getline(char s[], int n); /* Fggvny prototpusok. */
/* A makrdefinci pontos megrtshez tanulmnyozandk
a mutatk!!! */
#define strcopy(cel, forras) \
{ char *pcel=cel, *pforras=forras;\
int i=0;\
while((pcel[i]=pforras[i])!='\0') ++i; }
/* A makr mg elegnsabb lenne i, azaz indexels nlkl:
#define strcopy(cel, forras) \
{ char *pcel=cel, *pforras=forras;\
while(*pcel++=*pforras++); } */
void main(void){ /* Fggvnydefinci. */
int hsz; /* Az aktulis sor hossza. */
int min; /* Az aktulis min. sor hossza. */
char sor[MAX+1]; /* Az aktulis sor. */
char ment[MAX+1]; /* Az aktulis min. sor. */
printf("\n\n\nA legrvidebb szvegsor kivlasztsa:\n");
printf("A sorokat zrja le Enter-rel!\n");
printf("Utoljra adjon meg egy res sort is!\n\n");
min=MAX+1; /* Mestersges min. hossz. */
/* Sor olvass s minimumkeress res sorig: */
while((hsz=getline(sor, MAX))>0)
if(hsz<min){
min=hsz;
strcopy(ment, sor); }
/* Kijelzs csak akkor, ha megadtak sorokat: */
printf("A legrvidebb sor:\n");
if(min<MAX+1)printf("%s\n%d karakter.\n", ment, min); }
int getline(char s[],int n){
int c,i;
for(i=0;i<n&&(c=getchar())!=EOF&&c!='\n';++i) s[i]=c;
s[i]='\0';
while(c!=EOF&&c!='\n') c=getchar();
return(i); }
13.16STRMIN.C
/* STRMIN.C: A legrvidebb szvegsor kivlasztsa. */
#include <stdio.h>
#define MAX 128
int getline(char s[], int n); /* Fggvny prototpusok. */
void strcopy(char cel[], char forras[]);
void main(void){ /* Fggvnydefinci. */
int hsz; /* Az aktulis sor hossza. */
int min; /* Az aktulis min. sor hossza. */
char sor[MAX+1]; /* Az aktulis sor. */
char ment[MAX+1]; /* Az aktulis min. sor. */
printf("\n\n\nA legrvidebb szvegsor kivlasztsa:\n");
printf("A sorokat zrja le Enter-rel!\n");
printf("Utoljra adjon meg egy res sort is!\n\n");
C programnyelv 295
min=MAX+1; /* Mestersges min. hossz. */
/* Sor olvass s minimumkeress res sorig: */
while((hsz=getline(sor, MAX))>0)
if(hsz<min){
min=hsz;
strcopy(ment, sor); }
/* Kijelzs csak akkor, ha megadtak sorokat: */
printf("A legrvidebb sor:\n");
if(min<MAX+1)printf("%s\n%d karakter.\n", ment, min); }
int getline(char s[],int n){
int c,i;
for(i=0;i<n&&(c=getchar())!=EOF&&c!='\n';++i) s[i]=c;
s[i]='\0';
while(c!=EOF&&c!='\n') c=getchar();
return(i); }
void strcopy(char cel[], char forras[]){
/* forrs msolsa cel-ba. cel-t elg nagynak ttelezi
fel a fv. */
int i;
i=0;/* Az indexels a karakterlncok elejtl indul. */
/* Msols lezr nullig, s mg azt is tviszi: */
while((cel[i]=forras[i])!='\0') ++i; }
13.17STRRV.C
/* STRRV.C: Szvegsor megfordtsa a sajt helyn. */
#include <stdio.h>
#include <string.h>
#define MAX 128 /* Az input puffer mrete. */
int getline(char s[],int n){
int c,i;
for(i=0;i<n&&(c=getchar())!=EOF&&c!='\n';++i) s[i]=c;
s[i]='\0';
while(c!=EOF&&c!='\n') c=getchar();
return(i); }
void csere(int i, int j, char s[]){ /* Rekurzv csere fv.*/
char k;
/* Mg az als index kisebb a felsnl: */
if(i<j){
/* Az s karakterlnc kt elemnek cserje: */
k=s[i]; s[i]=s[j]; s[j]=k;
/* Az als index nvelend, s a fels meg
cs"kkentend: */
++i; --j;
/* A kt j indexszel jrahvjuk a csere fggvnyt. */
csere(i, j, s); } }
void strrv(char s[]){/* s karakterl nc megfordtsa a sajt
helyn. Rekurzivits knnyen a csernl biztosthat: */
if(strlen(s)>1) csere(0, strlen(s)-1, s); }
296 FGGELK
void main(void){
char sor[MAX+1]; /* Az aktu lis sor. */
printf("\n\n\nSz"vegsor megfordt sa a saj t helyn:\n");
printf("Utolj ra adjon meg egy res sort is!\n\n");
/* Sor olvas sa, megfordt sa s kijelzse res sorig: */
while(getline(sor, MAX)>0){
strrv(sor);
printf("%s\n\n", sor); } }
13.18STRSTRXT.C
/* STRSTRXT.C: Sorban adott szveg minden elfordulsnak
megkeresse. Lsd mg az INDEXEU.C pldaprogramot is! */
#include <stdio.h>
#define INP 2 /* Az input puffer mrete. */
#define KERSZOV "az" /* A keresett karakterlnc. */
int getline(char *, int);
char *strstr(const char *, const char *);
char *strstrnext(const char *, const char *);
void main(void){
char *n; /* Az elforduls cme. */
char sor[INP+1]; /* A beolvasott sor. */
printf("Gpeljen be egy sort, melyben a(z) \'%s\' "
"szveg\nelfordulsait keressk. Vge: EOF vagy"
" res sor.\n\n", KERSZOV);
while(getline(sor, INP)>0)
if(n=strstrnext(sor, KERSZOV)){
printf("Elfordulsi indexek: ");
/* Ha az elforduls cmbl kivonjuk a tmb
kezdcmt, az elforduls indext kapjuk. */
while(printf("%d ", n-sor),
(n=strstrnext(sor, KERSZOV)));
putchar('\n'); }
else printf("Nincs benn!\n"); }
int getline(char *s, int n){ /* Sor beolvassa s-be. */
int c; /* A hosszt adja vissza. */
char *t=s; /* Indexels helyett a t mutatval
haladunk az s karaktertmbn. A t mindig a kvetkez
szabad helyre mutat a tmbben, melynek tlrst az n
elfogysa akadlyozza meg. */
while(n-->0&&(c=getchar())!=EOF&&c!='\n') *t++=c;
*t='\0';
while(c!=EOF&&c!='\n') c=getchar();
/* A karakterlcot zr '\0' cmbl a tmb kezdcmt
kivonva, ppen a karakterlnc hosszt kapjuk. */
return(t-s); }
char *strstr(const char *s, const char *t){ /* Vissza t
s-beli els elfordulsnak cme, ill. NULL mutat, ha
t nincs is s-ben. */
const char *p, *r;
/* s tmbn a lncot zr '\0'-ig haladunk legfeljebb. */
for(;*s;++s){
C programnyelv 297
/* Mindenegyes s cmre rprbljuk a t kar.lncot: */
for(p=s, r=t; *r!=0&&*p==*r; ++p, ++r);
/* Ha mindenegyes karakterpozci egyezett, vissza-
adjuk a t els elfordulsnak cmt s-ben. */
if(*r=='\0')return((char *)s);}
return(NULL); }
char *strstrnext(const char *s,const char *t){/* Mindaddig
t s-beli kvetkez elfordulsnak cmt adja vissza, mg
NULL mutatt nem szolgltat. */
/* ws implicit kezdrtke a program indulsakor NULL! */
const static char *ws;
if(ws==NULL) ws=s;
else ++ws;
return ((char *)(ws=strstr(ws, t))); }
13.19TOBBOSZL.C
/* TOBBOSZL.C: Forint-eur tszmts 1 - 4 oszlopban. */
#include <stdio.h>
#define ALSO 100 /* A tartomny als hatra. */
#define FELSO 1000 /* A tartomny fels rtke. */
#define LEPES 100 /* A lpskz. */
#define ARFOLYAM 253.5 /* Ft/eur rfolyam. */
#define MAX 4 /* Max. lista-oszlopprok szma. */
void main(void){
int ft, i, max;
printf("\nForint-eur tszmts\n\n");
max=0;
while(max<1||max>MAX){
printf("Oszlopprok szma(1 - %d)?",MAX);
max=getchar()-'0';}
for(i=0; i<max;++i)printf("%9s|%9s|","Forint", "Eur");
if(max!=MAX)putchar('\n');
for(i=0; i<max;++i)printf("---------+---------+");
if(max!=MAX)putchar('\n');
for(ft=ALSO,i=0;ft<=FELSO*max;ft=ft+LEPES){
printf("%9d|%9.2f|", ft, ft/ARFOLYAM);
if(++i==max) { i=0; if(max!=MAX)putchar('\n');}}}
13.20XPLUSZOR.C
/* XPLUSZOR.C: Kt mtrix sszeadsa s szorzsa. */
#include <stdio.h>
#define SIZE 10
int meret(char *sz, int max);
void matrixbe(int m, int n, int (*A)[SIZE], char *s);
void szorzas(int m, int n, int o,
int (*A)[SIZE],int (*B)[SIZE],long (*C)[SIZE]);
void main(void){
int i,j, /* Indexek. */
m,n, /* Sorok, oszlopok szma. */
A[SIZE][SIZE],B[SIZE][SIZE];/* A mtrixok. */
long C[SIZE][SIZE];
printf("\nKt mtrix sszeadsa s szorzsa:\n");
298 FGGELK
m=meret("Sorok ",SIZE);
n=meret("Oszlopok",SIZE);
matrixbe(m,n,A,"az els ");
matrixbe(m,n,B,"a msodik");
printf("\nAz sszegmtrix:\n\n");
for(i=0;i<m;++i){
for(j=0;j<n;++j) printf("[%2d][%2d]:%6ld ",
i+1, j+1, (long)A[i][j]+B[i][j]);
printf("\n");}
if(m==n){ /* Ha a mrixok ngyzetesek! */
szorzas(m,m,m,A,B,C);
printf("\nA szorzatmtrix:\n\n");
for(i=0;i<m;++i){
for(j=0;j<n;++j) printf("[%2d][%2d]:%10ld ",
i+1, j+1, C[i][j]);
printf("\n"); } } }
int getint(int *); /* Lsd a PELDA27.C-ben! */
int meret(char *sz, int max){ /* 1 s max kztti egsz */
int m=0; /* szm bekrse, s ezt adja vissza*/
while(m<1||m>max){ /* afggvny. Az sz a szmbekrs
cljra utal szveg. */
printf("%s szma(1-%d)? ",sz,max);
getint(&m);}
return(m);}
void matrixbe(int m, int n, int (*A)[SIZE], char *sz){
/* Az mxn-es A mtrix elemeinek sorfolytonos */
int i,j; /* bekrse sz szveggel. */
printf("Krem %s mtrix elemeit a megadott "
"sorrendben!\n",sz);
for(i=0;i<m;++i)for(j=0;j<n;++j){
printf("[%2d][%2d] : ",i+1,j+1);
getint(&A[i][j]);}}
void szorzas(int m, int n, int o, int (*A)[SIZE],
int (*B)[SIZE], long (*C)[SIZE]){
/* Az mxn-es A mtrix szozsa az nxo-s B-vel s */
int i,j,k; /* az eredmny az mxo-s C-be kerl. */
for(i=0;i<m;i++){
for(j=0;j<o;j++){
C[i][j]=0l;
for(k=0;k<n;k++)C[i][j]+=((long)A[i][k])*B[k][j];}}}
#include <conio.h>
#include <limits.h>
#if SHRT_MAX == INT_MAX
#define HOSSZ 4
#else
#define HOSSZ 9
#endif
#define F6 64
#define CTRLZ 26
#define MAX INT_MAX/10
C programnyelv 299
#define HATAR INT_MAX%10+'0'+1
int getint(int *pn){/* Egsz beolvassa a bemenetrl. */
int c, /* A beolvasott karakter. */
sign=1, /* Eljel: pozitv +1, negatv -1. Alapr-
telmezs a pozitv, a kezdrtk miatt. */
elojel=0, /* Volt-e mr eljel? */
hossz=0, /* A beolvasott szmjegy karakterek szma. */
null=0; /* A beolvasott szm zrus-e? */
while(!hossz) switch(c=getch()){
case ' ':
case '\t':
case '\r': if(!elojel)
if(c!='\r')putch(' ');
else {putch('\n'); putch('\r'); }
break;
case '+':
case '-': if(!elojel){
putch(c); sign=(c=='+')?1:-1; ++elojel; }
break;
case '0': if(!elojel){
putch(c); *pn=0; ++hossz; null=1;}
break;
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
putch(c); *pn=c-'0'; ++hossz;
break;
default : if(!c)c=getch();
if(c==CTRLZ||c==F6) return EOF; }
while(1) switch(c=getch()){
case ' ':
case '\t':
case '\r': if(c!='\r')putch(' ');
else {putch('\n'); putch('\r'); }
*pn*=sign; return c;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
if(!null&&(hossz<HOSSZ||
(hossz==HOSSZ&&(*pn<MAX||*pn==MAX&&
(sign==1&&c<HATAR||sign!=1&&c<=HATAR))))){
putch(c);
*pn=*pn*10+c-'0';
++hossz; }
break;
default : if(!c)c=getch();
if(c==CTRLZ||c==F6){
*pn*=sign;
return EOF;} } }

You might also like