Labor, 4. hét: pointerek, sztringek

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

Pointerek (mutatók), tömbök átadása függvényeknek. Sztringek alacsony szintű kezelése és a C sztringkezelő függvényei.

A mai labor feladatai pointerekkel dolgoznak; hol indirekt paraméterátadás, hol tömbök miatt.

Ha egy függvénynek átadunk egy tömböt, akkor csak a kezdőcíme adódik át, mintha egy &t[0] alakú kifejezéssel lekérdeznénk azt. Emiatt általában a tömb méretét is át kell adnunk a függvénynek. A sztringeknél ezzel szemben nincs így; mivel a sztringeknél a tömb tartalma alapján kiderül, hol van a vége (a lezáró nullánál), ezért a méretet legtöbbször felesleges átadni paraméterként. A tömb mérete és a benne lévő sztring hossza amúgy sem egyezik meg. Gondold át minden feladatnál, átadod-e a méretet!

Felkészülés a laborra:

1. Hova mutatnak a pointerek?

Alább egy kis programot látsz, benne néhány változóval – egy valóssal és pointerekkel. A rajz a program futásának 1-essel jelölt helyén mutatja, hogy milyen változók léteznek, és azon belül a pointerek hova mutatnak.

int main(void) {
    double d1 = 3.14;
    double *p1, *p2;
    p1 = &d1;
    p2 = NULL;          // 1
}

Rajzold le papíron az alábbi program futásának buborékkal jelölt helyein, hogy milyen változók léteznek, és hogy hova mutatnak a pointerek! A buborékok, ahogy látod, szándékosan időrendben vannak. Határozd meg, mit ír ki a program – annak futtatása nélkül! Aztán végül egy futtatással ellenőrizd az eredményt.

#include <stdio.h>

void func1(int i2) {
    i2 *= 2;
    printf("func1()... i2 = %d\n", i2);     // 4
}

void func2(int *p3) {
    *p3 *= 2;
    printf("func2()... *p3 = %d\n", *p3);
    p3 = NULL;                              // 5, 6
    printf("func2()... p3 = %p\n", p3);
}

int main(void) {
    int i1 = 2;
    int *p1 = NULL;
    int *p2 = NULL;
    printf("Hova mutat p1 es p2?\n");       // 1

    p1 = &i1;
    printf("&i1 = %p, p1 = %p\n", &i1, p1);
    printf("i1 = %d, *p1 = %d\n", i1, *p1); // 2
    
    i1 = 3;  printf("*p1 = %d\n", *p1);
    *p1 = 4; printf("i1 = %d\n", i1);

    p2 = p1;
    *p2 = 5;
    printf("i1 = %d, p2 = %p\n", i1, p2);   // 3
    printf("-----\n");
    
    func1(i1);
    printf("main()... i1 = %d - de miert?\n", i1);
    printf("-----\n");
    
    func2(&i1);
    printf("main()... i1 = %d - miert?\n", i1);
    printf("-----\n");

    func2(p2);
    printf("main()... i1 = %d - miert?\n", i1);
    printf("main()... p2 = %p - miert?\n", p2);

    return 0;
}

2. Kocka – cím szerinti paraméterátadás

Írj egyetlen void visszatérési típusú függvényt, amely paraméterként kapja egy kocka oldalhosszúságát (valós szám), majd cím szerint átvett paraméterekben kiszámítja (visszaadja) a kocka felületét és térfogatát! Használd ezt a függvényt a főprogramban egy 2.7 oldalhosszúságú kocka felületének és térfogatának kiszámításához!

Emlékeztető

A cím szerint átvett paraméter esetén a függvény módosítani is tudja a neki átadott változó értékét. Gyakran ezt úgy hívjuk, hogy „paramétersoron adja vissza az eredményt.” Gondolj a printf()scanf() függvénypárra: a scanf() megváltoztatja a neki paraméterként átadott változót, a printf() nem. Ezért a scanf() cím szerint veszi át azt, a printf()-nek elég az értéke:

int x;
scanf("%d", &x);
printf("%d", x);

3. Tömb és függvény

Készíts függvényt, amely paraméterként vesz át egy egész számokból álló tömböt, továbbá egy számot, amit meg kell keresnie a tömbben! Térjen vissza a megtalált számnak az indexével, vagy −1-gyel, ha nem találta meg! (Ha több előfordulás is van, akkor mindegy, melyik sorszámával tér vissza.)

Írasd ki a tömböt sorszámozott elemekkel, és ellenőrizd a függvény működését! Írd ki az indexet, vagy a „nincs találat” szöveget!

Emlékeztető

Amikor függvénynek tömböt adunk át, a tömb nem másolódik le! A függvény mindig csak a tömb elejére mutató pointert kapja meg, akár int t[] formában, akár int *t formában definiáltuk a fejlécében a formális paramétert. Így tetszés és ízlés szerint mindkét forma használható. De sosem szabad elfelejteni, hogy a függvényparaméter kontextusban mindkettő pointert jelent! Ezért kell mindig átadni a tömb méretét is a függvénynek, ha máshonnan nem tudná.

Alakítsd át a programot úgy, hogy ne a találat indexét, hanem annak memóriacímét adja vissza! Mit tud visszaadni ilyenkor a függvény, ha nem talált semmit? Ha ezt a függvényt kell használnod, hogyan tudod segítségével az indexet meghatározni, egy újabb keresés nélkül?

Emlékeztető

p1 + integer = p2: mutató a tömb elejére + egész szám → mutató a tömb valahányadik elemére. Emiatt p2 - p1 = integer is igaz kell legyen – és tényleg, ki lehet számolni, hányat kell ugrani az egyik memóriacímtől a másikig.

Alakítsd át úgy is a programot, hogy a ciklusok tömbindexek helyett pointerekkel dolgozzanak, az előadáson bemutatott módon.

Emlékeztető

Ha p pointer típusú változó esetén p + 1 leírható, akkor p = p+1 is. Akkor pedig p += 1 is és ++p is. Így lehet lépkedni a tömbben.

Hasonló feladatok

Ha ez a feladat nehezen ment, példatárban itt találsz hasonlókat, amiken a labor után gyakorolhatsz otthon.

4. Függőlegesen

Készíts programot, mely bekér és eltárol egy keresztnevet, majd azt betűnként függőlegesen lefelé kiírja. Például ha a név „Imre”, akkor az eredmény:

I
m
r
e
Tipp

Hogy lehet beolvasni egy szót a billentyűzetről? Mekkora karaktertömbre van ehhez szükség? Mi történik akkor, ha túl kicsi a karaktertömb, ahhoz képest túl hosszú a felhasználó neve?

Hasonló feladatok

Ha ez a feladat nehezen ment, megoldhatsz pár hasonló feladatot a példatárból, mielőtt a következő feladatra rátérsz.

Vigyázz, a laborfeladatokat erősen ajánlott az utolsó feladatig megoldani, hogy a jövő hétre felkészült legyél. Ha nem sikerül, fejezd be őket otthon!

5. Trimmer

Gyakori feladat, hogy egy sztring elejéről és végéről el kell távolítani a szóközöket. Ezt a függvényt gyakran trim()-nek szokták hívni.

Írj függvényt, amelyik egy paraméterként kapott sztring elejéről és végéről eltávolítja a szóköz karaktereket (a többi maradjon)! Pl. ha a bemenet "  helló, mizu?   ", akkor az új sztring "helló, mizu?" legyen. A függvény vegyen át két paramétert: egy forrás tömböt (ebben van a szóközös sztring) és egy cél tömböt (ebbe kerül a szóköz nélküli).

Meg kell ennek a függvénynek kapnia a tömb méretét? Miért?

6. További feladatok

Ha elkészültél, gyakorlásnak folytathatod a példatár sztringes feladataival!