Kihagyás

8. gyakorlat

5. ZH

A gyakorlat elején 40 percben kerül megírásra az 5. zh. A feladatok témái:

  • algoritmus elkészítése
  • függvények megírása, bemenet/kimenet kezelés nélkül
  • tömbökön végzett műveletek
  • a struct típus használata

Pointerek

Új dinamikus változó létesítése

1
p=malloc(sizeof(E));

A malloc(S) függvény lefoglal egy S méretű memóriaterületet a program számára. A sizeof(E) megadja, hogy egy E típusú változó mekkora helyet igényel a memóriában. A malloc(sizeof(E)) hatására tehát létrejön egy új E típusú érték tárolására (is) alkalmas változó, és ez a változó lesz a p értéke.

Pointer dereferencia

1
*p

A * művelet segítségével érhetjük el a p értékét, vagyis a dinamikus változót. A *p változóhivatkozás a p értékére, vagyis a dinamikus változóra hivatkozik, tehát a *p értéke a dinamikus változó értéke lesz.

Dinamikus változó törlése

1
free(p);

A művelet hatására a p-hez tartozó memóriaterület felszabadul, ezáltal a dinamikus változó megszűnik. A művelet végrehajtása után a p pointerhez nem tartozik érvényes változó, ezért a *p változóhivatkozás végrehajtása jobb esetben azonnali futási hibát eredményez. (Rosszabb esetben pedig olyan lappangó hibát, aminek az eredménye a program egy teljesen más pontján jelenik meg.)

A címképző művelet

1
p = &i;

A művelet meghatározza egy változóhoz tartozó memória mező címét. Ha egy p pointer típusú változó értéke az i változóhoz tartozó memória címe, akkor azt mondjuk, hogy a p i-re mutat.

A pointerek megértésében segíthetnek az alábbi videók is:

  • Pointer alapok:

    ytv_ptr1

  • malloc:

    ytv_malloc

  • free:

    ytv_free

Feladat (f0215)

Feladat:

Futtasd le a cim.c programot, és értelmezd! Melyik érték melyik értékkel egyenlő, és miért?

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

#include <stdio.h>

int main() {
    int a = 10;
    int *pa;
    pa = &a;
    printf(" a=%18d   pa=%#18llx\n", a, (long long int)pa);
    printf("&a=%#18llx  &pa=%#18llx\n", (long long int)&a, (long long int)&pa);
    printf("                       *pa=%18d\n", *pa);
    return 0;
}
cim.c

Válaszok
  • A pa és &a értékek egyenlőek, mert a 14. sor miatt a pa az a változó címét tartalmazza, a pa az a változóra mutat.
  • Az a és *pa értéke megegyezik, hiszen a pa az a változóra mutat, tehát a pa által referált változó értéke az a változó értéke.

Feladat (f0216)

Feladat:

Javítsd ki a csere.c program csere függvényét (és a hozzá tartozó hívást) úgy, hogy megcserélje a main két változójának értékét.

 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>

void csere(int x, int y) {
    int tmp;
    tmp = x;
    x   = y;
    y   = tmp;
}

int main() {
    int x = 3, y = 5;
    printf("A függvény előtt: x = %d, y = %d\n", x, y);
    csere(x, y);
    printf("A függvény után: x = %d, y = %d\n", x, y);
    return 0;
}
csere.c

Ötlet (f0216)

A probléma az, hogy a függvény a két argumentum értéket veszi át, ezt eltárolja az x és y paraméterekben, majd a (technikailag lokális változóként működő) x és y paraméterek értékét cseréli meg. Ha e helyett a függvény azt kérné el, hogy hol van a memóriában ez a két érték, és ennek a két memóriaterületnek az értékét cserélné meg, akkor valójában a main függvény x és y változójának értékét cserélné fel. Vagyis a függvénynek két memóriacímet (pointert) kellene átvennie paraméterként, és híváskor a main két változójának a címét kellene átadni. A függvénynek a két pointer által dereferált értéket kellene megcserélnie.

