Gábor LÉKÓ, PhD student

Programozás alapjai gyakorlat 2017-2018/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) [2017-09-04]:
     2. (37) [2017-09-11]:
     3. (38) [2017-09-18]:
     4. (39) [2017-09-25]: 1. mini zh
     5. (40) [2017-10-02]: 2. mini zh
     6. (41) [2017-10-09]: 3. mini zh
     7. (42) [2017-10-16]: 4. mini zh
     8. (43) [2017-10-23]: --/5. mini zh
     9. (44) [2017-10-30]: 5. mini zh/--
    10. (45) [2017-11-06]: 6. mini zh
    11. (46) [2017-11-13]: 7. mini zh
    12. (47) [2017-11-20]: 8. mini zh
    13. (48) [2017-11-27]: Nagy zh
    14. (49) [2017-12-04]: Javító


A 8. héten a hétfő elmarad (Október 23.), a kedd-csütörtöki órák rendben
haladnak. A 9. héten hétfőn az előző hét lesz pótolva, a szerdai órák
elmaradnak (November 1.). Kedden és csütörtökön gyakorló, konzultációs órák
lesznek tartva, ezek látogatása nem kötelező, és a teremkapacitásig bármely
órára be lehet menni

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.

A gyakorlat teljesítésének értékelése pontozás alapján történik. Maximálisan
összegyűjthető pontszám 80 pont.

Laboratóriumi gyakorlatok értékelése:

8 darab 20-45 perces mini ZH., egyenként 5-10, összesen 60 pontért. A mini
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.

1 darab 135 perces nagy ZH., 20 pontért. A nagy ZH-n teljes programot kell
megírni hálózatról lekapcsolt számítógépen. A feladatok értékelése a bíró
rendszerén keresztül automatikus.

Minimális pontszámok / javítás:
Mini ZH-kon összesen minimum 15 pontot kell elérni, aki nem éri el az nem
teljesítette a félévet. Mini ZH pótlására / javítására nincs lehetőség. A
nagy ZH-n minimum 5 pontot kell elérni, a gyakorlaton összesen minimum 30
pont. Aki ezeket nem éri el, annak a nagy ZH pontszámát kiváltó javítót kell
írnia. A többiek is írhatnak javítót, de a javító pontszáma akkor is
felülírja a nagy zh pontszámát, ha rosszabbra sikerül (vagyis rontani is
lehet)!

A laboratóriumi gyakorlatokon való szereplésért (pl. házi feladatok táblánál
történő bemutatásáért vagy meg nem oldásáért) plusz / mínusz pontok adhatók,
amik az összpontszámba számítanak bele (így a gyakorlat 30 pontos minimumába
is).

A gyakorlat érdemjegyének meghatározása az összpontszám alapján történik a
következő ponthatárok szerint:

 *  0 - 29 pont : elégtelen (1)
 * 30 - 44 pont : elégséges (2)
 * 45 - 59 pont : közepes (3)
 * 60 - 69 pont : jó (4)
 * 70 - 80 pont : jeles (5)

Előadás:

Az előadás látogatása nem kötelező, de a gyakorlat épít az előadáson
elhangzottakra, így azt a hallgatóknak ismerniük kell!

A vizsgára jelentkezés előfeltétele a gyakorlat sikeres teljesítése. A
vizsgajelentkezés az ETR rendszeren keresztül történik. Vizsgáról való
távollét igazolásánál a TVSZ szerint kell eljárni.

A kollokvium érdemjegyének meghatározása a (várhatóan teszt jellegű) vizsgán
szerzett pontok alapján történik a következő ponthatárok szerint:

 *  0 -  49% : elégtelen (1)
 * 50 -  64% : elégséges (2)
 * 65 -  79% : közepes (3)
 * 80 -  89% : jó (4)
 * 90 - 100% : jeles (5)

A jó (4) és jeles (5) jegyekért szóbeli vizsgarészt is teljesíteni kell.

Linux operációs rendszer alapparancsai

  1. gyakorlat - 09.04. - Évkezdési adminisztárció + Linux alapok

C programozási nyelv

  2. gyakorlat - 09.11. - Fordítás & futtatás, változók ( lokális & globális ), input/output, blokkok, függvények

  3. gyakorlat - 09.18. - Feltételes vezérlési szerkezetek (IF-ELSE, SWITCH) és ciklusok (WHILE, DO-WHILE, FOR)

  4. gyakorlat - 09.25. - 1. kisZH (5p) - Konstansok (#define), 1D tömbök és karaktertömbök

  5. gyakorlat - 10.02. - 2. kisZH (5p) - Tipusok haladó, Hibajavítás, Gyakorlás

  6. gyakorlat - 10.09. - 3. kisZH (5p) - Rekurzió, Gyakorlás

  7. gyakorlat - 10.16. - 4. kisZH (5p) - File input/output, Sorozatok, Gyakorlás (k-ad rendű Fibonacci, Beszúró rendezés)

  8. gyakorlat - 10.23. - A GYAKORLAT ELMARAD! 1956-os Forradalom Ünnepe (hosszú hétvége).

  9. gyakorlat - 10.30. - 5. kisZH (10p) - Pointerek

10. gyakorlat - 11.06. - 6. kisZH (10p) - typedef, struct, union; pointerek és struktúrák kombinálása

11. gyakorlat - 11.13. - 7. kisZH (10p) - FILE IO (ismétlés), Pointer haladó (2D tömbök), Láncolt lista, Függvény pointer

12. gyakorlat - 11.20. - 8. kisZH (10p) - enum, parancssori argumentumok, modulok, makrók, IF-ELSE kicsit másképp, tárolási osztályok

13. gyakorlat - 11.27. - NagyZH (20p)

14. gyakorlat - 12.04. - Javító/Pótló ZH


1. gyakorlat




É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.).

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):
      • Hétfői 8-11 csoport esetén: [progalap2017][8][reg]
      • Hétfői 15-18 csoport esetén: [progalap2017][15][reg]
    • Tartalom:
      • h-s azonosító;Neptun-kód;név

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!




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


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

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;
}

Feladat: fordítsuk le az alábbit -Wall kapcsolóval! Milyen hibákat kapunk? Javítsuk őket!


#include <stdio.h> 

main() {
    printf("Hello Világ!\n");
}

Feladat: Futtassuk le az alábbi parancsokat a fenti, javított "Hello World" programon! Mi lett az eredmény és miért? Hogyan tudnánk felcserélni a 2. és 3. parancs eredményét?

