C03.qxd
9/1/2008
12:53 PM
Page 13
3 Elsõ programunk lefordítása és futtatása Ebben a fejezetben az olvasó bevezetést kap a C programozás gyakorlatába. És mi mással is lehetne ezt hatásosabban szemléltetni, mint egy igazi C nyelvû programmal? Kezdjük tehát egy egyszerû programmal, amely mindössze annyit ír ki a képernyõre, hogy Programming is fun. Ezt a feladatot valósítja meg a 3.1 Listában látható kód. 3.1 Lista • Elsõ C programunk #include <stdio.h> int main (void) { printf ("Programming is fun.\n"); return 0; }
A C programozási nyelvben különbözõnem számítanak a kis- és nagybetûk. Az utasítások egy soron belül bárhol elkezdõdhetnek, amely lehetõséget felhasználhatjuk programjaink olvashatóbbá tételéhez. A programozók gyakran tabulátorral oldják meg a sorok tagolását.
A program lefordítása Visszatérve elsõ C programunk megírásához az elsõ lépés nem más, mint egy szöveges állomány elkészítése. Bármilyen egyszerû szövegszerkesztõ alkalmas erre a célra. A Unix felhasználók például gyakran a vi-t vagy az emacs-ot használják. A legtöbb C fordító onnan ismeri fel a C programokat, hogy „.c”-re végzõdik a nevük. Tegyük fel tehát, hogy a 3.1 Listának megfelelõ programot egy prog1.c nevû szövegfájl tartalmazza. Ezek után már csak a program lefordítása van hátra. Ha GNU C fordítót használunk, akkor ez az alábbi egyszerû parancs kiadásával történik: $ gcc prog1.c
C03.qxd
9/1/2008
14
12:53 PM
Page 14
Programfejlesztés C nyelven Ha a szabványos Unix C fordítót használjuk, akkor gcc helyén cc áll. A begépelendõ karaktereket félkövéren szedtük. A dollár jelképezi a a parancssori promptot (készenléti jelet), amennyiben terminálablakból indítjuk a fordítást. Az olvasó gépén a promptkarakter természetesen ettõl eltérõ is lehet. Ha valami hiba csúszott a kódba, a gcc parancs kiadását követõen a fordító visszajelzést küld. Ilyenkor általában megjelenik a hibás részletet tartalmazó sor száma is. Ha egyszerûen csak visszakapjuk a promptot, az arra utal, hogy hibátlanul lefordult a program. Amikor a fordító lefordítja és linkeli a programot, akkor tulajdonképpen annak egy (számítógép által) végrehajtható változatát hozza létre. A GNU vagy a szabványos C fordítót használva ennek a neve alapértelmezésként a nem túl beszédes a.out lesz . Windows alatt a végrehajtható program gyakran az a.exe nevet viseli.
A program futtatása Ezek után a program futtatása mindössze abból áll, hogy begépeljük a parancssorba a program nevét1: $ a.out Programming is fun. $
Természetesen ettõl eltérõ nevet is adhatunk a végrehajtható állománynak már a fordítás során. A -o kapcsoló (azaz a kis o betû) után írhatjuk be a kívánt fájlnevet. Az alábbi utasítás hatására például a prog1.c program futtatható változatának neve prog1 lesz: $ gcc prog1.c –o prog1
A program a név beírásával indítható: $ prog1 Programming is fun. $
1
Ha az a.out: No such file or directory, (a.out: Nincs ilyen állomány vagy könyvtár) hibajelzést kapjuk, akkor ez valószínûleg azt jelenti, hogy az aktuális könyvtár nem szerepel az elérési utak között, vagyis nincs benne a PATH változóban. Ezen egyszerûen módosíthatunk, vagy ha ezt nem szeretnénk, hivatkozhatunk kifejezetten az aktuális könyvtárra programunk indításakor a következõ módon: ./a.out.
C03.qxd
9/1/2008
12:53 PM
Page 15
3. fejezet • Elsõ programunk lefordítása és futtatása
Vizsgáljuk meg elsõ programunkat Vegyük jobban szemügyre elsõ programunkat. A program elsõ sorában látható utasítást szinte minden C program elején megtaláljuk: #include <stdio.h>
Ez tudósítja a fordítóprogramot arról, hogy a program késõbbi részében szereplõ printf kimeneti parancsot hogyan kell megvalósítani. A 13. fejezetben tárgyaljuk majd ennek a részleteit. A program következõ sora szerint a program belépési pontjául szolgáló függvény neve main, futása végeztével pedig egy egész (integer, rövidítve: int) számértéket fog az operációs rendszernek visszaadni. int main (void)
Maga a main egy speciális név; azt jelzi, hogy a program végrehajtását a kódon belül hol kell elkezdeni. A main után álló zárójelpár arra utal, hogy egy függvényrõl van szó. A zárójelben álló void (üres) kulcsszó pedig jelzi, hogy ez a függvény nem vár paramétert. Ezek a fogalmak a legapróbb részletekig elõkerülnek majd a 8. fejezetben. Miután jeleztük a rendszernek, hogy a main függvény következik, ideje megadni, hogy mi is lesz az elvégzendõ feladat. Ezt úgy oldjuk meg, hogy a megfelelõ programlépéseket kapcsos zárójelek közé foglaljuk. Az összes parancsot, ami a most következõ kapcsos zárójelek között szerepel, a main függvény részének tekinti a fordítóprogram. A 3.1 Listában ez mindössze két utasításból áll. Az elsõbõl az derül ki, hogy egy printf nevû eljárást szeretnénk meghívni. A számára átadandó paraméter egy karakterlánc: "Programming is fun.\n"
A printf eljárás a C programkönyvtár része. Feladata egyszerûen annyi, hogy kiírja a képernyõre a neki átadott paramétert (vagy paramétereket, amint azt késõbb látni fogjuk). A két utolsó karakter a „\” (backslash) és az „n” a közmegegyezés szerint az újsor karaktert jelenti. Az újsor karakter pontosan azt jelenti, amit a neve sugall: egy új sor kezdetére viszi a kimeneti megjelenítést. Az ezt követõ karakterek már ebben az új sorban jelennek meg. Ez igen hasonlít a régmúlt idõk írógépeinek „kocsi vissza” mûveletéhez. (Emlékszik még egyáltalán valaki erre?) A C nyelvben minden utasítást pontosvesszõvel (;) kell lezárni – emiatt látható a printf utasítás meghívását követõen is a pontosvesszõ.
15
C03.qxd
9/1/2008
16
12:53 PM
Page 16
Programfejlesztés C nyelven Az utolsó utasítás azt jelzi, hogy a main végrehajtásának befejeztével 0 lesz a futási állapotra utaló visszatérési érték: return 0;
Itt bármilyen más egész számot használhatunk. A nulla a közmegegyezés szerint azt jelenti, hogy a program sikeresen, azaz hiba nélkül lefutott. A különbözõ számok különféle hibajelenségekre utalhatnak (például arra, hogy a program nem talált meg egy állományt). A futási állapotra utaló visszatérési értéket más programok (például a Unix héj) könnyen meg tudják vizsgálni. Bizonyos helyzetekben fontos lehet tudni, hogy hibátlanul lefutott-e egy-egy program. Elsõ programunk végiggondolása után vehetjük a bátorságot ahhoz, hogy módosítsunk rajta egy keveset. Írassuk ki vele például azt is, hogy And programming in C is even more fun. (És C-ben programozni még nagyobb öröm). Ez egy újabb printf utasítással oldható meg, ahogy az a 3.2 Listában látható. Ne feledkezzünk el arról, hogy minden C utasítást pontosvesszõvel kell lezárni. 3.2 Lista #include <stdio.h> int main (void) { printf ("Programming is fun.\n"); printf ("And programming in C is even more fun.\n"); return 0; }
Ha begépeljük a 3.2 Listát, majd lefordítjuk és futtatjuk, akkor az alábbi kimenetet kapjuk a parancssorban (vagy terminálablakban). 3.2 Lista • Kimenet. Programming is fun. And programming in C is even more fun.
A következõ kódrészlet arra mutat rá, hogy a kimenet különbözõ sorait nem feltétlenül kell különálló printf utasításokkal kiíratni. Arra kérem az olvasót, hogy vegye szemügyre a 3.3 Listát, és próbálja megjósolni a kimenetét anélkül, hogy megnézné a könyvben. Nem szabad csalni!
C03.qxd
9/1/2008
12:53 PM
Page 17
3. fejezet • Elsõ programunk lefordítása és futtatása 3.3 Lista • Többsoros kimenet kijelzése #include int main { printf return }
<stdio.h> (void) ("Testing...\n..1\n...2\n....3\n"); 0;
3.3 Lista • Kimenet Testing... ..1 ...2 ....3
Változók értékének megjelenítése Könyvünkben a printf valószínûleg a leggyakoribb utasítás, mivel egyszerû és kényelmes módon lehetõvé teszi egy program futási eredményeinek a kijelzését. Nemcsak elõre megfogalmazott szövegeket lehet vele kiíratni, hanem változók értékét vagy számítások végeredményét is. Példaként nézzük meg a 3.4 Listát, melyben a printf utasítással két szám (50 és 25) összegét íratjuk ki a képernyõre. 3.4 Lista • Változók kijelzése #include <stdio.h> int main (void) { int sum; sum = 50 + 25; printf ("The sum of 50 and 25 is %i\n", sum); return 0; }
3.4 Lista • Kimenet The sum of 50 and 25 is 75
A 3.4 Lista fõprogramjában az elsõ utasítás nem más, mint a sum változó deklarációja. Itt jelezzük, hogy ez egy egész (int) típusú változó lesz. A C nyelvben minden változót deklarálni kell annak használata elõtt. A fordítóprogram számára itt derül ki, hogy miként kell bánnia az adott változóval, milyen szerepe lesz a programban. Ez az információ ahhoz szükséges, hogy a lehetõ leghatékonyabb gépi utasítássor jöhessen létre a változók értékeinek eltárolásához és visszanyeréséhez. Egy egészként deklarált változó csak (tizedes-
17
C03.qxd
9/1/2008
18
12:53 PM
Page 18
Programfejlesztés C nyelven tört nélküli) egész számokat tárolhat, például ilyeneket: 3, 5, –20, 0. A tizedestörtet is tartalmazó számokat (mint például 3.14, 2.455, vagy 27.0) lebegõpontos vagy valós számoknak hívjuk. A sum egész változó tárolja a két egész szám, az 50 és a 25 összegét. Szándékosan maradt ki egy sor a változó deklarációja és elsõ használata között, hogy vizuálisan is nyilvánvaló legyen: más a szerepe a deklaráció(k)nak és a program utasításainak. Ez az elkülönítés ugyanakkor csak stiláris, sokszor olvashatóbbá válik tõle a programkód. Az összeadás szinte minden programnyelven ugyanígy néz ki: sum = 50 + 25;
Az 50-et (ahogy az a plusz jelbõl látszik) hozzáadjuk a 25-höz, az eredményt pedig (az egyenlõségjellel jelölt hozzárendelési operátorral) a sum változóba helyezzük. A printf utasításnak most két paramétere van, melyek a zárójelben vesszõvel elválasztva sorakoznak egymás után. Az elsõ paraméter egy karakterlánc, amit meg szeretnénk jeleníteni. Programjainkban gyakran nem csupán elõre meghatározott szövegeket szeretnénk kiíratni, hanem bizonyos változók értékeit is. Esetünkben a sum változó értékét szeretnénk megjeleníteni a The sum of 50 and 25 is
szövegrész után. Az itt felbukkanó százalék szimbólumnak speciális jelentése van a printf számára. A százalék utáni karakterbõl derül ki az itt megjelenítendõ változó típusa. Programunkban az i karakterrel jelezzük a printf utasításnak, hogy egy egész (integer) számot kell kiírnia.2 Amikor a printf utasítás egy %i szimbólumot talál az elsõ paraméterben, akkor annak helyén (egész számként) megjeleníti a következõ paraméter értékét. Példánkban a sum a második paraméter, így ennek értéke fog megjelenni a The sum of 50 and 25 is
szövegrész után. Próbáljuk megint megjósolni a 3.5 Lista kimenetét a program alapján.
2
Bár a printf utasítás a %d szimbólumot is elfogadja az egész típus jelzésére, a könyvben a %i használata mellett maradunk.
C03.qxd
9/1/2008
12:53 PM
Page 19
3. fejezet • Elsõ programunk lefordítása és futtatása 3.5 Lista • Több érték kijelzése #include <stdio.h> int main (void) { int value1, value2, sum; value1 = 50; value2 = 25; sum = value1 + value2; printf ("The sum of %i and %i is %i\n", value1, value2, sum); return 0; }
3.5 Lista • Kimenet The sum of 50 and 25 is 75
A program elsõ utasítása egészként (int) határozza meg a value1, value2, és a sum változókat. Ez akár három különálló deklarációs sorban is megadható: int value1; int value2; int sum;
A három változó deklarációja után a program hozzárendeli az 50-et a value1-hez, illetve a 25-öt a value2-höz. Kiszámítjuk ezek összegét, és az eredményt hozzárendeljük a sum változóhoz. A printf utasítást most négy paraméterrel hívjuk meg. Az elsõ paraméter (a formátumleíró karakterlánc) megadja, hogy hogyan történjen a hátralevõ paraméterek megjelenítése. A value1 értéke rögtön a „The sum of” szövegrész után jelenik meg. Ehhez hasonlóan a value2 és a sum értékének is ott kell megjelennie, ahol a formátumleíró karakterláncban a következõ két %i szerepel.
Megjegyzések A fejezet utolsó programjában (3.6 Lista) kerül elõ a megjegyzés fogalma. A megjegyzéseknek az a szerepe, hogy programjainkban dokumentálni tudjuk a fontosabb mozzanatokat, javítva ezzel azok olvashatóságát. Ahogy a következõ példán látni fogjuk, a megjegyzésekkel tájékoztathatjuk a program olvasóját arról, hogy mi volt a programozó fejében, amikor egy programot (vagy egy adott kódrészletet) megírt. A „program olvasója” lehet maga a szerzõ, de bárki más is, akinek késõbb karban kell tartania azt.
19
C03.qxd
9/1/2008
20
12:53 PM
Page 20
Programfejlesztés C nyelven 3.6 Lista • Megjegyzések használata a programban /* A program két egész értéket ad össze, majd megjeleníti az eredményt
*/
#include <stdio.h> int main (void) { // Változók deklarációja int value1, value2, sum; // Az értékek változókhoz rendelése és összeadása value1 = 50; value2 = 25; sum = value1 + value2; // Az eredmény kiíratása printf ("The sum of %i and %i is %i\n", value1, value2, sum); return 0; }
3.6 Lista • Kimenet The sum of 50 and 25 is 75
Kétféleképp is lehet megjegyzéseket illeszteni a C nyelvû programokba. Lehet perjellel és csillaggal: /* kezdeni egy megjegyzést, mely egészen a csillag és perjel: */ szimbólumpárig fog tartani. Az a szövegrész, mely e két jelpár: /* és */ között áll, mellõzve lesz a program fordításakor. Ez a fajta megjegyzés akkor elõnyös, amikor több sort szeretnénk megjegyzésbe tenni. A másik lehetõség rövid megjegyzések írására alkalmas. Írjunk két perjelt közvetlenül egymás után: //. Innentõl egészen a sor végéig megjegyzésnek tekinti a fordítóprogram a szöveget. A 3.6 Listában négy megjegyzés is szerepel. Ezektõl eltekintve maga a program teljesen megegyezik a 3.5 Listában bemutatottal. Valljuk meg, hogy a négy közül igazából csak a program elején álló megjegyzést nevezhetjük hasznosnak, a többi csak a módszer bemutatását szolgálja. (Azt is láthatjuk, hogy az apró és haszontalan megjegyzések tömkelege inkább rontja egy program olvashatóságát, semmint javítja.) Nem lehet eléggé hangsúlyozni az intelligens megjegyzések fontosságát. Számtalanszor elõfordul, hogy egy programozó beleolvas saját, fél éve írt programjába, és szinte kiveri a hideg verejték, mert egyszerûen elképzelése sincs, hogy egy-egy kódrészlettel mi volt a célja az adott helyen. Ezen egy megfelelõen elhelyezett, józanul megfogalmazott rövid megjegyzés rengeteget segíthet. Megjegyzések hiányában ugyanakkor hihetetlen mennyiségû idõt lehet elpazarolni programjaink, algoritmusaink logikájának újrafelfedezésével.
C03.qxd
9/1/2008
12:53 PM
Page 21
3. fejezet • Elsõ programunk lefordítása és futtatása Jó hozzászokni ahhoz, hogy már a program kódolásakor beírjuk a megfelelõ megjegyzéseket. Ennek több oka is van. Egyrészt sokkal könnyebb dokumentálni a programot, míg annak logikája még frissen a fejünkben van, mintsem a program megírásának végeztével újra átgondolni mindent. Másrészt nagyon hasznos lehet, ha már a program megírásának korai szakaszában megfelelõ helyre kerülnek a megjegyzések. Az esetleges logikai hibák feltárásakor, a nyomkövetéskor óriási segítséget jelenthet egy-egy jól eltalált szöveges iránymutatás. A megjegyzések nemcsak abban segítenek, hogy megértsük a program mûködését, hanem abban is, hogy könnyebben rátaláljunk egy-egy hibára. Meg kell persze azt is jegyeznem, hogy még nem találkoztam olyan programozóval, aki örömét lelte volna a megjegyzések írásában, vagy a program dokumentálásában. Amikor egy nehezebb hibakeresés végére ér az ember, nem szívesen áll neki megjegyzéseket írni. Ha azonban a megjegyzéseket már a program fejlesztése közben megírjuk, könnyebben elviselhetõ a dokumentálás kínos kötelessége is. Ezzel végére is értünk rövid „technikai bevezetõnknek”. Azzal a megnyugtató érzéssel térhet nyugovóra az olvasó, hogy már írt C programot, és ha úgy adódik, szinte bármilyen más programot is meg fog tudni írni a késõbbiekben. A következõ fejezetben újabb finomságokat tanulunk meg errõl a gyönyörû, hatékony és rugalmas programozási nyelvrõl. De elõtte végezzünk még néhány ujjgyakorlatot hiszen érdemes konkrét kérdések segítségével tisztázni, hogy valóban megértettük-e a fejezetben tanult fogalmakat.
Gyakorlatok 1. Gépeljük be és futtassuk le a fejezetben szereplõ hat példaprogramot! A kimeneteket hasonlítsuk össze a könyvben szereplõ programkimenetekkel. 2. Írjunk programot, mely a következõ szöveget írja ki a képernyõre: 1. A C nyelvben különbözõnek számítanak a kis- és nagybetûk. 2. A main kulcsszó jelzi a program végrehajtásának kezdetét. 3. A nyitó és záró zárójelek egy kódblokkba zárják az utasításokat. 4. A program minden utasítását pontosvesszõvel kell lezárni. 3. Milyen kimenetet várunk az alábbi programtól? #include <stdio.h> int main (void) { printf ("Testing..."); printf ("....1"); printf ("...2"); printf ("..3"); printf ("\n"); return 0; }
21
C03.qxd
9/1/2008
22
12:53 PM
Page 22
Programfejlesztés C nyelven 4. Írjunk programot, amely 87-bõl kivon 15-öt, és az eredményt (egy szöveges üzenet részeként) a képernyõre írja! 5. Keressük meg az alábbi programban megbúvó szintaktikai hibákat! A hibamentes változatot gépeljük be és próbáljuk ki! Így lehet a legbiztosabban meggyõzõdni arról, hogy valóban minden hibát megtaláltunk. #include <stdio.h> int main (Void) ( INT sum; /* COMPUTE RESULT sum = 25 + 37 - 19 /* DISPLAY RESULTS // printf ("The answer is %i\n" sum); return 0; }
6. Mi lesz az alábbi program kimenete? #include <stdio.h> int main (void) { int answer, result; answer = 100; result = answer - 10; printf ("The result is %i\n", result + 5); return 0; }