Minta első NZH

Czirkos Zoltán · 2021.08.24.

Minta nagy ZH, előző évek feladataiból összeollózva.

Minta nagy ZH, néhány előző évekből származó feladatból összeállítva. Tudnivalók a feladatsor felhasználásával kapcsolatban: lásd itt. Vigyázat: ez csak minta. Nem minden évben ugyanakkor volt az első NZH, nem minden évben pont ugyanaddig terjedt az első NZH anyaga. A pontozás is tájékoztató jellegű.

Virágnyelv

BEUGRÓ: Írj függvényt, amelyik igazat ad, ha kisbetűs magánhangzót kapott (a, e, i, o, u)! Használd ezt a következő programodban!

Írj kétparaméterű függvényt, amely a második paraméterként kapott, angol ábécé kisbetűiből álló szöveg virágnyelvű változatát állítja elő az első paramétereként kapott helyen! Ez azt jelenti, hogy a magánhangzókat megkétszerezi, és közéjük egy 'v' betűt rak, pl. „viragnyelv” → „viviravagnyevelv”. Felteheted, hogy az első sztring elég nagy ahhoz, hogy elférjen benne az új szöveg.

Írj főprogramot, melyből meghívod a virágnyelv függvényt, és kiírsz egy feldolgozott szöveget!

Megoldás (de előtte próbáld meg te magad!)
#include <stdio.h>

int maganhangzo(char c) {
    return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}

void virag(char *cel, char *forras) {
    int iforr = 0, icel = 0;
    while (forras[iforr] != '\0') {
        cel[icel++] = forras[iforr];
        if (maganhangzo(forras[iforr])) {
            cel[icel++] = 'v';
            cel[icel++] = forras[iforr];
        }
        iforr++;
    }
    cel[icel] = '\0';
}

int main(void) {
    char eredmeny[50];
    virag(eredmeny, "viragnyelven");
    printf("%s\n", eredmeny);
}

BEUGRÓ: megvan-e a maganhangzo() függvény, helyes-e a fejléce; a virag() függvény használja-e.

Pontozás:

  • maganhangzo(): 1p fejléc, 1p karakter vizsgálata
  • virag(): 1p fejléc, 1p lezáró 0-ig ciklus (ciklusfeltételben strlen() nem ér pontot), 1p betűk másolása, 2p lezáró nulla
  • main(): 1p cél tömb, 1p saját függvény használata, 1p kiírás.

Időpontok

Definiálj típust, amelyben egy időpontot tudsz tárolni, külön óra (0...23), perc (0...59) és másodperc (0...59) értékekkel! Írj függvényt, amelyben paraméterként egy sztringet veszel át, benne egy időponttal! Értelmezd a sztringet, majd add vissza az időpontot az előbb definiált típussal! A sztringben az időpont az alábbi három forma egyikében lesz:

  • 23:17:06 – óra, perc, másodperc, mindegyik két számjeggyel;
  • 15h 09m 53s – itt is óra, perc, másodperc, mindegyik két számjeggyel;
  • 10:15 AM – itt az óra és a perc két-két számjeggyel, a másodperc pedig nincs megadva, 0-nak kell tekinteni. Ez a formátum 12 órás; 12:00 AM = éjfél, 08:00 AM = reggel 8, 12:00 PM = dél, 05:00 PM = a délután 5 órai tea időpontja, azaz 17 óra.

Írj főprogramot, amelyben létrehozol három időpontot tároló változót, és a megírt függvényt használva feltöltöd őket a fenti példaidőpontokkal!

Megoldás (de előtte próbáld meg te magad!)

Alább két megoldás is látható, de természetesen elég volt egy megoldást adni. Az első a sscanf() függvényen alapul; az jelzi, hogy hány számot sikerült beolvasni. Ha a formátum stimmel, akkor ez 3 kell legyen. A második megoldás nyersebb, közvetlenül a karakterekkel dolgozik. A lényege ennek is az, hogy valahogyan fel kell ismerni, melyik formátumról van szó. Ha a sztring ötödik karaktere egy kettőspont, akkor csak az első lehet; ha a sztring második karaktere egy h betű, akkor pedig a második.

#include <stdio.h>

typedef struct Idopont {
    int ora, perc, masodperc;
} Idopont;

Idopont megoldas1(char *szoveg) {
    Idopont i;
    char ampm;
    if (sscanf(szoveg, "%d:%d:%d", &i.ora, &i.perc, &i.masodperc) == 3)
        return i;
    if (sscanf(szoveg, "%dh %dm %ds", &i.ora, &i.perc, &i.masodperc) == 3)
        return i;
    sscanf(szoveg, "%d:%d %cM", &i.ora, &i.perc, &ampm);
    i.masodperc = 0;
    i.ora %= 12;
    if (ampm == 'P')
        i.ora += 12;
    return i;
}

