Gábor LÉKÓ, PhD student
Programozás alapjai gyakorlat 2018-2019/1
Az alap kurzusrész tematikája: * Programozási alapfogalmak: számítási probléma, algoritmus, program. * A C fejlesztő környezetek. A forrásprogram fordításának folyamata. * A programozás fázisai: problémafelvetés, specifikáció, algoritmustervezés, megvalósítás, költségelemzés, tesztelés, végrehajtás, fenntartás. * Vezérlési módok. Szerkezeti ábra fogalma. * Szekvenciális vezérlés és megvalósítása C nyelven. * Adattípus és változó fogalma. * A C programozási nyelv alapjai, elemi adattípusai. * Kifejezés felépítése és kiértékelése. Logikai kifejezés. * Beviteli (input) és kiviteli (output) utasítások. * Egyszerű C program szerkezete. * Szelekciós vezérlések (egyszerű, többszörös, esetkiválasztásos) és megvalósítása C nyelven. * Ismétléses vezérlések (kezdőfeltételes, végfeltételes, számlálásos, hurok, diszkrét) és megvalósítása C nyelven. * Eljárásvezérlés, függvényművelet és megvalósítása C nyelven. * Egyszerű rekurzió. * Blokkstruktúra a C nyelven. * Folyamatábra, szabályos folyamatábra, kapcsolat a szerkezeti ábrával. * Adattípusok, absztrakt adattípus. * Elemi adattípusok, összetett adattípusok, típusképzések a C nyelven. * Pointer típus, pointeraritmetika. * A kimenő és a be- és kimenő argumentumok kezelése. * Dinamikus változók. Memória modell. Modulok. * Tömb típus, pointerek és tömbök kapcsolata. * String típus és megvalósítása C nyelven. * Szorzat-rekord típus és megvalósítása C nyelven. * Az egyesített-rekord típus megvalósítása C nyelven. * Függvényre mutató pointer. * Bonyolultabb deklarációk. * Típuskényszerítés. * A parancssorban lévő argumentumok kezelése. * Az I/O alapjai. Formatált I/O műveletek. Hozzáférés az adatállományokhoz. * Alacsony szintű I/O. * A C előfeldolgozó: makrók, feltételes fordítás. Ajánlott irodalom: * Brian W Kernighan and Dennis M Ritchie, A C programozási nyelv, Műszaki Kiadó, 1985. * Brian W Kernighan and Dennis M Ritchie, A C programozási nyelv, Az ANSI szerint szabványosított változat, Műszaki Kiadó, 1996 * Benkő Tiborné, Benkő László, Tóth Bertalan, Programozzunk C nyelven, ComputerBooks, 1998. * Herbert, Schildt: C/C++ Referenciakönyv. Bp. : Panem, 1998 * Andrew Koenig: C csapdák és buktatók, Kiskapu Kft. 2005. * Juhász István, Kósa Márk, Pánovics János: C példatár, Panem, 2005
Gyakorlat: A laboratóriumi gyakorlat látogatása kötelező. Igazolatlan hiányzás esetén a laboratóriumi gyakorlat nem teljesített. A távolmaradás pótlásának nincs lehetősége. Igazolt hiányzás esetén a hallgató köteles a hiányzást követő első gyakorlaton bemutatni az igazolását az oktatónak. Félévközi ellenőrzések: hét(naptári) 1. (36) [2018-09-03]: 2. (37) [2018-09-10]: 3. (38) [2018-09-17]: 4. (39) [2018-09-24]: 1. zh (5p) printf, scanf 5. (40) [2018-10-01]: 2. zh (5p) if, for 6. (41) [2018-10-08]: 3. zh (5p) tombok 7. (42) [2018-10-15]: 4. zh (5p) bugfix - syntax 8. (43) [2018-10-22]: --/5. zh 9. (44) [2018-10-29]: 5. zh/-- (10p) struct, alg - tombos 10. (45) [2018-11-05]: 11. (46) [2018-11-12]: 6. zh (10p) for - alg 12. (47) [2018-11-19]: 7. zh (10p) bugfix - semantics, dinamikus tömbök 1d-2d 13. (48) [2018-11-26]: 8. zh (10p) feladatok tömbökön 14. (49) [2018-12-03]: 9. zh (20p) két teljes program A 8. héten csak a csütörtöki órák (Október 25.), a 9. héten a hétfő-szerdai órák (Október 29-31) lesznek megtartva. A ZH-kon az azt megelőző hét végéig az előadáson vagy gyakorlaton elhangzott anyag kerül számonkérésre. Egy-egy ZH önmagában nem javítható vagy pótolható. A gyakorlat teljesítésének értékelése pontozás alapján történik. Maximálisan összegyűjthető pontszám 90 pont. Laboratóriumi gyakorlatok értékelése: A félév során összesen 9 alkalommal lesz gyakorlati számonkérés (zárthelyi dolgozat). Az első négy alkalommal 5-5 pontos 20-30 perces óra eleji programírás lesz. Az 5-8 alkalmakkor 10-10 pontos 35-45 perces óra eleji programírás lesz. A 9. alkalommal egész órás, 2x10 pontos programírás lesz. A ZH-k megírása a hálózatról lekapcsolt számítógépen, a kiértékelés a bíró rendszeren keresztül automatizáltan történik. A félév során hétről-hétre házi feladatok lesznek kiadva 1-1, összesen 10 pontért, melyek beleszámítanak a pontszámba. A házi feladatokért járó pontokat az kaphatja meg, aki a megfelelő módon beadja a házi feladatokat, és az adott heti zh-n legalább a pontszám (lefelé kerekített) felét eléri. Minimális pontszámok / javítás: Az egyes zh-kra minimum pontszám nincs meghatározva, de a 3. zh-tól kezdve a (házi feladatra kapott plusz 1 pontokkal együtt számolt) megszerzett összpontszám el kell hogy érje a 2, 3, 5, 8, 13, 21, és az utolsó zh után a 34 pontot. Aki ezt a minimum ponthatárt legalább két alkalommal nem teljesíti, az a gyakorlatra elégtelen (1) érdemjegyet kap. A folyamatos számonkérés miatt a gyakorlati eredmény javítására is csak folyamatosan, a kihirdetett számonkérésekre való készüléssel van mód. A gyakorlati végeredmény javítására egyéb módon (például a félév végén egyetlen javító zh megírásával) nincs lehetőség. A gyakorlat érdemjegyének meghatározása az összpontszám alapján történik a következő ponthatárok szerint: * 0 - 33 pont : elégtelen (1) * 34 - 50 pont : elégséges (2) * 51 - 67 pont : közepes (3) * 68 - 78 pont : jó (4) * 79 - 90 pont : jeles (5)
Linux operációs rendszer alapparancsai
1. gyakorlat - 09.03. - Évkezdési adminisztárció + Linux alapok
C programozási nyelv
2. gyakorlat - 09.10. - Fordítás & futtatás, változók ( lokális & globális ), input/output, blokkok, függvények
3. gyakorlat - 09.17. - Feltételes vezérlési szerkezetek (IF-ELSE, SWITCH) és ciklusok (WHILE, DO-WHILE, FOR)
4. gyakorlat - 09.24. - 1. ZH (5p) - 1D tömbök és karaktertömbök
5. gyakorlat - 10.01. - 2. ZH (5p) - Tipusok haladó, Hibajavítás, Gyakorlás
6. gyakorlat - 10.08. - 3. ZH (5p) - Rekurzió, Gyakorlás
7. gyakorlat - 10.15. - 4. ZH (5p) - File input/output, Sorozatok, Gyakorlás
8. gyakorlat - 10.22. - A GYAKORLAT ELMARAD! 1956-os Forradalom Ünnepe (hosszú hétvége).
9. gyakorlat - 10.29. - 5. ZH (10p) - Pointerek
10. gyakorlat - 11.05. - Gyakorló óra
11. gyakorlat - 11.12. - 6. ZH (10p) - Pointer tömbök, k-ad rendű fibonacci, beszúró rendezés
12. gyakorlat - 11.19. - 7. ZH (10p) - Függvény pointer, PGM fájl, láncolt lista, gyakorlás
13. gyakorlat - 11.26. - 8. ZH (10p)
14. gyakorlat - 12.03. - 9. ZH (20p)
1. gyakorlat
További oktatók a gyakorlaton:
- Olasz Csaba - olaszcs@inf.u-szeged.hu
- Gercsó Márk - gmark@inf.u-szeged.hu
Helyettesítő oktató:
- Kicsi András - akicsi@inf.u-szeged.hu
Évkezdési adminisztráció (!)
Ismerkedés
- Tűzvédelmi napló
- Szabályzatok
- Követelmények
Regisztráció (!)
- Regisztráció (http://www.stud.u-szeged.hu -> a bal menüből STUD regisztráció -> Adatlap kitöltése, majd küldése )
- Ekkor kapni fog mindenki egy aznonosítót (h-s azonosító: hxxxxxx - ahol az x-ek számok) és egy induló jelszót. Ezeket az adatokat írja fel mindenki mindenképp!
- Jelszóváltás - az előzőleg kapott jelszavat két helyen is meg kell változtatni:
- Jelszó leváltása STUD rendszeren: a bal menüből a Jelszóváltás kiválasztása.
- Jelszó leváltása a kabinethez: https://www.inf.u-szeged.hu/jelszo, jelszóváltó űrlap segítségével.
- Bejelentkezés - két külön rendszerbe tudsz bejelentkezni ezután:
- A STUD szerverre (levelezés, honlapkészítés)
- A kabinetbe (tantermi gépek, saját mappa, bíró szerver, stb.).
- Ezután regisztráljunk mindkét BÍRÓ rendszerben:
Levelezés (!)
- Ezután már levelezni is tudsz a STUD-os email címeddel.
- Jelentkezz be a levelező felületre a STUD szerver bal oldali menüjében lévő Levelezés / Horde / menüpont megnyitásával és az adataid megadásával.
- Azonosítód (itt és a kabinetes bejelentkezéskor is) a h-s azonosítód, a jelszavad pedig a módosított, általad az előbbiekben megadott jelszó.
- A te email címed formája:
- hxxxxxx@stud.u-szeged.hu (pl.: h123456@stud.u-szeged.hu) VAGY
- <Vezetéknév>.<Keresztnév, vagy Keresztnevek ponttal elválasztva>[sorszám]@stud.u-szeged.hu (pl.: Nagy.Bela.Janos.2@stud.u-szeged.hu)
- Majd sikeres bejelentkezés után mindenki küldjön nekem egy emailt a leko@inf.u-szeged.hu címre, melynek a szerkezete az alábbi módon nézzen ki:
- Tárgy (Copy-Paste használata ajánlott):
- [progalap2018][reg]
- Tartalom:
- h-s azonosító;Neptun-kód;név
Ülésrend
- A 3. héttől ülésrend lesz, melyet alapértelmezetten az ABC sorrend határoz meg. Ebből kifolyólag előfordulhat, hogy valakit hátra ültet a rendszer, holott elöl szeretne ülni, avagy fordítva. A 2. hét végéig lehet email-ben jelezni, ha valaki kérné, hogy hol üljön.
Egyéb (PUB és HOME)
-
A kabinetes rendszerben mindenki kap egy mappát ("home mappa"), amiben az órai munkáit tárolhatja. Ezen a kvóta 300 MB illetve 10000 fájl.
Ezenkívül mindenki eléri a pub-könyvtárat, melyben a tananyagok találhatók.
Otthonról való bejelentkezéshez és adatmozgatáshoz az alábbi programokat ajánlom (Windows alatt):
- WinSCP - Adatmozgatás a kabinetes szerverről/szerverre otthonról könnyedén.
- PUTTY - Otthonról való bejelentkezés a kabinetes szerverre.
Kabinet elereséhez részletes leírás itt .
- Próbáljuk is ki a saját HOME-unk felcsatolását, melyet a "Mount Home" iconra kattintás után a h-s azonosítónk és jelszavunk megadásával tehetünk meg. Tesztként hozzunk létre pl. egy üres dokumentumot, mentsük le, majd csatoljuk le a HOME-unkat - "Unmount Home". Egy ismételt felcsatlakozással ellenőrizzük le, hogy az előzőekben létrehozott file továbbra is megtalálható-e ott, ahol elhelyeztük. Minden felcsatolás esetén, használat után csatlakoztassuk le a HOME-unkat!
"Megmondom a véleményem" rovat
- Anonim véleménynyílvánítás félév közben. Nem a félév végi hallgatói véleményezést helyettesíti, csupán lehetőséget nyújt a hallgatók számára, hogy félév közben is jelezni tudják észrevételeiket, kéréseiket, panaszaikat, ... ezzel is hozzájárulva, hogy minél inkább a TI, és ne az én elképzeléseim formálják az órákat. Várok minden nemű, építő jellegő kritikát! (U.i. Lécci ne SPAMeljétek tele. Köszi!)
Linux alapok
Debian (az ez alatti linkeken belül szerepel, hogy melyiket ajánlott letölteni), Ubuntu és VirtualBox letöltési lehetőség.
Debian telepítés leírása (általános) itt .
Debian telepítés leírása (64 bit!) itt . (EZT AJÁNLOM. Részletes, érthető és jól működik - tesztelve)
A weboldalon fellelhető LINUX anyag fő forrásai: itt és itt .
Fájlkezelés
pwd
(print working directory)
Aktuális könyvtár elérési útvonala. Bármikor kiadhatod ezt a parancsot, eredményként megkapod, hogy pontosan "hol" is vagy.
lekogabi@lekogabi:~/Letöltések/eclipse$ pwd /home/lekogabi/Letöltések/eclipse
history
Kiírja a terminal előzményeket.
ls
(list)
Ez a parancs megmutatja az aktuális könyvtárban tálalható fájlok neveit. A lista alapértelmezés szerint abc sorrendben sorolja fel a neveket, de alkalmas kapcsolók segítségével más sorrendet is elõírhatunk. pl.:
lekogabi@lekogabi:~/Letöltések/eclipse$ ls
Eredményként kiíratódik a terminálban az 'eclipse' mappa tartalma.
Kapcsolók:
-l: oszlopokban, részletesen mutatja a fájlok adatait
-d <könyvtár>: csak az adott könyvtár adatait írja ki. (Használjuk a "-l" kapcsolót is.)
-a: a rejtett fájlokat is mutatja
-R: könyvtáron belüli könyvtárak tartalmát is listázza
-r: forditott sorrendben listáz
-h: "barátságosabb" formában listázza ki a számokat
A kapcsolókat lehet kombinálva is használni, igy pl.:
lekogabi@lekogabi:~/Letöltések/eclipse$ ls -l -a -r lekogabi@lekogabi:~/Letöltések/eclipse$ ls -lar
Mindkét parancs kifogja listázni oszlopokba rendezve (-l), részletes adatokkal a rejtett fájlokat (-a) is, forditott sorrendben (-r).
cd <none, könyvtár, könyvtárszerkezet>
(change directory)
A könyvtár rendszerben való mozgást teszi lehetõvé. Paraméterként a megcélzott könyvtár nevét kell megadni, vagy abszolút, vagy relatív elérési útvonal használatával.
Abszolút elérési útvonal megadásánál a keresett könyvtár teljes elérési útvonalát kell megadni. Tehát rootból indulva pl.: /home/hxxxxxx/mappa/file1 .
Relatív címzés esetén azt mondjuk csak meg, hogy az aktuális könyvtárhoz képest hol helyezkedik el a megcélzott könyvtár. Tehát aktuális könyvtárból indulva pl.: ha éppen a /home/hxxxxxx-ben vagyunk: ./mappa/file1 .
aktuális könyvtár: .
szülőkönyvtár: ..
További példák:
Abszolút címzés:
lekogabi@lekogabi:~$ lekogabi@lekogabi:~$ cd /home/lekogabi/Letöltések/eclipse lekogabi@lekogabi:~/Letöltések/eclipse$
Relatív címzés:
lekogabi@lekogabi:~$ lekogabi@lekogabi:~$ cd Letöltések/eclipse/ lekogabi@lekogabi:~/Letöltések/eclipse$
Visszalépés a szülő könyvtárba:
lekogabi@lekogabi:~/Letöltések/eclipse$ cd .. lekogabi@lekogabi:~/Letöltések$ cd .. lekogabi@lekogabi:~$vagy
lekogabi@lekogabi:~/Letöltések/eclipse$ cd ../.. lekogabi@lekogabi:~$
A cd parnacs önmagában visszadob a hxxxxxx könyvtárba.
lekogabi@lekogabi:~/Letöltések/eclipse$ cd lekogabi@lekogabi:~$
"~": a home könyvtár elérési útvonalát tárolja.
lekogabi@lekogabi:~/Letöltések/eclipse$ cd ~ lekogabi@lekogabi:~$
mkdir [kapcsoló]<új mappa>
(make directory)
Új könyvtár létrehozására (csak az adott könyvtárban). pl.:
lekogabi@lekogabi:~/Dokumentumok$ mkdir hello
Létrejön egy "hello" nevű mappa a 'Dokumentumok'-on belül.
Kapcsolók:
-p: Létrehozza a kívánt könyvtár eléréséig az összes szükséges könyvtárat. pl.:
lekogabi@lekogabi:~/Dokumentumok$ mkdir -p hello/hello2/hello3
Végig létrehozza a könyvtárszerkezetet.
-m: Megadhatjuk az új katalógus hozzáférési jogát oktálisan a "mode" értékének beállításával. pl.:
lekogabi@lekogabi:~/Dokumentumok/hello$ mkdir -m 777 hello2 lekogabi@lekogabi:~/Dokumentumok/hello$ ls -l drwxrwxrwx 2 lekogabi lekogabi 4096 aug 5 17:05 hello2
A '777' megadásával teljeskörű jogokat biztosítunk mindhárom felhasználói csoportnak (user, group, other). A 3 db 7-es számjegy egyenkénti csökkentésével (0-7) lehet egyre kisebb jogokkal felruházni a felhasználói csoportokat.
Az elérési jogok megváltoztatásáról/értelmezéséről részletesen a "Fájlkezelés" alfejezet végén (chmod).
rmdir [kapcsoló]<törlendő mappa>
(remove directory)
Könyvtárak törlésére szolgáló parancs. Az rmdir parancs csak üres könyvtárat vagy könyvtárakat töröl. pl.:
lekogabi@lekogabi:~/Dokumentumok$ mkdir hello lekogabi@lekogabi:~/Dokumentumok$ rmdir hello
Eredményül kitörlődik a 'hello' nevű mappa.
Kapcsolók:
-p: A könyvtár törlése után, a szülõ könyvtárat is törli, ha üres, rekurzívan.
A Dokumentumok mappán belül található egy hello nevű mappa és azon belül egy hello2 nevű mappa. Ha az aktuális könyvtár a Dokumentumok, akkor a -p kapcsoló segítségével, ha kitöröljük a hello2 mappát, akkor a hello mappa is törlődni fog (mivel nem tartalmaz mást).
lekogabi@lekogabi:~/Dokumentumok$ mkdir -p hello/hello2 lekogabi@lekogabi:~/Dokumentumok$ rmdir -p hello/hello2
rm [kapcsoló]<törlendő fájl(ok)>
(remove)
Kitörli az rm parancs után található fájlokat (könyvtárakat nem, arra az rmdir használandó, kivéve kapcsoló hozzáadásával - lásd lentebb). pl.:
lekogabi@lekogabi:~/Dokumentumok$ rm file1.txt file2.txt
Eredményül a file1.txt és a file2.txt törlésre kerül.
Kapcsolók:
-f: sosem kérdez.
-i: kétes esetben kérdez.
-r: könyvtár törlésére, akkor is törli ha nem üres!
-R: -//-
lekogabi@lekogabi:~/Dokumentumok$ ls elso lekogabi@lekogabi:~/Dokumentumok$ cd elso/masodik lekogabi@lekogabi:~/Dokumentumok/elso/masodik$ ls t.txt lekogabi@lekogabi:~/Dokumentumok/elso/masodik$ cd ../.. lekogabi@lekogabi:~/Dokumentumok$ rm -r elso lekogabi@lekogabi:~/Dokumentumok$ ls lekogabi@lekogabi:~/Dokumentumok$
Kitörlésre kerül az elso/masodik mapparendszer, annak ellenére, hogy nem üres.
mv [kapcsoló]<forrás><cél>
(move)
A fájlok állományrendszeren belüli mozgatására szolgáló parancs. Ha nem adunk meg fájlnevet a célnál, akkor nem változik meg a neve, különben a megadott fájlnév lesz a célkönyvtárban. pl.:
lekogabi@lekogabi:~/Dokumentumok$ mv hello /home/lekogabi/Letöltések
Eredményül a 'hello' nevű fájl átkerül a Dokumentumok könyvtárból a Letöltések könyvtárba.
Kapcsolók:
-b: biztonsági másolatot készít a forrásfájlról.
-f: sosem kérdez felülírásnál.
-i: kétes esetben kérdez (pl. névütközés...).
-u: csak régebbit ír felül.
cp [kapcsoló]<forrás><cél>
(copy)
Átmásolja a forrás fájlt a megadott helyre. pl.:
lekogabi@lekogabi:~/Letöltések$ cp image.png /home/lekogabi/Dokumentumok
Eredményül átmásolja a 'image.png' fájlt a Letöltések könyvtárból a Dokumentumok könyvtárba.
Kapcsolók:
-r: könyvtár egész tartalmának másolása.
-R: -//-
-b: minden célfájlról mentés.
-f: sosem kérdez.
-i: kétes esetben kérdez.
-u: csak régebbit írja felül.
-l: linkelés másolás helyett.
-s: szimbólikus linket készít.
ln [kapcsoló]<forrás><cél>
(link)
Az első paraméter a fájl, amihez szeretnénk linket készíteni, a második paraméter a link neve. Kapcsoló nélkül hard link készítése.
Kapcsolók:
-s: Szimbólikus (soft) link készitése.
Hard link pl.:
lekogabi@lekogabi:~/Dokumentumok$ cat > file1.txt hello lekogabi@lekogabi:~/Dokumentumok$ ln file1.txt file2.txt lekogabi@lekogabi:~/Dokumentumok$ ls -l -rw-r--r-- 2 lekogabi lekogabi 6 aug 7 01:15 file1.txt -rw-r--r-- 2 lekogabi lekogabi 6 aug 7 01:15 file2.txt lekogabi@lekogabi:~/Dokumentumok$ cat >> file1.txt world!
Létrehozunk egy .txt fájlt 'file1' névvel, melybe a "hello" szöveget irtuk. Majd készitettünk egy hard linket a fájlunkról 'file2' névvel. Majd módositottuk a file1-et, amelynek eredményeképp a file2 is módosult. Így mindkét .txt fájlban a "hello world!" szöveg fog szerepelni. Listázásnál a második mezõ jelenti a fájlra mutató hard linkek számát. Ha kitöröljük az egyik fájlt, attól a másik még használható. Gondolhatunk a Hard link-re egyfajta biztonsági mentés + automatikus módosítás kombinációra.
Szimbólikus link:
lekogabi@lekogabi:~/Dokumentumok$ ln -s file1.txt file3.txt lekogabi@lekogabi:~/Dokumentumok$ ls -l -rw-r--r-- 2 lekogabi lekogabi 13 aug 7 01:16 file1.txt -rw-r--r-- 2 lekogabi lekogabi 13 aug 7 01:16 file2.txt lrwxrwxrwx 1 lekogabi lekogabi 9 aug 7 01:29 file3.txt -> file1.txt lekogabi@lekogabi:~/Dokumentumok$ cat >> file1.txt lekogabi@lekogabi:~/Dokumentumok$ rm file1.txt lekogabi@lekogabi:~/Dokumentumok$ ls -l -rw-r--r-- 1 lekogabi lekogabi 29 aug 7 01:34 file2.txt lrwxrwxrwx 1 lekogabi lekogabi 9 aug 7 01:29 file3.txt -> file1.txt
A meglvévő file1.txt fájlunkhoz készítünk egy szimbólikus linket. Listázás után ez jól megfigyelhető az elkészült file3.txt után látható nyil alapján, amely a file1.txt-re mutat. A hard linkkel ellentétben, amennyiben töröljük a file1.txt-t, akkor a file3.txt használhatatlan lesz, mivel töröltük a fájlt, amire mutatott.
du
A fájljaink és könyvtáraink által elfoglalt lemezterületet lehet vele megtekinteni. pl.:
lekogabi@lekogabi:~/Dokumentumok$ du file2.txt 4 file2.txt lekogabi@lekogabi:~/Dokumentumok$ du file2.txt hello 4 file2.txt 4 hello
Kapcsolók:
-a: minden fájl adatait kiírja a könyvtár(ak)on belül, nem csak a könyvtár(ak)ét.
-h: "barátibb" alakban a számok.
-m: megabájtban írja ki a méretet.
-s: csak összméret.
chmod
Az elérési jogok megváltoztatása a chmod paranccsal lehetséges a tulajdonos számára. Szintaxisa pedig:
1. verzió:
chmod [ugoa][+-][rwx] fájlnév
Az [ugoa] kapcsolókkal írjuk elõ, hogy kinek adjuk a jogot. Adhatunk jogokat a tulajdonosnak (u - user), a csoportnak (g - group), másoknak (o - others) vagy pedig mindenkinek egyszerre (a - all). A [+-] azt jelenti, hogy adhatunk (+) vagy elvehetünk (-) jogokat. Végül pedig, hogy olvasási (r - Read), írási (w - Write) vagy futtatási (eXecute) jogot adunk. pl.:
lekogabi@lekogabi:~/Dokumentumok$ ls -l drwxrwxrwx 2 lekogabi lekogabi 4096 aug 9 15:07 hello lekogabi@lekogabi:~/Dokumentumok$ chmod g-w hello lekogabi@lekogabi:~/Dokumentumok$ ls -l drwxr-xrwx 2 lekogabi lekogabi 4096 aug 9 15:07 hello
2. verzió
chmod <xxx> fájlnév
Hasonló az előzőhöz, viszont itt minden x helyén 0-7-ig való osztályozással adható meg a különböző felhasználói csoportok jogosultágai.
Rendre egy darab x helyettesítésének jelentése:
0: 000 --- semmi jog 1: 001 --x csak futtatási 2: 010 -w- csak írási 3: 011 -wx írási és futtatási 4: 100 r-- csak olvasási 5: 101 r-x olvasási és futtatási 6: 110 rw- olvasási és írási 7: 111 rwx olvasási, írási és futtatási jog
pl.:
lekogabi@lekogabi:~/Dokumentumok$ ls -l drwx----wx 2 lekogabi lekogabi 4096 aug 9 15:07 hello lekogabi@lekogabi:~/Dokumentumok$ chmod 777 hello lekogabi@lekogabi:~/Dokumentumok$ ls -l drwxrwxrwx 2 lekogabi lekogabi 4096 aug 9 15:07 hello
Kapcsolók:
-R: rekurzívan az összes fájlra és alkönyvtárra.
zip / unzip
Adott fájl vagy mappa be- és kicsomagolása.
Fájl esetén
lekogabi@lekogabi:~/Dokumentumok$ zip file.zip file2.txt adding: file2.txt (stored 0%) lekogabi@lekogabi:~/Dokumentumok$ unzip file.zip Archive: file.zip replace file2.txt? [y]es, [n]o, [A]ll, [N]one, [r]ename: y extracting: file2.txt
Mappa esetén (rekurzívan)
lekogabi@lekogabi:~/Dokumentumok$ zip -r hello.zip hello updating: hello/ (stored 0%) updating: hello/file.txt (stored 0%) lekogabi@lekogabi:~/Dokumentumok$ rm -r uj lekogabi@lekogabi:~/Dokumentumok$ unzip hello.zip Archive: hello.zip creating: hello/ extracting: hello/file.txt lekogabi@lekogabi:~/Dokumentumok$ ls file2.txt hello hello.zip lekogabi@lekogabi:~/Dokumentumok$
Kapcsolók:
-r: rekurzívan az összes fájlra és alkönyvtárra.
Felhasználók
finger <argumentum>
who
w
Kiírja, hogy kik vannak bejelentkezve az aktuális gépre.
felhasználó: a megadott felhasználóról ír ki adatokat.
Kiírja, hogy kik vannak bejelentkezve az aktuális gépre, plusz adatokat ír ki a finger-hez képest.
Ugyanaz, mint a who, csak kiírja, hogy min dolgozik.
Multitask
ps
jobs
^C
^Z
bg %<szám>
fg %<szám>
kill %<szám>/PID
Kiírja a képernyőre az aktuális process-eket (futó vagy várakozó programokat, amik az adott terminálhoz kapcsolódnak).
-e: az összes futó process-t kiírja (más terminálhoz/terminálhoz nem kacspoltakat is).
-f: több információ.
-u user: csak a megadott user által "birtokolt" processzek listázása.
Kiírja az aktuális jobokat, amik az adott terminálhoz kapcsolódnak.
Ctrl+c paranccsal leállíthatunk előtérben futó folyamatokat.
Ctrl+z paranccsal szüneteltethetünk előtérben futó folyamatokat.
Várakozó job-ok elinditását teszi lehetővé, a "szám" helyére a job azonosítója kerül, háttérben indítja el (konzolt nem "használja").
Várakozó job-ok elindítását teszi lehetővé, a "szám" helyére a job azonosítója kerül, előtérben indítja el (konzolt "használja").
Process-eket és job-okat tudunk vele leállítani.
%<szám> formátumnál a szám helyére a job azonosítóját kell írni.
PID a process azonosítójának felel meg, és ezt a process-t szakítja meg (csak akkor, ha fut).
Kapcsolók:
-9: a leállított process-t is megszakítja.
-s: úgy állítja le a job-ot, hogy még újra lehet indítani.
Példa a job-ok kezelésére:
lekogabi@lekogabi:~$ cat > file.txt hello ^C lekogabi@lekogabi:~$ cat > file.txt hello ^Z [1]+ Megállítva cat > file.txt lekogabi@lekogabi:~$ jobs [1]+ Megállítva cat > file.txt lekogabi@lekogabi:~$ fg %1 cat > file.txt world ^Z [1]+ Megállítva cat > file.txt lekogabi@lekogabi:~$ jobs [1]+ Megállítva cat > file.txt lekogabi@lekogabi:~$ kill %1 [1]+ Megállítva cat > file.txt lekogabi@lekogabi:~$ jobs [1]+ Befejeződött cat > file.txt lekogabi@lekogabi:~$ jobs lekogabi@lekogabi:~$
Beleírtunk egy sort a file.txt-be, majd leállítottuk (Ctrl+c) a folyamatot. Aztán ismét írtunk bele egy sort, viszont ekkor csak szüneteltettük (Ctrl+z) a folyamatot. jobs paranccsal lekértük az aktuális job-okat, ahol látható az előbbi fájlba írás folyamatunk. fg paranccsal "vissza hívtuk" a job-ot. Ismét írtunk bele egy sort, majd várakozni küldük és a következő lépésben a kill paranccsal "kilőttük" a folyamatot. Ezután a jobs paranccsal lekérdezve már látható, hogy a fájlba írás teljes egészében leállt.
&
Ha egy progamot a háttérben akarunk futtatni, akkor a futtatandó program neve után egy & jelet kell tenni. pl.:
lekogabi@lekogabi:~$ gedit&
A fenti parancs hatására megnyílik a szövegszerkesztő a háttérben.
Szövegfájlok
echo
Az utána lévő szöveget írja ki a képernyőre. A szóközöket a "\<szóköz>" segítségével lehet beszúrni. Vagy ha az egész szöveget "" közé tesszük, akkor az kerül a képernyőre ami az "" között van. pl.:
lekogabi@lekogabi:~$ echo hello hello lekogabi@lekogabi:~$ echo "hello Kitty!" hello Kitty!
Változók is előállíthatóak az echo segítségével egy plussz '$' jel használatával. pl.:
lekogabi@lekogabi:~$ echo $asd (semmi) lekogabi@lekogabi:~$ asd="hello" lekogabi@lekogabi:~$ echo $asd hello lekogabi@lekogabi:~$ unset asd lekogabi@lekogabi:~$ echo $asd (semmi)
Létrehoztunk egy 'asd' nevű változót, amely kezdetben üres. Majd bele tettük a "hello" szöveget, majd az 'unset' parancs segítségével töröltük.
set
Kiírja az összes környezeti változót és az értéküket.
cat <fájl>
Paraméter nélkül írhatunk a képernyőre és Enter leütése után kiírja az addig beírt sort. Fájl paraméter esetén kiírja a fájl tartalmát a képernyőre. Ha "cat > szövegfájl" kombinációt használjuk, akkor a konzolra írt sorokat a szövegfájlba menti, ha >>-t írunk > helyett, akkor pedig a sorokat hozzáfűzi a fájl végéhez. pl.:
lekogabi@lekogabi:~/Dokumentumok$ cat hello hello ^C lekogabi@lekogabi:~/Dokumentumok$ cat > file.txt first ^C lekogabi@lekogabi:~/Dokumentumok$ cat file.txt first lekogabi@lekogabi:~/Dokumentumok$ cat >> file.txt second ^C lekogabi@lekogabi:~/Dokumentumok$ cat file.txt first second
Először kiírtuk a képernyőre, hogy "hello", majd a 'file.txt'-be bele írtuk a "first" sort. Aztán ezt kiírattuk a képernyőre, majd hozzáfűztük ugyanehhez a fájlhoz a "second" sort és kiírattuk.
Cat és a job műveletek használata, pl.:
lekogabi@lekogabi:~$ cat hello hello ^Z [1]+ Megállítva cat lekogabi@lekogabi:~$ jobs [1]+ Megállítva cat lekogabi@lekogabi:~$ fg %1 cat hi hi ^Z [1]+ Megállítva cat lekogabi@lekogabi:~$ jobs [1]+ Megállítva cat lekogabi@lekogabi:~$ kill %1 [1]+ Megállítva cat lekogabi@lekogabi:~$ jobs [1]+ Befejeződött cat lekogabi@lekogabi:~$ jobs lekogabi@lekogabi:~$
more
A fájl tartalmát oldalanként írja ki a képernyőre. ('Space' leütésével lehet léptetni.)
head [kapcsoló]<fájl>
Kiírja a fájl a bizonyos sorait a képernyőre.
Kapcsolók:
-n <-szám>: kiírja a file tartalmát, kivéve az utolsó "szám" mennyiségű sort.
-szám: az első "szám" számú sort írja ki
tail [kapcsoló]<fájl>
Kiírja a fájl a bizonyos sorait a képernyőre.
-n <+szám>: a "szám"-adik sortól kezdve ír ki.
-szám: az utólsó "szám" számú sort írja ki
-f: folyamatosan bővülő fájl tartalmát írja ki.
head, tail és head|tail pl.:
lekogabi@lekogabi:~/Dokumentumok$ cat file2.txt elso masodik harmadik negyedik otodik hatodik hetedik nyolcadik kilencedik tizedik lekogabi@lekogabi:~/Dokumentumok$ head -4 file2.txt elso masodik harmadik negyedik lekogabi@lekogabi:~/Dokumentumok$ tail -2 file2.txt kilencedik tizedik lekogabi@lekogabi:~/Dokumentumok$ head -9 file2.txt | tail -3 hetedik nyolcadik kilencedik
wc [kapcsoló]<fájl>
Kiírja a fájl sorainak a számát, szavainak a számát, a byte-ok számát és a fájl nevét.
Kapcsolók:
-l: csak a nevet és a sorok számát írja ki.
-w: csak a nevet és a szavak számát írja ki.
-c: csak a nevet és a byte-ok számát írja ki.
-m: csak a nevet és a betűk számát írja ki.
pl.:
lekogabi@lekogabi:~/Dokumentumok$ wc file2.txt 10 10 83 file2.txt lekogabi@lekogabi:~/Dokumentumok$ wc -l file2.txt 10 file2.txt
^D
Ctrl+d parancs megszünteti a bemenetet vagy kilép a terminálból (vagy shell programból)
/dev/null
Egy speciális fájl, amely minden beleírt adatot töröl, miközben az írasi művelet sikeres. Az eszközből való olvasás nem ad vissza semmilyen adatot, eredménye azonnali EOF, azaz fájl vége. Felfogható adatnyelő eszközként ("fekete lyuk"). A null eszközt tipikusan folyamatok kimeneti stream-jeinek eltüntetésére használják, vagy az üres bemenet biztosítására, általában átirányítás segítségével. pl.: OpenGL: ./LekoGabor > /dev/null
Beépített környezeti változók:
$PWD: Tárolja az aktuális elérési útvonalat.
$HOME: Tárolja a home könyvtár abszolút elérési útvonalát.
$PS1: A prompt kinézetét leíró kifejezést tárolja.
$PATH: A keresési könyvtárak elérési útvonalát tárolja, itt keresi a parancsokat.
~: Nem környezeti változó, de a home könyvtár elérési útvonalát tárolja.
Mintaillesztés
Ha nem tudjuk egy szöveg pontos alakját, csak egy részét, vagy több szövegrészlettel szeretnénk egyszerre dolgozni, akkor jön jól a mintaillesztés. Használható pl. egyszerre több fájl törlésénél, vagy keresésnél (fájlban, vagy fájlrendszerben).
Speciális karakterek:
? - pontosan egy karaktert helyettesít: pl. ?lma lehet alma vagy álma is így.
* - bármennyi (akár 0) karaktert helyettesít: pl. *gép lehet gép, mosógép, számítógép, stb.
[...] - a [] között felsorolt karakterekből pontosan egyet helyettesít: pl. [aó]lom lehet ólom vagy alom, fajl[0123456789] pedig fajl0, fajl1, ... fajl9.
pl.:
Az összes .txt végződésű fájl kilistázása:
lekogabi@lekogabi:~$ ls *.txt
Minden .png fájl átmásolása a Dokumentumok/hello mappába:
lekogabi@lekogabi:~$ cp *.png /home/lekogabi/Dokumentumok/hello
Az összes .png kép törlése a Dokumentumok/hello mappából:
lekogabi@lekogabi:~/Dokumentumok/hello$ rm *.png
grep [kapcsoló][minta]<fájl>
Kiírja egy fájl azon sorait, amelyekben szerepel a minta szövegrészlet.
Kapocsolók:
-A # : # db sor kiírása az illeszkedő sorok után.
-B # : # db sor kiírása az illeszkedő sorok előtt.
-C # : # db sor kiírása az illeszkedő sorok előtt és után.
-e minta : minta megadása; segítségével több minta is megadható, illetve akkor is jó, ha a minta a - karakterrel kezdődik.
-r, -R: könyvtárak feldolgozása rekurzívan.
-v: azon sorait írja ki, amik nem tartalmazzák a minta szövegrészletet.
pl.:
lekogabi@lekogabi:~/Dokumentumok$ grep hat file2.txt hatodik lekogabi@lekogabi:~/Dokumentumok$ grep ed file2.txt negyedik hetedik kilencedik tizedik lekogabi@lekogabi:~/Dokumentumok$ grep -v ed file2.txt elso masodik harmadik otodik hatodik nyolcadik lekogabi@lekogabi:~/Dokumentumok$
Átirányítások és parancsok láncolása
parancs > szövegfájl
A parancs kimenete a konzol helyett a fájlba fog íródni, a fájl addigi tartalma elvész. pl.:
lekogabi@lekogabi:~/Dokumentumok$ ls -l > file.txt lekogabi@lekogabi:~/Dokumentumok$ cat file.txt -rw-r--r-- 1 lekogabi lekogabi 83 aug 9 21:01 file2.txt -rw-r--r-- 1 lekogabi lekogabi 0 aug 13 19:10 file.txt drwxr-xrwx 2 lekogabi lekogabi 4096 aug 9 15:07 hello -rw-r--r-- 1 lekogabi lekogabi 15796 aug 13 19:09 progalap_linux
parancs >> szövegfájl
A parancs kimenete a konzol helyett a szövegfájl végéhez fog hozzáfűződni. pl.:
lekogabi@lekogabi:~/Dokumentumok$ ls >> file.txt lekogabi@lekogabi:~/Dokumentumok$ cat file.txt -rw-r--r-- 1 lekogabi lekogabi 83 aug 9 21:01 file2.txt -rw-r--r-- 1 lekogabi lekogabi 0 aug 13 19:10 file.txt drwxr-xrwx 2 lekogabi lekogabi 4096 aug 9 15:07 hello -rw-r--r-- 1 lekogabi lekogabi 15796 aug 13 19:09 progalap_linux file2.txt file.txt hello progalap_linux
parancs < szövegfájl
A parancs bemeneteként kapja a szövegfájl tartalmát.
parancs1 | parancs2
A parancs1 kimenete konzolra kiírás helyett a parancs2 bemenete lesz. pl.:
lekogabi@lekogabi:~/Dokumentumok$ cat file2.txt elso masodik harmadik negyedik otodik hatodik hetedik nyolcadik kilencedik tizedik lekogabi@lekogabi:~/Dokumentumok$ head -9 file2.txt | tail -3 hetedik nyolcadik kilencedik
parancs1 && parancs2
A parancs1 végrehajtása után a parancs2 csak akkor hajtódik végre, ha a parancs1 hiba nélkül futott le. pl.:
lekogabi@lekogabi:~/Dokumentumok$ mkdir ujmappa && rmdir ujmappa
Ha létre tudta hozni az 'ujmappa' nevű könyvtárat, akkor ki is törli a második paranccsal.
parancs1 || parancs2
A parancs1 végrehajtása után a parancs2 csak akkor hajtódik végre, ha a parancs1 futása közben hiba történt. pl.:
lekogabi@lekogabi:~/Dokumentumok$ rm -r ujmappa || mkdir ujmappa
Megpróbáljuk törölni az 'ujmappa' nevű könyvtárat. Mondjuk még nincs ilyen könyvtár, akkor hiba üzenetet kapunk, majd létrejön az 'ujmappa' nevű könyvtár.
parancs1;parancs2;parancs3
A parancsok ";"-vel elválasztva egymás után hajtódnak végre balról jobbra.
lekogabi@lekogabi:~/Dokumentumok$ mkdir ujmappa; cd ujmappa; ls -l összesen 0 lekogabi@lekogabi:~/Dokumentumok/ujmappa$
Linux hálózatok
scp <felhasználónév>@<szerver>:<távoli útvonal><helyi útvonal>
Átmásol egy bizonyos fájlt vagy könyvtárat a "távoli útvonal"-ról a "helyi útvonal"-ra, vagy vissza. pl.:
lekogabi@lekogabi:~$ scp h165057@linux.inf.u-szeged.hu:/n/pub/ProgramozasAlapjai/Gyakorlat/gyak02/anyag.txt ./ h165057@linux.inf.u-szeged.hu's password: anyag.txt 100% 3659 3.6KB/s 00:01
ssh [kapcsoló]<felhasználónév>@<szerver>
Csatlakozni lehet a szerverre, futtatni konzolos programokat.
-X: Ezzel a kapcsolóval grafikus programot is indíthatunk.
pl.:
lekogabi@lekogabi:~$ ssh h165057@linux.inf.u-szeged.hu h165057@linux.inf.u-szeged.hu's password: Linux linux1.inf.u-szeged.hu 3.2.0-4-686-pae #1 SMP Debian 3.2.54-2 i686 ****************************************************************************** * Udvozoljuk az Informatikai Tanszekcsoport linux szerveren! * * * * A szerver azt a celt szolgalja, hogy tavoli bejelentkezes eseten ugyanazt * * a kornyezetet biztositsa, amit egy tanteremben levo munkaallomas biztosit. * * * * A szerver mukodesevel, a bejelentkezessel kapcsolatos problemaikat kerjuk * * a kabinet@inf.u-szeged.hu cimen jelezzek. * ****************************************************************************** Last login: Sun May 4 21:38:49 2014 from 79.101.5.52 h165057@linux1:~$ cd LekoGabor h165057@linux1:~/LekoGabor$ make make: Nothing to be done for `application'. h165057@linux1:~/LekoGabor$ ./LekoGabor freeglut (./LekoGabor): failed to open display '' h165057@linux1:~/LekoGabor$ exit kijelentkezés Connection to linux.inf.u-szeged.hu closed. lekogabi@lekogabi:~$ ssh -X h165057@linux.inf.u-szeged.hu h165057@linux.inf.u-szeged.hu's password: Linux linux1.inf.u-szeged.hu 3.2.0-4-686-pae #1 SMP Debian 3.2.54-2 i686 ****************************************************************************** * Udvozoljuk az Informatikai Tanszekcsoport linux szerveren! * * * * A szerver azt a celt szolgalja, hogy tavoli bejelentkezes eseten ugyanazt * * a kornyezetet biztositsa, amit egy tanteremben levo munkaallomas biztosit. * * * * A szerver mukodesevel, a bejelentkezessel kapcsolatos problemaikat kerjuk * * a kabinet@inf.u-szeged.hu cimen jelezzek. * ****************************************************************************** Last login: Wed Aug 13 21:12:17 2014 from 79.101.5.234 h165057@linux1:~$ cd LekoGabor/ h165057@linux1:~/LekoGabor$ make make: Nothing to be done for `application'. h165057@linux1:~/LekoGabor$ ./LekoGabor > /dev/null
sftp <felhasználónév>@<szerver>
Csatlakozik a szerverre és lehetőségünk van lépkedni a szerver könyvtáraiban, illetve a lokális könyvtárunkban, majd leszedni illetve feltölteni bizonyos adatokat.
Egy 'l' betű hozzáadásával tudjuk közölni a géppel, hogy nem a szerveren szeretnék, hogy végrehajtódjon az adott parancs, hanem a lokális gépen. pl.:
ls - lls, pwd - lpwd, cd - lcd, mkdir - lmkdir.
put - fájl átmásolása a lokális gépről a szerver gépre.
get - fájl átmásolása a szerver gépről a lokális gépre.
exit - kilép a szerverről.
pl.:
lekogabi@lekogabi:~$ sftp h165057@linux.inf.u-szeged.hu h165057@linux.inf.u-szeged.hu's password: Connected to linux.inf.u-szeged.hu. sftp> cd ../.. sftp> cd pub/ProgramozasAlapjai/Gyakorlat/gyak02/ sftp> get anyag.txt Fetching /n/pub/ProgramozasAlapjai/Gyakorlat/gyak02/anyag.txt to anyag.txt /n/pub/ProgramozasAlapjai/Gyakorlat/gyak02/an 100% 306 0.3KB/s 00:00 sftp> exit lekogabi@lekogabi:~$
2. gyakorlat
C alapok
Órán használt fejlesztőkörnyezet: CodeLite (!)
További GCC Windows-ra: Code::Blocks , Cygwin
Első lépések
Kommentek:
// Ez egy egysoros komment, ami itt van az nem fog látszani a programban
/*
Ez egy többsoros komment, ez sem fog látszani a programban
*/
Main - fő függvény
/*
MAIN függvény, ez a függvény fog lefutni először
*/
int main(){
return 0; // a main függvény visszatérési értéke: Op. rendszer felé: Nincs hiba
/* return 1; // a main függvény visszatérési értéke: Op. rendszer felé: Valami hiba történt */
}
Input - Output használata
/*
A ki- és bevitel használatához szükségünk van az alábbi sorra.
*/
#include <stdio.h>
/*
Ezek után használhatjuk a scanf és printf I/O függvényeket
Az input-output használatához meg kell mondani a fordítónak, hogy szeretnénk használni az ezzel kapcsolatos függvényeket.
*/
Fordítás és futtatás parancssorban:
Fordítás és futtatás Linux alatt (terminalban): $ gcc -o prog progalap.c // fordítás $ ./prog // futtatás Object fájl készítése: $ gcc -c -o progalap.o progalap.c $ gcc -o progalap progalap.o Warning-ok kiíratása fordítás után: $ gcc -Wall -o hello helloworld.c
Szekvenciák
Minden utasítást pontosvessző (";") zár.
Ha nem teszünk pontos vesszőt, akkor kifejezésről beszélünk.
Kifejezés - egy (önmagában még nem végrehajtható) elemi művelet. pl.: 3 + 5
Utasítások sorozatát szekvenciának nevezzük.
Példa:
main() {
3 + 5 // kifejezés
3 + 5; // utasítás
}
Feladat: Csinálj utasítást a következő értékekből/értékeket kiszámító kifejezésekből:
- Egy év napjainak száma. - Mikor született az, aki most 18 éves? - Átlagban hány órát kell hetente otthon a progalap gyakorlásával tölteni a szorgalmi időszakban, ha egy kredit (a teljes félév során elvégzett) 30 munkaórát jelent, a félév 20 hétből áll, és ebbe a kreditszámba az órai munka is beleszámít?
Változók használata
Változók deklarációja - Deklaráció: elemek létrehozása
void main(){
// void - Ez egy adatot tárolni képtelen típus, többek között eljárásokhoz használatos
int egesz; // Egy egyszavas (esetünkben 32 bites - 4 bájtos) előjeles egész szám
// Műveletek: +, -, *, /, %, ahol a / az egészosztás egészrésze, a % az egészosztás maradéka
char karakter; // Egy egybájtos, előjeles, vagy előjeltelen egész szám. Jól használható szöveges karakterek tárolására is, ascii-kód segítségével.
float valos1; // Egy egyszavas lebegőpontos szám
// Műveletek: +, -, *, /
double valos2; // Annyiban különbözik a float-tól, hogy 8 bájtos
// Logikai és szöveges típus külön nincs, azokat máshogy kell megvalósítani. (Későbbi gyakorlaton)
}
Változók definiálása - Definíció: a tényleges értékadás
void main(){
int egesz = 2014;
char karakter = 'A'; // Karakterek megadásakor (és mint később látjuk, szövegekben is) használhatunk escape-szekvenciákat, pl.: \" - idézőjel, \' - aposztróf, \t - tabulátor, \n - soremelés (új sor), \r - kocsi-vissza
float valos1 = 3.1415916; // természetesen a float és double is tud tárolni sokkal nagyobb számokat is (ezekről későbbi gyakorlaton lesz szó)
double valos2 = 3.1415916; // hogy pontosan miben is különbözik a 4 és a 8 bájton való tárolás, arról később lesz szó
}
Input/Output alapok
printf - Kiíratás képernyőre:
#include <stdio.h>
void main(){
/* Változók deklarálása és definiálása */
int egesz = 2014;
char karakter = 'A';
float valos1 = 3.1415916;
double valos2 = 3.1415916;
/* Kiíratás képernyõre */
/* % + "adott típus jelző karakter(ek)" kombináció helyére fog behelyettesítődni, a szöveg után megadott változó értéke. Ügyeljünk a típusra! */
printf("Egyszerű szöveg\n");
printf("Integer érték: %d\n", egesz); // %d - int
printf("Karakter: %c\n", karakter); // %c - char
printf("Float érték: %f\n", valos1); // %f - float
printf("Double érték: %lf\n", valos2); // %lf - double
printf("%s\n", "Szöveg, mint \"string\"\n");
}
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:
printf("%10.3lf", 42.7); => " 42.700"
printf("%10.0lf", 42.7); => " 43"
printf("%.2lf", 42.7); => "42.70"
scanf - Adatok bekérése:
#include <stdio.h>
void main(){
int egesz;
float valos1;
double valos2;
/* Adatok bekérése */
printf("Adj meg egy egész számot:\n");
scanf("%d", &egesz);
printf("Adj meg két valós számot (Üss Enter-t a két szám bevitele között):\n");
scanf("%f", &valos1);
scanf("%lf", &valos2);
printf("\n\n");
}
Egy kis érdekesség:
#include <stdio.h>
void main(){
// Egész egészként és karakterként
printf("%d\n",65);
printf("%c\n\n",65); // az ASCII tábla szerint a 65. karakter az 'A'
// Valós valósként és egészként
printf("%f\n",65.5555);
printf("%d\n\n",65.5555); // egészként kiíratva egy valós számot nem épp a helyes eredményt kapjuk meg
// Karakter karakterként és egészként
printf("%c\n",'A');
printf("%d\n",'A'); // az ASCII tábla szerint ismét csak az 'A' karakterkódja 65
}
Több adat beolvasása egyszerre:
#include <stdio.h>
void main(){
int st, rd; // egész típusú változók
char nd, th; // karakter típusú változók
printf("Beolvasás (egész karakter egész karakter): ");
scanf("%d%c%d%c", &st, &nd, &rd, &th); // mivel különböző típusok vannak egymás után felsorolva, így gond nélkül bekérhetjük őket egymás után
printf("first = %d; second = '%c'; third = %d; fourth = '%c';\n", st, nd, rd, th);
}
Feladat: Írj egy programot amely bekéri a neved, majd a bekérés után kiírja azt a képernyőre! Ezután bekéri a születési dátumod és kiszámítja a korodat, és ezt is kiírja a képernyőre!
Feladat: Alakítsd át a fenti programot úgy, hogy bekérje a vezetékneved, majd a születési dátumod, majd a keresztneved és végül a korodat! A bekért adatokat "logikus sorrendben" írasd ki a képernyőre!
Blokkok
Blokknak nevezünk két kapcsos zárójel - { } - közé zárt programrészt.
Egy blokkon belül minden változónév csak egyszer használható, egy blokkon belül létrehozott változók csak az adott blokkban használhatók.
void main(){
int szam1;
{
int szam2 = 2;
}
{
int szam3 = 3;
//int szam4 = szam1 + szam2 + szam3; // itt hiba lesz mivel a szam2 nincs deklarálva ebben a blokkban
}
}
Globális és Lokális változók
Globális változó: blokkon kívül deklarált, mindenhol látszik.
Lokális változó: valamilyen blokkon (függvényen) belül deklarált, csak az adott blokkon belül látszik.
#include <stdio.h>
int global = 0;
int LG(int alpha) {
int local = 0;
local += alpha; // local = local + alpha; rövidítése
/*
Az alábbiakra is igaz:
a = a + b, ugyanaz, mint a+=b
a = a - b, ugyanaz, mint a-=b
a = a * b, ugyanaz, mint a*=b
a = a / b, ugyanaz, mint a/=b
*/
global += alpha;
return local;
}
void main() {
printf("Lokalis valtozo: %d, Globális változó: %d\n", LG(2), global);
printf("Lokalis valtozo: %d, Globális változó: %d\n", LG(2), global);
printf("Lokalis valtozo: %d, Globális változó: %d\n", LG(2), global);
}
Feladat: Próbáljuk ki, fordul-e a fenti program, ha a main függvényben megpróbáljuk felhasználni a local változót!
Feladat: Mi történik, ha a global-t csak a fuggveny után deklaráljuk?
Függvényekben és beágyazott blokkokban létrehozhatunk ugyanolyan nevű változót, mint amilyen valamilyen felsőbb szinten már deklarálva van. Ez el fogja rejteni a felsőbb szintű példányt:
#include <stdio.h>
int a = -1;
void fgv() {
printf("%d\n", a);
}
void main() {
int a = 0; // ez elrejti a globális a változót
{
int a = 1; // ez elrejti az eggyel feljebb lévő a változót
{
int a = 2; // ez elrejti az eggyel feljebb lévő a változót
printf("%d\n", a); // 2
}
printf("%d\n", a); // 1
}
printf("%d\n", a); // 0
fgv(); // -1
}
Feladat: Próbáld meg futtatás nélkül megtalálni a hibá(ka)t, majd javítsd (őket)!
int main() {
int elso;
elso = 3;
{
int masodik;
elso = 6
masodik = 5;
}
{
int harmadik;
elso = 9
masodik = 10;
harmadik = 8;
}
masodik = 15;
harmadik = 16;
return 0;
}
Függvények
Deklaráció:
típus név( formális_paraméterek );
Definíció:
típus név( formális_paraméterek ) {
törzs
}
Példa függvények használatára:
#include <stdio.h>
void main(){
// A main függvény allján lévő függvények hívása
nullParamVoid();
nullParamInt();
printf("%d\n\n", negyzetKerulet(5));
int terulet = teglalapTerulet(3,4);
printf("%d\n\n", terulet);
}
void nullParamVoid(){
printf("Ez egy paraméter nélküli függvény, amelynek nincs visszatérési értéke.\n\n");
}
int nullParamInt(){
printf("Ez egy paraméter nélküli függvény, amelynek 1 a visszatérési értéke.\n\n");
return 1;
}
// Egy egyparaméteres fgv, ami kiszámítja egy négyzet kerületét az oldalhosszból
int negyzetKerulet(int a){
int kerulet;
kerulet = 4*a;
return kerulet;
}
// Egy többparaméteres fgv, ami kiszámítja egy téglalap területét a két oldalhosszból
int teglalapTerulet(int a, int b){
return a*b;
}
Feladat: Írj egy függvényt, ami összead két egész értéket, és visszatér az eredménnyel! Írj egy programot is, ami felhasználja ezt!
3. gyakorlat
Mit is tanultunk a 3. gyakorlaton?
Ismerkedés a BÍRÓval
BÍRÓ: itt fogjátok az éles ZH-kat megkapni és feltölteni: https://biro.inf.u-szeged.hu
BÍRÓ2: itt tudjárok kipróbálni az éles ZH-k előtt a BÍRÓ működését: https://biro2.inf.u-szeged.hu
Két BÍRÓ rendszert különböztetünk meg:
Mindkét honlap esetén egy biztonsági kérdés érkezik először! Itt nem kell megijedni. Csak keressük meg a megjelenő oldalon, hogy hogyan kell elfogadni a feltételeket. Fogadjuk el, hogy tisztában vagyunk minden eshetőséggel és lépjünk tovább.
Ezután regisztráljunk mindkét BÍRÓ rendszerben:
Vezérlési szerkezetek
Az if utasítás segítségével valamely tevékenység (utasítás) végrehajtását egy kifejezés (feltétel) értékétől tehetjük függővé. Az if alábbi formájában az utasítás csak akkor hajtódik végre, ha a kifejezés értéke nem nulla (igaz):
if (kifejezés){
utasítás
}
Az if-else szerkezet használatával arra az esetre is megadhatunk egy tevékenységet, amikor a kifejezés (feltétel) értéke zérus (hamis):
if (kifejezés){
utasítás
} else {
utasítás
}
Az else-if szerkezet nem más, mint egymásba ágyazott if utasítások egy gyakran használt formája, amikor az else ágakban szerepel az újabb if utasítás:
if (kifejezés){
utasítás
} else if (kifejezés){
utasítás
} else if (kifejezés){
utasítás
} else {
utasítás
}
A zárójelben lévő kifejezés egy logikai kifejezést takar. Ezt a program a szelekciós vezérlőszerkezet végrehajtásakor kiértékeli, és a kiértékelés eredménye vagy igaz vagy hamis érték. Egy logikai kifejezés logikai változókból/értékekből és logikai operátorokból állhat. A C nyelvben nincs külön logikai típus, egész típusokban (int, char) tárolhatunk logikai értékeket: a 0 jelenti a hamisat, a nem nulla pedig az igazat (ez gyakran 1, DE fordítója válogatja). Logikai értékek keletkezhetnek relációs operátorok használatával, ezek két érték összehasonlítására használhatók
Relációs operátorok:
a és b értékek: változók, konstansok, valamilyen művelet vagy függvény eredményei, vagy literálok (literálnak nevezzük a helyben definiált adatot, pl. 5, vagy 'A')
a == b - a egyenlő-e b-vel. HA FELTÉTELESEN KÉRDEZÜNK RÁ MINDIG == KELL! a < b - a kisebb-e b-nél a > b - a nagyobb-e b-nél a <= b - a kisebb-egyenlő-e b-nél a >= b - a nagyobb-egyenlő-e b-nél a != b - a nem egyenlő-e b-vel
Logikai operátorok:
a és b logikai értékek: változók, konstansok, valamilyen művelet vagy függvény eredményei, vagy literálok
!a - a kifejezés értéke NEM a, tehát akkor lesz igaz, ha a hamis volt a && b - a kifejezés értéke a ÉS b, tehát akkor lesz igaz, ha a és b is igaz volt a || b - a kifejezés értéke a VAGY b, tehát akkor lesz igaz, ha a és b közül legalább az egyik igaz volt
Feladat: Készíts egy programot, ami bekér egy egész számot és kiírja, hogy az adott szám páros vagy páratlan-e. ( Emlékeztető: egész számok esetén az osztási maradékot a % jel segítségével kapjuk meg )
#include <stdio.h>
int main() {
int x;
printf("Kérek egy egész számot:");
scanf("%d", &x);
if (x%2 == 0) // megnézzük, hogy az x 2-vel való osztása után a maradék értéke 0-e, ha igen akkor az azt jelenti, hogy x osztható 2-vel, tehát páros
printf("A megadott szám páros.\n");
else // ellenkező esetben a maradék nem 0, tehát nem osztható maradék nélkül 2-vel, tehát páratlan
printf("A megadott szám páratlan.\n");
return 0;
}
Feladat: Módosítsuk most a programot úgy, hogy két egész számot kérjen be a program majd írja ki, hogy az első szám osztható-e a másodikkal.
Feladat: Próbáljuk ki, mi történik, ha a második szám 0! Javítsuk a programot!
Feladat: Használjunk többszörös szelekciót! ( else-if )
Feladat: Írjuk meg if nélkül a fenti programot. (megoldás a következő anyagrészben: feltételes kifejezések)
Feltételes kifejezések
Az if-else helyett feltételes kifejezések is használhatók. Ezzel tömörebb formában fogalmazható meg ugyanaz, sőt, egy adott helyre behelyettesítendő érték kiválasztására is használható.
feltetel ? muvelet ha igaz : muvelet ha hamis;
Feladat: Írjuk ki egyetlen printf segítségével, hogy egy szám páros vagy páratlan-e!
#include <stdio.h>
int main() {
int x;
printf("Kérek egy egész számot: ");
scanf("%d", &x);
// tehát ez a sor ugyanazt eredményezi, mint az előző részben az if-else használatával, csupán egyszerűbb a kivitelezés
printf("A szám %s.\n", (x%2 == 0) ? "páros" : "páratlan");
return 0;
}
PÉLDA: a feltételes kifejezéseket egymásba is ágyazhatjuk:
#include <stdio.h>
int main () {
int x;
printf("Kérek egy egész számot: ");
scanf("%d", &x);
printf("Kérek egy másik számot: ");
scanf("%d", &y);
printf("Osztoja-e %d-nek %d?. %s\n", x, y, // %s helyére string-ek, azaz karaktersorozatok helyettesíthetők be, így pl. bármilyen szöveg "" között megadva
(y==0) ? "A kerdes ertelmetlen!" : // tehát leellenőrizzük, hogy y nulla-e, ha igen, akkor kiírjuk, hogy értelmetlen,
((x%y==0) ? "Igen, osztója." : "Nem, nem osztója.") // ellenkező esetben, pedig az x és y oszthatóságától függően kerül kiírásra az 1. avagy a 2. állítás
);
}
Esetkiválasztásos szelekciós vezérlés
A switch utasítás többirányú programelágaztatást tesz lehetővé olyan esetekben, amikor egy egész kifejezés értékét több konstans értékkel kell összehasonlítanuk. Az utasítás álatlános alakja:
switch ( kifejezés ) {
case címke : műveletek; break;
case címke : műveletek; break;
...
case címke : műveletek; break;
default : műveletek; break;
}
A switch utasítás először kiértékeli a kifejezést, majd átadja a vezértlést arra a case címkére (esetre), amelyben a címke értéke megegyezik a kiértékelt kifejezés értékével - a futás ettől a ponttól folytatódik. Amennyiben egyik case sem egyezik meg a kifejezés értékével, a program futása a default címkével megjelölt utasítással folytatódik. Ha nem használunk default címkét, akkor a vezérlés a switch utasítás blokkját záró } utáni utasításra adódik. A break utasítás kiugrasztja a switchből a vezérlést, ha kihagyjuk, az a következő címkére kerül. Ez használható pl. olyankor, ha több címkéhez ugyanazokat a műveleteket kell végrehajtani.
Feladat: Írjunk egy függvényt, ami egy "x" egész számot kap paraméterként és kiírja, hogy a hét x. napja milyen nap.
void hetnapja_if (short int x) {
if (x==1) {
printf("Hétfő\n");
} else if (x==2) {
printf("Kedd\n");
} else if (x==3) {
printf("Szerda\n");
} else if (x==4) {
printf("Csütörtök\n");
} else if (x==5) {
printf("Péntek\n");
} else if (x==6) {
printf("Szombat\n");
} else if (x==7) {
printf("Vasárnap\n");
} else
printf("Hiba! x értéke legalább 1 és legfeljebb 7 lehet!\n");
}
Feladat: Írjuk meg ugyanezt az fgv-t switch használatával.
void hetnapja_switch (short int x) {
switch (x) { // tehát ez a sor miatt az x kerül összehasonlításra a case-ek után megadott értékkel
case 1: // amennyiben valamelyik case-re ráillik az x, akkor az azon belül lévő utasítás sorozat fog lefutni
printf("Hétfő\n");
break; // ha break-kel zárjuk le a case-t, akkor akár ráillene a többi eset valamelyikére az x, akár nem, mindenképp ki fog lépni a switch-ből
case 2:
printf("Kedd\n");
break;
case 3:
printf("Szerda\n");
break;
case 4:
printf("Csütörtök\n");
break;
case 5:
printf("Péntek\n");
break;
case 6:
printf("Szombat\n");
break;
case 7:
printf("Vasárnap\n");
break;
default: // tehát, ha egyik esetre sem illet rá az x, akkor a default fog lefutni (melynek megadása NEM kötelező)
printf("Hiba! x értéke legalább 1 és legfeljebb 7 lehet!\n");
}
}
Feladat: Írjuk meg a main-t is a fenti függvény használatához.
Kezdőfeltételes ismétléses vezérlés
Más néven előltesztelős ciklus, vagy while-ciklus.
A while ciklus mindaddig ismétli a hozzá tartozó utasítást (a ciklus törzsét), amíg a vizsgált kifejezés (vezérlőfeltétel) értéke igaz (nem nulla). A vizsgálat mindig megelőzi az utasítás végrehajtását. Általános alakja:
while (kifejezés){
utasítás
}
Tehát, ha a kifejezés értéke már kezdetben is hamis, akkor a while ciklus törzsén belül elhelyezkedő utasítás(ok) egyszer sem fut(nak) le.
A switch-nél látott break utasítás ciklusokból való "kitörésre" is alkalmazható. Így írhatunk olyan (esetleg egyébként végtelen) ciklust, amelyben egy, vagy több helyen egy if segítségével megvizsgálunk egy feltételt, majd az alapján (esetleg néhány művelet végrehajtása után) kilépünk a ciklusból. Ezt hívjuk hurok ismétléses vezérlésnek.
Feladat: Írjunk egy programot, ami kiírja 1-től 10-ig számokat.
#include <stdio.h>
int main() {
int i = 1;
while (i<=10) { // tehát addig fog futni a ciklus, amíg az i értéke kisebb vagy egyenlő, mint 10
printf("%d\n", i);
i = i + 1; // FONTOS! Ne felejtsük el növelni az i értékét, különben a ciklus futásának soha sem lesz vége, azt nevezzük VÉGTELEN CIKLUSnak
}
return 0;
}
Feladat: Írjunk olyan programot, ami addig kér be számokat a billentyűzetről, amíg a beírt szám nem 0! (0 az adott végjel)
Feladat: Módosítsuk a programot úgy, hogy végeredményként írja ki a beírt számok összegét!
Végfeltételes ismétléses vezérlés
Más néven hátultesztelős ciklus, vagy do-while-ciklus.
A do-while utasításban a ciklus törzsét képező utasítás végrehajtása után kerül sor a tesztelésre. Így a ciklus törzse legalább egyszer mindig végrehajtódik. Általános alakja:
do {
utasitas
} while (kifejezés);
A do-while ciklus futása során mindig először végrehajtódik az utasítás és ezt követően értékelődik ki a kifejezés. Amennyiben a kifejezés értéke igaz (nem nulla), akkor új iteráció kezdődik (azaz újra lefut a ciklus), míg hamis (0) érték esetén a ciklus befejezi működését.
Feladat: Írjunk egy olyan programot 'do-while' ciklus segítségével, ami 0 végjelig kér be számokat, majd kírja azok összegét. A ciklusban ne szerepeljen a 'break' utasítás.
#include <stdio.h>
int main() {
int x, osszeg=0;
do {
printf("Kérek egy számot (kilépéshez: 0):");
scanf("%d", &x);
osszeg+=x;
} while (x!=0); // tehát mindig a ciklus végén történik az ellenőrzés
printf("A számok összege: %d\n", osszeg);
return 0;
}
Számlálásos ismétléses vezérlés
Más néven for-ciklus.
A for utasítást átlagban akkor használjuk, ha a ciklusmagban megadott utasítást adott számszor kívánjuk végrehajtani. Általános alakja:
for (kezdőérték_kifejezés ; feltétel_kifejezés ; léptető_kifejezés){
utasítás
}
A ciklusban van egy változó (a ciklusváltozó, vagy számláló), amit egy kezdőértékből kiindulva, folyamatosan növelünk vagy csökkentünk egy végértékig, és minden ilyen körben végrehajtunk néhány műveletet. A műveletekben a ciklusváltozó aktuális értéke is felhasználható.
A kezdőérték_kifejezés-sel állítjuk be a ciklusváltozó kezdőértékét. A léptető_kifejezés-sel növeljük vagy csökkentjük a ciklusváltozó értékét tetszés szerint. A feltétel_kifejezés-t pedig minden egyes iterációban ellenőrizzük. A ciklus addig fut amíg ez a feltétel teljesül. Mivel a feltételünk akkor nem fog már teljesülni, amikor a ciklusváltozó elér egy bizonyos értéket, ezért jól befolyásolható, hogy a ciklus hányszor fusson le.
A ciklus változó növelésére (inkrementálására) és csökkentésére (dekrementálására) létezik egy-egy speciális operátor:
A++; => A = A + 1; (avagy A += 1;) A--; => A = A - 1; (avagy A -= 1;) Postfix és prefix alakban is használhatóak, jelentésük kicsit különböző: B = A++; => 1. B = A; 2. A = A + 1; Tehát B A korábbi értékét kapja. B = ++A; => 1. A = A + 1; 2. B = A; Tehát B A megnövelt értékét kapja meg. Ugyanez érvényes a -- operátorra is.
Feladat: Írjunk egy programot, ami összeszorozza 1-10-ig a számokat.
#include <stdio.h>
int main() {
int i;
int szorzat;
// több kezdő érték illetve léptető kifejezés is megadható vesszővel elválasztva
for (i=1, szorzat=1; i<=10; ++i) { // tehát i=1 miatt 1-től indul a számlálás és egész addig tart amíg i el nem éri a 10-es értéket, az i<=10 miatt
szorzat*=i; // és minden egyes körben képezzük az szorzatot az adott i-vel (1*2*3*...*10)
}
printf("A számok szorzata: %d\n", szorzat);
return 0;
}
Feladat: Módosítsuk a for ciklust úgy, hogy csak minden 3-mal osztható számot szorozzon össze!
#include <stdio.h>
int main() {
int i;
int szorzat;
for (i=3, szorzat=1; i<=10; i+=3) // csak annyit kell tennünk, hogy az i értékét nem 1-gyel, hanem 3-mal növeljük minden egyes körben 3-tól indítva
szorzat*=i; // mivel 3 ugyebár osztható 3-mal, ezért ha mindig 3-mal nő i, így mindig a 3-mal osztható számokat kapjuk, egész a végfeltételig (jelen esetben 10-ig)
printf("A számok szorzata: %d\n", szorzat);
return 0;
}
Feladat: Próbáljuk ki mit csinál az alábbi for ciklus:
int i,j,output;
for (i=1, j=100, output=0; i<=10; i++, j--)
output+=i*j;
Feladat: Módosítsuk a ciklusmagot úgy, hogy egy printf segítségével kiírjuk az i,j és out aktuális értékét.
Plusz pontos órai feladat ...
Jövő héten 1. ZH (2018.09.24.)
Téma:
C programozás (ezután mindig az lesz): 2. gyakorlat anyaga.
Gyakorlásra:
A honlapomon a 2. gyakorlathoz tartozó anyag, magyarázatokkal, példákkal.
A honlapom mellett további feladatok találhatóak a PUB-ban. (/n/pub/ProgramozasAlapjai/Gyakorlat/ - erős átfedés van az "itt" és "ott" található feladatok között).
Jelmondat: "Nézegetéssel nem lehet programozni tanulni, csak gyakorlással!"
Összegzésként:
Tudni kellene C programot fordítani és futtatni. ( "gcc -o vmi vmi.c" ÉS "./vmi" )
Létrehozni változókat. ( int, char, float, double )
Beolvasni adatot. ( scanf )
Kiíratni adatot. ( printf )
Visszatérési értékekre ügyelni. ( return )
Csak azt programozzuk le amit a feladat kér, se többet, se kevesebbet. Pl. ha sortörést kér, teszünk sortörést, ha nem írja, hogy ki kellene írni valamit a képernyőre, nem íratunk ki semmit, stb.
( Az itt felsoroltakra a további ZH-kon is mind szükség lesz. )
Egyéb infó:
Előreláthatóan 30 percetek lesz a feladatok megoldására és beadására. A feladatokat a BÍRÓ rendszeren keresztül fogjátok megkapni és beadni is, és az értékelést is a bíró fogja csinálni ott helyben. Tehát egyből látni fogjátok a pontszámokat amiket a bíró adott. Limitált a feltöltések száma és mindig a legjobb pontszám fog számítani. Aki késik, az is csak a fenti időintervallum alatt írhatja a ZH-t, mivel a bíró rendszer nyit, majd automatikusan zár is. Hiányozni csak igazolással lehet, de a ZH akkor sem pótolható!
4. gyakorlat
Mit is tanultunk a 3. gyakorlaton?
Ismétlő feladat:
(a) Kérj be 1 és 10 között egy számot az alapjan, hogy mennyit gyakorolja az adott hallgató hetente a progalapot.
Ha a szám >=5 és <=10, akkor eleget tanul a hallgató, <5 esetén többet kellene, ha > 10 akkor írjuk ki, hogy helytelen adat vagy csak nagyon jó a hallgató.
(b) Kérdezz rá, hogy szeretné-e a hallgató megváltoztatni a megadott számot (y/n). Írasd ki, hogy mit választott a hallgató.
(c) Kezdőfeltételes ismétléses vezérléssel kérj be 5 számot (tehát ciklusonként 1 számot).
(d) Számlálásos ismétléses vezérléssel oldd meg egy 5*5-ös táblázat kiíratását.
(e) Majd egy végfeltételes ismétléses vezérlést addig futtass, amíg nem kap a program egy SPACE karaktert.
Megoldás letöltése .
Tömbök
Több azonos típusú adat egyben való tárolására és kezelésére alkalmazhatók a tömbök.
Általános alakja:
típus név[méret];
pl.: 10 darab egész érték tárolására egy tömb létrehozása:
int tomb[10];
A tömbök egyes elemeire egy úgynevezett index-szel lehet hivatkozni. Ez maga a tömben lévő elemek sorszáma. A tömbben az elemek sorszámozása 0-tól kezdődik. Tehát a tömben lévő első elem indexe 0. Ennek megfelelően egy N méretű tömb utolsó eleme az N-1. indexen érhető el. Ha végig szeretnénk haladni a tömb elemein egy ciklussal, akkor az indexek helyes kezelésére nagy figyelmet kell fordítani.
Feladat: Készíts egy 10 egész szám tárolására alkalmas tömböt. Töltsd fel az 1..10 értékekkel, majd írasd ki az elemeit.
#include <stdio.h>
#define N 10
#define M 10
int main()
{
int tomb[N]; // létrehozzuk az N méretű, 1 dimenziós tömböt
int i;
for(i=0; i<M; i++) {
tomb[i]=i+1; // megyünk sorba a tömb elemein és mindnek értéket adunk, méghozzá a folyamatosan növő i értékét kapják meg a tömb elemei egymás után
}
for(i=0; i<M; i++) {
printf(" %d", tomb[i]);
}
return 0;
}
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|
Az első sor prezentálná a tömb elemek indexeit, a második sor pedig az adott indexhez tartozó tömb elem által tárolt értéket.
Kérdés: Mi történik, ha M<N? És ha N<M?
Egy tömbnek az alábbi módon is adhatunk értéket:
int tomb[10] = {2,3,4,7,6,5,10,9,8,1};
Feladat: Készíts egy 3x3-as mátrixot, töltsd fel elemekkel, majd írasd ki az elemeit sor illetve oszlopfolytonosan is!
#include <stdio.h>
#define N 3
int main()
{
int tomb[N][N];
int i, j;
for(i=0; i<N; i++) { // a különböző ciklusokat egybásba is lehet ágyazni
for(j=0; j<N; j++) { // jelen esetben N-szer fog lefutni a külső for ciklus
scanf("%d", &(tomb[i][j])); // és (N*N)-szer a belső
}
}
for(i=0; i<N; i++) { // természetesen itt is és a következőnél is ugyanaz a helyzet
for(j=0; j<N; j++) {
printf("%d ", tomb[i][j]);
}
printf("\n");
}
printf("\n");
for(i=0; i<N; i++) {
for(j=0; j<N; j++) {
printf("%d ", tomb[j][i]);
}
printf("\n");
}
return 0;
}
Feladat: Írj egy függvényt, ami egy egész tömböt kap paraméterül és lecseréli benne az elemeket az abszolútértékükre. A tömb kiírását szintén függvény végezze!
#include <stdio.h>
#define N 10
void tombabs(int tomb[], int meret) {
int i;
for(i=0; i<meret; i++) {
if(tomb[i<0) { // ha kisebb, mint 0, akkor negatív, tehát negálunk
tomb[i] = -tomb[i];
}
}
}
void kiir(int tomb[], int meret) {
int i;
for(i=0; i<meret; i++) {
printf(" %d", tomb[i]);
}
putchar('\n');
}
int main()
{
int i, T[N], e=1;
for(i=0; i<N; i++) { // a tömb feltöltése változó értékekkel
T[i]=e;
e *= -2;
}
kiir(T, N); // a jelenlegi tartalom kiíratása
tombabs(T, N); // abszolút értéket számoló függvény meghívása
kiir(T, N); // tömb ismételt kiíratása, immáron az abszolút értékekkel
return 0;
}
Karaktertömbök - "stringek"
Mivel C-ben nincs külön string típus, ezért karaktertömbök megvalósításával helyettesíthetjük őket.
Lényegileg ugyanolyan, mint egy sima tömb, csak egy karaktersorozatot fogunk benne letárolni,
és az előzőekhez hasonlóan hivatkozhatunk minden egyes karakterre a megadott szövegünkben,
külön-külön is akár, részekre bontva.
A szöveg végét egy 0 ascii kódú karakter (a NULL karakter)
jelzi. Ez a karakter a tömbön belül bárhol lehet, az utána levő tömbelemeket a sztringeket feldolgozó
függvények figyelmen kívül hagyják, így egy tömbben bármilyen hosszúságú szöveg tárolható,
ami rövidebb a tömb méreténél. A záró 0 karakternek mindenképpen szerepelnie kell,
mivel a tömb mérete nem állapítható meg, így nem lehetne tudni meddig tart a szöveg a memóriában.
Emiatt eggyel nagyobb méretű tömböt kell deklarálni szöveg tárolására, hogy a záró 0 elférjen
Tehát, hogy is nézne ez ki a létrehozás:
char karaktertomb[10]; // 10 karakter tárolására elegendő karaktertömb
Tételezzük fel, hogy feltöltöttük a tömbünket, mi van most benne? Mondjuk benne van a "PROGALAP" szó:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
P | R | O | G | A | L | A | P | 0 | ? |
Ahol a kérdőjelek definiálatlan, véletlenszerű adatot jelentenek.
Feladat: Deklarálj egy megfelelő hosszúságú karaktertömböt, majd írd bele a "Hello Vilag!" szöveget! Írasd ki az str értékét kétféleképpen!
#include <stdio.h>
int main()
{
char str[20];
str="Hello Vilag!";
printf("%s", str);
return 0;
}
Ez így fordítási hiba. A baj az, hogy str egy karaktertömb, tehát egyesével lehet feltölteni az elemeit. Vagy használhatjuk az strcpy() függvényt.
#include <stdio.h>
#include <string.h>
int main()
{
char str[20];
strcpy(str, "Hello Vilag!");
printf("%s", str);
printf(str);
return 0;
}
Feladat: Ha tudjuk, hogy egy karaktersorozatot a 0 karakter zár, akkor módosítsd a programot úgy, hogy a következő sorba csak a "Hello" szöveget írja ki!
Feladat: Készíts egy programot, amely beolvas egy legfeljebb 255 karakter hosszú sztringet, majd kiírja a sztringben található számjegyek számát.
Nézzünk néhány érdekesebb példát:
Feladat:
Buborék rendezés. Vegyünk egy 1D tömböt, amelybe 10 számjegyet olvasunk be, tetszőleges sorrendben. A buborék rendezés elve, hogy haladunk végig a tömbön és egyesével hasonlítgatjuk össze az egymás mellett lévő tömb elemeket. Ha az alacsonyabb indexű elem nagyobb, mint a mellette levő, magasabb indexű, akkor cseréljük ki őket. Így járjunk el egészen addig, amíg nagyság szerinti sorrendbe nem lesz rendezve a tömbünk.
Megoldás letöltése .
Feladat:
Fibonacci sorozat. A rákövetkező szám mindig az őt megelőző kettő összege. 0,1,1,2,3,5,8,13,21,34,55,89,...
Megoldás letöltése .
Feladat: Bővítsük úgy az előbbi feladatot, hogy ne a képernyőre íródjon ki az adott számot, hanem egy tömbbe kerüljenek a sorozat elemei, egymás után, majd az így kapott tömb tartalmát írjuk ki a program végén.
Megoldás letöltése .
Jövő héten 2. ZH (2018.10.01.)
Téma:
3. gyakorlat anyaga. (De tudni kell az azt megelőző gyakorlatok anyagát is!)
Gyakorlásra:
A honlapomon lévő anyag, magyarázatokkal, példákkal.
A honlapom mellett további feladatok találhatóak a PUB-ban. (/n/pub/ProgramozasAlapjai/Gyakorlat/ - erős átfedés van az "itt" és "ott" található feladatok között).
Egyéb infó:
Előreláthatóan 30 percetek lesz a feladatok megoldására és beadására. A feladatokat a BÍRÓ rendszeren keresztül fogjátok megkapni és beadni is, és az értékelést is a bíró fogja csinálni ott helyben. Tehát egyből látni fogjátok a pontszámokat amiket a bíró adott. Aki késik, az is csak a fenti időintervallum alatt írhatja a ZH-t (a bíró rendszer nyit, majd automatikusan zár is). Hiányozni csak igazolással lehet, de a ZH akkor sem pótolható!
5. gyakorlat
Karakter, Float és Integer típusról komolyabban
sizeof operátor - típusok méretének meghatározása byteokban. Pl.:
int i = sizeof(int); // ilyenkor az i változóba bele kerül az int típus mérete. ez a C esetén 4 byte
A legtöbb típust mind meglehet adni előjeles vagy előjeltelen formában. Egy típust előjelessé a signed, előjeltelenné az unsigned módosítóval tehetünk. A típusok alapértelmezés szerint általában előjelesek.
C típus méret(bájt) alsó határ felső határ _______________________________________________________ char 1 ? ? signed char 1 -128 127 unsigned char 1 0 255 short int 2 -32768 32767 unsigned short int 2 0 65535 int 4 -2147483648 2147483647 unsigned int 4 0 4294967295 long int 4 -2147483648 2147483647 unsigned long int 4 0 4294967295 long long 8 -263 263-1 float 4 -+3.4028234663852886E+38 double 8 -+1.7976931348623157E+308 long double 8 -+1.7976931348623157E+308
Túlcsordulás: Ha egy művelet eredménye túlhalad valamelyik irányban az azt eltárolni próbáló változó értékkészletén, akkor túlcsordulásról beszélünk. (Ha lefelé halad túl, szoktuk alulcsordulásnak is hívni.) Ilyenkor a "számláló körbefordul", tehát ha pl. egy unsigned char változóhoz, aminek az értéke 250 hozzáadunk 10-et, a változó értéke 4 lesz. ( Mivel a char típus mérete 1 byte = 8 bit. 250 + 10 = 260 bit. 5 bit a túlcsordulás. )
F: Hány bájton tárolódik a char/int/float/double típus?
==============================================================================
#include <stdio.h>
int main() {
printf("char: %d\n", sizeof(char));
printf("int: %d\n", sizeof(int));
printf("float: %d\n", sizeof(float));
printf("double: %d\n", sizeof(double));
return 0;
}
Feladat:: Próbáljuk ki a többi típusra is, hogy melyik hány bájton tárolódik.
F: Írasd ki a 64 és 95 közé eső kódú karaktereket.
==============================================================================
#include <stdio.h>
int main() {
char c;
for(c=64; c<96; c++) {
printf(" %c", c);
}
putchar('\n');
return 0;
}
Feladat: Alakítsd át az előző példát: írasd ki az 'a' és 'z' közé eső karakterek kódjait.
F: Mi a különbség a signed char és az unsigned char értékkészlete között?
Írasd ki -128-tól 255-ig egy signed és egy unsigned char típusú változó
számértékét!
==============================================================================
#include <stdio.h>
int main() {
int i;
signed char sc;
unsigned char uc;
for(i=-128; i<=255; i++) {
sc=i;
uc=i;
printf("%d %d\n", sc, uc);
}
return 0;
}
Feladat: Számoljuk meg egy karaktertömbben, hogy hány féle különböző karaktert tartalmaz.
Megoldás letöltése: kulonbozoKarakterek.c, illetve online verziója:
#include <stdio.h>
int main() {
char c;
int i=0, ossz = 0;
char tomb[7] = {'p','a','r','a','f','a', 0};
for(c='a'; c<='z'; c++) { // a-tol z-ig vegig iteralunk
i=0; // mindig visszaallitjuk az i erteket 0-ra,
// hogy amikor a kovetkezo beture lepunk az ABC-ben, mindig a tomb elejetol kezdje el ismet keresni
while(tomb[i] != 0){ // 0 jelig megyunk
if (tomb[i] == c){ // ha benne van a karakter
ossz++; // noveljuk az ossz-ta
break; // es kiugrunk a ciklusbol, mert nem akarjuk a tobbi egyezest is nezni ugyanarra a beture
}
i++; // VEGTELEN CIKLUS ELLEN lepegetnuk vegig egyessevel
}
}
printf("Kulonbozo karakterek szama: %d\n", ossz);
return 0;
}
F: Mi a különbség a float és a double pontossága között? Add hozzá az 1, 0.1,
0.01, 0.001, ... sorozat elemeit egy-egy float és double változóhoz. Milyen
értékeket kapsz lépésenként?
==============================================================================
#include <stdio.h>
int main() {
int i;
float f = 0.0, df = 1.0;
double d = 0.0, dd = 1.0;
for(i=0; i<20; i++) {
f += df;
d += dd;
df *= 0.1;
dd *= 0.1;
printf("%d: float: %22.20f; double: %22.20lf\n", i + 1, f, d);
}
return 0;
}
F: Deklarálj egy egész, egy valós és egy karakter változót. Mindhármat írasd
ki mindhárom formában! Figyeld meg a fordítási warningokat!
Warning-ok kiíratása -Wall kapcsolóval történik. pl. "gcc -Wall -o prog prog.c"
==============================================================================
#include <stdio.h>
void main(){
int a = 65;
float b = 65.5555;
char c = 'A';
// Egész egészként és karakterként
printf("%d\n",a);
printf("%c\n\n",a); // az ASCII tábla szerint a 65. karakter az 'A'
// Valós valósként és egészként
printf("%f\n",b);
printf("%d\n\n",b); // egészként kiíratva egy valós számot nem épp a helyes eredményt kapjuk meg
// Karakter karakterként és egészként
printf("%c\n",c);
printf("%d\n",c); // az ASCII tábla szerint ismét csak az 'A' karakterkódja 65
}
Nézzünk néhány érdekesebb példát:
(a) Írjunk egy ciklust, amely végig ellenőrzi egy bemenetként kapott n szám esetén, hogy 1-től 1000-ig mely számok oszthatóak n^2+n+1-gyel.
(b) Keressük meg egy tömb legnagyobb/legkisebb elemét.
(c) Írjunk egy függvényt, melynek legyen 4 egész értékű bemeneti paramétere. Az 1. legyen egy 1D int tömb. A 2. a tömb mérete. A 3. és a 4. egy-egy adott egész érték. A 3. parameterkent megadott erteku tomb elemet irjuk felul a 4. parameterkent megadott ertekkel.
(d) A (c) feladat módosítása úgy, hogy a 3. paraméterben megadott indexszű elemet cseréljük ki, a 4. paraméterben megadott indexszű elem értékével. Tehát a 3. elemet a 4.-re, a 4.-et pedig a 3.-ra.
(e) Hozzunk létre egy integer 2D tömböt és töltsük fel a szorzótábla értékeivel.
(f) Hozzunk létre egy karakter tömböt. Töltsük fel tetszőlegesen és írassuk ki 2 különböző módon. Ellenőrizzük le a hosszát is 2 különböző módon. Toljuk el egyesével az összes karakter értékét 1-gyel.
Megoldás letöltése: gyak05.c, illetve online verziója:
#include <stdio.h>
/**
Integer tomb kiiratasa
*/
void kiirIntegerTomb(int tomb[], int meret){
int i;
for (i=0; i<meret; i++){
printf("%4d", tomb[i]);
}
printf("\n");
}
/**
Char tomb kiiratasa
*/
void kiirCharTomb(char tomb[]){
int i = 0;
while (tomb[i] != 0){
printf("%c", tomb[i]);
i++; // INDEXVALTOZO NOVELESE, HOGY NE LEGYEN VEGTELEN CIKLUS
}
printf("\n");
// * * * (!) Egy karaktertomb kiiratasara termeszetesen egy %s-sel megadott printf is tökéletesen elegendo
// Csupan ZH-ban surun lesz, hogy egy megadott karakterig kell menni
}
/**
(a) Írjunk egy ciklust, amely végig ellenorzi egy bemenetként kapott n szám esetén, hogy 1-tol 1000-ig mely számok oszthatóak n^2+n+1-gyel
*/
int fgvA(int n){
int i;
for (i=1;i<1000;i++){ // vegig iteralunk 1-tol 1000-ig
if (i%(n*n+n+1) == 0) { // mindig az aktualis elemet elosszuk a megadott kifejezessel es vesszuk a maradekot
// amennyiben a maradek 0, akkor oszthatoak
printf("%4d\n", i);
}
}
return 0; // mivel nem volt megadva, hogy mi legyen a visszateresi ertek, ezert 0-t adunk vissza
}
/**
(b) Keressük meg egy tömb legnagyobb/legkisebb elemét. Ez az elem legyen a fuggveny visszateresi erteke.
(Itt most epp legkisebb. Legnagyobb eseten csak meg kellene forditani a relacios jelet az if soraban.)
*/
int fgvB(int tomb[], int meret){
int min, i;
min = tomb[0]; // kimentjuk a tomb elso (0.) elemet
for (i=1;i<meret;i++){ // vegig iteralunk rajta (A 0. elemet mar kivettuk, szoval az 1.-tol megyunk tovabb, egeszen a vegeig)
if (tomb[i] < min){ // amennyiben a tomb i-edik (azaz az aktualis) eleme kisebb, mint a min erteke
min = tomb[i]; // akkor felulirjuk a min-t vele
}
}
return min; // a legkisebb elem a visszateresi ertek
}
/**
(c) Írjunk egy függvényt, melynek legyen 4 egész értéku bemeneti paramétere.
Az 1. legyen egy 1D int tömb. A 2. a tömb mérete. A 3. és a 4. egy-egy adott egész érték.
A 3. parameterkent megadott erteku tomb elemet irjuk felul a 4. parameterkent megadott ertekkel.
*/
void fgvC(int tomb[], int meret, int a, int b){
int i; // index valtozo
kiirIntegerTomb(tomb, meret); // tomb aktualis allapotanak kiiratasa
for (i=0; i<meret; i++){ // vegig iteralunk a tombunkon (0. elemtol a legutolsoig)
if (tomb[i] == a){ // ha a tomb i-edik (azaz az aktualis) eleme egyenlo a 3. parameter ertekevel
tomb[i] = b; // akkor kicsereljuk a 4. perameter ertekere
}
}
kiirIntegerTomb(tomb, meret); // tomb aktualis allapotnak kiiratasa, hogy lassuk a valtozasokat
}
/**
(d) A (c) feladat módosítása úgy, hogy a 3. paraméterben megadott indexszu elemet cseréljük ki, a 4. paraméterben megadott indexszu elemmel.
Tehát a 3. elemet a 4.-re, a 4.-et pedig a 3.-ra.
*/
void fgvD(int tomb[], int meret, int a, int b){
int tmp; // segedvaltozo a cserehez
kiirIntegerTomb(tomb, meret);
if (a >= 0 && a < meret && b >= 0 && b < meret && a != b){
tmp = t[a];
t[a] = t[b];
t[b] = tmp;
kiirIntegerTomb(tomb, meret);
}
}
/**
(e) Hozzunk létre egy integer 2D tömböt és töltsük fel a szorzótábla értékeivel.
*/
int fgvE(int tomb[][10]) { // egy 2D tomb parameterkent valo megadasakor meg kell adni a meretet is legalabb a masodik tomb zarojelben
int i,j; // index valtozok
for (i=0;i<10;i++){ // az i fogja jelolni, hogy hanyadik sorban jarunk
for (j=0;j<10;j++){ // a j fogja jelolni, hogy hanyadik oszlopban jarunk
tomb[i][j]=(i+1)*(j+1); // a tomb [i][j]-edik (azaz az aktualis) elemet felul irjuk.
// i*j lenne normal korulmenyek kozott, viszont mivel 0-tol indul az indexszeles,
// ezert az i es a j erteket is szorzas elott megnoveljuk 1-gyel, hogy ne 0*0-val,
// hanem 1*1-gyel kezdjuk a tablat.
printf("%4d", tomb[i][j]); // kiiratas
}
printf("\n"); // ujsor irasa minden egyes sornak a feldolgozasa utan. Ez csak a tablazatos megjelenites miatt kell.
// a tomb feldolgozasan es feltoltesen nem valtoztat
}
return 0; // mivel nem volt megadva, hogy mi legyen a visszateresi ertek, ezert 0-t adunk vissza
}
/**
(f) Ellenorizzuk le egy karaktertomb hosszat. Toljuk el az osszes karaktert 1-gyel. A fuggveny a tomb meretevel terjen vissza.
*/
int fgvF(char tomb[]){
int i = 0, meret = 0; // indexvaltozo es a meret tarolasara hasznalt valtozo letrehozasa. Nagyon fontos a 0 kezdoertek!!
while (tomb[i] != 0){ // egesz addig haladunk vegig a tombon, amig meg nem latjuk a 0 jelet, ami a veget jelzi.
meret++; // noveljuk a meret valtozot, amig nem latjuk a 0 jelet
i++; // INDEXVALTOZO NOVELESE, HOGY NE LEGYEN VEGTELEN CIKLUS
}
kiirCharTomb(tomb);
for (i=0;i<meret;i++){ // vegig iteralunk a tombon. Most felhasznaljuk a meret valtozot, de itt is megtehetnenk, hogy 0 jelig megyunk
tomb[i] = tomb[i] + 1; // minden karakterhez adjunk hozza 1-et.
}
kiirCharTomb(tomb);
return meret; // visszateresi ertek
}
int main(){
int t1[10] = {5,3,12,7,4,89,1,8,9,45}, // 1D int tomb
t2[10][10], // 2D int tomb
m = 10; // meret valtozo
char t3[8] = {'b','e','l','a','f','u','t', 0}; // 1D char tomb
/** Pelda a fuggvenyek hivasara */
// fgvA(20);
// printf("%d\n",fgvB(t1,m));
// fgvC(t1,m,3,100);
// fgvD(t1,m,2,5);
// fgvE(t2);
// fgvF(t3);
return 0;
}
Egy kis programozás fun otthonra
Írjunk egy bombakereső játékot. A játékot a számítógép ellen játszuk. A számítógép induláskor feltölt egy 10*10-es tömböt random 0-kal és 1-esekkel, úgyh pl. 10 darab 1-es legyen a táblán, a többi mind 0. Az 1-esek szimbolizálják a bombákat. A játék kezdésekor a játékos úgyszint kitölt egy ugyanekkora táblát a saját elképzelése szerint, úgy, hogy megadja, hogy melyik pozícióra kerüljönek a bombái: [i,j]. Miután a random generátor feltöltötte az ellenfél tábláját, illetve a játékos is feltöltötte a sajátját, megkezdődhet a játék. Ezután felváltva találgathat a két játékos, hogy szerintük hol lehet bomba az ellenfél tábláján. Az nyer, aki előbb megtalálja az ellenfél összes bombáját. A játék végén írjuk ki, hogy ki nyerte a játszmát.
Egy kis segítség: nyugodtan töltsük fel mindkét táblát kezdetben 0-kal, majd ahova érkezik 1-es, ott csak írjuk felül. A számítógép táblájának feltöltésére egy lehetséges megoldás, hogy két számot generáltatunk: az egyik lesz az oszlop indexe, a másik pedig a sornak az indexe. Így jön ki pl., hogy hova kerüljön 1-es. Bevezethetünk két segéd változót, amely azt figyeli, hogy ki hány bombát talált eddig. Ha valamelyik változó értéke eléri a 10-et, meg van az összes bomba, a játék véget ér.
Ügyeljünk oda, hogy: Kétszer ugyanoda tippelve, ne szerezzen egyik játékos sem mégegyszer pontot. Legyegyszerűbb, ha egy találat esetén egyből felülírjuk 0-val az adott pozíciót az adott tömbben. Ellenőrizzük, a játékos által megadott pozíciókra, hogy a 10*10-es tömbön belül vannak-e.
A kódot kommentezzük is úgy, hogy ha más valaki olvassa az is megértse! (Melyik változó / elágazás / ciklus / függvény /.. mire való.)
A feladat megoldását/próbálgatását erősen ajánlom mindenkinek. Sok mindenre rá lehet jönni ilyenkor. Próbáljunk meg a körülményekhez mérten felhasználóbarát programot készíteni!
Jövő héten 3. ZH (2018.10.08.)
6. gyakorlat
Típus definiálás
A típus definiálás általános alakja:
typedef típus név
Feladat: Hogyan tudunk létrehozni egy olyan vector nevű tömb típust, amely egy háromdimenziós térbeli vektort reprezentál?
typedef double vector[3];
Feladat: Hogyan lehet létrehozni egy N hosszúságú sztringek tárolására szolgáló karaktertömb típust?
typedef char string[N+1];
Feladat: Hozz létre külön típust 16 bites nemnegatív értékek tárolására.
typedef unsigned short int u16;
Struktúrák
C nyelven a struktúra (struct) típus több tetszőleges típusú objektum együttese (kivéve a void és a függvény típust). Ezek az objektumok önálló, a struktúrán belül érvényes nevekkel rendelkeznek.
A struktúra szerkezetét meghatározó deklaráció általános formája:
struct struktúra_azonosító { típus1 tag1; típus2 tag2; ... típusN tagN; };
A fenti típussal változót az alábbi módon készíthetünk:
struct struktúra_azonosító struktúra_változó;
Az attributumokra a pont operátorral tudunk hivatkozni:
struktúra_változó.tag1
Példa: Könyvtárkezelő program készítése során jól alkalmazható az alábbi adatstruktúra:
struct book { char szerzo[20]; char cim[40]; int ev; int ar; };
Változók létrehozása:
struct book macska, gyerek, cprog;
Attribútumokra való hivatkozás:
macska.ev = 1992;
Elég gyakran alkalmazott megoldás a typedef kulcsszóra épül:
typedef struct { char szerzo[20]; char cim[40]; int ev; int ar; } BOOK;
Változók létrehozása:
BOOK macska, gyerek, cprog;
Egyszerűbb példa egy személy megvalósítására:
// !
#include <stdio.h>
// ember struktúra típus 3 attribútummal
struct ember {
char nev[20];
int igszam;
int kor;
};
// kiíratás - a bemeneti paraméter egy darab ember struktúra típusú változó
void szemelykiiras(struct ember szemely){
printf(" Nev: %s\n", szemely.nev);
printf("Ig.szam: %d\n", szemely.igszam);
printf(" Kor: %d\n", szemely.kor);
}
int main (){
// személy létrehozása a létrehozott struktúra típus alapján
struct ember BelaVagyok;
// szémélyhez tartozó attribútumok feltöltése
scanf("%s",BelaVagyok.nev);
scanf("%d",&BelaVagyok.igszam);
scanf("%d",&BelaVagyok.kor);
// személy adatainak kiírása függvény segítségével
szemelykiiras(BelaVagyok); // az előbb létrehozott paraméter kerül átadásra
return 0;
}
Ugyanez typedef-el:
// !
#include <stdio.h>
// ember struktúra típus 3 attribútummal
typedef struct {
char nev[20];
int igszam;
int kor;
} ember;
// kiíratás - a bemeneti paraméter egy darab ember struktúra típusú változó
void szemelykiiras(ember szemely){
printf(" Nev: %s\n", szemely.nev);
printf("Ig.szam: %d\n", szemely.igszam);
printf(" Kor: %d\n", szemely.kor);
}
int main (){
// személy létrehozása a létrehozott struktúra típus alapján
ember BelaVagyok;
// szémélyhez tartozó attribútumok feltöltése
scanf("%s",BelaVagyok.nev);
scanf("%d",&BelaVagyok.igszam);
scanf("%d",&BelaVagyok.kor);
// személy adatainak kiírása függvény segítségével
szemelykiiras(BelaVagyok); // az előbb létrehozott paraméter kerül átadásra
return 0;
}
Lehetőségünk van struktúrák egymásba ágyazására, tehát egy adott struktúrán belül, lehet struktúra típusú attribútum. Amennyiben ilyen struktúra attribútumokra szeretnénk hivatkozni, nincs szükség további egymás utáni felsorolásra, elegendő ugyanúgy hivatkozni rájuk, mint a többi, nem beágyazott attributumra. Ezért is nevezzük őket anoním struktúráknak.
#include <stdio.h>
// ember struktúra típus 3 attribútummal
typedef struct {
struct { // egymásba ágyazhatóság
char vnev[20];
char knev[20];
} nev;
int igszam;
int kor;
} ember;
// kiíratás - a bemeneti paraméter egy darab ember struktúra típusú változó
void szemelykiiras(ember szemely){
printf("\nA szemely adatai:\n");
printf(" Nev: %s %s\n", szemely.nev.vnev, szemely.nev.knev);
printf("Ig.szam: %d\n", szemely.igszam);
printf(" Kor: %d\n", szemely.kor);
}
int main (){
// személy létrehozása a létrehozott struktúra típus alapján
ember BelaVagyok;
// szémélyhez tartozó attribútumok feltöltése
scanf("%s",BelaVagyok.nev.vnev);
scanf("%s",BelaVagyok.nev.knev);
scanf("%d",&BelaVagyok.igszam);
scanf("%d",&BelaVagyok.kor);
// személy adatainak kiírása függvény segítségével
szemelykiiras(BelaVagyok); // az előbb létrehozott paraméter kerül átadásra
return 0;
}
Únió
Ismerkedjünk meg a union típussal. Igazából nincs sok dolgunk, mivel a struct típussal kapcsolatban ismertetett formai megoldások a union típusra is alkalmazhatóak.
Egyetlen és egyben lényegi különbség az adattagok elhelyezkedése között van. Míg a struktúra adattagjai a memóriában egymás után helyezkednek el, addig az únió adattagjai közös címen kezdődnek (átlapoltak).
short a; int b; long long c; Memóriafoglalás: STRUCT UNION _______ _ | | | | | | long long c | | | _______ _ |_______| _| | | | | | | int b |_______| _ | long long c |_______| _| |_______| _ | int b | |_______| _| short a |_______| _| short a _| _|
A union szerkezetét meghatározó deklaráció általános formája:
union union_azonosító { típus1 tag1; típus2 tag2; ... típusN tagN; };
A fenti típussal változót az alábbi módon készíthetünk:
union union_azonosító union_változó;
F: Mi a különbség a struct és a union között? Deklarálj egy struct és egy
union típust ugyanolyan mezőkkel. Adj értéket a mezőknek, majd írasd ki
őket!
Válasz: Jelenleg semmi különbség nem lesz látható a struct és a union között,
mivel egyszerre csak egy attribútumnak adunk értéket, illetve használunk.
==============================================================================
#include <stdio.h>
typedef struct {int i; double d; char c; float f;} st;
typedef union {int i; double d; char c; float f;} un;
int main()
{
st s;
un u;
s.i = u.i = 12345;
printf("s.i: %d u.i: %d\n", s.i, u.i);
s.d = u.d = 3.141593;
printf("s.d: %lf u.d: %lf\n", s.d, u.d);
s.c = u.c = 'A';
printf("s.c: %c u.c: %c\n", s.c, u.c);
s.f = u.f = 2.718281;
printf("s.f: %f u.f: %f\n", s.f, u.f);
return 0;
}
// !
Tehát az előzőekben nem látszott semmi. De mi van, ha egyszerre íratjuk ki a mezők értékeit?
Válasz: Mivel azt mondtuk, hogy a union adattagjai közös címen kezdődnek,
ezért ha mindnek értéket adunk, majd használni próbáljuk őket,
akkor is csak az utoljára értéket kapott attribútum értékét tudjuk felhasználni.
==============================================================================
#include <stdio.h>
typedef struct {int i; double d; char c; float f;} st;
typedef union {int i; double d; char c; float f;} un;
int main()
{
st s;
un u;
s.i = u.i = 12345;
s.d = u.d = 3.141593;
s.c = u.c = 'A';
s.f = u.f = 2.718281;
printf("s.i: %d u.i: %d\n", s.i, u.i);
printf("s.d: %lf u.d: %lf\n", s.d, u.d);
printf("s.c: %c u.c: %c\n", s.c, u.c);
printf("s.f: %f u.f: %f\n", s.f, u.f);
return 0;
}
// !
F: Írasd ki a mezők kezdőcímét! Az előző jelenség így még egyértelműbb lesz.
==============================================================================
== BEGIN union.c =============================================================
#include <stdio.h>
typedef struct {int i; double d; char c; float f;} st;
typedef union {int i; double d; char c; float f;} un;
int main()
{
st s;
un u;
printf("s.i: %p u.i: %p\n", &s.i, &u.i);
printf("s.d: %p u.d: %p\n", &s.d, &u.d);
printf("s.c: %p u.c: %p\n", &s.c, &u.c);
printf("s.f: %p u.f: %p\n", &s.f, &u.f);
return 0;
}
Feladatok:
1.) Írj egy programot ami három oldalhosszból kiszámítja egy háromszög kerületét és területét! A számítást egyetlen függvény végezze, a főprogram csak a bemenet-kimenetért feleljen. A terület és kerület tárolására hozz létre egy struct adattípust, a számítást végző függvény egy ilyen típusú értékkel térjen vissza.
#include <stdio.h>
#include <math.h>
// kerulet-terulet struktura típus letrehozasa
typedef struct {
float ker;
float ter;
} hszog;
// fuggveny a kerulet es terulet szamitasahoz
hszog KT(float a, float b, float c){
hszog kt; // kerulet-terulet struktura egyed letrehozasa
kt.ker = a+b+c; // kerulet szamitas
float s = kt.ker/2;
kt.ter = sqrt(s*(s-a)*(s-b)*(s-c)); // terulet szamitas
return kt;
}
int main (){
float a, b, c; // oldalhossz valtozok letrehozasa, majd feltoltese
scanf("%f", &a);
scanf("%f", &b);
scanf("%f", &c);
// kerulet es terulet kiiratasa, beepitett fuggvenyhivassal
// mivel a KT fuggveny visszateresi erteke egy struktura,
// ezert hivatkozhatunk az attributumaira a printf vegen lathato modon
printf("A 3szog kerulete: %f\n", KT(a,b,c).ker);
printf("A 3szog terulete: %f\n", KT(a,b,c).ter);
return 0;
}
2.) Írj egy programot ami három kétdimenziós koordináta-párból kiszámítja egy háromszög kerületét és területét! Az érdemi számításokat függvények végezzék, a főprogram csak a bemenet-kimenetért feleljen. A kétdimenziós pont tárolására, valamint a terület és kerület együttes tárolására is hozz létre struct adattípusokat, és a számítást végző függvények ezeket használják (ahol ez lehetséges).
Hint: Az előzőt bővítve, koordinátákból oldalhosszt számolni, utána ugyanaz mint az előbb.
#include <stdio.h>
#include <math.h>
// kerulet-terulet struktura típus letrehozasa
typedef struct {
float ker;
float ter;
} hszog;
// pont struktúra típus létrehozása
typedef struct {
float x;
float y;
} pont;
// fuggveny a kerulet es terulet szamitasahoz
hszog KT(float a, float b, float c){
hszog kt; // kerulet-terulet struktura egyed letrehozasa
kt.ker = a+b+c; // kerulet szamitas
float s = kt.ker/2;
kt.ter = sqrt(s*(s-a)*(s-b)*(s-c)); // terulet szamitas
return kt;
}
// két pont közti távolság koordinátageometriában
float tavolsag(pont p1, pont p2){
return sqrt(((p2.x-p1.x)*(p2.x-p1.x))+((p2.y-p1.y)*(p2.y-p1.y)));
}
int main (){
float a, b, c; // oldalhossz valtozok letrehozasa
pont A, B, C; // pont struktúra változók létrehozása és feltöltése
scanf("%f %f", &A.x, &A.y);
scanf("%f %f", &B.x, &B.y);
scanf("%f %f", &C.x, &C.y);
// a pontok közti távolságok kiszámítása, hogy megkapjuk az oldalhosszakat
a = tavolsag(A,B);
b = tavolsag(B,C);
c = tavolsag(C,A);
// kerulet es terulet kiiratasa, beepitett fuggvenyhivassal
// mivel a KT fuggveny visszateresi erteke egy struktura,
// ezert hivatkozhatunk az attributumaira a printf vegen lathato modon
printf("A 3szog kerulete: %f\n", KT(a,b,c).ker);
printf("A 3szog terulete: %f\n", KT(a,b,c).ter);
return 0;
}
3.) Írj egy programot, ami a bemeneti szöveget kiírja a kimenetre, de közben törli belőle a számjegy karaktereket, és a végén kiírja, hogy mennyi számjegyet törölt.
#include <stdio.h>
int main (){
char t[100] = "Emlekszem az 1. talalkozasunkra, pedig ma mar a 10. hazassagi evfordulonkat unnepeljuk.";
int i = 0, count = 0;
while (t[i] != 0){
if (t[i] < '0' || t[i] > '9'){
printf("%c", t[i]);
} else {
count++;
}
i++;
}
printf("\nA torolt szamjegyek szama: %d\n", count);
return 0;
}
4.) Hibajavítás: Fordítsuk le az alábbi kódot és javítsuk ki a hibaüzeneteket felhasználva. (Ha alaki terminálból fordít, akkor miután egy hiba sem maradt, fordítsuk le a -Wall kapcsolót használva is és folytassuk a javítást. pl.: "gcc -Wall -o prog prog.c")
#include <stdio.h>
typedef struct pont {
double x;
double y;
double z;
} pont_t;
int Main(int argc, char *argv[]) {
pont_t P[4];
double t[4];
double felszin;
if (argc < 5) {
fprintf(stderr, "Használat: %c '(x1,y1,z1)' '(x2,y2,z2)' '(x3,y3,z3)' '(x4,y4,z4)'\n", argv[0]);
return 1;
}
for (i = 0; i < 4; ++i) {
P(i) = get_pont(argv[i+1]);
t(i) = 0.0;
}
t[0] = terulet(P[1], P[2], P[3]);
t[1] = terulet(P[0], P[2], P[3]);
t[2] = terulet(P[0], P[1], P[3]);
t[3] = terulet(P[0], P[1], P[2]);
for (i = 0; i < 4; ++i) {
if (t[i] = 0.0)
printf("A megadott pontok egy síkba esnek.\n");
return 1;
}
}
for (i = 0; i < 4; ++i) {
felszin += t{i};
}
printf("A test felszíne: A = %.3lf\n", felszin);
return 0;
}
pont_t get_pont(const char *str) {
pont_t retval = {0.0, 0.0, 0.0};
sscanf(str, "(%lf,%lf,%lf)", retval.x, retval.y, retval.z);
}
double tavolsag[pont_t P, pont_t Q] {
pont_t d;
d.x = P.x - Q.x;
d.y = P.y - Q.y;
d.z = P.z - Q.z;
return sqrt(d.x * d.x + d.y * d.y + d.z * d.z);
}
double terulet(pont_t A, pont_t B, pont_t C) [
double a, b, c, s;
a = tavolsag(B, C);
b = tavolsag(A, C);
c = tavolsag(A, B);
s = (a + b + c) / 2.0;
return sqrt(s * (s - a) * (s - b) * (s - c));
]
Javított kód:
#include <stdio.h>
#include <math.h>
typedef struct pont {
double x;
double y;
double z;
} pont_t;
pont_t get_pont(const char *str) {
pont_t retval = {0.0, 0.0, 0.0};
sscanf(str, "(%lf,%lf,%lf)", &retval.x, &retval.y, &retval.z);
return retval;
}
double tavolsag(pont_t P, pont_t Q) {
pont_t d;
d.x = P.x - Q.x;
d.y = P.y - Q.y;
d.z = P.z - Q.z;
return sqrt(d.x * d.x + d.y * d.y + d.z * d.z);
}
double terulet(pont_t A, pont_t B, pont_t C) {
double a, b, c, s;
a = tavolsag(B, C);
b = tavolsag(A, C);
c = tavolsag(A, B);
s = (a + b + c) / 2.0;
return sqrt(s * (s - a) * (s - b) * (s - c));
}
int main(int argc, char *argv[]) {
pont_t P[4];
double t[4];
double felszin;
int i;
if (argc < 5) {
fprintf(stderr, "Használat: %s '(x1,y1,z1)' '(x2,y2,z2)' '(x3,y3,z3)' '(x4,y4,z4)'\n", argv[0]);
return 1;
}
for (i = 0; i < 4; ++i) {
P[i] = get_pont(argv[i+1]);
t[i] = 0.0;
}
t[0] = terulet(P[1], P[2], P[3]);
t[1] = terulet(P[0], P[2], P[3]);
t[2] = terulet(P[0], P[1], P[3]);
t[3] = terulet(P[0], P[1], P[2]);
for (i = 0; i < 4; ++i) {
if (t[i] == 0.0){
printf("A megadott pontok egy síkba esnek.\n");
return 1;
}
}
for (i = 0; i < 4; ++i) {
felszin += t[i];
}
printf("A test felszíne: A = %.3lf\n", felszin);
return 0;
}
Jövő héten 4. ZH (2018.10.15.)
7. gyakorlat
Input/Output műveletek FILE-ból/ba
F: Írj egy programot, ami beolvas két egész számot, majd kiírja az összegüket
és a szorzatukat.
==============================================================================
#include <stdio.h>
int main() {
int a, b;
scanf("%d %d", &a, &b);
printf("Osszeg: %d\nSzorzat: %d\n", a + b, a * b);
return 0;
}
F: Módosítsuk úgy a programot, hogy használja az stdin, stdout, fscanf és
fprintf függvényeket.
==============================================================================
#include <stdio.h>
int main() {
int a, b;
fscanf(stdin, "%d %d", &a, &b);
fprintf(stdout, "Osszeg: %d\nSzorzat: %d\n", a + b, a * b);
return 0;
}
/*
látható, hogyha elhagynánk az fscanf és az fprintf elejéről az f betűket,
valamint a zárójelekből az stdin és stdout függvényeket,
az előző feladattal ekvivalens megvalósítást kapnánk
*/
A fájlok adatfolyamként történő kezelése során egy FILE * típusú ún. filemutató azonosítja az állományt. (Ezt az állományt az STDIO.H file deklarálja.)
FILE *nev;
Ahhoz, hogy a háttértáron levő file tartalmához hozzáférjünk, a file-t meg kell nyitnunk. A file megnyitását a fopen függvény hívásával végezhetjük el, melynek prototípusa:
FILE * fopen(const char * filename, const char *mode);
avagy meglévő FILE * esetén
FILE * vmi;
vmi = fopen(const char * filename, const char *mode);
A filename helyére a beolvasandó file neve kerül, tehát egy sztring. (pl.: "be.txt")
A mode úgyszint egy sztring, amely a file elérését és típusát határozza meg. (pl.: "r")
A lehetséges elérési módok:
"r" - Létező file megnyitása olvasásra. "w" - Új file megnyitása írásra. Ha file már létezik, akkor a tartalma elvész. "a" - File megnyitása hozzáírásra. A nyitás után a file végén lesz az aktuális file-pozíció. Ha a file nem létezik, akkor az fopen létrehozza azt. "r+" - Létező file megnyitása írásra és olvasásra (update). "w+" - Új file megnyitása írásra és olvasásra (update). Ha a file már létezik, akkor a tartalma elvész. "a+" - File megnyitása a file végén végzett írásra és olvasásra (update). Ha a file nem létezik, akkor az fopen létrehozza azt.
Amikor többé nincs szükségünk a megnyitott file(ok)-ra, akkor kell használnunk az fclose hívást, amely lezárja a file-t.
fclose(vmi);
F: Módosítsuk úgy az előző programot, hogy valódi fájlokat használjon.
==============================================================================
#include <stdio.h>
int main() {
int a, b;
FILE *infile; // beolvasáshoz filemutató
FILE *outfile; // kiíratáshoz filemutató
infile = fopen("be.txt", "r"); // bementi fájl olvasásra
outfile = fopen("ki.txt", "w"); // kimeneti fájl írásra
fscanf(infile, "%d %d", &a, &b); // a megadott bementi fájlból (be.txt) beolvasunk 2 egész számot
fprintf(outfile, "Osszeg: %d\nSzorzat: %d\n", a + b, a * b); // majd a megadott kimeneti fájlba (ki.txt) kiírjuk a beolvasott 2 egész számot
fclose(infile); // bemeneti fájl lezárása
fclose(outfile); // kimeneti fájl lezárása
return 0;
}
be.txt :
3 4
ki.txt :
Osszeg: 7 Szorzat: 12
A be.txt-nek léteznie kell, viszont a ki.txt-t a program létrehozza magától, amennyiben nem volt ellőállítva.
Ha a megadott állományt nem sikerült megnyitni, vagy ha a FILE struktúrának nem sikerült helyet foglalni a memóriában, NULL lesz a függvényérték.
F: Hibakóddal lépjen ki a program, ha valamelyik fájl megnyitása nem sikerült.
==============================================================================
#include <stdio.h>
int main() {
int a, b;
FILE *infile;
FILE *outfile;
/*
ha nem sikerült megnyitni a fájlt, akkor NULL-t kapunk, ami HAMIS értéknek számít,
!NULL ebből adódóan IGAZ érték lesz,
tehát teljesül az IF feltétele és 1-es értékkel tér vissza a program
*/
if(!(infile = fopen("be.txt", "r"))) {
return 1;
}
if(!(outfile = fopen("ki.txt", "w"))) {
fclose(infile);
return 1;
}
fscanf(infile, "%d %d", &a, &b);
fprintf(outfile, "Osszeg: %d\nSzorzat: %d\n", a + b, a * b);
fclose(infile);
fclose(outfile);
return 0;
}
1. Feladat: Írj egy programot, ami bekéri egy torta piskótájanak sugarát és magasságát, majd kiszámolja a torta térfogatát
*Algoritmustervezés/Megvalósítás*: A főprogram csak az input/output műveleteket végezze, a számolást külön függvény(ek)ben oldd meg. A program a "be.txt" nevű fájlból olvassa be az adatokat és a "ki.txt" nevű fájlba írja ki az eredményt.
Egy lehetséges megoldás letöltése: fileIO_henger.c, illetve online verziója:
#include<stdio.h>
#include<math.h> // Matematikai konyvtar: innen jon a pi: M_PI (3.14159265358979323846)
void torta(){
float r, h; // sugar es magassag segedvaltozok letrehozasa
// Fajlok letrehozasa
FILE *be, *ki;
// fajlok megnyitasa
be = fopen("be.txt", "r");
ki = fopen("ki.txt", "w");
fscanf(be, "%f %f", &r, &h); // bemetrol valo olvasa
fprintf(ki, "%f\n", r*r*M_PI*h); // kimenetre valo iras: Henger terfogat keplete.
// fajlok lezarasa
fclose(be);
fclose(ki);
}
int main(){
/** Fuggveny hivasara pelda **/
torta();
return 0;
}
Rekurzió
Rekurziónak nevezzük, amikor egy függvény önmagát hívja, egy bizonyos feltétel teljesüléséig. Sokkal elegánsabb megoldást kapunk és csökkenti a redundanciát a kódunkban. Használata akkor ajánlott, ha egy bizonyos függvény hívását egymás után többször végre kell hajtani. Azonban a számítási idő és a memóriaigény jelentős növekedése miatt az esetek többségében mégis az iteratív megoldás ajánlott.
F: n faktoriális kiszámítása rekurzió NÉLKÜL
=============================================================================
#include <stdio.h>
int main(){
int n, i;
long f = 1;
printf("Enter an integer to find factorial: ");
scanf("%d", &n);
for (i=1; i<=n; i++){
f *= i;
}
printf("n! = %d\n", f);
return 0;
}
F: n faktoriális kiszámítása rekurzív módszerrel
=============================================================================
#include <stdio.h>
long factorial(int);
int main(){
int n;
long f;
printf("Enter an integer to find factorial\n");
scanf("%d", &n);
if (n < 0){
printf("Negative integers are not allowed.\n");
} else {
f = factorial(n);
printf("%d! = %ld\n", n, f);
}
return 0;
}
long factorial(int n){
if (n == 0)
return 1;
else
return(n * factorial(n-1));
}
/*
n = 5 esetén
5 * factorial(5-1) =
5 * 4 * factorial(4-1) =
5 * 4 * 3 * factorial(3-1) =
5 * 4 * 3 * 2 * factorial(2-1) =
5 * 4 * 3 * 2 * 1 * factorial(1-1) =
5 * 4 * 3 * 2 * 1 * 1 = 120
*/
Sorozatok
1. Feladat: Egy számtani sorozat első tagja A, differenciája D. Számítsa ki a sorozat N-edik tagját!
Egy sorozatot akkor nevezünk számtani sorozatnak, ha a szomszédos elemek különbsége – differenciája – (a sorozatra jellemző) állandó. Pl. (a1=1, d=1) 1,2,3,4,..., vagy (a1=12, d=15) 12,27,42,57,72... Részletesen lásd: Wikipedia
2. Feladat: Egy mértani sorozat első tagja A, hányadosa Q. Számítsa ki a sorozat N-dik tagját!
Egy sorozatot akkor nevezünk mértani sorozatnak, ha (a másodiktól kezdve) bármelyik tag és az azt megelőző tag hányadosa állandó. Ezt a hányadost idegen szóval kvóciensnek nevezzük. Jele: q. Pl. (a1=3, q=3) 3, 9, 27, 81, ... Részletesen lásd: Wikipedia
Egy lehetséges megoldás letöltése: sorozatok.c
Egyéb feladatok
1. Feladat: Írj programot, mely bekér egy n pozitív egész számot, és megadja az első n természetes szám összegét! Készíts kétféle algoritmust két külön függvényben, és mindkettővel számoltasd ki az eredményt:
- (a) Az első egy mechanikus, ciklust használó algoritmus legyen. (1+2+3+...+N)
- (b) A másik matematikailag átgondolt, minél egyszerűbb algoritmus legyen. ( bővebben ).
Hasonlítsd össze a két megoldás futásidejét! (időmérő futtatáshoz: Windows: "time ./prog"; Linux: "echo 1000 | /usr/bin/time -f %U") Ehhez használj long long int típusú értékeket.
Egy lehetséges megoldás letöltése: nosszeg.c
2. Feladat: Számoljuk ki egy véletlen mátrix sor/oszlop minimumát/maximumát.
// random számok megadásának módja
#include <stdlib.h> // Program elején, a többi include mellett.
#include <time.h> // - // -
srand(time(NULL)); // A main első sora
rand(); // Sorsolás helyén. Ha le akarjuk korlátozni, akkor a rand() után %n-nel kell megadni a felső korlátot. Az alsó automatikusan 0 lesz. Pl. rand() % 2 -> [0,1]
Egy lehetséges megoldás letöltése: matrixoszlopminmax.c
3. Feladat: Határozd meg egy NxM-es véletlen értékű elemekkel feltöltött egész mátrix transzponáltját.
Specifikáció: Az input két egész szám "NxM" alakban, ahol N és M (mindkettő maximum 128) a mátrix sorainak és oszlopainak száma.
Az output .csv formátumú (pontosvesszővel elválasztott) táblázat. Ebbe a bal felső saroktól kezdve kell kiírni a véletlen mátrixot, majd egy sor kihagyásával az első oszloptól kezdve a transzponáltját.
Például "2x3" input esetén:
1;2;3; 4;5;6; ; 1;4; 2;5; 3;6;
Egy lehetséges megoldás letöltése: matrixtranszponalt.c
(!) JÖVŐ HÉTEN (2018.10.22.) A GYAKORLAT ELMARAD! 1956-os Forradalom Ünnepe (hosszú hétvége).
8. gyakorlat
A GYAKORLAT ELMARAD! 1956-os Forradalom Ünnepe (hosszú hétvége)
Jövő héten 5. ZH (2018.10.29.)
9. gyakorlat
Pointerek
Új dinamikus változó létesítése
p=malloc(sizeof(E));
A malloc(S) függvény lefoglal egy S méretű memóriaterületet a program számára. A sizeof(E) megadja, hogy egy E típusú változó mekkora helyet igényel a memóriában. A malloc(sizeof(E)) hatására tehát létrejön egy új E típusú érték tárolására (is) alkalmas változó, és ez a változó lesz a p értéke.
Pointer dereferencia
*p
A * művelet segítségével érhetjük el a p értékét vagyis a dinamikus változót. A *p változóhivatkozás a p értékére, vagyis a dinamikus változóra hivatkozik, tehát a *p értéke a dinamikus változó értéke lesz.
Dinamikus változó törlése
free(p);
A művelet hatására a p-hez tartozó memóriaterület felszabadul ezáltal a dinamikus változó megszűnik. A művelet végrehajtása után a p pointerhez nem tartozik érvényes változó, ezért a *p változóhivatkozás végrehajtása jobb esetben azonnali futási hibát eredményez. (Rosszabb esetben pedig olyan lappangó hibát, aminek az eredménye a program egy teljesen más pontján jelenik meg.)
A címképző művelet
p = &i;
A művelet meghatározza egy változóhoz tartozó memória mező címét. Ha egy p pointer típusú változó értéke az i változóhoz tartozó memória címe, akkor azt mondjuk, hogy a p i-re mutat. Ez a referencia szerinti értékátadás.
Feladat: Futtasd le a cim.c programot, és értelmezd! Melyik érték melyik értékkel egyenlő, és miért?
/* $Id: cim.c 3234 2017-09-21 12:25:20Z gertom $ */
#include <stdio.h>
int main(){
int a = 10;
int *pa;
pa = &a;
printf("a=%d pa=%#x\n", a, (int)pa);
printf("&a=%#x &pa=%#x\n", (int)&a, (int)&pa);
printf("*pa=%d\n", *pa);
return 0;
}
Feladat: Javítsd ki a csere.c program "csere" függvényét (és a hozzá tartozó hívást) úgy, hogy megcserélje a main két változójának értékét.
/* $Id: csere.c 3234 2017-09-21 12:25:20Z gertom $ */
#include <stdio.h>
void csere(int x, int y){
int tmp;
tmp = x;
x = y;
y = tmp;
}
int main(){
int x = 3, y = 5;
printf("A függvény előtt: x = %d, y = %d\n", x, y);
csere(x, y);
printf("A függvény után: x = %d, y = %d\n", x, y);
return 0;
}
Ugyebár ebben a formában a program nem hajtja végre azt, amit szeretnénk, mivel a main-ben illetve a csere függvényben találhato x és y változók teljesen különböző 2-2 változót jelölnek.
#include <stdio.h>
void csere(int *x, int *y){ // az x es y pointert a main-ben letrehozott x es y valtozok cimere allitjuk ezzel
int tmp;
// * segitsegevel a cimen levo erteket erjuk el, majd erjuk felul
tmp = *x;
*x = *y;
*y = tmp;
}
int main(){
int x = 3, y = 5;
printf("A függvény előtt: x = %d, y = %d\n", x, y);
csere(&x, &y); // x es y cimenek atadasa
printf("A függvény után: x = %d, y = %d\n", x, y);
return 0;
}
Feladat: Elemezd és futtasd a pointerek.c programot. Mi a különbség p, q, illetve *p és *q értéke között?
#include <stdio.h>
#include <stdlib.h>
int main()
{
/* Két pointer deklarációja */
int *p, *q;
/* Két int típusú dinamikus változó létrehozása (memóriafoglalás) */
p = malloc(sizeof(int));
q = malloc(sizeof(int));
/* Értékadás a két dinamikus változónak */
*p = 3;
*q = 3;
printf("p és q %s\n", p == q ? "megegyezik" : "nem egyezik meg"); // NEM, mivel különböző mem. címekről van szó
printf("*p == %d, *q == %d\n", *p, *q);
*p = 4; // p által mutatott mem. címen tárolt érték felülírása
printf("*p == %d, *q == %d\n", *p, *q);
free(p); // p által mutatott mem. címen foglalt terület felszabadítása
p = q; // p is mutasson ezentúl oda, ahova a q
printf("p és q %s\n", p == q ? "megegyezik" : "nem egyezik meg"); // IGEN, mivel mostmár ugyannarról a mem. címről beszélünk
printf("*p == %d, *q == %d\n", *p, *q);
*p = 4; // mivel p és q ugyanoda mutat, ezért ha *p-t felül írjuk, akkor *q is ugyanaz lesz
printf("*p == %d, *q == %d\n", *p, *q);
free(q); // q által mutatott mem. címen foglalt terület felszabadítása
return 0;
}
Feladat: Módosítsuk a következő kódot úgy, hogy "értelmes" műveleteket végezzen.
#include <stdlib.h>
int main() {
int *p, *q;
p = malloc(sizeof(int));
free(q);
return 0;
}
Lehetséges módosítások: Írjuk át a free(q) utasításon belül a q változót p-re. Vagy a p mellé allokáljunk a q-nak is memória területet és a végén mind a két pointerhez tartozó memória területet szabadítsuk fel.
Feladat: Írj egy programot, amelyben deklarálj egy 10 elemű int tömböt, majd töltsd fel értékekkel a standard inputról! Írasd ki a tömb elemeit.
#include <stdio.h>
int main(){
int t[10], i;
for (i=0; i<10; i++){
scanf("%d", &t[i]);
}
for (i=0; i<10; i++){
printf("%d ", t[i]);
}
printf("\n");
return 0;
}
Feladat: Az előző programban deklarálj egy int pointert is, és a beolvasást ennek segítségével valósítsd meg!
#include <stdio.h>
int main(){
int t[10], i, *p; // pointer letrehozasa
for (i=0; i<10; i++){
p = &t[i]; // pointer raallitasa a tomb aktualis elemere
scanf("%d", p); // a pointer altal mutatott teruletre olvasunk be, azaz a tomb i-edik elemebe
}
for (i=0; i<10; i++){
printf("%d ", t[i]);
}
printf("\n");
return 0;
}
Feladat: Ezután töröld a tömb deklarációját és az azonosítóját pointerként deklaráld! Az elemszám megadása után, de a tömbelemek bekérése előtt, dinamikusan foglalj helyet a tömb elemei számára (pontosan annyit, amennyi kell)!
#include <stdio.h>
#include <stdlib.h> // malloc miatt kell
int main(){
int *t, // pointer letrehozasa
i, meret;
printf("Add meg, hogy mekkora meretu dinamikus tombot szeretnel letrehozni: ");
scanf("%d", &meret);
t = malloc(meret*sizeof(int)); // allokaljunk meret mennyisegu integer nagysagu memoria teruletet, melyre a t fog mutatni
printf("Olvasd be a tomb elemeinek ertekeit:\n");
for (i=0; i<meret; i++){
scanf("%d", &t[i]);
//scanf("%d", t+i); // ekvivalens az elozo sorral
}
for (i=0; i<meret; i++){
printf("%d ", t[i]);
//printf("%d ", *(t+i)); // ekvivalens az elozo sorral
}
printf("\n");
return 0;
}
Feladat: Vizsgáld meg a tombbejaras.c programot. Mi történik, ha a három konstans (N, M és K) értékét megváltoztatod?
- Vedd N értékét valamivel nagyobbra.
- Vedd M értékét valamivel nagyobbra.
- Vedd K értékét valamivel nagyobbra.
- Vedd K értékét valamivel kisebbre.
Mely esetekben hogyan viselkedik a program a futás során? Mi az oka a tapasztalt viselkedésnek?
/* $Id: tombbejaras.c 3234 2017-09-21 12:25:20Z gertom $ */
#include <stdio.h>
#define N 42
#define M 7
#define K 294 // 42*7
int main(){
int tomb[N][M];
int i = 0, j = 0, *p = NULL, *t = NULL; // a p és a t is ponterek, egyelore nem mutatnak sehova (ezert NULL)
p = t = (int*)tomb; // a p es a t is a tomb-re (a tomb kezdocimere) fognak mutatni
while (p < t + K) { // addig megy a ciklus, amig a p az utolso elem cimet meg nem haladja
*(p++) = i++; // a p altal mutatott teruletre beirjuk az i aktualis erteket, majd mind a ketto erteket noveljuk eggyel
}
for (i = 0; i < N; ++i) {
for (j = 0; j < M; ++j) {
printf(" %5d", tomb[i][j]);
}
putchar('\n');
}
return 0;
}
Fun feladat
Készíts egy programot, amely bekér egy magasságot illetve egy karaktert, majd kirajzol egy ilyen magas piramist, az így megadott karakterből.
Példa:
Add meg, hogy milyen magas legyen a piramis: 5 Add meg milyen karakterbol epuljon fel a piramis: A A AAA AAAAA AAAAAAA AAAAAAAAA
Egy lehetséges megoldás: piramis.c
További gyakorló feladatok otthonra:
1.) SZERK.: Írj függvényt, ami egy tömböt és a tömbben lévő elemek számát várja paraméterül, visszatérési érték nincs. Bekérünk a felhasználótól egy pozíciót és egy értéket, és elhelyezi az értéket az adott pozíción a tömbben. Ezt a műveletet tetszőleges mennyiségszer megismételheti a felhasználó a függvényen belül. A függvényt a main függvényen belül hívd meg, miután feltöltötted a tömböt tetszésed szerint (A tömb mérete mindenéppen nagyobb kell, hogy legyen a híváskor benne lévő elemek számánál, hogy tudjunk még új elemeket beszúrni). Példa: input: tömb: [2, 5, 7, 45] pozíció: 2 érték: 1000 output: tömb: [2, 5, 1000, 7, 45] input: tömb: [2, 5, 1000, 7, 45] pozíció: 0 érték: 55 output: tömb: [55, 2, 5, 1000, 7, 45] Tehát az adott pozícióra (0-tól indexszelünk) az új érték kerül és minden elem eggyel arrább tolódik. >>> Egy lehetséges megoldás: gyakfel01_1.c 2.) Írj függvényt, aminek nincs bemeneti paramétere és visszatérési értéke sem. A függvényen belül olvass be N számot (melyek között lehet egyforma is) majd: a.) Írasd ki az összes számot, viszont mindet csak egyszer. Példa: input: 11 12 13 11 15 12 output: 11 12 13 15 b.) Csak azokat a számokat írasd ki, melyekből egynél több van. Példa: input: 11 12 13 11 15 12 output: 11 12 Ezt a függvényt a main függvényen belül hívd meg. Tetszésed szerint használhatsz tömböket, vagy amire szükséged van a feladat megoldásához. >>> Egy lehetséges megoldás: gyakfel01_2.c 3.) Írj függvényt, aminek a bemeneti paramétere egy karaktertömb, visszatérési értéke a karaktertömb hossza a feladat elvégzése után. A függvényen belül: a.) Cseréld ki a kapott tömb összes kisbetűjét nagybetűre, a nagybetűket pedig kisbetűre. Példa: input: "Bela nem hajlando Dezso nelkul Las Vegasba menni." output: "bELA NEM HAJLANDO dEZSO NELKUL lAS vEGASBA MENNI." b.) Vedd ki az összes helyközt a karaktertömbből. input: "Bela elment megkapalni a lekvarfoldet." output: "Belaelmentmegkapalnialekvarfoldet." A változtatásokat a kapott karaktertömbben is végezzük el, ne csak kiíratás során végezzük el a változtatásokat. Ezt a függvényt a main függvényen belül hívd meg, miután feltöltötted a karaktertömböt tetszésed szerint.
Jövő héten NINCS ZH, de a gyakorlaton meg kell jelenni. Gyakorló óra lesz. (2018.11.05.)
10. gyakorlat
1. Feladat
Feladakiírás: tombhisztogram_2018.pdf
Egy lehetséges megoldás: tombhistogram.c
2. Feladat
Feladakiírás: akasztofa_2018.pdf
Egy lehetséges megoldás: akasztofa_modified_v2.c
Jövő héten 6. ZH (2018.11.12.)
11. gyakorlat
Pointer haladó
// !
F: Dinamikus kétdimenziós tömb létrehozása
==============================================================================
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p, **t;
int N=3, M=4;
int i, j, v=0;
/* V1 */
p=malloc(N*M*sizeof(int));
for(i=0; i<N; i++) {
for(j=0; j<M; j++) {
p[i*M+j]=v++;
}
}
free(p);
/* V2 */
t=malloc(N*sizeof(int*));
for(i=0; i<N; i++) {
t[i]=malloc(M*sizeof(int));
}
for(i=0; i<N; i++) {
for(j=0; j<M; j++) {
t[i][j]=v++;
}
}
for(i=0; i<N; i++) {
free(t[i]);
}
free(t);
return 0;
}
Gyakorló feladatok
(1.) k-ad rendű Fibonacci
Általánosítsd a Fibonacci sorozatot: tekintsük azt a k-ad rendű Fibonacci sorozatot, melynek első k eleme 1 (azaz a[0]=..a[k-1]=1), a többi elemét pedig az előző k elem összegeként kapjuk, (azaz a[n]=a[n-1]+...+a[n-k]). Írj programot, mely bekér egy k és egy n természetes számot, és kiszámítja a k-ad rendű Fibonacci-sorozat n-ik elemét!
Egy lehetséges megoldás: kfibo.c
(2.) Beszúró rendezés
Leírás: Wikipedia
Egy lehetséges megoldás: beszurorendezes.c
Jövő héten 7. ZH (2018.11.19.)
12. gyakorlat
Függvény pointer
Több feladat közül futási időben döntöm el, hogy melyiket hajtom végre. A függvényre mutató pointer a függvény kódjának a címére mutat, azon keresztül meghívhatom a függvényt. A pointernek tudnia kell a függvény típusát (paraméterek és visszatérési érték típusa). Pl.:
double fgv(double, double); /* függvény deklarációja */ double (*fptr)(double, double); /* ilyen típusú függvényre mutató pointer deklarációja */ fptr = fgv; /* a függvény nevét adom kezdőértékül, a fordító persze ebből címet állít elő */ fptr(x, y); /* meghívom a függvényt a pointeren keresztül */
F: Egy tömbben soroljunk fel függvényeket, és hívjuk meg valahányadikat.
==============================================================================
#include <stdio.h>
#include <math.h>
/* sinus negyzet - beepitett fuggvennyel */
double sin2(double x){
return sin(x)*sin(x);
}
/* kettes alapu logaritmus - beepitett fuggvennyel */
double ln2(double x){
return log(x)/log(2);
}
/* cosinus negyzet - beepitett fuggvennyel */
double cos2(double x){
return cos(x)*cos(x);
}
typedef double (*fp)(double); /* fuggvenyre mutato pointer tipusa */
/* melynek double a visszateresi erteke es double tipust var a parameterlistaban */
int main(){
fp tomb[3] = {sin2, ln2, cos2}; /* ilyen pointerek tombje, fuggveny neve ertekul adhato fuggvenyre mutato pointernek */
int f;
double x;
printf("Melyik fuggveny legyen: \n 1: sinx\n 2: log2\n 3: cos2\n");
scanf("%d", &f);
printf("Mi legyen a fuggveny parametere: ");
scanf("%lf", &x);
printf("\nA valasztott fuggveny erteke a megadott parameterrel: %lf\n", tomb[f-1](x) );
/* a tombben levo pointeren keresztul hivom a fuggvenyt */
/* 1-tol 3-ig vart bemenetet a program.
0-tol valo indexeles miatt levon 1-et [tomb-1]
es parameterkent atadodik az ugyszint beolvasott ertek (x) */
return 0;
}
Egy egyszerűbb példa:
#include <stdio.h>
#include <time.h>
/* Csinálunk 4 fuggvenyt, ahol mindegyiknek megegyező lesz a tipusa es a bemeneti parametereknek a tipusa illetve szama is */
/* Egyszeru pelda reven legyen ez a 4 fuggveny a 4 alapmuvelet */
int osszead (int a, int b){
return a+b;
}
int kivon (int a, int b){
return a-b;
}
int szoroz (int a, int b){
return a*b;
}
int oszt (int a, int b){
if (b > 0) // mivel 0-val nem osztunk!
return a/b;
else
return 0;
}
/* hozzuk letre az ilyen fuggvenyekre mutato pointer tipust */
typedef int (*muveletekPointer)(int, int);
/* hozzunk letre egy tombot, mely az elozoleg definialt tipusu legyen,
es a 4 eleme a 4 fuggvenyunk neve legyen */
muveletekPointer muveletekTomb[] = {osszead, kivon, szoroz, oszt};
int main(){
srand(time(NULL));
int a, b, eredmeny, // 3 segedvaltozo a 2 bemeneti paramterhez es a visszaadott ertekhez
random = rand()%4; // random szam sorsolasa 0 es 3 kozott [0,3]
printf("Add meg az elso parametert: ");
scanf("%d",&a);
printf("Add meg a masodik parametert: ");
scanf("%d",&b);
/* a radnom elem alapjan kivalasztott eleme a tombnek az adott sorszamu fuggveny,
mely megkapja az elozoleg beolvasott ket erteket bemeneti parameternek.
Mint latszik a fuggvenyek hasonlosagabol adodoan az osszes fuggvenyre raillik ez a hivasmod */
eredmeny = muveletekTomb[random](a, b);
/* csak hogy legyen egy kis regen latott vezerlesi szerkezet,
az alapjan, hogy melyik muveletet sorsoltuk,
az alapjan valtozik az eredmeny kiiratasa */
switch(random){
case 0: printf("A ket szam osszege: "); break;
case 1: printf("A ket szam kulonbsege: "); break;
case 2: printf("A ket szam szorzata: "); break;
case 3: printf("A ket szam hanyadosa: "); break;
}
printf("%d\n\n", eredmeny);
return 0;
}
PGM fájl
! Feladat: Invertálj egy PGM képet, azaz minden képpont intenzitását változtasd az ellenkezőjére (így pl. feketéből fehér, világosból sötét lesz, mint a fotónegatívokon).
Specifikáció: A program inputja egy (egyszerűsített) PGM formátumú kép. A PGM formátum egy szürkeárnyalatos képet ír le a következő formában. A PGM fájl első sora a "P2" szöveg; a második sortól kezdve egész értékeket tartalmaz whitespace karakterekkel (szóköz, tabulátor, sortörés, stb.) elválasztva. Az első két érték X és Y, a kép szélessége és magassága, a harmadik M, a képpontok lehetséges maximális értéke. Ezt további X*Y darab [0..M] intervallumba eső érték követi, az egyes képpontok intenzitásértékei, sorfolytonosan megadva. A kimenet egy PGM formátumú kép, az eredeti kép inverze.
Használj strukturát a pgm formátumú kép tárolására!
Dinamikus memóriafoglalással oldjuk meg a feladatot!
A program teszteléséhez használjuk az alábbi fájlt: progalap.pgm
Egy lehetséges megoldás: pgmInverter.c
FILE IO - példa és segítség a 9. ZH-hoz
#include <stdio.h>
/*
be.txt
0
5
8 5 2 6 4
ezegypeldaszoveg
ki.txt
"valamilyen eloirt muvelet eredmenye"
LEIRAS:
A be.txt elso sora azt mondja meg, hogy a szamsort vagy a karaktersort kell majd feldolgozni a kesobbiekben:
0 - szamsor, 1 - karaktersor
A masodik sor azt mondja meg, hogy hany szam talalhato a szamsorban.
A harmadik es negyedik sor pedig maga a szamsor vagy a karaktersorozat.
A szamsor es a karaktersor hossza sem haladhatja meg a 100 elemet.
FELADAT:
Ez majd definialva lesz. Egyelore mi csak olvassuk be a leiras alapjan a be.txt tartalmat.
*/
int main(){
int szamVagyKar;
int meret, szamtomb[100];
char karaktertomb[101];
int i;
FILE *be, *ki;
be = fopen("be.txt", "r");
ki = fopen("ki.txt", "w");
// BEOLVASAS
fscanf(be, "%d", &szamVagyKar);
fscanf(be, "%d", &meret);
for (i=0; i<meret; i++){
fscanf(be, "%d", &szamtomb[i]);
}
fscanf(be, "%s", karaktertomb);
// MINDIG TESZTELJUK LE, HOGY SIKERES VOLT-E A BEOLVASAS
printf("%d\n%d\n", szamVagyKar, meret);
for (i=0; i<meret; i++){
printf("%d ", szamtomb[i]);
}
printf("\n%s\n", karaktertomb);
// * * * MUVELET * * *
if (szamVagyKar == 0){
// csinalunk vmit
} else {
// csinalunk mas vmit
}
// FAJLOK LEZARASA
fclose(be);
fclose(ki);
return 0;
}
Láncolt lista - egy komolyabb feladat(!)
F: Írj egy programot, ami egy láncolt listába olvas be egész számokat egy
konstansként megadott végjelig, majd fordított sorrendben kiírja a
beolvasott értékeket.
==============================================================================
== BEGIN linkedlist.c ========================================================
#include <stdio.h>
#include <stdlib.h>
#define VEGJEL 0
struct cella {
int ertek;
struct cella *kov;
};
int main()
{
struct cella *elso = NULL; // ezt a mutatot hasznaljuk majd az elso elemre valo mutatasra minden korben
struct cella *p; // ezt a mutatot hasznaljuk majd az aktualis elem lementeserr
int input; // ide olvasunk majd be ertekeket
scanf("%d", &input); // indito beolvasas
while(input!=VEGJEL) { // minden korben leellenorizzuk, hogy a vegjelet olvastuk-e be (ami ugyebar a 0)
// ha nem végjel, akkor:
p = malloc(sizeof(struct cella)); // foglalunk neki helyet (egy stuktura meretet), ahova a p mutat
p->ertek = input; // a beolvasott ertek lesz az uj struct elem erteke
p->kov = elso; // raalitjuk az elozo korben beolvasott elemre
elso = p; // azt mondjuk, hogy a most beolvasott elem lesz aktualisan az elso
scanf("%d", &input); // kovetkezo input beolvasasa
}
/* kiiratas visszafele
tudjuk, hogy az "elso" pointer mutat a legutoljara beolvasott elemre es
mivel visszafele akarunk kiiratni, ezert ettol az elemtol indulunk, ezert p=elso a kezdoertek
tudjuk, hogy a legelso elem NULL-ra mutat,
mivel belallitottuk a main elso soraban, ezert p!=NULL a feltetel
tudjuk, hogy a kovetkezo elem a "kov" valtozoban van benne,
mivel a while harmadik parancsakent raallitottuk, ezert p=p->kov a leptetes
*/
for(p=elso; p!=NULL; p=p->kov) {
printf("%d\n", p->ertek);
}
// Lefoglalt memoria teruletek felszabaditasa
// Itt ha csak az elozo ciklust hasznalnak, akkor mindig felszabadulna az a terulet ami alapjan a kovetkezo elemre ugranank
while(elso!=NULL) {
p =elso; // aktualis elemre valo hivatkozas
elso=p->kov; // kovetkezo ellem kimentese
free(p); // aktualis terulet felszabaditasa (a kovetkezo elem mem. cimevel egyutt)
}
return 0;
}
Jövő héten 8. ZH (2018.11.26.)
C kód szintaxis kiemelő stílus csere