c++ jegyzet old

121
Pohl László C labor jegyzet BME 2005-2006

Upload: kereklovag

Post on 21-Nov-2015

19 views

Category:

Documents


4 download

DESCRIPTION

Informatika-c++ jegyzet

TRANSCRIPT

  • Pohl Lszl

    C labor jegyzet

    BME 2005-2006

  • 2

    Tartalom Tartalom ........................................................................................................................................... 2 Bevezets.......................................................................................................................................... 4 1. Integrlt fejlesztkrnyezet .......................................................................................................... 5 1.1 Program ltrehozsa Borland C++-ban.................................................................................. 5 1.2 Program ltrehozsa Visual C++ 6.0-ban .............................................................................. 6 1.3 Az els program ..................................................................................................................... 8 1.4 A program mkdse ........................................................................................................... 10 1.4.1 Megjegyzsek, formzs a C programban .................................................................... 10 1.4.2 Header fjlok beszerkesztse ........................................................................................ 12 1.4.3 Fggvnydeklarci, fggvnydefinci....................................................................... 13 1.4.4 A main() fggvny ........................................................................................................ 15 1.4.5 A tbbi fggvny .......................................................................................................... 19

    1.5 Fordts, futtats, hibakeress .............................................................................................. 22 2. Beolvass s kirs, tpusok, tmbk ......................................................................................... 27 2.1 Programrts ........................................................................................................................ 27 2.1.1 Egsz tpusok ................................................................................................................ 30 2.1.2 Lebegpontos szmok................................................................................................... 31 2.1.3 Stringek ......................................................................................................................... 33 2.1.4 Tmbk ......................................................................................................................... 34

    2.2 Programrs .......................................................................................................................... 35 3. Feltteles elgazsok, ciklusok, opertorok ............................................................................... 37 3.1 Programrts ........................................................................................................................ 37 3.2 Programrs .......................................................................................................................... 43

    4. Tbbdimenzis tmbk, pointerek ............................................................................................ 44 4.1 Programrts ........................................................................................................................ 44 4.1.1 Mtrix sszeads ........................................................................................................... 44 4.1.2 Tmbk bejrsa pointerrel, stringek............................................................................ 46

    4.2 Programrs .......................................................................................................................... 50 5. Rendezs, keress....................................................................................................................... 52 5.1 Programrts ........................................................................................................................ 52 5.1.1 Kzvetlen kivlasztsos s bubork rendezs............................................................... 52 5.1.2 Qsort.............................................................................................................................. 55 5.1.3 Keress .......................................................................................................................... 58 5.1.4 Hashing ......................................................................................................................... 58

    5.2 Programrs .......................................................................................................................... 62 6. Fjlkezels, dinamikus tmbk.................................................................................................. 63 6.1 Programrts ........................................................................................................................ 63 6.1.1 Sznszmll ................................................................................................................. 63 6.1.2 Dinamikus tmb. struktrk binris fjlban.................................................................. 64 6.1.3 Szveges fjlok ............................................................................................................. 67 6.1.4 Tbbdimenzis dinamikus tmb................................................................................... 70 6.1.5 Tbbdimenzis dinamikus tmb mskpp................................................................. 71

    6.2 Programrs .......................................................................................................................... 73 7. Dinamikus struktrk: lncolt listk, binris fk ....................................................................... 75 7.1 Programrts ........................................................................................................................ 75 7.1.1 Egyszeresen lncolt lista strzsaelem nlkl................................................................. 75 7.1.2 Binris fa, rekurzi........................................................................................................ 83

  • 3

    7.2 Programrs .......................................................................................................................... 88 8. llapotgp s egyebek ............................................................................................................... 90 8.1 Programrts ........................................................................................................................ 90 8.1.1 Poppe Andrs llapotgpes pldja: megjegyzsek szrse ......................................... 90 8.1.2 kezetes karaktereket konvertl llapotgpes feladat................................................. 90 8.1.3 Vltoz paramterlista .................................................................................................. 92 8.1.4 Fggvnypointerek........................................................................................................ 93

    8.2 Programrs .......................................................................................................................... 93 9. Minta nagy hzi feladat telefonknyv..................................................................................... 94 9.1 Specifikci.......................................................................................................................... 94 9.2 Tervezs ............................................................................................................................... 94 9.3 A program ............................................................................................................................ 95 lista.h ...................................................................................................................................... 95 lista.cpp .................................................................................................................................. 96 fuggv.h ................................................................................................................................. 102 fuggv.cpp.............................................................................................................................. 103 main.cpp ............................................................................................................................... 106

    9.4 Hasznlati utasts (felhasznli dokumentci) ............................................................... 107 j elfizet hozzadsa........................................................................................................ 108 Keress/Vltoztats .............................................................................................................. 108 Adatok mentse.................................................................................................................... 109

    9.5 Programozi dokumentci ............................................................................................... 109 lista.h, lista.cpp..................................................................................................................... 109 fuggv.h, fuggv.cpp ............................................................................................................... 111 main.cpp ............................................................................................................................... 112

    F.1 Segtsg a feladatok megoldshoz ....................................................................................... 114 F.2 Lehetsges nagy hzi feladatok ............................................................................................. 115 F.3 Hivatkozsok ......................................................................................................................... 121

  • 4

    Bevezets Ez a jegyzet azokat a gyakorlati ismereteket kvnja bemutatni, melyek a C programozs tanulsa sorn felmerlnek, s a trgy tematiknak rszei. A jegyzet felptse eltr a hagyomnyostl, ezt azrt fontos megjegyezni, mert a kezd programoz taln elborzad, ha belepillant az els fejezetben, ahol a fejlesztkrnyezet indtst bemutat rsz utn rgtn egy ktszz soros programba botlik. Ettl nem kell megijedni, eleinte nem cl ekkora programok ksztse, viszont cl, hogy megrtsk a mkdsket. A hagyomnyos programozs oktatsban az adott tmakrhz tartoz pldk ltalban nagyon rvidek. Ezek elnye, hogy knny megrteni a mkdsket, s knny hasonlt ltrehozni. Htrnyuk, hogy a gyakorlati letben ltalban ennl sokkal hosszabb programokat ksztnk, a rvid program esetben nem hasznlunk olyan eszkzket, melyek egy hosszabbnl elengedhetetlenek. Ilyen pldul a megfelel formtum, magjegyzsek, vltoznevek, fggvnynevek hasznlata, a hibatr viselkeds (lsd Most nem kell hibaellenrzs, de majd a nagyhziban igen.). Az els fejezetben bemutatott program clja, hogy kiprbljuk rajta a klnfle hibakeressi funkcikat. Az 1.4 rszben szerepel a program lersa, mely egyarnt tartalmaz a kezd s a halad programozk szmra szl ismereteket. Az els gyakorlat sorn a cl annyi, hogy nagyjbl kvetni tudjuk a program mkdst, hogy megrtsk, hogy amikor az 1.5 sorn vgiglpkednk a sorokon, mi mirt trtnik, ezrt ekkor csak fussuk t a lerst. Javaslom azonban, hogy a flv msodik felben, mikor mr nagyobb programozi rutinnal rendelkeznk, lapozzunk vissza az 1.4 fejezethez, s olvassuk el ismt. A tovbbiakban vegyesen fognak szerepelni kisebb s nagyobb pldaprogramok, a nagyokat mindig csak megrteni kell, nem kell tudni hasonlt rni, br a flv vgre mr igen. A hallgat feladata egy gynevezett Nagy hzi feladat elksztse, egy ilyen mintafeladat is szerepel a jegyzetben. A C nyelvet, hasonlan a beszlt nyelvekhez, nem lehet elsajttani nll tanuls nlkl, ezrt mindenkppen oldjunk meg gyakorl feladatokat rrl rra, egyedl, otthon! A pldaprogramokat nem kell begpelni. A jegyzet elektronikus formban a http://www.eet.bme.hu/~pohl/ oldalon megtallhat, a pdf-bl ki lehet msolni a szveget, ha az Adobe Reader fels eszkztrn a Select Text-et vlasztjuk, de ha minden igaz, akkor a pldaprogramok zip-elve is letlthetk ugyanonnan, gy mg a formzs is megmarad. A jegyzettel kapcsolatos kritikkat, hibalistkat a [email protected] cmre vrom.

  • 5

    1. Integrlt fejlesztkrnyezet

    A knyelmes s gyors munka rdekben programfejlesztsre lehetsg szerint olyan szoftvereket hasznlunk, mely egybeptve tartalmazza a programkd szerkesztsre alkalmas szvegszerkesztt, a programmodulokbl gpi kdot ltrehoz fordtt (compiler), a gpi kd modulokbl futtathat programot ltrehoz linkert, s a programhibk feldertst megknnyt debugger rendszert.

    Ebben a fejezetben kt ilyen krnyezettel fogunk megismerkedni. Az els mg a 90-es vek elejn kszlt Borland C++, melyet egyszer kezelhetsge miatt hasznlnak manapsg is az oktatsban. Htrnya, hogy DOS opercis rendszerhez kszlt, emiatt a futtathat program ltal hasznlt memriamret igen alacsony, mindssze nhny szz kilobjt, de pldul egy tmb, vagy brmely adatstruktra mrete nem haladhatja meg a 64 kB-t. Tovbbi rszletekrt, lsd [1].

    A msik a Microsoft Visual C++ 6.0, mely a HSzK sszes termben a hallgatk rendelkezsre ll. Ennl lteznek jabb Visual C++ fordtk is, a Visual C++ .Net, a .Net 2003, illetve a .Net 2005. (Ezek a fordtk 32 bites kdot ksztenek. A 32 bites programok maximum 2 GB memrit kezelhetnek, ez ltalban mr nem jelent szmunkra problmt, nem gy, mint a 16 bites DOS 64 kB-os, illetve nhny szz kB-os korltai.)

    Ahogy a programok nevbl ltszik, ezek C++ fordtk. A C++ nyelv fellrl kompatibilis a C-vel, teht minden C program egyben C++ program is. Napjainkban mr csak kevs esetben tallkozunk olyan fordt programmal, mely csak a C-t ismeri, s a C++-t nem.

    Aki ingyenes Windowsos fordtra vgyik, annak rdemes kiprblnia a [3] rendszert, mely a DevC++-ra pl grafikus fellet, Delphi- (ill. C++ Builder)-szeren hozhatunk ltre benne grafikus Windowsos programokat, de dolgozhatunk konzol mdban is. Htrnya, hogy lass a fordt (ez legyen a legnagyobb bajunk). (Erre a rendszerre Nagy Gergely hvta fel a figyelmem, ezton is ksznet neki.)

    1.1 Program ltrehozsa Borland C++-ban

    Indtsuk el a BC.EXE programot! A kvetkez kp trul elnk:

    1. bra

    A gombra kattintva tudjuk bezrni a szerkesztmezt, a gombbal pedig

    kinagythatjuk, hogy befedje az ablak egsz bels rszt. Ha vletlenl (vagy szndkosan) becsuktuk a szerkesztmezt, a File men New parancsval hozhatunk ltre jat.

  • 6

    Most nincs ms dolgunk, mint begpelni a kdot. A kszl programot rdemes nhny percenknt elmenteni.

    1.2 Program ltrehozsa Visual C++ 6.0-ban

    A Visual C++-t elindtva a kvetkez ablak fogad:

    2. bra

    Ezttal a helyzet bonyolultabb, ugyanis nem kezdhetnk el egybl gpelni. Elbb ltre kell hozni a program projektjt. Ehhez kattintsunk a File men New parancsra!

    A New ablakban alaprtelmezs szerint a Projects fl nylik meg. Ha mgsem, akkor

    vlasszuk ki azt. A listbl vlasszuk ki a Win32 Console Application-t.

    Vlasszuk ki a mappt, ahova a projektet tenni szeretnnk, s adjuk meg a projekt nevt. A

    kivlasztott mappban ltre fog jnni egy j mappa a megadott nvvel, ebbe kerlnek a program fjljai.

    Kattintsunk az OK-ra! Ekkor a jobb oldali ablakot kapjuk (3. bra). Itt maradjunk meg az An empty project belltsnl!

    Figyelem! Ne a sima Win32 Application-t vlasszuk, mert ellenkez esetben kezdhetjk elrl az egsz projekt ltrehozst!

    Ne hasznljuk a New ikont! Ez egy txt fjlt hoz ltre, amivel nem tudunk mit kezdeni, mert nem rsze a projektnek. Ha vletlenl mgis egy ilyen ablakba kezdtk rni a programit, ne essnk ktsgbe, hanem mentsk el a fjlt (cpp kiterjesztssel! teht pl. valami.cpp), csukjuk be, majd a kvetkezkben lertak szerint hozzuk ltre a projektet. Ha ez megvan, vlasszuk a Project men Add To Project almenjbl a Files parancsot! Keressk meg az elmentett fjlt, s adjuk a projekthez!

  • 7

    3. bra

    Ha a projekt ltrejtt, akkor ismt vlasszuk ki a File men New parancst!

    4. bra

    Ezttal a Files fln kattintsunk, ha nem az lenne kivlasztva. Vlasszuk ki a C++ Source File-t a listbl. Adjunk neki nevet a File name szerkesztmezben, s nyomjuk meg az OK-t. Az eredmnyt az 5. brn ltjuk.

    5. bra

  • 8

    1.3 Az els program

    Msoljuk be az albbi programot az ltalunk hasznlt fejlesztkrnyezetbe. A program letlthet a http://www.eet.bme.hu/~pohl/ weboldalrl.

    //******************************************************* #include // Header fjlok beszerkesztse #include #include //******************************************************* //******************************************************* // prototpusok, azaz fggvnydeklarcik //******************************************************* void osszead(); void kivon(); void szoroz(); void oszt(); void gyok(); void szinusz(); void osztok(); int egy_int_beolvasasa(); double egy_double_beolvasasa(); void ket_double_beolvasasa(double*,double*); //******************************************************* //******************************************************* // fggvnydefincik //******************************************************* //******************************************************* int main(){ //******************************************************* int valasztott_ertek=0; // egsz tpus vltoz 0 kezdrtkkel printf("Udvozoljuk! On a szamologepet hasznlja. Jo munkat!\n"); // kirs while(valasztott_ertek!=10){ // ciklus, mg a v.. nem egyenl 10-zel // A men kirsa printf("\nKerem, valassza ki a muveletet!\n"); printf("1 Osszeadas\n"); printf("2 Kivonas\n"); printf("3 Szorzas\n"); printf("4 Osztas\n"); printf("5 Negyzetgyok\n"); printf("6 Szinusz\n"); printf("7 Egesz szam osztoi\n"); /* printf("8 Termszetes logaritmus\n"); printf("9 Exponencilis\n"); */ printf("10 Kilepes\n"); // A vlasztott rtk beolvassa fflush(stdin); // standard input puffer rtse if(scanf("%d",&valasztott_ertek)!=1)valasztott_ertek=0; // A vlasztott mvelet vgrehajtsa switch(valasztott_ertek){ // a v..-nek megfele case utn folytatja case 1: osszead(); break; // az osszead fggvny hvsa case 2: kivon(); break; case 3: szoroz(); break; case 4: oszt(); break; case 5: gyok(); break; case 6: szinusz(); break; case 7: osztok(); break; /* case 8: logarit(); break; // termszetes logaritmus

    Aki Borland fordtt hasznl, nem tudja hasznlni a [Ctrl+C] [Ctrl+V] (msols+beilleszts) funkcikat. A Borland fordt menjben is tallunk olyan funkcit, hogy Paste ([Shift+Ins]), de ez sajt vglapot hasznl, nem a Windowst, ezrt a Windows vglapra helyezett szveg nem msolhat be a Borland fordtba.

  • 9

    case 9: exponen(); break; */ case 10: break; default: printf("Hibas muveletszam (%d). Probalja ujra!",valasztott_ertek); } } printf("\nTovabbi jo munkat!\n"); return 0; } //******************************************************* void osszead(){ //******************************************************* double a,b; // kt vals rtk vltoz printf("\nOsszeadas\n"); ket_double_beolvasasa(&a,&b); // fggvnyhvs printf("\nAz osszeg: %g\n",a+b); // sszeg kirsa } //******************************************************* void kivon(){ //******************************************************* double a,b; printf("\nKivonas\n"); ket_double_beolvasasa(&a,&b); printf("\nA kulonbseg: %g\n",a-b); } //******************************************************* void szoroz(){ //******************************************************* double a,b; printf("\nSzorzas\n"); ket_double_beolvasasa(&a,&b); printf("\nA szorzat: %g\n",a*b); } //******************************************************* void oszt(){ //******************************************************* double a,b; printf("\nOsztas\n"); ket_double_beolvasasa(&a,&b); printf("\nA hanyados: %g\n",a/b); } //******************************************************* void gyok(){ //******************************************************* double a; printf("\nGyokconas\n"); a=egy_double_beolvasasa(); printf("\nA negyzetgyok: %g\n",sqrt(a)); } //******************************************************* void szinusz(){ //******************************************************* double a; printf("\nSzinusz\n"); a=egy_double_beolvasasa(); printf("\nA szinusz: %g\n",sin(a)); } //******************************************************* void osztok(){ //******************************************************* int a,i; printf("\nOsztok szamitasa\n"); a=egy_int_beolvasasa(); printf("\n%d osztoi:\n",a); for(i=1;i

  • 10

    while(OK==0){ printf("\nKerem a szamot: "); fflush(stdin); if(scanf("%d",&szam)!=1){printf("\nHibas szam, adja meg helyesen!\n"); continue;} OK=1; } return szam; } //******************************************************* double egy_double_beolvasasa(){ //******************************************************* int OK=0; double szam; while(OK==0){ printf("\nKerem a szamot: "); fflush(stdin); if(scanf("%lg",&szam)!=1){printf("\nHibas szam, adja meg helyesen!\n"); continue;} OK=1; } return szam; } //******************************************************* void ket_double_beolvasasa(double * a, double * b){ //******************************************************* // Els szm bekrse int OK=0; while(OK==0){ printf("\nKerem az elso szamot: "); fflush(stdin); if(scanf("%lg",a)!=1){printf("\nHibas elso szam, adja meg helyesen!\n"); continue;} OK=1; } // Msodik szm bekrse OK=0; while(OK==0){ printf("\nKerem a masodik szamot: "); fflush(stdin); if(scanf("%lg",b)!=1){printf("\nHibas masodik szam, adja meg helyesen!\n"); continue;} OK=1; } }

    Prbljuk ki a programot, futtassuk le! Ezt Borland fordtnl a Run men Run parancsval

    tehetjk meg, Visual C++ esetn pedig a Debug men Start, vagy Start Without Debugging parancsval.

    1.4 A program mkdse

    Ebben a pontban ttekintjk a fenti program mkdst, megismerkednk az egyes rszek

    szerepvel, funkcijval. Most mg nem feladat, hogy hasonlt tudjunk rni, de a kvetkez pontban bemutatott hibakeresshez rtennk kell a mkdst.

    Az ebben a jegyzetben hasznlt program szneket a Visual C++fordt hasznlja, de a Borland

    is hasonlkppen ms-ms sznnel jelli a kd egyes rszeit. Mindez a jobb ttekinthetsget szolglja. Aki Visual C++-t hasznl, s a kdja fekete-fehr, az nem cpp fjlknt nyitotta meg a kdot. Ebben az esetben tekintse t ismt az 1.2 fejezetben lertakat!

    1.4.1 Megjegyzsek, formzs a C programban

  • 11

    Az ANSI/ISO C nyelv ktfle megjegyzstpust tmogat, de a rgebbi fordtk (pl. TurboC) csak a /* */ tpust ismerik. Ha ilyen fordtval van dolgunk, akkor kzzel kell kicserlni a // tpus megjegyzseket a /* */ tpusakra.

    A megjegyzsek a programba helyezett olyan szvegek, melyek a programozk szmra ttekinthetbb teszik a forrskdot, tovbb lehetv teszik, hogy egyes programrszeket ideiglenesen eltvoltsanak a kdbl, pldul hibakeressi clbl.

    Az egyik megjegyzsfajta a /* opertorral kezddik. A kt karakter kz nem tehetnk ms karaktert, pl. szkzt. A /* utni szveg, brmit is tartalmaz, megjegyzsnek szmt, teht a fordt nem veszi figyelembe. A megjegyzs az els */ opertorig tart, teht tbbsoros is lehet (lsd a fenti programot).

    A /* */ tpus megjegyzsek nem gyazhatk egymsba, ami azt jelenti, hogy egy ilyen kd: /* /* case 8: logarit(); break; // termszetes logaritmus */ case 9: exponen(); break; */ helytelen, ugyanis a msodik /*-ot a fordt nem veszi figyelembe, mert egy megjegyzsen bell volt, s a fordt semmit sem vesz figyelembe, ami egy megjegyzsen bell van. A fordtprogram a fordts sorn ezt kt zenettel is jelzi: f:\vc7\szgl\main.cpp(69) : warning C4138: '*/' found outside of comment f:\vc7\szgl\main.cpp(69) : error C2059: syntax error : '/'

    A msik megjegyzsfajtt, a //-t a C nyelv a C++-bl vette t. Ez a megjegyzs a sor vgig tart.

    A /* */ megjegyzsben nyugodtan lehet // tpus megjegyzs, mert a /*-gal kezdett megjegyzs mindig a */-ig tart, s a kztk lv //-t ppgy nem veszi figyelembe a fordt, mint a /*-ot az elbbi pldban (de a lezr */-t ne a // utn tegyk!). // utn csak akkor kezdhetnk /* megjegyzst, ha azt mg a sor vge eltt be is fejezzk, mert ekkor a /*-t sem veszi figyelembe a fordt, pl.: case 4: oszt(); break; // ez /* gy j */ kt megjegyzs egyben

    Sem a megjegyzst jelz opertorok el, sem mg nem ktelez szkzt rni, itt mindssze azrt szerepel, mert jobban tlthat kdot eredmnyez.

    A bemutatott programban a // tpus megjegyzseket hasznltuk arra, hogy a programkd

    ttekinthetbb legyen. Ezt a clt szolglja az egyes programrszeket jelz csillagsor (termszetesen ms karakterek is hasznlhatk, pl. //----------, //#########, //@@@@@, kinek mi tetszik), a megjegyzst kvet kdrsz funkcijt ler // Msodik szm bekrse, vagy a sor vgre biggyesztett, a sor funkcijt ler megjegyzs is: case 8: logarit(); break; // termszetes logaritmus

    A /**/ tpus megjegyzsekkel olyan kdrszeket tvoltottunk el, melyeket most nem akarunk hasznlni, de ksbb esetleg igen, vagy valamilyen ms okbl nem kvnjuk trlni.

    Az ttekinthetsget javt megjegyzsek ltalban egysorosak, de pldul, ha egy teljes fggvny funkciit, paramtereit akarjuk lerni, akkor is legfeljebb prsorosak. Az eltvoltott kdrszek hossza viszont akr tbb szz sor is lehet. Emiatt alakult ki az, hogy melyik megjegyzstpust mire hasznljuk. Ugyanis az eltvoltott kdrszben valsznleg j nhny, az ttekinthetsget javt megjegyzs is tallhat, s ha erre a clra is a /**/ megjegyzst hasznlnnk, akkor minden */-rel zrult, ttekinthetsget javt megjegyzs megszaktan a kd eltvoltst.

    Most pedig a formtumrl. A C programokban minden olyan helyre, ahova egy szkzt

    tehetnk, oda tbbet is tehetnk, st akr soremelst, vagy tabultort is. Az utasts vgt a ;, vagy a } jelzi. pldul:

    if(scanf("%d",&valasztott_ertek)!=1)valasztott_ertek=0; trhat lenne: if ( scanf

  • 12

    ( "%d" , & valasztott_ertek ) != 1 ) valasztott_ertek = 0 ; mdon is, csak ettl jval tlthatatlanabb lenne a kd.

    Annak rdekben, hogy jl ltsszon, meddig tart egy utasts vagy egy utastsblokk, az adott blokkhoz tartoz utastsokat beljebb kezdjk, ahogy ez a pldaprogramban is ltszik (nem szksges ennyivel beljebb kezdeni, elg 2-3-4 szkznyi tvolsg).

    A { elhelyezsre kt jellemz szoks alakult ki. Az els: void szoroz(){ double a,b; printf("\nSzorzas\n"); ket_double_beolvasasa(&a,&b); printf("\nA szorzat: %g\n",a*b); }

    A msodik:

    void szoroz() { double a,b; printf("\nSzorzas\n"); ket_double_beolvasasa(&a,&b); printf("\nA szorzat: %g\n",a*b); }

    Az els kisebb helyet foglal, a msodiknl jobban ltszik, hogy melyik kapocshoz melyik

    kapocs tartozik. Abban az esetben, ha valaki nem tartja be ezeket a szablyokat, s mindent a bal szlen kezd, nagyon nehz dolga lesz, ha valahol vletlenl lefelejt egy nyit vagy zr kapcsot, mert gy a prnlklit elg nehz megtallni.

    Ha egy utastst osztunk kett, mert egy sorban nehezen fr el, akkor a msodik felt beljebb kell kezdeni. Pldul: fflush(stdin); if(scanf("%d",&valasztott_ertek)!=1)

    valasztott_ertek=0; printf("\nSzorzas\n"); ket_double_beolvasasa(&a,&b); printf("\nA szorzat: %g\n",a*b);

    Itt jl ltszik, hogy a valasztott_ertek=0; az if utastshoz tartozik, ha nem tennnk beljebb: fflush(stdin); if(scanf("%d",&valasztott_ertek)!=1)

    valasztott_ertek=0; printf("\nSzorzas\n"); ket_double_beolvasasa(&a,&b); printf("\nA szorzat: %g\n",a*b);

    gy azt hihetnnk, hogy a valasztott_ertek=0; egy kln utasts, mert a ; hinya az elz sor vgn nem feltn.

    1.4.2 Header fjlok beszerkesztse //******************************************************* #include #include #include //*******************************************************

    A C programok fordtsa kt lpsben trtnik. Elszr az n. elfordtnak, vagy

    preprocesszornak szl utastsokat figyelembe vve kszl egy kztes C program, majd a fordt ebbl a kztes kdbl kszti el a gpi kd, lefordtott fjlt. Az sszes, elfordtnak

  • 13

    szl utasts # (hash mark, vagy ketts kereszt) szimblummal kezddik, s az adott sorban csak szkz vagy tabultor karakterek vannak eltte.

    A #include az utna megadott nev fjlt hozzszerkeszti a forrskdhoz. A fjl neve ktfle formban szerepelhet (a fenti kdban csak az egyiket hasznltuk): #include #include sajat.h

    Az els esetben, teht kztt megadott nvnl, a fordt a fejlesztkrnyezetben belltott mapp(k)ban keresi a fjlt. (Ez Borland C++ esetn az Options men Directories pontjban llthat, Visual C++ esetn a Tools/Options/Directories-ban.). Ha kztt szerepel, akkor pedig abban a mappban, ahol a program forrskdja is van. Teht esetn a programunkhoz tartozik a header fjl, esetn pedig a rendszerhez.

    A header fjlok konstansokat s fggvnyek prototpusait tartalmazzk. Pldul ha megnyitjuk az stdio.h-t (ez az ltalam hasznlt szmtgpben C:\Program Files\Microsoft Visual Studio .NET\Vc7\include\stdio.h), akkor pl. ezt lthatjuk benne:

    _CRTIMP int __cdecl printf(const char *, ...); _CRTIMP int __cdecl putc(int, FILE *); _CRTIMP int __cdecl putchar(int); _CRTIMP int __cdecl puts(const char *); _CRTIMP int __cdecl _putw(int, FILE *); _CRTIMP int __cdecl remove(const char *); _CRTIMP int __cdecl rename(const char *, const char *); _CRTIMP void __cdecl rewind(FILE *); _CRTIMP int __cdecl _rmtmp(void); _CRTIMP int __cdecl scanf(const char *, ...); _CRTIMP void __cdecl setbuf(FILE *, char *);

    A printf() s a scanf() ezek kzl szerepel is a programban. Ugyancsak az stdio.h-ban

    szerepel a fflush() fggvny is. A sin() s az sqrt() a math.h rsze. A program nem hasznlja az stdlib.h-t, teht ezt az include sort trlni is lehet.

    A standard fggvnyek (printf, scanf stb.) forrskdja nem ll rendelkezsnkre, azt a gyrt nem mellkeli a fordtprogramhoz. Ezeknek a fggvnyeknek a lefordtott kdja .lib fjlokban tallhat, melyet a linker szerkeszt a programhoz (csak azokat a fggvnyeket, melyeket valban hasznlunk is).

    Hogy mely headerekben milyen fggvnyek tallhatk, az pl. a megfelel C nyelv knyvekben megtallhat (pl. [1]).

    stdio=Standard Input Output, stdlib=Standard Library

    1.4.3 Fggvnydeklarci, fggvnydefinci Az els programnyelvekben az egsz program csak utastsok sorozatbl llt. Ez azonban

    mr a kzepes mret programokat is tlthatatlann tette. Ezrt szlettek a strukturlt programozst tmogat programnyelvek, mint a C (bizonyos mret fltt ez is ttekinthetetlenn vlik, ezrt jttek ltre az objektumorientlt nyelvek, mint amilyen a C++).

    A strukturltsg azt jelenti, hogy a programot adott funkcit ellt rszekre, fggvnyekre osztjuk. A fggvnyek elnye, hogy ha azonos mveletet kell tbbszr megismtelni, akkor elg csak egyszer lerni az ehhez szksges kdot, s ezt a programban akrhnyszor meghvhatjuk, vagyis vgrehajthatjuk.

    A fenti program msodik rszt a fggvnydeklarcik alkotjk:

    //******************************************************* // prototpusok, azaz fggvnydeklarcik //******************************************************* void osszead(); void kivon(); void szoroz();

  • 14

    void oszt(); void gyok(); void szinusz(); void osztok(); int egy_int_beolvasasa(); double egy_double_beolvasasa(); void ket_double_beolvasasa(double*,double*); //*******************************************************

    Gondot szokott okozni a deklarci s a definci elnevezsek megklnbztetse. Ebben

    segthet, hogy a francia la declaration de la Republic Hongroise azt jelenti magyarul, hogy a Magyar Kztrsasg kikiltsa. A deklarci teht kikiltst jelent: megmondjuk, hogy van ilyen. Ha nem csak azt akarjuk tudni, hogy van ilyen, hanem azt is tudni akarjuk, milyen, akkor definilni kell a fggvnyt.

    A kkkel szerepl szavak a kulcsszavak, melyeket a C nyelv definil. Feketvel a tbbi programrsz szerepel, a zld pedig a megjegyzs (1.4.1).

    Itt minden egyes sorban egy-egy fggvny neve szerepel, mely hrom rszbl ll: 1. Visszatrsi rtk. Ha van egy matematikai egyenletnk, pl. x=sin(y), akkor ebben az

    esetben a sin fggvny visszatrsi rtke y szinusza, s ez kerl be x-be. Programozs kzben gyakran runk olyan fggvnyeket, melyeknek szintn van visszatrsi rtke, pl. maga a szinusz fggvny a fenti programban is szerepel. A fenti fggvnyek kztt kett olyan van, melynek szintn van visszatrsi rtke: az egy_int_beolvasasa() int tpus, teht egsz szmot ad vissza, az egy_double_beolvassa() double tpus, teht vals szmot ad vissza. Azok a fgg vnyek, melyek neve eltt a void szerepel, nem adnak visszatrsi rtket. Pldul, ha egy fggvnynek az a feladata, hogy kirjon valamit a kpernyre, akkor nincs szksg visszatrsi rtkre.

    2. A fggvny neve. Ez angol kis s nagybetkbl, szmokbl, valamint _ jelekbl llhat, szkz vagy egyb elvlaszt karakter nem lehet benne, s nem kezddhet szmmal (alhzssal igen).

    3. A () zrjelek kztt vannak a fggvny paramterei. Pldul a sin(y) esetn a szinusz fggvny meg kell, hogy kapja y rtkt, mivel annak szinuszt kell kiszmtania. A fenti deklarcik kzl csak a ket_double_beolvasasa(double*,double*); fggvnynek vannak paramterei, mghozz kt double tpus pointer (a * jelzi, hogy pointerrl, vagyis memriacmrl van sz).

    A deklarcinak mindig elbb kell szerepelnie, mint ahol a fggvnyt hasznljuk, a definci lehet ksbb is, vagy akr msik programmodulban, vagy .lib fjlban. Fontos megjegyezni, hogy a definci egyben deklarci is, teht ha a fggvnyek defincijt a main() fggvny el tettk volna (ez igen gyakran megesik), ahol azokat hasznljuk, akkor felesleges odarni kln a deklarcit. Ebben a programban pldul nem rtunk deklarcit a main() fggvnyhez (ez nem is szoks).

    Lssuk most a fggvnydefincit! Pldul:

    //******************************************************* void ket_double_beolvasasa(double * a, double * b){ //******************************************************* // Els szm bekrse int OK=0; while(OK==0){ printf("\nKerem az elso szamot: "); fflush(stdin); if(scanf("%lg",a)!=1)

    {printf("\nHibas elso szam, adja meg helyesen!\n"); continue;} OK=1; }

  • 15

    // Msodik szm bekrse OK=0; while(OK==0){ printf("\nKerem a masodik szamot: "); fflush(stdin); if(scanf("%lg",b)!=1)

    {printf("\nHibas masodik szam, adja meg helyesen!\n"); continue;} OK=1; } }

    sszehasonltva a deklarcival, a kvetkezk a klnbsgek:

    1. A paramterlistban nem csak a peremter tpusa szerepel, hanem egy vltoznv is. A fggvny kdjban ezen a nven hivatkozunk a paramterre. Deklarci esetn is oda szabad rni a vltoz nevt, de ott nem ktelez, defincinl viszont igen. (A deklarcinl megadott vltoznv nem kell, hogy megegyezzen a definciban megadottal.)

    2. A ) utn nem ; ll, hanem egy kapcsos zrjelek kz zrt utastsblokk. Ha a fggvnynek van visszatrsi rtke (teht nem void), akkor a fggvnyben kell, hogy

    szerepeljen return utasts, a return utn kell rni a visszaadott rtket. Pl.:

    //******************************************************* int egy_int_beolvasasa(){ //******************************************************* int OK=0,szam=0; while(OK==0){ printf("\nKerem a szamot: "); fflush(stdin); if(scanf("%d",&szam)!=1)

    {printf("\nHibas szam, adja meg helyesen!\n"); continue;} OK=1; } return szam; }

    Visszatrsi rtket nem ad (void tpus) fggvny esetn is lehet return utasts, ekkor a

    return-t pontosvessz kveti. Egy fggvnyben tbb return utasts is lehet. Ez pldul akkor hasznos, ha valamilyen

    felttel esetn csak a fggvny egy rszt kell vgrehajtani.

    1.4.4 A main() fggvny Minden C nyelv program futtatsa a main() fggvny futtatst jelenti. Amikor rkattintunk

    az exe-re, akkor a program main() fggvnye indul el. A main termszetesen ms fggvnyeket is hvhat, s azok is hvhatnak ms fggvnyeket, stb.

    Ha egy fggvnynek nem runk visszatrsi tpust, akkor C fordt esetben alaprtelmezs szerint int, C++ fordt esetben void lesz ez a tpus. Mivel mi C++ fordtt hasznlunk, de C programot fordtunk, a fordt ltalban rugalmasan kezeli ezt a krdst, s mindkettt elfogadja, a return paramterezse alapjn dnti el, hogy mit is akarunk: ha egy egsz rtket adunk vissza (mint a fenti programban), akkor int main()-nek tekinti, ha simn return;-t runk, vagy nem hasznljuk a return-t, akkor void main()-nek.

    Lssuk, hogyan mkdik!

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

  • 16

    int main(){ //******************************************************* int valasztott_ertek=0;

    Elszr ltrehozunk (definilunk) egy valsztott_ertek nev, egsz rtkkszlet vltozt, s 0

    kezdrtket adunk neki. Ha nem adunk kezdrtket, akkor brmi lehet benne, ez nincs meghatrozva.

    Borland C++ esetn -32768 s +32767 kztti egsz szmokat trolhatunk benne, mert itt az int 16 bites, Visual C++ esetn pedig -2147483648 s +2147483647 kztti, mert az int 32 bites. Ezek az rtkek gy addnak, hogy 215 ill. 231 rtkek a hatrok, a 16. ill. a 32. bit jelenti az eljelet, tovbb pozitv irnyban azrt eggyel kevesebb rtknk van, mert a nullnak is kell hely.

    Amennyiben 64 bites rendszerben fordtjuk a programot, az int ltalban tovbbra is 32 bites marad, mert a 2 millird egsz rtk mveleteknl ltalban elg szokott lenni, ritkn van szksg ennl nagyobbra. Ha mgis szksg volna erre, akkor a long tpust hasznlhatjuk (32 ill. 16 bites rendszerben a long 32 bites, de a legjabb C++ szabvnyban ltezik long long tpus, mely 64 bites, de ez egyik, ltalunk hasznlt fordtban sem hasznlhat. Ehelyett Visual C++-ban az _int64 tpust hasznlhatjuk, de ez nem szabvnyos.)

    Tovbbi, a C nyelvben hasznlt tpusokkal kapcsolatban lsd a szakirodalmat, pl. [1].

    printf("Udvozoljuk! On a szamologepet hasznlja. Jo munkat!\n");

    A printf fggvny a standard kimenetre kirja a paramterknt megadott, idzjelek kztt

    szerepl szveget. A standard kimenet ltalban a kperny. Ha azonban a programot gy indtjuk el, hogy program.exe > kimemet.txt, akkor a kpernyn nem jelenik meg semmi, ehelyett a szveg a kimenet.txt nev fjlba kerl.

    Az idzjelek kztti szvegben hasznlhattunk volna kezeteket, csak sajnos ezt a Windows hibsan jelenti meg, az kezetek nlkli szveg olvashatbb. (Prbljuk ki!)

    A kirt szvegekben nem minden rdik ki a kpernyre, a \ (fordtott per, vagy back slash) s a % jel utn specilis, a kiratst vezrl karakter(ek) szerepel(nek). Errl mg ksbb lesz sz. Ebben a stringben (a string karakterlnc, vagyis az, ami a kt idzjel kztt van) egy ilyen szerepel, a \n. A \n utn kvetkez szveg j sorba kerl. (Jelen esetben ez a szveg egy ksbbi printf()-ben kerl kirsra, de akr itt is rhattunk volna utna valamit.)

    while(valasztott_ertek!=10){

    A while utni {, s a hozz tartoz } kztti utastsok addig ismtldnek, mg a paramterknt

    megadott kifejezs igaz, jelen esetben, amg a valasztott_ertek nem egyenl 10-zel. Teht a != azt jelenti, hogy nem egyenl.

    A while utni {-hez tartoz }-t a while w betjvel egyvonalban fgglegesen lefel haladva talljuk meg. Pont azrt rtuk ide, hogy jl ltsszon, mi van a while-on bell, lsd az 1.4.1 pontot, a formzssal kapcsolatban.

    Ne felejtsk, hogy a valasztott_ertek ltrehozsakor 0 kezdrtket adtunk, ami ugye nem egyenl tzzel, teht a felttel igaz, ezrt vgrehajtdnak az utastsok a kapcsos zrjelek kztt. Ha ehelyett int valasztott_ertek=10; szerepelne, akkor a felttel hamis lenne, teht a {} kztti utastsok (vagyis a ciklusmag) egyszer sem hajtdna vgre. (Prbljuk ki!)

    Fontos! Ha nem adtunk volna kezdrtket, teht int valasztott_ertek; szerepelt volna, akkor valasztott_ertek kezdrtke meghatrozatlan lenne, teht akr 10, akr brmi ms is lehetne, teht kiszmthatatlann vlna a program mkdse, s ez slyos hiba, amirt a ZH-ban pontlevons jr!

    // A men kirsa

  • 17

    printf("\nKerem, valassza ki a muveletet!\n"); printf("1 Osszeadas\n"); printf("2 Kivonas\n"); printf("3 Szorzas\n"); printf("4 Osztas\n"); printf("5 Negyzetgyok\n"); printf("6 Szinusz\n"); printf("7 Egesz szam osztoi\n"); /* printf("8 Termszetes logaritmus\n"); printf("9 Exponencilis\n"); */ printf("10 Kilepes\n");

    Az els printf() \n-nel kezddik, s mivel az elz printf() \n-nel vgzdtt, ez azt jelenti,

    hogy egy res sor marad a kt szvegsor kztt. A kt \n-t egy stringbe is tehettk volna, gy: \n\n, ez zls krdse (ne felejtsk azt sem, hogy ez egy ciklus belsejben van, teht valsznleg tbbszr ismtldni fog a kirs).

    Az egyes kirt sorok csak azrt kerltek kln-kln prontf-be, hogy tlthatbb legyen a program. (Ez az tlthatbb legyen a program igen gyakori hivatkozsi alap, ugyanakkor rendkvl fontos, hogy gyorsan megtalljunk brmit a programunkban, mert egy rosszul felptett program nagysgrendekkel megnvelheti a hibakeresssel vagy bvtssel tlttt idt. A hibakeress ideje (persze a bvts is) egy jl megrt program esetn is sszemrhet, st, akr nagyobb is lehet, mint maga a program megrsa. Gondoljuk csak meg, milyen sok ez egy rosszul megrt programnl!)

    Teht megrhattuk volna pl. gy is, az eredmny ugyanaz, csak a ltvny nem:

    printf("1 Osszeadas\n2 Kivonas\n3 Szorzas\n4 Osztas\n"); printf("5 Negyzetgyok\n6 Szinusz\n7 Egesz szam osztoi\n");

    A 8-as s 9-es kirst ideiglenesen eltvoltottuk a kdbl, mert az ezekhez szksges

    fggvnyeket nem valstottuk meg. Ez ksbb az olvas feladata lesz.

    // A vlasztott rtk beolvassa fflush(stdin); if(scanf("%d",&valasztott_ertek)!=1)valasztott_ertek=0;

    Ezt a kt sort fordtva trgyaljuk, mert a scanf ismerete nlkl nem rthet az fflush. Az if utasts, hasonlan a while-hoz, egy felttelt vr paramterknt. Jelen esetben azt nzi,

    hogy vajon a scanf() visszatrsi rtke 1-e, vagy sem. Ha az if felttele igaz, akkor a ) utn szerepl utasts vgrehajtdik, ha nem igaz, akkor kihagyja. (Az if s a while kztti klnbsg teht az, hogy az if utni utasts csak egyszer fut le, mg a while utni mindaddig, amg a felttel igaz. Ha tbb utastst szeretnnk az if utn rni, akkor azokat tegyk {} kz, mint a while esetben!)

    Teht ha a scanf visszatrsi rtke nem 1, akkor a valasztott_ertek 0-val lesz egyenl. A scanf() fggvny tulajdonkppen a printf() ellentte, teht a billentyzetrl krhetnk be

    adatokat, jelen esetben azt, hogy hnyas szmot r be az, aki a programot lefuttatja. (A scanf igazndibl a standard bemenetrl olvas, mely alapesetben a billentyzet, de itt is tirnythatunk egy fjlt: program.exe < bemene.txt. Termszetesen ebben az esetben a bemenet.txt-nek lteznie kell, s megfelel adatokat kell tartalmaznia.)

    A scanf els paramtere egy string csakgy, mint a printf-. Ez a string azonban csak vezrl karaktereket s elvlaszt jeleket tartalmazhat, mert a scanf soha semmit sem r ki, s ha mst is runk bele, akkor hibsan fog mkdni!

  • 18

    Jelen esetben egy darab %d szerepel itt, vagyis egy darab egsz szmot akarunk beolvasni. %d helyett rhattunk volna %i-t is, mindkett ugyanazt jelenti (a d a decimal-ra utal, vagyis 10-es szmrendszerbeli szmra, az i pedig int-re).

    A string utn, vesszvel elvlasztva szerepel azoknak a vltozknak a neve, ahov a beolvasott rtket tenni akarjuk. Annyi vltozt kell megadni, ahny beolvasst a stringben jeleztk! (A scanf fggvny megszmolja, hogy a stringben hny beolvasand rtket adtunk meg, s ezutn annyi darab vltozt keres a string utn, amennyi a string alapjn vrhat. Sajnos a fordt nem tudja megllaptani, hogy annyit adtunk, kevesebbet, vagy tbbet, s abban az esetben, ha nem pontosan annyit adtunk, akkor ez a program futtatsa kzben jelentkez hibt okozhat.)

    Figyeljk meg a vltoz neve eltt szerepl & jelet! Ez az opertor ugyanis az utna rt vltoz memriacmt adja, vagyis egy pointert (mutatt), mely a vltozra mutat a memriban. Ha ezt nem rnnk el, akkor a scanf() fggvny azt az rtket kapn, ami a valasztott_ertek-ben van, vagyis els futskor 0-t, hiszen ez volt a kezdrtk. Ezzel nem sok mindent tudna kezdeni, mert neki az lenne a dolga, hogy a vltozba tegyen be egy rtket, nem az, hogy a vltozbl kivett rtkkel brmit csinljon. Emiatt a memriacmet kell neki tadni, gy ugyanis tudni fogja, hogy hol van a valasztott_ertek, amibe a beolvasott rtket pakolnia kell.

    A scanf() fggvny visszatrsi rtke azt mondja meg, hogy hny darab vltozt olvasott be

    sikeresen. Jelen esetben egy darabot szeretnnk beolvasni. Mikor trtnik az, ha nem 1 a visszatrsi rtk? Pldul, ha az udvarias Kerem valassza ki a muveletet! krsnkre a felhasznl ezt vlaszolja Anyd!. Ezt ugyanis a scanf nem kpes egsz szmknt rtelmezni, ezrt a valasztott_ertek-be nem tesz semmit, viszont 0-t ad vissza.

    Az fflush(stdin) funkcija az, hogy kirtse a standard input puffert. Ehhez meg kell

    magyarzni, hogy mi a standard input puffer, s hogyan mkdik a scanf. A standard input puffer egy olyan hely a memriban, ahonnan a scanf beolvassa a bert

    szveget, s talaktja pldul egsz, vagy vals szmm, vagy meghagyja szvegnek, attl fggen, hogy a scanf-ben pl. %d, %lg, vagy %s szerepelt-e. Ha a scanf ezt a puffert resen tallja, akkor szl az opercis rendszerek (a DOS-nak, Windowsnak, Unixnak/Linuxnak stb.), hogy olvasson be a standard inputrl. Az opercis rendszer pedig mindaddig gyjti a lenyomott billentyket, mg az -t le nem nyomjuk, aztn az egszet bemsolja a standard input pufferbe.

    Az opercis rendszer egyik legfontosabb feladata, hogy ilyen jelleg szolgltatsokat biztostson. Ezek igazbl fggvnyhvsok. Ugyanis nagyon sok program szeretne pl. billentyzetrl olvasni, s elg macers lenne, ha minden egyes billentymveletet a billentyzet ramkreinek programozsval, az adott programoznak kellene megoldania. Teht minden billentyzet, lemez, kperny stb. mveletet egy driver segtsgvel az opercis rendszer dolgoz fel, s a programok az opercis rendszer megfelel fggvnyeit hvjk. DOS esetn mg csak nhnyszz ilyen volt, de manapsg mr sokezer. Ez teszi lehetv pldul, hogy minden Windowsos program ugyanolyan ablakot nyit, ha az Open parancsot vlasztjuk a File menben. Ez a fjlnyits ablak pldul a commdlg.dll-ben, vagyis a common dialog dinamic linked library-ben tallhat.

    Ha nem rtuk volna be az fflush(stdin); utastsokat mindenegyes scanf el, akkor elfordulhatna, hogy a felhasznl mondjuk azt rja be, hogy 1 2 3 4. Ebben az esetben ez a scanf gond nlkl beolvassa az 1-et a valasztott_ertek-be (az 1 utn szkz kvetkezik, ami nem szmjegy, ezrt itt abbahagyja a beolvasst, a puffer tovbbi tartalmt nem bntja). Ezutn (ahogy ltni fogjuk) a program megvizsglja a valasztott_ertek-et, s mivel 1-et tall benne, az osszead() fggvnyre ugrik. Ez a fggvny azzal kezdi, hogy beolvas kt vals szmot, az sszeadandkat. fflush nlkl ezek termszetesen a 2 s a 3 lesznek. Kiszmolja az sszeget, kirja, majd jra felteszi a krdst, hogy melyik mveletet vlasztjuk. Mivel a 4-es mg a pufferben maradt, azt beolvassa, s ezutn vrni fogja az osztandt s az osztt, hiszen a 4-es az osztst jelenti.

    Ha az fflush-t hasznljuk, akkor az osszead() ltal meghvott ket_double_beolvasasa() fggvnyben lv fflush() kirti a puffert, teht az utna kvetkez scanf vrni fogja, hogy most rjuk be a kt sszeadand rtket.

    // A vlasztott mvelet vgrehajtsa

  • 19

    switch(valasztott_ertek){ case 1: osszead(); break; case 2: kivon(); break; case 3: szoroz(); break; case 4: oszt(); break; case 5: gyok(); break; case 6: szinusz(); break; case 7: osztok(); break; /* case 8: logarit(); break; // termszetes logaritmus case 9: exponen(); break; */ case 10: break; default: printf("Hibas muveletszam (%d). Probalja ujra!",

    valasztott_ertek); }

    A switch utasts paramtere egy egsz tpus mennyisg, jelen esetben a valasztott_ertek. A

    program vgrehajtsa azzal az utastssal folytatdik, ahol a case utn szerepl rtk megegyezik a valasztott_ertek-kel. Ha egyik case-szel sem egyezik meg, akkor a default utni utasts jn.

    Minden sor vgn ltjuk a break; utastst. Ha kitrlnnk, akkor miutn az adott case sorra kerl a vezrls, s lefut az ott szerepl utasts (pldul az osszead() fggvny) akkor a kvetkez sorra menne tovbb a program, teht a kivon(); fggvnyre. Ha van break, akkor a switch-et lezr } utn folytatdik a vgrehajts.

    printf("\nTovabbi jo munkat!\n"); return 0; }

    Mivel a main() visszatrsi tpusa int, egy egsz rtket kell visszaadnunk. A 0 azt jelzi, hogy

    nem trtnt hiba. A hibt ltalban -1-gyel jelezhetjk. Ezt a visszatrsi rtket az opercis rendszer kapja meg. Windowsban szinte sohasem foglalkozunk vele, Unixban kicsit gyakrabban.

    1.4.5 A tbbi fggvny A tbbi fggvnyt kt csoportra oszthatjuk. Az egyik csoportba azok a fggvnyek tartoznak,

    amelyek a menbl kivlasztott matematikai mveletet vgrehajtjk, a msikba azok, amelyek bekrik a felhasznltl a szmtsokhoz szksges szmokat.

    Elszr nzzk ez utbbi csoportot. Egy vagy kt szm bekrse tulajdonkppen egy

    viszonylag ltalnos feladat, nem is igazn ktdik ehhez a programhoz. A matematikai mveleteknek megfelelen hrom ilyen fggvnyre lesz szksg, mert vannak mveletek, melyekhez kt vals szm szksges, vannak, melyekhez egy, s van egy olyan is, melyhez egy egsz szm. A hrom fggvny mkdse nagyon hasonl egymshoz, tulajdonkppen ha az egyik megvan, akkor a msik kett Copy+Paste-tel s nmi mdostssal elkszthet.

    Vegyk az egy vals szmot bekr fggvnyt!

    //******************************************************* double egy_double_beolvasasa(){ //******************************************************* int OK=0; double szam; while(OK==0){ printf("\nKerem a szamot: "); fflush(stdin); if(scanf("%lg",&szam)!=1)

    {printf("\nHibas szam, adja meg helyesen!\n"); continue;} OK=1;

  • 20

    } return szam; }

    A while ciklus addig fut, mg az OK egsz rtk vltoz rtke 0. Figyeljk meg, hogy annak vizsglatra, hogy az OK vajon egyenl-e nullval, kt darab egyenlsgjelet rtunk. Jegyezzk meg, hogy az egyenlsg vizsglatra mindig 2 db = jelet hasznlunk! Egy darab egyenlsgjel az rtkadst jelenti!

    Mi trtnne, ha azt rnnk: while(OK=0)? Nos, ebben az esetben az OK vltozba 0 kerlne, s a kifejezs azt jelenten, mintha ezt rtuk volna: while(0). Van-e ennek rtelme? Igen, a C nyelvben van. A C nyelvben ugyanis az egsz szmoknak igaz/hamis jelentse is van: a 0 hamisat jelent, minden ms egsz szm igazat! s mivel ebben az esetben 0, azaz hamis volna a zrjelben, a while ciklus egyszer sem futna le. Ennl is kellemetlenebb kvetkezmnye lehet, ha nem nulla van a while felttelben, hanem mondjuk 1: while(1). Ez ugyanis azt jelenti, hogy a ciklus rkk fut, vagyis vgtelen ciklust kaptunk. Ez pedig a program lefagyst eredmnyezheti. Elfordul, hogy szndkosan csinlunk vgtelen ciklust, ekkor azonban gondoskodunk arrl, hogy ki tudjunk lpni belle. Ciklusbl kilpni a break vagy a return utastssal tudunk (ezutbbival termszetesen az egsz fggvnybl kilpnk).

    A printf, fflush s scanf mkdst korbban mr ttekintettk: kirja a szveget, kirti a standard input puffert, s bekr egy double tpus szmot. A scanf-ben lg-vel jelltk, hogy double tpus vals szmot akarunk beolvasni. Ehelyett hasznlhatjuk az le s az lf vltozatot is, ezek beolvassnl ugyanazt jelentik (printf esetn klnbz a jelentsk).

    Az if utn ezttal kt utastst is tettnk, ezrt azokat {} kz kellett zrni. Ezek kzl a continue az j. Azt jelenti, hogy a ciklus elejre ugrunk, a felttelvizsglathoz, teht az utna kvetkez OK=1; utasts mr nem hajtdik vgre, ha nem sikerlt beolvasni az egy darab vals szmot (mert a felhasznl nem szmot rt).

    Ha sikerlt beolvasni a szam-ot, akkor az if felttele hamis, teht a {}-be tett rsz nem hajtdik vgre, hanem a kvetkez sorra lpnk, OK=1 lesz, a while felttele teht hamis lesz: nem fut le tbbszr a ciklus, hanem a return szam; kvetkezik.

    Az egsz szmot bekr fggvny gyakorlatilag ugyanez. Nzzk a kt vals szmot bekr fggvnyt!

    //******************************************************* void ket_double_beolvasasa(double * a, double * b){ //******************************************************* // Els szm bekrse int OK=0; while(OK==0){ printf("\nKerem az elso szamot: "); fflush(stdin); if(scanf("%lg",a)!=1)

    {printf("\nHibas elso szam, adja meg helyesen!\n"); continue;} OK=1; } // Msodik szm bekrse OK=0; while(OK==0){ printf("\nKerem a masodik szamot: "); fflush(stdin); if(scanf("%lg",b)!=1)

    {printf("\nHibas masodik szam, adja meg helyesen!\n"); continue;} OK=1; } }

  • 21

    Itt ktszer ugyanaz szerepel, mint az elz fggvnyben, azaz csak majdnem. A klnbsg az,

    hogy ezttal kt darab beolvasott rtket kell visszaadnunk. A return viszont csak egyet tud visszaadni. Mit tehetnk ebben az esetben? Kt pointert (mutatt) adunk paramterknt a fggvnynek, melyek egy-egy vals szmok trolsra szolgl vltozra mutatnak.

    Nzzk meg a scanf fggvnyek hasznlatt! Itt az a ill. b vltoz eltt nem szerepel az & jel, mert a s b nem vals szm, hanem vals szmra mutat pointer, pont az, amire a scanf-nek szksge van. Ltni fogjuk, hogy az & jel a ket_double_beolvasasa() fggvny meghvsakor fog szerepelni. (Egybknt lehetsges lett volna gy is megoldani, hogy csak az egyik szmot adjuk vissza gy, pointerrel, a msikat pedig a return-nel.)

    Kvetkeznek a szmol fggvnyek.

    //******************************************************* void osszead(){ //******************************************************* double a,b; printf("\nOsszeadas\n"); ket_double_beolvasasa(&a,&b); printf("\nAz osszeg: %g\n",a+b); }

    Ltrehozunk kt vltozt az sszeg kt sszeadandja szmra, bekrjk a kt szmot (ltjuk

    az & opertorokat: a s b cmt vesszk), majd kirjuk az sszeget. Az sszeg kirsra hasznlt printf kicsit bvebb, mint eddig lttuk: a scanf-re hasonlt, itt is

    ltunk benne egy %-os vezrl szekvencit, s a szveg utn vesszvel elvlasztva, az sszeadst.

    A float vagy double tpus szmok kirsra a %e, %f, %g szolgl, ezek kicsit ms formtumban rnak ki. A %le, %lf, %lg pedig a long double szmok kirsra szolgl. Ez egy logiktlansg, hiszen a scanf-nl lttuk, hogy ott ezeket a sima double szmok beolvassra hasznltuk. Rszletesebb ismertets, lsd pl. [1].

    A printf esetn a felsorols is klnbzik a scanf-tl, hiszen itt nem azt kell megmondanunk, hogy hol van a memriban, amit kirni szeretnnk, hanem az, hogy mit akarunk kirni, ezrt nem pointert, hanem rtket adunk meg, teht nem kell az & a vltoz neve el, st, ahogy itt is lthat, kifejezs is szerepelhet.

    Nzznk egy egy paramtert beolvas fggvnyt:

    //******************************************************* void gyok(){ //******************************************************* double a; printf("\nGyokconas\n"); a=egy_double_beolvasasa(); printf("\nA negyzetgyok: %g\n",sqrt(a)); }

    Ezttal az rtk az a=egy_double_beolvasasa(); mdon kerl az a-ba. A ngyzetgykt

    pedig az sqrt() fggvnnyel szmtjuk ki, melynek prototpusa (deklarcija) a math.h-ban tallhat (maga a fggvny pedig valamelyik .lib fjlban, amit a linker szerkeszt a ksz programhoz).

    //******************************************************* void osztok(){ //******************************************************* int a,i; printf("\nOsztok szamitasa\n"); a=egy_int_beolvasasa(); printf("\n%d osztoi:\n",a);

  • 22

    for(i=1;i

  • 23

    Build all: Mkdse hasonl a Make-hez, mindssze annyi a klnbsg, hogy akkor is jrafordtja a forrsfjlokat, ha azok nem vltoztak meg a legutbbi fordts ta.

    Microsoft VC++ 6.0 esetn a fordtssal sszefgg parancsok az IDE Build menjben,

    illetve az eszkztron is megtallhatk (ha a Build eszkztr be van kapcsolva). Compile valami.cpp: lefordtja a valami.cpp fjlt, obj. fjlt hoz belle ltre. Build Elso program.exe: lefordtja azokat a forrsfjlokat, melyek mdosultak a

    legutbbi fordts ta, majd a linker ltrehozza az .exe-t. Gyakorlatilag ugyanazt csinlja, mint a Borland Make parancsa.

    Rebuild All: a forrsfjlokat akkor is jrafordtja, ha nem mdosultak a legutbbi fordts ta. Ez pldul akkor lehet hasznos, ha idkzben megvltoztattuk a fordtt. Pldul az Intel C++ Compiler felteleptve bepl a Visual C++-ba, s ezutn magunk vlaszthatjuk ki, hogy az eredeti Microsoft fordtval kszljn az adott menetben a program, vagy az Intelvel (ezutbbi segtsgvel jelentsen felgyorsthatjuk a programunkat, mivel kihasznlja az MMX, SSE, SSE2, SSE3 utastskszleteket, s tovbbi jnhny optimalizcis eljrst is tartalmaz, melyeket a Microsoft fordtja nem). Az Intel fordtjnak idlimites, amgy teljes rtk prbavltozata regisztrci utn letlthet a vllalat honlapjrl.

    Mind Borland, mind Visual C++ esetben szmos lehetsg ll rendelkezsre, melyben a

    lefordtott program tulajdonsgait llthatjuk be. Ezek a lehetsgek a BC++ esetben az Options menben vannak, pldul az Options/Compiler/Advanced Code Generation-t vlasztva kivlaszthatjuk, hogy a fordt hasznlja a 386-os processzor utastskszlett, s a 387-es matematikai koprocesszor utastskszlett (a matematikai koprocesszor a Pentium ta minden processzor rsze, teht nincs rtelme ennl albb adni.

    Visual C++ esetn a Build men Set Active Configuration pontjban kt alaprtelmezett konfigurci kzl vlaszthatunk. Ltrehozhatunk tbbet is, de a kt alaprtelmezettnl tbbre csak a legritkbb esetben van szksg. A kt konfigurci a kvetkez:

    Debug: minden optimalizci ki van kapcsolva, az .exe fjlba belekerlnek a debuggolst segt kdok is. Emiatt ez gy kapott exe nagy s lass lesz.

    Release: a vglegesnek sznt vltozat, optimalizcival s a debuggolst segt kdok nlkl: release llsban nem tudunk debuggolni, csak ha megvltoztatjuk a konfigurcit, de akkor mr inkbb a debug mdot hasznljuk.

    A konfigurcikhoz tartoz belltsokat a Project men Settings pontjban llthatjuk be. Itt teljesen tszabhatjuk a belltsokat, akr olyannyira, hogy Release zemmdban legyen olyan, mint alaprtelmezs szerint Debug mdban, s fordtva. Ha a C/C++ fln kattintunk, s a Category legrdl listbl kivlasztjuk a Code Generation-t, akkor a Processor menben a 386-ostl a Pentium Pro-ig ll rendelkezsnkre a vlasztsi lehetsg. Aki ennl tbbet szeretne, annak ott az Intel Compiler, j pnzrt.

    Amennyiben a programunk szintaktikai hibt tartalmazott, teht valamit rosszul rtunk, esetleg

    lefelejtettnk egy zrjelet vagy pontosvesszt, az erre vonatkoz hibazenetek a kperny aljn jelennek meg. A hibazenetre kattintva a kurzor arra a sorra ugrik, ahol a hibt elkvettk a fordt szerint, de elfordulhat, hogy a hiba az elz sorban volt, pl. ott hagytuk le a pontosvesszt (ez a jelensg inkbb a Borland fordtjt rinti). Ha tbb hibt tall a fordt, akkor mindig fllrl lefel haladjunk ezek kijavtsban, mert gyakran elfordul, hogy a lejjebb lert hibk nem is hibk, hanem csak egy elbb lv hiba kvetkeztben mondja azt a fordt. Ilyen pldul akkor fordul el, ha lehagyunk egy zrjelet.

  • 24

    Ha sikerlt lefordtani a programot, az mg nem jelenti azt, hogy helyesen is mkdik. Vannak olyan esetek, amikor a program szintaktikailag helyes, teht le lehet fordtani, de a fordt tall olyan gyans rszeket, ahol hiba lehet. Ilyen esetekben figyelmeztetst (warning) r ki. A warningokat is nzzk t, s csak akkor hagyjuk figyelmen kvl, ha biztosak vagyunk benne, hogy j, amit rtunk.

    A kezd programoznak gyakran a szintaktikai hibk kijavtsa is nehz feladat, de k is r fognak jnni, hogy a szemantikai hibk (bugok) feldertse sokkal nehezebb, hiszen itt nem ll rendelkezsre a fordt segtsge, nem mondja meg, hogy itt s itt van a hiba, hanem a rendellenes mkdsbl erre neknk kell rjnnnk. A fejlesztkrnyezet azonban nem hagy ilyen esetekben sem eszkzk nlkl.

    A legegyszerbb eszkz a hibakezelsre, ha soronknt futtatjuk vgig a programot. Ehhez

    Borland C++ esetn a Run/Step over ill. Run/Trace into, Visual C++ esetn a Build men Start Debug almenjben pl. a Step Into-t vlasztva

    megjelenik a Debug men (s a debug eszkztr), itt megtalljuk a Step Over s a Step Into parancsot is.

    A Step/Trace Into s Over kztt az a klnbsg, hogy amennyiben egy adott programsorban fggvnyhvs szerepel, az Into paranccsal belpnk a fggvnybe, s annak sorain is vgigmehetnk. Ezzel szemben az Over parancs az egsz fggvnyt egy utastsnak tekinti, s egyben vgrehajtja.

    BC++-nl egy-egy sor lefutsa utn megnzhetjk a kimeneti kpernyt, ha lenyomjuk az Alt+F5 kombincit. Innen az any key :-) lenyomsval trhetnk vissza a programhoz.

    Tovbbi fontos parancs a Go to cursor (BC) ill. Run To Cursor (VC). Ha valamelyik programsorra belltjuk a kurzort, s kiadjuk ezt a parancsot, akkor a program normlisan fog futni egsz addig a sorig, ahol megll, s onnantl lptethetjk tovbb Step Intoval, ill. Step Overrel.

    Az eddigi parancsokkal csak azt vizsglhattuk, hogy mely utastsok hajtdnak vgre, s melyek nem, azonban ennl is tbb lehetsgnk van: megnzhetjk a vltozk rtkt, s folyamatosan figyelemmel ksrhetjk azt.

    Borlandnl vlasszuk a Debug/Watches/Add watch pontot, s rjuk be mondjuk azt, hogy valasztott_ertek. Alul megjelenik egy kis ablak, benne a vltoz nevvel, s ha a program egy olyan rszn lpkednk, ahol a vltoz ltezik, akkor megjelenik az aktulis rtke.

    Visualnl miutn Debug zemmdba kerltnk (pl. a Step Into-val, vagy a Run To Cursorral), alul megjelenik egy kettosztott ablak. Bal oldalon a fejelszkrnyezet automatikusan kivlasztja azokat a vltozkat, melyeket fontosnak tart, s eltnnek, mikor gy dnt, hogy mr nem fontosak. Jobb oldalon (alul Watch1 cmkvel) pedig mi magunk rhatunk be vltozneveket:

  • 25

    6. bra

    A fenti brn pp a harmadik printf eltt ll a kurzor, ezt mutatja a srga nyilacska.

    Automatikus rtk az elz printf visszatrsi rtke (a kirt karakterek szma), az ltalunk vlasztott vltozk az i s a valasztott_ertek. A main fggvnyben nem hasznlunk i nev vltozt, ezt jelzi a hibazenet, a valasztott_ertek most a kezdeti 0 rtket tartalmazza.

    Nem csak vltozk, hanem kifejezsek is vizsglhatk, pldul t[23], *yp vagy a+b is. A Debuggols a Run/Program reset (BC) ill. Debug/Stop Debugging (VC) paranccsal

    megszakthat, vagy a program normlisan futtathat tovbb a Run/Run ill. Go paranccsal. Kvetkez eszkznk a hibakeressre a trspontok behelyezse. A trspont (breakpoint)

    behelyezshez lltsuk a kurzort a kvnt sorra, majd BC esetn Debug/Toggle Breakpoint, VC esetn jobb klikk a soron, s Add/Remove Breakpoint. Ezutn BC-nl Debug/Breakpoints/Edit, ill. VC-nl Edit/Breakpoints/Condition vlasztsa esetn bellthatjuk, hogy milyen felttel teljeslse esetn lljon meg a program az adott sornl (pl. i==10), hnyszor menjen vgig a soron meglls nlkl, mikzben a felttel igaz (ha a felttelt resen hagyjuk, akkor azt nzi, hogy sszesen hnyszor ment mr vgig a soron, mieltt megllna, ha az ismtlsszmot hagyjuk resen, akkor az els alkalommal megll itt, amikor a felttel teljesl, ha mindkettt resen hagyjuk, akkor pedig mindig megll itt, amikor ider a program: ez olyan, mintha a Run To Cursort vlasztottuk volna).

    Feladat: lpkedjnk vgig a programon a Step Into, a Step Over, a Run To Cursor

    utastsokat kiprblva. Prbljuk ki a trspontok behelyezst is! Lehetsg van arra, hogy a fordtprogramok Assembly nyelv kdot generljanak (BC esetn

    Options/Compiler/Code generation/Options/Generate assembler source, VC esetn Project/Settings/(C/C++)/Category/Listing Files/Listing file type/Assembly with Source Code. Ez azoknak jelent segtsget, akik ismerik valamennyire az Assembly nyelvet.

  • 26

    7. bra

    Fjlkezelshez rendkvl hasznos eszkz a Total Commander, sokkal hatkonyabban lehet vele dolgozni, mint a My Computer-rel.

    Szmtalan hasznos funkcija kzl emltst rdemel, hogy kt fjlt knnyedn ssze tudunk hasonltani.

    A Borland C++ fordt csak azokat a fjlokat generlja, melyekrl eddig sz volt. Ezzel

    szemben a Visual C++ rengeteg olyat is ltrehoz, melyek a fordt munkjt knnytik meg. Mi kell ebbl neknk, s mi nem?

    Nos: a Debug s a Release mappt minden szvfjdalom nlkl trlhetjk. Ha kell az exe, akkor azt azrt elbb msoljuk t valahova. Amikor legkzelebb jrafordtjuk a programunkat, ezek automatikusan ismt ltrejnnek.

    A projekt fknyvtrbl a .cpp s .h fjlokra van szksgnk. Ha a tbbit letrljk, akkor legkzelebb ismt ltre kell hoznunk a konzol alkalmazs projektet az 1.2 pontban bemutatottak szerint, majd a projekthez hozz kell adnunk a .cpp s .h fjlokat.

    Ha teht haza akarjuk kldeni napi munknkat, akkor clszer elszr letrlni a Debug s Release mappt, majd a maradkot becsomagolni (Total Commanderrel Alt+F5), s ezt csatolni a levlhez. Ha nagyon szks a svszlessgnk, akkor csak a .cpp s .h fjlokat tmrtsk.

    Feladat: Egsztsk ki a programot a logaritmus s az exponencilis fggvny hasznlatnak lehetsgvel. Ehhez:

    a. Trljk ki a /**/ prosokat a megfelel printf s case rszekrl! b. Hozzuk ltre a logarit() s az exponen() fggvnyek prototpusait! c. Hozzuk ltre a logarit() s az exponen() fggvnyeket a gyok() vagy a szinusz()

    fggvnyek Copy+Paste-jvel, s mdostsuk gy hogy a fggvnyek a logaritmus ill. az exponencilis szmtsnak megfelelen mkdjenek! (A logaritmus kiszmtsra a log(), az exponencilis kiszmtsra az exp() fggvny hasznlhat.

  • 27

    2. Beolvass s kirs, tpusok, tmbk Az elz fejezetben tallkoztunk mr a kt legfontosabb fggvnnyel, melyekkel a beolvasst

    s a kpernyre rst megoldjk, ezek voltak a scanf() s a printf(). Ezeket hasznljuk leggyakrabban, most rszletesebben is megismerkednk velk. Megismernk nhny tovbbi beviteli (input) s kiviteli (output) fggvnnyel is.

    A fejezetben megismerkednk a C nyelv adattpusaival, s az els sszetett adatszerkezettel, a tmbbel.

    2.1 Programrts

    A programrts az idegennyelv tanulsnl ismert szvegrts megfelelje. Ebben a

    rszben teht a program megrtse, lefuttatsa, kiprblsa a feladat.

    //******************************************************* #include #include #include #include // egsz tpusok rtkkszlete #include // a valos tipusok tulajdonsagai //******************************************************* //******************************************************* void egesz(); void valos(); void string(); void tomb(); //******************************************************* //******************************************************* int main(){ //******************************************************* int valasztott_ertek=0; // egsz tpus vltoz 0 kezdrtkkel printf("I/O, tipusok, tombok\n"); // kirs while(valasztott_ertek!=10){ // ciklus, mg a v.. nem egyenl 10-zel // A men kirsa printf("\nKerem, valassza ki a muveletet!\n"); printf("1 Egesz tipusok\n"); printf("2 Valos tipusok\n"); printf("3 Stringek\n"); printf("4 Tombok\n"); printf("10 Kilepes\n"); // A vlasztott rtk beolvassa fflush(stdin); // standard input puffer rtse if(scanf("%d",&valasztott_ertek)!=1)valasztott_ertek=0; // A vlasztott mvelet vgrehajtsa switch(valasztott_ertek){ // a v..-nek megfele case utn folytatja case 1: egesz(); break; // az osszead fggvny hvsa case 2: valos(); break; case 3: string(); break; case 4: tomb(); break; case 10: break; default: printf("Hibas muveletszam (%d). Probalja ujra!",valasztott_ertek); } } printf("\nTovabbi jo munkat!\n"); return 0; } //******************************************************* void egesz(){ // Egsz szm I/O //*******************************************************

  • 28

    char c1; unsigned char c2; signed char c3; int i1; unsigned i2; // vagy unsigned int i2; short s1; // vagy short int l1; unsigned short s2; // vagy unsigned short int l2; long l1; // vagy long int l1; unsigned long l2; // vagy unsigned long int l2; // char csald printf("**************************************************************************\n"); printf("\nchar min=\t%d\nchar max=\t%d\n",CHAR_MIN,CHAR_MAX); printf("\nunsigned char min=\t0\nnunsigned char max=\t%d\n",UCHAR_MAX); // a min mindig 0 printf("\nsigned char min=\t%d\nsigned char max=\t%d\n",SCHAR_MIN,SCHAR_MAX); printf("\nA scanf karakterkent es nem szamkent kezeli a char tipust.\n"); printf("Adjunk meg egy karaktert, majd nyomjuk meg az ENTER-t!\n"); fflush(stdin); if(scanf("%c",&c1)!=1)printf("\nSikertelen beolvasas\n"); printf("A(z) %c karakter szamkent=\t%d\tvagy\t%u\n",c1,c1,c1); c2=(unsigned char)c1; c3=(signed char)c1; printf("A(z) %c karakter elojel nekluli karakterre konvertalva=\t%u\n",c1,c2); printf("A(z) %c karakter elojeles karakterre konvertalva=\t%d\n",c1,c3); // int csald printf("**************************************************************************\n"); printf("\nint min=\t%d\nint max=\t%d\n",INT_MIN,INT_MAX); printf("\nunsigned int min=\t0\nnunsigned int max=\t%u\n",UINT_MAX); // a min mindig 0 printf("\nA signed int ugyanaz, mint az int\n"); printf("\nAdjunk meg egy egesz szamot az int ertekkeszletben!\n"); fflush(stdin); if(scanf("%d",&i1)!=1)printf("\nSikertelen beolvasas\n"); i2=(unsigned)i1; printf("%i elojel nelkulive konvertalva=\t%u\n",i1,i2); printf("\nAdjunk meg egy nemnegativ egesz szamot az unsigned ertekkeszletben!\n"); fflush(stdin); if(scanf("%u",&i2)!=1)printf("\nSikertelen beolvasas\n"); i1=(int)i2; printf("%u elojelesse konvertalva=\t%d\n",i2,i1); // short csald printf("**************************************************************************\n"); printf("\nshort min=\t%hd\nshort max=\t%hd\n",SHRT_MIN,SHRT_MAX); printf("\nunsigned short min=\t0\nnunsigned short max=\t%hu\n",USHRT_MAX); // a min mindig 0 printf("\nA signed short ugyanaz, mint az short\n"); printf("\nAdjunk meg egy egesz szamot a short ertekkeszletben!\n"); fflush(stdin); if(scanf("%hd",&s1)!=1)printf("\nSikertelen beolvasas\n"); s2=(unsigned)s1; printf("%hi elojel nelkulive konvertalva=\t%hu\n",s1,s2); printf("\nAdjunk meg egy nemnegativ egesz szamot az unsigned short ertekkeszletben!\n"); fflush(stdin); if(scanf("%hu",&s2)!=1)printf("\nSikertelen beolvasas\n"); s1=(int)s2; printf("%hu elojelesse konvertalva=\t%hd\n",s2,s1); // long csald printf("**************************************************************************\n"); printf("\nlong min=\t%ld\nlong max=\t%ld\n",LONG_MIN,LONG_MAX); printf("\nunsigned long min=\t0\nnunsigned long max=\t%lu\n",ULONG_MAX); // a min mindig 0 printf("\nA signed long ugyanaz, mint az long\n"); printf("\nAdjunk meg egy egesz szamot a long ertekkeszletben!\n"); fflush(stdin); if(scanf("%ld",&l1)!=1)printf("\nSikertelen beolvasas\n"); l2=(unsigned)l1; printf("%li elojel nelkulive konvertalva=\t%lu\n",l1,l2); printf("\nAdjunk meg egy nemnegativ egesz szamot az unsigned long ertekkeszletben!\n"); fflush(stdin); if(scanf("%lu",&l2)!=1)printf("\nSikertelen beolvasas\n"); l1=(int)l2; printf("%lu elojelesse konvertalva=\t%ld\n",l2,l1); printf("**************************************************************************\n");

  • 29

    } //******************************************************* void valos(){ // Vals (lebegpontos) szm I/O //******************************************************* float f,f2; double d,d2; long double l,l2; // float printf("**************************************************************************\n"); printf("\nA legkisebb float pozitic ertek\t\t%g\n",FLT_MIN); printf("A legnagyobb float pozitic ertek\t%g\n",FLT_MAX); printf("\nAdjunk meg valos szamot!\n"); fflush(stdin); if(scanf("%g",&f)!=1)printf("\nSikertelen beolvasas\n"); // %e, %f, %g egyarnt hasznlhat printf("A szam harom alakban\t%e\t%f\t%g\n",f,f,f); // double printf("**************************************************************************\n"); printf("\nA legkisebb double pozitic ertek\t%g\n",DBL_MIN); printf("A legnagyobb double pozitic ertek\t%g\n",DBL_MAX); printf("\nAdjunk meg valos szamot!\n"); fflush(stdin); if(scanf("%lg",&d)!=1)printf("\nSikertelen beolvasas\n"); // %le, %lf, %lg egyarnt hasznlhat printf("A szam harom alakban\t%e\t%f\t%g\n",d,d,d); // long double printf("**************************************************************************\n"); printf("\nA legkisebb long double pozitic ertek\t%g\n",LDBL_MIN); printf("A legnagyobb long double pozitic ertek\t%g\n",LDBL_MAX); printf("\nAdjunk meg valos szamot!\n"); fflush(stdin); if(scanf("%Lg",&l)!=1)printf("\nSikertelen beolvasas\n"); // %le, %lf, %lg egyarnt hasznlhat printf("A szam harom alakban\t%Le\t%Lf\t%Lg\n",l,l,l); // A "vals" szmok diszkrt rtkkszlete printf("**************************************************************************\n"); for(f=1.0,f2=0.0;f!=f2;f*=1.2F,f2=f+1.0F); printf("Ket float ertek kozott >=1 a kulonbseg elelett az ertek felet: %g\n",f); for(d=1.0,d2=0.0;d!=d2;d*=1.2,d2=d+1.0); printf("Ket double ertek kozott >=1 a kulonbseg elelett az ertek felet: %g\n",d); for(l=1.0,l2=0.0;l!=l2;l*=1.2L,l2=l+1.0L); printf("Ket long double ertek kozott >=1 a kulonbseg elelett az ertek felet: %Lg\n",l); printf("**************************************************************************\n"); } //******************************************************* void string(){ // String I/O //******************************************************* char t[100],c; printf("**************************************************************************\n"); printf("Irjon be egy szoveget!\n"); fflush(stdin); if(scanf("%s",t)!=1)printf("\nSikertelen beolvasas\n");// Nincs & a t neve eltt printf("\nEzt irta: %s\n",t); printf("Ha volt benne szokoz, csak az elso szot olvasta be.\n"); printf("\nIrjon be meg egy szoveget!\n"); fflush(stdin); if(gets(t)==NULL)printf("\nSikertelen beolvasas\n"); puts("\nEzt irta: "); puts(t); puts("\nMost az egesz sort beolvasta\n"); printf("\nIrjon be egy karaktert(vagy tobbet), aztan ENTER!\n"); fflush(stdin); if((c=getchar())==EOF)printf("\nSikertelen beolvasas\n"); printf("Ezt irta: "); putchar(c); putchar('\n'); printf("**************************************************************************\n"); } //*******************************************************

  • 30

    void tomb(){ // Tmb I/O //******************************************************* double d[20]; int i,j; printf("**************************************************************************\n"); printf("Adjon meg max. 20 szamot! Ha befejezte a szamok magadasat, irjon 0-t!\n"); for(i=0;i

  • 31

    vlaszolni, hogy a 0 karaktert a 48-as szm trolja. Mi ennek az oka? Minden szmtgp azokat a karaktereket, melyeket pldul ebben a szvegben is olvashatunk, egy szmmal trolja. Hogy melyik karakterhez hnyas tartozik azt az ASCII szabvny rgzti. Eszerint a 0-t a 48, az 1-et a 49, a szkzt a 32, az A-t a 65, az a-t a 97 jelenti.

    Egy karaktert beolvasni vagy kirni a %c suffixszel lehet a scanf ill. printf fggvnyben. Karakterbeolvassra ill. kirsra szolgl a getchar ill. putchar fggvny, lsd 2.1.3

    Tpuskonverzi: c2=(unsigned char)c1; c3=(signed char)c1;

    Ezt rhattuk volna gy is: c2=c1; c3=c1;

    A msodikat implicit tpuskonverzinak nevezzk, mert nincs odarva, hogy milyen tpusra szeretnnk, az elst pedig explicit tpuskonverzinak, mert oda van rva a cltpus. gy nem csak karakterrl karakterre, hanem brmely ms egsz, vagy lebegpontos tpusra, ill. -rl tudunk konvertlni. Ha nem rjuk oda zrjelben a cltpust, bizonyos esetekben a fordt warninggal fogja jelezni, hogy az adott irny konverzi vesztesggel jrhat, hiszen ha pl. az int vltoz rtke 1000, akkor ez az rtk nem fog belefrni a charba. Ekkor is bele fog tenni valamit, de nyilvn nem 1000-et. Ha odarjuk a zrjeles rszt, akkor nem kapunk warningot, de az rtkads ugyangy hibs lesz, ha a cltpusba nem fr bele a forrs. Ha vals szmrl konvertlunk egszre, akkor kerekts trtnik.

    A fggvny kvetkez rsze az int tpussal foglalkozik. Ez a rsz (s a short ill. longgal

    foglalkoz rsz) hasonl a charhoz, ezrt kln nem trnk ki r, de a kdot mindenki nzze meg!

    Viszont itt kell kitrnnk arra, hogy hogyan is lesz a karakterbl szm. Amikor pl. az int tpusnl a %d (vagy %i, teljesen mindegy) szuffixszel beolvasunk egy egsz szmot, akkor a begpelt karakterekbl el kell lltani az egsz szmot. Pldul berjuk, hogy 123, s megnyomjuk az ENTER-t. a scanf megszmolja, hogy hny karakterbl ll a szm, aztn gy konvertlja: (els_karakter-48)*100+(msodik_karakter-48)*10+(harmadik_karakter-48). Azrt 48, mert, ahogy az elbb lttuk, a 0 karakter kdja 48, az 1- 49, s gy tovbb. Printf esetben pont fordtva jr el, ott az egsz szmbl kell karaktereket kszteni.

    2.1.2 Lebegpontos szmok A C nyelv hrom lebegpontos szm tpust hasznl:

    float: egyszeres pontossg lebegpontos szm, tipikusan 32 bites. Csak akkor hasznljuk, ha nagyon muszj, mert pontatlan.

    double: dupla pontossg lebegpontos szm, tipikusan 64 bites, a legtbb esetben megfelel pontossg.

    long double: mg nagyobb pontossg lebegpontos szm, az jabb fordtkban ez is 64 bites, s csak kln krsre 80 bites, mert a 80 bites mret memria-hozzfrs szempontjbl nem idelis.

    A lebegpontos azt jelenti, hogy a tizedespont nem marad a helyn, hanem elre ugrik az els

    rtkes szmjegy utn, s az egszet megszorozzuk egy kitevvel. Pldul a 6847.12 ebben a formban fixpontos, 6.84712103 formban pedig lebegpontos. Ezutbbi szmot C-ben gy rhatjuk: 6.84712e3, esetleg: 6.84712e+003. Nagy E-t is hasznlhatunk. A lebegpontos szmokat a gp termszetesen kettes szmrendszerben trolja, gy ez a szm 1.10101011111100011110101212, ha floatban troljuk. Float esetn ugyanis 23 bit ll az

  • 32

    rtkes szmjegyek trolsra (mantissza) + egy eljelbit, a pont eltt ll 1-est, s a pontot nem kell trolni, a kitev pedig -128 s +127 kztti (ez 8 bit). Double esetn a mantissza 51+1 bites, a kitev (karakterisztika) pedig 12 bit.

    A pldaprogramban lthatjuk azt a furcsasgot, hogy double tpus esetn a scanf s a printf eltr suffixet hasznl: printf-nl a float s a double egyarnt %e, %f s %g-vel rand ki, mg beolvasni a double-t %le, %lf s %lg-vel kell. A fordtprogramok el szoktk fogadni kirsnl is a %le stb. vltozatot.

    A hrom kirsmd jelentse: %e: kitevs alak, pl. 6.84712e+003 %f: fixpontos alak, pl.: 6847.12. Nullhoz kzeli szmoknl 0.00000-t r ki, de nagy

    szmoknl ez is kitevs alakot hasznl: 2.45868e+066. Ez egsz szmoknl is kiteszi a pontot, pl. 150.0000.

    %g: a kirs alkalmazkodik a szmhoz. Nullhoz kzel s tvol kitevs alak: 8.754e-019. A kett kztt fixpontos alak, pl. 6847.12. Az egsz szmokat egszknt rja, pl. 150.

    A kvetkez programrszlet egy igen fontos dologra hvja fel a figyelmnket:

    // A "vals" szmok diszkrt rtkkszlete for(f=1.0,f2=0.0;f!=f2;f*=1.2F,f2=f+1.0F); printf("Ket float ertek kozott >=1 a kulonbseg elelett az ertek felet: %g\n",f); for(d=1.0,d2=0.0;d!=d2;d*=1.2,d2=d+1.0); printf("Ket double ertek kozott >=1 a kulonbseg elelett az ertek felet: %g\n",d); for(l=1.0,l2=0.0;l!=l2;l*=1.2L,l2=l+1.0L); printf("Ket long double ertek kozott >=1 a kulonbseg elelett az ertek felet: %Lg\n",l);

    Br a knnyebb rthetsg rdekben gyakran mondjuk a szmtgp ltal hasznlt

    lebegpontos szmra, hogy vals, ez nem igaz, ugyanis csak a racionlis szmok egy tredkt trolhatjk, hiszen vges szm bitet hasznlunk. Ez az esetek nagy rszben nem jelent problmt, azonban mindig figyelemmel kell lennnk erre. A fenti programrszlet megmutatja, hogy krlbell hol van az a legkisebb rtk, amihez 1-et hozzadva nem vltozik meg a szm, mert kt trolhat rtk kztt tl naggy vlik a tvolsg. Egy egyszer 10-es szmrendszerbeli plda a kvetkez: ha pl. 1.2345106 ilyen pontossgban trolhat. Adjunk hozz egyet: 1.2345106=123450 => +1 => 123451 => 1.2345106. Teht eltnt a hozzadott 1, ugyanazt kaptuk vissza.

    Ez pldul olyan esetben jelenthet gondot, ha egy olyan gykkeres algoritmust futtatunk, amelyik kt oldalrl kzelti meg a gykt, s mondjuk az a lells felttele, hogy a kt kzelts klnbsge kisebb legyen, mint mondjuk 1e-5. Ha lefuttatjuk a fenti programot, lthatjuk, hogy float esetn mr 2e+007 eltt 1 lesz kt trolhat szm kztt a klnbsg, double esetn ez 9.8e+015 (long double esetn VC++ 7.0-val ugyanennyi).

    Mdostsuk a fenti programot, hogy azt rja ki, hogy mennyinl lesz 1e-5-nl nagyobb a klnbsg!

    A mdosts utn nekem az jtt ki, hogy float esetn 164.845 esetn mr ennl nagyobb volt a klnbsg! Teht ennl nagyobb gykk esetn kiakadhat a gykkeres program! Ezrt ne hasznljunk floatot! A double esetn 1.46e+011 a hatr, ami mr elegenden nagy rtk, hogy ne legyen gondunk.

    Hogy mkdik ez a for ciklus? Ez egy kicsit bonyolultabb, mint az eddigiek, ezrt nzzk meg

    kln! A pontosvesszket figyeljk, abbl tovbbra is kett van a zrjelen bell (minden for ciklusban kett, s csak kett van).

    Az els pontosvessz eltt van a kezdeti inicializls, ahol ezttal kt vltoznak is rtket adunk. Ez a rsz sszesen egyszer fut le, a tnyleges ciklus eltt.

  • 33

    A kt pontosvessz kztt van a felttel. A ciklus addig fut, mg ez igaz, vagyis a szm s a szmnl eggyel nagyobb szm nem egyforma.

    A msodik pontosvessz utni rsz mindig a ciklusmag utn fut le (a ciklusmag ezttal res, mert a ) utn csak egy ; ll). Itt elbb az egyik vltoz rtkt 1,2-vel szorozzuk, a msik vltoz pedig eggyel nagyobb rtket kap, mint az els. Az f*=1.2F ugyanazt jelenti, mintha azt rtuk volna: f=f*1.2F. A konstans utn ll F bet azt jelzi, hogy float tpusrl van sz, ha nem runk ilyet, akkor double, ha L-et runk, long double (f ill. l is hasznlhat). Egsz szmok esetn az L a long intet, U az unsigned intet jelenti. Nyilvn UL vagy LU az unsigned long. A shortnak nincs suffixe. A szabvnyrl bvebben pl. [2].

    2.1.3 Stringek Mr a kezdet kezdettl hasznlunk stringeket, azaz inkbb string konstansokat. A string

    konstansok kz zrt szvegek, pldul azok, amiket a printf-ben hasznlunk. A stringek (nem csak a konstansok) a kvetkezkpp helyezkednek el a memriban: (pl. a Jo munkat!\n):

    J o m u n k a t ! \n \0

    Itt minden egyes cella egy bjtot, vagyis egy char tpus vltozt jelent a memriban.

    Figyeljk meg, hogy az egyes karaktereket gondolatjelek kz zrtuk. C-ben gy jelljk a karakter konstansokat.

    A string vgn szerepel egy \0, ami a 0 szmot jelli (emlkezznk, hogy a 0 karakter, melyhez a 48-as szm tartozik, a 0-s szmhoz viszont a \0 karakter). Ezzel jelezzk, hogy itt van a string vge. A ksbbiekben mi is fogunk olyan fggvnyeket kszteni, amelyek stringeket dolgoznak fel, s addig mennek, mg egy \0-ba nem tkznek. Emiatt a \0 miatt a stringeknek mindig 1 karakterrel tbb hely kell, mint a string tnyleges hossza!

    Mit tegynk akkor, ha nem konstans stringre van szksg, hanem pldul a felhasznltl

    szeretnnk megkrdezni, mondjuk a nevt? Ehhez elszr is szksg van egy vltozra, ahol trolhatjuk. Ennek a vltoznak ugyanolyan formtumnak kell lennie, mint ahogy a Jo munkat!\n esetben ltjuk, vagyis sok egyms mellett ll karakterre van szksgnk, azaz egy karakter tmbre. gy adhatunk meg egy 100 elem karakter tmbt: char t[100];

    Ebben a tmbben teht maximum 100 karakter fr el, azaz egy 99 karakterbl ll string+ a lezr \0. Kisebb string is lehet benne, legfeljebb a vgt nem hasznljuk ki. Figyeljnk azonban arra, hogy akkora tmbmretet adjunk meg, amelybe biztosan belefr a string, mert ha tl kicsire csinljuk a tmbt, s tbbet runk bele, akkor a program ezt nem fogja szrevenni, s j esetben ezt a kedves zenetet fogjuk megkapni:

    8. bra

  • 34

    Itt clszer a Dont Sendet vlasztani, legalbbis ha nem az a clunk, hogy a Microsoftot

    bosszantsunk, hiszen k nem sokat tudnak kezdeni egy olyan program hibjval, amit mi magunk rtunk .

    Teht j esetben ezt az zenetet kapjuk, rossz esetben a tlrs megmarad a programunk sajt memriaterletn, gy ezt az opercis rendszer nem veszi szre, viszont ms vltozink adatai tnkremennek, s az ilyen rejtlyes hibk feldertse nehz feladat.

    A string beolvassa scanf-fel: scanf("%s",t) Figyeljk meg, hogy a t el nem rtuk az & opertort! A tmb neve (nem csak

    karaktertmb, brmilyen) a [] nlkl a tmb 0. elemre mutat pointer. A scanf pedig pont egy karaktertmb 0. elemre mutat pointert vr. (A C-ben a tmbk elemeinek sorszmozsa 0-tl n-1-ig megy, ahol az n az elemszm, jelen esetben 100.) Termszetesen megadhatjuk kzvetlenl is a 0. elemre mutat pointert, ez ugyanazt jelenti:

    scanf("%s",&t[0]) A scanf mellett hasznlhatjuk a gets fggvnyt is szvegbevitelre. A scanf htrnya, hogy

    csak az els szkzig olvas, teht ha valakitl a nevt szeretnnk megtudni, akkor a scanf-fel bajban lennnk, mg akkor is, ha ktszer egyms utn hvjuk, hiszen van akinek egy keresztneve van, van akinek kett, de elfordulhat tbb is. Szerencsre hasznlhatjuk a gets fggvnyt, mellyel egy egsz sort olvashatunk be.

    A gets prja a puts. A puts(t) ugyanazt csinlja, mint a printf(%s,t). Karakter beolvassra hasznlhatjuk a scanf(%c,&c) helyett a c=getchar()-t is. Sikertelen

    beolvass esetn a getchar EOF (End Of File) rtket ad vissza. A getchar ellentte a putchar.

    2.1.4 Tmbk Abban az esetben, ha ugyanabbl a vltoztpusbl tbb ezerre, netn tbb millira van

    szksg, nem csak macers, hanem lehetetlen is minden egyes elemnek kln vltoznevet hasznlni, ha sikerlne is, a kezelsk rendkvl megbonyoltan a program mkdst.

    A tmb olyan sszetett vltoz tpus, mely adott szm, azonos tpus elembl ll. Ltrehozsakor a nv utn szgletes zrjelben kell megadni az elemek szmt:

    double d[20];

    Ez egy 20 elem, double elemeket trol tmb. A [] kz tett nemnegatv egsz szm a

    tmbelem indexe. Fontos, hogy a tmb indexelse 0-tl kezddik, ezrt a legnagyobb index elem indexe eggyel kisebb, mint a tmb mrete, jelen esetben 19.

    Ezt jl jegyezzk meg! A tmb mretnek megadshoz kizrlag konstans, teht a fordts idejn ismert

    rtket hasznlhatunk! (Nem krdezhetjk meg a felhasznlt, hogy az ltala megadott mrettel definiljuk a tmb mrett!)

    double d[20]; d[ 0]=12.3; // A tmb els eleme d[19]=-8.1; // A tmb utols eleme d[20]=3.14; // HIBS!!! Kvetkezmny lsd a 8. brn!

  • 35

    A tmb tovbbi elnye az egyedi vltozkhoz kpest az is, hogy a tmbelem indexe nem csak konstans, hanem egsz tpus vltoz is lehet. gy egyszer egy ciklussal a tmb elemeit feldolgozni. A pldaprogramban elszr feltltjk egy ciklussal.

    for(i=0;i

  • 36

    3. rjunk programot, amely bekr egy pozitv egsz szmot, s kiszmtja a faktorilist. A faktorilist double tpus vltozval szmoljuk, hogy nagy megadott szmoknl is mkdjn!

    4. rjunk C programot, amely bekr hrom pozitv szmot, s eldnti, hogy lehetnek-e egy hromszg oldalai.

    5. rjon C programot, amely a felhasznl ltal Celsiusban megadott hmrskletet Farenheitben adja vissza.

    6. rjon C programot, amely eldnti egy bekrt pozitv egsz szmrl, hogy prm-e! 7. rjon C programot, amely kirja a felhasznltl bekrt pozitv egsz szm prmtnyezs

    felbontst.

  • 37

    3. Feltteles elgazsok, ciklusok, opertorok if, case, rendezs, bitszmlls

    3.1 Programrts

    Ezttal tbb klnll programot nznk.

    //******************************************************* #include #include //******************************************************* //******************************************************* void error(char s[]){ //******************************************************* printf("\n\nHiba: %s\n",s); exit(-1); // kilpnk a programbl } //******************************************************* main(){ //******************************************************* double a,b,c,max; printf("Adjon meg harom szamot!\n+); printf(" a : "); if(scanf("%lf",&a)!=1)error("Hibas adat!"); printf(" b : "); if(scanf("%lf",&b)!=1)error("Hibas adat!"); printf(" c : "); if(scanf("%lf",&c)!=1)error("Hibas adat!"); if(a>b){ // ha a nagyobb mint b, akkor if(a>c)max=a; else max=c; } else{ // egybknt (vagyis ha a nem nagyobb, mint b) if(b>c)max=b; else max=c; } printf("Maximum: %f\n",max); }

    Hrom szm kzl kirja a legnagyobbat. Mg egy varici ugyanerre:

    //******************************************************* main(){ //******************************************************* double a,b,c,max; printf("Adjon meg harom szamot!\n+); printf(" a : "); if(scanf("%lf",&a)!=1)error("Hibas adat!"); printf(" b : "); if(scanf("%lf",&b)!=1)error("Hibas adat!"); printf(" c : "); if(scanf("%lf",&c)!=1)error("Hibas adat!"); max=c; if(a>b&&a>c)max=a; else if(b>c)max=b; printf("Maximum: %f\n",max); }

    Az error() fggvnyt s az include-okat csak az els programnl rtuk ide, de termszetesen a

    msodikhoz is hozz tartoznak. Az error() fggvny bemen paramtere egy karaktertmb. Figyeljk meg, hogy nem adtuk meg a tmb mrett!

    A kvetkez program ismt kt vltozatban megmondja, hogy a begpelt karakter kisbet,

    nagybet vagy szm.

    #include main(){ int ch; printf("karakter: "); fflush(stdin); ch=getchar(); if(ch>='0'&&ch

  • 38

    if(ch>='A'&&ch='a'&&ch='0' s ch

  • 39

    //******************************************************* void biztonsagos(){ //******************************************************* int c; // Ezttal int-et hasznlunk karakter trolsra, de lehetne char is printf("**************************************************************************\n"); printf("\nA kovetkezo kerdesre igen eseten I,i,Y,y valasz adhato, nem eseten N es n.\n"); printf("Miztonsagos?\n"); fflush(stdin); c=getchar(); switch(c){ case 'i': case 'I': case 'y': case 'Y': printf("Biztonsagos.\n"); break; case 'n': case 'N': printf("Cseppet sem biztonsagos.\n"); break; default: printf("Nem tudom.\n"); } printf("**************************************************************************\n"); } //******************************************************* voi