Programming | C / C++ » Bodlaki Tamás - Programozás C nyelven, távoktatási segédlet

Datasheet

Year, pagecount:2003, 135 page(s)

Language:Hungarian

Downloads:5310

Uploaded:June 06, 2004

Size:366 KB

Institution:
-

Comments:

Attachment:-

Download in PDF:Please log in!



Comments

11111 ragacs21 April 6, 2011
  Kösz! OK
11111 NIstvan1951 September 26, 2010
  Nagyon jó

Content extract

Bodlaki Tamás Programozás C nyelven Távoktatási segédlet TARTALOMJEGYZÉK 1. Bevezetés 7 2. A C nyelv egyszerû adattípusai 2.1 Az elsô C program beírása és futtatása 2.2 Az alapvetô egyszerû adattípusok felsorolása 2.3 A printf() függvény leírása 2.4 A scanf() függvény leírása 2.5 Konstansok definiálása 2.6 Változók inicializálása 2.7 Megjegyzések a programon belül 8 8 8 10 11 12 13 13 3. Mûveletek és operátorok 3.1 Aritmetikai operátorok 3.2 Relációs operátorok 3.3 Logikai operátorok 3.4 Értékadó kifejezések és operátorok 3.5 Inkrementáló és dekrementáló operátorok 3.6 Méret operátor . 3.7 Bitenkénti operátorok 3.8 Típuskonverzió Automatikus . Kikényszerített . 3.9 Precedencia táblázat 3.10 Fontosabb matematikai függvények leírása 14 14 15 15 15 15 16 16 19 19 20 20 21 4. Vezérlési szerkezetek 4.1 Szelekció Az if - else utasítás . A ? operátor . Az else - if szerkezet . A switch

utasítás . 4.2 Ciklusok A while utasítás . A do - while utasítás . A for utasítás . A break utasítás . A continue utasítás . 4.3 A goto utasítás, cimkék Feladatok a 2. - 3 - 4 fejezetek anyagából 22 22 22 23 24 25 26 26 27 29 31 31 31 32 5. Tömbök - I rész 5.1 Egydimenziós tömbök 5.2 Kétdimenziós tömbök Feladatok az 5. fejezet anyagából 33 34 35 37 6. Karaktertömbök és karaktermüveletek 6.1 Karaktertömbök 6.2 Karaktermûveletek A getchar() függvény . A putchar() függvény . A getch() ill. getche() függvények A scanf() függvény . 6.3 Stringkonverziós mûveletek Numerikus értékek stringgé alakítása . String numerikus értékekké alakítása . Feladatok a 6. fejezet anyagából 38 38 39 39 39 40 41 43 43 44 45 7. Függvények - I rész 7.1 A függvények általános jellemzôi 7.2 Változók érvényességi köre 7.3 Paraméterátadás kérdése Feladatok a 7. fejezet anyagából 46 46 48 49 49 8. Mutatók (

Pointerek ) - I rész 8.1 Általános rész 8.1 Változó címének átadása 8.2 Indirekció Feladatok a 8. fejezet anyagából 50 50 50 50 54 9. Függvények - II rész 9.1 Tárolási osztályok Automatikus . Extern . Statikus . Regiszter . Feladatok a 9. fejezet anyagából 55 57 57 57 58 58 59 10. Tömbök - II rész 10.1 Egydimenziós tömbök és pointerek 10.2 Címaritmetika 10.3 Kétdimenziós tömbök és pointerek 60 60 61 62 10.4 Memória kezelés 64 Feladatok a 10. fejezet anyagából 67 11. Mutatók ( Pointerek ) - II rész 11.1 Pointertömbök 11.2 Függvényre mutató pointer 11.3 Függvényekre mutató pointertömbök 68 68 70 71 12. Struktúrák . 12.1 A struktúra fogalma, deklarálása, definíciója 12.2 Struktúrák és függvények Struktúra címének elôállítása . Struktúra taghoz való hozáférés a "->" operátorral . 12.3 Struktúratömbök Feladatok a 11. - 12 fejezet anyagából 73 73 75 75 75 77 79 13.

Parancssor argumentumok használata 80 14. Típusnév definíciók 82 15. File kezelés - I rész 15.1 Szabványos be és kimenet átirányítása 15.2 File deklaráció 15.3 File megnyitása 15.4 File írása Egy karakter kiírása . Formátumozott változólista kiírása . 15.5 File olvasása Egy karakter beolvasása . Formátumozott változólista beolvasása . 15.6 File lezárása Feladatok a 13. - 14 - 15 fejezet anyagából 83 83 83 84 85 85 85 85 85 86 86 88 16. File kezelés - II rész 16.1 File elejére történô pozicionálás 16.2 Adategység formátum nélküli kiiratása 16.3 Adategység formátum nélküli beolvasása 16.4 File vége ( EOF) vizsgálat Feladatok a 16. fejezet anyagából 89 89 89 89 90 95 Függelék : A Borland C++ 2.0 alapvetô grafikai függvényei 96 Kidolgozott feladatok .102 1. Bevezetés A C nyelv megalkotója Dennis Ritchie, aki egy PDP gépen készitette el a fordítót. A nyelv hatékonyságára jellemzô, hogy a UNIX

operációs rendszer túlnyomó része C nyelven íródott. Csak a legalapvetôbb rutinokat írták gépi nyelven A C nyelv alapvetô tulajdonságai közé tartozik a tömörség, a függvénycentrikusság és a pointerek elterjedt használata, valamint az, hogy a függvényhívásnál a paraméterátadás érték szerinti. Egy egyszerû C program általában a következôképpen néz ki : #include <stdio.h> /* Header file ; lehet több is ! / main() { /* F ô p r o g r a m / } függvény 01() { /* A függvények használata esetleges, / /* az adott feladattól függ / } függvény 02() { } függvény 03() { } Egy C program tehát nem más, mint C függvények diszjunkt halmaza. A segédletben szereplô példaprogramokat a BORLAND C++ 2.0 verziójú fordítójával fordítottuk. Felhasznált irodalom : B.W Kernighan - DM Ritchie : A C programozási nyelv Mûszaki Könyvkiadó, Budapest, 1988 Thomas Plum : Tanuljuk meg a C nyelvet. Novotrade Rt, Budapest 1987 2. A C nyelv

egyszerû adattípusai 2.1 Az elsô C program beírása és futtatása #include <stdio.h> /* A printf függvény használata miatt szükséges / void main() { printf("Kupacsapataink szereplése elkeserítô ! "); } A szövegben szereplô az új sor jele. Az <stdioh> a szabványos I/O mûveletekkel kapcsolatos definíciókat tartalmazza. A C utasításokat a ; zárja ! 1. sz példaprogram : #include <stdio.h> void main() { int x,y; // A void jelzi, hogy a main nem ad // vissza értéket printf(" Kérem az elsô számot : ");scanf("%d",&x); printf(" Kérem a második számot : ");scanf("%d",&y); printf(" X + Y = %d ",x+y); } 2.2 Az alapvetô egyszerû adattípusok felsorolása Minden adatot definiálni kell, azok használata elôtt. Az alapvetô adattípusok a következôk : Típus karakter integer Értelmezés Az érvényes karakterkészlet egy eleme. Bináris egész szám. Byte 1 2

Definíció char int 0 float double Egyszeres pontosságú lebegôpontos szám. 4 Kétszeres pontosságú lebegôpontos szám. 8 float double A definíció a tárolási osztálynak, változó típusának majd - egy vagy több szóköz után - a változó nevének megadásából áll. Ezt egy ; ( pontosvesszô ) karakter követi A változó neve tartalmazhat betûket, számokat és az ( aláhúzás ) karaktert, de mindenképpen betûvel vagy aláhúzással kel kezdôdnie. A Borland C++ 20 a változó nevének elsô 32 karakterét különbözteti meg ! ( Az elsô 32 karakter szignifikáns ! ) A kis és nagybetûk között a fordító különbséget tesz ! A változó nevét célszerû "beszédesre" választani, azaz jó ha elárulja azt, hogy mire akarjuk használni ! A C nyelvben azonban nemcsak a felsorolt alapvetô adattípusok használhatók, ugyanis létezik néhány minôsítô szimbólum, melyek egész jellegü mennyiségek esetén használhatók, ill.egy

esetben a double alaptípusra is A minôsítô szimbólumok a következôk : short long unsigned "rövid" "hosszú" "elôjel nélküli" A short az int típust minôsítheti, a long szintén az int-et, valamint a BORLAND C++ 2.0-ban a double típust is Az unsigned minôsítô a char, ill az int típusok elôtt állhat, beleértve a már - short-tal vagy long-gal - minôsített int típust Típus Értelmezés short integer "Rövid" bináris egész szám. long integer "Hosszú" egész szám. long double "Hosszú" double szám Méret (byte) 2 4 10 Minôsítô short long long double Megjegyzés : A long double típus nem eleme az alap C változótípusainak, késôbbi C fordítókban hozták létre. A számábrázolási tartományok a következôk, az összes lehetséges esetet figyelembe véve : Változótípus char : unsigned char : int : unsigned int : Alsó határ -128 0 -32 768 0 Felsô határ 127 255 32 767 65 535 1

long int : unsigned long : float : double : long double : -2 147 483 648 0 3.4E - 38 1.7E - 308 1.2E - 4932 2 147 483 647 4 294 967 295 3.4E + 38 1.7E + 308 1.2E + 4932 A short ill. int más gépeken ( pl IBM 370 ) különbözô méretü : a short 16, az int 32 bit hosszú. Jelen esetben mindkettô 16 bit hosszú ! Példa a definícióra : char c; int i,j; unsigned k; long l; float f; double d; Konstansok : Egész típusú Oktális Hexadecimális Long Lebegôpontos Karakteres : : : : : : -123, 12 034 / Mindig a 0 (nulla) karakterrel kezdôdik ! / 0x1f 123L 123.45, -2356, 012345E3 A Láthatjuk tehát, hogy mind tízes, mind nyolcas ill. tizenhatos számrendszerben megadhatunk konstansokat. Figyelembe kell venni azt a tényt, hogy oktális számok esetén a 08 szintaktikus hibát eredményez, hiszen nyolcas számrendszerben a legnagyobb számjegy a 7-es ! Minden konstansnál figyelembe kell venni az illetô típus számábrázolási határát. Minden lebegôpontos konstans

double típusként vesz részt a mûveletekben 2.3 A printf() függvény leírása Általános alak : printf("<formátum vezérlô mezô>"[,<változólista>]); Példa : printf(" I értéke = %d",i); 2 Leírás : A formátum vezérlô mezô állhat szövegbôl, karakteres állandókból ill. formátum vezérlô karakterekbôl A karakteres állandók a ( back slash ) - sel kezdôdnek Alapvetô karakteres állandók : = Új sor = Tabulátor f = Lapdobás A formátum vezérlô karaktereket mindig a % jel elôzi meg, utána következhet több karakter, ami utal a kiiratni kívánt változó típusára, és a kiiratás formátumára. A függvény mûködése során a formátumvezérlô karakterek helyére rendre behelyettesíti a változólista elemeit. Fontos : Ha több formátumvezérlô karakter van, mint ahány változót megadtunk a listában, akkor azon vezérlôkarakterek helyén, amelyekhez nem tartozik változó, véletlen érték fog

megjelenni. Ha hosszabb, mint ahány formátumvezérlô karakter van, akkor a lista végén szereplô változók értékei nem jelennek meg a kiiratásnál ! Alapvetô formátum vezérlô karakterek : %d = Integer %ld = Long integer %x = Hexadecimális egész %o = Oktális egész %f = Float %lf = Double %c = Egy karakter %s = Karakterlánc (string) A változólista a kiiratni kívánt változók neveit tartalmazza, vesszôvel elválasztva egymástól. Mód van a kiiratni kívánt érték mezôszélességének megadására is Amennyiben egy integert n számjegy szélességben akarunk kiiratni, akkor a megfelelô formátumvezérlés a következô : "%nd". Ebben az esetben az n számjegynél kisebb egészek balról szóközökkel lesznek feltöltve Például : a "%6d" formátumvezérlés a 123-at a következôképpen írja ki : 123. Lebegô pontos számok esetén a szélesség megadása a következô : "%x.yf", ahol x a teljes számhosszúságot

jelenti - a tizedespontot is beleszámítva - , y pedig a tizedesjegyek számát. Például : a "%82" formátumvezérlés a 12345-öt a következôképpen írja ki : 12345 3 2.4 A scanf() függvény leírása Általános alak : scanf("<formátum vezérlô mezô>",<változócim lista>); Példa Leírás : : scanf("%f",&f); A formátum vezérlô mezô formátum vezérlô karakterekbôl állhat. Ld: a printf() függvény leírásánál Mivel a scanf függvény a változó(k)-ban el akarja helyezeni a beolvasott értéket, ezért a változó(k) címeit kell átadni. Ennek a ténynek a részletes magyarázatára késôbbiekben térünk ki ! A változó címét a változó neve elé írt & karakter segítségével tudjuk elôállítani. Amennyiben egyszerre több változóba akarunk értékeket beolvasni, úgy kétféle módszert alkalmazhatunk : 1.) A programban a formátumvezérlô karaktereket vesszôvel választjuk el

egymástól, és a program futása során a bebillentyûzött értékeket is vesszôvel választjuk el . Példa : int x, y, z ; scanf("%d,%d,%d",&x,&y,&z); esetén a beolvasás a következôképpen történik : 2,3,4 <ENTER> . 2.) A programban a formátumvezérlô karaktereket nem választjuk el egymástól, és a program futása során az egyes bebillentyûzött értékek után lenyomjuk az <ENTER> billentyût . Példa : int x, y, z ; scanf("%d%d%d",&x,&y,&z); esetén a beolvasás a következôképpen történik : 2 <ENTER>, 3 <ENTER> 4 <ENTER> 4 2.5 Konstansok definiálása A konstansok definiálása a main() elôtt történik a következô alakban: #define <KONSTANS NEVE> <konstans értéke> pld.: vagy : #define MAXELEM 1000 #define PI 3.1415 MAXELEM és PI úgynevezett szimbolikus állandók, melyeket nagybetûvel szokás írni. Az állandókat egy úgynevezett elôfordító a

fordításkor behelyettesíti a programba. A konstans definíciók után tilos pontosvesszôt tenni, ugyanis az elôfordító nemcsak a konstans értékét, hanem a pontosvesszôt is behelyettesítené a hivatkozás helyére. A szimbolikus állandók használata egyrészt áttekinthetôbbé teszi a programot, másrészt, ha a konstans értéke megváltozik, akkor a módosítást csak egyszer kell végrehajtani. Példa a szimbolikus állandó használatára : ker = 2*rPI ; / A kör kerülete / vagy : x = MAXELEM - 100 ; Megjegyzés : A BORLAND C++ 2.0 fordító lehetôséget nyújt arra, hogy másképpen is tudjunk konstansokat definálni. Ez a lehetôség a const kulcsszó, melynek használata a következô : const [<típus>] <konstans név> = <kezdôérték>; Például : const int i = 123; vagy const float f = 123.4; A konstans típusát áttekinthetôségi okokból is célszerû jelezni. A két konstans definálási lehetôség megegyezik abban, hogy egy

definiált konstansnak már nem adhatunk új értéket a program futása során. A különbség pedig abban áll, hogy a const a BORLAND C++ fordító egyik kulcsszava és az általa definiált konstans neve és értéke része lesz a fordítás során keletkezô tárgykódnak. Ezzel ellentétben a #define direktíva a fordító elôfeldolgozó részére bír csak jelentéssel, ugyanis az általa definiált konstans nevével a C fordító már nem találkozik, hanem csak az értékével. Ilymódon a tárgykódban a konstans neve nem szerepel, hanem csak az értéke. 5 2.6 Változók inicializálása A változó definiálásakor megadhatunk egy konstans értéket, például : int i=0; float f=67.25; Az értékadást az = jellel hajtjuk végre és minden utasítást a ; zár le! A változó inicializálás és a konstans definiálás között az alapvetô különbség az, hogy inicializálás esetén a változó értéke módosítható, konstans definíció esetén pedig nem ! 2.7

Megjegyzések a programon belül C programokhoz megjegyzést a /* ill. */ közé lehet elhelyezni. A megjegyzések nem ágyazhatók egymásba ! Tetszôleges sorban, oszlopban kezdôdhetnek és végzôdhetnek . Például : /* Itt kezdôdik a bemenô adat vizsgálata ! / jó, de /* Kiiratás / A,B,C és D / a képernyôre / alak hibás ! A megjegyzés másik lehetôsége a // (két per jel) alkalmazása. Csak arra a sorra vonatkozik, ahol áll ! 6 3. Mûveletek és operátorok 3.1 Aritmetikai operátorok Öt fajta létezik a C nyelvben : + , - , * , / , %. Ha két egész számot osztunk, akkor az eredmény a hányados egész része lesz. A % operátor két egész osztása esetén a maradékot adja eredményül, float ill. double típusra nem alkalmazható ! Pld.: 5/3 = 1 és 5%3 = 2 Ezen operátorok közül az elôjel (-) precedenciája a legmagasabb, utána következik a / , * , % majd a + , - . Az aritmetikai operátorok balról jobbra kötnek Ennek a ténynek fôleg azonos

precedenciájú mûveleteknél van jelentôsége. Pl: 4/2*2 = 4 és nem 1. A mûveletek végrehajtási sorrendjét zárójelezéssel befolyásolhatjuk : ( ill. ) Ebben az esetben : 4/(2*2) = 1. A zárójelezés precedenciája ugyanis megelôzi a többi operátorét ! Fontos : Ha valamely összetett mûvelet eredménye int típusú és a mûveletben résztvevô változók is int típusúak, ettôl függetlenül valamely részmûvelet eredménye túllépheti az int ábrázolási tartományát ( túlcsordulás ! ). Ebben az esetben célszerû típusmódosítást elôírni 2. sz példaprogram : #include <stdio.h> main() { int i,j,k,q; printf(" Kérem J értékét : ") ; scanf("%d",&j); printf(" Kérem K értékét : ") ; scanf("%d",&k); printf(" Kérem Q értékét : ") ; scanf("%d",&q); i = (j*k)/q ; printf(" Simán -> I = %d",i); // Típusmódosítással : i = (long) (j)*k/q ; printf("

(LONG) -> I = %d",i); } A típusmódosításról még lesz szó ! 3.2 Relációs operátorok Azonos precedenciájúak : >, >= , <, <=. Eggyel alacsonyabb szinten azonos precedenciájúak :  , != . Az  operátor két operandus egyenlôségét vizsgálja és ezzel a jelölésmóddal különböztetjük meg az értékadástól. A != operátor a "nem egyenlô" reláció jelölésére szolgál A relációs operátorok precedenciája alacsonyabb mint az aritmetikai operátoro ké. Bármely relációs kifejezés igaz vagy hamis értéke integerré (1 vagy 0) konvertálódik, amint azt a 3.81 pontban látni fogjuk ! 3.3 Logikai operátorok && : Logikai ÉS, ¦ ¦ : Logikai VAGY, ! : Logikai NEM . A && és a ¦¦ szimbólumokkal összekapcsolt kifejezések kiértékelése balról jobbra történik, és a kiértékelés azonnal megáll, amint az eredmény igaz vagy hamis volta kiderül ! A && precedenciája

magasabb mint az ¦¦ -é, de mindkettôé alacsonyabb mint az elôbbieké ! A NEM precedenciája a () után következik. 3.4 Értékadó kifejezések és operátorok Az olyan típusú kifejezések mint pld. osszeg = osszeg + forint a += értékadó operátorral úgy írhatjuk, hogy osszeg += forint Ez igaz az eddig tanultak közül a +, -, * , / , % operátorokra. Ez az írásmód tömörebb, jobban kifejezi a lényeget és a végrehajtása is gyorsabb. Figyeljünk arra, hogy az ilyen kifejezések mint pld y* = x+1 ; azt jelentik, hogy y = y(x+1); és nem azt, hogy y = yx+1 ; 3.5 Inkrementáló és dekrementáló operátorok Az inkrementáló operátor jele : ++, a dekrementálóé --. Mindkét operátor lehet prefix vagy postfix operátor. A ++ operátor 1-gyel növeli azt a változót amely elôtt, vagy amely után áll, mig a -- operátor 1-gyel csökkenti a változó tartalmát. Ha értékadásban, vagy más mûveletben vesznek részt, akkor a következôre kell nagyon vigyázni

: 3. sz példaprogram (részlet) : x = 5; y = ++x; x = 5; y = x++; // // // // // // A ++ prefix-ként x értéke elôszôr 6 lesz és ez adódik át y-ba x = 6 és y = 6. A ++ postfix-ként x értéke elôszôr átadódik y-ba, utána lesz 6 x = 6 és y = 5. Ugyanez vonatkozik a -- operátorra. A ++ és a -- nem használható kifejezésekre, például : x = (i+j)++ nem megengedett ! 3.6 Méret operátor A méret operátor - sizeof - valamely objektum méretét adja vissza byte-okban. Például : sizeof(long) = 4. 3.7 Bitenkénti logikai operátorok A bitenkénti operátorok jelölésmódja és értelmezése a következô : & : bitenkénti ÉS ¦ : bitenkénti VAGY ^ : bitenkénti KIZÅRÓ VAGY <<: bitléptetés balra (SHIFT LEFT) >>: bitléptetés jobbra (SHIFT RIGHT) ~ : egyes komplemens képzés ( egyoperandusú ! ) Az operátorok mûködésének magyarázata a következô : - Az & kétoperandusú mûvelet eredménye csak akkor 1, ha mindkét operandus

ugyanazon bitpozíciójában elhelyezkedô bitek értéke egyaránt 1. Minden más esetben az eredmény 0. Az & operátort valamely bithalmaz maszkolására használhatjuk - Az ¦ kétoperandusú mûvelet eredménye csak akkor nulla, ha mindkét operandus ugyanazon bitpozíciójában elhelyezkedô bitek értéke egyaránt 0. Minden más esetben az eredmény 1. A ¦ operátort bit(ek) 1-re állítására használhatjuk - Az & ill. ¦ nem tévesztendô össze a && ill ¦¦ operátorokkal Például : ha x értéke 2 és y értéke 4, akkor x & y = 0 ill x && y = 1 : x = 00000010 | = 2 y = 00000100 | = 4 ---------------------x&y = 00000000 | = 0 ill. x && y értéke nyilván 1 lesz mert x is igaz és y is igaz ( Értékük nullától különbözô ! ) - A ^ kétoperandusú mûvelet eredménye csak akkor 1, ha mindkét operandus ugyanazon bitpozíciójában elhelyezkedô bitek értéke egymással ellentétes. Ellenkezô esetben az eredmény

0. - A << kétoperandusú mûvelet során a baloldali operandus minden bitje, annyiszor mozdul el balra 1 pozicióval, ahányszor azt a jobb oldali operandussal megadjuk. - A >> kétoperandusú mûvelet során a baloldali operandus minden bitje, annyiszor mozdul el jobbra 1 pozicióval, ahányszor azt a jobb oldali operandussal megadjuk. - A ~ egyoperandusú mûvelet a mögötte álló operátor 1-es komplemensét állítja elô, azaz minden 1-es bitet nullára állít és viszont. Fontos : A bitmûveletek kizárólag egész jellegü mennyiségekre értelmezettek (példánkban a char típusra), float és double típusú változókra nem alkalmazhatók ! 4. sz példaprogram : // Példa a bitmûveletekre #include <stdio.h> #include <conio.h> // A getch() függvény miatt szükséges void main() { char x, y, es, vagy, kizaro vagy; char bitlep bal, bitlep jobb; unsigned char egyes kompl; x = 0x06 ; y = 0x03 ; es = x & y ; vagy = x | y ; kizaro

vagy = x ^ y ; bitlep bal = x << 3 ; bitlep jobb = bitlep bal >> 3 ; egyes kompl = ~x ; clrscr(); printf(" X = %x printf(" X & Y printf(" X | Y printf(" X ^ Y printf(" X << 3 printf(" X >> 3 printf(" ~X = = = = = = Y = %x ",x,y); %d ",es); %d ",vagy); %d ",kizaro vagy); %d ",bitlep bal); %d ",bitlep jobb); %d ",egyes kompl); getch(); } A program eredményül a következô értékeket szolgáltatja : Az es értéke 2, a vagy értéke 7, a kizaro vagy-é 5. A bitlep bal értéke 48 lesz, míg a bitlep jobb-é 6. Végezetül az egyes kompl értéke 249 lesz Az eredmények alakulását a következô táblázat magyarázza : X Y X&Y X¦ Y X^ Y X << 3 BITLEP JOBB>>3 ~X 128 64 32 16 8 4 2 1 Eredmény =============================== 0 0 0 0 0 1 1 0 6 0 0 0 0 0 0 1 1 3 =============================== 0 0 0 0 0 0 1 0 2 0 0 0 0 0 1 1 1 7 0 0 0 0 0 1 0 1 5 0 0 1 1 0 0 0 0 48 0 0

0 0 0 1 1 0 6 1 1 1 1 1 0 0 1 249 3.8 Típuskonverziók Amennyiben egy kifejezésben különbözô típusú operandusok fordulnak elô, úgy a kiértékeléshez az operandusokat azonos típusúakká kell alakítani. A típuskonverziónak két fajtája van : automatikus és kikényszeritett Automatikus típuskonverzió Általános szabály : Ha az operandusok különbözô típusúak, akkor az alacsonyabbik típusú alakul át magasabb típusúvá, a mûveletek elvégzése elôtt. Az eredmény magasabb típusú lesz 5. sz példaprogram (részlet) : int i; float z,y; . z = y + i; /* i -bôl elôször float-ot csinál a program / Konkrétan : - char és short mennyiségek int típusúvá alakulnak át, a float mennyiségek double típusúvá. Ezért van értelme pl annak, hogy : q = 1 ; k = q - 0 ; /* k értéke 1 lesz a 49 - 48 mûvelet miatt / - relációs ill. logikai kifejezések értéke 1, ha a kifejezés értéke igaz, és 0 ha hamis. Például : a=2 ; b=2 ; c = (a == b) ;

/* c értéke 1 lesz / c = (a != b) ; /* c értéke 0 lesz / - ezután ha az egyik operandus long double, akkor a másik is az lesz és az eredmény is. - ezután ha az egyik operandus double, akkor a másik is az lesz és az eredmény is. - egyébként ha az egyik operandus long, akkor a másik is az lesz és az eredmény is. - egyébként ha az egyik operandus unsigned, akkor a másik is az lesz és az eredmény is. - egyébként az operandusoknak int típusúaknak kell lenniük és az eredmény is az lesz. - az értékadás szintén típuskonverzióval jár : a jobboldal értéke átalakul a baloldal típusának megfelelõen. A float-ból int-be történô konverzió a törtrész levágását eredményezi. A double-bôl float-tá történô konverzió kerekítéssel történik. - függvényeknek történô argumentumátadás esetén a char és a short típusok int-té válnak, a float típus double típusúvá ! Kikényszerített típuskonverzió - cast operátor Alakja :

(típusnév) kifejezés. Szükséges lehet a 7. oldalon található 2 sz példaprogramban említett példán kívül, hasonló esetben is : A könyvtári gyökvonó függvény ( sqrt ) bemenô paraméterül double típusú változót vár Ha int típusból akarunk gyököt vonni, úgy típuskonverziót kell alkalmazni : int n = 9; double eredm; eredm = sqrt( (double) n ) ; /* eredm értéke 3.000000 lesz */ 3.9 Az eddig tanult operátorok precedencia táblázata Operátor () !, ~, ++, --, -, (tipus), sizeof *, /, % balról jobbra +, <<, >> <, <=, >, >= ==, != & ^ | && Asszociativitás balról jobbra jobbról balra balról jobbra balról jobbra balról jobbra balról jobbra balról jobbra balról jobbra balról jobbra balról jobbra || =, +=, -=, *=, /=, %= balról jobbra jobbról balra Fontos : Az olyan típusú kifejezések esetén mint az x = f() + g(); , ahol f és g két függvény nem tudjuk, hogy a fordító elôször f-et és utána

