Programozás alapjai gyakorlat 2014-2015/1

4. gyakorlat


    Mit is tanultunk a 3. gyakorlaton?

Ismétlő feladat: Írjunk olyan programot amely bekér egy karaktert majd, kiírja azt. Használjunk blokkokat, lokális és globális változókat. Mindezt egy függvényben valósítsuk meg, melyhez írunk egy programot is, amely ezt a függvényt használja.

Megoldás letöltése .




    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ás1
} else {
    utasítás2
}

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

#include <stdio.h>

int main() {
    int x;

    printf("Kérek egy egész számot:");
    scanf("%d", &x);

    if (x%2 == 0)
        printf("A megadott szám páros.\n");
    else
        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!

Feladat: Írjuk meg if nélkül a fenti programot.



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

feltétel ? művelet ha igaz : művelet 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);

	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, 
    (y==0) ? "A kerdes ertelmetlen!" :
    ((x%y==0) ? "Igen, osztója." : "Nem, nem osztója.")
  );
}


    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) {
    case 1: 
      printf("Hétfő\n");
      break;
    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:
      printf("Hiba! x értéke legalább 1 és legfeljebb 7 lehet!\n");
  }
}


    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;

  i=1;
  while (i<=10) {
    printf("%d\n", i++);
  }

  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 {
    utasítás
} 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;
  int osszeg=0;

  do {
    printf("Kérek egy számot (kilépéshez: 0):");
    scanf("%d", &x);
    osszeg+=x;
  } while (x!=0);

  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;
  
  for (i=1, szorzat=1; i<=10; ++i) {
    szorzat*=i;
  }

  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)
    szorzat*=i;

  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,out;
   for (i=1, j=100, out=0; i<=10; i++, j--)
      out+=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.




Házi feladat

A házi feladatot megoldani nem kötelező és bemutatni sem kell, viszont a következő gyakorlaton visszakérhető (kikérdezés, táblához hívás, stb. formájában)! Ha a hallgató megoldása ötletes, szép kivitelezésű, plusz pont adható. Amennyiben viszont nem tudja megoldani gyakorlaton a házi feladatban szereplő példákat vagy nem tud válaszolni az azzal kapcsolatban feltett kérdésekre, mínusz pont adható. Plusz és mínusz pontból is egyaránt maximum 10 pontot gyűjthet össze egy-egy hallgató.

Házi feladat letöltése .

Gyakorlásra a PUB-ban lévő további házi feladatok megoldása: 02-hazi.txt, 03-hazi.txt .




    Jövő héten 2. miniZH (2014.09.29.)

Téma:

  C programozás (ezután mindig az lesz): 3. gyakorlat anyaga.

  Gyakorlásra:

    A honlapomon a 3. gyakorlathoz tartozó anyag, magyarázatokkal, példákkal (egy ismétléses példa a 4. gyakorlat elején).

    A gyakorlatok végén lévő házi feladat és gyakorló feladatok megoldása.

    A honlapom mellet 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ó:

  A gyakorlat 8:10-kor kezdődik és a ZH-t 8:15-kor kezdhetitek írni. Előreláthatóan 30 percetek lesz a feladat megoldására és beadására (tehát 8:45-ig). A feladatot 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ó!

     Vissza a lap tetejére.