$ ./hello ; ./hello
$ ./hello && ./hello
$ ./hello || ./hello



    Input/Output alapok


Kiíratás képernyőre (printf):


#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"

Adatok bekérése (scanf):


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

A BÍRÓ2-esen már kiosztásra is került az idei próba ZH. Lépjünk be és töltsük le!





    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. miniZH (2017.09.25.)

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 (tehát hétfő reggeli csoport - 8:40-ig/ hétfő délutáni csoport - 15:30-ig). 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 .





    #define macro


Fordítási időben jönnek létre. A konstansdefiniálás általános alakja:


#define NÉV érték

Az érték bármi lehet, később a fordítás első menetében a preprocesszor a név összes előfordulását szövegesen a megadott értékkel helyettesíti, majd folytatódik a fordítás. Így a konstans értéke akár programrészlet is lehet.

Feladat: Írj egy programot, ami 1-től 10-ig kiírja a számokat, majd minden második, majd minden negyedik számot.


#include <stdio.h>

int main() {
	int i;
	for(i=1; i<=10; i++) {
		printf(" %d", i);
	}
	putchar('\n');
	for(i=1; i<=10; i+=2) {
		printf(" %d", i);
	}
	putchar('\n');
	for(i=1; i<=10; i+=4) {
		printf(" %d", i);
	}
	putchar('\n');
	return 0;
}

Feladat: Módosítsuk úgy a programot, hogy 21-től 144-ig írjon ki. Hány helyen kellett átírnunk számokat?

Feladat: Csináljuk meg ugyanezt konstansokkal. Így hány helyen kellene módosítani?


#include <stdio.h>

#define A 1
#define B 10

int main() {
	int i;
	for(i=A; i<=B; i++) {
		printf(" %d", i);
	}
	putchar('\n');
	for(i=A; i<=B; i+=2) {
		printf(" %d", i);
	}
	putchar('\n');
	for(i=A; i<=B; i+=4) {
		printf(" %d", i);
	}
	putchar('\n');
	return 0;
}

Elmélkedjünk: Mi lesz az eredménye az alábbinak:


#include <stdio.h>

#define int 100.0

int main() {
	float f=int;
	printf("%f\n", f);
	return 0;
}



    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]);
		}
	}
	for(i=0; i<N; i++) {
		for(j=0; j<N; j++) {
			printf("%d", tomb[j][i]);
		}
	}
	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. miniZH (2017.10.02.)

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 (tehát 8:40-ig/15:30-ig). 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
}



    Hibajavítás


Feladat: Fordítsuk le az alábbi kódot és javítsuk ki a terminal hibaüzeneteit felhasználva. 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));
]





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ére. 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");
}


/** 
	(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 i, tmp;	// indexvaltozo es segedvaltozo a cserehez
	kiirIntegerTomb(tomb, meret);	
	for (i=0; i<meret; i++){
		if (i == a){	// ha az index megegyezik a 3. parameter ertekevel, akkor 3 lepeses ("haromszog") csere
			tmp = tomb[a];		// kimentjuk az egyik elemet
			tomb[a] = tomb[b];	// ekkor mar felul irhatjuk
			tomb[b] = tmp;		// a tmp-be mentett ertek mehet a masik valtozoba 
		}
	}
	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;
}




Plusz pontos házi feladat

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

Beküldési határidő: 2017. 10. 09., éjfél

Küldés STUD-os email címről, melynek tárgya: [progalap2017][05][plusz], tartalma pedig a csatolt .c fájl.

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 kommentezni kell, magyarul! (Melyik változó / elágazás / ciklus / függvény /.. mire való.)

Csak akkor jár plusz pont, ha az összes kritérium teljesül!

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!

Egy lehetséges megoldás: bomb.c





    Jövő héten 3. miniZH (2017.10.09.)



6. gyakorlat




    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
*/




    Gyakorlás


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: time ./prog) Ehhez használj long long int típusú értékeket.


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 <time.h>	// Program elején, a többi include mellett.
     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]

3. Feladat: Írjunk programot, mely a bemeneti szöveg kiírását végzi el a képernyőre, számjegyek nélkül.


4. Feladat: Béla és egyik haverja moziba mennek. A mozitermen közepén végig vezet egy folyosó lefelé és a folyosó jobb és bal oldalán egyforma mennyiségű ülőhely található (tehát pl. 10 sor és 10 oszlop mindkét oldalon). Mindketten nagyon nagy fanok így a lehető legjobb pozícióból szeretnék látni a vásznat. Azaz mindketten a középső folyosó mellett szeretnének ülni közvetlenül, de ugyanabban a sorban. Készíts két darab N*N-es integer tömböt, majd töltsd fel őket random 0-kal és 1-esekkel. Írasd ki őket egymás mellé. Majd keresd meg azokat a sorokat, amelyeknél az 1. tömb utolsó oszlopában és a 2. tömb első oszlopában egymás mellett 0 található.


5. Feladat: FIFO (First In First Out) algoritmus megvalósítása 1D tömbbel. Töltsünk fel egy 10 méretű, 1D tömböt 1..10 elemekkel. Majd olvassunk be egy értéket egy változóba. Ha az az érték már szerepel a tömbben, akkor ne tegyünk semmit, mivel nincs szükség cserére. Ha viszont nincs benne az érték a tömbben, akkor töröljük a tömbből a legrégebben betöltött elemet és tegyük a tömb végére a beolvasott értéket. Ciklussal olvassunk be bizonyos mennyiségű elemet.


Megoldás letöltése: gyak06.c, illetve online verziója:



#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define N 4
#define M 5
#define S 10

void kiir (int t[]){
	int i;
	for (i=0; i<S; i++){
		printf("%d  ", t[i]);
	}
	printf("\n");
}

int fgv1A(int n){
	int i, ossz = 0;
	for (i=1; i<=n; i++){	// az elso n szamon fogunk vegig iteralni
		ossz += i;	// mindig hozza adjuk az aktualist az elozo osszeghez
	}
	return ossz;	// osszeg visszaadasa (osszeggel valo visszateres)
}

int fgv1B(int n){
	return n*(n+1)/2;	// keplet eredmenyenek a visszaadasa
}

