Kihagyás

7. gyakorlat

4. ZH

A gyakorlat elején 30 percben kerül megírásra a 4. zh. A feladat(ok) témái:

  • szintaktikus hibajavítás, szintaktikailag helytelen, nem fordítható forráskód (függvények) kijavítása a program elvárt viselkedésének megváltoztatása nélkül

Input/Output műveletek FILE-ból/ba

Feladat

Írj egy programot, ami beolvas két egész számot, majd kiírja az összegüket és a szorzatukat!

Lehetséges megoldás
1
2
3
4
5
6
7
8
#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;
}

Feladat

Módosítsuk úgy a programot, hogy az stdin és stdout változókat, valamint az fscanf és fprintf függvényeket használja!

Megjegyzés

Az stdin és stdout az úgynevezett standard bemeneti-kimeneti csatornák. Ezek az azonosítók az stdio.h-ban definiált FILE* típusú változók, és technikailag azonnal használhatók. A printf és scanf ezeket a csatornákat használják, ezeken keresztül kommunikálnak.

Az fscanf és fprintf pont úgy működik mint a scanf és printf, csak éppen tetszőleges fájlokat képesek kezelni (nem fixen a standard csatornákkal dolgoznak). Mindkettőnek van egy plusz paramétere (a paraméterlista elején, a formátumsztring előtt), ahol megadjuk, hogy milyen fájlt használjanak. Ide akár a standard fájlokat is megadhatjuk: az fscanf(stdin, ...) pontosan úgy fog működni, mint a hasonlóképpen felparaméterezett scanf(...), és az fprintf(stdout, ...) is ekvivalens a hasonlóan paraméterezett printf(...) függvényhívással.

Lehetséges megoldás
1
2
3
4
5
6
7
8
#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;
}

A fájlok adatfolyamként történő kezelése során egy FILE* típusú ún. filemutató azonosítja az állományt. (Ezt a típust az stdio.h headerfile deklarálja.)

1
FILE *nev;

Ahhoz, hogy a háttértáron levő fájl tartalmához hozzáférjünk, a fájlt meg kell nyitnunk. (Ez a "megnyitás" a standard fájlok esetében a program legelején automatikusan megtörténik, ezért lehet őket egyből használni.) A fájl megnyitását a fopen függvény hívásával végezhetjük el, melynek prototípusa:

1
FILE * fopen(const char *filename, const char *mode);

avagy meglévő FILE* esetén:

1
2
FILE* vmi;
vmi = fopen("megnyitandó fájl neve", "megnyitási mód");

A "megnyitandó fájl neve" sztringben annak a fájlnak az elérési útvonalát kell megadnunk, amivel dolgozni szeretnénk (pl.: "be.txt"). A "megnyitási mód" szintén egy sztring, amely a file elérésének módját és a fájl típusát határozza meg (pl.: "rb" vagy "at"). A leggyakoribb elérési módok:

mode sztring elérési mód
"r" Létező fájl megnyitása olvasásra.
"w" Új fájl megnyitása írásra. Ha fájl már létezik, akkor a tartalma elvész.
"a" File megnyitása hozzáírásra. A fájl tartalma megmarad, annak a végéhez tudunk írni. Ha a fájl nem létezett, akkor üresen létrejön.
"r+" Létező fájl megnyitása olvasásra, de akár írhatunk is bele.
"w+" Új fájl megnyitása írásra, de akár olvashatunk is belőle. Ha a fájl már létezik, akkor a tartalma elvész.
"a+" Fájl megnyitása hozzáírásra, de akár olvashatunk is belőle. Ha a fájl nem létezik, akkor üresen létrejön.

Fájltípusok:

mode sztring fájl típusa
"t" Text módú, szöveget változó hosszú sorokban tartalmazó fájl. Ha a megnyitási módban nem adjuk meg a fájl típusát jelző karaktert, akkor az text lesz.
"b" Bináris módú, adatot általában fix hosszúságú egységekben tartalmazó fájl.

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 fájlt.

1
fclose(vmi);

Feladat

Módosítsuk úgy az előző programot, hogy valódi fájlokat használjon!

Lehetséges megoldás
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#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 megnyitva
    outfile = fopen("ki.txt", "w");  // kimeneti fájl írásra megnyitva

    fscanf(infile, "%d %d", &a, &b);
    fprintf(outfile, "Osszeg: %d\nSzorzat: %d\n", a + b, a * b);

    fclose(infile);                  // bemeneti fájl lezárása
    fclose(outfile);                 // kimeneti fájl lezárása

    return 0;
}

be.txt

1
3 4

ki.txt

1
2
Osszeg: 7
Szorzat: 12

A be.txt-nek léteznie kell, viszont a ki.txt-t a program magától létrehozza (és ha létezett is előtte, a tartamát felülírja). 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.

Feladat

A program kezelje le, ha valamiért nem sikerül megnyitni valamelyik fájlt.

Segítség

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, az fopen visszatérési értéke NULL (azaz 0, vagyis hamis) lesz.

Lehetséges megoldás
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