Idopont megoldas2_seged(char *ora, char *perc, char *mperc) {
    Idopont i;
    i.ora = (ora[0]-'0') * 10 + (ora[1]-'0');             /* vagy stdlib.h atoi() */
    i.perc = (perc[0]-'0') * 10 + (perc[1]-'0');
    i.masodperc = (mperc[0]-'0') * 10 + (mperc[1]-'0');
    return i;
}

Idopont megoldas2(char *szoveg) {
    Idopont i;
    if (szoveg[5] == ':')
        return megoldas2_seged(szoveg+0, szoveg+3, szoveg+6);
    if (szoveg[2] == 'h')
        return megoldas2_seged(szoveg+0, szoveg+4, szoveg+8);
    i = megoldas2_seged(szoveg, szoveg+3, "00");
    i.ora %= 12;
    if (szoveg[6] == 'P')
        i.ora += 12;
    return i;
}

int main(void) {
    Idopont a = megoldas2("23:17:06");
    Idopont b = megoldas2("15h 09m 53s");
    Idopont c = megoldas2("10:15 AM");
}

A pontozás, az alábbi részfeladatok helyes megoldására:

  • 1 p, struktúra definíciója, struktúra típusú változó létrehozása
  • 1 p, char 'x' és sztring "x", aposztróf/idézőjel helyes használata
  • 2 p, sztring átadása függvénynek, sztringek helyes kezelése (indexelés stb.)
  • 2 p, algoritmus: időpont formátumok megkülönböztetése
  • 3 p, számok kiszedése a sztringekből (bármilyen módszerrel); am/pm kezelése
  • 1 p, főprogram, változók létrehozása, saját függvény helyes használata

Potenciális egyéb pontlevonások:

  • Sztringek helytelen kezelése
  • Lezáró nulla fogalmának nem ismerete, sztring méretének átadása
  • Túlindexelés
  • Kódduplikáció

Továbbá az általános pontozási irányelvek.

Szállóvendégek

Egy hétemeletes szállodában a szobafoglalásokat tömbben tárolják. A szobák a szokásos módon vannak számozva, a százasok adják meg az emeletet, a többi pedig a szoba sorszámát (pl. 712 = 7. emelet, 12. szoba). A földszint a 0. szint, utána 1-től 7-ig az emeletek. Ennél a feladatnál nem kell teljes programot írni, csak a megadott részeket.

  • BEUGRÓ: Definiálj Vendeg nevű típust, amelyik egy szállóvendég adatait (név: max. 50 karakter, szobaszám: egész) tartalmazza! Írj függvényt, amely átvesz egy vendéget, és visszaadja, hogy melyik emeleten lakik!
  • Írj függvényt, amely átvesz egy Vendeg elemekből álló tömböt és egy nevet! Keresse ez meg a névhez tartozó foglalást és adja vissza a megtalált tömbelem címét vagy NULL-t, ha nincs találat!
  • Írj függvényt, amely paraméterként kapja a vendégek tömbjét és egy másik, inicializálatlan tömböt, amelyet a szint sorszámával indexelünk! Írja be az utóbbi tömbbe, hogy az egyes emeleteken hány vendég lakik!
  • Írj függvényt, amely megkapja a vendégek tömbjét, az előző függvénnyel előállítja a betöltöttségek tömbjét, és végül visszatér a legzsúfoltabb emelet sorszámával – tehát azzal, ahol a legtöbb vendég van éppen!
Megoldás (de előtte próbáld meg te magad!)
typedef struct Vendeg {
    char nev[50+1];
    int szobaszam;
} Vendeg;

int emelet(Vendeg v) {
    return v.szobaszam / 100;
}

Vendeg *keres(Vendeg *vendegek, int meret, char *nev) {
    for (int i = 0; i < meret; ++i)
        if (strcmp(vendegek[i].nev, nev) == 0)
            return &vendegek[i];
    return NULL;
}

void betoltottseg(Vendeg *vendegek, int meret, int *szintek) {
    for (int i = 0; i <= 7; ++i)
        szintek[i] = 0;
    for (int i = 0; i < meret; ++i)
        szintek[emelet(vendegek[i])] += 1;
}

int legtobb_vendeg(Vendeg *vendegek, int meret) {
    int szintek[8];
    betoltottseg(vendegek, meret, szintek);
    int max = 0;
    for (int i = 1; i < 8; ++i)
        if (szintek[i] > szintek[max])
            max = i;
    return max;
}