g-t számítja ki, vagy fordítva. Igy, ha akár f akár g olyan változót módosít, amelytôl a másik függ, x értéke függhet a kiértékelési sorrendtôl. ( Mellékhatás jelensége ! ) Megoldás : Åtmeneti változók használata. z = f() ; w = g() ; x=z+w; /* Elôször f() -et számoljuk / /* Utána g() -t számoljuk / /* Meghatározzuk a mûveletvégzés sorrendjét / 3.10 Fontosabb matematikai függvények leírása A Borland C++ 2.0 többek között a következô könyvtári függvényeket tartalmazza : Szintakika Leírás ---------------------------------------------------------------------------------------------int abs( int x ) x egész szám abszolútértéke long labs( long y ) y long szám abszolútértéke double fabs( double z ) z double szám abszolútértéke double sqrt( double w ) w double szám négyzetgyöke double pow( double p, double q ) p a q - adikon hatvány értéke double sin( double b ) b szög szinusza, b radiánban értendô double cos( double c

) c szög koszinusza, c radiánban értendô double tan( double d ) d szög tangense, d radiánban értendô A matematikai függvények használatához a #include <math.h> szükséges ! A matematikai függvények használatát - többek között - a 11. sz példaprogram mutatja be. 4.1 Szelekció 4. Vezérlési szerkezetek 4.1 Szelekció Az utasításokat a { (begin) ill. } (end) zárójelek használatával egyetlen összetett utasításba, más néven blokkba foghatjuk össze. A } után nincs pontosvesszô ! Az if - else utasítás Az if - else utasítás alakja : if( kifejezés ) 1. utasítás(blokk) else 2. utasítás(blokk) Amennyiben a kifejezés igaz - azaz értéke nem nulla - akkor az 1. utasitás(blokk), ha a kifejezés hamis - azaz értéke nulla - akkor a 2. utasítás(blokk) kerül végrehajtásra. Az else használata nem kötelezô ! Ha az if ill. else kulcsszót csak egy utasítás követi, akkor nem kötelezô a { ill } jelek használata, egyébként igen !

6. sz példaprogram (részlet) : if( a%2 { a = } else { a = if( } == 0 ) a/2; 3*a + 1; a>max ) max = a; Fontos : Mivel az else használata nem kötelezô, ezért elôfordulhat, hogy összetettebb alakokban nem egyezik meg az if-ek és az else - k szá15 4. Vezérlési szerkezetek ma. Annak eldöntésére, hogy melyik else melyik if - hez tartozik a következô szabály érvényes : Az else a hozzá legközelebb esô else nélküli if-hez tartozik ! Ajánlatos a { ill. a } zárójelek alkalmazása, így egyértelmûvé tehetjük a szerkezetet ! 7. sz példaprogram (részlet) : if( n == 0 ) if( a>b ) x = a; else y = b; Az elsô if után azért nem kell { ill. } mert az azt követô if egy utasításnak felel meg. Jelen konstrukcióban az else ág az if( a>b ) - hez tartozik Ha eredetileg nem ezt akartuk akkor a { ill. } használatával tudunk változtatni: 8. sz példaprogram (részlet) : if( n == 0 ) { if( a>b ) x = a; } else y = b; A ? operátor Az if - else

kifejezés egy speciális rövidítése : az ilyen típusú alakot, mint az if( a>b ) z = a; else z = b; a ? operátor használatával rövidíthetünk. Általános alak : 16 4.1 Szelekció kif1 ? kif2 : kif3 ; Ha kif1 értéke igaz akkor kif2, egyébként kif3 lesz ennek a kifejezésnek az értéke: z = (a>b) ? a : b; /* z = max(a,b) / Az else - if szerkezet - többszörös elágazás I. Általános alakja : if( kifejezés ) utasítás(blokk) else if( kifejezés ) utasítás(blokk) else if( kifejezés ) utasítás(blokk) else utasítás(blokk) Itt meg kell jegyezni, hogy gyakorlatilag nem külön utasításról van szó, hiszen egymásba ágyazott kétágú szelekciókkal van dolgunk. Mivel gyakran elôfordul ilyen döntési szerkezet, ezért az áttekinthetô programozási alak miatt külön tárgyaljuk. A kifejezések - egymás után történô - kiértékelése után az az utasítás kerül végrehajtásra, amelyhez tartozó kifejezés igaznak bizonyult. Ezután a

program kilép az else-if szerkezetbôl Az utasítások helyén egy utasítás vagy { ill. } között utasításblokk állhat Az utolsó else a "fentiek közül egy sem" szituációt kezeli. A hozzá tartozó utasítás csak akkor kerül végrehajtásra, ha elôtte mindegyik kifejezés hamisnak bizonyult. 9. sz példaprogram (részlet) : 17 4. Vezérlési szerkezetek k = (x-u)*(x-u) + (y-v)(y-v); if( k == r*r ) printf(" Rajta van a körön !"); else if( k > r*r ) printf(" Kivül van a körön !"); else printf(" Belül van a körön !"); A switch utasítás - többszörös elágazás II. Åltalános alakja : switch( kifejezés ) { case konstans 1: utasítás(blokk) break; case konstans 2: utasítás(blokk) break; . . . case konstans i: utasítás(blokk) break; default: utasítás(blokk) break; } A kifejezés csak egész típusú lehet ! Kiértékelése után azzal az utasítás(blokk)-kal folytatódik a program amelyhez tartozó case

konstans megegyezett a kifejezés értékével. A break hatására befejezôdik a switch végrehajtása A default utáni utasítás(blokk) - ra akkor adódik a vezérlés, ha egyik case-re sem teljesült az egyenlôség. A case után csak a kifejezés típusának megfelelô állandót lehet megadni ! A case utáni kifejezés típusa csak 18 egész jellegû lehet, tehát char, int vagy long. Egymás után több case-t is fel sorolhatunk. 10. sz példaprogram (részlet) : switch(c) /* c - ben egy karakter értéke található / { case 2: case 4: case 6: case 8: printf(" Páros !"); break; case 1: case 3: case 5: case 7: case 9: printf(" Páratlan !"); break; case 0: printf("Nulla !"); break; default: if( c >= A && c <= Z ) printf(" Nagybetû !"); else if( c >= a && c <= z ) printf(" Kisbetû !"); else printf(" Egyéb !"); break; } Fontos : Ha egyszer beléptünk egy switch utasítás valamelyik

case ágába, akkor az utasítások mindaddig végrehajtódnak amíg egy break utasításra nem jut a vezérlés ! Két case-nek nem lehet ugyanaz az értéke ! 4.2 Ciklusok 19 4. Vezérlési szerkezetek Elôltesztelô ciklus : A while utasítás. A while utasítás alakja : while( kifejezés ) utasítás(blokk) A program mindaddig végrehajtja az utasítás(blokk)-ot amíg a while-t követô kifejezés értéke IGAZ, azaz 0-tól különbözik . 11. sz példaprogram : // // // // // Az 1 - 1/2 + 1/4 - 1/8 . váltakozó elôjelü sor összegének kiszámítása a billentyûzetrôl megadott pontossággal. A sor a (-1)(n-1)*(1/2(n-1)) zárt alakban írható fel és összege : 2/3. Vezérlési szerkezet : a WHILE utasítás #include <stdio.h> #include <conio.h> #include <math.h> // Az fabs() és a pow() függvé// nyek miatt szükséges void main() { double n, e, s, os; printf(" Kérem a pontosságot : "); scanf("%lf",&e) ; s = 1 ; os =

0 ; n = 1 ; // Amíg az új és a régi összeg különbségének // abszolút értéke nagyobbb mint a hibahatár, // addig, folytatódjon a sorösszeg képzés. while( fabs( s - os ) > e ) { os = s ; n += 1 ; s += pow( -1, n-1 ) * (1.0/pow(2,n-1)) ; } 20 4.2 Ciklusok printf(" Az összeg : %lf",s); getch(); } Hátultesztelô ciklus : A do - while utasítás A do - while utasítás alakja : do utasítás(blokk) while( kifejezés ); A program elôször végrehajtja az utasítás(blokk)-ot, majd kiértékeli a kifejezést. Ez a ciklikus tevékenység folyik mindaddig, amíg a kifejezés értéke IGAZ, azaz 0-tól különbözik Mint látható, a C nyelv hátultesztelô ciklusa eltér a - több programnyelvnél - megszokott UNTIL típusú hátultesztelô ciklustól, amelynél a ciklus addig mûködik, amíg az UNTIL-t követô feltétel hamis. Amennyiben valaki az UNTIL alakot tartja "igazi" hátultesztelô ciklusnak, úgy a #define direktíva segítségével,

bármikor elôállíthatja az UNTIL alakot, amint azt a 13. sz példaprogram mutatja 12. sz példaprogram : // A 11. sz példaprogramban szereplô feladat megol// dása a DO WHILE utasítás alkalmazásával #include <stdio.h> #include <conio.h> #include <math.h> void main() { double n, e, s, os; printf(" Kérem a pontosságot : ") ; scanf("%lf",&e) ; 21 4. Vezérlési szerkezetek s = 0 ; os = 0 ; n = 1 ; do { os = s; s += pow( -1, n-1 ) * (1.0/pow(2,n-1)) ; n += 1 ; } while( fabs( s - os ) > e ) ; printf(" Az összeg : %lf",s); getch(); } 13. sz példaprogram : // A 11. sz példaprogramban szereplô feladat megol// dása az általunk definiált UNTIL utasítás alkal // mazásával. #include <stdio.h> #include <conio.h> #include <math.h> #define UNTIL(condition) while(!(condition)) void main() { double n, e, s, os; printf(" Kérem a pontosságot : ") ; scanf("%lf",&e) ; s = 0 ; os

= 0 ; n = 1 ; do { os = s; s += pow( -1, n-1 ) * (1.0/pow(2,n-1)) ; 22 4.2 Ciklusok n += 1 ; } UNTIL( fabs( s - os ) <= e ) ; printf(" Az összeg : %lf",s); getch(); } Taxatív ciklusszervezés : A for utasítás A for utasítás alakja : for( kifejezés1; kifejezés2; kifejezés3 ) utasítás(blokk) A kifejezések általában a következôket jelentik : , kifejezés1 : Kezdeti értékadás a ciklusváltozónak. kifejezés2 : A lefutási feltétel(ek) megfogalmazása. Lefutási feltételként nem csak a ciklusváltozóval kapcsolatos feltételt lehet megadni hanem bármilyen más feltételt is. kifejezés3 : A ciklusváltozó növelése vagy csökkentése. Bármelyik kifejezés hiányozhat ! Példák : 1./ for( i=1; i<=100; i++) { printf(" A(z) %d négyzete = %d",i,i*i); } // Kinyomtatja a természetes számok négyzetét 1-100 - ig. 2./ A for ciklusok egymásba ágyazhatóak : int i, j, prim, n; . for( i=5; i<=n; i=i+2 ) // Páratlan számok

képzése 5-tôl n-ig { prim = 1; for( j=3; j<=i-1 && prim == 1; j++) // Természetes számok képzése { // 3-tól i-1 ig. if( i%j == 0 ) prim = 0; // Ha j osztója i-nek akkor i 23 4. Vezérlési szerkezetek } if( prim == 1 ) printf(" %3d",i); // nem prímszám } A belsô for ciklus akkor is befejezôdik, ha a prim változó értéke 0 lesz így nem biztos, hogy lefut (i - 1) - ig. A külsô for ciklus i változójának egy értékéhez a belsô for ciklus a feltételében meghatározottak szerint kerül végrehajtásra. Ezután i értéke kettôvel növelôdik, és újra a belsô ciklus fut le. Ez így megy mindaddig, amíg i el nem éri n értékét. A for ciklus több ciklusváltozót is tartalmazhat, ezeket a , operátorral kell elválasztani egymástól. 14. sz példaprogram (részlet) : for( i=1, j=2; i<=100; i+=2, j+=2) { printf(" Páratlan = %d < - > Páros = %d",i,j); } Bizonyos esetekben nagyon kényelmes a használata !

Fontos : Ez a konstrukció nem tévesztendô össze az egymásba ágyazott for ciklussal. Megjegyzés : A for utasítás egyenértékü a kifejezés1; while( kifejezés2 ) { utasítás(blokk) kifejezés3; } alakkal. Kilépés ciklusból ill. a switch-bôl : A break utasítás A break hatására a vezérlés azonnal kilép a for, while, do-while ill. switch konstrukciókból, és a konstrukciót követô elsô utasítással folytatódik a program végrehajtása. Egymásba ágyazott szerkezetek esetén mindig abból a legbelsô ciklusból lép ki a break, amelyik azt tartalmazza. 24 4.3 A goto utasítás, címkék Következô iteráció kezdeményezése : A continue utasítás. A continue utasítás csak ciklusokban használható. A while ill do-while ciklus belsejében az azonnali feltételvizsgálat végrehajtását eredményezi, for ciklus esetén pedig a ciklusváltozó módosítását. A switch utasításban hatástalan, ill ha a switch egy ciklusban szerepel, akkor erre a

ciklusra érvényesek a fent leírtak Az utóbbi két utasítást nem használjuk gyakran ! 4.3 A goto utasítás, címkék A goto utasítás használatától általában elzárkóznak a programozók. Elvileg a C-ben a goto-ra soha sincs szükség, és a gyakorlatban programozhatunk goto nélkül.Mégis elôfordulhatnak olyan esetek, amikor a goto használata a legcélszerûbb Ilyen például az a helyzet, amikor valamilyen hibakezelés során, egy kétszeresen - vagy többszörösen - egymásba ágyazott ciklus legbelsejébôl akarunk kilépni. Ilyenkor a break utasítást nem tudjuk használni 15. sz példaprogram (részlet ) : for( . ) { . for( . ) { if( hiba) goto hiba jav; } . } hiba jav : hiba lekezelése Feladatok a 2. - 3 - 4 fejezetek anyagából 25 4. Vezérlési szerkezetek 1.) Olvassunk be két egész számot, és irassuk ki összegüket, különbségüket, szorzatukat, valamint az elsônek a másodikkal való egész osztásának hányadosát és

maradékát ! 2.) Olvassunk be két valós számot, és irassuk ki a négyzetösszegüket valamint mértani közepüket ! 3.) Számítsuk ki egy henger felszínét és térfogatát, ha adott az alapkörének sugara és a magassága ! 4.) Olvassunk be két valós számot, és álapítsuk meg, hogy elôjelük megegyezik-e, különbözik-e, esetleg valamelyik szám nulla ! 5.) Olvassunk be egy egész számot, és döntsük el, hogy háromjegyû-e ! 6.) Olvassuk be egy intervallum két végpontját és egy értéket. Döntsük el, hogy az érték az intevallumba esik, ill. attól jobbra vagy balra ! 7.) Olvassunk be egy egyjegyû számot és irassuk ki szövegesen ( egy, kettô . ) ! 8.) Olvassunk be egy egész szögértéket (fokban), és irassuk ki a típusát ! (hegyes, derék, tompa, egyenes, homorú, teljes ) 9.) Olvassuk be egy pont ( x,y ) koordinátáit, és irassuk ki, hogy hol helyezkedik el a pont ! (Valamelyik síknegyedbe esik, vagy az origóra, vagy valamelyik

tengelyre) 10.) Hány kockából építhetô fel egy n emeletes gúla, ha minden emelet négyzet alakú, és az oldalhossza kettôvel nagyobb a fölötte lévônél ? A legfelsô ( n. ) emelet egy kockából áll 11.) Hány emeletes gúla építhetô fel m db kockából ? Irjuk ki, hogy mennyi kocka marad esetleg ki ! 12.) Irjunk programot a következô - váltakozó elôjelü - sor összegének adott pontosságú kiszámítására. A pontosság mértékét a program a billentyûzetrôl olvassa be: 1 - 1/2 + 1/3 - 1/4 + . 26 5. Tömbök - I rész Eddig olyan esetekkel foglalkoztunk, ahol egy változónévhez egy értéket tudtunk hozzárendelni. ( Skalár változó ) A tömb azonos típusú, véges számú elemből épül fel. Olyan közvetlen elérésû adatstruktúra, amelynek egy elemét a tömb nevével és az utána következô index-szel tudjuk elérni - alapesetben. Milyen jellemzôi vannak egy tömbnek C-ben ? A tömbnek öt jellemzôje van : - Tárolási osztály

specifikátor ( Ld.: 57 oldal) - Típus - Név - Méret - Dimenzió Típus : Az eddig megismert változó típusok valamelyike lehet. Név : A tömb nevének megválasztásával kapcsolatban a 2.2 pontban leírtak érvényesek Méret : A tömb definícíónál a tömb típusa után a nevét adjuk meg és utána az elemek számát - "[" ill. "]" között C -ben a tömb indexelése szigorúan a 0 - dik elemtôl kezdôdik. Indexelésnek nevezzük azt a mûveletet, amikor a tömb neve után "[" és "]" között direkt módon - egy számmal - megadjuk, hogy az illetô tömb hányadik elemét kívánjuk elérni. Igy például, az : int elemek[10] ; módon definiált tömbnek 10 eleme van : elemek[0] , elemek[1], . , elemek[9] ; de nincs 10-es indexü eleme Példa az indexelésre: elemek[3] = 20; vagy : for(i=0; i<10; i++) elemek[i] = 0; Dimenzió : Az elôbb bemutatott egydimenziós tömbön kívül kétdimenziós tömböt is használhatunk. Az

egydimenziós tömböt a matematikában megismert egy dimenziós vektorhoz hasonlíthatjuk, a kétdimenziós tömböt pedig a mátrixhoz Ezekután az egydimenziós tömb definiálása úgy történik, hogy megadjuk a típusát, ezután - egy vagy több szóközt követôen - a nevét, majd szögletes zárójelek között, az elemek számát. A deklarálást követheti - kapcsos zárójelek között a tömb elemeinek felsorolása, vesszôvel elválasztva. Ezt nevezzük a tömb inicializálásának ! Amennyiben a felsorolt elemek száma kevesebb a tömb méreténél, úgy a maradék elemek értéke nulla lesz ! Példa : int vv[10] ; // Egy integer típusú, vv nevû, 10 elemû tömb. vagy : int zz[10] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 } ; // Egy integer típusú, zz nevû, 10 elemû tömb, inicializálással. A példákban szereplô deklarációk egyben definíciók is, mert a tömbméretnek megfelelô memóriaterület lefoglalódik ! 5.1 Egydimenziós tömbök 16. sz

példaprogram : /* ============ Legkisebb elem kiválasztása =========== / #include <stdio.h> void main() { //a egy 10 elemû,integer tömb,inicializálva. int a[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; int i, min; min = a[0]; for(i=0; i<10; i++) { // Ha az aktuális minimum nagyobb a // tömbelemnél if( min > a[i] ) min = a[i] ; } printf(" A legkisebb elem = %2d",min); } Egydimenziós tömbbe történô adatbeolvasás a scanf() függvény segítségével oldható meg, a következô módon : #include <stdio.h> void main() { int beolv[10], i; for(i=0; i<10; i++) scanf("%d",&beolv[i]); . } Az "&" jel ( cím operátor ) ugyanúgy szükséges a tömbelem elôtt, mint egyszerû változó esetén ! ( Lásd késôbb részletesen ! ) 5.2 Két dimenziós tömbök A kétdimenziós tömb definiálása a típust és a nevet tekintve megegyezik az egydimenziós tömb definiálásával. A különbség a méretek számában van A

név után azt kell megadni, hogy a tömbnek hány sora van, utána pedig azt, hogy hány oszlopa. A kétdimenziós tömb tehát egy olyan vektor, amely azonos típusú és azonos elemszámú vektorokból áll ! Az indexelés itt is 0-tól kezdôdik ! Példa : A double x[4][5]; egy olyan kétdimenziós tömböt jelent amelynek 4 sora van (0.3) és 5 oszlopa ( 04 ) Az x mátrix egy elemére kettôs indexeléssel hivatkozhatunk : x[2][3] = 5.67; Az x mátrix 2-es indexü ( azaz 3-ik ) sora ill. 3-as indexü (azaz 4-ik) oszlopbeli eleme vegye fel az 5.67-es értéket A mátrix tárolása a memóriában sorfolytonosan történik, azaz a 0. sor után az 1 sor következik stb Az általunk hivatkozott x[2][3] tehát a memóriában a 2*5+3 = 13. elem Az indexelés 0-tól indult ! A kétdimenziós tömbök inicializálása is megoldható : a tömb elemeit - kapcsos zárójelek között - soronként kell feltüntetni, vesszôvel elválasztva : int mx[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 // Egy

integer típusú, mx nevû mátrix, // 3 sorral és 3 oszloppal, a megfelelô // elemekkel inicializálva. }; 17. sz példaprogram : /* ======== Két double típusú mátrix összege ======= / #include <stdio.h> #include <conio.h> main() { double a[3][3], b[3][3], c[3][3]; int i, j; for(i=0; i<3; i++) // Beolvasás az a mátrixba { for(j=0; j<3; j++) { printf("A[%d][%d] = ",i,j) ; scanf("%lf",&a[i][j]) ; } } printf(" ------------------------------- "); for(i=0; i<3; i++) // Beolvasás a b mátrixba { for(j=0; j<3; j++) { printf("B[%d][%d] = ",i,j) ; scanf("%lf",&b[i][j]) ; } } printf(" ------------------------------- "); for(i=0; i<3; i++) // A c = a + b képzése { for(j=0; j<3; j++) c[i][j] = a[i][j] + b[i][j]; } for(i=0; i<3; i++) // A c mátrix kiiratása { for(j=0; j<3; j++) printf("%8.2lf%c", c[i][j],( ((j+1)%3 == 0) : ) ); } getch(); } Feladatok az 5.

fejezet anyagából 1.) Töltsünk fel egy 10 elemû integer vektort ! Ezután számítsuk ki a vektor elemek átlagát ! 2.) Határozzuk meg ugyanennek a vektornak a legnagyobb elemét ! 3.) Töltsünk fel két 10 elemû integer vektort ! Ezután határozzuk meg a két vektor összeg ill. különbség vektorát ! 4.) Számítsuk ki az elôbbi két vektor skalárszorzatát ! 5.) Egy 20 fôs csoport zárthelyi eredményeit kell kiértékelni A pontszámhatárok a következôk : 0 - 15 elégtelen 16 - 25 elégséges 26 - 35 közepes 36 - 45 jó 46 - 50 jeles Az egyes zh. pontszámokat egy vektorba kell beolvasni, ki kell iratni az egyes zh-k osztályzatát, és meg kell állapítani, hogy hány elégtelen, elégséges . volt a csoportban ! 6.) Töltsünk fel egy 5x5-ös integer mátrixot ! Ezután határozzuk meg mindegyik sorának legnagyobb ill. legkisebb elemét ! 7.) Töltsünk fel egy 5x5-ös double mátrixot ! ( Inicializálással is megoldható ! ) Ezután határozzuk meg sor

ill. oszlop összegeit Az összegeket megfelelô méretü és típusú tömbökben tároljuk és irassuk is ki ! 8.) Töltsünk fel két 5x5-ös double mátrixot ! ( Inicializálással is megoldható ! ) Ezután képezzük a. különbség mátrixot és irassuk ki ! 9.) Olvassunk be egy nxn - es mátrixot ! Készítsünk programot amely egy menü rendszerbôl történô választás alapján a következô értékeket számítja ki : 1. 2. 3. 4. 5. egy tetszôleges sor átlaga egy tetszôleges oszlop átlaga valamennyi sor átlaga valamennyi oszlop átlaga az összes elem átlaga 6.1 Karaktertömbök 6. Karaktertömbök és karaktermûveletek 6.1 Karaktertömbök A C nyelvben nincsenek hagyományos értelemben vett string (karakterlánc) típusú változók, mint például a BASIC-ban az A$. A C nyelvben a karakterláncok ábrázolása karaktertömbökkel történik úgy, hogy a tömbelemek a karakterlánc egy-egy karakterének felelnek meg és a karakterlánc végét a (

bináris nulla ) karakter jelzi. Ezért a tömb méretet mindig eggyel nagyobbra kell választani a karakterlánc tényleges hosszánál. Például, ha a "NOVEMBER" szót el akarjuk helyezni a c nevû karaktertömbben akkor a következôt kell tennünk : char c[9]; // A méretet [] zárójelek között adjuk meg. strcpy(c,"NOVEMBER"); Az STRCPY függvény az elsônek megadott változóba másolja a második paramétert amely lehet konstans vagy változó. Változó esetén a tömb nevét kell átadni, konstans esetén az " " jelek közé kell írni a szöveget ! A string végét jelzô ‘’ is átmásolódik. Az strcpy() használatához a <stringh>-t be kell include-olni ! Ezek után nézzük meg, hogy helyezkedik el a "NOVEMBER" a c tömbben. ASCII kódok -> 78 79 86 69 77 66 69 82 0 ( decimális értékek ) Karakter -> N O V E M B E R Tömb index -> 0 1 2 3 4 5 6 7 8 A C nyelvben minden tömb indexelése szigorúan 0-tól

kezdôdik ! A karakter vektor egyes elemeinek önállóan is lehet értéket adni : Például a : c[0] = D ; c[1] = E ; c[2] = C ; hatására a c értéke "DECEMBER" lesz. Mivel itt egy karakteres értékadás történik, ezért az aposztrófokat ( ) használjuk A karaktertömb neve nem más mint a karaktertömb kezdôcíme, azaz a 0-dik elemre mutató cím. Jelen esetben tehát a DECEMBER szó D betûjére mutató cím. ( Lásd késôbb bôvebben ! ) Fontos stringkezelô függvény még az strcat() , amely két string összefûzését végzi olymódon, hogy az elsônek megadott stringhez hozzáfûzi a másodikat. 1 6.2 Karakter mûveletek Példa : . strcpy(c1,"BORLAND") ; strcpy(c2," C++") ; strcat(c1,c2) ; . hatására a c1-ben a "BORLAND C++" szöveg található. c1 méretének elegendôen nagynak kell lennie ahhoz, hogy c2-t befogadja, különben a memória - nem c1-hez tartozó része - felülíródik ! c1 lezárása a -val

történik és a <string.h> használata itt is kötelezô ! Kétdimenziós karaktertömbök deklarálása a következôképpen történik : char cmx[5][10] ; Ezalatt egy olyan karaktertömböt ( mátrixot ) kell érteni, amelynek 5 sora van, ( indexelés : 0 . 4 ), és soronként max 9 értékes karaktert tartalmaz. (Gondoljunk a karakterlánc végét jelzô - ra ! ) 6.2 Karakter mûveletek Egy karakter beolvasása puffereléssel : int getchar() A getchar() függvény a leütött karaktert nem olvassa be mindjárt a megadott változóba, hanem egy átmeneti tároló területen ( billentyûzet puffer ) tárolja. A karakter beolvasás addig tart, ameddig a puffer be nem telik ( kb. másfél képernyô sor ), vagy ameddig az <ENTER> billentyût le nem nyomjuk. A getchar mûködését a <CTRL> <Z> billentyûkkel tudjuk megszakítani. Ilyenkor a getchar() az EOF-ot (End Of File) adja vissza, aminek az értéke -1. Ez a magyarázata annak , hogy a getchar() miért

int-et ad vissza és miért nem char-t. Egy karakter kiírása pufferbôl : int putchar( int ) A putchar() a getchar()-ral ellentétes mûveletet végez, a pufferbôl ír ki egy karaktert a képernyôre. Ha a puffer kiürült akkor az EOF-ot adja vissza. 2 6.2 Karakter mûveletek 18. sz példaprogram : /* Példa a getchar() ill. putchar() függvények mûködésére */ #include <stdio.h> void main() { int c; c = getchar(); while( c != EOF ) { putchar(c) ; printf("*"); c = getchar(); } } /*/ // // Az elsô getchar() hívás a klaviatúra pufferbe ír. Addig // olvas a klaviatúráról amíg <ENTER>-t nem nyomunk. Ennek // hatására a puffer elsô pozícióján lévô karakter c-be ke// rül, majd EOF vizsgálat következik. Ha c értéke nem EOF // akkor belépünk a while ciklusba. A karakter kiíródik a // display-ra, és az utána következô getchar() beolvassa a // puffer második pozícióján lévô karaktert c-be. Ezután me// gint vizsgálat és

