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>

  • Kiírja, hogy kik vannak bejelentkezve az aktuális gépre.

    felhasználó: a megadott felhasználóról ír ki adatokat.


  • who

  • Kiírja, hogy kik vannak bejelentkezve az aktuális gépre, plusz adatokat ír ki a finger-hez képest.


  • w

  • Ugyanaz, mint a who, csak kiírja, hogy min dolgozik.




Multitask

  • ps

  • 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.


  • jobs

  • Kiírja az aktuális jobokat, amik az adott terminálhoz kapcsolódnak.


  • ^C

  • Ctrl+c paranccsal leállíthatunk előtérben futó folyamatokat.


  • ^Z

  • Ctrl+z paranccsal szüneteltethetünk előtérben futó folyamatokat.


  • bg %<szám>

  • 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").


  • fg %<szám>

  • 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").


  • kill %<szám>/PID

  • 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

ASCII kódtábla

C könyvtár-referencia




    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


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.





    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