Lehetséges megoldás (m0216.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
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 *
 * Keleti Márton, 2018. őszi félév.
 *
 * Feladat:
 *    Javítsd ki a csere.c program csere függvényét (és a hozzá tartozó hívást)
 *    úgy, hogy megcserélje a main két változójának értékét.
 *
 * Megoldás:
 *    A csere() függvényben pointereken keresztül kicseréljük a két változó
 *    értékét.
 */

#include <stdio.h>

void csere(int *x, int *y) {
    int tmp;
    tmp = *x;
    *x   = *y;
    *y   = tmp;
}

int main() {
    int x = 3, y = 5;
    printf("A függvény előtt: x = %d, y = %d\n", x, y);
    csere(&x, &y);
    printf("A függvény után: x = %d, y = %d\n", x, y);
    return 0;
}

A fenti feladattól eltérő, a változók cseréjéről készült kapcsolódó videó:

ytv_swap

Feladat (f0214)

Feladat:

Elemezd és futtasd a pointerek.c programot. Mi a különbség p, q, illetve *p és *q értéke között?

 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
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 */

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

int main() {
    /* Két pointer deklarációja */
    int *p, *q;
    /* Két int típusú dinamikus változó létrehozása (memóriafoglalás) */
    p = malloc(sizeof(int));
    q = malloc(sizeof(int));
    /* Értékadás a két dinamikus változónak */
    *p = 3;
    *q = 3;
    printf("p és q %s\n", p == q ? "megegyezik" : "nem egyezik meg");
    printf("*p == %d, *q == %d\n", *p, *q);
    *p = 4;
    printf("*p == %d, *q == %d\n", *p, *q);
    free(p);
    p = q;
    printf("p és q %s\n", p == q ? "megegyezik" : "nem egyezik meg");
    printf("*p == %d, *q == %d\n", *p, *q);
    *p = 4;
    printf("*p == %d, *q == %d\n", *p, *q);
    free(p);
    return 0;
}
pointerek.c

Válaszok (f0214)
  • p és q két pointer, két memóriacím, amik egyszer a 16. és 17. sorban kapnak különböző értékeket, majd a 26. sortól megegyeznek.
  • *p és *q a p és q változók által mutatott, a 16. és 17. sorban a malloc() segítségével létrehozott két különböző dinamikus változó, legalábbis a 25. sorig. A 25. sorban az addig *p-vel hivatkozott, 16. sorban létrehozott dinamikus változót megszüntetjük, majd a 26. sortól az értékadás miatt a *p és *q ugyanazt a dinamikus változót jelöli.
  • Vagyis a 26. sorig a *p és *q két különböző (dinamikus) változó(-ra hivatkozik), a 26. sortól pedig a *p és *q ugyanaz az egy (dinamikus) változó (ugyanarra hivatkozik).

Feladat (f0191)

Feladat:

Egészítsd ki a malloc-free.c programot úgy, hogy a végrehajtása során ne keletkezzen futási hiba!

  • A 12. sorban inicializáld a változókat!
  • A 14. sorba szúrj be egy utasítást!
  • A kettő közül melyik a helyes megoldás? A másik (önmagában) miért nem jó?

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

int main() {
    int *p, *q;
    p = malloc(sizeof(int));

    free(q);
    return 0;
}
malloc-free.c

Lehetséges megoldás (m0191-1.c)
 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 <stdlib.h>

int main() {
    int *p = NULL, *q = NULL;
    p = malloc(sizeof(int));

    free(q);
    return 0;
}
Lehetséges megoldás (m0191-2.c)
 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 <stdlib.h>

int main() {
    int *p, *q;
    p = malloc(sizeof(int));
    q = p;
    free(q);
    return 0;
}
Válaszok (f0191)

A kettő közül a második verzió, azaz a q = p; utasítás beszúrása a 14. sorba a helyes. Az első verzióval az a baj, hogy bár a free(q) hívás NULL pointert kap, és a free() függvény NULL pointer argumentum esetén nem dob hibát, a p által mutatott memóriaterület nem lesz felszabadítva.

Megjegyzés

Az igazán szép és helyes megoldás, ha mindkét előző "korrekciót" egyszerre alkalmazzuk, vagy is a két változó inicializálása mellett szúrjuk be a q = p; utasítást a 14. sorba.

A malloc-ot több elem (tömbök) egyszerre történő lefoglalásához is használhatjuk. Amikor egy tömbnek ilyen módon foglalunk memóriát, akkor azt mondjuk, hogy a tömb egy dinamikus tömb. A dinamikus tömbökről az alábbi videó ad részletes magyarázatot:

ytv_din_array

Azt már lehet sejteni, hogy a tömbök és a pointerek igen szoros kapcsolatban állnak egymással. Ezt a szoros kapcsolatot magyarázza el az alábbi videó:

ytv_arr_ptr_conn

Feladat (f0217)

Feladat:

  1. Írj egy programot, amelyben deklarálj egy 10 elemű int tömböt, majd töltsd fel értékekkel a standard inputról! Írasd ki a tömb elemeit.

  2. Az előző programban deklarálj egy int pointert is, és a beolvasást ennek segítségével valósítsd meg!

  3. Most az első tömbelem értéke előtt kérd be a tömb méretét (a beolvasandó elemek számát). Mi történik, ha 10-nél kisebb értéket, 10-et, 10-nél nem sokkal nagyobb értéket, illetve 10-nél sokkal nagyobb értéket adsz meg elemszámként?

  4. Ezután töröld a tömb deklarációját és az azonosítóját pointerként deklaráld! Az elemszám megadása után de a tömbelemek bekérése előtt dinamikusan foglalj helyet a tömb elemei számára (pontosan annyit, amennyi kell)! Most mi történik, ha tömbméretnek különböző értékeket adsz meg?

Lehetséges megoldás (m0217-1.c)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 */

#include <stdio.h>

#define N 10

int main() {
    int tomb[N], i;
    for(i = 0; i < N; ++i) {
        scanf("%d", &tomb[i]);
    }
    for(i = 0; i < N; ++i) {
        printf("%d%s", tomb[i], (i == N - 1) ? "\n" : ", ");
    }
    return 0;
}
Ötlet (f0217/2)

Ha egy pointer egy tömb valamelyik elemére mutat, akkor a pointer eggyel növelt értéke a tömb következő elemére fog mutatni. (Általában a pointer i-vel növelt értéke a tömb pointer által mutatott elemétől számolt i. elemre fog mutatni.) A scanf egy memóriacímet vár, ahová eltárolhatja a beolvasott értéket (ezért kellett a változók elé az & jel); a pointer értéke pedig önmagában egy memóriacím. Vagyis, ha a beolvasó ciklus elején a pointer a tömb első elemére mutat, akkor a pointert minden ciklus végén eggyel-eggyel növelve az szépen végigmegy az összes tömbelemen. A scanf-nek pedig ezt a pointer értéket kell átadni, hiszen ez mutat arra a tömbelemre, ahová az éppen beolvasott értéke el kell tárolni.

Lehetséges megoldás (m0217-2.c)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 */

#include <stdio.h>

#define N 10

int main() {
    int tomb[N], i, *ptr;
    for(i = 0, ptr = tomb; i < N; ++i, ++ptr) {
        scanf("%d", ptr);
    }
    for(i = 0; i < N; ++i) {
        printf("%d%s", tomb[i], (i == N - 1) ? "\n" : ", ");
    }
    return 0;
}
Lehetséges megoldás (m0217-3.c)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 */

#include <stdio.h>

#define N 10

int main() {
    int tomb[N], i, *ptr, n;
    scanf("%d", &n);
    for(i = 0, ptr = tomb; i < n; ++i, ++ptr) {
        scanf("%d", ptr);
    }
    for(i = 0; i < n; ++i) {
        printf("%d%s", tomb[i], (i == n - 1) ? "\n" : ", ");
    }
    return 0;
}
Válaszok (f0217/3))
  • 10-nél nem nagyobb érték esetén nincs probléma: legfeljebb annyi történik, hogy a program nem használja fel a tömb összes elemét, így azok feleslegesen lesznek lefoglalva, de ez a program futásában nem okoz problémát.
  • 10-nél kicsit nagyobb érték megadása lehet, hogy furcsa viselkedést idéz elő a programban. Működhet látszólag jól, helyesen, esetleg rendellenes viselkedést tapasztalhatunk (pl. több elemet olvas be, kevesebbet ír ki) vagy látszólag helyes működés mellett kiírhat stack hiba miatti leállást ("stack smashing detected").
  • 10-nél sokkal (nagyságrendekkel) nagyobb szám esetén simán memóriahibával ("Segmentation fault") elszáll.