egy karakter kiiratása következik A // program CTRL+Z hatására fejezi be mûködését ! // /*/ Egy karakter beolvasása közvetlenül : int getch(), int getche() Mindkét függvény közvetlenül a baloldalon álló változóba olvassa be a leütött karaktert, az átmeneti tárolás mellôzésével. A különbség az, hogy a getch() alkalmazásánál a leütött karakter nem jelenik meg a képernyôn, a getche()-nél viszont megjelenik. Az EOF vizsgálat egyik függvény esetén 3 6.2 Karakter mûveletek sem oldható meg, mivel a <CTRL> <Z> -re nem adják vissza az EOF kódot. Használatukhoz a <conio.h> include-olása szükséges Mûködésüket a következô példaprogram mutatja be egyszerû változók esetén: 19. sz példaprogram : /* Karakterolvasó mûveletek egyszerû változók esetén. */ #include <stdio.h> #include <conio.h> void main() { int c, gc, gce; // A getchar() a klaviatúra pufferbe olvas ; // <ENTER>-re áll le !

printf(" Ez egy GETCHAR() hívás : ") ; c = getchar(); printf(" C = %d C = %c ", c, c); // A getch() közvetlenül a klaviatúráról olvas // echózás nélkül! printf(" Ez egy GETCH() hívás : ") ; gc = getch(); printf(" GC = %d GC = %c ",gc,gc); // A getche() közvetlenül a klaviaturáról olvas // echózással ! printf(" Ez egy GETCHE() hívás : ") ; gce=getche(); printf(" GCE = %d GCE = %c ",gce,gce); } Egy karakterlánc beolvasása puffereléssel : int scanf() 4 6.2 Karakter mûveletek A scanf() használatával több karaktert tudunk beolvasni pld. egy karaktertömbbe. Ehhez a "%s" formátumvezérlô karaktert kell használnunk, és változóként a karaktertömb nevét kell megadnunk. A beolvasás az <ENTER> vagy a szóköz megnyomásáig tart. 20. sz példaprogram : /* === Karakterolvasó mûveletek tömbök esetén. === */ #include <stdio.h> #include <conio.h> void main()

{ char c[11], gc[11], gce[11], sc[11]; int igce[11], i; c[10]=; gc[10]=; gce[10]=; sc[10]=; igce[10]= ; // Elôször a pufferba olvas utána az elsô // 10 karaktert a tömbbe ! printf(" Ez egy GETCHAR() hívás : "); for(i=0; i<10 ; i++) c[i] = getchar() ; printf(" C = %s ",c); // Közvetlenül a tömbbe olvas, i=10 - re leáll; a // karakter nem látszik ! printf(" Ez egy GETCH()hívás : ") ; for(i=0; i<10; i++) gc[i] = getch() ; printf(" GC = %s ",gc); // Közvetlenül a tömbbe olvas, i=10 - re leáll; a // karakter látszik ! printf(" Ez egy GETCHE() hívás : ") ; for(i=0; i<10; i++) gce[i] = getche() ; printf(" GCE = %s ",gce); // Közvetlenül az (int) tömbbe olvas, i=10-re // leáll ; a karakter látszik ! printf(" Ez egy GETCHE() hívás integer tömbre : "); for(i=0; i<10; i++) igce[i] = getche() ; 5 6.3 Stringkonverziós mûveletek : int sprintf(), int sscanf() printf(" IGCE

= "); for(i=0; i<10; i++) printf("%c",igce[i]); printf(" "); // // // // Pufferbôl olvas <ENTER>-ig ! Ha a program elején a getchar() hívásakor több mint 10 karaktert ütöttünk be, akkor a maradékot a scanf() automatikusan beolvassa ! printf(" Ez egy SCANF() hívás : ") ; scanf("%s",sc) ; printf(" SC = %s ",sc); } Megjegyzés : Amennyiben mindenképpen a scanf() függvénnyel akarunk egy karaktert beolvasni, úgy a karakter beolvasása után ki kell "söpörni" a klaviatúra buffert az fflush() függvény segítségével : printf(" Kérek egy karaktert : ") ; scanf("%c",&a) ; fflush(stdin) ; printf(" Kérek egy karaktert : ") ; scanf("%c",&b) ; fflush(stdin) ; Az fflush() függvény argumentumában szereplô stdin a standard input ( azaz a klaviatúra buffer ) rövidítése. 6.3 Stringkonverziós mûveletek : int sprintf(), int sscanf() Numerikus

értékek stringgé alakítása : int sprintf() A sprintf() függvény általános alakja : sprintf(puffer,formátum,változólista); A változólistában megadott numerikus értékeket, a formátum szerint a pufferben tárolja stringként. Példa: Numerikus alakban megadott dátum átalakítása stringgé. char datum[11]; int ev,ho,nap; 6 6.3 Stringkonverziós mûveletek : int sprintf(), int sscanf() // Bekérjük a dátumot integer változókba : scanf("%d",&ev) ; scanf("%d",&ho) ; scanf("%d",&nap) ; // Átalakítjuk stringgé. sprintf(datum, "%4d.%2d%2d", ev, ho, nap); // A dátum a datum nevû karaktertömbben tárolódik ÉÉÉÉ.HHNN // alakban. Kiiratjuk a dátumot : printf("Dátum : %s", datum); String numerikus értékekké alakítása : int sscanf() A sscanf() függvény általános alakja: sscanf(puffer,formátum,változócím lista); A pufferben tárolt stringet numerikus értékekké alakítja. A

változó cím listában a scanf() függvénnyel megegyezô módon a változók címeit kell átadni ( & operátor ! ). Az okát lásd késôbb ! Példa : String alakban megadott dátum átalakítása numerikussá. char datum[11],pont1,pont2; int ev,ho,nap; strcpy(datum,"1994.1212"); // Átakítjuk numerikus értékekké : sscanf(datum,"%d %c %d %c %d",&ev,&pont1,&ho,&pont2,&nap); // Kiiratjuk az értékeket. printf(" Év : %4d Hó : %2d Nap : %2d",ev,ho,nap); 21. sz példaprogram : /*Példa az sprintf() ill. sscanf() függvények használatára*/ #include <stdio.h> void main() { char dbuf1[11], dbuf2[11], point1, point2; int ev, ho, nap, year, month, day; // Az sprintf használata : printf(" Kérem az évet : ") ; scanf("%d",&ev) ; printf(" Kérem a hónapot : ") ; scanf("%d",&ho) ; printf(" Kérem a napot : ") ; scanf("%d",&nap);

sprintf(dbuf1,"%4d.%2d%2d",ev,ho,nap); printf(" Dátum sprintf = %s",dbuf1); // Az sscanf használata : printf(" Kérem a dátumot ÉÉÉÉ.HHNN alakban : ") ; 7 Feladatok a 6. fejezet anyagából scanf("%s",dbuf2) ; if ( sscanf(dbuf2,"%d %c %d %c %d", &year,&point1,&month,&point2,&day)!= 5 ) printf(" Rossz dátum !); else printf(" Év : %4d Hó : %2d Nap : %2d", year,month,day); } Feladatok a 6. fejezet anyagából 1.) Olvassunk be két karaktert és irassuk ki ôket abc sorrendben ! 2.) Olvassunk be egy karaktert és állapítsuk meg, hogy nagybetû, kisbetû, szám vagy egyéb karakter. 3.) Olvassunk be egy karaktert és döntsük el, hogy a [ A, L ] intervallumba esik-e ! 4.) Olvassunk be egy maximum 70 karakter hosszú szöveget, amely csak számjegyeket tartalmaz Számoljuk meg, hogy hány 0, 1 , , 9 - es karaktert tartalmaz a szöveg. 5.) Olvassunk be egy maximum 70 karakter hosszú

mondatot Számoljuk meg, hogy hány szóból áll a mondat. A szavakat a szóköz ( ) karakter választja el egymástól A mondat végén a pont ( ) karakter áll 6.) Olvassunk be egy maximum 20 karakterbôl álló sorozatot, majd irjuk ki fordítva ! Irassuk ki a karaktersorozat hosszát is ! 7.) Készítsünk programot, amely feltölt vezetéknevekkel egy 5x10-es karakteres mátrixot, illetve keresztnevekkel egy 3x10-es karakteres mátrixot. Ezután írja ki a képernyôre, az összes lehetséges teljes név változatot ! 8.) Készítsünk programot, amely beolvas - egy karakter típusú vektorba - egy dátumot ÉÉÉÉHHNN alakban A beolvasott dátummal kapcsolatban a következô elvárásaink vannak : - Az évszámot és a hónapot a pont ( . ) karakternek kell követnie - Az évszám nem lehet kisebb mint 1990, és nem lehet nagyobb mint 2000. - A hónap nem lehet nagyobb mint 12. - A nap nem lehet nagyobb mint 31. - Az 1995.0000 alak elfogadott 8 Feladatok a 6.

fejezet anyagából A program ellenôrizze le, hogy a beolvasott dátum megfelel-e az elvárásainknak ! Amennyiben nem, úgy küldjön egyértelmü hibaüzenetet a képernyôre, és kérje be újra a dátumot. 9.) Adott egy szöveg 79 hosszú karakterláncok tömbjeként Átnézve a szöveget, ahol a pont, kérdôjel vagy felkiáltójel karakterek valamelyike szerepel, ott a közvetlenül utána következô - szóköztôl eltérô - karaktert alakítsuk nagybetûvé ! ( Figyeljünk arra, ha egy mondat éppen egy sor végén ér véget, akkor a következô sor elején kell nagybetûvé alakítani ! ) 9 7. Függvények - I rész 7.1 A függvények általános jellemzôi A függvények hasonló célt szolgálnak a C-ben, mint más nyelvekben a "szubrutin" ill. a "procedura" Olyan önállóan elkészített alprogramokat nevezünk függvényeknek, melyek forrás szövegei nem részei a fô (hívó) programnak, innen hívhatjuk meg azokat. Olyan

tevékenységsorozatot célszerû függvény formájában megvalósítani, amely egyrészt önállóan kezelhetô ( kiemelhetô ), másrészt ismétlôdô, azaz a program futása során többször szükséges a hívása. Ajánlott, hogy egy függvény egy mûveletet valósítson meg, de azt jól ! A függvénynek öt jellemzôje van : Típus, Név, Paraméter(lista), Paraméterdeklaráció, Blokk ( függvénytest ) Típus : Valamely függvény típusa megegyezik annak a változónak a típusával, amellyel a függvény visszatér az ôt meghívó programba. Annak a függvénynek - amely nem ad vissza értéket - a típusa void. Ha nem deklaráljuk a függvényt és a megvalósításánál nem tüntetjük fel a típusát, akkor a C alapértelmezés szerint integer-nek veszi a típust. Név : A függvény nevének megválasztásánál az egyszerû változó nevével kapcsolatos szabályok érvényesek. Paraméterlista : A függvény bemenô paramétereinek listájáról van szó, ha

egyáltalán létezik ilyen. Fontos a változók hozzáférésének szabályozása miatt ! Paraméter deklaráció : A bemenô paraméterek típusait adja meg. Az automatikus típuskonverzió szabályai itt is érvényesek ! 38 7. Függvények - I rész Blokk : "{" és "}" közé zárva a függvény megvalósítása. ( Forrásprogram ) 22 sz. példaprogram : // n! meghatározása függvény alkalmazásával. #include <stdio.h> #include <conio.h> void main() { // Az n fact függvény prototípusa long n fact( int ); long ennyi; int n; printf(" Hányadik faktoriálist számoljuk scanf("%d",&n); : "); // Függvényhívás és a visszatérô érték átadása az // ennyi nevû változóba. ennyi = n fact( n ) ; printf(" N! értéke = %ld", ennyi ); getch(); } * ==== Az n fact függvény megvalósítása ===== / long n fact( int nf ) { int i; long fact; fact = 1L ; for(i=1 ; i <= nf ; i++) fact *= i ; // A

