kategória | ||||||||||
|
||||||||||
|
||
Dinamikus memória allokálás. Függvények és pointerek kapcsolata.
Dinamikus memóriakezelés
A pointerek után nézzük a dinamikus memóriakezelést. Ez a dolog onnan kezdődik,
hogy memóriát foglalunk magunknak, és erre egy pointerrel hivatkozunk. Kezdjük
ott, hogy mennyi memóriát foglalhatunk, és hol. Ez mindig a memóriamodelltol
függ. A small és tiny modellekben a rendelkezésünkre álló terület az
adatszegmens végétől a stack tetejéig tart. Egy vékony sávot kivéve a stack
előtt. Ez persze kisebb, mint 64k. A compact large és huge modelleknél a
lefoglalható terület a 838g65i stack végétől a memória végéig tart.
Mi maradjunk csak SMALL-ban. Ekkor az összes adat maximum egy szegmens lehet.
Tehát a statikus, és a dinamikus együtt 64k lehet. Hogy mire jó? Segítségével,
mint ahogy az nevéből is következik, futási idő alatt dinamikusan hozhatunk
létre változókat. Ez azért előnyös, mert bizonyos esetekben nem tudhatjuk
előre, pl. egy tömb, egy karakter, vagy egy láncolt lista elemszámát, ezért a
statikus memóriakezelés teljesen csődöt mond. Arról nem is beszélve, hogy pl.
egy statikusan kezelt globális hosszú tömb a program egész futási ideje alatt
ott foglalja a memóriát, míg egy dinamikusan lefoglalt területet bármikor
felszabadíthatunk, ha már nem kell. Ennyi elméletileg.
Gyakorlatilag: használhatjuk olyan tömbök létrehozására, melynek elemszáma
futási időben derül ki. pl.: file beolvasás. Segítségével megvalósíthatunk
bizonyos logikai adatszerkezeteket. pl.: sor, verem, bináris fa ... És utoljára
de nem utolsósorban (habár ez már nem az a klasszikus dinamikus memóriakezelés)
kiterjeszthetjük az adatméretet a memóriamodellben maximált fölé, ha nem a
heap-bol foglalunk, hanem a DOS-tól. Ugyanis a C a Pascallal ellentétben nem
foglalja le az összes memóriát ahogy a program elindul, csak annyit, amennyi az
adott memóriamodell kezel. Így aztán small módban jó megközelítéssel van még
400k DOS memóriánk, amit dinamikus kezeléssel igen könnyen kihasználhatunk
(persze csak szegmensenként), nélküle azonban sehogy.
Azt már tudjuk, hogy egy szál pointert nyugodtan kezelhetünk tömbként. Az új a
malloc() függvény használata volt. Vele tudunk a heap-ből memóriát foglalni.
Egyedül a lefoglalandó byte-ok számát kel megadni paraméterként, és a lefoglalt
memóriaterület kezdőcímével (egy pointer) tér vissza. Már ha sikerült
lefoglalnia, egyébként NULL. Azt hiszem némi magyarázatra szorul az-az, (int *)
a függvényhívás elott. Nos ezt nevezik Cast-olásnak (kikényszerített
típuskonverzió). nagyjából annyit tesz, hogy megmondja a fordítónak a mögötte
álló kifejezés típusát. Tehát azt mondjuk a fordítónak: figyelj öreg ez nem
akármilyen, hanem, egy int-re mutató pointer ám. Ha ezt nem tennénk a compiler
valami can't convert void * to int * hibaüzenettel dobna meg minket. Mivelhogy
a szerencsétlen convertálni akar. Ezért aztán ehhez hasonlóan akárhányszor
egymással nem megegyező típusú pointereket akarunk egymással megfeleltetni,
castolnunk kell. Ami még új lehet, az a size() használata. Ez a függvény
megadja a paraméterként megadott típus méretét byte-okban. Használatára azért
van szükség, mert a malloc()-nak byte-okban kell megadni a lefoglalandó terület
hosszát.
Pointertömbök
Tekintsük a következô definíciót : int *w[5];
Ez a definíció egy olyan 5 elemű vektort definiál amelynek minden eleme egy integerre mutató pointer. Ez a konstrukció kiválóan alkalmas változó hosszúságú integer vektorok kezelésére, amit a 30. sz. példaprogram mutat be.
Fontos : Az int *w[5]; definíció nem tévesztendô össze az int (*w)[5]; definícióval. Az utóbbi ugyanis egyetlen pointert definiál, ami egy 5 elemű integer vektorra mutat. Ebben az esetben tehát a w++ művelet 5 integernyit azaz 10 byte-ot léptet.
/* ======= Változó hosszúságú integer vektorok ========== */
/* ======= kezelése pointertömb
segítségével ========== */
#include <stdio.h>
int *pvek[5];
int v0[3] = ;
int v1[5] = ;
int v2[2] = ;
int v3[4] = ;
int v4[6] = ;
int lv[5] = ; // A vektorok hosszai
void main()
A pointertömbök alkalmazásának még gyakoribb esete a char típusú pointer-tömbök alkalmazása változó hosszú stringek kezelésére.
Függvényre mutató pointer
/ Példa függvényre
mutató pointer használatára */
#include <stdio.h>
#include <conio.h> // A getch() függvény miatt
#include <math.h> // Az sqrt() függvény miatt
void main()
w = func(x,y,z);
printf("\nEredmény =
%5.2f",w); getch();
}
// A három függvény
megvalósítása
float osszeg( int o1, int o2, int
o3 )
float atlag( int a1, int a2, int a3
)
float gyok( int g1, int g2, int g3
)
Mint látható a függvényre mutató pointer alkalmazása akkor nagyon hasznos, amikor ugyanazokon az adatokon más más műveletet kell elvégezni. A pointernek úgy adhatjuk át az aktuális függvény címét, hogy a függvény nevét használjuk, hasonlóan a vektoroknál látottakhoz.
Függvényekre mutató pointertömbök
/* Példa függvényre mutató pointertömb
használatára */
#include <stdio.h>
#include <conio.h>
#include <math.h>
void main()
// A három függvény
megvalósítása
float osszeg( int o1, int o2, int
o3 )
float atlag( int a1, int a2, int a3
)
float gyok( int g1, int g2, int g3
)
Egyértelmüen kiderül, hogy a pointertömb alkalmazása miatt nincs szükség a case szerkezetre, hanem közvetlenül tudjuk hívni a kívánt függvényt !
Találat: 1700