Ötlet (f0217/4)

Használd a malloc függvényt, és ne feledkezz meg a memória felszabadításáról (free) sem!

Lehetséges megoldás (m0217-4.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
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 */

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

int main() {
    int *tomb, i, *ptr, n;
    scanf("%d", &n);
    tomb = malloc(n * sizeof(int));
    for(i = 0, ptr = tomb; i < n; ++i, ++ptr) {
        scanf("%d", ptr);
    }
    for(i = 0; i < n; ++i) {
        printf("%d%s", tomb[i], (i == n - 1) ? "\n" : ", ");
    }
    free(tomb);
    return 0;
}
Válaszok (f0217/4))
  • A program bármekkora (a gép fizikai korlátai által megengedett) pozitív elemszámra helyesen működik.

Feladat (f0221)

Feladat:

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

  • Vedd N értékét valamivel nagyobbra.
  • Vedd M értékét valamivel nagyobbra.
  • Vedd K értékét valamivel nagyobbra.
  • Vedd K értékét valamivel kisebbre.

Mely esetekben hogyan viselkedik a program a futás során? Mi az oka a tapasztalt viselkedésnek?

 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
/*
 * Szegedi Tudományegyetem
 * Informatikai Tanszékcsoport
 * Szoftverfejlesztés Tanszék
 *
 * Programozás Alapjai
 */