faktoriális értékével tér vissza a függvény return( fact ); } Megjegyzések az n fact függvénnyel kapcsolatban : Az n fact függvénnyel kapcsolatban négy teendô van : 1. A függvény megtervezése 2. Elôállítása ( programozás ) 7.2 Változók érvényeségi köre 3. Deklarálás ( prototípus elôállítása ) 4. Hívás A függvény elôállításánál a "{" elôtt meg kell adni a függvény típusát, nevét, paramétereinek típusát és azok nevét. Ezek a paraméterek az ún formális paraméterek. A deklarálásnál a függvény típusát, nevét és paramétereinek típusát kell megadni. Ezt hívjuk a függvény prototípusának Ilymódon a fordító hibaüzenetet küld akkor, ha a függvényt nem megfelelô számú ill típusú paraméterrel hívjuk meg. A bemenõ paraméter nélküli függvény használatát kerülni kell ! A hívásnál a függvény neve után zárójelben kell megadni azokat a változóneveket amelyekkel éppen akkor el

akarjuk végezni a függvény által megvalósított mûveleteket. Ezeket a paramétereket ezért hívjuk aktuális paramétereknek A függvény visszatérési értékét a return utasítással adhatjuk át a hívó programnak. A return után csak egyetlen kifejezés szerepelhet a "(" ill. ")" között, és típusa meg kell egyezzen a függvény típusával. 7.2 Változók érvényeségi köre A függvények alkalmazása felveti azt a kérdést, hogy egy adott változó milyen érvényességi körrel rendelkezik (láthatóság). Ebbôl a szempontból kétféle típussal foglakozunk egyelôre : a külsô (globális) ill. a belsô (lokális) változóval A külsô változókat a függvényeken kívül definiáljuk, legegyszerûbb esetben a main() elôtt. Ennek az a következménye, hogy ezek a változók a program futása alatt fennmaradnak és az adott forrásprogram egészére nézve "láthatóak". 23. sz példaprogram : #include <stdio.h> int x; //

Globális változó void f(); // f() definíciója void main() { x=2 ; f() ; printf(" X = %d",x); // Az x értéke 3 lesz ! } void f() { x = 3 ; } A belsô változókat egy adott függvényen belül definiáljuk. Ennek az a következménye, hogy ezek a változók a függvény hívásakor keletkeznek és annak befejezôdésekor megszûnnek. Ezért kapták az "automatikus változó" nevet Ezek 7. Függvények - I rész a változók csak az adott függvényen belül "láthatóak". 7.3 Paraméterátadás kérdése A C-ben függvény híváskor a formális paramétereknek hely foglalódik a memóriában ( stack ), és ide másolódik az aktuális paraméterek értéke. Ezért is fontos, hogy megfelelô számú és típusú paraméterrel hívjuk a függvényt ! Ezen formális paraméter értékeken végrehajtódik a kívánt mûvelet.A C-ben a paraméterátadás tehát érték szerinti. A függvény végén a formális paraméterek ( a belsô

változókhoz hasonlóan ) megszûnnek létezni, és a rajtuk végzett változtatások elvesznek ! Arra az esetre, amikor egy hivó programbeli változó értékét a hívott programban akarjuk megváltoztatni, a pointerek tárgyalása után térünk vissza. Feladatok a 7. fejezet anyagából 1.) Irjunk egy olyan függvényt amely eldönti egy évszámról, hogy az adott év szökôév vagy sem. Az évszámot a main()-ban olvassuk be, ezután mint bemenô paraméterrel hívjuk meg a függvényt A függvény nullát adjon vissza, ha nem szökôév ill. egyet ha szökôév volt az adott év ( Egy év szökôév, ha az évszám osztható néggyel és nem osztható négyszázzal ) 2.) Irjunk olyan függvényt amely eldönti három double típusú számról, hogy szerkeszthetô-e belôlük háromszög ! A függvény egyet adjon vissza, ha szerkeszthetô, nullát ha nem ! 3.) Irjunk egy függvényt amely egy long típusú szám abszolút értékével tér vissza ! ( A függvény a ?

operátor alkalmazásával egy sorban megírható ! ) 4.) Irjunk olyan programot, amely megállapítja, hogy milyen egy kör és egy pont kölcsönös helyzete ! ( A pont a körön belül van, rajta van a körön ill. a körön kivül van. ) Minden érték double típusú ! Az adatok beolvasását a main()-ban oldjuk meg, a kölcsönös helyzet megállapítását pedig egy függvény segítségével ! Oldjuk meg a feladatot úgy is, hogy - a felhasználó döntése alapján egymásután több pont-kör helyzetet is meg lehessen vizsgálni ! 5.) Irjuk meg az úgynevezett elôjel függvényt ! (Az elôjel függvény -1-et ad vissza, ha a bemenô paramétere negatív szám, 0-át ha nulla és 1-et ha pozítív szám ! ) 6.) Irjunk egy "kódoló" függvényt A kódok négyjegyû pozítív számok A kódolás mindaddig tart ameddig nullát nem billentyûzünk. A negatív szám hibás adatnak minôsül, és új számot kell helyette kérni Ezeket a vizsgálatokat is függ-

Feladatok a 7. fejezet anyagából vény(ek)-kel valósítsuk meg ! A kódoló függvény bemenô paramétere tehát egy négyjegyû, pozitív szám, kimenete pedig a szám - megfordítva (1234->4321) ! A kódokat a képernyôn kell megjeleníteni ! 7.) Irjuk meg a 6) feladatban szereplô kódokat "dekódoló" függvényt ! 8. Mutatók ( Pointerek ) - I rész 8.1 Általános rész Általában mutatónak ( a továbbiakban pointer ) nevezzük az olyan változót amely valamely objektum címét tartalmazza. C - ben ez az objektum lehet egy egyszerû változó, tömb, struktúra és függvény is. A pointer definíciója a típusmegadással kezdôdik. Itt nem a pointer típusáról van szó hanem annak az objetumnak a típusáról, amelyre a pointer mutat A pointer neve elôtti "*" jelzi, hogy nem egyszerû változóról van szó, hanem pointerrôl. Ezután következik a pointer neve Maga a pointer általában 4 byte hosszú. Ebbôl 2 byte a szegmenscím, 2

byte pedig az offset. Ezalól egyetlen kivétel van : a near ( közeli ) pointer amely csak 2 byte hosszú ! Példa : int *px ; // px nevû, integer típusú változóra mutató pointer. 8.2 Változó címének átadása az & operátor segítségével Hogyan adhatjuk át egy változó címét egy pointer változónak ? Példa : Tekintsük a következô definíciókat : int x, *px; px = &x ; // Az & a cím operátor ! Ezen utasítás hatására a px nevû pointer felveszi az x változó címét. Azaz, ha az x változó az 1000 memória címen kezdôdik, akkor a px értéke 1000 lesz. A változó típusának ill. a pointer típusának meg kell egyeznie, vagy típuskonverziót kell alkalmaznunk. ( Lásd : 25 sz példaprogram ! ) 8.3 Indirekció Indirekciónak nevezzük azt az eljárást, melynek során egy változó értékét nem a változó nevének segítségével érjük el, hanem a változóra mutató pointer segítségével. Az indirekció operátora a "*"

( csillag ). Példa : Tekintsük a következô programrészletet : int x, *px; x = 2; px = &x ; // px felveszi x címét. Ezek után a px által mutatott cím // tartalmát így iratjuk ki : printf(" PX által mutatott cím tartalma = %d", *px) ; // A képernyôn 2 jelenik meg, az = jel után ! Vigyázat : A "*" használata kettôs jelentésü. A definíciónál azt jelenti hogy a definiált változó pointer lesz. A program során valamely mûveletnél, pedig tartalomra való hivatkozást jelent ( Indirekció ! ). Összefoglaló példa az eddigiekre : 24. sz példaprogram : #include <stdio.h> void main() { int x,y, *px; x // X értéke 2 lesz = 2; // PX felveszi X címét px = &x; y // Y felveszi a PX által mutatott címen lévô // értéket. Mivel a PX az X-re mutat, X érté// ke pedig 2,ezért az Y értéke is 2 lesz ! = *px; // Kiiratjuk X,Y értékét a PX által mutatott // cím értékét, ill. annak tartalmát ! printf("

X=%d Y=%d PX=%p *PX=%d",x,y,px,px); // Látható hogy PX hossza 4 byte ! } Megjegyzés : Természetesen a gyakorlatban ritkán valósul meg az x=y értékadás ebben a formában. Az indirekció szemléltetésére azonban kiválóan alkalmas ! További példa a pointerek alkalmazására : Bár a pointerek használatának fontossága a függvények, tömbök ill. struktúrák további tárgyalásánál lesz nyilvánvaló, azért egyszerû változók esetén is szükség lehet az alkalmazásukra. Gyakorlatban elôfordult az a probléma, hogy egy 4 byte-os integer ( C-ben long ) alsó és felsô 2 byte-ját meg kellett cserélni, mert az adott számítógépen másként ábrázolta a FORTRAN fordító, és másként a C fordító. Ezért, ha egy C program által készített adatállományt a késôbbiekben FORTRAN programból akartunk használni akkor a 4 byte-os integereket meg kellett "fordítani" : 25. sz példaprogram : // Egy long integer alsó és #include

<stdio.h> void main() { long x; int segit , *y; felsô 2 byte-jának felcserélése printf(" X erteke : ") ; scanf("%ld",&x); // Az Y az X címét veszi fel ugyan, de a cím // típusa az (int *) típusmódosítás miatt nem 4 // byte-ra mutató cím lesz, hanem 2 byte-ra // mutató cím. y = (int *) &x ; // Végeredményben az Y az X "alsó" 2 byte-jára // mutat. *Y nem más mint ennek a 2 byte-nak az // értéke. printf("Y tartalma = %d ",*y); // Az Y+1 az X "felsô" 2 byte-jára mutat. *(Y+1) // nem más mint ennek a 2 byte-nak az értéke. printf("Y+1 tartalma = %d ",*(y+1)); // Most kezdôdik a csere : A SEGIT felveszi X alsó // két byte-jának értékét; segit = *y ; // Az X alsó két byte-ja felveszi a felsô 2 byte // értékét *y = *(y+1) ; // Az X felsô 2 byte-ja felveszi SEGIT értékét, // azaz az alsó 2 byet értékét. *(y+1) = segit ; // ---- A csere befejezôdött

printf("X értéke forditva = %ld ",x); } A programot lefuttatva, ha X-nek 1-et adunk meg, akkor a csere utáni értéke 65536 lesz amely megfelel elôzetes várakozásainknak ! Megjegyzés : A *(y+1) mûvelet elôször 1 integer-nyit azaz 2 byte-ot ad az y címhez, mivel y egy integer típusú változóra mutató pointer. (Lásd késôbb: Címaritmetika). Ha y float típusú lenne akkor az 1gyel való növelés 4 byte hozzáadását jelentené stb Ezután történik az új cím tartalmára való hivatkozás a "*" operátorral ! Létezik egy speciális eset a pointer értékére vonatkozóan : amikor a pointer a 0 (nulla) értéket tartalmazza. Ekkor beszélünk NULL pointerrôl, aminek a konkrét jelentése az, hogy maga a pointer nem mutat érvényes adatra. A fordító gondoskodik arról, hogy a <stdioh>-ban definiált NULL szimbólumhoz tartozó 0 (nulla) érték, ne a nullás memóriahelyet jelentse, nehogy a pointer erre a helyre mutasson. Ez a

konstrukció kiválóan alkalmas hibakezelésre, mint azt a file kezelésnél (15. fejezet), látni fogjuk ! A másik speciális eset egy pointer típusra vonatkozik, aminek a neve void. A void a pointer deklarálásnál azt jelenti, hogy - egyelôre - nincs meghatározott típusa. A void-nak deklarált pointer típusát akkor kell megadni, amikor a pointerrel valamilyen mûveletet végzünk. Példa : Tekintsük a következô utasításokat : ( Hasonló a Borland C++ 2.0 helpjében szereplô példához ! ) int i ; float f ; void *vp ; // A vp pointernek egyelôre nem ismerjük a típusát , // azaz nem tudjuk, hogy milyen típusú változóra mutat vp = &i ; // vp felveszi az i változó címét. * ( int ) vp = 5 ; // vp tartalma 5 lesz, az ( int ) típusmódosítás, az // egyértelmû méret meghatározás miatt szükséges ! vp = &f ; // vp az f változó címét veszi fel. * ( float ) vp = 4.8; // itt is szükséges a ( float * ) típusmódosítás ! Feladatok a 8.

fejezet anyagából 1.) Irjunk programot amely beolvas két karaktert Az elsônek beolvasott karaktert egy integer változó alsó byte-jában helyezi el , a másodiknak beolvasott karaktert, ugyanannak az integer változónak a felsô byte-jában helyezi el ! 2.) Irjunk olyan programot, amely egy integert olvas be, és az alsó byte-ját egy karakteres típusú változóban helyezi el, a felsô byte-ját pedig egy másik karakteres típusú változóban helyezi el. 3.) Irjunk programot, amely felcseréli két integer típusú változó értékét, de gyakorlásképpen ne segédváltozót használjunk, hanem egy integer típusú pointert ! 4.) Irjunk programot, amely egy integer alsó és felsô byte-ját felcseréli ! 5.) Irjunk programot, amely sorba rendezi három double típusú változó értékét ! Segédváltozónak double típusú pointert használjunk ! 6.) Egy szöveget akarunk titkosítani olymódon, hogy rendre minden négy karaktert egy long típusú változóba

helyezünk el. Az eredeti szövegbôl tehát a végén long típusú számok sorozata áll elô. Irjuk meg ennek a programnak azt az egyszerûsített változatát, amikor egy öt elemû karaktertömbben elhelyezkedô szöveget ( legyen például négy darab A betû ) rendre elhelyezünk egy long típusú változó 0., 1, 2, 3 byte-jában Irassuk ki a képernyôre külön-külön a long változó bytejait - karakteresen, valamint a teljes long változó értékét is ! 7.) Irjuk meg azt a programot, amely az 6) feladatban keletkezett long típusú változót dekódolja, azaz a változó tartalma alapján visszaállítja az eredeti karakteres üzenetet. Az eredményt irassuk ki a képernyôre, és hasonlítsuk össze a 6) feladat kiinduló szövegével ! 8.) Gyakorlatban elôforduló probléma, amikor egy float típusú változó négy byteját kell helyezni egy karakteres típusú "puffer"-ben Irjunk programot, amely beolvas egy float típusú változóba egy értéket, majd a

szükséges méretû karakter tömbben elhelyezi annak byte-jait ! Erre a mûveletre használjuk a memcpy() függvényt, amelynek a szintaktikája a következô : void *memcpy( void dest, const void src, size t n ) ; A memcpy() függvény az src pointer által mutatott helyrôl, n byte-ot másol a dest pointer által mutatott helyre. Használatához a stringh header file szükséges ! Példa : memcpy( &puffer[0], &byte 1, 1 ) ; ahol puffer[] és byte 1 karakteres típusúak ! 9.1 Tárolási osztályok 9. Függvények - II rész Amint a 7.2 - ben látható, a C-ben a függvények formális paraméterei érték szerinti paraméter átadással kapják meg értékeiket Ez azt jelenti, hogy a hívó program aktuális paramétereinek értékei bemásolódnak a hívott függvény megfelelô formális paramétereibe, és a függvény ezen értékekkel végrehajtja a kívánt mûvelet(ek)et. Ez a tény nagy problémát jelent akkor, ha a hívott függvényben meg szeretnénk

változtatni a hívó függvény bizonyos változóinak értékét. Egy változó esetén még megoldás lehetne a megváltoztatott érték return-nal történô visszaadása, de több változó esetén ez sem jelent megoldást. Egy másik megoldás lehet erre az esetre a globális változók alkalmazása, mivel ezek a változók az egész forrásprogramban láthatók. A globális változók nagyszámú alkalmazása azonban egy idô után zavarossá teszi a programot és számos súlyos hiba forrásává válik ! A probléma megnyugtató megoldását a pointerek használata teszi lehetôvé ! Példa : Tételezzük fel, hogy meg akarunk cserélni két integert. Az elsô esetben érték szerinti átadást alkalmazunk, a második esetben cím szerintit. ( Pointerek alkalmazása. ) 26. sz példaprogram ( elsô eset ) : // Két integer cseréje érték szerinti átadással #include <stdio.h> void main() { // A cserélô függvény prototípusa void csere 1( int,int ); int x, y;

printf(" Kérem az elsô integert : ") ; scanf("%d",&x); printf(" Kérem a második integert : ") ; scanf("%d",&y); // Érték szerinti hívás ! csere 1( x, y ); //Nincs felcserélve ! printf(" Felcserélve : %d < - > %d ",x,y); } void csere 1( int cs1 x, int cs1 y ) { int s; s = cs1 x ; cs1 x = cs1 y ; cs1 y = s ; } 1 9.1 Tárolási osztályok Tételezzük fel, hogy X értékének 1-et Y-nak 2-t adunk meg. Ezek után meghívjuk a csere 1 függvényt ezekkel az értékekkel. Ennek hatására a CS1 X formális paraméter felveszi az X aktuális paraméter értékét azaz 1-et. A CS1 Y formális paraméter értéke nyilvánvalóan 2 lesz. Az értékek átmásolása után már nincs tényleges kapcsolat a formális és aktuális paraméterek között ! Maga a függvény valóban megcseréli CS1 X és CS1 Y értékét, de mivel ezek automatikus változók, ezért a függvény végén megszûnnek létezni. Igy a

fôprogramban X és Y értéke mit sem változik ! 27. sz példaprogram ( második eset ) : // Két integer cseréje cím szerinti átadással #include <stdio.h> void main() { //A cserélô függvény prototípusa void csere 2(int *,int ); int x, y; printf(" Kérem az elsô integert : "); scanf("%d",&x); printf(" Kérem a második integert : ") ; scanf("%d",&y); // Cím szerinti hívás ! csere 2( &x, &y ); // Felcserélôdtek ! printf(" Felcserélve : %d < - > %d ",x,y) ; } void csere 2( int *cs2 x, int cs2 y ) { int s; s = *cs2 x ; cs2 x = cs2 y ; cs2 y = s ; } Legyenek a bemenô adatok most is X=1 ill. Y=2 ! A függvény hívásakor viszont az X és Y címét adjuk át a csere 2 függvénynek. Éppen ezért CS2 X pointer értéke az X címe lesz, CS2 Y-é pedig az Y címe. Emiatt a függvényben az S változóba az az érték kerül, amelyre a CS2 X pointer mutat, vagyis pont a fôprogrambeli X változó

értéke. Ugyanilyen okok miatt *CS2 Y az Y változó 2 9.1 Tárolási osztályok értékét jelenti. Itt is igaz az, hogy CS2 X és CS2 Y megszûnnek a függvény végén, de addigra az általuk mutatott címeken lévô értékek már felcserélôdtek ! Megjegyzés : Most kaptunk magyarázatot arra, hogy miért kell a scanf() függvény változó listájában az egyszerû változók neve elôtt az "&" jelet használnunk. Mivel a scanf() módosítani akarja a változó addigi értékét ezért a változó címét kell átadnunk ! 9.1 Tárolási osztályok A C nyelv különféle tárolási osztályokat ismer a változókra nézve. Függvények, illetve program modulok használata esetén messzemenôen nem közömbös, hogy milyen tárolási osztályokat alkalmazunk ! Automatikus Valamely függvényen belül definiált változó. Csak az illetô függvényen belül látható. A függvény mûködésének kezdetén keletkezik (a stack szegmens-ben) és a függvény

befejeztével megszûnik létezni. Hatásköre és élettartama is a függvényre korlátozódik ! Extern A függvényeken de akár az egész forrásprogramon kívül definiált változó. Az egész forrásprogramban vagy akár több forrásprogramban is látható. Csak a program végén szûnik meg létezni. Az adatszegmensben (memória) foglal helyet Hogyan használhatjuk pld. az i integer változót akkor, ha van egy "fô" programunk ( FO.C ) és egy "al" programunk ( ALC ) ? A két programot külön akarjuk fordítani, és utána linkelni. Az i-t mind a két programban "látni" akarjuk. 1. lépés : Létrehozunk egy SAJATTYP állományt, amely többek között a következôt tartalmazza : extern int i; // Nem definíció, csak deklaráció ! A deklaráció // ugyanis csak a változó típusát és nevét adja meg, // de - a definícióval ellentétben - nem foglal helyet // a változó számára a memóriában ! Arra utal, // hogy az i nem az illetô

forrásprogramban van // definiálva, hanem máshol ! 2. lépés : Létrehozunk egy SAJATH állományt, amely többek között a következôt tartalmazza : 3 9.1 Tárolási osztályok int i; // Itt a definíció ! 3. lépés : Ezek után a FOC programban : #include "sajat.typ" // Feltételezzük, hogy a két állomány abban #include "sajat.h" // a directory-ban van, ahol éppen dolgozunk 4. lépés : Ezek után az ALC programban : #include "sajat.typ" // A sajat.h-t itt már nem kell include- olni ! Ilymódon az i változó mindegyik programban látható ! Az itt ismertetett eljárás akkor is igaz, ha a programunkat több forrásállományból szerkesztjük össze. Statikus (static) A static változók lehetnek automatikus (belsô) ill. extern változók Automatikus változóként ugyanúgy lokálisak arra a függvényre nézve, ahol deklaráljuk, viszont - az automatikustól eltérôen - a memóriaterületük megmarad, azaz nem keletkeznek

újra és nem szûnnek meg létezni a függvény minden egyes aktivizálásakor ! Ez azt jelenti, hogy a static változók a függvényen belül saját, állandó tárat képeznek ! Ilymódon csak a függvényen belül láthatók, de értéküket megtartják két függvényhívás között is. A külsô static változó annak a forrásállománynak a további részében lesz ismert, ahol deklaráljuk, de egyetlen más forrásállományban sem lesz látható ! Amennyiben egy függvényt egy adott forrásállományban staticnak deklarálunk, akkor a neve minden más forrásállományban ismeretlen lesz ! Maga a deklaráció úgy történik, hogy a változó vagy függvény közönséges deklarációja elé a static szót írjuk : static int i; A static használata tehát az állandóság és az elzártság megvalósítására ad lehetôséget ! Regiszter Az az egész típusú változó, amelyre ez a deklaráció vonatkozik az adott gép valamely hardware regiszterében kerül

tárolásra, amennyiben ilyen rendelkezésre áll. A változó típusa függ az adott hardwaretôl, általában char, int vagy pointer lehet. 4 Feladatok a 9. fejezet anyagából A programfutás gyorsítására szolgál, gyakran használt változó esetén célszerû alkalmazni. A deklaráció úgy történik, hogy a változó deklaráció ja elé a register szót kell írni : register int y; Feladatok a 9. fejezet anyagából 1.) Irjunk függvényt a 81) feladat megoldására ! A függvény elsô két paramétere a két karakter legyen, a harmadik pedig annak az integer változónak a címe, amelyen a két karaktert el akarjuk helyezni ! 2.) Irjunk függvényt a 84) feladat megoldására ! 3.) Irjunk függvényt a 85) feladat megoldására ! 4.) Az eddig tanultak alapján gondoljuk át, hogy mi történne akkor, ha a scanf() függvény használatakor nem a változók címeit adnánk át, hanem csak a változók neveit ? 5.) Irjunk függvényt, amely meghatározza a Húsvét