void fgv2(int t[][M]){	// jelenleg sorminimumok szamolasa
	srand(time(NULL));
	int i, j, min = 0;
	for (i=0; i<N; i++){	// sorokat hatarozza meg
		for (j=0; j<M; j++){	// oszlopokat hatarozza meg
			t[i][j] = rand() % 100;	// random sorsolunk: [0, 99] 
		}
	}
	for (i=0; i<N; i++){	// sorokat hatarozza meg
		min = t[i][0];	// kimentjuk az adott sor legelso oszlopanak elemet es vele fogjuk kezdeni az osszehasonlitast, igy nem fordulhat elo, hogy tul kicsi kezdoerteket adunk meg
		for (j=0; j<M; j++){	// oszlopokat hatarozza meg
			printf("%3d", t[i][j]);	// kiiratjuk a tomb elemeit
			if (t[i][j] < min){	// ha a tomb adott eleme kisebb, mint a min
				min = t[i][j];	// akkor, az azt jelenti, hogy "ő" a jelenlegi legkisebb elem, irjuk felul vele a min-t 
			}
		}
		printf("  |  %2d\n", min);	// sorminimumok kiirasa
	}
}

void fgv3(char t[]){
	int i;
	printf("%s\n",t);	// tomb kiiratasa
	for (i=0; t[i] != 0; i++){
		if (t[i] < '0' || t[i] > '9'){	// amennyiben az adott karakter nem szam (ASCII)
			printf("%c", t[i]);	// akkor kiiratjuk
		}
	}
	printf("\n");
	// NEM elfelejteni, hogy az elozo ciklus nem valtoztat a tomb tartalman,
	// csupan a kiiratast vegezzuk el szamok nelkul
}

void fgv4(int t1[][S], int t2[][S]){
	srand(time(NULL));
	int i, j;
	for (i=0; i<S; i++){	// sorokat hatarozza meg
		for (j=0; j<S; j++){	// oszlopokat hatarozza meg
			t1[i][j] = rand() % 2;	// random sorsolunk: [0, 1] 
			t2[i][j] = rand() % 2;	// random sorsolunk: [0, 1] 
		}
	}
	
	// a ket tomb kiiratasa egymas melle
	for (i=0; i<S; i++){	// sorokat hatarozza meg
		for (j=0; j<S; j++){	// oszlopokat hatarozza meg
			printf("%2d", t1[i][j]);
		}
		printf("\t");
		for (j=0; j<S; j++){	// oszlopokat hatarozza meg
			printf("%2d", t2[i][j]);
		}
		printf("\n");
	}
	
	printf("\nAjanlott sorok:\n");
	for (i=0; i<S; i++){
		// ha a t1 utolso oszlopa es a t2 elso oszlopa is nulla, ugyanabban a sorban
		if (t1[i][S-1] == 0 && t2[i][0] == 0){
			printf("%d.\n", i+1);	// akkor kiiratjuk (azert i+1, hogy ne 0-tol indexszeljunk)
		}
	}
}

void fgv5 (int t[], int bejovo){
	int i, voltE = 0;
	for (i=0;i<S;i++){	// vegig elemezzuk a tombot
		if (t[i] == bejovo){	// ha a bejovo ertek szerepel benne
			voltE = 1;	// akkor egy valtozo erteket 1-re allitjuk
		}
	}
	if (voltE == 0){	// amennyiben a valtozo erteke 0, tehat meg nincs a tombben az ertek
		for (i=0;i<S;i++){
			t[i] = t[i+1];	// akkor az osszes elemet eggyel balra mozgatjuk
		}
		t[S-1] = bejovo;	// es az utolso poziciora behelyezzuk az uj erteket
							// igy mindig a tomb elso eleme kerult bele a legregebben / legeloszor
	}
}


int main(){
	
	int be, i,
		tInt1[N][M],	// NxM 2D tomb
		tInt21[S][S], tInt22[S][S],	// 2 db SxS 2D tomb
		tInt3[S] = {1,2,3,4,5,6,7,8,9,10};	// 1D tomb
	char tChar[S] = {'B','2','8','e','2','l','9','a','6',0};	// 1D karakter tomb
	
	/** Pelda a fuggvenyek hivasara */
	
//	printf("%d\n",fgv1A(5));

//	printf("%d\n",fgv1B(5));

//	fgv2(tInt1);

//	fgv3(tChar);

//	fgv4(tInt21, tInt22);

/*
	for (i=0; i<5; i++){
		kiir(tInt3);
		printf("Adj meg egy erteket: ");
		scanf("%d",&be);
		fgv5(tInt3, be);
		kiir(tInt3);
		putchar('\n');
	}
*/	
	return 0;
}

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;
}





    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, illetve online verziója:


#include<stdio.h>

/** 1. Feladat **/
float szamtani(float A, float D, int N){
	int i;
	for (i=2; i<=N; i++){
		A = A + D;
		printf("(%d) %f   ", i, A);
	}
	return A;
}

/** 2. feladat **/
float mertani(float A, float Q, int N){
	int i;
	for (i=2; i<=N; i++){
		A = A*Q;
		printf("(%d) %f  ", i, A);
	}
	return A;
}

int main(){
	/** Pelda a fuggvenyek hivasara **/
	
	printf(" Szamtani sorozat N-ig: \n");
	szamtani(1.5, 3, 4);

	printf("\n\n Mertani sorozat N-ig: \n");
	mertani(3, 3, 5);

	return 0;
}





    További gyakorló feladatok



1. Feladat: Á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!


2. Feladat: Valósítsuk meg a beszúró rendezés algoritmust! Részletesen lásd: Wikipedia


Egy lehetséges megoldás letöltése: gyak07.c, illetve online verziója:


#include<stdio.h>

#define M1 20
#define M2 10

void kiir(int t[], int n){
	int i;
	for (i=0; i<n; i++){
		printf("%d  ", t[i]);
	}
	printf("\n");
}

/** 1. feladat **/
void fiboK(int t[], int k, int n){
	int i, j;	
	for (i=0; i<k; i++){	// az elso k elemet feltoltjuk 1-esekkel
		t[i] = 1;
	}
	
	for (i=k; i<n; i++){	// n-edik elem szamolasa: i=k..n
		t[i] = 0;	// kinulazzuk az aktulis elemet, hogy ide tudjuk osszegezni a megelozo k elemet
		for (j=i-k; j<i; j++){	//	visszalepunk k elemnyit (i-k), es az aktualis elemig (i) osszegzunk
			t[i] += t[j];
		}
	}
	
	kiir(t, n);
}

