Labor, 3. hét: tömbök

Pohl László, Czirkos Zoltán · 2016.08.28.

Tömbök létrehozása és kezelése. Egyszerű algoritmusok megvalósítása tömbökön.

Felkészülés a laborra:

1. Haladási napló

Töltsd ki a haladási naplódat a linkre kattintva: /adminhallgato?haladasinaplo.

Itt minden héten lesznek új kérdések, amik segítik a felkészülést. De a régiekre adott válaszokat is frissíteni tudod, amikor úgy érzed, megtanultál már egy adott témakört!

2. Számok szorzata

Legyen a szorzat 1.
Legyen n értéke 10.
Ismétlés, amíg n≥2
    A szorzat legyen szorzat × n.
    Csökkentem n-et eggyel.
Ismétlés eddig
Kiírom a szorzatot.

Írj programot úgy, hogy az első 10 szám (1…10) szorzatát, vagyis a 10 faktoriálisát számolja ki! Mintának használhatod az oldalt látható pszeudokódot. Tegyél a ciklus belsejébe egy olyan programsort is, amely kiírja a ciklusváltozó értékét, és a szorzatot tároló változó értékét is!

Megoldás

#include <stdio.h>

int main(void) {
    int szorzat;
    int n;

    szorzat = 1;
    n = 10;
    while (n >= 2) {
        printf("szorzat: %d, n: %d\n", szorzat, n);
        szorzat = szorzat*n;
        n = n-1;
    }
    printf("%d", szorzat);

    return 0;
}

3. Osztók összege

Adjuk meg egy felhasználótól kért szám osztóinak összegét! (Pl. 6-hoz: 1+2+3+6 = 12.) Melyik programozási tételeket kell ehhez kombinálni? Nevezd meg őket! Írd meg a programot úgy is, hogy az osztók összegébe a számot önmagát nem számítod bele! Hol kell ehhez módosítani a programot?

Tökéletes szám az, amelynél az utóbbi összeg megegyezik magával a számmal (vagyis az osztóinak összege, 1-et beleértve, de a számot magát nem). A 6 a legkisebb tökéletes szám, mert 1+2+3=6. A következők 28 és 496. Írjuk ki, hogy a kapott szám tökéletes-e!

Megoldás

Az osztók összegzéséről egyből eszünkbe juthat az összegzés tétele: ciklus a számokon, akkumulátor változóban összegzés. Az összeghez azonban nem mindegyik számot kell hozzáadni, hanem csak az osztókat, vagyis válogatunk közülük. A kiválogatás tétele haszonlít a számláláshoz: ha egy feltétel teljesül, akkor csinálunk valamit a számmal:

CIKLUS AMÍG van még szám, ADDIG
    szám = következő elem
    HA feltétel(szám), AKKOR
       KIÍR: szám
    FELTÉTEL VÉGE
CIKLUS VÉGE
#include <stdio.h>

int main(void) {
    int szam, oszto, osztoosszeg;

    printf("Szam: ");
    scanf("%d", &szam);

    osztoosszeg = 0;
    /* oszto>szam/2 mar nincsen (csak sajat maga lenne) */
    for (oszto = 1; oszto <= szam / 2; oszto += 1)
        if (szam % oszto == 0)
            osztoosszeg += oszto;

    if (osztoosszeg == szam)
        printf("Ez egy tokeletes szam.\n");
    else
        printf("Nem tokeletes szam, %d != %d.\n", szam, osztoosszeg);

    return 0;
}

4. Karakterkódok

Mit csinál az alábbi program? Hogy működik? Hogyan lehet kilépni belőle, mit jelent az end of file? Miért szerepel kétszer is a printf()-ben a betu változó? A scanf("%c", &betu) == 1 kifejezésnek egyszerre két szerepe is van, melyik ez a kettő?

#include <stdio.h>

int main(void) {
    char betu;
    while (scanf("%c", &betu) == 1) {
        printf("betu='%c', betu=%d\n", betu, betu);
    }
    
    return 0;
}

Vedd észre, hogy a programod csak akkor írja ki a betűket és a számokat, amikor sok karakter, egy teljes sor begépelése után megnyomtad az Enter-t. Ez nem azt jelenti, hogy a scanf() nem karakterenként olvas! A programod igenis karakterenként fogja megkapni a bemenetét, mert a scanf %c egy karaktert kér – csak az operációs rendszer mindig megvárja egy teljes sor beírását, mielőtt odaadná a szöveget a programodnak. Ez azért jó, mert így a felhasználó tud javítani a beírt szövegen elgépelés esetén, a program pedig már csak a javított szöveget kapja meg.

Megoldás

A program karakterenként beolvassa a felhasználó által beírt szöveget: scanf "%c", és aztán kiírja ezeket a karaktereket printf %c, és melléjük a karakterkódot %d. A printf() kétszer kapja meg ugyanazt a számot (a karakterkódot), csak először a kódnak megfelelő karaktert írja ki %c, és utána a számot magát %d. A programból fájl vége jel adásával lehet kilépni, ami Windowson F6Enter vagy Ctrl+ZEnter, Linuxon Ctrl+d.

A while () fejében lévő kifejezés két szerepe: a) beolvasni egy karaktert, b) ellenőrizni, hogy sikeres volt-e a beolvasás, és ezt ciklusfeltételként használni.