vasárnap pontos dátumát A dátum március 22 és április 25 között változhat. A niceai zsinat az ünnep pontos dátumát a következôképpen határozta meg : A tavaszi napéjegyenlôséget követô elsô holdtölte utáni elsô vasárnap. Ha T az évszámot jelöli, akkor a következô algoritmust használhatjuk : A = T / 19 maradéka, B = T / 4 maradéka, C = T / 7 maradéka , D = ( 19*A + 24 ) / 30 maradéka , E = ( 2B + 4C + 6D + 5 ) / 7 maradéka. Ezekbôl a Húsvét vasárnap dátuma : H = 22 + D + E , ami márciusi dátum ha H <= 31, különben áprilisi és H - 31 az értéke. Két kivétel van : Ha E = 6 és D = 29, akkor H=50 illetve, Ha E = 6 és D = 28 és A > 10, akkor H = 49. A függvénynek három bemenô paramétere legyen : az elsô az évszám, a második a kiszámítandó hónap sorszámára mutató pointer, a harmadik a kiszámítandó nap értékére mutató pointer : void husvet vas( int evszam, int *honap, int nap) { . } Az évszámot a main()-ban

kell bekérni, utána meg kell hívni a függvényt, és a hívás után ki kell iratni a képernyôre a pontos dátumot. 5 Feladatok a 9. fejezet anyagából 6.) Tételezzük fel, hogy gyakran van szükség egy olyan mûveletre, hogy egy 1 és 3000 közötti egész számot 10-zel kell szorozni, de csak bit mûveleteket használhatunk. Irjunk egy olyan függvényt, amely megkapja az eredeti integer változó címét, és a szorzás után ezen a címen helyezi el a kapott értéket. 6 10. Tömbök - II rész Ezek után nézzük meg, hogy milyen kapcsolatban állnak egymással a tömbök és a pointerek. 10.1 Egydimenziós tömbök és a pointerek kapcsolata Ez a kapcsolat már csak azért is érdekes, mert felmerül a kérdés, hogy milyen módon adjunk át egy vektort egy függvénynek. Nyilván nem úgy, hogy egyenként átadjuk az összes elemét Az is kérdéses, hogy egy függvény hogyan adjon vissza egy vektort. Mint láttuk a függvény return-ja után csak egy

kifejezés szerepelhet. Ezen kérdésekre is választ ad a következô szabály : Egy egydimenziós vektor neve megegyezik a vektor 0-dik elemének a címével, tehát a vektor kezdôcímével : vektor = &vektor[0] , ahol "vektor" egy n elemû egydimenziós tömb. Példa : int x[10], *px; px = x; // Egyenértékü a px = &x[0] értékadással. px jelenleg az // x vektor kezdôcímét tartalmazza. Amennyiben egy vektor kezdôcímét egy azonos típusú pointernek adjuk át, akkor mind a pointer mind a vektor neve a vektor kezdôcímét tartalmazza. A két kifejezés között van azonban egy alapvetô különbség ! A pointer egy változó, a tömb neve pedig egy konstans. Ebbôl következôen, az elôbbi példánál maradva : px++; // Megengedett mûvelet : A vektor következô elemére mutat. x++; // Nem megengedett mûvelet, mert az x konstans ! Ha válaszolni akarunk a feltett kérdésekre, akkor azt mondhatjuk : egy vektort úgy adhatunk át egy függvénynek,

hogy a nevét adjuk át aktuális paraméterként. A függvénybôl való visszatérés esetén pedig a vektor nevével tér vissza a függvény. Ennek az esetnek nyilván csak akkor van értelme, ha a függvényben staticnak deklaráljuk a vektort Itt újabb kérdés merül fel : hogyan hivatkozhatunk a vektor kezdô címének ismeretében a vektor tetszôleges elemének címére ill. 55 annak tartalmára. Ezt a kérdést a C nyelv címaritmetikára vonatkozó szabályainak ismeretében válaszolhatjuk meg ! 10.2 Címaritmetika Egy cím + egész kifejezésnek az az alapvetô tulajdonsága, hogy mindig az illetô cím típusának megfelelôen a következô elemre mutató címet állítja elô. A 10.1 példájánál maradva : &x[2] = x+2; // A vektor 3. elemének a címe = A vektor kezdôcíme + 2 // Általában : &x[i] = x + i x[2] = *(x+2);// A vektor 3. elemének értéke = Az arra mutató cím // tartalmával // Általában : x[i] = *(x + i) 28. sz példaprogram : //

Buborékrendezés függvénnyel megvalósítva. #include <stdio.h> void main() { int a[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; void bubble sort( int *, int ); int ii; bubble sort( a, 10 ); for(ii=0; ii<10; ii++) printf(" A[%2d] = %2d",ii,a[ii]); } void bubble sort( int *bs v, int bs n ) { int i, j, x; for(i=0; i<bs n; i++) for(j=0; j<bs n-1; j++) if( *(bs v+j) > (bs v+j+1) ) // Csere van ! { x = *(bs v+j) ; (bs v+j) = (bs v+j+1) ; *(bs v+j+1) = x ; } } 2 Konkrétan : a bs v+1 ( vagy bs v++ ) mûvelet a bs v címet két byte-nyival lépteti, ha bs v egy integer típusú pointer. Ha float vagy double típusú lenne, akkor a léptetés nagysága 4 ill. 8 byte lenne További szabályok : - Ha két pointer ugyanannak a tömbnek az elemeire mutat, akkor értelmezettek a <, >, ==, != stb. relációs mûveletek - Ha két pointer ugyanannak a tömbnek az elemeire mutat, ( pl.: a és b ), akkor a - b az a és b közötti elemek darabszámát adja. -

Pointerhez hozzáadhatunk, ill. levonhatunk egész számot - Tilos : Pointerek szorzása, osztása, shiftelése, maszkolása, ill. float vagy double mennyiségek pointerekhez való hozzáadása vagy kivonása. 10.3 Kétdimenziós tömbök és a pointerek kapcsolata Amint az 5.2-ben megállapítottuk, kétdimenziós tömböt vektorok vektoraként adhatunk meg. A C a mátrixot sorfolytonosan tárolja ! Példa a definícióra : int y[10][5]; Amíg az egydimenziós tömbök esetén a tömb neve a tömb kezdô elemének a címével egyenlô, kétdimenziós tömbök esetén a tömb neve a tömb kezdô sorának címével egyenlô ! Fizikailag a kezdô elem, ill. a kezdô sor címe megegyezik, csak más a típusuk : amíg az elôbbi egy integerre mutató pointer, addig az utóbbi egy integer vektorra mutató pointer. ( Természetesen a típus mindkét esetben integer ! ) Ez azért lényeges, mert pld. ha az elôbbit eggyel növeljük, akkor egy integernyit lép arrébb a cím, az utóbbi

esetében az eggyel való növelés egy integer vektornyi léptetést jelent. Ennek a vektornak a méretét nyilván a mátrix oszlopmérete határozza meg. Példa : Amennyiben a már definiált y tömb után, a következô definíciókat végezzük el : int (*ppy)[5], py ; akkor a következôket állapíthatjuk meg : Az y nem az y tömb kezdô elemének a címe, hanem a kezdô (azaz 0.) sorának - egy öt elemû vektornak - a címe A ppy egy öt elemû egész típusú vektorra mutató pointer , így a következô értékadások helyesek : ppy = &y[0] ; vagy ppy = y; de a py = y ; rossz, mivel py egy egyszerû változóra mutató pointer ! Az y+1 mûvelet a következô sor, azaz y[1]-nek a címét állítja elô, tehát ebben az esetben az eggyel való növelés öt integernyi léptetést jelentett, mert az oszlopméret öt. A mátrix kezdôelemének a címét a py = &y[0][0]; mûvelettel helyezhetjük el py-ban. Ekkor a py+1 mûvelet a mátrix következô elemének

a címét állítja elô, tehát az y[0][1] elem címét ! Ha adott a mátrix kezdô elemének a címe, akkor egy tetszôleges elemét a *( py + sorindexoszlopméret + oszlopindex) művelettel érhetjük el. Példa : y[2][3] = *(py + 25 + 3) mert y[2][3] valóban a 13. elem ( Az indexelés 0 - tól indul ! ) 29. sz példaprogram : /*Egy 3x2-es és egy 2 elemû double típusú mátrix és vektor/ /* összeszorzása címaritmetika alkalmazásával / #include <stdio.h> #define N 3 #define M 2 void main() { void mv multiplication( double * , double , double , int , int ); double a[N][M], b[M], c[N]; int i, j; // Az a mátrix feltöltése for(i=0; i<N; i++) { for(j=0; j<M; j++) { printf("A[%d][%d] = ",i,j); scanf("%lf",&a[i][j]); } } // A b vektor feltöltése for(i=0; i<M; i++) { printf("B[%d] = ",i) ; scanf("%lf",&b[i]); } // &a[0][0] jelenti az a mátrix, b a b vektor c // pedig a c vektor kezdô elemének a címét. N

a sor, // M pedig az oszlopméret. mv multiplication( &a[0][0], b, c, N, M ); // Az eredmény vektor kiiratása for(i=0; i<N; i++) { 4 printf("C[%d] = %4.0lf ",i,c[i]); } } void mv multiplication(double *mva, double mvb, double *mvc, int mvn , int mvm) { int i, j; for(i=0; i<mvn; i++) { *(mvc+i)=0.0; for(j=0; j<mvm; j++) *(mvc+i)+=(mva+imvm+j)(mvb+j); } } 10.4 Memória kezelés Számos esetben elôfordul az a probléma, amikor azon elemek száma, melyeket egy vektorban akarunk tárolni - maga is a program bemenô adatai közé tartozik, vagy a vektor mérete más okból változó ! Ebben az esetben a vektort nem tudjuk definiálni, mivel méretét nem ismerjük. Ilyenkor - definíció helyett - a vektor aktuális méretének megfelelôen, egy függvény segítségével foglaljuk le a vektor számára a helyet a memóriában. A Borland C++ 2.0 memóriakezelô függvényei közül az alábbi hármat említjük meg : ( A függvények használatához az alloc.h

használata szükséges ! ) 1./ void *malloc( size t size ); A malloc nevü függvény size számú byte-ot foglal le a memóriában, és a lefoglalt memóriaterület kezdôcímével tér vissza. Amennyiben nem áll rendelkezésre a szükséges memória, úgy a függvény a NULL pointerrel tér vissza. A size t típusdefiníciója az alloch-ban található : typedef unsigned size t; , tehát size t egy elôjel nélküli integer. Mivel a visszaadott pointer típusa void, ezért a tárolni kívánt adatok típusának megfelelô konverziót kel végrehajtani ! (Ld: 30. sz példaprogram !) 2./ void *calloc( size t nitems , size t size ); Használata hasonló a malloc() függvényéhez, azzal a különbséggel, hogy nem közvetlenül a lefoglalni kívánt byte-ok számát adjuk meg, hanem elsô paraméterként a lefoglalni kívánt elemek számát, második paraméterként pedig egyetlen elem méretét. ( Ld: 31 sz példaprogram ! ) 3./ void free( void *block ); Lefoglalt

memóriaterület felszabadítása. A block a memóriaterület kezdô címe. ( Ld: 30 ill 31 sz példaprogramok !) 30. sz példaprogram : // Dinamikus vektordimenzionálás a malloc() segítségével #include <stdio.h> #include <conio.h> #include <alloc.h> void main() { int elemszam, i; int *tomb kezdet; printf(" Kérem a tömb elemeinek számát : " ); scanf("%d",&elemszam); // Mivel a malloc() void * típusú pointert ad // vissza,ezért típuskonverziót kell végrehajtani // void * - ról int -ra ! tomb kezdet = (int *) malloc( elemszamsizeof(int) ); if ( tomb kezdet == NULL ) { printf(" Nincs elég memória ! ) ; exit(0) ; } // // // // Sikeres helyfoglalás esetén a tomb kezdet egy elemszam számú integer típusú vektor kezdôcíme ! Feltöltjük a vektort a természetes számokkal 0 - tól elemszam-ig. for(i=0; i<elemszam; i++) *(tomb kezdet + i) = i; // A vektor kiiratása következik. printf(" "); for(i=0;

i<elemszam; i++) printf( " %d", *(tomb kezdet + i) ); getch(); // Felszabadítjuk a lefoglalt memóriát free( (void *) tomb kezdet ); } 6 31. sz példaprogram : // Dinamikus vektordimenzionálás a calloc() segítségével #include <stdio.h> #include <conio.h> #include <alloc.h> void main() { int elemszam, i; int *tomb kezdet; printf(" Kérem a tömb elemeinek számát : " ); scanf("%d",&elemszam); // Mivel a calloc() void * típusú pointert ad // vissza, ezért típuskonverziót kell végrehajtani // void * - ról int -ra ! tomb kezdet = (int *) calloc( elemszam,sizeof(int) ); if ( tomb kezdet == NULL ) { printf(" Nincs elég memória ! ) ; exit(0) ; } // // // // Sikeres helyfoglalás esetén a tomb kezdet egy elemszam számú integer típusú vektor kezdôcíme ! Feltöltjük a vektort a természetes számokkal 0 - tól elemszam-ig. for(i=0; i<elemszam; i++) *(tomb kezdet + i) = i; // A vektor kiiratása

következik. printf(" "); for(i=0; i<elemszam; i++) printf( " %d", *(tomb kezdet + i) ); getch(); // Felszabadítjuk a lefoglalt memóriát free( (void *) tomb kezdet ); } Feladatok a 10. fejezet anyagából 1.) Adva van egy bolt, ahol 10 fajta terméket árulnak A termékeket a sorszámaik azonosítják, ezenkívül nyilvántartjuk az induló mennyiségeket, és a termékek egységárait. A napi eladásokat egy mátrixban tároljuk, amelynek egy eleme ( például : a[i][j] ) megmutatja, hogy az i. napon mennyit adtunk el a j termékbôl. Az eladásokat egy hét ( 5 munkanap ) idôtartamra rögzítjük ! Készítsünk olyan menüvezérelt programot, amelynek a funkciói a következôk : 1.) Lista a pillanatnyi helyzetrôl : A lista tartalmazza a termék sorszámát, az induló mennyiséget, az addig eladott mennyiséget, a termék egységárát és a termékenkénti, valamint az összes bevételt. 2.) Eladás : Az eladás során vizsgálni kell, hogy

van-e még az illetô termékbôl annyi, amennyit el akarunk adni. Egy eladás után meg kell kérdezni, hogy akarunk-e még eladni . 3.) Bevétel összesítô napi bontásban : Az összesítônek tartalmaznia kell a napok sorszámát, az illetô napon eladott eladott termékek összes darab számát ill. az aznapi összes bevételt. Az összesítô végén végösszesen-t kell csinálni, az eladott darab számra ill. a bevételre 4.) Bevétel összesítô termék szerinti bontásban : Az összesítônek tartalmaznia kell a termék sorszámát, az illetô termék összes eladott darab számát ill. az abból származó összes bevételt. Az összesítô végén végösszesen-t kell csinálni, az eladott darab számra ill a bevételre 0.) Kilépés : A program befejezése. A négy funkciót függvények használatával kell megvalósítani ! 8 11. Mutatók ( Pointerek ) - II rész 11.1 Pointertömbök Tekintsük a következô definíciót : int *w[5]; Ez a definíció egy

olyan 5 elemû vektort definiál amelynek minden eleme egy integerre mutató pointer. Ez a konstrukció kiválóan alkalmas változó hosszúságú integer vektorok kezelésére, amit a 30. sz példaprogram mutat be Fontos : Az int *w[5]; definíció nem tévesztendô össze az int (w)[5]; definícióval. Az utóbbi ugyanis egyetlen pointert definiál, ami egy 5 elemû integer vektorra mutat. Ebben az esetben tehát a w++ mûvelet 5 integernyit azaz 10 byte-ot léptet 32. sz példaprogram : /* ======= Változó hosszúságú integer vektorok ========== / /* ======= kezelése pointertömb segítségével ========== */ #include <stdio.h> int *pvek[5]; int v0[3] = { 1, 2, 3 }; int v1[5] = { 4, 5, 6, 7, 8 }; int v2[2] = { 9,10 }; int v3[4] = { 11,12,13,14 }; int v4[6] = { 15,16,17,18,19,20 }; int lv[5] = { 3, 5, 2, 4, 6 }; // A vektorok hosszai void main() { int i, j; // Elhelyezzük a vektorok címeit a pointervektor // megfelelô elemeiben. pvek[0]=v0 ; pvek[1]=v1 ; pvek[2]=v2 ;

pvek[3]=v3 ; pvek[4]=v4 ; printf(" PVEK[2][1] -> V2[1]) printf(" V1[1] = *++PVEK[1] printf(" V3[2] = *(PVEK[3]+2) printf(" V4[5] = *(PVEK[4]+5) = = = = %d ",pvek[2][1]); %d",*++pvek[1]); %d",*(pvek[3]+2)); %d",*(pvek[4]+5)); // A pvek[1] címet az eredetire kell állítani ! pvek[1] = v1 ; for( i=0; i<5; printf(" "),i++ ) for( j=0; j<lv[i]; printf(" %2d",*(pvek[i]+j++) )); } A pointertömbök alkalmazásának még gyakoribb esete a char típusú pointertömbök alkalmazása változó hosszú stringek kezelésére. 33. sz példaprogram : /* === Sorszámával adott hónap nevének visszakeresése === / /* === K&R : "A C programozási nyelv" 117. oldal === */ #include <stdio.h> char *month name(int); void main() { int h; printf(" Kérem a hónap sorszámát : ") ; scanf("%d",&h); printf(" A hónap neve : %s", month name(h)); } char *month name( n )

/Visszaadja az n-edik hónap nevét/ int n; { static char *name[] = { "nem létezô hónap", "január", "február", "március", "április", "május", "június", "július", "augusztus", "szeptember", "október", "november", "december" }; return( (n<1 || n>12) ? name[0] : name[n] ); } A name egy ismeretlen méretü char típusú pointertömb, tehát minden eleme egy karakterláncra mutató pointer. A name[1] pointer például a "január" szövegre mutat. A tömb méretét a forditó határozza meg - a tömb inicializálása alapján 11.2 Függvényre mutató pointer 34. sz példaprogram : /* Példa függvényre mutató pointer használatára #include <stdio.h> #include <conio.h> // A getch() függvény miatt #include <math.h> // Az sqrt() függvény miatt void main() { int v, x, y, z ; */ // // // float A func egy

olyan függvényre mutató pointer, amely float-ot ad vissza, és három darab int típusú bemenô paramétere van ! (*func)( int, int, int ); // // float float float float A három függvény más más ugyanazokon az adatokon. osszeg( int, int, int ); atlag( int, int, int ); gyok( int , int, int ); w; mûveletet végez, x = y = z = 2; // Választás menübôl clrscr(); printf(" 1. Összeg képzése printf(" 2. Átlag képzése printf(" 3. Négyzetösszeg gyöke printf(" Melyiket a három közül: scanf("%d",&v); switch(v) { case 1: func = osszeg ; break; case 2: func = atlag break; ; func = gyok break; ; case 3: default: "); "); "); printf(" "); ") ; break; } w = func(x,y,z); printf(" Eredmény = %5.2f",w); getch(); } // A három függvény megvalósítása float osszeg( int o1, int o2, int o3 ) { return( (float) (o1+o2+o3) ); } float atlag( int a1, int a2, int a3 ) { return( (a1+a2+a3) /

3.0 ); } float gyok( int g1, int g2, int g3 ) { double gy; gy = sqrt( (double) (g1*g1 + g2g2 + g3g3) ); return( (float) gy ); } Mint látható a függvényre mutató pointer alkalmazása akkor nagyon hasznos, amikor ugyanazokon az adatokon más más mûveletet kell elvégezni. A pointernek úgy adhatjuk át az aktuális függvény címét, hogy a függvény nevét használjuk, hasonlóan a vektoroknál látottakhoz 11.3 Függvényekre mutató pointertömbök 35. sz példaprogram : /* Példa függvényre mutató pointertömb használatára */ #include <stdio.h> #include <conio.h> #include <math.h> void main() { int v, x, y, z ; // A func egy olyan függvényre mutató pointertömb, // amelynek minden eleme egy - float-ot visszaadó // és három int típusú bemenôparaméterrel rendel// kezô függvényre mutat! float (*func[3])( int, int, int ); float osszeg( int, int, int ), atlag( int, int, int ); float gyok( int , int, int ), w; x = y = z = 2; // A func

tömb megfelelô elemeit feltöltjük, a há// rom függvény címeivel. func[0] = osszeg ; func[1] = atlag ; func[2] = gyok ; // Választás menübôl clrscr(); printf(" 1. Összeg képzése printf(" 2. Átlag képzése printf(" 3. Négyzetösszeg gyöke printf(" "); printf(" Melyiket a három közül scanf("%d",&v); "); "); "); : ") ; // A kívánt függvény meghívása w = func[v-1]( x, y, z ); printf(" Eredmény = %f",w); getch(); } // A három függvény megvalósítása float osszeg( int o1, int o2, int o3 ) { return( (float) (o1+o2+o3) ); } float atlag( int a1, int a2, int a3 ) { return( (a1+a2+a3) / 3.0 ); } float gyok( int g1, int g2, int g3 ) { double gy; gy = sqrt( (double) (g1*g1 + g2g2 + g3g3) ); return( (float) gy ); } Egyértelmüen kiderül, hogy a pointertömb alkalmazása miatt nincs szükség a case szerkezetre, hanem közvetlenül tudjuk hívni a kívánt függvényt ! 12.1

A struktúra fogalma, deklarálása, definíciója 12. Struktúrák 12.1 A struktúra fogalma, deklarálása, definíciója Véges számú különbözô típusú, logikailag összetartozó változó együttese, amelyeket az egyszerû kezelhetôség érdekében gyûjtünk össze. C-ben a struktúra fogalma hasonlít a PASCAL rekord fogalmához. Struktúra deklarálása : A struktúra deklarációt a struct kulcsszóval kezdjük, amelyet struktúracimke követ. A struktúracimke egy név, amely az adott típusú struktúrát nevezi meg A struktúracimkét egy kapcsos zárójelek közé zárt deklarációlista követi, pontosvesszôvel a végén : struct <struktúratípus név> { <típus> <változónév> ; . . . }; A struktúrában elôforduló változókat tagoknak nevezzük. Példa egy struktúra deklarálására : struct szemely { char nev[31]; char cim[31]; char fogl[16]; long fizetes; }; 1 12.1 A struktúra fogalma, deklarálása, definíciója Ez a