/** 2. feladat **/
void beszuroRendezes(int t[], int n){
	int	count = 0, // itt gyujtjuk majd, hogy a vizsgalt elem hany tombbeli elemnel nagyobb
		i, j, 	// indexvaltozok
		tmp;	// ide mentjuk majd ki a vizsgalt elemet
	kiir(t, n);
	for (i=1; i<n; i++){	// az osszes elemet meg kell vizsgalni egyszer (kiveve az elsot, mivel neki ugysincs balrol szomszedja)
		count = 0;	// minden elem eseten nullazas, hogy ujra gyujthessuk az aktualis osszeget	
		tmp = t[i];	// mentsuk ki a vizsgalt elemet, hogy a tomb eleminek mozgatasakor ne vesszen el
		
		for (j=0; j<i; j++){	// menjunk vegig az egesz tombon es vizsgaljuk meg, hogy az aktualis elem hany elemnel nagyobb
			if (tmp > t[j]){
				count++;	// ha nagyobb, akkor noveljuk a fenntartott valtozo erteket
			}
		}

		for (j=i; j>count; j--){	// ha balrol jobbra akarunk elemeket mozgatni, akkor jobbrol balra kell feldolgozni oket
			t[j] = t[j-1];	// jobbra mozgatas
		}
		t[count] = tmp;	// ahany elem nagyobb volt a vizsgalt elemnel, arra a poziciora kell tenni a muvelet vegen
		kiir(t, n);
		//getchar();	// komment kitorlesevel elemenkenti mozgatasonkent Enter utesevel engedhetjuk tovabb a program futasat
	}
	
	kiir(t, n);
}

int main(){
	int t1[M1], t2[M2] = {41,4,1,38,23,-12,78,12,-1000,2};
	
	/** Fuggvenyek hivasara pelda **/
	
//	fiboK(t1, 4, M1);
	// output: 1  1  1  1  4  7  13  25  49  94  181  349  673  1297  2500  4819  9289  17905  34513  66526
	
	beszuroRendezes(t2, M2);
	// output: -1000  -12  1  2  4  12  23  38  41  78
	
	return 0;
}




(!) JÖVŐ HÉTEN (2017.10.23.) A GYAKORLAT ELMARAD! 1956-os Forradalom Ünnepe (hosszú hétvége).




8. gyakorlat



A GYAKORLAT ELMARAD! 1956-os Forradalom Ünnepe (hosszú hétvége)


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.

Megoldás - a változóknak nem az értékét, hanem a memória címét kell átadni, majd a csere függvényben pointereket használva, ezekre a címekre írni be a változtatásokat:


#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;
}



Plusz pontos órai 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


10. 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 book {
	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
struct ember {
    char nev[20];
    int igszam;
    int kor;
};

// kiíratás
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
    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 fgv segítségével
    szemelykiiras(BelaVagyok);

    return 0;
}

Ugyanez typedef-el:


// !
#include <stdio.h>

// ember struktúra
typedef struct {
    char nev[20];
    int igszam;
    int kor;
} ember;

// kiíratás
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
    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 fgv segítségével
    szemelykiiras(BelaVagyok);

    return 0;
}


3 komolyabb példa (otthoni gyakorlásra):


F: Adott a síkon 3 pont, mi az általuk meghatározott háromszög területe?

==============================================================================

#include <stdio.h>
#include <math.h>

struct pont {
	float x;
	float y;
};

float tav(struct pont P, struct pont Q) {
	return sqrtf((P.x-Q.x)*(P.x-Q.x) + (P.y-Q.y)*(P.y-Q.y));
}

int main() {
	struct pont A, B, C;
	float a,b,c,s;
	scanf("%f %f", &A.x, &A.y);
	scanf("%f %f", &B.x, &B.y);
	scanf("%f %f", &C.x, &C.y);
	a=tav(B, C);
	b=tav(A, C);
	c=tav(A, B);
	s=(a+b+c)/2;
	printf("Terulet: %f\n", sqrtf(s*(s-a)*(s-b)*(s-c)));
}


F: Készítsünk komplex számok tárolására alkalmas adatszerkezetet (egész
   komponensekkel). Készítsünk továbbá olyan függvényeket, melyek feladata:
   - kiír egy komplex számot az stdout-ra,
   - összead két komplex számot, és visszaadja az eredményt
   - összeszoroz két komplex számot, és visszaadja az eredményt

==============================================================================
== BEGIN komplex.c ===========================================================

#include <stdio.h>

typedef struct komplex {
	int real;
	int imag;
} komplex;

komplex add(komplex k1, komplex k2)
{
    komplex e;
    e.real = k1.real+k2.real;
    e.imag = k1.imag+k2.imag;
    return e;
}

komplex mul(komplex k1, komplex k2)
{
    komplex e;
    e.real = k1.real*k2.real-k1.imag*k2.imag;
    e.imag = k1.imag*k2.real+k1.real*k2.imag;
    return e;
}

void printk(komplex k)
{
    printf("(%d%+di)\n", k.real, k.imag);
}

int main()
{
	komplex x1,x2,e;
	x1.real = 10;
	x1.imag = 2;
	x2.real = 20;
	x2.imag = -3;
	printk(x1);
	printk(x2);
	e = add(x1,x2);
	printk(e);
	printk(mul(x1,x2));
	return 0;
}


F: Láncolt lista. Olvassunk be egész számokat egy láncolt listába egy adott
   végjelig, majd írassuk ki őket.

==============================================================================
== 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;
	struct cella *p;
	int i;
	scanf("%d", &i);
	while(i!=VEGJEL) {
		p        = (struct cella*)malloc(sizeof(struct cella));
		p->ertek = i;
		p->kov   = elso;
		elso     = p;
		scanf("%d", &i);
	}
	for(p=elso; p!=NULL; p=p->kov) {
		printf("%d\n", p->ertek);
	}
	while(elso!=NULL) {
		p   =elso;
		elso=p->kov;
		free(p);
	}
	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!

==============================================================================

#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;
}


// !
Így nem látszik semmi. De mi van, ha egyszerre íratjuk ki a mezők értékeit?

==============================================================================

#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!

==============================================================================
== 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;
}



Feladat: Írjunk egy programot, melyen belül megvalósítjuk az 1D mátrixszorzást. A mátrixokat és méretüket egy struktúrán belül tároljuk le. A mátrixoknak dinamikusan foglaljunk helyet. Minden egyes műveletet külön függvényben programozzunk le. Használjunk pointereket a függvény paramétereinek átadásakor. Ne feledkezzünk meg a lefoglalt memória területek felszabadításáról sem.

