Kihagyás

4. gyakorlat

1. ZH

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

  • függvények megírása, bemenet/kimenet kezeléssel
  • bemeneti/kimeneti műveletek
  • változók használata, alapműveletek

A zh-t a bíró rendszeren keresztül kell leadni az óra időpontjában.

Tömbök

Gyakran előfordul, hogy egyszerre több azonos típusú adattal, adatok sorozatával kellene dolgoznunk. Ilyenkor egyrészt lehetetlen minden egyes adatnak külön változónevet találni, másrészt nem is lenne praktikus. Ehelyett használhatunk tömböket, amik több azonos típusú változó egyben tárolására/kezelésére valók. Deklarációnál meg kell adnunk, hogy hány darab azonos típusú változóra lesz szükségünk, és ezután ezekre a változókra a tömb nevével és egy sorszámmal/indexszel hivatkozhatunk.

A tömb deklarációjának általános alakja:

típus név[méret];

Például, egy 10 darab egész érték tárolására alkalmas tömb (10 darab egész változóból álló tömb) létrehozása:

int tomb[10];

A tömbök egyes elemeire egy úgynevezett index-szel lehet hivatkozni, ami tulajdonképpen a tömbben lévő elemek (majdnem) sorszáma. Azért majdnem, mert C-ben a tömbindexelés 0-tól kezdődik, vagyis a tömb első elemének indexe 0. Ennek megfelelően egy N méretű (N elemet tartalmazó) tömb utolsó eleme az N-1. indexen érhető el. Például az előbb deklarált tömb sorban 4., azaz 3. indexű elemére így hivatkozhatunk:

tomb[3]

Ez a hivatkozás így ahogy van felel meg egy változónak, vagyis pl. értéket adhatunk neki, vagy képletben használhatjuk.

Figyelj oda!

A C programban nem tudod lekérdezni egy tömbben tárolt elemek számát, ez az információ egész egyszerűen nem tárolódik el (legalábbis nem C nyelvi szinten hozzáférhető módon) automatikusan a programban. Ha szükség van erre az adatra (márpedig általában szükség lesz), annak a tárolásáról, megőrzéséről neked kell gondoskodnod (pl. konstansként lehet definiálni, vagy egy külön változóban lehet tárolni)!

Ebből az is következik, hogy C-ben nincs indexhatár-ellenőrzés. Vagyis egy 10 elemű tömbnek hivatkozhatsz a 100., sőt, akár -100. elemére is: a program ilyenkor hiba nélkül lefordítható, de a működése definiálatlan. Ez azt jelenti, hogy ha szerencséd van, akkor elszáll memóriahibával, ha nincs, akkor pedig csak egyszerűen rosszul fog működni anélkül, hogy észrevennéd.

Amiért a tömbök igen használhatóak lesznek az az, hogy a tömbindexet futás közben tudjuk kiszámolni. Ellentétben a tömb méretével, amit már konstansként/konstans értékként a program megírásakor (úgymond fordítási időben) meg kell adni, az indexek értékeit elég, ha futásidőben ki tudjuk számolni valamilyen kifejezés segítségével (ami lehet pl. akár egy egyszerű változó is). Ilyen módon akár egy ciklussal is végig tudunk haladni a tömb elemein, de az indexek helyes kezelésére nagy figyelmet kell fordítani! (Egyébként, ha tömbünk van, akkor elég nagy az esélye, hogy valamilyen ciklus is lesz a programban, és az szintén nagy valószínűséggel for lesz.) Egy N elemű tömböt tipikusan a

for (i = 0; i < N; ++i) { ... tomb[i] ... }

ciklusszervezéssel tudunk bejárni.

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!

Megoldás

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#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 sorban a tömb elemein és mindnek értéket adunk,
                            // méghozzá úgy, hogy az i. indexű elem az i+1 értéket kapja.
    }
    for (i = 0; i < M; ++i) {
        printf(" %d", tomb[i]);
    }
    return 0;
}

Kicsit eltérő eredménnyel, de a következő videó is ezt a feladatot oldja meg:

array_1

Nagyon fontos megkülönböztetni a tömbelem indexét és értékét. Az index az egy sorszám, a változóhivatkozásnak a megfelelő tömbelem kiválasztásához szükséges része, míg az érték az az adat, amit az adott tömbelemben tárolunk.

tömbelem index 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
tömbelem érték 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?

Válaszok

Ha M < N az nem gond, csupán annyi történik, hogy nem használjuk ki a teljes tömböt. Ha N < M az viszont baj, hiszen "túlindexeljük" a tömböt, azaz olyan indexű tömbelemet is használunk, ami nem létezik. Ha kicsi az eltérés, az általában hibás számítást eredményez, és nagyon nehéz észrevenni. Ha nagy az eltérés, akkor általában memóriahibával fog elszállni a program.

Egy tömbnek az alábbi módon adhatunk kezdőértéket (incializálás, értékadás a deklarációval együtt):

int tomb[10] = {2, 3, 4, 7, 6, 5, 10, 9, 8, 1};

Ennek az eredménye az alábbi tömb:

tömbelem index 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
tömbelem érték 2 3 4 7 6 5 10 9 8 1

Vigyázz!

Az = művelet nem használható arra, hogy a teljes tömbnek értéket adjunk. A tomb = {2, 3, 4, 7, 6, 5, 10, 9, 8, 1};, vagy akár egyiktomb = masiktomb; (ahol a deklaráció mondjuk int tomb[10], egyiktomb[10], masiktomb[10];) műveletek C-ben fordítási hibát okoznak!

Készíthetünk többdimenziós tömböket is. Ezek tulajdonképpen olyan egydimenziós tömbök, amiknek az elemei szintén tömbök. Egy kétdimenziós tömb deklarációja például így néz ki:

int matrix[3][7];

Ez egy 3 sorból és 7 oszlopból, azaz összesen 21 elemből álló kétdimenziós tömb.

kétdimenziós mátrix indexei 0. 1. 2. 3. 4. 5. 6.
0. [0][0] [0][1] [0][2] [0][3] [0][4] [0][5] [0][6]
1. [1][0] [1][1] [1][2] [1][3] [1][4] [1][5] [1][6]
2. [2][0] [2][1] [2][2] [2][3] [2][4] [2][5] [2][6]

Egy egyszerű kétdimenziós tömb létrehozását és elemeinek kiírását mutatja be a következő videó:

2d_tomb

Feladat

Készíts egy \(3 \times 3\)-as mátrixot, töltsd fel elemekkel, majd írasd ki az elemeit sor- illetve oszlopfolytonosan is!

Megjegyzés

A sorfolytonos kiíratás az, amikor végigmegyünk az első soron, balról jobbra kiíratva az elemeket, utána a második, majd harmadik, stb. sorokkal tesszük ugyanezt. Az oszlopfolytonos kiíratás pedig az, amikor először az első oszlop elemeit íratjuk ki fentről lefelé, utána a második, majd harmadik, stb. oszlopokkal tesszük ugyanezt. Mindkét kiíratás eredménye egyetlen számsor, tehát a "mátrix alak" elveszik.

Megoldás

 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
#include <stdio.h>

#define N 3

int main() {
    int tomb[N][N];
    int i, j;
    for (i = 0; i < N; ++i) {           //  a különböző ciklusokat egybásba is lehet ágyazni
        for (j = 0; j < N; ++j) {       // jelen esetben N-szer fog lefutni a külső for ciklus
            scanf("%d", &(tomb[i][j])); // és (N*N)-szer a belső
        }
    }
    for (i = 0; i < N; ++i) {            // természetesen itt is és a következőnél is ugyanaz a helyzet
        for (j = 0; j < N; ++j) {
            printf("%d ", tomb[i][j]);
        }
        printf("\n");
    }
    printf("\n");
    for (j = 0; j < N; ++j) {
        for (i = 0; i < N; ++i) {
            printf("%d ", tomb[i][j]);
        }
        printf("\n");
    }
    return 0;
}