konstrukció tehát csak deklarálja a szemely típusú stuktúrát, de nem definiálja, azaz nem foglal számára helyet a memóriában. Struktúra definiálása : A struktúra definíciója szintén a struct kulcsszóval kezdôdik, amelyet a struktúra deklarálásánál használt struktúratípus név követ. Ezután adjuk meg magának a struktúrának a nevét, azt a nevet amelynek a segítségével a struktúrára, és annak tagjaira hivatkozni tudunk : struct <struktúratípus név> <struktúranév> ; Példa egy struktúra definiálására: struct szemely sz; Ez az utasítás foglalja le a szemely típusú, sz nevû struktúra számára a helyet a memóriában. Struktúratagra történô hivatkozás, minôsített névvel : Valamely struktúratagra - egy kifejezésen belül - úgy hivatkozhatunk, hogy leírjuk a struktúra nevét, majd a "." (pont) operátort, ezután pedig a tag nevét : struktúranév.tagnév; Példa struktúra tagra történô

hivatkozásra : A programban a következôképpen hivatkozhatunk az sz nevû struktúra egy tagjára: sz.fizetes = 33000; vagy strcpy(sz.nev,"Lisztes Krisztián"); A struktúrák egymásba ágyazhatóak : Legyen adott a következô struktúra : struct date { 2 12.2 Struktúrák és függvények int ev; int ho; int nap; }; Ha az sz nevû szemely típusú struktúrát ki akarjuk bôvíteni a születési dátummal, akkor a következôt tehetjük : struct szemely 01 { char nev[31]; char cim[31]; struct date szul dat; char fogl[16]; long fizetes; }; struct szemely 01 sz 01; Ezek után hivatkozhatunk például a születési dátum egyes mezôire : sz 01.szul datev = 1976 ; vagy : sz 01.szul datho = 11 ; 12.2 Struktúrák és függvények Az alap C-ben a függvények csak struktúrára mutató pointereket kaphatnak bemenô paraméterként, és csak struktúrára mutató pointereket adhatnak vissza. ( A C++ nyelv-ben ennél tágabbak a lehetôségek ! ) A struktúrákon két

mûveletet végezhetünk : Struktúra címének elôállítása A struktúra címét az & operátor segítségével állíthatjuk elô. Példa struktúrára mutató pointer definiálására : struct szemely 01 *szem 01; szem 01 = &sz 01; // szem 01 egy szemely 01 típusú // struktúrára mutató pointer. // szem 01 felveszi az sz 01 // struktúra címét. Struktúra taghoz való hozzáférés a "->" operátor segítségével . 3 12.2 Struktúrák és függvények Amennyiben nem a struktúra neve áll rendelkezésünkre, hanem a struktúra kezdôcímét tartalmazó pointer, akkor a struktúratagra történô hivatkozás úgy oldható meg, hogy leírjuk a pointer nevét, majd a nyíl ( a mínusz és a nagyobb jel : -> ) operátort, és utána a tag nevét : pointernév->tagnév; Példa struktúra tagra történô hivatkozásra pointer segítségével: szem 01->fizetes = 33000; // Ugyanaz a hatása mint az sz 01.fizetes = // 33000; értékadásnak.

Megjegyzés : Mivel a "->" operátor precedenciája magasabb mint a ++ operátoré ezért a ++szem 01->fizetes; utasítás a fizetés tagot fogja inkrementálni és nem a szem 01 pointert. Ha a pointert akarjuk inkrementálni, akkor a (++szem 01)->fizetes; zárójelezést kell alkalmaznunk. 36. sz példaprogram : /* Egyszerû példa a struktúrák használatára */ #include <stdio.h> #define SIZE 5 struct szemely { char nev[26]; char cim[26]; long fizetes; }; void main() { struct szemely szm; struct szemely *psz; void sz load(struct szemely *); // psz felveszi az szm struktúra címét. psz = &szm; // sz load bemenô paramétere lesz ez a cím. sz load( psz ); printf(" NÉV = %s CIM = %s FIX = %ld", szm.nev, szmcim, szmfizetes); } 4 12.3 Struktúratömbök void sz load( struct szemely *p sz ) { strcpy( p sz->nev,"Kovács"); strcpy( p sz->cim,"Pécs"); p sz->fizetes = (long) 20000; } 12.3

Struktúratömbök Ha a feladat úgy kívánja, definiálhatunk struktúra tömböket is. Ezzel a módszerrel kiválóan kezelhetjük egymással összefüggô változók tömbjeit - azaz táblázatokat.A struktúratömb definíció elôtt - a 121-ben ismertetett módon deklarálni kell azt a struktúratípust, amelybôl struktúratömböt akarunk létrehozni Ezután a struktúratömb definiálását úgy végezhetjük el, hogy leírjuk a struct kulcsszót, utána a struktúratípus nevét. Ezt követi a struktúratömb neve, majd szögletes zárójelek között, a tömb elemszáma : struct <struktúratípus név> <struktúratömb név>[<elemszám>]; Példa egy struktúratömb definiálására: struct szemely 01 szt 01[10]; Ez az utasítás foglalja le a szemely 01 típusú szt 01 nevû 10 elemû struktúra tömb számára a helyet a memóriában. A tömb 0-9 -ig indexelhetô ! Példa struktúratömb tagra történô hivatkozásra : A programban a következôképpen

hivatkozhatunk az szt 01 nevû struktúra tömb 5. elemének egy tagjára : szt 01[4].fizetes = 33000 ; vagy : strcpy(szt 01.nev[4],"Lisztes Krisztián"); Példa struktúratömb címének elôállítására : A struktúratömb címének elôállítására most is az & operátort használjuk. Ha definiálunk egy szemely 01 típusú pointert : 5 12.3 Struktúratömbök struct szemely 01 *szemt 01; akkor a struktúra tömb címe a szemt 01 = &szt 01[0] ; utasítással adható át. Ekkor a szemt 01++ mûvelet az szt 01[1] címét állítja elô, azaz a táblázat következô sorának címét. 37. sz példaprogram : /* Példa #include #include #define struktúratömbök használatára */ <stdio.h> <conio.h> SIZE 5 struct szemely { char nev[26]; char cim[26]; long fizetes; }; void main() { void sz load(struct szemely *); struct szemely szm[SIZE]; struct szemely *psz; int i; // A kezdô cím átadása psz-nek. psz = &szm[0] ; sz load( psz ) ; for(i=0;

i<SIZE; i++) printf(" NÉV[%d] = %s CIM = %s FIX = %ld", i, szm[i].nev, szm[i]cim, szm[i]fizetes); } void sz load( struct szemely *p sz ) { char *cj; int j; for(j=0; j<SIZE; j++) { 6 Feladatok a 11. - 12 fejezet anyagából strcpy( (p sz+j)->nev,"Kovács "); // Karakter típusú sorszám elôállítása itoa(j,cj,10); // Sorszám hozzáfûzése a névhez strcat( (p sz+j)->nev,cj); strcpy( (p sz+j)->cim,"Pécs "); // Sorszám hozzáfûzése a címhez strcat( (p sz+j)->cim,cj); (p sz+j)->fizetes = (long) 20000+j; } } Feladatok a 11. - 12 fejezet anyagából 1.) Adott a következô struktúra típus : struct konfig { long alaplap ft; long winch ft; long disp ft; long floppy ft; long printer ft; char alaplap typ[21]; char winch typ[21]; char disp typ[21]; char floppy typ[21]; char printer typ[21]; }; A típus alapján definiálni kell egy struktúrát, valamint egy ilyen típusú struktúrára mutató pointert, és menüvezérlés

alapján a következô mûveleteket kell végrehajtani : 1.) 2.) 3.) 0.) A struktúra feltöltése adatokkal. A struktúra tartalmának listázása képernyôre. A struktúra törlése. ( Numerikus adatok értéke nulla, karakteres adatok értéke az üres string / "" / ). Kilépés a programból. A feladatot négyféle módszerrel kell megoldani. 7 Feladatok a 11. - 12 fejezet anyagából a.) Fôprogramban, függvényhasználat nélkül. A struktúra tagokra történô hivatkozás a pont ( "" ) operátorral történik b.) A három funkciót egy-egy függvénnyel valósítsuk meg, melyek típusa void lesz, és bemenô paraméterük a konfig típusú struktúrára mutató pointer. A struktúra tagokra történô hivatkozás a nyíl ("->") operátorral történik. c.) Marad a három függvény, de a hívásukat függvényre mutató pointerrel kell megoldani ! d.) Ugyanaz mint c.) de a függvényhívásokat függvényre mutató

pointertömbbel kell megoldani ! 8 13. Parancssor argumentumok használata A C környezet lehetôséget nyújt arra, hogy a kész programunkat végrehajtás elôtt paraméterekkel lássuk el, ugyanúgy ahogy pld. egy DOS parancsot : COPY AC B.C Ahhoz, hogy ezt megtehessük az eddig használt void main() függvényt két bemenô paraméterrel kell ellátnunk. Az egyik paraméter int típusú és C konvenció szerint "argc" a neve. Ez mutatja meg, hogy a programunkat hány bemenô paraméterrel indítjuk el. A másik paraméter char * típusú pointertömb, a neve pedig "argv". Ebben a pointertömbben helyezkednek el a programunk bemenô paraméterei, karakterlánc formában Az argv[0] tartalmazza a programunk nevét, tehát argc értéke legalább 1 Az argv[1] tartalmazza az elsô paramétert, az argv[2] a másodikat stb. Ha parancssor argumentumokat akarunk használni, akkor az eddig szokásos : #include <stdio.h> void main() { } helyett a következôt

kell írnunk a forrásprogramban : #include <stdio.h> void main( int argc, char *argv[] ) { } Adott esetben a parancssor argumentumok használata lehetôséget nyújt opcionális kapcsolók használatára. Ezeket a kapcsolókat a "-" jel elôzi meg, és a kapcsolóknak összefûzhetôknek kell lenniük. Példa : Ha van egy rendez.exe programunk és a növekvô rendezést az -a kapcsoló jelenti, a kis és nagybetû megkülönböztetést a -c , továbbá meg kell adni az input és output file neveket, akkor a rendezô programot így indíthatjuk el : rendez -a -c elso.txt r elsotxt vagy : rendez -ac elso.txt r elsotxt A C nyelv most megismert tulajdonsága tette lehetôvé - többek között - , hogy a UNIX operációs rendszer nagy részét C nyelven írták újra. ( Az elsô UNIX verziók ugyanis assemblyben készültek ) Az operációs rendszerek parancsai ugya73 nis gyakran használnak kapcsolókat, és ezt az igényt a parancsor argumentumok használatával

maximálisan ki lehet elégíteni ! 38. sz példaprogram : /* ECHO.C : A program inditásakor megadott, szóközökkel /* elválasztott parancssor argumentumok vissza/* írása a képernyôre. /* K&R : "A C programozási nyelv" 119. oldal */ */ */ */ #include <stdio.h> void main( int argc, char *argv[] ) { int i; // Az argv[0]-t nem iratjuk vissza // mert az a programunk neve ! for(i=1; i<argc; i++) printf("%s%c",argv[i],( i<argc-1 ) ? : ); // Az utolsó szó után nem szóköz követ// kezik, hanem soremelés ! } Ha most a dos prompt után a következôt gépeljük : echo Ez egy példa a parancssor argumentumok használatára ! és <ENTER>-t nyomunk, akkor a képernyôn az Ez egy példa a parancssor argumentumok használatára ! szöveg jelenik meg. A parancssor argumentumokról még a file kezelés témában is lesz szó ! 14. Típusnév definícíók A typedef kulcsszó segítségével új adattípus neveket hozhatunk létre a C

nyelv rendelkezésre álló adattípusainak segítségével. Ebbôl következik, hogy semmiképpen nem új adattípus létrehozásáról van szó, hanem egy meglévô adattípus új - számunkra kényelmesebb - névvel való ellátásáról. A típus definíciót a következôképpen végezhetjük el: typedef <eredeti típus> <általunk definiált típus> ; Példa : typedef unsigned char BOOL; BOOL b; // A b tulajdonképpen egy unsigned char lesz, de adott // esetben szemléletesebb BOOL-ként használni. A típusdefiníció különösen hasznos akkor, ha többféle struktúrát használunk a programunkban. Szemléletesebb és könnyebb megérteni egy struktúra típus nevet, vagy egy pointer típusnevet mint egy bonyolult strukúra nevét, vagy egy arra mutató pointer nevét. A típusnév definíció használatának másik oka a gépfüggôség kivédése Ha a programunkban gépfüggô adattípusokat használunk, akkor egy másik gépre történô áthelyezésnél elég

csupán a typedef-eket módosítani. 39. sz példaprogram : #include <stdio.h> #define SIZE 5 struct szemely { char nev[26]; char cim[26]; long fizetes; }; typedef struct szemely person; typedef struct szemely *p person; void main() { // Az szm egy person típusú struktúra person szm; // A psz egy p person típusú pointer p person psz ; void sz load(p person); psz = &szm ; sz load( psz ); printf(" %s %s %ld", szm.nev , szmcim ,szmfizetes); } void sz load( p person p sz ) { strcpy( p sz->nev,"Kovács"); >cim,"Pécs"); p sz->fizetes = (long) 20000; } 82 strcpy( p sz- 15. File (adatállomány) kezelés - I rész A C- ben egy file-t egy olyan pointerrel tudunk azonosítani ami egy FILE típusú struktúrára mutat. A FILE egy struktúra típusnév definíció, mely struktúra tartalmazza az aktuális file-lal kapcsolatos információkat (pld. azt, hogy a file írás vagy olvasás alatt áll). Az <stdioh>-ban található az

iobuf struktúra deklarálása, és utána a "typedef struct iobuf FILE ;" típusnév definíció. 15.1 Szabványos be és kimenet átirányítása Alapesetben egy C program a klaviatúrát használja bemenetként, és a képernyôt használja kimenetként. Abban az esetben, ha a programot a következôképpen indítjuk : rendez < adatok.txt akkor a rendez nevû program nem a klaviatúráról, hanem az adatok.txt állományból olvassa az adatokat Abban az esetben, ha az alábbi módon indítjuk : rendez > r adatok.txt akkor nem a képernyôre írja ki a rendezett adatokat, hanem az r adatok.txt állományba 15.2 File deklaráció A file deklarációja az úgynevezett állománymutató segítségével történik, ami a már említett FILE típusú struktúrára mutat : FILE < állománymutató >; Példa file definícióra : FILE *fp; Ezekután az fp pointerrel hivatkozhatunk a file-ra, a használat során. 15.3 File megnyitása A file megnyitása az

fopen() függvénnyel történik, ami egy FILE * típusú pointert ad vissza. Az fopen() függvénynek két char * típusú bemenô paramétere van. Az elsô a megnyitandó állomány neve, a második a megnyitás módja : <állománymutató> = fopen( <filenév> , <mód >); Alapesetben háromféle megnyitási módról beszélhetünk : 1. Megnyitás olvasásra : "r" File pointer az állomány elejére áll 2. Megnyitás írásra : "w" File pointer az állomány elejére áll. 3. Megnyitás hozzáfûzésre : "a" File pointer az állomány végére áll Az "r" mód alkalmazása esetén a file-nak természetesen léteznie kell ! A "w" mód alapesetben egy új file-t kreál írásra. Ha a "w" módot egy már meglévô file esetén alkalmazzuk, akkor számolnunk kell azzal, hogy a file tartalma felülíródik ! A hozzáfûzésre való megnyitás ( "a" ) esetén a file írható, - a file végétôl. Ebben

az esetben a meglévô file tartalma nem íródik felül ! Ha a file nem létezik, akkor a "w" módhoz hasonlóan egy új file jön létre - írásra. Az alapesetet a + (plusz) karakterrel tudjuk módosítani, ha a feladat úgy kívánja ! A + karaktert az aktuális mód karakteréhez egyszerûen hozzá kell fûzni, így az alap megnyitási módok a következôképp módosulnak : Az "r+" mód csakis egy létezô file-ra vonatkozik. A file-t olvasásra és írásra nyitja meg ( update ). A "w+" mód egy üres file-t nyit meg irásra és olvasásra A file-nak tehát nem kell léteznie ! Létezô file esetén a file tartalma felülíródik ! Az "a+" mód olvasásra és hozzáfûzésre nyitja meg a file-t. Ha a file még nem létezik, akkor új file-t nyit meg. Minden írási mûvelet a file végén történik, így egy meglévô file tartalma nem íródik felül ! Ha ASCII állományról van szó akkor a "t", ha bináris állományról

akkor a "b" üzemmódot használjuk, az ennek megfelelô karaktert hozzá kell fûzni az elôbb ismertetett karakterek valamelyikéhez. Az alapértelmezés a text üzemmód ! Példa file megnyitásra : fp = fopen("adatok.txt","rt"); // Az adatoktxt file megnyitása olvasásra, // text üzemmódban. A gyakorlatban természetesen a file megnyitással együtt hiba vizsgálatot is végzünk, hiszen az fopen() függvény NULL pointert ad vissza, ha a megnyitás valamilyen oknál fogva nem sikerült ! (Például nem létezô file-t akartunk megnyitni) Ld.: 38 sz példaprogram ! 15.4 File írása Ha "w" módban nyitottunk meg egy file-t, akkor az írás mindig a file elejétôl történik, így a file-ban lévô adatok felülíródnak ! Egy karakter kiírása : int fputc( int c, FILE *f ) ahol : c : a kiirandó karakter, f : a file struktúrára mutató pointer Az fputc() normál esetben a kiírt karaktert adja vissza, hiba esetén pedig az EOF-ot.

Formátumozott változólista kiírása : int fprintf( FILE *f ,char fs , <args> ) ahol : f : a file struktúrára mutató pointer fs : a formátum vezérlô string <args> : változó(lista) Az fprintf() a kiírt karakterek számát adja vissza. Látható, hogy az fprintf() használata teljesen megegyezik a printf() függvényével, a FILE típusú pointertôl eltekintve. 15.5 File olvasása Egy karakter beolvasása : int fgetc( FILE *f ) ahol : f : a file struktúrára mutató pointer Az fgetc() normál esetben a beolvasott karaktert adja vissza, hiba esetén pedig az EOF-ot. A file pointert automatikusan a következô beolvasandó karakterre állítja. Formátumozott változólista beolvasása : int fscanf( FILE *f , char fs,<args>) ahol : f: a file struktúrára mutató pointer fs : a formátum vezérlô string <args> : változócím(lista) Az fscanf() a beolvasott karakterek számát adja vissza. Látható, hogy az fscanf() használata teljesen

megegyezik a scanf() függvényével, a FILE típusú pointertôl eltekintve. 15.6 File lezárása int fclose(f) ; ahol f egy FILE típusú pointer. Az fclose() függvény 0-át ad vissza akkor, ha a file lezárása sikeresen megtörtént. Ellenkezô esetben EOF-ot ad vissza a függvény 40. sz példaprogram ( az eddig tárgyaltakra ) : /* Adatok irása il. olvasása file használattal /* fprintf(), fscanf() */ #include <stdio.h> #define SIZE 5 struct szemely { char nev[26]; char cim[26]; long fizetes; }; */ void main() { FILE *fp; struct szemely szm[SIZE]; struct szemely *psz; int i; void sz load(struct szemely *); // Inicializálás for(i=0; i<SIZE; i++) { strcpy(szm[i].nev," strcpy(szm[i].cim," szm[i].fizetes = 0L; } "); "); psz = &szm[0] ; // A struktúra feltöltése adatokkal sz load( psz ); // File megnyitás írásra if( (fp=fopen("szemely.dat","wt")) == NULL ) { printf(" Hiba a file megnyitásnál ->

IRÁS!"); exit(0); } // Kiiratás file - ba for(i=0; i<SIZE; i++) { fprintf(fp," %s %s %ld", szm[i].nev,szm[i]cim,szm[i]fizetes); } // Az írásra megnyitott file lezárása fclose(fp); // File megnyitás olvasásra if( (fp=fopen("szemely.dat","rt")) == NULL ) { printf(" Hiba a file megnyitásnál -> OLVASÅS !") ; exit(0) ; } // Beolvasás file - ból for(i=0; i<SIZE; i++) { fscanf(fp,"%s %s %ld, szm[i].nev,szm[i]cim,&szm[i]fizetes); printf(" NÉV[%d] = %s CIM = %s FIX = %ld", i,szm[i].nev,szm[i]cim,szm[i]fizetes); } // Az olvasásra megnyitott file lezárása fclose(fp); } void sz load( struct szemely *p sz ) { char *cj; int j; for(j=0; j<SIZE; j++) { strcpy( (p sz+j)->nev,"Kovács") ; itoa(j,cj,10) ; strcat( (p sz+j)->nev,cj); strcpy( (p sz+j)->cim,"Pécs"); strcat( (p sz+j)->cim,cj); (p sz+j)->fizetes = (long) 20000+j; } } Feladatok a 13. - 14 - 15 fejezet

anyagából 1.) Lássuk el az ECHOC programot ( 38 sz példaprogram ) egy -nx kapcsolóval, ahol 1 <= x <=9 szám, ami megmutatja azt hogy a visszaírt szöveg után hány darab soremelést akarunk látni a képernyôn. Ha x nem 1 és 9 közé esik, akkor a program küldjön hibaüzenetet és fejezze be mûködését. Példa az indításra : echo1. exe -n3 Ez már egy intelligensebb echo program ! 2.) Tekintsük a 11-121) - ben adott konfig típusú struktúrát Ezen típus alapján definiáljunk egy 10 elemû struktúratömböt, töltsük fel adatokkal, és irassuk ki a struktúratömb tartalmát az SZ GEPEK.DAT nevû "t" módú file-ba Ha ez megtörtént akkor a feladat a következô : Irjunk egy olyan általános beolvasó függvényt, amely egyszerrre csak egy struktúrányi adatot olvas be az SZ GEPEK.DAT nevû file-ból Ezen függvény bemenô paramétere - többek között - annak a függvénynek a címe is, amelyet ha meghívunk a függvénybôl, akkor az

éppen beolvasott struktúrán a kívánt mûveletet hajtja végre. Kétféle mûveletet különböztetünk meg : Az egyik a struktúra listázása displayra, a másik a struktúra szétválogatása olymódon, hogy az elsô öt long típusú változót az arak[10][5] long típusú tömb megfelelô sorába, az utána következô öt karakteres típusú vektort pedig a nevek[10][21] karakteres típusú tömb megfelelô sorába helyezzük el. A két tömböt globális változóként kell definálni Ennek a látszólag bonyolult megoldásnak az az elônye, hogy csak egy beolvasó ciklust kell írni, és a ciklusmagban hívhatjuk meg azt a függvényt, amely elvégzi a kívánt mûveletet. A beolvasó függvény szintaxisa lehet például a következô : void beolv( FILE *fszg, struct konfig kf, void (funkcio) () ) { . } ahol fszg jelenti az SZ GEPEK.DAT nevû file-ra mutató pointert, kf arra a struktúrára mutat, ahol a beolvasott adatokat el kell helyezni, funkció pedig annak a

