A verem (stack) A verem egy olyan struktúra, aminek a tetejére betehetünk egy új (vagy sorban több) elemet a tetejéről kivehetünk egy (vagy sorban több) elemet A verem felhasználása Függvény visszatérési címe ide kerül 1 Függvényparaméterek ebbe kerülnek Lokálisan deklarált változók Operátorok kiértékelése itt történik Függvény visszatérési értéke ennek a tetejére kerül 1 Ennek a mikéntjét most nem tárgyaljuk
A verem működése kétparaméteres művelet végzésekor i n t a ; a = 1 + 2 ; A program fenntart egy helyet a lokális változónak Beteszi a konstansokat a verem tetejére Kivesz a verem tetejéről két számot Elvégzi velük a műveletet Leteszi az eredményt a verem tetejére Beálĺıtja a változó értékét A verem alakulása: 2 1 a =? + operátor: két elemet kivesz, egyet betesz 3 a =? értékadás: egy elemet kivesz, lokális változó értékét beálĺıtja a = 3
A verem működése függvényhíváskor A hívó kód leteszi az összes függvényparamétert a verembe, egyesével, a sorrendre ügyelve A hívó kód meghívja a függvényt A hívott függvény elvégzi a műveleteket Eközben a veremből kiszedegeti az összes paramétert Hozhat létre lokális változókat A végeredményt beteszi a verembe tetejére, ez a visszatérési érték Visszatér a hívó függvényhez, amelyik a verem tetején találja a visszatérési értéket
Tudnivalók 1. A függvény sosem áshat mélyebbre a veremben, mint ahol a verem teteje a függvényhívás előtt volt 2. Egy függvény meghívása után mindig leüríti a vermet addig, ameddig a függvényhívás előtt volt: kiveszi az összes paraméterét és lokális változóját 3. Függvényparaméterek ebbe kerülnek 4. Visszatéréskor a függvény mindig leteszi a visszatérési értéket a verem tetejére 5. Ha egy paramétert érték szerint adunk át, akkor az bemásolódik a verembe 6. Ha cím szerint adunk át egy paramétert, akkor annak csak a mutatója másolódik be a verembe
A halomterület (heap) A verem nagyon gyorsan elérhető (mindig tudjuk, hol a teteje) véges méretű (a program előre fix méretet foglal neki) lefoglalása: lokális változó deklarálása függvény visszatérésekor a lokális változók elvesznek Ha nagy memóriaterületre van szükség a halomterületről (heap) lehet lefoglalni malloc, realloc stb. függvények free függvény - kézzel kell felszabadítani! a heap tartalmára csak pointereken keresztül hivatkozhatunk
A heap A heap elérése lassú: Foglaláskor meg kell nézni, hogy van-e elég nagy egybefüggő terület Le kell könyvelni a foglalásokat és felszabadításokat Használatkor pointert kell feloldani, ez lassú (stack esetében csak ki kell kapni az értéket a legtetejéről) Előnye: Megmarad függvényhívások között is, hiszen nem a stack-en van lekönyvelve Problémák Sok foglalás és felszabadítás: a memória felaprózódik Nem lesz elég hely egy nagy, egybefüggő blokk lefoglalására Memória-fragmentáció
Tömbök allokálása a stack-en double a [ 1 2 ] ; emiatt csak lokális függvény látja, hiszen a stack leürül visszatérés előtt return &a; értelmetlen címet ad vissza, hiszen a stack-re mutat, ami már leürült mivel a stack-en szűkös a hely, csak kicsi lehet viszont gyors az elérése Figyelem: a szögletes zárójelek között csak konstans állhat! GCC lefordítja, ha ott változó áll, de ez nem szabványos más fordítók meghalnak tőle (pl. Intel C)
Tömbök allokálása a stack-en double a [ 3 ] [ 5 ] ; ez 3 5 = 15 db 8 bájtos blokkot foglal a stack-en mindig a legutolsó index szerint jönnek sorban az elemek [0][0] [0][1] [0][2] [0][3] [0][4] [1][0] [1][1] [1][2]...
Stack-en allokált tömbök Stack-en allokált tömbök átadhatók függvénynek A mérete csak konstans lehet GCC erre tud egy trükköt, de megint csak nem szabványos! i n t myfunc ( double b [ 1 2 ] ) {... } i n t main ( ) { i n t a [ 1 2 ] ;... myfunc ( a ) ; }
Többindexes tömbök allokálása heap-en double a ; a = ( double ) m a l l o c (N s i z e o f ( double ) ) ; f o r ( i = 0 ; i < N; i ++) { a [ i ] = ( double ) m a l l o c (M s i z e o f ( double ) ) ; } Problémák: Ez M + 1 memóriallokációval jár Korábban láttuk, hogy ez lassú, és fragmentálja a memóriát A lineáris algebra csomagok (pl. LAPACK) nem szeretik