5. Túlindexelés

Mi történik a következő program futtatásakor? Mit jelent a while (true)?

#include <stdio.h>
#include <stdbool.h>

int main(void) {
    int tomb[10], i;
    
    for (i = 0; i < 10; i += 1)
        tomb[i] = i;
    i = 0;
    while (true) {
        printf("%d. elem: %d\n", i, tomb[i]);
        i += 1;
    }

    return 0;
}

Megoldás

A while (true) végtelen ciklust jelent, mert a ciklus belépési feltétele mindig igaz. Így a program „örökké” növeli az indexet, viszont előbb-utóbb már olyan memóriaterülethez ér, amelyik nem tartozik hozzá – ilyenkor az operációs rendszer leállítja a programot.

6. Legkisebb

Írj programot, amely tartalmaz egy tíz elemű tömböt, az általad megadott kezdeti értékekkel inicializálva! (Tehát nem kell a programnak egyesével beolvasnia azokat a billentyűzetről.) Írd ki ezt a tömböt!

A tömb: 25 69 54 8 77 6 29 10 3 98

Írd át úgy a programot, hogy megjelenjen a tömbelemek előtt a tömbindex is!

A tömb: [0]=25 [1]=69 [2]=54 [3]=8 [4]=77 [5]=6 [6]=29 [7]=10 [8]=3 [9]=98

Írj programrészt, amely megmondja, melyik a legkisebb szám a tömbből! Írd ki ezt a számot! (Próbáld ki a programod úgy is, hogy a legkisebb szám a tömb legelején és legvégén van!) Írj programrészt, amely megkeresi a legkisebb elemet – és utána úgy írja ki a tömböt, hogy a legkisebb elem mellé tesz egy jelzést!

A legkisebb: 3
Jelölve: 25 69 54 8 77 6 29 10 3[MIN] 98

Megoldás

#include <stdio.h>

int main(void) {
    int tomb[10] = { 25, 69, 54, 8, 77, 6, 29, 10, 3, 98 };
    int i;

    /* Kiírás */
    printf("A tömb:");
    for (i = 0; i < 10; ++i)
        printf(" %d", tomb[i]);
    printf("\n\n");

    /* Kiírás */
    printf("A tömb:");
    for (i = 0; i < 10; ++i)
        printf(" [%d]=%d", i, tomb[i]);
    printf("\n\n");

    /* Keresés */
    int min = 0;
    for (i = 1; i < 10; ++i)
        if (tomb[i] < tomb[min])
            min = i;
    /* Kiírás */
    printf("A legkisebb: %d\n", tomb[min]);
    printf("Jelölve:");
    for (i = 0; i < 10; ++i) {
        printf(" %d", tomb[i]);
        if (i == min)
            printf("[MIN]");
    }
    printf("\n");

    return 0;
}

7. Tömb léptetése

25 69 54  8 77  6 29 10  3 98
69 54  8 77  6 29 10  3 98 25
54  8 77  6 29 10  3 98 25 69
 8 77  6 29 10  3 98 25 69 54
77  6 29 10  3 98 25 69 54  8
 6 29 10  3 98 25 69 54  8 77
29 10  3 98 25 69 54  8 77  6

Írj egy programot, amely tartalmaz egy általad megadott értékekkel feltöltött, tíz elemű tömböt! Írja ki a program ezt a tömböt a képernyőre!

Léptesd egy tömb összes elemét eggyel az eleje felé. A tömb egyik végén kilépő elem jöjjön be a túlsó végén. Ismételd meg ezt a műveletet tízszer, közben mindig írd ki a tömböt! Az eredmény a jobb oldalon láthatóhoz hasonló kell legyen.

Vigyázz, nem az a feladat, hogy egy trükkös kiírást csinálj! A tömböt kell úgy megváltoztatni, hogy elmozduljanak benne az elemek. A kiírásnak mindig a tömb elejétől a végéig kell haladnia, minden sorban. A kód felépítése tehát ez kell legyen:

CIKLUS

    a tömb kiírása        itt csak printf van, nem változik a tömb

    léptetés 1-gyel balra itt változik a tömb, és nincs printf

CIKLUS VÉGE

Tipp

Segédtömbre ehhez nincs szükség! Az első felülírható a másodikkal, a második a harmadikkal… Kérdés, az utolsó helyre ilyenkor mi kerül. Rajzold le, és gondold végig úgy, minek kell történnie!

Megoldás

#include <stdio.h>

int main(void) {
    int tomb[10] = { 25, 69, 54, 8, 77, 6, 29, 10, 3, 98 };

    /* Kiírás és elemek léptetése 10szer */
    int j;
    for (j = 0; j < 10; j++) {
        int i;
        /* Kiírás */
        for(i = 0; i < 10; i++)
            printf("%2d ",tomb[i]);
        printf("\n");

        /* Léptetés */
        int tmp = tomb[0]; /* Az első elemet kell félretenni */
        for (i = 0; i < 9; i++)
            tomb[i] = tomb[i+1]; /* Léptetés */
        tomb[9] = tmp; /* Az utolsó elem a régi első lesz */
    }

    return 0;
}

8. További feladatok

Ha elkészültél, folytasd a feladatgyűjtemény ehhez a témakörhöz kapcsolódó tömbös feladataival!