függvénynek a címe, amelyet a beolv() függvény belsejében kell meghívni. Ilymódon a beolv() függvényt kétféleképpen hívhatjuk meg : 1.) beolv( fp, &SZG, lista ) ; // A listázó funkció kerül végrehajtásra 2.) beolv( fp, &SZG, valogat) ; // A szétválogató funkció kerül végrehajtásra Az elsô esetben a funkcio a lista nevû függvény címét veszi fel, a második esetben a valogat nevû függvényét. Ezekután a funkció által mutatott függvény a következô képpen hívható meg : (*funkcio) ( ) ; 16.1 File elejére történô pozicionálás 16. File (adatállomány) kezelés - II rész 16.1 File elejére történô pozicionálás void rewind( FILE *f ); ahol : f : A file struktúrára mutató pointer. A függvény hatására a file pointer a file elejére fog mutatni, és bármilyen író, vagy olvasó mûvelet a file elejétôl lesz érvényes. Csak "a+" olvasás+hozzáfûzés üzemmódban hatásos ! 16.2 Adategység formátum

nélküli kiiratása file-ba int fwrite( char *buffer, int size, int count, FILE f ); ahol : buffer size count f : Az a memóriacím, ahol a kiiratni kívánt adategység kezdôdik. : Az adategység mérete byte-okban kifejezve. : A kiiratni kívánt adategységek száma. : A file struktúrára mutató pointer. Ez a függvény kiválóan alkalmas tömbök, struktúrák, ill. struktúra tömbök kiiratására. Utóbbira lásd: 40 sz példaprogram 16.3 Adategység formátum nélküli beolvasása file-ból int fread( char *buffer, int size, int count, FILE f ); ahol : buffer size count f : Az a memóriacím, ahova az adategységet be akarjuk olvasni. : Az adategység mérete byte-okban kifejezve. : A beolvasni kívánt adategységek száma. : A file struktúrára mutató pointer. 1 16.4 File vége ( End Of File ) vizsgálat Ez a függvény kiválóan alkalmas tömbök, struktúrák, ill. struktúra tömbök beolvasására. Utóbbira lásd: 40 sz példaprogram 16.4 File

vége ( End Of File ) vizsgálat int feof( FILE *f ); ahol f : : A file struktúrára mutató pointer. A függvény 0 értéket ad vissza, ha nem a file végén vagyunk, ill. nem 0 értéket, ha a file végén vagyunk. 41. sz példaprogram : /* FEOF.C = Példa a feof() függvény használatára */ #include <stdio.h> void main() { int c; FILE *fp; if( (fp = fopen("szemely.dat","rt")) == NULL ) { printf(" Hiba a szemely.dat megnyitásánál !); // Kilépés a programból exit(0); } // Elôolvasás. c = fgetc(fp); // Amíg nincs file vége. while( !feof(fp) ) { printf(" A beolvasott karakter : %c",c); // Olvassa a következôt. c = fgetc(fp); } // A file lezárása. fclose(fp); } 42. - 43 sz példaprogramok az fwrite(), fread() függvények használatára : A példában egy 5 elemû struktúratömböt akarunk kiiratni ill. beolvasni Nyilván meg lehetne oldani az fprintf() ill. az fscanf() függvényekkel is, de ez esetben 2 16.4 File

vége ( End Of File ) vizsgálat ciklust kellene szerveznünk mind a kiiratásra mind a beolvasásra. Jelen esetben az fwrite() ill. az fread() használata egyszerûbb megoldást jelent, bonyolultabb struktúrák esetén pedig - gyakorlatilag - csak ez jöhet szóba. Megjegyzés : A "t" ill. "b" üzemmód mind a formátumozott mind a formátum nélküli író/olvasó mûveleteknél használható Az fprintf() ugyanúgy karakterláncként írja ki a numerikus változókat mindkét üzemmódban, és az fwrite() ugyanúgy byte-osan írja ki a numerikus változókat, mindkét üzemmódban. Az alapvetô különbség annyi, hogy "t" módban a soremelés ( 0A h ) karakter helyett a kocsi-vissza, soremelés ( 0Dh 0Ah ) karakterpár íródik ki, míg "b" üzemmód esetén ez a konverzió elmarad ! A 40. sz példaprogramban a "t" , a 41. sz példaprogramban a "b" módot alkalmaztuk ! #include <stdio.h> #define SIZE 5 struct

szemely { char nev[26]; char cim[26]; long fiz; }; void main() { FILE *fp; struct szemely szm[SIZE]; struct szemely *psz; int i; void sz load(struct szemely *); // Inicializálás for(i=0; i<SIZE; i++) { strcpy(szm[i].nev," strcpy(szm[i].cim," szm[i].fiz = 0L; } "); "); // A struktúra feltöltése psz = &szm[0] ; sz load( psz ) ; // A file megnyitása írásra if( (fp=fopen("szemely1.dat","wt")) == NULL ) { printf(" Hiba a file megnyitásnál -> IRÁS!"); exit(0); } 3 16.4 File vége ( End Of File ) vizsgálat // Kiiratás a file-ba fwrite(psz, sizeof(szm[0]), 5, fp); // A file lezárása fclose(fp); // A file megnyitása olvasásra if( (fp=fopen("szemely1.dat","rt")) == NULL ) { printf(" Hiba a file megnyitásnál -> OLVASÁS !"); exit(0); } // Beolvasás a file-ból fread(psz, sizeof(szm[0]), 5, fp) ; // A beolvasott adatok kiírása képernyôre for(i=0; i<SIZE; i++) {

printf(" %s %s %ld",szm[i].nev,szm[i]cim,szm[i]fiz); } fclose(fp); } void sz load( struct szemely *p sz ) { char *cj; int j; for(j=0; j<SIZE; j++) { strcpy( (p sz+j)->nev,"Kovács ") ; itoa(j,cj,10) ; strcat( (p sz+j)->nev,cj); strcpy( (p sz+j)->cim,"Pécs "); strcat( (p sz+j)->cim,cj); (p sz+j)->fiz = (long) 20000+j; } } #include <stdio.h> #define SIZE 5 struct szemely { char nev[26]; char cim[26]; long fiz; }; 4 16.4 File vége ( End Of File ) vizsgálat void main() { FILE *fp; struct szemely szm[SIZE]; struct szemely *psz; int i; void sz load(struct szemely *); // Inicializálás for(i=0; i<SIZE; i++) { strcpy(szm[i].nev," strcpy(szm[i].cim," szm[i].fiz = 0L; } "); "); // A struktúra feltöltése psz = &szm[0] ; sz load( psz ) ; // A file megnyitása írásra if( (fp=fopen("szemely2.dat","wb")) == NULL ) { printf(" Hiba a file megnyitásnál -> IRÁS!");

exit(0); } // Kiiratás a file-ba fwrite(psz,sizeof(szm[0]),5,fp); fclose(fp); // A file megnyitása olvasásra if( (fp=fopen("szemely2.dat","rb")) == NULL ) { printf(" Hiba a file megnyitásnál -> OLVASÁS !"); exit(0); } // Beolvasás a fileból fread(psz,sizeof(szm[0]),5,fp) ; // A beolvasott adatok kiírása képernyôre for(i=0;i<SIZE;i++) { printf(" %s %s %ld",szm[i].nev,szm[i]cim,szm[i]fiz); } fclose(fp); } void sz load( struct szemely *p sz ) { char *cj; 5 16.4 File vége ( End Of File ) vizsgálat int j; for(j=0; j<SIZE; j++) { strcpy( (p sz+j)->nev,"Kovács") ; itoa(j,cj,10) ; strcat( (p sz+j)->nev,cj); strcpy( (p sz+j)->cim,"Pécs"); strcat( (p sz+j)->cim,cj); (p sz+j)->fiz = (long) 20000+j; } } 44. sz példaprogram a parancssor argumentum használatára, file-ok kezelése esetén : /* C fileok másolása ARGC, ARGV argomentumokkal. */ #include <stdio.h> main( argc, argv) int

argc; char *argv[]; { FILE *mit; FILE *hova; char infile[20], outfile[20]; int i,c; printf(" ARGC értéke = %d",argc); for(i=0; i<argc; i++) { printf(" ARGV[%d] = %s",i,argv[i]); } // Az argv[1] által mutatott file megnyitása if( (mit=fopen(argv[1],"r")) == NULL ) { printf(" Nincs input file ") ; exit(0) ; } // Az argv[2] által mutatott file megnyitása if( (hova=fopen(argv[2],"w")) == NULL) { printf(" Az output file nem nyitható meg ! ") ; exit(0) ; } // Elôolvasás 6 Feladatok a 16. fejezet anyagából c = fgetc(mit); // Másolás ciklusa while( !feof(mit) ) { fputc(c,hova); c = fgetc(mit); } // File-ok lezárása fclose(mit); fclose(hova); } Feladatok a 16. fejezet anyagából 1.) Készítsünk - parancssor argumentum felhasználásával - olyan programot, amely összefûz két C forrásprogramot. Az elsô argumentum legyen annak a programnak a neve amihez hozzá akarunk fûzni, a második pedig a

hozzáfûzendô program neve Például : illeszt.exe elsoc masodikc Az összefûzött állomány neve az elsô argumentum legyen, jelen esetben tehát : elso.c 2.) Készítsünk - parancssor argumentum felhasználásával - olyan programot, amely a képernyôre listázza azt a C forrásprogramot, amelynek a nevét megadjuk. ( Hasonlít a DOS type parancsára ) Legyen lehetôség a -p kapcsoló opcionális megadására, amely azt jelenti, hogy egy képernyô lista után, a program várakozzon egy billentyû lenyomására és azután folytassa a listát. 3.) Tekintsük a már ismert konfig típusú struktúrát Ennek alapján definiáljunk egy 10 elemû struktúratömböt, töltsük fel adatokkal, és az fwrite() függvény alkalmazásával írjuk ki az adatokat egy tetszôleges nevû "b" módú file-ba. Ezekután a következô mûveleteket hajtsuk végre - menüvezérléssel : 1.) Olvassuk be a file-t és válasszuk ki a legdrágább konfigurációt, majd irassuk ki az

adatait a képernyôre. 2.) Kérjünk be klaviatúráról egy printer megnevezést, és irassuk ki azokat a konfigurációkat a képernyôre, amelyeknek printer typ tagja megegyezik ezzel a megnevezéssel. 7 Feladatok a 16. fejezet anyagából 3.) Kérjünk be klaviatúráról egy sorszámot 0 és 9 között. Irassuk ki az ennyiedik konfiguráció adatait a képernyôre és tegyük lehetôvé a módosítást. ( Új adatok bevitelét a régiek felülírásával ! ) 4.) Olvassuk be az elôbb létrehozott file-t egy alkalmas adatszerkezetbe, és rendezzük sorba az alaplap typ tag szerint. A rendezett állományt irassuk ki egy file-ba. 5.) Egy klaviatúráról bekért - 0 és 9 közé esô - sorszám alapján töröljük a megfelelô sorszámú konfigurációt. A törlés a memóriában történjen olymódon, hogy ha például az 5. számú konfigurációt akarjuk törölni, akkor ezt felülírjuk a 6.-sal, a 6-t a 7-sel stb Az így kapott adatsort irassuk ki egy file-ba. 8

Függelék A Borland C++ 2.0 alapvetô grafikai függvényei Az alapvetô grafikai függvények ismertetése elôtt néhány megjegyzést kell tenni, azok használatával kapcsolatban : 1.) A grafikai függvényeket használó programnak tartalmaznia kell a #include <graphics.h> direktívát 2.) A linkelésnél a graphics.lib-et hozzá kell linkelni a tárgymodulhoz 3.) Szükséges a grafikus kártya vezérlôk (driver-ek) használata. Ezeknek a file-oknak a kiterjesztése a .BGI és a Borland C fordító /BGI alkönyvtárában helyezkednek el. 4.) A változó ill. függvénydeklarációban szereplô far kifejezés azt jelenti, hogy a változó bárhol elhelyezkedhet a memóriában, nem csak az alapértelmezés szerinti adatszegmensben. Függvény esetében, az illetô függvény bárhol elhelyezkedhet a memóriában, nemcsak az alapértelmezés szerinti kódszegmensben 5.) mindig A képernyô koordinátákra vonatkozóan : a grafikus képernyôn a bal felsô sarok

jelenti a ( 0,0 ) pontot ! 6.) A függvények mûködését a 45. sz példaprogram mutatja be Ezen megjegyzések után tekintsük át a fontosabb grafikai függényeket : A grafikus rendszer inicializálása : initgraph() void far initgraph( int far *graphdriver, int far graphmode, char far pathtodriver ) ; ahol : graphdriver a grafikus kártya típusa, jellemzô értékei a következôk : CGA = 1 EGA = 3 89 VGA = 9 HERCMONO = 7 DETECT = 0 Ha a DETECT-et adjuk meg (lásd 45. sz példaprogram), akkor a grafikus kártya típusa és az üzemmód automatikusan kiválasztásra kerül graphmode a grafikus üzemmód pathtodriver az aktuális .BGI file-t tartalmazó alkönyvtár elérési útvonala, például : "s:\borlandc\bgi\" Bármilyen grafikai mûveletet tartalmazó programot az initgraph() függvény meg hívásával kell kezdeni. Ez a függvény tölti be az aktuális grafikus meghajtót, és a rendszert a megfelelô grafikus módba helyezi. A grafikus üzemmód

lezárása : closegraph() void far closegraph( void ) ; Visszaállítja az eredeti képernyô üzemmódot, és felszabadítja a grafikához allokált memóriát. Hibakezelés : graphresult() int far graphresult( void ) ; Az utoljára végrehajtott grafikai mûvelet hibakódját adja vissza. A hibakódok a következôk : grOK grNoinitGraph grNotDetected grFileNotFound . 0 -1 -2 -3 Nincs hiba Nincs .BGI file installálva Nincs grafikus kártya Nem találja a .BGI file-t Hibaüzenet : grapherrormsg() char far *grapherrormsg( int errorcode ) ; ahol : errorcode a hiba kódja, amelyet rendszerint a graphresult() függvénnyel tudunk lekérdezni. A hibakódhoz tartozó hibaüzenet szövegére mutató pointert ad vissza. Az aktuális üzemmód maximális X koordinátája : getmaxx() int far getmaxx( void ) ; A visszaadott érték grafikus kártya típusonként változik. Az aktuális üzemmód maximális Y koordinátája : getmaxy() int far getmaxy( void ) ; A visszaadott érték

grafikus kártya típusonként változik. Szöveg helyzetének beállítása : settextjustify() void far settextjustify( int horiz, int vert ); ahol : horiz a vízszintes beállítás vert a függôleges beállítás Az elôre definált konstansok a következôk : Vízszintes Szöveg pozíció LEFT TEXT =0 CENTER TEXT = 1 RIGHT TEXT = 2 Szöveg eleje, azaz bal oldala Szöveg közepe Szöveg vége, azaz jobb oldala Függôleges BOTTOM TEXT = 0 CENTER TEXT = 1 =2 TOP TEXT Szöveg pozíció Szöveg alja Szöveg közepe Szöveg teteje Szöveg megjelenítése képernyôn : outtextxy() void far outtextxy( int x, int y, char far *textstring ); ahol : x, y a szöveg kezdetének képernyô koordinátái textstring a kiiratni kívánt szövegre mutató pointer A függvény a már korábban beállított betûtípussal, mérettel és beállítással helyezi el a képernyôn a szöveget. Ha például a settextjustify() függvénnyel mind vízszintes mind függôleges irányban középre

állítottuk be a szöveget, akkor az x, y koordináták közül az x a szöveg horizontális közepét, az y a vertikális közepét jelöli ki. Rajzolás színének beállítása : setcolor( ) void far setcolor( int color ); ahol : color a rajzolás színe Maximális színérték lekérdezése : getmaxcolor() int far getmaxcolor( void ); Az aktuális rendszer maximális színértékét adja vissza. Adott képpont kifestése adott színnel : putpixel() void far putpixel( int x, int y, int color ) ahol : x, y a pont koordinátái color a pont színe Vonal stílusának beállítása : setlinestyle() void far setlinestyle( int linestyle, unsigned hpattern, int thickness ); ahol : linestyle a vonal stílusa ( szaggatott, pont-vonal stb. ) hpattern thickness a vonal vastagsága Egyenes rajzolás : line() void far line ( int x1, int y1, int x2, int y2 ); ahol : x1, y1 a kezdôpont koordinátái x2, y2 a végpont koordinátái Az egyenest a már korábban definált színnel és vonal

stílussal rajzolja meg. Téglalap rajzolás : rectangle() void far rectangle( int left, int top, int right, int bottom ); ahol : left, top a téglalap bal felsô sarkának koordinátái right, bottom a téglalap jobb alsó sarkának koordinátái A téglalapot a már korábban definált színnel és vonal stílussal rajzolja meg. Kör rajzolás : circle() void far circle( int x, int y, int radius ); ahol : x, y a kör középpontja radius a kör sugara Csak azokat a grafikai függvényeket ismertettük, amelyeket a most következô - 45. sz - példaprogram tartalmaz. A többi függvény ismertetése megtalálható a Borlandc C++ 2.0 Help-jében ! 45. sz példaprogram : Egyszerû grafikai program az eddig ismertetett függvények mûködésének bemutatására. #include #include #include #include <stdio.h> <conio.h> <graphics.h> <stdlib.h> // A getch() függvény miatt // A grafikus függvények miatt // Az exit() függvény miatt int main( void ) { int

gdriver = DETECT, gmode, errorcode; int x, y, k, l; // A grafikai rendszer inicializálása // következik initgraph( &gdriver, &gmode, "s:\borlandc\bgi"); // Hiba lekérdezés következik errorcode = graphresult(); // Hiba vizsgálat következik if( errorcode != grOk ) { printf(" Hiba a grafikánál : %s ! ", grapherrormsg(errorcode) ); getch() ; exit( 1 ) ; } // A legnagyobb x,y képernyôkoordináták // lekérdezése következik k = getmaxx() ; l = getmaxy() ; printf(" MAX X = %d MAX Y = %d ", k, l); getch(); // Szöveg beállítás és kiiratása következik x = getmaxx()/2 ; y = getmaxy()/2 ; settextjustify( CENTER TEXT,CENTER TEXT ); outtext( x, y, "Grafikus mód" ); // Színbeállítás és kör rajzolás következik setcolor( getmaxcolor() ); circle( 100, 100, 100 ); // Képernyô pont világoskékre történô ki// festése következik putpixel( 100, 100, LIGHTBLUE ); // Piros szín- ill. vonalstílus beállítás //

következik setcolor( RED ) ; setlinestyle( 0, 1, 1 ); // Egyenes rajzolás következik line( 0, l, 0, k ); // Sárga szín beállítás és téglalap rajzolás // következik setcolor( YELLOW ); rectangle( 50, 50, 100, 100 ); // Várakozunk egy billentyû lenyomására getch(); // A grafikus rendszer lezárása következik closegraph(); // Visszatértünk karakteres módba printf(" Text mód "); getch(); return(0); } Megjegyzés : módosításokkal Ajánlatos az itt közölt programot különféle is lefuttani. Módosithatjuk például a szöveg ill szín beállításokat Változtassuk meg a vonalstílus beállítását is ! Kidolgozott feladatok 2. - 3 - 4 fejezet 1. feladat Irjunk programot, amely egy double típusú szám - mint sugár - alapján kiszámítja és kiírja a képernyôre a következôket : - az adott sugarú kör kerületét és területét - az adott sugarú gömb felszínét és térfogatát #include <stdio.h> #include <math.h>

#include <conio.h> #define PI 3.1457 void main() { double r, ker, ter, felsz, terf; clrscr() ; printf(" Kérem a sugarat : ") ; scanf("%lf",&r) ; // Számítások következnek ker ter felsz terf = = = = 2*PIr ; pow(r,2)*PI ; 4*pow(r,2)PI ; 4*pow(r,3)PI/3; // Kiiratások következnek printf(" ----------------------------------- "); printf(" A kör kerülete : %10.3lf ",ker); printf(" A kör területe : %10.3lf ",ter); printf(" A gömb felszíne : %10.3lf ",felsz); printf(" A gömb térfogata : %10.3lf ",terf); getch(); } 2. feladat 102 2. - 3 - 4 fejezet Irjunk programot, amely kilistázza a képernyôre a Fibonacci számsor elsô n tagját. Az n értékét a program a klaviatúráról várja A Fibonacci számsor kiszámítására a következô szabály érvényes : F0 = 0 ; F1 = 1 ; Fi = Fi-1 + Fi-2 #include <stdio.h> #include <conio.h> ( i >= 2 ) /* A getch() miatt

