2. gyakorlat¶
Fejlesztői környezet¶
Szövegszerkesztő¶
Amikor elkezdünk programozni, akkor amire biztosan szükségünk lesz az egy szövegszerkesztő. Fontos, hogy olyan szövegszerkesztőt használjunk, amit nem formázott szöveg szerkesztésére terveztek (MS Word, OpenOffice Writer, stb. kizárva), hanem egyszerű (plain text) szövegek írására.
Linux és Windows alatt használható néhány szövegszerkesztő:
- Sublime text
- Geany
- Atom
- VS Code
- Gedit (csak Linux)
- mcedit (Linux - terminálban használható)
- nano (Linux - terminálban használható)
- vi/vim (Linux - terminálban használható, advanced (mármint haladó felhasználóknak))
Miután kiválasztottuk a számunkra megfelelő szövegszerkesztőt, mellyel a programokat fogjuk írni, szükségünk lesz egy fordítóprogramra is, amivel a forráskódból futtatható (bináris) állományt hozunk létre. Ilyen például a gcc (GNU Compiler Collections), ami alapvetően Linux alatt érhető el, de Windows-ra is felvarázsolható (MinGW).
Megjegyzés
Az előre telepített image-en már van gcc
telepítve, így aki azt használja nyugodtan ugorja át a következő részeket!
gcc telepítés Linux alatt¶
- Nyiss egy terminált!
sudo apt update
sudo apt install build-essential
sudo apt-get install manpages-dev
gcc --version
A 2. sor frissíti a telepíthető csomagok listáját, a 3. sorban telepítjük a fejlesztéshez szükséges alapvető eszközöket, melyek között a gcc is megtalálható. A 4. sor opcionális jellegű, de hasznos lehet, mivel felhasználói kézikönyvet (manual) telepíti a fejlesztőeszközökhöz, azaz a gcc-hez is. Az utolsó sorral validálhatjuk, hogy a gcc valóban telepítésre került. Valamilyen hasonló kimenetet kell kapnunk:
Kimenet
1 2 3 4 |
|
gcc telepítés Windows alatt¶
Ehhez egy kicsit több lépésre van szükségünk.
-
lépés: MinGW (Minimalist GNU for Windows) telepítése
Töltsük le a MinGW Installer-t, majd alapbeállításokkal telepítsük a rendszert! Én a telepítőben a
C:\MinGW
könyvtárat adtam meg, így a továbbiakban ezt használom majd. Amennyiben valaki ezt máshová adta meg, az majd az útvonalakat ennek függvényében módosítsa. -
Amikor a MinGW elindult (ha nem indult el magától akkor MinGW Installation Manager-t kell keresned), bal oldalon válaszd a "Basic Setup"-ot, és mellette jobbra jelöld ki
mingw32-base-bin
csomagot (Mark for installation)! - Ezután menüben válaszd ki az
Installation
->Apply Changes
->Apply
pontot! - Ezután, ha elnavigálunk a telepítési könyvtárba, ami
C:\MinGW
volt, akkor ott látnunk kell egybin
könyvtárat, melyben megtalálható agcc.exe
állomány. - Annak érdekében, hogy ne kelljen mindig abszolút útvonallal meghívni a gcc-t, adjuk hozzá a
PATH
környezeti változóhoz (aPATH
változó adja meg azon útvonalak halmazát, ahol a rendszer keresi a futtatható programokat a kiadott parancsoknak megfelelően) ezt a telepítési helyet! - Windows gomb -> "A rendszer környezeti változóinak módosítása" -> "Környezeti változók" gomb -> "Rendszerváltozók" (ha nincs rendszergazdai jogod, akkor fenti "xyz felhasználói változói") alatt keresd meg a Path-ot és jelöld ki, majd
Szerkesztés...
->Új
-> Másold be aC:\MinGW\bin\
elérési utat -> OK - Teszteléshez nyiss egy új parancssort (
Windows -> cmd
-> ↵), majd írd be, hogygcc --version
! -
Az alábbi kimenethez hasonlót kell kapnod:
Kimenet
1 2 3 4
gcc (MinGW.org GCC Build-2) 9.2.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
IDE (Integrated Development Environment)¶
Az egyszerű szövegszerkesztők mellett léteznek úgynevezett IDE-k (Integrated Development Environment), melyek megkönnyíthetik a fejlesztést (inkább nagyobb projektek esetében), mivel automatikus kódkiegészítést, IDE-n belüli fordítást és futtatást is lehetővé tesznek, illetve ezen felül rengeteg extra műveletet kínálnak még. Ha valamilyen IDE mellett döntünk, nagy valószínűséggel akkor is fel kell telepítenünk egy fordítót, mert az IDE alapból azt nem adja, csak használja.
IDE-k C programozáshoz:
Az említett IDE-k szintén telepítve vannak a kiadott Ubuntu VM image-ben. Természetesen magunk is telepíthetjük őket, ha szeretnénk.
C alapok¶
Mielőtt beleugrassz a gyakorlati részekbe hasznos lehet, ha elolvasod az előadáshoz tartozó jegyzet idevágó részét.
Első lépések¶
Első dolgunk, hogy megnyitjuk a kedvenc szövegszerkesztőnket vagy az IDE-t, amit használni szeretnénk a fejlesztéshez.
Hozzunk létre egy új szöveges állományt, melynek kiterjesztése .c
legyen!
Legyen a fájl neve például progalap.c
!
Ezután már írhatjuk is a C nyelvű programjainkat.
Ahogy a legtöbb programozási nyelv, úgy a C nyelv is támogatja a kommentek írását, melybe mindenféle hasznos megjegyzést rakhatunk anélkül, hogy az a program működését befolyásolná.
Két fajtája létezik:
- egysoros (line comment): ami a
//
után van az adott sorban az komment lesz - többsoros (block comment): amit
/*...*/
közé írunk, azok a blokk komment részei lesznek
1 2 3 4 5 6 7 |
|
Minden programnak van valamilyen belépési pontja, azaz valahol el kell kezdeni a program futtatását.
Például, amikor kiadjuk Linux alatt az ls
parancsot - amely szintén egy program - akkor valahol elkezdődik a program futtatása.
C-ben a programok belépési pontja a main
függvény.
Egyelőre nem fontos, hogy mi az a függvény és miért van main
elé az írva, hogy int
.
Egyelőre fogadjuk el, hogy elé int
-et írunk, utána rakunk egy zárójelpárost, amibe nem kell most még semmit se írni.
Azt, hogy mit csináljon a program a main
függvény törzsében adjuk meg, azaz a {...}
jelek között.
Nézzük is meg, hogy hogyan néz ki egy nagyon egyszerű program, ami igazából nem is csinál semmit.
1 2 3 4 5 6 |
|
A main-en belül most a return 0
utasítás szerepel.
A return
egy utasítás, melyet a függvényeken belül adhatunk ki, és segítségükkel valamilyen értéket adhatunk vissza az őket meghívóknak.
A main függvényt maga az operációs rendszer hívja meg, így a return 0
eredményeképpen ez a program 0-t ad vissza az operációs rendszernek, ami megegyezés szerint azt jelenti, hogy a programunk sikeresen lefutott.
0-tól különböző visszatérési értéket szokás használni arra, ha valamilyen hibát szeretnénk jelezni az operációs rendszer felé.
A fenti C kód csak maga a forrás. Ezt még nem tudjuk lefuttatni, előtte le kell fordítani olyan nyelvre, amelyet megért a számítógép (közvetlenül végre tud hajtani). Ezt a melót végzik el a fordítóprogramok (igen ezek is programok), mint amilyen például a gcc.
Így néz ki Linux alatt (terminalban) a gcc-vel történő fordítás:
1 |
|
és futtatás:
1 |
|
Az első parancsban a gcc-nek megmondjuk, hogy a progalap.c
állományt szeretnénk lefordítani, illetve a -o prog
kapcsolómegadással azt fejezzük ki, hogy a kimeneti futtatható állomány neve prog
legyen.
A második paranccsal futtatjuk az aktuális könyvtárban lévő prog
programunkat, mely jelen esetben nem csinál semmit, így vissza is kell kapnunk egyből a command prompt-ot ($
-al kezdődő szöveg a terminálon), amellyel jelzi az operációs rendszer, hogy kész fogadni az utasításainkat.
Megjegyzés
A fordítás menetét részletesen lásd itt!
Megjegyzés
Ha nem a fenti elvárt viselkedést tapasztaljuk és még fordítás közben valamilyen hibát kapunk, akkor alaposan nézzük meg, hogy mindent helyesen írtunk-e be!
A legegyszerűbb C nyelvű program megírását mutatja be az alábbi videó is:
Minden programozási nyelv tanulása során az első feladatok közé tartozik, hogy írjunk egy olyan programot, ami kiírja a "Hello World" szöveget a képernyőre. Ez a szokás Brian Kernighan, "Programming in C: A Tutorial" könyvéből eredeteztethető, aki nem mellesleg a C nyelv egyik megalkotója. Tehát nincs más választásunk, meg kell írni ezt a programot.
A programozás és maga a szoftverfejlesztés nem tartana ott ahol, ha nem használnánk fel már megírt kódokat.
Ilyen előre megírt kódot biztosítanak a szabványos függvénykönyvtárak is.
C-ben a standard input/output műveleteket már nem kell magunknak megírnunk, hanem elég az stdio
(standard input/output) szabványos függvénykönyvtárat használnunk, pontosabban ebből most egy függvényt fogunk felhasználni mégpedig a printf
-et.
A standard függvénykönyvtárak használatához a következőt kell a programunkba illesztenünk:
1 2 3 4 |
|
Az #include
mondja meg, hogy ide emeljük be az stdio.h
(header)fájl tartalmát, amiben a printf
függvény deklarációja is található.
Ezek után nézzük meg a teljes "Hello World" program kódját!
1 2 3 4 5 6 |
|
Kimenet
1 |
|
Ebben a kódban a printf()
függvényt hívjuk meg, melyet azzal jelzünk, hogy a függvény neve mögé kitesszük a kerek zárójelpárt, amik között az argumentumokat adhatjuk meg.
A printf
argumentuma az a szöveg, amit ki kell írnia a képernyőre.
Ezt a szöveget idézőjelek közé kell tennünk.
Itt meg is adjuk a "Hello World" szöveget, azonban van utána egy furcsa \n
is.
Mivel az idézőjelek között nem tudunk Enter-t megadni (ez fordítási hibát okozna), ha a kiírásban valahol - jelen esetben a "Hello World" szöveg után - sortörést szeretnénk csinálni, azt máshogy tudjuk jelezni.
(Ha nem lenne sortörés, akkor a Hello World
után jelenne meg a command prompt, és nem új sorban.)
Konkrétan a printf
paraméterében (melyet formátumsztring-nek is neveznek) egy \n
-nel tudjuk jelezni a sortörést (és más speciális karakterkombinációkkal az egyéb speciális, úgynevezett vezérlő karaktereket).
Mint ahogyan az már kezd kirajzolódni, az utasításaink (printf
, return
) után mindig kell egy pontosvesszőt raknunk.
Ezzel zárjuk az utasításokat.
Egyelőre ízlelgessük a szintaxist.
A helloworld
program fordítása és futtatása:
1 2 |
|
HelloWorld
program videóban bemutatva:
Feladat (f0002)
Feladat:
Írj egy olyan C programot, ami kiírja, hogy "Hello Vilag!"! Készíst belőle
egy hello
nevű futtathatót először egy, majd két lépésben (helloworld.o
objekten keresztül), és futtasd!
Problémafelvetés:
Írj egy olyan C programot, ami kiírja, hogy "Hello Vilag!"!
Specifikáció:
A programnak nincs inputja. A program outputja a "Hello Vilag!" szöveg egy lezárt sorban.
Megoldás (m0002.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Feladat (f0003)
Feladat:
Írj egy olyan C programot, ami kiírja, hogy "Hello Vilag!"! Javítsd ki a
programot, hogy fordításkor ne legyen benne warning -Wall
kapcsolóval sem!
Futtasd!
Problémafelvetés:
Írj egy olyan C programot, ami kiírja, hogy "Hello Vilag!"!
Specifikáció:
A programnak nincs inputja. A program outputja a "Hello Vilag" szöveg egy lezárt sorban.
Megoldás (m0003.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Szekvenciák¶
Minden utasítást pontosvessző (";") zár.
Ha nem teszünk pontosvesszőt, akkor kifejezésről beszélünk.
Kifejezés - egy érték olyan jelölése, amely műveleteket is tartalmazhat, pl.: 3 + 5
.
Utasítások sorozatát szekvenciának nevezzük.
Példa:
1 2 3 4 |
|
Változók használata¶
Minden programozási nyelvben szükség van arra, hogy valamilyen adatokon tudjunk műveleteket elvégezni. Az adatokat a program futása közben a memóriában tárolhatjuk. A programban deklarálhatunk változókat, azaz kérünk egy kis szeletet a memóriából, hogy abban majd számunkra valamilyen hasznos adatot tudjunk tárolni. Attól függően, hogy milyen jellegű adatot szeretnénk benne tárolni másképpen kell a memóriaterületet elkérni az operációs rendszertől (különböző mennyiségű bit-et kaphatunk egy egész szám tárolásához, mint egy valós szám tárolásához).
Az adattárolásról bővebben majd a előadás adatkezelés szintjeiről és elemi adattípusokról szóló részében lesz szó.
Vizsgáljuk meg a következő kódrészletet, melyben különböző deklarációkat láthatunk.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Miután deklaráltuk a változónkat, a hozzárendelt memóriaterületre értékeket is elhelyezhetünk, azaz tárolni tudjuk az adatot. Amikor értéket is adunk egy változónak, akkor definiáljuk azt (változó definíció). Nézzük meg az alábbi kódrészletet, melyben az alap típusú változóknak értékeket is adunk a deklarációval egy időben, azaz kezdőértékkel látjuk el a változókat (inicializáljuk őket).
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Videó egyszerű változó deklarációról:
Egyszerű műveletek¶
Miután már vannak változóink is, valószínűleg szeretnénk velük valamilyen műveleteket elvégezni.
A matematikában megszokott összeadás (+
), kivonás (-
), osztás (/
), szorzás (*
) mellet van maradékos osztás (%
) alapműveletünk is.
A zárójelezést szintén a megszokott módon használhatjuk.
Két szám összegét kiszámító program:
Az alapműveletek használatát bemutató program:
Konstansok¶
A változók mellett előfordulhat, hogy konstans értékekkel (értéke állandó) szeretnénk dolgozni.
Ilyen állandó értékek megadására használhatjuk a define
preprocesszor utasítást.
A konstansok nevét általában csupa nagy betűvel írjuk, így amikor találkozunk velük a kódban, már ránézésre tudjuk, hogy egy állandóról van szó.
Példa:
1 2 3 4 5 6 7 8 |
|
A define
a preprocessálás ideje alatt fut és egyszerű szöveges behelyettesítést végez, szóval teljesen legálisan csinálhatunk huncutságokat (mármint a fordító nem fog érte szólni, viszont készüljünk fel a mérges kollégákra):
1 |
|
Túlcsordulás¶
Az elemi adattípusoknál látható, hogy az egyes típusok milyen értékhatárok között képesek tárolni az értékeket. Amikor az értékhatár aljánál "lejjebbi", azaz kisebb értéket szeretnénk beállítani, akkor a bitjeink nem tudnak hirtelen megsokasodni, hogy kisebb számot is képesek legyenek tárolni, így nincs más választásuk, mint "átbillenek" és az intervallum tetejére kerülünk. Ilyen esetben beszélünk alulcsordulásról, illetve a fordított esetben, amikor felfelé szaladunk ki az értéktartományból, akkor felülcsordulással van dolgunk. Magát a jelenséget általánosságában túlcsordulásnak nevezzük.
Példa:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Kimenet
1 2 |
|
A túlcsordulás jelenségét az alábbi videó is bemutatja:
Input/Output alapok¶
printf¶
A "Hello World" programban már használtuk a kiíratásra használatos függvényt, a printf
-et.
Most, hogy már ismerjük a változókat, a következő feladat az, hogy valamilyen formában képesek legyünk a változók aktuális értékét kiírni a képernyőre.
Vizsgáljuk meg a következő kódrészletet!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
A fenti kódban azt láthatjuk, hogy a printf
első argumentumában, a formátumsztringben szerepelnek %
jelek.
Így adhatjuk meg, hogy az adott helyre majd valamilyen változó (vagy kifejezés) értékét helyettesítse a rendszer.
Pl: a %d
jelenti azt, hogy "ide majd egy egész számot írj ki decimális formában".
Hogy pontosan mi lesz ez a szám, azt a printf
további argumentumaiban adhatjuk meg (az argumentumokat vesszővel választjuk el egymástól).
Ez azt is jelenti, hogy egy printf
-ben több változó/kifejezés értékét is kiírhatjuk.
Például a egesz
változó és annak duplájának kiírására használhatnánk a következő utasítást:
1 |
|
Videó az alapvető típusokról és ilyen típusú változók értékeinek kiírásáról:
C nyelvben a printf
függvény formátumsztringjében a %
és lf
közé a.b
alakban írt két egész számmal vezérelhetjük a valós számok kiíratásának "szélességét" és "pontosságát". Az a
jelenti, hogy összesen legalább hány karakteren szélességben legyen kiírva a szám, a b
pedig a tizedesjegyek számát jelenti. Ha az a
elmarad, akkor a .b
alak csak a tizedesjegyek számát fixálja, de minimális "szélességet" nem mond. Pl:
1 2 3 |
|
Feladat
- Kezdj új programot!
- Hozz létre három változót,
int
,float
éschar
típusúakat! - A programban adj értékeket ezeknek a változóknak!
printf
paranccsal írasd ki a változók értékét magyarázó szöveggel, mindet új sorban!printf
paranccsal írasd ki azint
és afloat
típusú változó összegét magyarázó szöveggel, új sorban!printf
paranccsal írasd ki achar
változót, minthaint
lenne. Működik? Miért? Hogyan?
Lehetséges megoldás
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Az utolsó két printf
kicsit trükkösebb.
Egy egész és egy valós típusú változó összege (igazából a közöttük végzett bármilyen értelmes alapművelet) eredménye valós típusú lesz, így azt %f
-fel kell kiíratni.
A másik trükk a karakter kiírása, amiben igazából nincs semmi trükk csak azt fontos megértenünk, hogy a memóriában bináris formában kerülnek tárolásra az adatok, így a karakterek is. Egészen pontosan egy karakter tárolására 1 bájtot, azaz 8 bitet kapunk, ami 256 (\(2^8\)) különböző értéket vehet fel. Ezek az értékek vannak megfeleltetve az egyes karaktereknek (általánosságában a karakterek számmal való reprezentációját hívjuk karakter kódolásnak). A C nyelv alapból az ASCII kódolás kódolást használja.
Feladat (f0005)
Problémafelvetés:
Deklarálj egy valós, egy karakter és két egész típusú változót! Inicializáld a valós értéket 3.14 -re, a karaktert a nagy A karakterre, és művelettel adj értéket a két egész változónak is. Írasd ki a változók értékeit, valamint a két egész változó összegét és szorzatát is!
Specifikáció:
A programnak nincs inputja. A program outputja külön-külön sorokban az "A", a 3.1415 érték lebegőpontos alakban tetszőleges pontossággal, egy-egy tetszőleges egész érték, valamint a két egész érték összege és szorzata (a+b)=c és (a*b)=d alakban. Vagyis összesen 6 sor.
Megoldás (m0005.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
A következő programka is azt hivatott illusztrálni, hogy a különböző típusú adatokat hogyan írhatjuk ki és az milyen hatással lesz a kiírás eredményére. Próbáld ki a programot!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
scanf¶
Az adatok kiírása mellett egy másik fontos opció, hogy a felhasználótól adatokat kérjünk be.
A printf
"párja" a scanf
, mely nagyon hasonló paraméterezéssel működik, de beolvasáshoz használjuk.
Nézzünk is egy példát!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
A scanf
első argumentuma szintén a formátumsztring, ahol a printf
-nél megszokott placeholderek (%<valami>
) használhatóak.
A további argumentumok pedig ezeknek a placeholdereknek mondják meg, hogy akkor hova is tegyék az adatot.
Például a 11. sorban az egesz
változóba helyezzék el a beolvasott értéket.
Azt egyelőre fogadjuk el, hogy a scanf
-nél kell az &
a változó neve elé, későbbi gyakorlaton meg fogjuk érteni, hogy ez miért is szükséges.
Most olvassuk úgy a kódot, hogy: "Olvass be egy értéket a xy változóba"!
Videó a scanf
alapvető használatáról:
Ahogy egyszerre több adatot is ki tudtunk írni egy printf
segítségével, úgy igaz ez a scanf
-re is.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
scanf
használatáról egy másik bővebb videó, ahol némi anomáliát is felfedezhetünk:
Feladat
Írj egy programot amely bekéri a születési dátumodat, kiszámítja a korodat (idén hányadik évedet töltöd be), és ezt kiírja a képernyőre!
Feladat (f0006)
Problémafelvetés:
Kérj be két egész számot, cseréld meg, majd írd ki őket!
Specifikáció:
A program inputja két egész szám. A program outputja a két bekért egész érték egy sorban, egy szóközzel elválasztva, a bevitelhez képest fordított sorrendben.
Megoldás (m0006.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
Feladat (f0007)
Olvass be egy egész, egy valós és egy karakter értéket, majd írasd ki őket! Mi történik, ha különféle értékeket próbálsz meg egy sorban megadni? Mit olvas be a program, és mit nem? Próbáld ki a következő inputokat:
1 2 3 4 |
|
Problémafelvetés:
Olvass be egy egész, egy valós és egy karakter értéket, majd írasd ki őket.
Specifikáció:
A program inputja egy-egy whitespace karakterrel elválasztott egész, valós és karakter érték. A program outputja külön-külön sorokban a beolvasott egész, (lebegőpontos alakban tetszőleges pontossággal kiírt) valós valamint karakter értékek.
Megoldás (m0007.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Rajzoló program (grafika)¶
A fejlesztés során lehetőségünk van mások által megírt programrészleteket használni a saját programjainkban. Ebben az a jó, hogy egyrészt ezeket nem nekünk kell megírni, másrészt igazából a belső működésükkel sem szükséges tisztában lennünk, elég ha tudjuk, hogy milyen függvényeket használhatunk és azoknak mi az eredménye (mit csinálnak, mi a visszatérési értékük).
Korábban találkoztunk már az stdio.h header fájllal, amit include-olnunk kellett ahhoz, hogy használni tudjuk a printf
és scanf
függvényeket.
A header fájlok (többnyire) függvénydeklarációkból állnak, vagyis csak azt mondják meg, hogy milyen nevű függvényt hogyan lehet felparaméterezni, és mivel tér vissza, de magát a működést (itt még) nem írják le. Minden header fájlhoz tartozik egy (vagy több) forrásfájl is, amely tartalmazza a függvények definícióit, tehát már leírja a függvények konkrét működését is. Ezeknek a részletes ismerete azonban nem szükséges a függvények a használathoz (sokszor maga a forráskód rendelkezésünkre sem áll).
Grafika példa¶
A következőkben bemutatunk egy olyan header fájlt, melynek segítségével Linux-on (X11 felületen) grafikus programokat lehet készíteni, hasonlóan a Logo nyelvhez (csak ez itt sokkal kevesebbet tud és nem néz ki olyan jól). A rajzoláshoz a paint.h header fájlt fogjuk használni, ami így néz ki:
Header fájl Logo szerű programozáshoz (paint.h)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
|
Ezt a header-t kell majd include-olni #include "paint.h"
módon (tehát <>
helyett ""
között), de a teljes működéshez szükség lesz még a paint.c, gfx.h és gfx.c fájlokra is.
Ezeket is töltsük le (ugyanabba a könyvtárba mentsük, ahol a paint.h is van, és ahol a grafikus programokat is írjuk majd)!
Most készítsünk egy egyszerű programot, ami mindössze egy vonalat rajzol. Ehhez csak létre kell hoznunk egy nem túl nagy grafikus ablakot, előremozogni a kurzorral, majd bezárni az ablakot. Ez a program a paint.h segítségével így nézne ki:
1 2 3 4 5 6 7 8 |
|
A fájl első sora tartalmazza az include-ot, ez teszi lehetővé, hogy használhassuk a paint.h-ban lévő függvényeket.
Azt természetesen tudnunk kell, hogy ezek a függvények MIT csinálnak, de azt nem, hogy HOGYAN.
A create_window(500, 500)
például létrekoz egy 500x500 pixeles grafikus ablakot, amelynek kezdetben a közepén van a kurzor (és felfelé néz).
A forward(250)
előrefele mozgatja ezt a kurzort 250 pixelnyit, és közben fehérrel rajzolja a bejárt útvonalat, a close_window()
pedig megvárja, amíg megnyomjuk a 'q' pillentyűt, és bezárja az ablakot.
Mentsük el az elkészített programot mondjuk pelda.c néven!
A program fordítása az eddigiekhez képest kicsit bonyolultabb lesz, mert a paint.h-ban deklarált függvények megvalósítására, az ezekben használt egyéb függvények megvalósítására, az ezekben használt ... (ezt itt jó sokáig lehetne folytatni) ... függvények megvalósítására is szükség lesz.
További részletek nélkül, a fordítás így néz ki (a paint.c gfx.c -lX11 -lm
parancssorhoz adása a lényeg):
1 |
|
Futtassuk le a programot:
1 |
|
Otthoni használat¶
A program az XLib függvénykönyvtárat használja, amely csak linuxon elérhető, ezért a használatához valamilyen grafikus linuxra lesz szükség. (Az ssh tehát alapesetben nem megoldás; bár azon keresztül is megoldható lenne, ezzel most nem foglalkozunk.) Egy grafikus interfésszel rendelkező virtuális gép vagy natív linux megfelelő lehet.
Lehetőségek¶
A Logo alapvetően úgy működik, hogy egy kurzort mozgatunk a képernyőn néhány parancs segítségével, a megtett útvonalat pedig bejelöli a program (de kérhetjük, hogy ne tegye, csak menjen). Érdemes átnézni a paint.h fájlt, hogy milyen lehetőségeink vannak a mozgatásra, színezésre, stb. Minden függvényhez tartozik egy leírás (a függvény előtti komment).
További feladatok¶
Feladat (f0008)
Problémafelvetés:
Készíts egy programot, amely beolvas 3 valós számot, majd kiírja őket, mindegyiket új sorba!
Specifikáció:
A program inputja három valós szám, whitespace karakterekkel elválasztva. A program outputja a három beolvasott valós szám tetszőleges pontossággal, egy-egy új sorban.
Lehetséges megoldás (m0008.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Feladat (f0019)
Problémafelvetés:
Írj egy programot ami az oldalhosszból kiszámítja egy négyzet kerületét és területét!
Specifikáció:
A program inputja egyetlen nemnegatív valós szám, a négyzet oldalhossza. A program outputja két sor. Az elsőben a "T = " szöveg után a négyzet területe, a második sorban a "K = " szöveg után a négyzet kerülete szerepel. Mindkét számot 10 karakteren jobbra igazítva 3 tizedesjegy pontossággal kell kiíratni! A beolvasás előtt a program elején ki kell írni egy rövid tájékoztatót arról, hogy a program milyen adatot kér be!
Lehetséges megoldás (m0019.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Feladat (f0030)
Problémafelvetés:
Írj egy programot ami az átló hosszából kiszámítja egy négyzet kerületét és területét!
Specifikáció:
A program inputja egyetlen nemnegatív valós szám, a négyzet átlójának hossza. A program outputja két sor. Az elsőben a "T = " szöveg után a négyzet területe, a második sorban a "K = " szöveg után a négyzet kerülete szerepel. Mindkét számot 10 karakteren jobbra igazítva 3 tizedesjegy pontossággal kell kiíratni. A beolvasás előtt a program elején ki kell írni egy rövid tájékoztatót arról, hogy a program milyen adatot kér be!
Lehetséges megoldás (m0030.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Feladat (f0032)
Problémafelvetés:
Írj egy programot ami a három oldalhosszból kiszámítja egy téglatest felszínét és térfogatát!
Specifikáció:
A program inputja három nemnegatív valós szám, a téglatest oldalhosszai. A program outputja két sor. Az elsőben a "V = " szöveg után a téglalap térfogata, a második sorban az "A = " szöveg után a téglalap felülete szerepel. Mindkét számot 10 karakteren jobbra igazítva 3 tizedesjegy pontossággal kell kiíratni. A beolvasás előtt a program elején ki kell írni egy rövid tájékoztatót arról, hogy a program milyen adatot kér be.
Lehetséges megoldás (m0032.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Feladat (f0044)
Problémafelvetés:
Írj egy programot ami kiszámítja, hogy egy adott kezdősebességgel függőlegesen kilőtt test adott nehézségi gyorsulás (\(g=1,63 m/s^2\)) mellett mennyi idő alatt esik vissza a Hold felszínére? Feltételezhető, hogy a kezdősebesség nem elég nagy ahhoz, hogy a testre ható tömegvonzás érezhetően megváltozzon.
Algoritmustervezés:
A számításhoz segítség lehet a \(v=v_0+(a*t)\) képlet, ahol \(v_0\) a kezdősebességet, \(a\) a gyorsulást, \(t\) pedig az eltelt időt jelenti.
Lehetséges megoldás (m0044.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Feladat (f0023)
Problémafelvetés:
Írj programot, amely egy Euróban megadott összeget adott középárfolyamon Forintra számít át!
Specifikáció:
A program inputja két nemnegatív valós szám, az Euro árfolyama (1EUR/1HUF) és az átváltandó összeg. A program megfelelő tájékoztatás után kéri be a két értéket. A program outputja egyetlen sor, melynek tartalma egy valós szám tizedesjegyek nélkül, ami a megadott Euromennyiség adott árfolyamon számolt értéke Forintban, valamint mögötte egy szóközzel elválasztva a "HUF" megjelölés.
Lehetséges megoldás (m0023.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Feladat (f0010)
Problémafelvetés:
Írj egy programot, amely az egész típus értékkészletének korlátossága miatt rossz eredményt ad valamilyen műveletekre. Az alul- és túlcsordulást is mutasd meg!
Specifikáció:
A programnak nincs inputja. A program outputja két egész szám. A két szám egy-egy művelet eredménye, amely műveletek matematikailag olyan eredményt adnának, amik a típus értékkészletéből felfelé illetve lefelé kilógnak.
Megvalósítás:
Mivel az int
értékkészlete a legtöbb mai rendszeren kb. \(\pm2.1 \times 10^9\), érdemes
olyan 1500000000 (\(1.5 \times 10^9\)) körüli értékekkel dolgozni. Két ilyen
nagyságrendű pozitív szám összeadása negatív számot, két ilyen nagyságrendű
negatív szám összeadása pozitív számot eredményez (ha az eredményt is int
változóban tároljuk). De dolgozhatunk char
típussal is, akkor ezek a
jelenségek -128 alatt és 127 felett fordulnak elő.
Lehetséges megoldás (m0010.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Feladat (f0021)
Problémafelvetés:
Adott a síkon két pont. Határozd meg a távolságukat!
Specifikáció:
A program inputja kép koordinátapár, összesen négy valós szám, melyek \(x_1, y_1, x_2, y_2\) sorrendben a \(P_1(x_1,y_1)\) és \(P_2(x_2,y_2)\) síkbeli pontok koordinátái. A program outputja egyetlen sor, amely a
1 |
|
tartalmú, ahol x1
, y1
, x2
és y2
a megadott koordináták, d
pedig a két
pont síkbeli távolsága. A beolvasás előtt a program elején ki kell írni
egy rövid tájékoztatót arról, hogy a program milyen adatot kér be.
Megvalósítás:
Négyzetgyök számítására a math.h-ban deklarált egyparaméteres
1 |
|
függvény használható. Ehhez a C program elejére be kell szúrni az
1 |
|
sort, ezután a programban használható az sqrt()
függvény, amely az
argumentumként megadott valós kifejezés négyzetgyökével tér vissza. De ez
még nem elég, a fordításkor (pontosabban annak a linkelési lépésében) meg kell adni a -lm
kapcsolót is.
Próbáld ki, milyen hibaüzenet lesz a fordítás eredménye, ha nem adod meg a -lm
kapcsolót.
Lehetséges megoldás (m0021.c)
Szükséges képlet \(d = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Feladat (f0022)
Problémafelvetés:
Írj egy programot ami kiszámítja, hogy egy egyenletes sebességgel egyenes vonalban haladó test mennyi idő alatt tesz meg egy adott útszakaszt!
Specifikáció:
A program inputja egy pozitív és egy nemnegatív valós szám, a test sebessége (\(v\)) és az útszakasz hossza (\(s\)). A program megfelelő tájékoztatás után kéri be a két értéket, melyek mértékegységei \(m/s\) illetve \(m\). A program outputja a megadott \(s\) távolság egyenletes \(v\) sebességgel történő megtételéhez szükséges \(t\) idő, másodpercekben, ezredmásodperces pontossággal kiírva.
Algoritmustervezés:
Az eltelt idő az \(s=vt\) képletből számolható.
Lehetséges megoldás (m0022.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Feladat (f0025)
Problémafelvetés:
Írj programot ami bekér egy pénzösszeget (egy számot), majd meghatározza, hogyan fizethető ki ez az összeg a lehető legkevesebb 200, 100, 50, 20, 10, 5, 2 és 1 koronás érmével!
Specifikáció:
A program inputja egyetlen nemnegatív egész szám, a felváltandó összeg. A program kimenete nyolc sor, minden érmetípushoz egy. Minden sor első három karaktere jobbra igazítva tartalmazza az érme értékét, ezt egy kettőspont és egy szóköz követi, majd az adott érméből szükséges darabszám szintén három karakteren jobbra igazítva. A program semmi mást ne írjon ki.
Algoritmustervezés:
Ezekkel az érmékkel a felváltás egyszerű: ha mindig a legnagyobb olyan érmét választjuk, ami még "belefér" az összegbe, akkor az érmeszám minimális lesz.
Lehetséges megoldás (m0025.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
|
Feladat (f0045)
Problémafelvetés:
Írj egy programot ami adott nehézségi gyorsulás (\(g=9,81 m/s^2\)) mellett a kilövési szög és a kezdősebesség alapján kiszámolja, hogy hol lesz a kilőtt test a felhasználó által megadott idő múlva. Számítsd ki azt is, hogy mikor és hol éri el a röppálya maximális magasságát, illetve a test mikor és hol ér földet. Nem kell számolnod a légellenállással és feltételezd, hogy a terep sík, és a megadott idő alatt a test még nem esik vissza a földre.
Specifikáció:
A program inputjai:
- \(\alpha\): valós érték, kilövési szög a vízszinteshez képest fokban megadva, \(0 < \alpha \leq 90\)
- \(v_0\) : valós érték, kezdősebesség \(m/s\)-ben megadva, \(0 < v_0\)
- \(t\) : valós érték, az eltelt idő, \(0 \leq t \leq\) {a teljes repülési idő}
A program outputjai:
- \((x_t,y_t)\): Valós koordináta-pár, a test vízszintes \((x_t)\) és függőleges \((y_t)\) koordinátája a kilövés utáni \(t\) időpontban.
- \(t_h\) : A maximális magasság eléréséhez szükséges idő.
- \((x_h,y_h)\): Valós koordináta-pár, a test vízszintes \((x_h)\) és függőleges \((y_h)\) koordinátája a kilövés utáni \(t_h\) időpontban.
- \(t_d\) : A földetérés időpontja.
- \((x_d,y_d)\): Valós koordináta-pár, a test vízszintes \((x_d)\) és függőleges \((y_d)\) koordinátája a kilövés utáni \(t_d\) időpontban.
Megvalósítás:
A math.h
a négyzetgyök számító függvény mellett (többek között) a szintén
egyparaméteres
1 2 |
|
függvényeket is tartalmazza, melyek szintén használhatóak.
Lehetséges megoldás (m0045.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
Grafikus szorgalmi feladatok¶
A grafikus programozás nem lesz számonkérve, viszont látványos dolgokat lehet vele csinálni a C-s vezérlési szerkezetek gyakorlása mellett.
Feladat (fgr01)
Problémafelvetés:
Rajzoljunk egy négyzetet!
Megvalósítás:
A paint.h segítségével egy ablakban rajzoljunk egy négyzetet.
Lehetséges megoldás (mgr01.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Feladat (fgr02)
Problémafelvetés:
Rajzoljunk egy gyógyszertári keresztet csak körvonalakkal!
Megvalósítás:
A paint.h segítségével egy ablakban rajzoljunk egy gyógyszertári keresztet.
Lehetséges megoldás (mgr02.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Feladat (fgr03)
Problémafelvetés:
Rajzoljunk egymásba ágyazott négyzeteket!
Megvalósítás:
A paint.h segítségével egy ablakban rajzoljunk több négyzetet közös középponttal.
Lehetséges megoldás (mgr03.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
Feladat (fgr04)
Problémafelvetés:
Rajzoljunk egy négyzetes kokárdát!
Megvalósítás:
A paint.h segítségével egy ablakban rajzoljunk három egymásba ágyazott négyzetet közös középponttal, majd színezzük ki a kapott területeket.
Lehetséges megoldás (mgr04.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
|
Feladat (fgr05)
Problémafelvetés:
Rajzoljunk egy virágot véletlenszerű színekkel!
Megvalósítás:
A paint.h segítségével egy ablakban rajzoljunk egy színes virágot.
Lehetséges megoldás (mgr05.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|