Egy lehetséges megoldás: matrixszorzas1D.c


/*
	Pelda 1D matrixszorzasra:
	m1 = [1,2,3]
	m2' = [4,5,6]
	result = m1 * m2 = 1*4 + 2*5 + 3*6
*/

#include <stdio.h>
#include <stdlib.h>

typedef double* data_t;	// double tipusu mutato tipus letrehozasa

typedef struct {	// matrix_t nevu struktura definialasa, melynek ket attributuma van: n es data
    int n;
    data_t data;
} matrix_t;

/*
	Struktura elemeinek feltoltese
*/
void beolvas (matrix_t *mat){
	int i;
	printf("Add meg a meretet: ");
	/* 	
		KET FELE MODSZERT IS MUTATUNK A STRUKTURAK HASZNALATARA, 
		MELYEK KOZUL BARMELY MEGKOZELITEST HASZNALHATJUK (A TOBBI FUGGVENYBEN IS)
	*/
	scanf("%d", &(*mat).n);
	//scanf("%d", &mat->n);	// Ekvivalens az elozo sorral
	(*mat).data = malloc( (*mat).n * sizeof(double));	// helyet foglalunk a memoriaban matrix elemeinek
	//mat->data = malloc( mat->n * sizeof(double));	// Ekvivalens az elozo sorral
	for (i=0; i < mat->n ; i++){	// feltoltjuk a matrix elemit
		scanf("%lf", &(*mat).data[i]);
		//scanf("%lf", &mat->data[i]);	// Ekvivalens az elozo sorral
	}
}

/*
	Struktura elemeinek kiiratasa
*/
void kiir (matrix_t *mat){
	int i=0;
	printf("\n%d\n", mat->n);
	for (i=0; i < mat->n ; i++){
		printf("%lf ", mat->data[i]);
	}
}

/*
	Strukturak matrix attributumainak osszeszorzasa
*/
int szoroz (matrix_t *mat_1, matrix_t *mat_2, double *res){
	int i;
	if (mat_1->n != mat_2->n){	// leellenorizzuk, hogy egyforma meretuek-e a matrixok
		return 0;	// ha nem, akkor 0 (hamis) ertekkel terunk vissza 
	} else {
		for (i=0; i< mat_1->n ; i++){	// vegig nezzuk az osszes elemet
			*res += mat_1->data[i] * mat_2->data[i];	// es feltoltjuk a szorzatokkal
		}
		return 1;
	}
}

/*
	Strukturan belul foglalt memoriaterulet felszabaditasa
*/
void torol(matrix_t *mat){
	free(mat->data);
}

int main(){
	int sikeres;
	double eredmeny = 0;
	matrix_t elso, masodik;	// 2 matrix_t struktura letrehozasa
	
	beolvas(&elso);	// ertekadas
	beolvas(&masodik);	// ertekadas
	
//	kiir(&elso);
//	kiir(&masodik);
	
	sikeres = szoroz(&elso, &masodik, &eredmeny);	// ket matrix osszeszorzasa. A sikeres volt a szorzas a "sikeres" valtozo erteke 1 lesz, ellenkezo esetben 0
	
	if (sikeres == 1){
		printf("Az eredmeny: %lf\n", eredmeny);
	} else {
		printf("\nA mereteknek meg kell egyezniuk!\n");
	}
	
	torol(&elso);	// lefoglalt memoriaterulet felszabaditasa
	torol(&masodik);	// lefoglalt memoriaterulet felszabaditasa
	
	return 0;
}

Feladat otthonra: Alakítsuk át az előző feladatot úgy, hogy 2D mátrixokra is működjön. Figyeljünk arra, hogy két mátrix csak akkor szorozható össze, ha az első mátrixnak a szélessége, megegyezik a második mátrix magasságával.

Egy lehetséges megoldás: matrixszorzas2D.c


/*
	Pelda 2D matrixszorzasra:
    m1 =  |1 2|
          |3 4|
			
    m2 =  |4 5 6|
          |7 8 9|
	
    result =  |18 21 24|
              |40 47 54|
*/

#include <stdio.h>
#include <stdlib.h>

typedef double** data_t;	// double tipusu mutato tipus letrehozasa

typedef struct {	// matrix_t nevu struktura definialasa, melynek ket attributuma van: n es data
    int n, m;
    data_t data;
} matrix_t;

/*
	Struktura elemeinek feltoltese
*/
void beolvas (matrix_t *mat){
	int i, j;
	
	printf("Add meg a magassagot: ");
	scanf("%d", &mat->n);
	printf("Add meg a szelesseget: ");
	scanf("%d", &mat->m);
	
	mat->data = malloc( mat->n * sizeof(double*));	// helyet foglalunk a memoriaban matrix elemeinek
	for (i=0; i < mat->n ; i++){
		mat->data[i] = malloc( mat->m * sizeof(double));
	}
	
	for (i=0; i < mat->n ; i++){	// feltoltjuk a matrix elemit
		for (j=0; j < mat->m ; j++){
			scanf("%lf", &mat->data[i][j]);
		}
	}
}

/*
	Struktura elemeinek kiiratasa
*/
void kiir (matrix_t *mat){
	int i, j;
	printf("\nMagassag = %d, Szelesseg = %d\n", mat->n, mat->m);
	
	for (i=0; i < mat->n ; i++){
		for (j=0; j < mat->m ; j++){
			printf("%2.2lf ", mat->data[i][j]);
		}
		printf("\n");
	}
}

/*
	Strukturak matrix attributumainak osszeszorzasa
*/
int szoroz (matrix_t *mat_1, matrix_t *mat_2, matrix_t *mat_res){
	int i, j, k;
	double osszeg = 0;
	if (mat_1->m != mat_2->n){	// leellenorizzuk, hogy osszeszorozhatoak-e
		return 0;	// ha nem, akkor 0 (hamis) ertekkel terunk vissza 
	} else {
		/* Eredmeny struktura elemeinek feltoltese */
		mat_res->n = mat_1->n;	// a magassaga az elso matrix magassaga lesz
		mat_res->m = mat_2->m;	// a szelessege az masodik matrix szelessege lesz
		// 2D matrix memoria foglalasa
		mat_res->data = malloc(mat_res->n * sizeof(double*));	// N darab
		for (i=0; i < mat_res->n; i++){	// majd mindhez M darab
			mat_res->data[i] = malloc(mat_res->m * sizeof(double));
		}
		
		// Ezen elmelkedjunk el egy kicsit, hogy hogy is jon ki ez a 3 egymasba agyazott for ciklus (rajzoljuk is le, ha szukseges)
		for (k = 0; k < mat_res->m ; k++){
			for (i = 0 ; i < mat_1->n ; i++){
				for (j = 0; j< mat_2->n ; j++){
					osszeg += mat_1->data[i][j] * mat_2->data[j][k];
				}
				mat_res->data[i][k] = osszeg;
				osszeg = 0;
			}
		}
		
		return 1;
	}
}