Feladat (f0136)

Problémafelvetés:

Készíts egy programot, amely beolvas legfeljebb 128 egész számot, eltárolja őket egy tömbben, lecseréli a tömbelemeket az abszolút értékeikre, majd kiírja a tömböt.

Specifikáció:

A program inputjának első eleme egy 0 és 128 közötti N egész szám, majd N darab további egész szám. A program kimenete N darab nemnegatív egész szám, szóközökkel elválasztva, a végén sortöréssel.

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

A számok tárolására készítsünk egy előre megadott fix méretű tömböt. Ezt a tömböt és a beolvasandó számok darabszámát a főprogram kezelje. A tömb elemeinek beolvasását, az elemek cseréjét és a kiírást is egy-egy külön függvény végezze, amely megkapja a tömböt és a tömbméretet is.

Megjegyzés

Egy függvény paramétere lehet tömb is. Ilyenkor a paraméter deklarációjában simán a [] jelölést használjuk, nem adjuk meg a tömbméretet, pl.:

int tombotkezel(int parametertomb[]) { ... }

Ez két dolog miatt lehetséges: az első, hogy híváskor a függvény nem az argumentumként megadott tömb értékeit, hanem magát a tömböt kapja meg, ami akkora, amekkorának a függvényen kívül deklaráltuk; másrészt, mivel C-ben nincs indexhatár-ellenőrzés, tök mindegy mekkora értéket írnánk be tömbméretként, úgyis bármilyen indexet tudnánk használni.

Vigyázz!

Ha egy függvény egy tömböt vár paraméterként, akkor híváskor nem az argumentumként megadott tömb értékeit, hanem magát a tömböt kapja meg. Vagyis a tömb paraméter nem csak felveszi a megadott tömb argumentum értékeit (mint ahogyan az egy egyszerű változó esetén történik), hanem azonos lesz vele. Ennek pedig az a következménye, hogy ha a függvény a paraméterként kapott tömbben megváltoztatja egy tömbelem értékét, akkor tulajdonképpen az argumentumként kapott tömb elemének értékét változtatja meg. Vagyis a függvényben végzett (tömbelemeket érintő) művelet hatással lesz a függvényen kívüli, argumentumként átadott tömbre!

Ötlet (f0136)

Ha egy függvény tömböt vár paraméterként, akkor a függvényt érdemes úgy megírni, hogy a tömb méretét (a tömbben tárolt elemek számát) is paraméterben lehessen megadni. (Kivéve, ha a tömb végét más módon jelezzük, mint például a sztringek esetében, lásd alább.)