#include <stdio.h>

#define N 42
#define M 7
#define K 294

int main() {
    int tomb[N][M];
    int i = 0, j = 0, *p = NULL, *t = NULL;
    p = t = (int*)tomb;
    while (p < t + K) {
        *(p++) = i++;
    }
    for (i = 0; i < N; ++i) {
        for (j = 0; j < M; ++j) {
            printf(" %7d", tomb[i][j]);
        }
        putchar('\n');
    }
    return 0;
}
tombbejaras.c

Válaszok (f0221)
  • Ha több sor van (N-t növeljük), akkor a tömb sorfolytonosan kerül feltöltésre, az utolsó elemek értékei véletlenszerűek lesznek.
  • Ha több sor van (M-et növeljük), akkor a tömb sorfolytonosan kerül feltöltésre, az utolsó elemek értékei véletlenszerűek lesznek.
  • Ha több elemet töltünk fel, mint amekkora a tömb (K-t növeljük), akkor a program kiszámíthatatlan módon működik. Elszállhat memóriahibával, furcsán viselkedhet, de az is lehet, hogy nem tapasztalunk semmi különöset (ha K-t csak kicsivel növeljük).
  • Ha kevesebb elemet töltünk fel, mint amekkora a tömb (K-t növeljük), akkor a tömb sorfolytonosan kerül feltöltésre, az utolsó elemek értékei véletlenszerűek lesznek.

Fun feladat

Feladat

Készíts egy programot, amely bekér egy magasságot illetve egy karaktert, majd kirajzol egy ilyen magas piramist, az így megadott karakterből.

Példa:

1
2
3
4
5
6
7
Add meg, hogy milyen magas legyen a piramis: 5
Add meg milyen karakterbol epuljon fel a piramis: A
    A
   AAA
  AAAAA
 AAAAAAA
AAAAAAAAA

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
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>

void piramis (int magassag, char betu) {
    int i, j, 
        B = 1,                          // kezdetben 1 karaktert kell kiirni
        H = magassag - 1;               // kezdetben egyel kevesebb helykoz kell, mint amilyen magas a piramis
    for (i = 0; i < magassag; ++i) {    // magassag-szor kell lefutnia, mivel enni sor lesz
        for (j = 0; j < H; ++j) {       // a H tarolja az aktualis helykozszamot
            putchar(' ');
        }
        /* Alternatíva a fenti for ciklus helyett:
            printf("%*c", H, ' ');
        */
        for (j = 0; j < B; ++j) {       // a B tarolja az aktualis betuszamot
            putchar(betu);
        }
        B += 2;                         // mindig kettovel tobb beto es
        H -= 1;                         // 1-gyel kevesebb helykoz kell
        putchar('\n');                  // dobjunk egy uj sort, mikor megvolt egy sora a piramisnak
    }
}


int main() {
    int magassag;
    char betu;
    printf("Add meg, hogy milyen betubol epuljon fel a piramis: ");
    scanf("%c",&betu);
    printf("Add meg, hogy milyen magas legyen a piramis: ");
    scanf("%d",&magassag);
    piramis(magassag, betu);    // piramis fuggveny meghivasa - parameterek: magassag es a hasznalando karakter
    return 0;
}

Challenge - Matrix Code Rain

Feladat

Készítsünk egy programot, mely a "Mátrix" című filmben látható "code rain"-t valósítja meg!

1 Hour Matrix Rain Code

Figyelem!

Ez a feladat már túlmutat a törzsanyagon, így ennek elkészítését csak azoknak ajánljuk, akik már megbirkóztak az egyszerűbb pointer-es feladatokkal.

Lehetséges megoldás (Videó)

ytv_code_rain

Feladatok

Feladat

Írj függvényt, ami egy tömböt és a tömbben lévő elemek számát várja paraméterül, visszatérési érték nincs. Bekérünk a felhasználótól egy pozíciót és egy értéket, és elhelyezi az értéket az adott pozíción a tömbben. A függvényt a main függvényen belül hívd meg, miután feltöltötted a tömböt tetszésed szerint. (A tömb mérete mindenképpen nagyobb kell, hogy legyen a híváskor benne lévő elemek számánál, hogy tudjunk még új elemeket beszúrni).

Példák:

  1. példa:

    • A tömb: [2, 5, 7, 45]
    • Input: 2 1000
    • Output: [2, 5, 1000, 7, 45]
  2. példa:

    • A tömb: [2, 5, 1000, 7, 45]
    • Input: 0 55
    • Output: [55, 2, 5, 1000, 7, 45]

Tehát az adott pozícióra (0-tól indexszelünk) az új érték kerül és minden elem eggyel arrább tolódik.

Figyelj!

Figyelj arra, hogy a tömb mérete elég legyen ahhoz, hogy a beszúrt elemek is elférjenek benne!

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
23
24
25
26
27
28
29
30
#include<stdio.h>

int beszur (int tomb[], int elemszam) {
    int poz, ertek, i, j;

    printf("Adj meg egy poziciot es egy erteket: ");
    scanf("%d %d", &poz, &ertek);   // a poz valtozoba megy a kivant pozicio, az ertek valtozoba pedig az ertek
    /* a tomb vegetol haladunk az eleje fele es mindig eggyel jobbra masolunk minden elemet
    egesz addig, mig el nem erunk ahhoz a poziciohoz, ahova az elemet be kell szurni */
    for (i = elemszam - 1; i > poz; --i) {
        tomb[i] = tomb[i - 1];    // atmasolas
    }
    tomb[poz] = ertek;    // miutan arrabb masoltunk mindenkit, behelyezzuk a beolvasott szamot a helyere
    /* mivel az elemszam valtozo jelzi, hogy hany elemunk van a tombben, most pedig egyet beleraktunk, 
    ezert egyel tobb elemunk van, tehat novelni kell az erteket eggyel */
    ++elemszam;

    // tomb kiiratasa
    for (i = 0; i < elemszam; ++i) {
        printf("%d ", tomb[i]);
    }
    printf("\n");
}