/*
	Strukturan belul foglalt memoriaterulet felszabaditasa
*/
void torol(matrix_t *mat){
	int i;
	for (i=0; i < mat->n ; i++){
		free(mat->data[i]);
	}
	free(mat->data);
}

int main(){
	
	int sikeres;
	matrix_t elso, masodik, eredmeny;	// 2 matrix_t struktura letrehozasa
	
	beolvas(&elso);	// ertekadas
	beolvas(&masodik);	// ertekadas
	
	kiir(&elso);
	kiir(&masodik);
	
	sikeres = szoroz(&elso, &masodik, &eredmeny);	// ket matrix osszeszorzasa. A sikeres volt a szorzas a "sikeres" valtozo erteke 1 lesz, ellenkezo esetben 0
	
	if (sikeres == 1){
		kiir(&eredmeny);
		torol(&eredmeny);
	} else {
		printf("\nA mereteknek meg kell egyezniuk!\n");
	}
	
	torol(&elso);	// lefoglalt memoriaterulet felszabaditasa
	torol(&masodik);	// lefoglalt memoriaterulet felszabaditasa
	
	return 0;
}




Plusz pontos házi feladat:

Leírás elérhető .pdf formátumban: akasztofa.pdf

Küldés STUD-os email címről, melynek tárgya: [progalap2017][10][plusz], tartalma pedig maga a kód, vagy a csatolt .c fájl.

A feladat megoldásához nagy segítséget jelenthet a 10. gyakorlat anyaga, meg persze úgy alapjáraton az eddig vett anyag. Minden szükséges anyag és példa megtalálható a honlapomon.

Beküldési határidő: 2017. 11. 13., éjfél .

Egy lehetséges futási eredmény:

_ _ _ _ _ _ _
Tippelj egy betut: l
Eltalaltad az adott karaktert, lephetsz tovabb!
l _ _ _ _ _ _
Tippelj egy betut: v
Nem talalt! Meg 5 lehetoseg az adott karakterre!
l _ _ _ _ _ _
Tippelj egy betut: m
Nem talalt! Meg 4 lehetoseg az adott karakterre!
l _ _ _ _ _ _ 
Tippelj egy betut: o
Eltalaltad az adott karaktert, lephetsz tovabb!
l o _ _ _ _ _
Tippelj egy betut: v
Eltalaltad az adott karaktert, lephetsz tovabb!
l o v _ _ _ _
Tippelj egy betut: a
Eltalaltad az adott karaktert, lephetsz tovabb!
l o v a _ _ _
Tippelj egy betut: t
Nem talalt! Meg 5 lehetoseg az adott karakterre!
l o v a _ _ _ 
Tippelj egy betut: r
Nem talalt! Meg 4 lehetoseg az adott karakterre!
l o v a _ _ _ 
Tippelj egy betut: e
Nem talalt! Meg 3 lehetoseg az adott karakterre!
l o v a _ _ _
Tippelj egy betut: g
Eltalaltad az adott karaktert, lephetsz tovabb!
l o v a g _ _
Tippelj egy betut: o
Eltalaltad az adott karaktert, lephetsz tovabb!
l o v a g o _
Tippelj egy betut: n
Nem talalt! Meg 5 lehetoseg az adott karakterre!
l o v a g o _
Tippelj egy betut: k

Gratulalok! Kitalaltad a keresett szot, amely "lovagok" volt!


11. gyakorlat




    FILE IO - példa a nagyZH-hoz



// !
/* 
	Pelda a [7307] feladat FILE IO muveleteire.
	Hasonlokeppen oldhato meg az osszes tobbi feladat eseten is.

	[7307]
	be.txt:
		1 11
		EZAKULCSSZO
		menekuljetekmertjonazellenseg

	ki.txt:
		qdnoefnbwssolebnuqfsyspkexmpi
*/

#include <stdio.h>
#include <string.h>	// Ezt a header-t nem hasznalhatjatok, en csak a tenyleges szamitasok helyett hasznalom

int main () {
	/* Valtozok letrehozasa */
	int kodolase, hossz;
	char kulcsszo[27], szoveg[201], eredmeny[201];
	
	FILE *in, *out;
	
	in = fopen("be.txt","r");
	out = fopen("ki.txt", "w");
	
	/* Beolvasas */
	fscanf(in, "%d%d%s%s",&kodolase, &hossz, kulcsszo, szoveg);
	
	/* Beolvasott valtozok ellenorzese */
	printf("%d %d\n%s\n%s\n", kodolase, hossz, kulcsszo, szoveg);
	
	/* Kodolt vagy dekolot szoveg eloallitasa */
	// . . .
	// AZ ALABBI SOR NALATOK NEM SZEREPEL, HELYETTE A TENYLEGES SZAMITASOKKAL ELOALL AZ EREDMENY TOMB
	strcpy(eredmeny, "qdnoefnbwssolebnuqfsyspkexmpi");
	// . . .
	
	/* Kapott szoveg kiiratasa */
	fprintf(out, "%s\n", eredmeny);	// FONTOS, az uj sor ne maradjon le! (\n)
	
	fclose(in);
	fclose(out);
	
	return 0;
}



    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: egydimenziós tömb */
    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: sorokat külön-külön */
    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ó feladat

! 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




    Láncolt lista



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;
}



    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 négyzet - beépített függvénnyel */
double sin2(double x) {
	double sinx = sin(x);
	return sinx*sinx;
}

/* kettes alapú logaritmus - beépített függvénnyel */
double log2(double x) {
	return log(x) / log(2);
}

/* cosinus négyzet - beépített függvénnyel */
double cos2(double x) {
	double cosx = cos(x);
	return cosx*cosx;
}