Pontozás, beugró értékelési szempontjai:

  • BEUGRÓ: legyen struktúra, tartalmazzon egy sztringet és egy egész számot. (Ha 50-es a karaktertömb, akkor beugrónak elfogadható.) Legyen emelet függvény, amelynek a fejléce legyen rendben.
  • 1 p, struktúra (typedef nem kell). Ha 50 a tömb mérete, nem 51, nem jár a pont.
  • 1 p, emelet(). Simán szobaszám / 100, mert egész osztás van.
  • 2 p, keresés: 1 p algoritmus, 1 p sztring összehasonlítás (strcmp).
  • 3 p, betöltöttség: 1 p fejléc, 1 p nullázás (aminek itt kell megtörténnie!), 1 p hisztogram. A vendégtömb méretét át kell adni, a szinttömb méretét nem, de nem baj, ha ott van. A függvény visszaadhatja az int *szintek-et, de fölösleges. Nem a függvény dolga létrehozni a szintek tömbjét!
  • 3 p, legtöbb vendég: 1 p fejléc és visszatérési érték, 1 p tömb létrehozása + betoltottseg() hívása, 1 p maximum keresése. A maximum keresésében az indexet kell megjegyezni, mert az adja az emelet számát.

Súlyos hibák:

  • Tömbök/pointerek keverése. Pl. nem lehet a betöltöttség függvényben a szintek tömbjének létrehozása.
  • Tömb végén NULL, EOF és hasonló konstansok feltételezése.
  • Túlindexelés.

Továbbá az általános pontozási irányelvek.

Rendezés

BEUGRÓ: Írj függvényt, amely képes megcserélni két paraméterként kapott, valós típusú változó tartalmát!

Írj függvényt, amely paraméterként egy valósakat tartalmazó tömböt vesz át, továbbá két indexet, amelyek egy tartomány elejét és végét határozzák meg! Térjen vissza a függvény a megadott tartományból a legkisebb elem indexével!

Írj függvényt, amely paraméterként egy valós tömböt vesz át, és az előbbi két függvényt is felhasználva növekvő sorba rendezi a tömb számait!

Egészítsd ki ezeket egy főprogrammal, amely létrehoz egy 5 elemű tömböt, rendezi azt, majd kiírja a tömbelemeket sorszámozva!

Megoldás (de előtte próbáld meg te magad!)
#include <stdio.h>

void csere(double *x, double *y) {
    double temp = *x;
    *x = *y;
    *y = temp;
}

int minindex(double *tomb, int mettol, int meddig) {
    int min = mettol;
    for (int i = mettol + 1; i <= meddig; ++i)
        if (tomb[i] < tomb[min])
            min = i;
    return min;
}

void rendez(double *tomb, int meret) {
    for (int i = 0; i < meret - 1; ++i) {
        int min = minindex(tomb, i, meret - 1);
        if (min != i)
            csere(&tomb[i], &tomb[min]);
    }
}

int main(void) {
    double tomb[5] = {1.2, 3.5, 9.5, 3.4, 4.5};
    rendez(tomb, 5);
    for (int i = 0; i < 5; ++i)
        printf("%d. %g\n", i, tomb[i]);
}

Beugró: 1) cím szerinti paraméterek legyenek, 2) tudja használni a * operátort a cím szerint átvett változók kiolvasásához, írásához. Ha esetleg void csere(double tomb[], int i1, int i2) van, beugrónak elfogadható.

  • csere(): Két darab double* vagy float* paraméter, és pointerek dereferálása.
  • Lokális segédváltozó valós szám. Kell lennie segédváltozónak, lásd a következőt.
  • Háromlépéses csere. Xor csere nem lehet, mert nem int. *pa += *pb nem lehet, mert 1e40 + 1e-40 == 1e40.
  • minindex(): Fejléc és visszatérési érték helyes. Méret nem kell, mert a két index meghatározza.
  • Minimumkeresés, amely az indexet is képes megtalálni egy ciklusban. Ha értéket keres, aztán újabb ciklus az indexet, ez nem jár. Nem lehet double minval = 0, mert negatív szám is előfordulhat. A mintamegoldás mindkét végén zárt intervallummal dolgozik, de más is elképzelhető.
  • rendez(): Ciklus a paraméterként átvett méretet figyelembe véve.
  • Minimumkeresés függvény hívása.
  • Csere hívása helyes paraméterezéssel, &t[i] vagy t+i.
  • főprogram(): Tömb létrehozása és rendezése. Tömb kezdőcíme és mérete átadva; tomb és &tomb[0] jó, &tomb nem.
  • Tömb kiírása, indexek is látszódjanak.

Továbbá az általános pontozási irányelvek.