Lehetséges megoldás (m0136.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
50
51
52
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2008. őszi félév.
 *
 * fordítás:
 *    gcc -o m0136 m0136.c
 *
 * futtatás:
 *    ./m0136
 */

#include <stdio.h>

#define N 128

void beolvas(int tomb[], int meret) {
    int i;
    for (i = 0; i < meret; ++i) {
        scanf("%d", &(tomb[i]));
    }
}

void tombabs(int tomb[], int meret) {
    int i;
    for (i = 0; i < meret; ++i) {
        if (tomb[i] < 0) {
            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 t[N], m;
    scanf("%d", &m);
    beolvas(t, m);
    tombabs(t, m);
    kiir(t, m);
    return 0;
}

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

array_abs

Feladat (f0143)

Problémafelvetés:

Készíts egy programot, amely beolvas legfeljebb 256 egész számot, eltárolja őket egy tömbben, majd a tömböt úgy alakítja át, hogy a sorban egymás után ismétlődő elemek közül csak egyet hagy meg.

Specifikáció:

A program inputjának első eleme egy 0 és 256 közötti N egész szám, majd N darab további egész szám. A program kimenete az input számsorozat de úgy, hogy az egymást közvetlenül követő azonos értékű elemek közül csak egy marad meg. A kimenetben a számok egy-egy szóközzel vannak elválasztva, a sort pedig egy sorvége jel zárja.

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

A számok tárolására készítsünk egy előre megadott fix méretű tömböt. Ezt a tömböt és a beolvasandó számok darabszámát a főprogram kezelje. A tömb elemeinek beolvasását, az elemek cseréjét és a kiírást is egy-egy külön függvény végezze, amely megkapja a tömböt és a tömbméretet is.

Ötlet (f0143)

A törlés megvalósítása az, ami érdekes (a többi olyan, mint az előbb). Lássunk egy példát. Legyen adott az alábbi tömb:

0. 1. 2. 3. 4. 5.
7 7 0 2 2 6

A tömb minden elemén végig kell menni, és meg kell határozni, hogy hová kell őt előrébb mozgatni a tömbben. A 0. elemet nyilván a 0. helyre kell másolni.

0. 1. 2. 3. 4. 5.
7 7 0 2 2 6

Az 1. elem megegyezik az előzővel, tehát semmit nem kell vele csinálni.

0. 1. 2. 3. 4. 5.
7 7 0 2 2 6

A 2. elem nem egyezik az előzővel (ami megegyezett a 0.-kal) tehát be kell másolni a következő, azaz 1. helyre.

0. 1. 2. 3. 4. 5.
7 0 0 2 2 6

A 3. elem nem egyezik az előzővel (amit az 1. helyre másoltunk) tehát be kell másolni a következő, azaz 2. helyre.

0. 1. 2. 3. 4. 5.
7 0 2 2 2 6

A 4. elem megegyezik az előzővel (amit a 2. helyre másoltunk) tehát semmit nem kell vele csinálni.

0. 1. 2. 3. 4. 5.
7 0 2 2 2 6

A 5. elem nem egyezik az előzővel (amit a 2. helyre másoltunk) tehát be kell másolni a következő, azaz 3. helyre.

0. 1. 2. 3. 4. 5.
7 0 2 6 2 6

Mivel elfogytak az eredeti tömb elemei, és csak 4 másolás történt, az eredmény tömb 4 elemű.

0. 1. 2. 3.
7 0 2 6

Mivel C-ben a tömb méretét nem lehet csökkenteni, egyszerűen nem foglalkozunk a többi elemmel, nem íratjuk ki őket.

Lehetséges megoldás (m0143.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
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: egy 0 és 256 közötti N egész szám
 *           N darab további egész szám
 *    Output: az input számsorozat de úgy, hogy az egymást közvetlenül követő
 *            azonos értékű elemek közül csak egy marad meg. A kimenetben a
 *            számok egy-egy szóközzel vannak elválasztva, a sort pedig egy
 *            sorvége jel zárja.
 *
 * Algoritmustervezés:
 *    A számok tárolására készítünk egy előre megadott fix méretű tömböt. Ezt a
 *    tömböt és a beolvasandó számok darabszámát a főprogram kezeli. A tömb
 *    elemeinek beolvasását, az elemek törlését és a kiírást is egy-egy külön
 *    függvény végezi, amely megkapja a tömböt és a tömbméretet is.
 *
 * Fordítás:
 *    gcc -Wall -o m0143 m0143.c
 *
 * Futtatás:
 *    ./m0143
 */

#include <stdio.h>

void beolvas(int tomb[], int n) {
    for (int i = 0; i < n; ++i) {
        scanf("%d", &tomb[i]);
    }
}

int torol(int tomb[], int n) {
    if (n <= 1) {
        return n;
    }
    int i = 0;
    for (int j = 1; j < n; ++j) {
        if (tomb[i] != tomb[j]) {
            ++i;
            tomb[i] = tomb[j];
        }
    }
    return i + 1;
}

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

int main() {
    int meret;
    int tomb[256];

    scanf("%d", &meret);

    beolvas(tomb, meret);
    meret = torol(tomb, meret);
    kiir(tomb, meret);

    return 0;
}

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

array_abs

Feladat (f0144)

Problémafelvetés:

Készíts egy programot, amely beolvas legfeljebb 255 nemnegatív egész számot, majd kiírja a sorozat elemeinek a sorozat minimumától való eltérését.

Specifikáció:

A program inputja egy nemnegatív számokból álló legfeljebb 255 elemű számsorozat, melyet a -1 érték zár. A program kimenete egy ugyanennyi elemű nemnegatív számsorozat, ahol az egyes elemek az adott input elem minimumtól való eltérését mutatja. A kimenetben a számok egy-egy szóközzel vannak elválasztva, a sort pedig egy sorvége jel zárja.

Példa be- és kimenetek:

  1. példa:
    • Input: "1 0 7 12 -1"
    • Output: "1 0 7 12"
  2. példa:
    • Input: "7 12 30 9 7 23 -1"
    • Output: "0 5 23 2 0 16"

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

A számok tárolására készítsünk egy előre megadott fix méretű tömböt. Ezt a tömböt a főprogram kezelje. A tömböt úgy fogjuk használni, hogy a benne lévő -1 érték jelzi a tömbben tárolt számsorozat végét. A tömb elemeinek beolvasását egy függvény végezze, melynek paramétere a feltöltendő tömb, visszatérési értéke pedig a tömbben tárolt elemek minimális értéke. A tömb elemeinek módosítását egy olyan függvény végezze, melynek három paramétere van: az első egy bemenő paraméter, az eredeti tömb, a második a tömb elemeiből levonandó szám, a harmadik pedig egy kimenő paraméter, az eredménytömb. A kiíratását szintén egy függvény végezze melynek egyetlen paramétere van: a -1 értékkel lezárt tömb. Figyelj oda a megvalósításra, mert a főprogramban egyetlen tömböd van, míg az egyik függvény két tömböt vár!

Lehetséges megoldás (m0144-1.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
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
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 *
 * Specifikáció:
 *    Input: egy nemnegatív számokból álló legfeljebb 255 elemű számsorozat,
 *           melyet a -1 érték zár
 *    Output: egy ugyanennyi elemű nemnegatív számsorozat, ahol az egyes elemek
 *            az adott input elem minimumtól való eltérését mutatja. A
 *            kimenetben a számok egy-egy szóközzel vannak elválasztva, a sort
 *            pedig egy sorvége jel zárja.
 *
 * Algoritmustervezés:
 *    A számok tárolására készítünk egy előre megadott fix méretű tömböt. Ezt a
 *    tömböt a főprogram kezeli. A tömböt úgy fogjuk használni, hogy a benne
 *    lévő -1 érték jelzi a tömbben tárolt számsorozat végét. A tömb elemeinek
 *    beolvasását egy függvény végzi, melynek paramétere a feltöltendő tömb,
 *    visszatérési értéke pedig a tömbben tárolt elemek minimális értéke.
 *    Beolvasásokor nem csak a záró -1-re figyelünk, hanem a tömb méretére is.
 *    A tömb elemeinek módosítását egy olyan függvény végzi, melynek három
 *    paramétere van: az első egy bemenő paraméter, az eredeti tömb, a második a
 *    tömb elemeiből levonandó szám, a harmadik pedig egy kimenő paraméter, az
 *    eredménytömb. A kiíratását szintén egy függvény végzi melynek egyetlen
 *    paramétere van: a -1 értékkel lezárt tömb. A főprogramban egyetlen tömbünk
 *    van, míg a modosit függvény két tömböt vár. Mivel a módosítás sorban
 *    egyszer fut le minden elemre, most használhatjuk ugyanazt a tömböt be- és
 *    kimenetként (ennek azonban általános esetben megvannak a veszélyei!).
 *
 * Fordítás:
 *    gcc -Wall -o m0144 m0144-1.c
 *
 * Futtatás:
 *    ./m0144
 */

#include <stdio.h>

#define N 256

int feltolt(int t[]) {
    int min, i = 0;
    scanf("%d", &t[0]);     // Beolvassuk a legelső tömbelemet,
    min = t[0];             // ami egyben a sorozat legkisebb eleme is lesz.
    while (t[i] != -1) {    // Amíg a legutóbb tárolt érték nem a tömb vége jel:
        if (t[i] < min) {   // Ha kisebb az eddigi minimumnál,
            min = t[i];     // akkor ez lesz az új minimum.
        }
        if (++i == N - 1) { // Ha már csak ehy helyünk marad a tömbben,
            t[i] = -1;      // akkor le kell zárni a sorozatot a -1 értékkel
        } else {
            scanf("%d", &t[i]); // különben beolvassuk a következő értéket.
        }
    }
    return min; // Ha üres sorozatot adtunk meg, akkor -1-gyel térünk vissza, ami
                // hiba lenne, de szerencsére a program többi része ilyenkor
                // érdemben nem használja fel ezt az értéket.
}

void modosit(int src[], int m, int dst[]) {
    int i;
    for (i = 0; src[i] != -1; ++i) {    // Ha a sorozat üres, akkor a for
        dst[i] = src[i] - m;            // tulajdonsága miatt nem történik semmi
    }                                   // (egyszer sem fut le a ciklus).
    dst[i] = -1;                        // Az eredménytömböt is le kell zárni!
}

void kiir(int t[]) {
    int i = 0;
    if (t[0] != -1)  {          // Ha van első elem (a tömb nincs rögtön lezárva),
        printf("%d", t[i]);     // az elé nem kell szóköz.
        ++i;
    }
    for (; t[i] != -1; ++i) {   // Minden további elemre, ami nem a lezáró -1 érték
        printf(" %d", t[i]);    // szóköz után írjuk ki a tömbelemet.
    }
    printf("\n");
}

int main() {
    int tomb[N];
    int min;
    min = feltolt(tomb);
    modosit(tomb, min, tomb);
    kiir(tomb);
    return 0;
}
Lehetséges megoldás (m0144-2.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
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
/*
 * 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 nemnegatív számokból álló legfeljebb 255 elemű számsorozat,
 *           melyet a -1 érték zár
 *    Output: egy ugyanennyi elemű nemnegatív számsorozat, ahol az egyes elemek
 *            az adott input elem minimumtól való eltérését mutatja. A
 *            kimenetben a számok egy-egy szóközzel vannak elválasztva, a sort
 *            pedig egy sorvége jel zárja.
 *
 * Algoritmustervezés:
 *    A számok tárolására készítünk egy előre megadott fix méretű tömböt. Ezt a
 *    tömböt a főprogram kezeli. A tömböt úgy fogjuk használni, hogy a benne
 *    lévő -1 érték jelzi a tömbben tárolt számsorozat végét. A tömb elemeinek
 *    beolvasását egy függvény végzi, melynek paramétere a feltöltendő tömb,
 *    visszatérési értéke pedig a tömbben tárolt elemek minimális értéke.
 *    Beolvasásokor nem csak a záró -1-re figyelünk, hanem a tömb méretére is.
 *    A tömb elemeinek módosítását egy olyan függvény végzi, melynek három
 *    paramétere van: az első egy bemenő paraméter, az eredeti tömb, a második a
 *    tömb elemeiből levonandó szám, a harmadik pedig egy kimenő paraméter, az
 *    eredménytömb. A kiíratását szintén egy függvény végzi melynek egyetlen
 *    paramétere van: a -1 értékkel lezárt tömb. A főprogramban egyetlen tömbünk
 *    van, míg a modosit függvény két tömböt vár. Mivel a módosítás sorban
 *    egyszer fut le minden elemre, most használhatjuk ugyanazt a tömböt be- és
 *    kimenetként, ennek azonban megvannak a veszélyei.
 *
 * Fordítás:
 *    gcc -Wall -o m0144 m0144-2.c
 *
 * Futtatás:
 *    ./m0144
 */

#include <stdio.h>
#include <limits.h>                         // az INT_MAX konstans használatához

#define N 256

int beolvas(int tomb[]) {
    int min = INT_MAX;
    int i = 0;

    while (1) {     // Végtelen ciklus, break-kel kell majd kiugrani belőle
        scanf("%d", &tomb[i]);
        if (tomb[i] < 0 || i == N-1) { // Ha negatív értéket kaptunk vagy elértük a tömb végét
            tomb[i] = -1;              // akkor le is kell zárni a tömböt, mielőtt
            break;                     // kiugrunk a ciklusból
        }
        if (tomb[i] < min) {
            min = tomb[i];
        }
        ++i;
    }

    return min;
}

void modosit(int be[], int levon, int ki[]) {
    int i;
    for (i = 0; be[i] != -1; ++i) {
        ki[i] = be[i] - levon;
    }
    ki[i] = -1;
}

void kiir(int tomb[]) {
    for (int i = 0; tomb[i] != -1; ++i) {
        printf("%d ", tomb[i]);
    }
    printf("\n");
}

int main() {
    int tomb[N];

    int min = beolvas(tomb);
    modosit(tomb, min, tomb);
    kiir(tomb);

    return 0;
}
Figyelmeztetés

Az előző feladatban egy olyan függvényt használtunk (modosit()), amelynek volt egy "bemenő" tömb paramétere (src/be), és egy "kimenő" tömb paramétere (dst/ki). A függvény hívásakor viszont argumentumként mindkét paraméternek ugyanazt a tömböt adtuk meg (modosit(tomb, ..., tomb);). Ez azt jelenti, hogy a függvény tulajdonképpen ugyanazon a tömbön dolgozott.

Mivel a függvény algoritmusa "helyben", egy tömbön is jól működne (meg lehetne úgy írni, csak a dst/ki műveleteket is az src/be paramétereken kellene végrehajtani), ezzel nincs gond. Általában viszont, ha egy függvénynek külön bemeneti és kimeneti tömbje van, akkor két külön tömböt kell megadni, különben rossz eredményt kaphatunk!

Hasonló feladat megoldása

Az alábbi videó egy nagyon hasonló probléma (kicsit eltér a specifikáció) megoldását mutatja be:

array

Karaktertömbök - "sztringek"

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 a 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 a tömbben, de az a sztring értékének már nem része, csak egy szükséges technikai lezáró elem. (Mivel a tömb mérete C-ben nem állapítható meg a tömb változóból, ha nem lenne lezárva a 0 kódú karakterrel, nem lehetne tudni meddig tart a szöveg a memóriában.) Emiatt adott méretű tömbben legfeljebb a tömb méreténél eggyel rövidebb (eggyel kevesebb karakterből álló) szöveg tárolható.

Tehát, hogy is nézne ez ki a létrehozás:

1
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, és mondjuk benne van a "PROGALAP" szó:

index 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
tömbelem karakterként 'P' 'R' 'O' 'G' 'A' 'L' 'A' 'P' '\0' ?
tömbelem számként (ascii karakterkód) 80 82 79 71 65 76 65 80 0 ?

Figyeljük meg, hogy a 0 ascii kódú lezáró NULL karakter jelölése karakterként '\0', ami nem azonos a '0' karakterrel (aminek az ascii kódja 48). A kérdőjel definiálatlan, lényegtelen adatot jelent: ez is része a karaktertömbnek, de nem része a sztring értékének!

Megjegyzés

Az egyes karakterek ascii kódjait nem kell megtanulni. C-ben a 65 teljesen egyenértékű az 'A' jelöléssel, az 'A' + 80 pontosan ugyanaz, mint a 65 + 'P'. Ebből adódóan például az ('A' <= k) && (k <= 'Z') pontosan akkor lesz igaz, ha a k változó értéke az 'A' és 'Z' karakterek ascii kódjai közé esik, vagyis a k értéke egy nagybetű (ascii kódja).

Az alábbi videó a sztringek alapjait magyarázza el:

string_1

Feladat (f0134)

Feladat:

Vizsgáld meg a sztring.c programot. Mi a hiba? Javítsd ki úgy, hogy

  • a) az str változó inicializálással kapjon értéket, és úgy is, hogy
  • b) az str változó NE inicializálással kapjon értéket!

A b) verzióval dolgozz tovább! Mi a különbség a két kiíratás között? Mely esetben lenne látható a különbség?

  1. A kiíratások előtt cseréld le az str változó 2. karakterét '%'-ra. Mit tapasztalsz?
  2. A kiíratások előtt cseréld le az str változó 6. karakterét '\0'-ra (nullás kódú karaktere). Mit tapasztalsz?
  3. Kiíratások után cseréld vissza ugyanezt a karaktert az eredeti értékére, majd újból írasd ki a sztringet. Mit tapasztalsz?
  4. Írasd ki a teljes str tömb minden karakterét, és hasonlítsd össze a sztringként kiírt értékkel.
  5. A sztring méretét csökkentsd 4-re. Mit tapasztalsz?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 */

#include <stdio.h>

int main() {
    char str[20];
    str = "Hello Vilag!\n";
    printf("%s", str);
    printf(str);
    return 0;
}
sztring.c

Válasz (f0134 első rész)

Az = művelet tömbökre nem (és így sztringekre sem) alkalmazható.

Lehet viszont a tömböket (és így a sztringeket is) inicializálni, vagyis a deklaráció sorában kaphatnak kezdőértéket (a) feladat):

char str[20] = "Hello Vilag!\n";

Ha ez nem elegendő, akkor a string.h-ban található strcpy() függvényt tudjuk használni (b) feladat):

strcpy(str, "Hello Vilag!\n");

Válasz (f0134 második rész)

A '%' karakter beszúrásával (a 2. karakter, azaz az 1. indexű 'e' betű helyére) az első kiíratás megbirkózik, nem lesz gond. A másodiknál viszont, mivel a sztringet formátumsztringként értelmezi, és megtalálja benne a "%llo" specifikációt (ami egy nyolcas számrendszerbeli szám kiírását írja elő), a "H" és a " Vilag!" közé számjegyeket fog írni a kimeneten.

Ha a 6. szóköz karaktert a 0 kódú karakterré változtatjuk, akkor ezzel itt lezárjuk a sztringet, vagyis a kimeneten csak a "HelloHello" szöveg fog megjelenni (a "Hello" kétszer kiírva), sortörés nélkül. (Vagy valami "H%lloH512434154223" alakú szöveg, ha nem cseréltük vissza az előbb beírt '%' karaktert.)

Visszacsere után megjavul a program, ismét az eredeti szöveget fogja kiírni.

Ha a sztringet mint tömböt íratjuk ki, az első 13 (14?) karakter, ami megjelenik, nem lesz meglepetés. A 12 karakteres szöveg, a sorlezáró karakter (sortörés), és a sztringet lezáró NULL karakter (ami kiíródik ugyan, de nem fog megjelenni). De utána (új sorban a '\n' miatt) megjelenhet még 6 véletlenszerű karakter, a tömb maradék elemei. Azért feltételesen, mert ezek a tömbelemek nem lesznek inicializálva, vagyis véletlenszerű értékeket tartalmaznak, tehát lehet, hogy semmit sem látunk (ha pl. véletlenül mind NULL értékű).

Csökkentsük a sztring méretét (méretét, nem hosszát!) 4-re:

1
2
3
4
    ...
    char str[4];
    strcpy(str, "Hello Vilag!\n");
    ...
Ekkor futás közben sokféle eredményt kaphatunk. Lehet, hogy semmi különöset nem tapasztalunk (ettől a program még nem jó!), vagy kiírhat furcsa értéket, de az is lehet, hogy a program memóriahibával elszáll!

Feladat (f0169)

Problémafelvetés:

Határozd meg egy 128 karakter méretű tömbben elférő, a felhasználó által megadott sztring hosszát.

Ötlet (f0169)

A sztring hossza ugyanaz, mint az első 0 kódú karakter indexe. A sztring elejétől indulva meg kell keresni az első 0 értéket a tömbben, és meg kell mondani, hogy ez melyik indexhez tartozik.

Lehetséges megoldás (m0169.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
50
51
52
53
54
55
56
/*
 * 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 128 karakter méretű tömbben elférő, a felhasználó által
 *           megadott sztring
 *    Output: egy N szám, a sztring hossza
 *
 * Algoritmustervezés:
 *    A főprogramban beolvasunk egy maximum 127 karakteres szöveget egy 128
 *    méretű tömbbe. Definiálunk egy függvényt, aminek egy egész számban fogja
 *    visszaadni a paramétereként kapott karaktertömb hosszát. A főprogramból
 *    meghívjuk, majd kiírjuk az eredményt.
 *
 * Fordítás:
 *    gcc -Wall -o m0169 m0169.c
 *
 * Futtatás:
 *    ./m0169
 */

#include <stdio.h>

int hossz(char str[]) {
    int i;

    //nincs ciklusmag, ezt blokk helyett egy üres utasítással (;) tudjuk jelölni
    for (i = 0; str[i]; ++i);

    return i;
}

int main() {
    char tomb[128];

    // az input tartalmazhat szóközt, a scanf("%s", tomb) ezért nem jó
    fgets(tomb, 128, stdin); 
    int h = hossz(tomb);
    // Az fgets() beolvassa és a sztringben eltárolja az input sor végi '\n'
    // karaktert is. Ha tehát a sztring utolsó karaktere '\n', akkor a megadott
    // sztring hossza valójában eggyel kevesebb. Ha viszont a 128-as korlát
    // lép érvényre, nem lesz '\n' a sztring végén, mert a beolvasás nem ér el
    // odáig.
    if (tomb[h-1] == '\n') {
        --h;
    }
    printf("%d\n", h);

    return 0;
}

Egy hasonló megoldást mutat be a következő videó is részletes magyarázattal:

string_1

Megjegyzés

Ha csak a sztring hossza kell, és mást műveletet nem tervezünk a sztringgel végezni közben, akkor a string.h-ban található strlen() függvény tökéletesen megfelel a célra.

Feladat (f0137)

Problémafelvetés:

Készíts egy programot, amely beolvas egy legfeljebb 127 karakter hosszú sztringet, egy másik változóba megfordítja, majd kiírja a megfordított értéket.

Specifikáció:

A program inputja egy whitespace karaktereket nem tartalmazó legfeljebb 127 karakter hosszú sztring. Outputja a beolvasott sztring visszafelé.

Ötlet (f0137)

Először olvassuk be a sztringet egy karaktertömbbe, majd keressük meg a végét, a \0 karaktert. Ha ez megvan, nincs más dolgunk mint a végéről előrefele lépkedve minden karaktert átmásolni egy másik sztringbe, de a másik sztring elejétől kezdve a feltöltést. Ne feledkezzünk meg arról, hogy a sztring értékét lezáró \0 karakter nem része a sztring értékének (azt nem kell a másik sztring legelejére berakni), viszont a végén másik sztring értékét is le kell zárni egy \0 karakterrel!

Lehetséges megoldás (m0137.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
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2008. őszi félév.
 *
 * Megvalósítás:
 *    Mivel a beolvasandó szöveg nem tartalmaz whitespace karaktereket, a
 *    scanf() függvény használható a "%s" konverziós specifikációval. A
 *    biztonság kedvéért a beolvasott karakterek számát korlátozzuk.
 *
 * fordítás:
 *    gcc -o m0137 m0137.c
 *
 * futtatás:
 *    ./m0137
 */

#include <stdio.h>

#define N 128

int main() {
    int i, j;
    char str[N], rev[N];
    scanf("%127s", str);   /* Legfeljebb 127 karaktert engedünk beolvasni */
    for (i = 0; str[i] != 0; ++i);         /* Megkeressük a sztring végét */
    for (j = 0; i-- > 0; ++j) {     /* A str karaktereit hátulról előre   */
        rev[j] = str[i];           /* haladva egyesével átmásoljuk rev-be */
    }                              /* a rev elejétől kezdve a bemásolást  */
    rev[j] = 0;                /* Végül lezárjuk a megfordított sztringet */
    printf("%s\n", rev);
    return 0;
}

Egy hasonló megoldást mutat be a következő videó részletes magyarázat mellett:

str_rev

Feladat (f0279)

Problémafelvetés:

Írj egy programot ami meghatározza, hogy egy adott, maximálisan 255 hosszúságú szöveg palindróma-e, azaz ugyanaz előről olvasva, mint hátulról!

Specifikáció:

A program inputja egy maximálisan 255 karakter hosszú szöveg. A program outputja a "Palindróma" vagy "Nem palindróma" szöveg, melyet sortörés követ.

A programban a palindróma ellenőrzését egy külön függvény végezze, mely int-et ad vissza és egy karaktertömböt kap paraméterül! A függvény visszatérési értéke 0, ha nem palindróma a kapott szöveg, illetve 1, ha palindróma.

Algoritmustervezés:

A szöveg elejéről és hátuljáról szinkronban lépkedve össze tudjuk hasonlítani ezeket a karaktereket páronként.

Lehetséges megoldás (m0279.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
50
51
52
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 *
 * Tóth Zoltán, 2020. őszi félév.
 *
 * Fordítás:
 *    gcc -Wall -o m279 m0279.c
 *
 * Futtatás:
 *    ./m0279
 */

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

int palindrom(char str[]) {
    int i, j;

    for (i = 0, j = strlen(str) - 1; i < j; ++i, --j) {
        if (str[i] != str[j]) {
            return 0;
        }
    }

    return 1;
}

int main() {
    char str[256];

    printf("Adja meg az ellenorizni kivant szoveget!\n");
    fgets(str, 256, stdin);

    int length = strlen(str);

    // removing new line
    if (str[length-1] == '\n') {
        str[length-1] = '\0';
    }

    if (palindrom(str)) {
        printf("\nPalindróma\n");
    } else {
        printf("\nNem palindróma\n");
    }

    return 0;
}

Egy lehetséges megoldást mutat be a következő videó is, mely részletes magyarázatot is tartalmaz:

str_palindrom

Feladat (f0139)

Problémafelvetés:

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.

Specifikáció:

A program inputja egy legfeljebb 255 karakter hosszú (esetleg whitespace karaktereket is tartalmazó) sztring. Outputja egy egész szám, a sztringben található számjegyek száma.

Algoritmustervezés:

Külön főprogramot írunk, amely a be- és kimenetkezelésért felel, a számolást pedig egy függvény végzi el.

FÜGGVÉNY:

Problémafelvetés:

Készíts egy függvényt, ami megszámolja egy sztringben található számjegyek számát.

Specifikáció:

A függvénynek közvetlenül nincs se bemenete, se kimenete. A függvénynek egy sztring paramétere van, visszatérési értéke pedig a sztringben található számjegy karakterek száma.

Megjegyzés

Az ascii kódtáblában a számjegyek sorban követik egymást, vagyis az a karakter számít számjegynek, aminek a kódja a '0' és a '9' karakterek kódjai közé esik.

Lehetséges megoldás (m0139.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
50
51
52
53
54
55
56
/*
 * 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 legfeljebb 255 karakter hosszú (esetleg whitespace karaktereket
 *           is tartalmazó) sztring
 *    Output: egy egész szám, a sztringben található számjegyek száma
 *
 * Algoritmustervezés:
 *    Külön főprogramot írunk, amely a be- és kimenetkezelésért felel, a
 *    számolást pedig egy függvény végzi el.
 *
 *    A függvény végighalad a paraméterként kapott sztring karakterein és
 *    megszámolja a számjegyeket.
 *
 * fordítás:
 *    gcc -Wall -o m0139 m0139.c
 *
 * futtatás:
 *    ./m0139
 */

#include <stdio.h>

int szamjegyszamol(char str[]) {
    int szam = 0;

    for (int i = 0; str[i]; ++i) {
        if ('0' <= str[i] && str[i] <= '9') {
            ++szam;
        }
    }

    return szam;
}

int main() {
    char szoveg[256];

    // Az input tartalmazhat whitespace karaktereket, ezért nem használhatjuk
    // a scanf() függvényt %s formátummal.
    fgets(szoveg, 255, stdin);
    // vagy:
    //scanf("%255[^\n]", szoveg);

    int eredmeny = szamjegyszamol(szoveg);
    printf("%d\n", eredmeny);

    return 0;
}

Egy hasonló megoldást (specifikációtól eltérő) mutat be a következő videó részletes magyarázat mellett:

str_rev

Érdekesebb példák

Feladat

Vegyünk egy egydimenziós tömböt, amelyben az 1-10 értékeket tároljuk, 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
 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
#include <stdio.h>

int main() {
    int i, j, temp;
    int tomb[10] = {2, 3, 4, 7, 6, 5, 10, 9, 8, 1};
    printf("Az eredeti tomb:\n");
    for (i = 0; i < 10; ++i) {
        printf("%d ",tomb[i]);
    }
    printf("\nA rendezett tomb:\n");
    for (i = 0; i < 9; ++i) {   // Legfeljebb 9-szer kell a szomszédcseréket végrehajtani,
                                // utána már biztos, hogy sorban lesznek az elemek. (Lehet,
                                // hogy kevesebb menet is elég, de biztos ami biztos.
        for (j = 0; j < 9; ++j) {   // 10 elem esetén 9 pár lesz, amit cserélhetünk
            if (tomb[j] > tomb[j+1]) {
                temp = tomb[j];
                tomb[j] = tomb[j+1];
                tomb[j+1] = temp;
            }
        }
    }
    for (i = 0; i < 10; ++i) {
        printf("%d ",tomb[i]);
    }

    return 0;
}

Feladat

Számoljuk ki a Fibonacci-sorozat elemeit. Ebben az első két (nulladik és első) elem után (amik értéke 0 és 1) 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
 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
#include <stdio.h>

int main() {
    int a = 0, b = 1, c = 0;
    int i = 0;
    int fibo;
    printf("Add meg, hogy meddig menjen a fibonacci sorozat: ");
    scanf("%d", &fibo);
    if (fibo == 0) {
        printf("0");
    } else if (fibo == 1) {
        printf("0 1");
    } else if (fibo > 1) {
        printf("0 1");
        for (i = 0; i < fibo - 1; ++i) {
            c = a + b;  // c az aktuális (i.) sorozatelem
            a = b;      // Az a a 2-vel ezelőtti elem, a következő körben
                        // ez a mostani eggyel megelőző (b) elem lesz.
            b = c;      // A b a mostani eggyel megelőző elem, a következő körben
                        // ez a mostani aktuális sorozatelem lesz.
            printf("%d ",c);
        }
    }
    printf("\n");
    return 0;
}

Feladat

Bővítsük úgy az előbbi feladatot úgy, hogy ne a képernyőre íródjon ki az adott számot, hanem egy tömbbe kerüljenek a sorozat elemei. Az így kapott tömb tartalmát írjuk ki a program végén!

Megoldás
 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
#include <stdio.h>

#define N 128

int main() {
    int a = 0, b = 1, c = 0;
    int i = 0;
    int fibo;
    printf("Add meg, hogy meddig menjen a fibonacci sorozat: ");
    scanf("%d", &fibo);
    int fibonacci[N];   // Legfeljebb 128 elemet tudunk számolni, de ez bőven elég
    if (fibo == 0) {
        fibonacci[0] = 0;
    } else if (fibo == 1) {
        fibonacci[0] = 0;
        fibonacci[1] = 1;
    } else if (fibo > 1) {
        fibonacci[0] = 0;
        fibonacci[1] = 1;
        for (i = 2; i <= fibo; ++i) {
            fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
        }
    }
    printf("\n");
    for (i = 0; i < fibo; ++i) {
        printf("%d ", fibonacci[i]);
    }
    return 0;
}

Jövő héten 2. ZH

Téma:

  • A 3. gyakorlat anyaga. (De tudni kell az azt megelőző gyakorlatok anyagát is!)

Gyakorlásra:

  • A honlapon lévő anyag, magyarázatokkal, példákkal.
  • További feladatok találhatóak a PUB-ban. (/pub/ProgramozasAlapjai/Gyakorlat/ - lehetséges átfedés van az "itt" és "ott" található feladatok között).

Egyéb infó:

  • Előreláthatóan 25 percetek lesz a feladatok megoldására és beadására.
  • A feladatokat a bíró rendszeren keresztül fogjátok megkapni és beadni is, és az értékelést is a bíró fogja csinálni ott helyben.
  • Tehát egyből látni fogjátok a pontszámokat amiket a bíró adott.
  • Aki késik, az is csak a fenti időintervallum alatt írhatja a ZH-t (a bíró rendszer nyit, majd automatikusan zár is).
  • Hiányozni csak igazolással lehet!

Feladatok

Feladat (f0141)

Problémafelvetés:

Készíts egy programot, amely beolvas egy legfeljebb 255 karakter hosszú sztringet, majd kisbetűsítve kiírja azt.

Specifikáció:

A program inputja egy legfeljebb 255 karakter hosszú (esetleg whitespace karaktereket is tartalmazó) sztring. Outputja egy sztring, amely abban különbözik a beolvasott sztringtől, hogy az angol ábécé nagybetűi helyett a nekik megfelelő kisbetűk szerepelnek.

Algoritmustervezés:

Írjunk egy főprogramot, amely külön tárolja a be- és kimeneti sztringet és ezek kezelésért felel, a módosított sztring előállítását pedig egy függvény végezze el.

FÜGGVÉNY:

Problémafelvetés:

Készíts egy függvényt, ami egy sztringből előállít egy másikat úgy, hogy lecseréli a nagybetűket a nekik megfelelő kisbetűkre!

Specifikáció:

A függvénynek közvetlenül nincs se bemenete, se kimenete. A függvénynek két sztring paramétere van. Az első egy bemenő paraméter, a második egy kimenő paraméter. Utóbbit a függvény az előbbiből állítja elő úgy, hogy a sztringben található nagybetűket (csak az angol ábécé betűit) kicseréli a megfelelő kisbetűkre. A függvény visszatérési értéke a végrehajtott cserék száma legyen.

Lehetséges megoldás

Egy lehetséges megoldást (specifikációtól eltérő) mutat be a következő videó:

str_lowercase

Feladat (f0142)

Problémafelvetés:

Készíts egy programot, amely beolvas egy legfeljebb 255 karakter hosszú sztringet, majd törli belőle a számjegyeket és kiírja az eredményt. A törlés nem helyettesítést jelent!

Specifikáció:

A program inputja egy legfeljebb 255 karakter hosszú (esetleg whitespace karaktereket is tartalmazó) sztring. Outputja egy sztring, amely abban különbözik a beolvasott sztringtől, hogy abból törölve lettek a számjegyek.

Példa be- és kimenetek:

  1. példa:
    • Input: "Ez 1 pelda"
    • Output: "Ez pelda"
  2. példa:
    • Input: "1meg1az2"
    • Output: "megaz"

Algoritmustervezés:

Külön főprogramot írunk, amely a be- és kimenetkezelésért felel, a törlést egy külön függvény végzi.

FÜGGVÉNY:

Problémafelvetés:

Készíts egy függvényt, ami törli egy sztringből a számjegyeket.

Specifikáció:

A függvénynek közvetlenül nincs se bemenete, se kimenete. A függvénynek egy sztring paramétere van. A függvény ebben a sztringben található számjegyeket törli (ami által a sztring rövidülhet). A függvény visszatérési értéke a törölt karakterek száma legyen.

Lehetséges megoldás

Nem pontosan a specifikációnak megfelelő megoldást mutat be a következő videó:

str_remove_nums

Feladat (f0147)

Problémafelvetés:

Készíts egy programot, amely kiszámolja két legfeljebb 256 dimenziós valós vektor skalárszorzatát.

Specifikáció:

A program inputja két vektor. Egy vektor leírásának első eleme egy 1 és 256 közötti N egész szám, amit N darab valós szám követ. A program kimenete a két input vektor skalárszorzata, vagy a "HIBA" sztring, ha a két vektor nem összeszorozható. A kimenetet egy sorvége jel zárja.

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

Egy \(v_1=(a_1,...,a_n)\) és egy \(v_2=(b_1,...,b_n)\) vektor skalárszorzata a \(c=(a_1*b_1)+...+(a_n*b_n)\) szám. A két vektor nem összeszorozható, ha a dimenziószámuk különbözik. A vektorok összeszorzását egy külön függvény végezze.

Feladat (f0149)

Problémafelvetés:

Testek síkbeli mozgását szimuláljuk. A megjelenítéshez referenciapontként a testek tömegközéppontját használjuk. A feladat ennek kiszámítása, és a testek koordinátáinak módosítása úgy, mintha a súlypont az origó lenne.

Specifikáció:

A program inputja több sor (legfeljebb 256), soronként egy-egy test adatai "t (x, y)" formátumban, ahol t a test tömege, x és y a koordináták, mindhárom valós adat, de t nemnegatív. Az output az inputhoz hasonló formátumú, a program a testeket az inputban megadott sorrendben írja ki a súlyponthoz képest számított relatív koordinátáikkal.

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

A testek súlypontja a helyvektoraik (koordinátáik) tömeggel súlyozott átlaga.

Feladat (f0160)

Feladat:

Készíts egy programot, amelyben definiálj egy legfeljebb 32 karakter hosszúságú szó tárolására való adattípust. Olvass be biztonságosan két szót két ilyen sztringbe és fűzd őket egymás után egy harmadik sztringbe, de az összefűzés ne csonkolja az értéket (vagyis akár 64 hosszú is lehessen az eredmény). Ehhez használd a string.h függvényeit! Írasd ki az eredmény első legfeljebb 48 karakterét.

Lehetséges megoldás (m0160.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
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2008. őszi félév.
 *
 * Megvalósítás:
 *    Készítünk két típusdefiníciót, egyet az input és egyet az eredmény
 *    sztringeknek. A szavak beolvasására a scanf-et használjuk, de a
 *    beolvasott érték méretét korlátozzuk. A beolvasásnál "%32s" konverziós
 *    specifikációt adunk meg (sajnos a scanf -- szemben a printf-fel -- nem
 *    tud dinamikus, futás közben megadott méretet kezelni). A sztringkezelő
 *    függvények közül a biztonságosabb strncpy() és strncat() változatokat
 *    használjuk (de C11-től lehetne a még biztonságosabb az strncpy_s() és
 *    strncat_s() verziókat használni, plusz 1-1 paraméterrel). A szöveg
 *    kiíratásánál a pontosság megadásával érjük el, hogy legfeljebb az első
 *    32 karakter kerüljön kiírásra.
 *
 * fordítás:
 *    gcc -o m0160 m0160.c
 *
 * futtatás:
 *    ./m0160
 */

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

#define MAXLEN 32

typedef char inp_string_t[MAXLEN+1];
typedef char res_string_t[2*MAXLEN+1];

int main() {
    inp_string_t egyik, masik;
    res_string_t harmadik;
    scanf("%32s %32s", egyik, masik);
    strncpy(harmadik, egyik, 2*MAXLEN); // Másolás
    strncat(harmadik, masik, 2*MAXLEN); // Hozzáfűzés
    printf(" -> %.48s\n", harmadik);
    return 0;
}

Feladat (f0170)

Problémafelvetés:

Hasonlíts össze két, egy-egy 128 karakter méretű tömbben elférő, a felhasználó által megadott sztringet, majd döntsd el, hogy a két beolvasott sztring értéke megegyezik-e.

További gyakorló feladatok

Feladat (f0059)

Feladat:

Készíts egy programot, ami bekér két természetes számot és írja ki, hogy az első szám osztható-e a másodikkal. A nullával osztás nem megengedett, ezt a program külön jelezze, magát az oszthatóságot viszont egy függvény ellenőrizze le!

FŐPROGRAM:

Problémafelvetés:

Készíts egy programot, ami bekér két természetes számot és írja ki, hogy az első szám osztható-e a másodikkal. A nullával osztás nem megengedett, ezt külön jelezze.

Specifikáció:

A program inputja két nemnegatív egész szám, M és N. A program outputja egyetlen sor, melyben a "Nullával nem osztunk!", "M osztója N-nek." illetve "M nem osztója N-nek." szöveg szerepel a két szám oszthatóságának függvényében. A program a két számot külön-külön tájékoztatás után kérje be.

FÜGGVÉNY:

Problémafelvetés:

A függvény a paraméterként kapott két számról döntse el, hogy az első osztható-e a másodikkal.

Specifikáció:

A függvénynek nincs sem inputja, sem outputja. A függvénynek két paramétere van, visszatérési értéke pedig igaz, ha a második szám osztja az elsőt, különben hamis.

Lehetséges megoldás (m0059.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
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai feladat megoldása
 *
 * Gergely Tamás, 2008. őszi félév.
 *
 * Megvalósítás:
 *    C nyelvben a logikai értékek egészként tárolódnak. (Létezik ugyan az
 *    stdbool.h, de arról majd később). Így a függvényünk visszatérési
 *    értéke egész típusú lesz. Az osztást ellenőrző kifejezésünk eredménye
 *    eleve logikai érték, így a függvény közvetlenül visszatérhet vele.
 *
 * fordítás:
 *    gcc -o m0059 m0059.c
 *
 * futtatás:
 *    ./m0059
 */

#include <stdio.h>

int oszthato(int mit, int mivel) {
    return (mit % mivel == 0);
}

int main() {
    int m, n;
    printf("Kérek egy egész számot:");
    scanf("%d", &m);
    printf("Kérek egy másik egész számot:");
    scanf("%d", &n);
    if (n != 0) {
        if (oszthato(m, n)) {
            printf("%d osztója %d-nek.\n", n, m);
        } else {
            printf("%d nem osztója %d-nek.\n", n, m);
        }
    } else {
        printf("Nullával nem osztunk!\n");
    }
    return 0;
}
Feladat (f0119)

Problémafelvetés:

Írj egy programot ami bekér egy n nemnegatív egész számot, majd kiírja az 1-től n-ig terjedő zárt intervallumba eső egész számok négyzeteit.

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

A beolvasást a főprogram végezze, de a működés lényegi része külön függvény(ek)ben legyen! 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 (f0120)

Problémafelvetés:

Írj egy programot ami bekér egy n számot, majd kiírja az első n természetes szám szorzatát!

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

A beolvasást és kiírást a főprogram végezze, de a működés lényegi része külön függvény(ek)ben legyen! 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 (f0122)

Problémafelvetés:

Írj egy programot ami bekér egy egész számokból álló sorozatot, amit a 0 érték zár, és úgy írja ki, hogy a legelső elem a legvégére kerül! (A 0 záróelem nem része a sorozatnak.)

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

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 (f0127)

Problémafelvetés:

Írj egy programot ami bekér egy n nemnegatív egész számot, majd kiírja az 1-től n-ig terjedő zárt intervallumba eső páros számok négyzeteit.

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

A beolvasást a főprogram végezze, de a működés lényegi része külön függvény(ek)ben legyen! 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 (f0128)

Problémafelvetés:

Írj egy programot ami bekér egy n nemnegatív egész számot, majd kiírja az 1-től n-ig terjedő zárt intervallumba eső páratlan számok négyzeteit.

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

A beolvasást a főprogram végezze, de a működés lényegi része külön függvény(ek)ben legyen! 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 (f0133)

Feladat:

Vizsgáld meg a tombindexeles.c programot. Mi történik, ha a két konstans (N és M) értékét megváltoztatod?

  • Vedd a tömb méretét (N) eggyel kisebbre, mint a ciklus futásszáma.
  • Vedd a tömb méretét (N) sokkal kisebbre, mint a ciklus futásszáma.
  • Vedd a tömb méretét (M) eggyel nagyobbra, mint a ciklus futásszáma.
  • Vedd a tömb méretét (M) sokkal nagyobbra, mint a ciklus futásszáma.

Mely esetekben hogyan viselkedik a program fordítás közben és futás során? Mi az oka a tapasztalt viselkedésnek? Cseréld meg a tomb és i változók deklarációjának sorrendjét! Megváltozik-e a program viselkedése valamelyik fentebb említett esetben?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 */

#include <stdio.h>

#define N 1024
#define M 1024

int main() {
    int tomb[N];
    int i;
    for (i = 0; i < M; ++i) {
        tomb[i] = i - 1;
    }
    for (i = 0; i < M; ++i) {
        printf(" %d", tomb[i]);
    }
    return 0;
}
tombindexeles.c

Feladat (f0138)

Problémafelvetés:

Készíts egy programot, amely beolvas egy legfeljebb 127 karakter hosszú sztringet, helyben megfordítja, majd kiírja a megfordított értéket.

Specifikáció:

A program inputja egy legfeljebb 127 karakter hosszú (esetleg whitespace karaktereket is tartalmazó) sztring. Outputja a beolvasott sztring visszafelé.

Feladat (f0140)

Problémafelvetés:

Készíts egy programot, amely beolvas egy legfeljebb 255 karakter hosszú sztringet, majd kiírja a sztringben található kisbetűk számát.

Specifikáció:

A program inputja egy legfeljebb 255 karakter hosszú (esetleg whitespace karaktereket is tartalmazó) sztring. Outputja egy egész szám, a sztringben található kisbetűk száma.

Algoritmustervezés:

Külön főprogramot írunk, amely a be- és kimenetkezelésért felel, a számolást pedig egy függvény végzi el.

FÜGGVÉNY:

Problémafelvetés:

Készíts egy függvényt, ami megszámolja egy sztringben található kisbetűk számát.

Specifikáció:

A függvénynek közvetlenül nincs se bemenete, se kimenete. A függvénynek egy sztring paramétere van, visszatérési értéke pedig a sztringben található kisbetű karakterek száma.

Feladat (f0145)

Problémafelvetés:

Készíts egy programot, amely beolvas legfeljebb 255 nemnegatív egész számot, majd kiírja a sorozat elemeinek a sorozat minimumától való eltérését.

Specifikáció:

A program inputja egy nemnegatív számokból álló legfeljebb 255 elemű számsorozat, melyet a -1 érték zár. A program kimenete egy ugyanennyi elemű nemnegatív számsorozat, ahol az egyes elemek az adott input elem minimumtól való eltérését mutatja. A kimenetben a számok egy-egy szóközzel vannak elválasztva, a sort pedig egy sorvége jel zárja.

Példa be- és kimenetek:

  1. példa
    • Input: "1 0 7 12 -1"
    • Output: "1 0 7 12"
  2. példa
    • Input: "7 12 30 9 7 23 -1"
    • Output: "0 5 23 2 0 16"

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

A főprogram a következő:

1
2
3
4
5
6
7
#define N 256

int main() {
    int t[N];
    writeTomb(subTomb(t, readTomb(t)));
    return 0;
}

Valósítsd meg úgy a függvényeket, hogy működjön a program!

Feladat (f0146)

Problémafelvetés:

Készíts egy programot, amely beolvas két legfeljebb 255 karakter hosszú sztringet, majd kiírja a rövidebbiket, vagy ha egyformák, akkor azt, hogy egyformák.

Specifikáció:

A program inputja két legfeljebb 255 karakter hosszú (whitespace karaktereket nem tartalmazó) sztring. Outputja az első sztring, ha az a rövidebb, a második sztring, ha az a rövidebb, vagy az "Egyforma" sztring, ha egyforma hosszúak.

Algoritmustervezés:

Külön főprogramot írunk, amely a be- és kimenetkezelésért felel, a két sztring hosszának összehasonlítását viszont egy függvény végezze el.

Feladat (f0148)

Problémafelvetés:

Készíts egy programot, amely kiszámolja két legfeljebb 256 dimenziós valós vektor összegét.

Specifikáció:

A program inputja két vektor. Egy vektor leírásának első eleme egy 1 és 256 közötti N egész szám, amit N darab valós szám követ. A program kimenete a két input vektor összege, az inputban használt formátumban (egy sorban, az egyes értékeket egy-egy szóköz válassza el), vagy a "HIBA" sztring, ha a két vektor nem összeadható. A kimenetet egy sorvége jel zárja.

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

Egy \(v_1=(a_1,...,a_n)\) és egy \(v_2=(b_1,...,b_n)\) vektor összege a \(v_3=(a_1+b_1,...,a_n+b_n)\) vektor. A két vektor nem összeadható, ha a dimenziószámuk különbözik. A vektorok összeadását egy külön függvény végezze.

Feladat (f0164)

Problémafelvetés:

Készíts egy programot, amely kiszámolja N dimenziós vektorok sorozatának összegét. A program először bekéri az N értéket (maximum 256), majd a vektorokat. A vektorok a végpontjaik valós koordinátáival adottak. A sorozat végét a nulla vektor jelzi.

Specifikáció:

A program inputjának első eleme egy egész szám (N), majd ezt követi I darab N elemű, valós számból álló számsor, ahol I legalább 1, az utolsó N elemű számsorban mindegy szám nulla értékű, de előtte minden N elemű számsorban van 0-tól különböző érték.

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

Egy \(v_1=(a_1,...,a_n)\) és egy \(v_2=(b_1,...,b_n)\) vektor összege a \(v_3=(a_1+b_1,...,a_n+b_n)\) vektor. A vektorokon értelmezett összeadás művelet sorozatban alkalmazva a számokon értelmezett összeadáshoz hasonló tulajdonságokkal rendelkezik.

Feladat (f0168)

Feladat:

Készíts olyan programot, mely bekér két maximum 128 karaktert tartalmazó tömböt, majd azokat egy harmadik tömbbe összefésüli oly módon, hogy az eredmény tömb felváltva tartalmazza az első és második tömb karaktereit (a tömbelemek relatív sorrendjét megtartva). Ha valamelyik tömb elfogy, az eredményben onnantól kezdve csak a másik tömb elemei szerepelnek.

Készítsd el a programot egész tömbökkel illetve sztringekkel is.

Kapcsolódó linkek


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