int main() {
    int a, b;
    FILE *infile;
    FILE *outfile;

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

Feladat (f0193)

Problémafelvetés:

Írj egy programot, ami bekéri egy torta piskótájának sugarát és magasságát, majd kiszámolja a torta 1cm vastag bevonásához szükséges krém térfogatát 5%-os ráhagyással dolgozva. (A torta alját nem kell bekrémezni, csak az oldalát és a tetejé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. Az adatok tárolására használj összetett adatszerkezetet, ha van értelme. A program a bemenet.txt nevű fájlból olvassa be az adatokat és a kimenet.txt nevű fájlba írja ki az eredményt.

Ötlet

Vedd elő az 5. gyakorlat f0192-es gyakorló feladatának általad írt megoldását, és azt alakítsd át!

Lehetséges megoldás (m0193)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 *
 * Keleti Márton, 2018. őszi félév.
 *
 * Specifikáció:
 *    Input: két lebegőpontos szám, a torta sugara és magassága
 *    Output: 1 cm vastag tortabevonathoz szükséges krém térfogata +5%
 *
 * Algoritmustervezés:
 *    A torta tárolására létrehozunk egy henger struktúrát. A henger
 *    térfogatának és a a körlap területének kiszámítására külön függvényeket
 *    írunk. A bevonat mennyiségének meghatározásához kiszámoljuk a torta
 *    jelenlegi és 1 cm-rel megnövelt térfogatát is. A kettő különbsége plusz 5%
 *    lesz a megoldás.
 *
 * Fordítás:
 *    gcc -Wall -o m0193 m0193.c
 *
 * Futtatás:
 *    ./m0193
 */

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

typedef struct {
    double sugar;
    double magassag;
} henger;

double korterulet(double sugar) {
    return sugar * sugar * M_PI;
}

double terfogat(henger h) {
    return korterulet(h.sugar) * h.magassag;
}

double tortakrem(henger h) {
    henger uj = {.sugar = h.sugar + 1, .magassag = h.magassag + 1};
    double eredeti = terfogat(h);
    double bevont = terfogat(uj);
    return (bevont - eredeti) * 1.05;
}

int main() {
    henger torta;

    FILE* be = fopen("bemenet.txt", "r");
    if (be == NULL) {
        fprintf(stderr, "Hiányzik a \"bemenet.txt\"!\n");
        return 1;
    }
    fscanf(be, "%lf %lf", &torta.sugar, &torta.magassag);
    fclose(be);

    FILE* ki = fopen("kimenet.txt", "w");
    if (ki == NULL) {
        fprintf(stderr, "A \"kimenet.txt\" nem írható!\n");
        return 2;
    }
    fprintf(ki, "%lf\n", tortakrem(torta));
    fclose(ki);

    return 0;
}
Az alábbi videó egy hasonló (specifikációtól eltérő) megoldást mutat be:

f0193

Feladat (f0201)

Problémafelvetés:

Írj egy programot, ami kiszámolja, majd irányszöggel és nagysággal megadja a hasonlóképpen megadott fizikai erők sorozatának eredőjét a kétdimenziós térben. Az erők sorozatának végét egy 0 nagyságú erő jelzi.

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. Az adatok tárolására használj összetett adatszerkezetet, ha van értelme. A program a bemenet.txt nevű fájlból olvassa be az adatokat és a kimenet.txt nevű fájlba írja ki az eredményt.

Ötlet

Vedd elő az 5. gyakorlat f0200-as gyakorló feladatának általad írt megoldását, és azt alakítsd át!

Lehetséges megoldás (m0201)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2018. őszi félév.
 *
 * Algoritmustervezés/Megvalósítás:
 *    Kétféle főbb adattípusunk lesz, mindkettő a vektor reprezentálására. Az
 *    egyik a polárkoordináták (irányszög és nagyság, a szög fokokban), a
 *    másik a derékszögű koordinátarendszer (x és y koordináták) szerinti
 *    tárolásra. A konverziót az egyikről a másikra függvényekkel oldjuk meg.
 *    Az összegzéshez az (x,y) verziót használjuk (az egyszerűbb), és külön
 *    függvényt írunk rá.
 *
 * fordítás:
 *    gcc -o m0201 m0201.c -lm
 *
 * futtatás:
 *    ./m0201
 */

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

typedef struct {
    double x, y;
} vector_xy_t;

typedef struct {
    double irany, nagysag;
} vector_in_t;

vector_xy_t convert_to_xy(vector_in_t v) {
    vector_xy_t retval;
    retval.x = cos(v.irany * M_PI / 180.0) * v.nagysag;
    retval.y = sin(v.irany * M_PI / 180.0) * v.nagysag;
    return retval;
}

vector_in_t convert_to_in(vector_xy_t v) {
    vector_in_t retval;
    if (v.x == 0.0) {
        if (v.y == 0.0) {
            retval.irany = 0.0;
        } else {
            retval.irany = (v.y > 0.0) ? 90.0 : -90.0;
        }
    } else {
        retval.irany = atan(v.y/v.x) * 180.0 / M_PI;
        if (v.x < 0.0) {
            if (v.y < 0.0) {
                retval.irany -= 180.0;
            } else {
                retval.irany += 180.0;
            }
        }
    }
    retval.nagysag = sqrt(v.x*v.x + v.y*v.y);
    return retval;
}

vector_xy_t add(vector_xy_t a, vector_xy_t b) {
    vector_xy_t retval;
    retval.x = a.x + b.x;
    retval.y = a.y + b.y;
    return retval;
}

int main() {
    vector_in_t v_in;
    vector_xy_t v_xy, v_sum = { .x = 0.0, .y = 0.0 };
    FILE *f;
    if ((f = fopen("bemenet.txt", "r")) == NULL) {
        return 1;
    }
    scanf("%lf %lf", &v_in.irany, &v_in.nagysag);
    while (v_in.nagysag != 0.0) {
        v_xy = convert_to_xy(v_in);
        v_sum = add(v_sum, v_xy);
        scanf("%lf %lf", &v_in.irany, &v_in.nagysag);
    }
    fclose(f);
    v_in = convert_to_in(v_sum);
    if ((f = fopen("kimenet.txt", "w")) == NULL) {
        return 1;
    }
    printf("(%lf°, %lf)\n", v_in.irany, v_in.nagysag);
    fclose(f);
    return 0;
}

Rekurzió

Rekurziónak nevezzük, amikor egy függvény (közvetve vagy közvetlenül) önmagát hívja (bizonyos, a problémától függő feltételek teljesüléséig). A rekurzió sok esetben intuitív és elegáns megoldás egy problémára. Használata akkor ajánlott, ha egy bizonyos problémát önmaga "kisebb" verziójára tudunk visszavezetni. Vannak olyan problémák, melyek megoldása rekurzióval kifejezetten könnyebb mint iteratív módon (pl: Hanoi-tornyai probléma). Bizonyos problémák rekurzív megoldása viszont jelentős számítási- és memóriaigénnyel jár, ami miatt az esetek többségében mégis az iteratív megoldás ajánlott.

Feladat (f0126)

Feladat:

Számítsd ki \(n!\) értékét az \(n! = 1 * 2 * ... * (n-1) * n\) képlet segítségével nem rekurzív módon ciklussal, és a \(0! = 1\), \(n! = n * (n-1)!\) képlet segítségével rekurzív módon is! Próbáld ki a megoldásod egyre nagyobb számokra! Előbb-utóbb furcsa eredményeket fogsz kapni. Miért?

Lehetséges megoldás (m0126-1)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 *
 * Keleti Márton, 2018. őszi félév.
 *
 * Specifikáció:
 *    Input: egy n nem negatív egész szám
 *    Output: n! azaz n faktoriálisa
 *
 * Algoritmustervezés:
 *    Tudjuk, hogy a faktoriális definíciója: 0! = 1, n! = n * (n-1)
 *    Ez egy rekurzív definíció. Definiálunk egy fakt() függvényt, ami 1-nél
 *    kisebb számokra 1-et, minden más esetben n*fakt(n-1)-et ad vissza.
 *
 * Fordítás:
 *    gcc -Wall -o m0126-1 m0126-1.c
 *
 * Futtatás:
 *    ./m0126-1
 */

#include <stdio.h>

long fakt(int n) {
    if (n < 1) {
        return 1;
    } else {
        return n * fakt(n-1);
    }
}

int main() {
    int n;
    scanf("%d", &n);
    printf("%ld\n", fakt(n));
    return 0;
}
Lehetséges megoldás (m0126-2)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 *
 * Keleti Márton, 2018. őszi félév.
 *
 * Specifikáció:
 *    Input: egy n nem negatív egész szám
 *    Output: n! azaz n faktoriálisa
 *
 * Algoritmustervezés:
 *    Tudjuk, hogy a faktoriális definíciója: 0! = 1, n! = n * (n-1)
 *    Ez egy rekurzív definíció, azonban ha nem muszáj, kerüljük a rekurzív
 *    függvények használatát, ugyanis lassabbak és több memóriát használnak,
 *    mintha egy ciklust írnánk. Sajnos nem minden rekurzív függvényt lehet
 *    ciklussal helyettesíteni. Jelen esetben viszont ha kifejtjük a képletet,
 *    láthatjuk, hogy szerencsénk van:
 *    n * (n-1)! = n * (n-1) * (n-2)! = ... = n * (n-1) * (n-2) * ... * 2 * 1
 *    Tehát csak össze kell szoroznunk a számokat 1-től n-ig. 
 *
 * Fordítás:
 *    gcc -Wall -o m0126-2 m0126-2.c
 *
 * Futtatás:
 *    ./m0126-2
 */

#include <stdio.h>

long fakt(int n) {
    long eredmeny = 1;
    // 2-től indulunk, mert 1-gyel nincs értelme szorozni
    for (int i = 2; i <= n; ++i) {
        eredmeny *= i;
    }
    return eredmeny;
}

int main() {
    int n;
    scanf("%d", &n);
    printf("%ld\n", fakt(n));
    return 0;
}
Lehetséges megoldás (videó)

Az alábbi videó a fenti kettőhöz hasonló megoldásokat mutat be:

f0126

Sorozatok

Feladat (f0050)

Problémafelvetés:

Egy számtani sorozat első tagja \(A\), differenciája \(D\). Számítsa ki a sorozat \(N\)-dik tagját!

Információ

Egy sorozatot akkor nevezünk számtani sorozatnak, ha a szomszédos elemek különbsége – differenciája – (a sorozatra jellemző) állandó. Jele: \(d\).

Pl. \((a_1=1, d=1) \to 1,2,3,4,\dots\), vagy \((a_1=12, d=15) \to 12,27,42,57,72 \dots\)

Részletesen lásd: Wikipedia

Lehetséges megoldás (m0050)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2018. őszi félév.
 *
 * Algoritmustervezés:
 *    A program bekéri az adatokat, és az n. tagra vonatkozó képlet
 *    segítségével kiszámolja az elemet.
 *
 * Megvalósítás:
 *    Mindent a főprogram csinál.
 *
 * fordítás:
 *    gcc -o m0050 m0050.c
 *
 * futtatás:
 *    ./m0050
 */

#include <stdio.h>

int main() {
    double a, d;
    int n;
    printf("Az első tag: ");
    scanf("%lf", &a);
    printf("A differencia: ");
    scanf("%lf", &d);
    printf("Hányadik tagot számoljam? ");
    scanf("%d", &n);
    a += (n - 1) * d;
    printf("A sorozat %d. tagja %lf\n", n, a);
    return 0;
}

Az alábbi videó egy hasonló (specifikációtól eltérő) megoldást mutat be:

f0050

Feladat (f0052)

Problémafelvetés:

Egy mértani sorozat első tagja \(A\), hányadosa \(Q\). Számítsa ki a sorozat \(N\)-dik tagját!

Megvalósítás:

A math.h a tartalmaz egy kétparaméteres hatványozó függvényt, a

1
double pow(double,double)

függvényt, melynek első paramétere az alap, második paramétere a kitevő.

Információ

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. \((a_1=3, q=3) \to 3, 9, 27, 81, \dots\)

Részletesen lásd: Wikipedia

Lehetséges megoldás (m0052)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2018. őszi félév.
 *
 * Algoritmustervezés:
 *    A program bekéri az adatokat, és az n. tagra vonatkozó képlet
 *    segítségével kiszámolja az elemet.
 *
 * Megvalósítás:
 *    Mindent a főprogram csinál. Hatványozásra a pow(double, double)
 *    függvényt használjuk.
 *
 * fordítás:
 *    gcc -o m0052 m0052.c -lm
 *
 * futtatás:
 *    ./m0052
 */

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

int main() {
    double a, q;
    int n;
    printf("Az első tag: ");
    scanf("%lf", &a);
    printf("A hányados: ");
    scanf("%lf", &q);
    printf("Hányadik tagot számoljam? ");
    scanf("%d", &n);
    a *= pow(q, n - 1);
    printf("A sorozat %d. tagja %lf\n", n, a);
    return 0;
}

Az alábbi videó egy hasonló (specifikációtól eltérő) megoldást mutat be:

f0052

Algoritmus feladatok

Feladat (f0115)

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:

  • Az első egy mechanikus, ciklust használó algoritmus legyen.
  • A másik matematikailag átgondolt, minél egyszerűbb algoritmus legyen.

Hasonlítsd össze a két megoldás futásidejét! Ehhez használj long long int típusú értékeket (különben int használatával túlcsordulás nélkül még a hosszabb futásidejű algoritmus is túl gyorsan lefutna), és milliárdos (a mai processzorok GHz-es órajelével összevethető) nagyságrendű inputot. Futásidő mérésére használhatod a linux-os /usr/bin/time parancsot, például:

1
echo 1000 | /usr/bin/time -f %U program

Ez így a program érdemi része által felhasznált CPU időt mutatja (századmásodperc pontossággal). A program inputját azért érdemes ilyen módon megadni, hogy a beolvasás sebessége (a felhasználó nagyságrendekkel lassabb reakciója) minél kevésbé befolyásolja az eredményt. A programból vagy kétféle verziót kell fordítani (amik fixen a két függvény valamelyikét használják), vagy egy plusz inputtal választhatóvá kell tenni, hogy a program melyik függvénnyel dolgozzon.

Lehetséges megoldás (m0115)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2018. őszi félév.
 *
 * Algoritmustervezés:
 *    A program bekér egy karaktert majd egy számot, és a karakter alapján
 *    futtatja a megfelelő algoritmust.
 *
 * Megvalósítás:
 *    Egy programot írunk, benne két függvényt, és long long int típust
 *    használunk. A 'c' a ciklusos, a 'k' a képletes megoldást jelenti.
 *
 * fordítás:
 *    gcc -o m0115 m0115.c -lm
 *
 * futtatás:
 *    echo c 100000000 | /usr/bin/time -f %U ./m0115
 *    echo k 100000000 | /usr/bin/time -f %U ./m0115
 */

#include <stdio.h>

long long int ciklus(long long int n) {
    long long int sum = 0ll, i;
    for (i = 1ll; i <= n; ++i) {
        sum += i;
    }
    return sum;
}

long long int keplet(long long int n) {
    return n * (n + 1ll) / 2ll;
}

int main() {
    char a;
    long long int n, s;
    scanf("%c %lld", &a, &n);
    if (a == 'c') {
        s = ciklus(n);
    } else if (a == 'k') {
        s = keplet(n);
    } else {
        return 1;
    }
    printf("1 + ... + %lld = %lld\n", n, s);
    return 0;
}

Az alábbi videó egy hasonló (specifikációtól eltérő) megoldást mutat be:

f0115

Feladat (f0165)

Problémafelvetés:

Határozd meg egy \(N \times M\)-es véletlen értékű elemekkel feltöltött egész mátrix transzponáltját.

Specifikáció:

Az input két egész szám NxM alakban, ahol \(N\) és \(M\) (mindkettő maximum 128) a mátrix sorainak és oszlopainak száma.

Az output .csv formátumú (pontosvesszővel elválasztott) táblázat. Ebbe a bal felső saroktól kezdve kell kiírni a véletlen mátrixot, majd egy sor kihagyásával az első oszloptól kezdve a transzponáltját. Például 2x3 input esetén:

1
2
3
4
5
6
1;2;3;
4;5;6;
;
1;4;
2;5;
3;6;

Algoritmustervezés/Megvalósítás:

A .csv a Comma Separated Values rövidítése. Ez a formátum tetszőleges számú sort tartalmaz, ahol egy sort vesszővel (vagy tágabb értelemben véve pontosveszővel, kettősponttal vagy tabulátorral) elválasztott elemek sorozata alkot. A sor utolsó eleme után nem kötelező az elválasztó jel.

Segítség

Egy mátrix transzponáltját úgy kapjuk, hogy a mátrixot tükrözzük a főátlójára. Egy \(n\times m\)-es mátrixból egy \(m\times n\)-es mátrix lesz, az eredeti mátrix \((i,j)\) pozíciójú eleme a transzponálás után a \((j,i)\) pozícióba kerül. Pl. az

1
2
1 2 3
4 5 6
mátrixból transzponálás után
1
2
3
1 4
2 5
3 6
lesz.

Részletesen lásd: Wikipedia

Segítség

Egy C programban lehetőségünk van pszeudo-random (véletlenszerűnek tűnő) számok (számsorozat) generálására. Ehhez a program elején szükségünk lesz az alábbi include-okra:

1
2
#include <stdlib.h>
#include <time.h>

Ezután az első véletlenszám generálása előtt (praktikusan valahol a main függvény elején) a véletlenszám-generátort is inicializálni kell:

1
srand(time(NULL));

Végül, ahol egy véletlen számra van szükségünk, ott a rand(); függvényt hazsnálhatjuk, pl.:

1
veletlen = rand();
Ez egy előre megadott intervallumba eső nemnegatív egész számot ad vissza. Ha nekünk kisebb intervallum kell, akkor nézhetjük a kapott érték maradékát: pl. a rand() % 7 kifejezés egy \([0, 6]\) közötti véletlenszámot fog adni.

Videó a randomszám generálásról:

Random szám generálás

Lehetséges megoldás (m0165)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 *
 * Keleti Márton, 2018. őszi félév.
 *
 * Specifikáció:
 *    Input: két egész szám "NxM" alakban, N és M <= 128
 *    Output: .csv formátumú (pontosvesszővel elválasztott) táblázat az eredeti
 *            és a transzponált mátrixszal
 *
 * Algoritmustervezés:
 *    Beolvassuk N-t és M-et egy-egy változóba, majd lefoglalunk egy NxM-es
 *    egész számokból álló tömböt. Dupla for ciklussal végigmegyünk az elemein
 *    és a rand() függvény segítségével értéket adunk nekik. Az első kiíratás
 *    ugyanúgy megy, mint a feltöltés. A másodiknál viszont transzponálnunk
 *    kell, ehhez az indexelést felcseréljük (azaz nem sorfolytonosan, hanem
 *    oszlopfolytonosan járjuk be a tömböt). Vigyázzunk, nehogy túlindexeljük
 *    a tömböt!
 *
 * Fordítás:
 *    gcc -Wall -o m0165 m0165.c
 *
 * Futtatás:
 *    ./m0165
 */

#include <stdio.h>
#include <stdlib.h>  // rand() és srand() függvények miatt
#include <time.h>    // time() függvény miatt

int main() {
    // véletlenszámgenerátor inicializálása az aktuális időre,
    // így minden futásnál más eredményt fogunk kapni
    srand(time(NULL));

    int n, m;
    scanf("%dx%d", &n, &m);

    int tomb[n][m];
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            tomb[i][j] = rand();
        }
    }

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            printf("%d;", tomb[i][j]);
        }
        printf("\n");
    }

    printf(";\n");

    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            printf("%d;", tomb[j][i]);
        }
        printf("\n");
    }


    return 0;
}