szükséges / void main() { int n, fee, fe, fib, i; printf("Kérem n értékét : ") ; scanf("%d",&n) ; fee = 0 ; fe = 1 ; for(i=2; i<=n; i++) { fib = fe + fee; printf(" FIB[%3d] = %5d",i,fib); fee = fe ; fe = fib ; } printf(" "); getch(); /* Egy karakter lenyomására vár / } 3. feladatat Irjunk programot, amely kiszámítja az 1 - 1/3 + 1/5 - 1/7 . végtelen sor összegét, tetszôleges pontossággal. A kívánt pontosságot a program a klaviatúráról várja Ellenôrzésül : a sor összege /4. 103 Kidolgozott feladatok #include <stdio.h> #include <math.h> /* A fabs() ill. pow() függvények */ /* miatt szükséges / #include <conio.h> void main() { double n, e, s, os; printf(" Kérem a pontosságot : ") ; scanf("%lf",&e) ; s // Az elsô összeg legyen 1 = 1 ; // A régi összeg legyen 0. os = 0 ; n = 1 ; // Amíg a két összeg különbsége nagyobb a hibahatárnál while(

fabs( s - os ) > e ) { // Az eddigi összeg legyen a régi összeg. os = s ; n += 1 ; // Számoljunk új összeget s += pow( -1, n-1 ) * (1.0/(2*n-1)) ; } printf(" A sor összege : %lf",s); getch() ; } 4. feladat Irjunk programot, amely beolvas egy egész számot. A szám 2, 3 ill 4 jegyû lehet. Ezt le is kell ellenôrizni Az ellenôrzés után a program fordítsa meg a számot, és írja ki a képernyôre. A szám negatív is lehet ! #include <stdio.h> #include <math.h> #include <conio.h> 104 2. - 3 - 4 fejezet main() { int n, jegyek,vane; long szam,absszam,e,t,sz,ez,hanyados,maradek,ujszam; do { do { } printf(" Kérem a számot : ") ; scanf("%ld",&szam) ; absszam = labs(szam); while( absszam%1 !=0 || absszam/10 < 1 || absszam/1000 > 9 ); // Most megállapítjuk, hogy hány jegyü a szám n=3 ; hanyados = 0 ; while( n>0 && hanyados == 0 ) { hanyados = absszam/(long) pow( 10,(double) n ); n-- ; } jegyek =

n+2 ; switch( jegyek ) { case 2: e = absszam/10 ; t = absszam%10 ; ujszam = 10*t+e ; break; case 3: e = absszam/100 ; maradek = absszam%100 ; t = maradek/10 sz = maradek%10 ; ; ujszam = 100*sz + 10t + e; break; case 4: e = absszam/1000 ; maradek = absszam%1000 ; t = maradek/100 ; 105 Kidolgozott feladatok maradek = maradek%100 sz = maradek/10 ez = maradek%10 ; ; ; ujszam = 1000*ez + 100sz + 10t + e; break; default: break; } if( szam > 0 ) { printf(" A megfordított szám = %ld ",ujszam); } else { printf(" A megfordított szám = %ld ",-1*ujszam); } printf(" Van - e még szám (i/n) : ") ; vane = getche() ; } while( vane == i ); } 5. fejezet 1. feladat Adva van két 10 elemû, integer típusú vektor. Irjunk progamot, amely az elsôt a buborékrendezés, a másikat a javított buborékrendezés módszerével rendezi. #include <stdio.h> #include <conio.h> void main() { int x[10] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int y[10] = {

10, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 106 5. fejezet int i, j, csere, s; // Sima buborékrendezés clrscr(); for(i=0; i<10-1; i++) { for(j=0; j<10-i-1; j++) { if( x[j] > x[j+1] ) { s = x[j] ; x[j] = x[j+1] ; x[j+1] = s ; } } } printf(" Sima buborékrendezés, menetek száma: %d ",i); for(i=0; i<10; i++) printf("%3d",x[i]); printf(" "); // Javított buborékrendezés csere = 1 ; for(i=0; csere; i++) { csere = 0 ; for(j=0; j<10-i-1; j++) { if( y[j] > y[j+1] ) { s=y[j] ; y[j]=y[j+1] ; y[j+1]=s ; csere=1 ; } } } printf(" Jav.buborékrendezés, menetek száma : %d ",i); for(i=0; i<10; i++) printf("%3d",y[i]); printf(" ");getch(); } 2. feladat Adva van egy 5x5-ös mátrix. Irjunk programot amely a fôátlójára tükrözi ! #include <stdio.h> #include <conio.h> void main() { int a[5][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,15, 16,17,18,19,20, 107 Kidolgozott feladatok 21,22,23,24,25

}; int i,j,s; clrscr(); printf(" EREDETI : "); printf(" "); for(i=0; i<5; i++) { for(j=0; j<5; j++) { printf(" %2d",a[i][j]); } printf(" "); } // Most következik a mátrix tükrözése for(i=0; i<5; i++) { for(j=i; j<5; j++) { s = a[j][i]; a[j][i] = a[i][j]; a[i][j] = s; } } printf(" TÜKRÖZÖTT : ");printf(" "); for(i=0; i<5; i++) { for(j=0; j<5; j++) { printf(" %2d",a[i][j]); } printf(" "); } getch(); } 3. feladat Adva van egy 2x3 - as és egy 3x2 - es mátrix. Irjunk programot, amely összeszorozza ôket ! #include <stdio.h> #include <conio.h> #define N 3 #define M 2 main() { int a[N][M] = { 1, 2, 3, 4, 108 5. fejezet 5, 6 int b[M][N] = }; { 1, 2, 3, 4, 5, 6 }; long c[N][N]; int i, j, k; for(i=0; i<N; i++) { for(j=0; j<N; j++) { c[i][j]=0L; for(k=0; k<M; k++) { c[i][j] += a[i][k]*b[k][j]; } } } clrscr(); for(i=0; i<N; i++) { for(j=0; j<N; j++) {

printf("C[%d][%d] = %3ld%c",i,j,c[i][j], (j == N-1) ? : ); } } getch(); } Megjegyzés : Az itt bemutatott programok egyelôre csak konkrét adatokra mutatták be a nyelv lehetôségeit ! A pointerekre vonatkozó fejezetben vizsgáljuk meg, az általános megoldások lehetôségét ! 109 Kidolgozott feladatok 6. fejezet 1. feladat Irjunk egy egyszerüsített morze jeleket elôállító programot ! A program inputja egy négyjegyü egész szám ! Le is kell ellenôrizni, hogy valóban négyjegyü-e ! A számot elôször átkódoljuk úgy, hogy az egyeseket a százasokkal ill. a tízeseket az ezresekkel cseréljük fel Az így kapott számot kell morze jelek sorozatává alakítani a következôképpen : Az elsô jel a START legyen, ezt három szóköz kövesse. Ezután következzen a kódnak megfelelô jelsorozat szóközökkel elválasztva. Ezt a jelsorozatot kövesse három szóköz ill a STOP jel. Mindaddig "morzézni" kell amíg az i billentyüt nyomjuk

le a program által feltett kérdésre. A szükséges morze kódok a következôk : START = -.-1 = ---- 2 = .--- 3 = .-- 4 = .- 5 = . 6 = -. 7 = --. 8 = ---. 9 = ----. 0 = ----- STOP = .-- #include <stdio.h> #include <conio.h> void main() { int kod, ez, sz, tz, eg, ujkod, szamjegy, valasz, i; clrscr(); do { kod = 0 ; printf(" Kérem a számot : "); do { scanf("%d",&kod); } while(kod<1000 || kod>9999); ez = kod/1000 ; sz = (kod - ez*1000)/100 ; tz = (kod - ez*1000 - sz100)/10 ; eg = (kod - ez*1000 - sz100 - tz10 ); ujkod = 1000*tz + 100eg + 10ez + sz ; printf(" A számnak megfelelô kod : %4d ",ujkod); printf(" ") ; printf("-.-") ; // START jel 110 6. fejezet for(i=1; i<=4; i++) { if( i==1 ) { szamjegy = } else if( i==2 ) { szamjegy = } else if( i==3 ) { szamjegy = } else szamjegy = tz; eg; ez; sz; switch(szamjegy) { case 0: printf("----break; case 1: printf(".---break; case 2:

printf(".--break; case 3: printf(".-break; case 4: printf(".break; case 5: printf(". break; case 6: printf("-. break; case 7: printf("--. break; case 8: printf("---. break; case 9: printf("----. break; default: printf("7"); break; } "); "); "); "); "); "); "); "); "); "); } 111 Kidolgozott feladatok printf(" .--") ; // STOP jel printf(" További szám (i/n) : "); valasz = getche() ; } while( valasz == i ); } 2. feladat Irjunk programot, amely beolvas egy karakter típusú vektorba egy számot. A szám max. 6 db egész jegyet, tizedespontot és két tizedesjegyet tartalmaz Igazítsuk a számot jobbra úgy, hogy a formátuma 92 legyen ! #include <stdio.h> #include <conio.h> #include <string.h> void main() { char balra[10], jobbra[10]; int i, tizedes, volt tizedes, valasz; clrscr(); do { strcpy(balra," strcpy(jobbra," . ")

; "); do { printf(" Kérem a számot : ") ; scanf("%s",balra); } while( strlen(balra) > 9 ); volt tizedes=0; for(i=0; i<strlen(balra); i++) { if( balra[i] == . ) { tizedes = i ; volt tizedes = 1 ; break ; } } if(volt tizedes == 0) 112 7. fejezet { balra[i] = .; tizedes = i; } for( i=7 ; i<9 ; i++) { jobbra[i] = ( volt tizedes && balra[tizedes+i-6] != && balra[tizedes+i-6] != 32) ? balra[tizedes+i-6] : 0 ; } for( i=5 ; tizedes > 0; tizedes-- , i-- ) { jobbra[i] = balra[tizedes-1]; } // Helyiérték jelzô printf(" 123456.78"); // A jobbraigazított szám és hossza printf(" %s %d ",jobbra,strlen(jobbra)); printf(" További átalakítás (i/n) : "); valasz = getche(); } while( valasz == i ); } 7. fejezet 113 Kidolgozott feladatok 1. feladat Irjunk programot, amely függvény alkalmazásával meghatározza n a értékét, az általunk megadott pontossággal, iterációval. Az iteráció

képlete a következô: xuj = xregi + ( 1/n ) * ( a/xregin-1 - xregi ) ; ahol : xuj : a kiszámolandó érték, xregi : az elôzôleg kiszámolt érték a : az alap, n : a gyökkitevô Az iteráció befejezôdik, ha | xuj - xregi | < e ; ahol : e a pontosság értéke. #include <stdio.h> #include <conio.h> #include <math.h> void main() { int valasz; // Az iter függvény prototípusa double iter( double, double, double ); double n, a, e, gyok; clrscr(); do { printf(" "); printf("Kérem a gyökkitevôt : "); scanf("%lf",&n); printf("Kérem az alapot : "); scanf("%lf",&a); printf("Kérem a hibahatárt : "); scanf("%lf",&e); // Az iter függvény meghívása és a visszatérô érték // átadása a gyok változóba gyok = iter( n, a, e ) ; printf(" A^(1/N) = %lf ",gyok); printf(" További iteráció (i/n) : ") ; valasz = getche() ; } while( valasz == i ); } // Az

iter függvény megvalósítása 114 7. fejezet double iter( double kitevo, double alap , double hiba ) { double xuj, xregi; xuj = alap ; xregi = 0 ; do { xregi = xuj ; xuj = xregi + (1/kitevo)*( alap/pow(xregi,kitevo-1) - xregi ); } while( fabs(xuj - xregi) > hiba ) ; // A gyök értékével tér vissza a függvény return( xuj ); } 2. feladat Irjunk programot, amely beolvas egy kétjegyû számot és kiírja szövegesen. #include <stdio.h> #include <conio.h> main() { void egyesek ( int ); // Az egyesek függvény prototípusa int szam,tizes,egyes,vane; do { do { printf(" Kérem a kétjegyü számot : ") ; scanf("%d",&szam) ; } while( szam%1 != 0 || szam/10 < 1 || szam/10 > 9 ); tizes = szam/10 ; egyes = szam%10 ; switch( tizes ) { case 1: if( egyes == 0 ) { printf(" Tiz") ; } 115 Kidolgozott feladatok else { printf(" Tizen"); } break; case 2: if( egyes == 0 ) { printf(" Húsz") ; } else {

printf(" Huszon"); } break; case 3: printf(" Harminc"); break; case 4: printf(" Negyven"); break; case 5: printf(" Ötven") ; break; case 6: printf(" Hatvan"); break; case 7: printf(" Hetven"); break; case 8: printf(" Nyolcvan"); break; case 9: printf(" Kilencven"); break; default: break; } /* End SWITCH / // Az egyesek függvény hívása egyesek( egyes ) ; printf(" Ft "); printf(" Van-e még szám (i/n) : ") ; vane = getche() ; } while( vane == i ); } // Az egyesek függvény megvalósítása void egyesek( int e ) { 116 switch( e ) { case 1: printf("egy") ; break; case 2: printf("kettô"); break; case 3: printf("három"); break; case 4: printf("négy"); break; case 5: printf("öt"); break; case 6: printf("hat"); break; case 7: printf("hét"); break; case 8: printf("nyolc"); break; case 9:

printf("kilenc"); break; default: break; } } 8. fejezet 1. feladat 117 Kidolgozott feladatok Irjunk programot, amely beolvas egy long értéket, és a long változó négy byteját rendre egy-egy karakteres típusú változóban helyezi el ! #include <stdio.h> #include <conio.h> void main() { char a, b, c, d, *x; long l; clrscr() ; printf(" Kérem a long változó értékét : ") ; scanf("%ld",&l); x = (char *) &l ; printf(" x = %p", x ); a b c d = = = = *(x+0) *(x+1) *(x+2) *(x+3) ; ; ; ; printf(" l printf(" a printf(" b printf(" c printf(" d = = = = = %ld",l) ; %c", a ); %c", b ); %c", c ); %c", d ); getch(); } 2. feladat Irjunk programot, amely beolvas négy karaktert, és elhelyezi ôket egy long típusú változó négy byte-ján ! #include <stdio.h> #include <conio.h> void main() { char a, b, c, d, long l; clrscr() ; 118 *x; 8. fejezet

printf(" Kérem scanf("%c",&a); fflush(stdin) ; printf(" Kérem scanf("%c",&b); fflush(stdin) ; printf(" Kérem scanf("%c",&c); fflush(stdin) ; printf(" Kérem scanf("%c",&d); fflush(stdin) ; a értékét : "); b értékét : "); c értékét : "); d értékét : "); x = (char *) &l ; printf(" x = %p ",x); *(x+0) *(x+1) *(x+2) *(x+3) = = = = a b c d ; ; ; ; printf(" l = %ld ",l); getch(); } 3. feladat Irjunk programot, amely egy nyolc karakterbôl álló üzenetet kódol ( titkosít ) egy double típusú változóban, majd - fordított sorrendben - dekódolja az üzenetet ! #include #include #include #include <stdio.h> <conio.h> <string.h> <float.h> void main() { char sz[9],uj[9], *x; int i; double d; clrscr(); strcpy(sz,"ABCDEFGH"); 119 Kidolgozott feladatok // x felveszi a d kezdôcímét x = (char *) &d; //

Titkosítás for(i=0; i<8; i++) { *(x+i) = sz[i]; } // (x+i) mindig a soron következô egy byte címét adja // meg for(i=0; i<8; i++) { printf(" %c",*( ((char ) &d)+i ) ); } printf(" "); // Az üzenet megfordítása for(i=0; i<8; i++) { uj[i] = *( ((char ) &d) + 7-i ); } uj[8]=; printf(" D = %lf",d); printf(" UJ = %s ",uj); getch(); } 9. fejezet 1. feladat Irjunk programot, amely a 8. fejezet 2 feladatát ( 118 oldal ) függvény alkalmazásával oldja meg. Bemenô paraméterek : a négy karakter és a long változó címe. 120 9. fejezet #include <stdio.h> #include <conio.h> #include <string.h> void main() { void elhelyez( char, char, char, char, long * ); char a, b, c, d; long l; clrscr() ; printf(" Kérem scanf("%c",&a); fflush(stdin) ; printf(" Kérem scanf("%c",&b); fflush(stdin) ; printf(" Kérem scanf("%c",&c); fflush(stdin) ;

printf(" Kérem scanf("%c",&d); fflush(stdin) ; a értékét : "); b értékét : "); c értékét : "); d értékét : "); elhelyez( a, b, c, d, &l ); printf(" l = %ld ",l); getch(); } void elhelyez( char ea, char eb, char ec, char ed, long *el) { char *x; x = (char *) el ; printf(" x = %p ",x); *(x+0) *(x+1) *(x+2) *(x+3) = = = = ea eb ec ed ; ; ; ; } 2. feladat Irjunk programot, amely beolvas három double értéket. Döntse el, hogy lehet-e háromszöget szerkeszteni belôlük, és ha igen akkor milyen típusút ! #include <stdio.h> #include <conio.h> 121 Kidolgozott feladatok void main() { void kivalaszt( double *, double , double ); int van meg; double a,b,c, mx; do { clrscr(); printf(" Kérem A oldal értékét: "); scanf("%lf",&a); printf(" Kérem B oldal értékét: "); scanf("%lf",&b); printf(" Kérem C oldal értékét:") ;

scanf("%lf",&c); // A legnagyobb oldal kiválasztása a c változóba kivalaszt( &a, &b, &c ); printf(" A = %lf B = %lf C = %lf ",a,b,c) ; if( a + b <= c ) { printf("Nem szerkeszthetô: %lf+%lf<=%lf",a,b,c ); } else if( a*a + bb == cc ) { printf(" Derékszögü: %lf+%lf=%lf",a*a,bb,cc); } else if( a == b && b == c ) { printf(" Egyenlôoldalú: %lf=%lf=%lf",a,b,c); } else if( a == b || a == c || b == c ) { printf(" Egyenlôszárú : %lf %lf %lf",a,b,c); } else { printf(" Általános : %lf , %lf , %lf",a,b,c); } printf(" További adatok (i/n): "); van meg=getche(); } while( van meg ); } void kivalaszt( double *ca, double cb, double cc) { void csere( double *, double ); if( *ca > cb ) { if( *ca > cc ) { 122 10. fejezet csere( ca, cc ); ) } else { if( *cb > cc ) { csere( cb, cc ); } } } void csere( double *csa, double csb ) { double mx; mx = *csa ; *csa = csb ;

*csb = mx ; } 10. fejezet 1. feladat Irjuk meg az 5. fejezet 3 programját (109 oldal) általánosan ! Mutassuk meg két esetben a mátrixszorzó függvény mûködését ! 123 Kidolgozott feladatok #include <stdio.h> #include <conio.h> #include <float.h> void main() { // A mat mult függvény prototípusa. A paraméterek // jelentését lásd a hívásnál ! void mat mult(double *,double ,double ,int,int,int); double a[3][2] = { {1 , 2}, {3 , 4}, {5 , 6} }; double b[2][3] = { {1, 2, 3}, {4, 5, 6} }; double c[2][5] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9,10} }; double x[3][3], y[3][5]; // Az elsô mátrixszorzás az a * b = x lesz, // A második az a * c = y ! int i, j, n, m, q; clrscr(); // // // // A függvény hívásának elôkészítése : n jelenti a szorzandó mátrix sorainak számát, m jelenti a szorzó mátrix sorainak számát valmint q az eredmény mátrix oszlopainak számát ! n = 3 ; m = 2 ; q = 3 ; // // // // // // // A függvény hívása : az

elsô paraméter a szorzandó mátrix kezdô elemének a címe, a második paraméter a szorzó mátrix kezdô elemének a címe, a harmadik pedig az eredmény mátrix kezdô elemének a címe ! A negyedik, ötödik ill. hatodik paraméter értéke rendre az elôbb megimert n, m és q ! Ez a függvényhívás az a * b = x szorzást végzi el ! mat mult( &a[0][0], &b[0][0], &x[0][0], n, m, q ); 124 12. - 15 fejezet // Az eredmény kiiratása for(i=0; i<n; i++) { for(j=0; j<q; j++) { printf("%7.2lf%c",x[i][j],(j == q-1) ? : ); } } getch(); printf(" "); // Elôkészület a * c = y szorzáshoz n = 3 ; m = 2 ; q = 5 ; // A szorzás elvégzése mat mult( &a[0][0], &c[0][0], &y[0][0], n, m, q ); // Az eredmény kiiratása for(i=0; i<n; i++) { for(j=0; j<q; j++) { printf("%7.2lf%c",y[i][j],(j == q-1) ? : ); } } getch(); } void mat mult( double *mm1, double mm2, double mm3, int mmn, int mmm, int mmq ) { int i, j,

k; for(i=0; i<mmn; i++) { for(j=0; j<mmq; j++) { *(mm3+immq+j)=0.0; for(k=0; k<mmm; k++) { *(mm3+immq+j)+= (mm1+immm+k) (mm2+kmmq+j); } } } } 12. - 15 fejezet 1. feladat Irjunk programot, amely meglévô adatállományok ( JATEKOS.DAT ill CSAPAT.DAT ) alapján kilistázza az NB I-es játékosok adatait úgy, hogy a csapat kódja helyett, annak megnevezése szerepel ! 125 Kidolgozott feladatok #include #include #include #include <stdio.h> <conio.h> <string.h> <stdlib.h> // Az strcpy() függvény miatt // Az exit() függvény miatt #define SIZE 16 struct jatekos { char knev[15]; char vnev[10]; int szulev; int cs kod; int meccs; int gol; }; struct csapat { int cs kod; char cs nev[15]; }; void main() { void cs load(struct csapat *); FILE *fj; struct jatekos j; struct csapat cs[SIZE]; struct csapat *pc; int i; // Inicializálás strcpy(j.knev," strcpy(j.vnev," for(i=0; i<SIZE; i++) { strcpy(cs[i].cs nev," } "); ");

"); // A csapat struktúratömb feltöltése adatokkal pc = &cs[0] ; cs load( pc ) ; // A JATEKOS file megnyitása olvasásra */ if( (fj=fopen("jatekos.dat","rt")) == NULL ) { printf(" Hiba a JATEKOS file megnyitásnál !") ; exit(0) ; } 126 12. - 15 fejezet clrscr(); pc = &cs[0] ; // Fejléc printf(" Vezetéknév Keresztnév Sz.é Csapat" " Meccs Gól "); printf(" ------------------------------------------" "------------------- "); // Elôolvasás fscanf(fj,"%s %s %d %d %d %d", j.knev,jvnev,&jszulev,&jcs kod,&jmeccs,&jgol); // Olvasó ciklus kezdôdik while( !feof(fj) ) { printf(" %-15s %-10s %4d %-15s %4d %4d", j.knev,jvnev,jszulev,(pc+jcs kod-1)->cs nev, j.meccs,jgol); fscanf(fj,"%s %s %d %d %d %d",j.knev, jvnev, &j.szulev,&jcs kod,&jmeccs,&jgol); } getch() ; fflush(fj) ; fclose(fj); } void cs load( struct csapat *p c ) { FILE *fc;

int j; // Megnyitás olvasásra if( (fc=fopen("csapat.dat","rt")) == NULL ) { printf(" Hiba a csapat file megnyitásnál !"); exit(0); } for(j=0; j<SIZE; j++) { fscanf( fc,"%d",&(p c+j)->cs kod ); fscanf( fc,"%s",(p c+j)->cs nev ); } fflush(fc) ; fclose(fc) ; } 2. feladat Irjunk programot, amely a paraméteréül megadott C forrásprogramban megszámolja a ( ill. ) zárójeleket, és a megfelelô üzenettel fejezi be mûködését ! #include <stdio.h> #include <conio.h> #include <stdlib.h> 127 Kidolgozott feladatok void main( int argc, char *argv[] ) { FILE *mit; int i , c , zarojel ; clrscr() ; printf(" ARGC értéke = %d ",argc); for(i=0; i<argc; i++) { printf(" ARGV[%d] = %s",i,argv[i]); } printf(" "); // File megnyitás olvasásra if( (mit=fopen(argv[1],"r")) == NULL ) { printf(" Nincs input file ") ; exit(0) ; } zarojel = 0; //

Elôolvasás c = fgetc(mit); // File olvasó ciklus while( !feof(mit) ) { if( c == ( ) zarojel++; if( c == ) ) zarojel--; c = fgetc(mit); } fflush(mit) ; fclose(mit); if( zarojel == 0 ) { printf(" Rendben van a () zárójelek száma ! "); } else if( zarojel > 0 ) { printf(" %d - (v)el több a ( zárójelek száma ! ", zarojel); } else { printf(" %d - (v)el több a ) zárójelek száma ! ", abs(zarojel)); } getch(); } 128