int main() {
    int t[20] = {2, 5, 7, 45};  // tomb letrehozasa
    beszur(t, 4);               // fuggvenyhivas

    return 0;
}
Feladat

Írj függvényt, aminek a bemeneti paramétere egy karaktertömb, visszatérési értéke a karaktertömb hossza a feladat elvégzése után. A függvényen belül:

  1. Cseréld ki a kapott tömb összes kisbetűjét nagybetűre, a nagybetűket pedig kisbetűre. Példa:

    • Input: "Bela nem hajlando Dezso nelkul Las Vegasba menni."
    • Output: "bELA NEM HAJLANDO dEZSO NELKUL lAS vEGASBA MENNI."
  2. Vedd ki az összes helyközt a karaktertömbből. Példa:

    • Input: "Bela elment megkapalni a lekvarfoldet."
    • Output: "Belaelmentmegkapalnialekvarfoldet."

A változtatásokat a kapott karaktertömbben is végezzük el, ne csak kiíratás során végezzük el a változtatásokat. Ezt a függvényt a main függvényen belül hívd meg, miután feltöltötted a karaktertömböt tetszésed szerint.

Feladat (f0218)

Feladat:

Olvass be 5 darab maximum 99 karakter hosszú szót úgy, hogy mindegyiknek pontosan annyi helyet foglalsz, amennyi kell! A sztringeket írasd ki, majd szabadítsd fel a lefoglalt területet! (Természetesen beolvasáskor használhatsz egy átmeneti tárolót.)

Feladat

Írj egy programot, melyben egy függvény képes a paraméterben megkapott sztring megfordítására! A függvény tisztán pointer aritmetikával dolgozzon, azaz ne használj benne tömbindex operátort ([])!

Lehetséges megoldás

A lehetséges megoldást a következő videó mutatja be:

ytv_str_rev_ptr

Feladat (f0228)

Problémafelvetés:

Számítsuk ki egy mátrix transzponáltját.

Specifikáció:

A program inputja egy mátrix, (n,m)[a_11,...,a_1m,a_21,...,a_n1,...,a_nm] alakban, ahol n a sorok, m az oszlopok száma (egész számok), a_ij pedig valós szám, a mátrix i. sorának j. eleme, (azaz a mátrix elemeit sorfolytonosan adjuk meg). A program outputja a transzponált mátrix az inputhoz hasonló alakban.

Algoritmustervezés:

Dinamikus memóriafoglalással dolgozzunk. A transzponálást valóban végezzük el, ne csak a kiíratás során.

Segítség (videó)

Segítséget adhat a dinamikus tömbfoglaláshoz a következő videó:

ytv_din_arr_alloc

Feladat (f0230)

Problémafelvetés:

Egy számsorozat negatív és nemnegatív elemeit kell szétválogatni.

Specifikáció:

A program inputja egy A számsorozat (n)[a_1,...,a_n] alakban megadva. A kimenet első sora az A negatív elemeiből, a második sora az A nemnegatív elemeiből képzett számsorozat, az inputhoz hasonló formában megadva. A két részsorozatban az elemek sorrendje megegyezik az eredeti sorozatban megadott sorrendjükkel.

Algoritmustervezés:

Dinamikus memóriafoglalással dolgozzunk. A két részsorozatot valóban állítsuk elő, ne csak a kiíratás során.

Feladat (f0265)

Problémafelvetés:

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

Specifikáció:

A program inputja egy A és egy B vektor, (n)[a_1,...,a_n] illetve (m)[b_1,...,b_m] alakban, külön sorban megadva. A program kimenete egyetlen szám, 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:

Dinamikus memóriafoglalással dolgozzunk.

Segítség

Egy \(A=(a_1, a_2, ..., a_n)\) és egy \(B=(b_1, b_2, ..., b_n)\) vektor skalárszorzata a \(\sum_{i=1}^{n}a_ib_i\) szám.

Részletesen lásd: Wikipedia

Feladat (f0268)

Problémafelvetés:

Készíts egy programot, amely beolvas N 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 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:

Dinamikus memóriafoglalással dolgozzunk.

További gyakorló feladatok

Feladat (f0196)

Problémafelvetés:

Írj egy programot, ami megmondja, hogy egy csoport hallgatói teljesítették-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 egy 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 először kérje be a hallgatók számát, majd foglaljon memóriát az adataik számára, és ezzel a dinamikus tömbbel dolgozzon.

Feladat (f0197)

Problémafelvetés:

Írj egy programot, ami megmondja, hogy egy csoport hallgatói teljesítették-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 egy 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 először kérje be a hallgatók számát, majd foglaljon memóriát az adataik számára, és ezzel a dinamikus tömbbel dolgozzon. 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.

Feladat (f0211)

Problémafelvetés:

Adottak síkidomok (kör, elipszis, háromszög, négyzet, téglalap) a jellemző értékeikkel. Készíts egy tömböt ilyen alakzatok tárolására, olvasd be az adataikat, majd írd ki az összterületüket. Ezután írd ki mindegyik fajtából a legnagyobb területű síkidom kerületé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.

Feladat (f0229)

Problémafelvetés:

Számítsuk ki két vektor tenzorszorzatát.

Specifikáció:

A program inputja egy A és egy B vektor, (n)[a_1,...,a_n] illetve (m)[b_1,...,b_m] alakban, külön sorban megadva. A kimenet egyetlen sor, ami az A és B vektor tenzorszorzatát (az A mint oszlopvektor és B mint sorvektor mátrixszorzatát) tartalmazza (n,m)[c_11,...,c_1m,c_21,...,c_n1,...,c_nm] alakban (azaz a mátrix elemeit sorfolytonosan kiírva).

Algoritmustervezés:

Dinamikus memóriafoglalással dolgozzunk. A műveleteket valóban végezzük el, ne csak a kiíratás során.

Segítség

Egy \(A=(a_1, a_2, ..., a_n)\) és egy \(B=(b_1, b_2, ..., b_m)\) tenzori (didaktikus) szorzata az a \(C\), \(n \times m\)-es mátrix, amelynek elemei a \(c_{i,j}=a_ib_j\) képlettel kaphatóak meg. (Ha az \(A\)-t mint sorvektort egy \(n \times 1\)-es mátrixként, a \(B\)-t pedig mint oszlopvektort egy \(1 \times m\)-es mátrixként fogjuk fel, akkor ezen két mátrix mátrixszorzatára vagyunk kíváncsiak.)

Részletesen lásd: Wikipedia

Feladat (f0266)

Problémafelvetés:

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

Specifikáció:

A program inputja egy A és egy B vektor, (n)[a_1,...,a_n] illetve (m)[b_1,...,b_m] alakban, külön sorban megadva. A program kimenete egyetlen sor, melyben az összegvektor van a bemeneti vektorok formájában kiírva, 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:

Dinamikus memóriafoglalással dolgozzunk.

Segítség

Egy \(A=(a_1, a_2, ..., a_n)\) és egy \(B=(b_1, b_2, ..., b_n)\) vektor összege a \(C=(a_1+b_1, a_2+b_2, ..., a_n+b_n)\) vektor.

Részletesen lásd: Wikipedia

Feladat (f0267)

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, 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 minden 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:

Dinamikus memóriafoglalással dolgozzunk.

Kapcsolódó linkek


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