Az alábbi videók a mátrix transzponálását illetve véletlen feltöltését mutatják be:

mx_tr

mx_rnd

A feladat megoldásához közvetlenül ugyan nem kapcsolódnak, de segíthetnek a mátrixkezelés gyakorlásában. A két kapcsolódó videó a mátrix feltöltését illetve kiírását mutatják be mind fájlból, illetve fájlba történő műveletekkel.

mx_rf

mx_wf

Feladat (f0167)

Problémafelvetés:

Határozd meg egy \(N \times M\)-es véletlen értékű elemekkel feltöltött egész mátrix minden egyes sorának és oszlopának minimumát és maximumát is.

Specifikáció:

Az input két egész szám NxM alakban, ahol \(N\) és \(M\) (mindkettő maximum 128) a mátrix sorainak és oszlopainak száma.

Az output .csv formátumú (pontosvesszővel elválasztott) táblázat. Ennek az első és második sorába az oszlopok minimális illetve maximális elemeit, első és második oszlopába a sorok minimális és maximális elemeit kell kiírni. A harmadik sor illetve harmadik oszlop üres, kivéve az első két-két cellát, melyek értéke a "Min." és "Max." szöveg. A mátrix első sorának első eleme a táblázat negyedik sorának negyedik oszlopába kerül. A táblázat bal felső sarkában \(2\times 2\) cella üresen marad. Például 3x3 input esetén:

1
2
3
4
5
6
;;"Min.";1;2;3
;;"Max.";7;8;9
"Min.";"Max."
1;3;;1;2;3
4;6;;6;5;4
7;9;;7;8;9

Algoritmustervezés/Megvalósítás:

A .csv a Comma Separated Values rövidítése. Ez a formátum tetszőleges számú sort tartalmaz, ahol egy sort vesszővel (vagy tágabb értelemben véve pontosveszővel, kettősponttal vagy tabulátorral) elválasztott elemek sorozata alkot. A sor utolsó eleme után nem kötelező az elválasztó jel.

Lehetséges megoldás (m0167)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2018. őszi félév.
 *
 * Algoritmustervezés/Megvalósítás:
 *    Mivel tömbökkel dolgozunk, aminek a túlindexelése veszélyes a
 *    memóriára, a megadott méreteket megvizsgáljuk. Ezután az eleve
 *    lefoglalt 128x128-as mátrix megfelelő (NxM-es) részét feltöltjük
 *    0 és 99 közötti véletlen elemekkel. A sor- és oszlopminimumokat és
 *    -maximumokat a sor illetve oszlop első elemével tudjuk biztonságosan
 *    inicializálni. Ezután végigmegyünk a mátrix minden elemén és
 *    megnézzük, hogy ő-e a minimum/maximum a sorában és/vagy az oszlopában.
 *
 * fordítás:
 *    gcc -o m0167 m0167.c
 *
 * futtatás:
 *    ./m0167
 */

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

