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:
- A pointerekről és sztringekről szóló előadás átismétlése.
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;
}
Í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);
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.
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!
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?