typedef double (*fgvtip)(double);  /* függvényre mutató pointer típusa */
                                   /* melynek double a visszatérési értéke és double típust vár a paraméterlistában */

fgvtip tabla[] = {   /* ilyen pointerek tömbje */
	sin2, 	     /* a függvény neve értékül adható függvényre mutató pointernek */
	log2,
	cos2
};
 
int main() {
    int f, x;
    char* valasztek = "{  1: sin2x  }\n{  2: log2x  }\n{  3: cos2x  }\n";	/* karakterekre mutató pointer, lényegileg egy string */
    printf("Melyik fuggveny legyen?:\n%s?:\t", valasztek);
    scanf("%d", &f);
    printf("Argumentum erteke?:\t");
    scanf("%d", &x);
    printf("A fuggveny erteke az adott pontban:\t%lf\n", tabla[f-1](x) );
		/* a tömbben lévő pointeren keresztül hívom a függvényt */
		/* 1-től 3-ig várt bemenetet a program. 
		   0-tól való indexelés miatt levon 1-et [f-1] 
		   és paraméterként átadódik az úgyszint beolvasott érték (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;
}



12. gyakorlat




    Felsorolás típus - enum


Felsorolás adattípus értékhalmaza a típusképzésben felsorolt azonosítók, mint konstans azonosítók által meghatározott értékek.

Feladat: Definiálj egy felsorolástípust a hét napjainak tárolására, majd írasd ki a napok értékeit!


#include <stdio.h>

int main()
{
	enum { Hetfo,
		Kedd,
		Szerda,
		Csutortok,
		Pentek,
		Szombat,
		Vasarnap
	} nap;
	for(nap=Hetfo; nap <= Vasarnap; nap++) {
	    	printf("%d\n", nap);
	}
	return 0;
}

Feladat: Vedd külön a típusdefiníciót és a változódeklarációt!


#include <stdio.h>

typedef enum { Hetfo,
		Kedd,
		Szerda,
		Csutortok,
		Pentek,
		Szombat,
		Vasarnap
} het;

int main()
{
	het nap;
	for(nap=Hetfo; nap <= Vasarnap; nap++) {
	    	printf("%d\n", nap);
	}
	return 0;
}

Egy enum változó tulajdonképpen egy egész változó.

Elmélkedjünk:

F: Mi történik, ha Hetfo=1 -ként adod meg az első elemet?
F: Mi történik, ha Szombat=10 -ként adod meg a hatodik elemet?
F: Adhatod-e az enum mindegyik elemének ugyanazt az int értéket?




    Parancssori argumentumok


A main függvénynek három paramétere lehet. Az első egy int, a parancssorban kapott argumentumok száma + 1 (a program neve maga is egy argumentum). A második egy olyan pointer-tömb, mely azokra a memóriaterületekre mutatnak, ahol sztringként vannak letárolva a parancssori argumentumok. A harmadik hasonló a másodikhoz, csak ez a környezeti változók címeit tartalmazza. Mi csak az első kettővel foglalkozunk.

Írjuk ki a parancssorban lévő argumentumokat:


#include <stdio.h>

int main(int argc, char **argv)	// tehát itt látható a main függvény alapértelmezett parancsori paramétereinek használata
// vagy így is lehet az argv-t deklarálni:
// main(int argc, char *argv[])
{
    int i;
    printf("argc = %d\n\n",argc);
    for (i=0; i<argc; ++i) {
        printf("argv[%d]: %s\n", i, argv[i]);
    }
	
    return 0;
}

Mentsük el a fenti programot arg.c néven és fordítsuk le!

fordítás:
$ gcc -o arg arg.c
futtatás:
$ ./arg alma korte szilva barack palinka
argc = 6

argv[0]: ./arg
argv[1]: alma
argv[2]: korte
argv[3]: szilva
argv[4]: barack
argv[5]: palinka


F: Írj egy programot, ami összeadja a parancssori paramétereket.

==============================================================================

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    int i;
    int arg = 0;
    printf("Osszesen %d programargumentumot kaptam!\n",argc);
	
    for(i = 0; i< argc; i++)
        printf("%d : %s\n",i, argv[i]);
	
    if(argc > 1)
    {
        for(i = 1; i< argc; i++)
            arg += atoi(argv[i]);	// az atoi fuggveny atkonvertalja a megadott karaktersorozat típusú parametert szamma
    }

    printf("Az argumentumok osszege : %d\n", arg);
	
    return 0;
}



    Modulok


Egy C program egy vagy több modulból áll. A modulok valamelyikének tartalmaznia kell a main függvényt, ami továbbra is a program belépési pontja lesz, vagyis ez kezd el végrehajtódni. Minden modul külön file, de függhetnek egymástól. Több modul használata nagy programok esetén szükségszerű. A moduláris programozás lényege, hogy minden modul önálló fordítási egységet képez, melyeknél érvényesül az adatrejtés elve.

Tehát lényegileg több forrásból szeretnénk felépíteni egy programot. Az előállított header fájlokat a program elején tudjuk be include-olni. Így tudjuk elérni a "külső" fájlokban lévő szügkséges kódrészeket.

Az alábbi példa egy 3 fájlból felépülő programot mutat be:

A következő 3 fájl felépítése:

 - lib.h : függvények deklarációja, a függvényekhez kommentek
 - lib.c : a lib.h -ban deklarált függvények implementálása
 - libmain.c : olyan program, amely használja a "lib" függvénykönyvtárunkat

Elkészítés a következőképpen zajlik:

$ gcc -o futtathato lib.c libmain.c

Tehát csak fel kell sorolni az összes source fájlt, melyet használ a programunk.



==============================================================================
== BEGIN lib.h ===============================================================

#ifndef LIB_H
#define LIB_H 1

/*
 * Olyan függvény, mely az első paraméterében kapott sztringet megfordítva
 * beleteszi a második paraméterében kapott sztringbe.
 * */
void megfordit(char *str, char *forditott);

/*
 * Olyan függvény, amely kiszámolja a paraméterében kapott tömb átlagát.
 * */
float atlag(int *t, int meret);
#endif

== END lib.h =================================================================
==============================================================================


==============================================================================
== BEGIN lib.c ===============================================================

#include "lib.h"

void megfordit(char *str, char *forditott)
{
    int i,j;
    for(i=0;str[i]!='\0';i++)
        ;
    i--;
    for(j=0;i>=0;--i,j++)
        forditott[j] = str[i];
    forditott[j] = '\0';
}

float atlag(int *t, int meret)
{
    float atlag = 0.0;
    int i=0;
    while(i<meret)
    {
        atlag += *(t+i);
        i++;
    }
    atlag /= meret;
    return atlag;
}

== END lib.c =================================================================
==============================================================================


==============================================================================
== BEGIN libmain.c ===========================================================

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "lib.h"

int main()
{
    char *sz1 = "Discovery Channel";
    char *sz2 = (char*)calloc(strlen(sz1)+1,sizeof(char));

    int tomb[] = {-2, 10, 23, -45, 67, 0, 0, 34, 99 };

    megfordit(sz1,sz2);

    printf("%s megfordítva : %s\n",sz1,sz2);
    free(sz2);

    printf("A tömb átlaga : %f\n",atlag(tomb,9));

    return 0;
}

== END libmain.c =============================================================
==============================================================================

Egy nagyon egyszerű példa:

my.h fájl tartalma


void kiir();

my.c fájl tartalma


#include <stdio.h>
#include "my.h"

void kiir(){
	printf("Ez egy kulso header fajl, amit en csinaltam. Hahh!\n");
}

main.c fájl tartalma


#include <stdio.h>
#include "my.h"

int main(){
	kiir();

	return 0;
}



    Makrók


A #define direktívákat arra használjuk, hogy "beszédes" azonosítókkal lássunk el C konstansokat, kulcsszavakat, illetve gyakran használt utasításokat és kifejezéseket. A makrónevekre ugyanaz a képzési szabály vonatkozik, mint más azonosítókra. A makróneveket csupa nagy betűvel ajánlott írni, hogy a szövegben elkülönüljenek a programban használt azonosítóktól.

Az alábbi program meghatározza két szám közül, hogy melyik a kisebb.


#include<stdio.h>

#define min(X,Y) ( (X)<(Y) ? (X) : (Y))		// makró - paraméterben kaphat két számot. A visszatérési értéke az utóbbi zárojelben lévő kiértékelés eredménye

int main() {
    printf("%d\n",min(4,34));
    return 0;
}

Az előfeldolgozó (preprocesszor) minden programsort átvizsgál, hogy az tartalmaz-e valamilyen korábban definiált makrónevet. Ha igen, akkor azt lecseréli a megfelelő helyettesítő szövegre, majd halad tovább a vizsgálattal.

A preprocesszálás eredménye megtekinthető (mindig a frissen létrejövő *.i fájl végén található a saját kódunk - ez a mi esetünkben az utolsó 4 sor):

gcc -E makrofgv.c|tail -4>makrofgv.i

Írjuk meg a negyzet(a) makrót!


#include <stdio.h>

#define negyzet(a) (a*a)

int main()
{
    int a = 5;
    printf("negyzet(%d) = %d",a,negyzet(a));
    return 0;
}



    IF-ELSE kicsit másképp


Lehetőségünk van makrók segítségével megválasztani, hogy mely programrészek fussanak le és melyek ne.

Az alábbi programban szerepel egy #define, mellyel létrehozzuk a TRIAL_VERSION nevű makrót. Ezután található egy #ifdef parancs mely egy makrót vár közvetlen utána. Abban az esetben, ha a megadott makró létezik, akkor lefut az #ifdef utáni rész. Abban az esetben, ha ez a makró nem létezik, akkor az #else után szerepló kódrészlet fog lefutni. Egy #ifdef parancsot mindig egy #endif kell, hogy zárjon.


#include <stdio.h>

#define TRIAL_VERSION 1

#ifdef TRIAL_VERSION
void calculate(int a,int b)
{
    printf("Ez csak próbaverzió! Az összes funkció eléréséhez fizess!\n");
}
#else
void calculate(int a,int b)
{
    printf("%d és %d számtani közepe : %f\n",a,b,(float)a/2 + (float)b/2);
}
#endif

int main()
{
    calculate(10,20);
    return 0;
}

Használható még az #if és #elif parancsok is, melyek az if és else if parancsnak felelnek meg. Valamint az #ifndef parancs, mely alapból egy makró definiálást vár és az utána lévő rész egész a következő #endif-ig lefog futni, ha csak nincs közben (tehát benne) másik, az előbbihez hasonló "if" ág.




    Tárolási osztályok



Tárolási osztályokat bemutató program

==============================================================================

#include <stdio.h>

#define MAX_NUM 5

/* A static tárolási osztály azt jelenti, hogy az adott változó megmarad a
 * blokkból kilépés után is, és a következő belépéskor elérhető lesz a
 * legutóbbi tartalom.
 * 
 * Használhatjuk arra, hogy megszámoljuk, hányszor hívtuk az adott függvényt.
 */
int* counter()
{
    static int count = 0;
    count++;
    printf("Count : %d\n",count);
    return &count;
}

int* kell()
{
	return counter();
}

int main()
{
    /* Az auto tárolási osztály az alapértelmezett, ki sem szükséges tenni.
     */
    auto int valami = 10;
    
    /* A register tárolási osztály arra szolgál, hogy jelezzük a fordítónak,
     * hogy olyan gépi kódot PRÓBÁLJON meg csinálni, amely során ez a változó
     * folyamatosan a CPU egy regiszterében van. -> Gyorsabb elérésű, mint a
     * memória, de sokkal kevesebb ilyen változó létezhet. Gyakran változó
     * változót érdemes.
     *
     * A fordító figyelmen kívül hagyhatja!
     */
    register int i;

    /* A volatile módosító azt mondja a fordítónak, hogy:
     * "Vigyázat, ez a változó értéke úgy is módosulhat, hogy a kódban nincsen
     * annak módosítására szolgáló utasítás!"
     * Pl. a változó egy porthoz csatlakozik, ahová az adott eszköz írhat!
     */
    volatile unsigned short int device = (unsigned short int)0;

    /* A const módosító azt mondja a fordítónak, hogy az érték nem
     * megváltoztatható. Ez viszont csak annyit jelent, hogy az adott
     * változóhivatkozás nem szerepelhet értékadás bal oldalán.
     */
    const long int nemvaltozo = 2007;

    int *p;
    p=&i; /* EZ HIBÁS */
    p=counter();
    printf("*%p = %d\n", p, *p);
    p=kell();
    printf("*%p = %d\n", p, *p);
    *p = 100;
    counter();

    return 0;
}



C kód szintaxis kiemelő stílus csere