#define MAX_VALUE 100
#define MAX_SIZE  128

int matrix[MAX_SIZE][MAX_SIZE];

int main() {
    int N = 0, M = 0, i, j;
    int omin[MAX_SIZE], omax[MAX_SIZE], smin[MAX_SIZE], smax[MAX_SIZE];
    scanf("%dx%d", &N, &M);
    /* Ellenőrzés, hogy elkerülhessük a tömb alul- illetve túlindexelését */
    if (N < 1 || M < 1 || MAX_SIZE < N || MAX_SIZE < M) {
        fprintf(stderr, "A mátrix mérete legalább 1x1 és legfeljebb %dx%d lehet!\n", MAX_SIZE, MAX_SIZE);
        return 1;
    }
    /* Mátrix feltöltése */
    srand(time(NULL)); // Hogy ne mindig ugyanazt a véletlen sorozatot kapjuk ;)
    for (i = 0; i < N; ++i) {
        for (j = 0; j < M; ++j) {
            matrix[i][j] = rand() % MAX_VALUE;
        }
    }

    /* Sor minimum és maximum inicializálás*/
    for (i = 0; i < N; ++i) {
        smin[i] = matrix[i][0];
        smax[i] = matrix[i][0];
    }

    /* Oszlop minimum és maximum inicializálás*/
    for (j = 0; j < M; ++j) {
        omin[j] = matrix[0][j];
        omax[j] = matrix[0][j];
    }

    /* Sor és oszlop minimum és maximum számítás */
    for (i = 0; i < N; ++i) {
        for (j = 0; j < M; ++j) {
            int mij = matrix[i][j];
            if (mij < smin[i]) {
                smin[i] = mij;
            } else if (mij > smax[i]) {
                smax[i] = mij;
            }
            if (mij < omin[j]) {
                omin[j] = mij;
            } else if (mij > omax[j]) {
                omax[j] = mij;
            }
        }
    }

    /* Kiíratás */
    // Az első sor elemei ...
    printf(";;\"Min.\"");
    for (j = 0; j < M; ++j) {
        // ... az oszlopminimumok.
        printf(";%d", omin[j]);
    }
    // A második sor elemei ...
    printf("\n;;\"Max.\"");
    for (j = 0; j < M; ++j) {
        // ... az oszlopmaximumok.
        printf(";%d", omax[j]);
    }
    // A harmadik sor fix.
    printf("\n\"Min.\";\"Max.\"\n");
    // A további sorok ...
    for (i = 0; i < N; ++i) {
        // ... minimuma és maximuma ...
        printf("%d;%d;", smin[i], smax[i]);
        for (j = 0; j < M; ++j) {
            // ... majd a sor elemei.
            printf(";%d", matrix[i][j]);
        }
        printf("\n");
    }
    return 0;
}

Feladatok

Feladat (f0051)

Problémafelvetés:

Egy számtani sorozat első két tagja \(A_1\) és \(A_2\). Számítsa ki a sorozat \(N\)-dik tagját!

Feladat (f0053)

Problémafelvetés:

Egy mértani sorozat első két tagja \(A_1\) és \(A_2\). Számítsa ki a sorozat \(N\)-dik tagját!

Feladat (f0124)

Problémafelvetés:

Írj programot, amelyben a felhasználónak egy, a program által meghatározott számot kell kitalálnia! A felhasználó tippjét a program vagy elfogadja, vagy megmondja, hogy a gondolt szám annál kisebb vagy nagyobb, és kéri a következő tippet!

Algoritmustervezés/Megvalósítás:

A kitalálandó szám és a tippelt érték viszonyát egy külön függvény határozza meg, de a kiírás már a főprogramban történjen! Készíts többféle algoritmust és megvalósítást. Először oldd meg a feladatot megkötések nélkül, majd úgy, hogy az alábbi megszorítások közül kiválasztasz egyet, és azt betartod:

  • A for, while és do-while közül csak a for szerkezetet használhatod.
  • A for, while és do-while közül csak a while szerkezetet használhatod.
  • A for, while és do-while közül csak a do-while szerkezetet használhatod.
Feladat (f0171)

Problémafelvetés:

Egy könyvelő minden év végén statisztikát készít az általa kezelt cégek havi eredményességéről. A cégek havi bevétele és kiadása alapján kiszámolja a:

  • minimális, maximális és átlagos havi bevételt,
  • minimális, maximális és átlagos havi kiadást,
  • minimális, maximális és átlagos havi pénzügyi eredményt,
  • a relatív pénzügyi eredményesség (profit) alapján a hónapok rangsorát.

Specifikáció:

Az input egy 2 oszlopot és 12 sort tartalmazó, elválasztó karakterként ';'-t használó .csv fájl. Az első oszlop a havi bevétel, a második a havi kiadás, az n. sor az n. hónap értékeit tartalmazza.

Az output egy ';'-vel elválasztott .csv fájl. Az első 4 sora a havi bevétel, kiadás és pénzügyi eredmény statisztikáit mutatja. Az első sor első cellája üres, a következő három oszlopban rendre a "min.", "max." és "átlag" szövegek szerepelnek. A következő három sorban az első oszlop a "Bevétel", "Kiadás" és "Eredmény" szövegeket, a következő 3 oszlop rendre a kiszámított minimális, maximális és átlagos értékeket tartalmazza. Az 5. sor üres, a 6. sor első három cellája a "Hónap", "Profit%" és "Eredmény" szövegeket tartalmazza. A következő 12 sor rendre a hónapok neveit, valamint a hozzájuk tartozó profit (eredmény/bevétel) százalékos értékét (két tizedesjegy pontossággal) és a pénzügyi eredményt tartalmazza, a profit szerint csökkenő sorrendben. Profitegyenlősség esetén a magasabb eredmény kerül előbbre, ha az is egyenlő, akkor a korábbi hónap.

Feladat (f0202)

Problémafelvetés:

Írj egy programot, ami bekéri a tér 4 pontjának koordinátáit, és számítsd ki az általuk meghatározott test felszínét. Feltehető, hogy a 4 pont nem egy síkba esik.

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. Az adatok tárolására használj összetett adatszerkezetet, ha van értelme.

Feladat (f0204)

Problémafelvetés:

Írj egy programot, ami adott nehézségi gyorsulás (\(g=9,81 m/s^2\)) mellett szimulálja egy \(\alpha\) kilövési szögben és \(v\) kezdősebességgel kilőtt test röppályáját légüres térben sík terepen. A felhasználó adja meg a kilövési paramétereken túl azt is, hogy a kezdő és végpontokon kívül teljes repülési időt hány egyenlő részre osztva kell meghatározni és kiírni a test helyzetét (\(x,y\) koordinátáit).

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. Az adatok tárolására használj összetett adatszerkezetet, ha van értelme.

További gyakorló feladatok

Feladat (f0118)

Feladat:

Írj programot, mely bekér egy természetes számot, és kiszámítja a Fibonacci-sorozat n-ik elemét! A Fibonacci-sorozat nulladik és első eleme 1, a többi pedig az őt megelőző két elem összege. Készíts kétféle algoritmust két külön függvényben, és mindkettővel számoltasd ki az eredményt:

  • Az első egy rekurzív algoritmus legyen.
  • A másik átgondolt, ciklust használó algoritmus legyen.

Hasonlítsd össze a két megoldás futásidejét!

Lehetséges megoldás (videó)

Az alábbi videó a Fibonacci-sorozat elemeinek rekurzív kiszámítását mutatja be:

f0118

Feladat (f0135)

Problémafelvetés:

Készíts egy programot, amely kiírja egy \(4 \times 4\)-es egész mátrix transzponáltját.

Specifikáció:

Az input 16 darab -99999 és 99999 közötti egész szám, a mátrix elemei sorfolytonosan megadva. Az output a mátrix és a mátrix transzponáltja "szépen formázva", azaz 4 sorban 4-4 egymás alá igazított egész értékkel.

Feladat (f0195)

Problémafelvetés:

Írj egy programot, ami megmondja, hogy egy hallgató teljesítette-e a félévet programozás alapjai gyakorlatból.

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. Készíts egy adatszerkezetet, amiben a hallgató nevét, pontjait tároljuk. A program tároljon külön minden részpontszámot és a hiányzásokat is. A program a bemenet.txt nevű fájlból olvassa be az adatokat és a kimenet.txt nevű fájlba írja ki az eredményt.

Ötlet

Vedd elő az 5. gyakorlat f0194-es gyakorló feladatának általad írt megoldását, és azt alakítsd át!

Feladat (f0203)

Problémafelvetés:

Írj egy programot, ami bekéri a tér 4 pontjának koordinátáit, és számítsd ki az általuk meghatározott test felszínét. Feltehető, hogy a 4 pont nem egy síkba esik.

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. Az adatok tárolására használj összetett adatszerkezetet, ha van értelme. A program a bemenet.txt nevű fájlból olvassa be az adatokat és a kimenet.txt nevű fájlba írja ki az eredményt.

Ötlet

Vedd elő az f0202-es gyakorló feladat általad írt megoldását, és azt alakítsd át!

Feladat (f0205)

Problémafelvetés:

Írj egy programot, ami adott nehézségi gyorsulás (\(g=9,81 m/s^2\)) mellett szimulálja egy \(\alpha\) kilövési szögben és \(v\) kezdősebességgel kilőtt test röppályáját légüres térben sík terepen. A felhasználó adja meg a kilövési paramétereken túl azt is, hogy a kezdő és végpontokon kívül teljes repülési időt hány egyenlő részre osztva kell meghatározni és kiírni a test helyzetét (\(x,y\) koordinátáit).

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. Az adatok tárolására használj összetett adatszerkezetet, ha van értelme. A program a bemenet.txt nevű fájlból olvassa be az adatokat és a kimenet.txt nevű fájlba írja ki az eredményt.

Ötlet

Vedd elő az f0204-es gyakorló feladat általad írt megoldását, és azt alakítsd át!

Feladat (f0207)

Problémafelvetés:

Adott két körszerű test a kétdimenziós síkon. A testek helyzetét a középpontjaikkal azonosítjuk. Kezdetben a felhasználó mindkét testhez megadja:

  1. a középpontját \(x,y\) koordinátákkal,
  2. sugarát,
  3. kezdősebességét és annak irányát, valamint
  4. a test tömegét.

Megad továbbá egy \(\Delta t\) és egy \(T\) időintervallumot. A feladat a két test kétdimenziós fizikai mozgásának szimulálása a \(0..T\) időintervallumban \(\Delta t\) időbeosztással. Ez azt jelenti, hogy a kezdő időpontban kiszámoljuk a testekre ható erőket, majd a test mozgását a következő \(\Delta t\) időintervallumban úgy közelítjük, mintha a testre ebben az időintervallumban nem hatna egyéb erő. Ezután újra kiszámítjuk az erőket, majd újra közelítjük a mozgást, stb. A mozgás szimulálása a \(T\) időpontig vagy a két test "ütközéséig" tart. A pontosság kedvéért a két test helyzetét (\(x,y\) koordinátáit) úgy írassuk ki, mintha az origo, azaz a koordinátarendszer középpontja a két test közös tömegközéppontja lenne, azaz a kiszámított koordinátaértékeket ezek szerint korrigáljuk minden lépésben.

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. Az adatok tárolására használj összetett adatszerkezetet, ha van értelme. A program a bemenet.txt nevű fájlból olvassa be az adatokat és a kimenet.txt nevű fájlba írja ki az eredményt.

Ötlet

Vedd elő az 5. gyakorlat f0206-os gyakorló feladatának általad írt megoldását, és azt alakítsd át!

Grafikus szorgalmi feladatok

A grafikus programozás nem lesz számonkérve, de rekurzióval érdekes ábrákat lehet vele produkálni.

Feladat (fgr06)

Problémafelvetés:

Rajzolj egy n-ed rendű szabályos háromszöget az alábbi ábrák alapján, ahol

  • a 0. rendű háromszög egy "hagyományos" szabályos háromszög, oldalai egyenes vonalak,
  • egy n-ed rendű "nagy" háromszög oldalainak középső illetve első és harmadik harmada pedig ki van cserélve alacsonyabb rendű háromszögekre a példákon látható módon, és
  • csak az alakzat külső vonalait kell megrajzolni.

Az n értéket (n≥0) a program indulás után kérje be!

Megvalósítás:

A paint.h segítségével egy ablakban rajzoljuk ki a "háromszöget".

Példák n-ed rendű háromszögre:

paint01

Lehetséges megoldás (mgr06.c)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* Grafikus példaprogram C nyelvhez.
 *
 * Rekurzív háromszögrajzolás.
 *
 * Gergely Tamás, gertom@inf.u-szeged.hu
 */

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

void line_at_level(int lvl, float len) {
    if (lvl > 0) {
        line_at_level(lvl - 2, len / 3.0);
        right(60.0);
        line_at_level(lvl - 1, len / 3.0);
        left(120.0);
        line_at_level(lvl - 1, len / 3.0);
        right(60.0);
        line_at_level(lvl - 2, len / 3.0);
    } else {
        forward(len);
    }
}


int main() {
    int lev = 0;
    scanf("%d", &lev);

    create_window(800, 800);

    hide_cursor();
    set_speed(5+lev);
    jump_to_position(400.0, 60.0);
    turn_to(120.0);
    pen_down();

    for (int i = 0; i < 3; ++i) {
        line_at_level(lev, 600.0);
        left(120.0);
    }

    save_image("reqtri.ppm");

    close_window();

    return 0;
}
Feladat (fgr07)

Problémafelvetés:

Rajzolj egy n-ed rendű négyzet, ahol

  • a 0. rendű négyzet egy "hagyományos" négyzet, oldalai egyenes vonalak,
  • egy n-ed rendű négyzet oldalainak középső illetve első és harmadik harmada ki van cserélve egy-egy alacsonyabb rendű négyzetre az ábrán látható módon, és
  • csak az alakzat külső vonalait kell megrajzolni (ha a külső vonal egyetlen csúcsban érinti önmagát, akkor a "hurok" rész is külső vonalnak számít).

Az n értéket (n≥0) a program indulás után kérje be!

Megvalósítás:

A paint.h segítségével egy ablakban rajzoljuk ki a "négyzetet".

Példák n-ed rendű négyzetre:

paint01

Lehetséges megoldás (mgr07.c)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/* Grafikus példaprogram C nyelvhez.
 *
 * Rekurzív négyszögrajzolás.
 *
 * Gergely Tamás, gertom@inf.u-szeged.hu
 */

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

void line_at_level(int lvl, float len) {
    if (lvl > 0) {
        line_at_level(lvl - 2, len / 3.0);
        right(90.0);
        for (int i=0; i<3; ++i) {
            line_at_level(lvl - 1, len / 3.0);
            left(90.0);
        }
        left(180.0);
        line_at_level(lvl - 2, len / 3.0);
    } else {
        forward(len);
    }
}


int main() {
    int lev = 0;
    scanf("%d", &lev);

    create_window(800, 800);

    hide_cursor();
    set_speed(5+lev);
    jump_to_position(200.0, 200.0);
    turn_to(90.0);
    pen_down();

    for (int i = 0; i < 4; ++i) {
        line_at_level(lev, 400.0);
        left(90.0);
    }

    save_image("reqrec.ppm");

    close_window();

    return 0;
}

Kapcsolódó linkek


Utolsó frissítés: 2022-11-25 15:25:14