Mutatók és mutató-aritmetika C-ben 2018 március 19
Memória a Neumann-architektúrában Neumann-architektúra: a memória egységes a címzéshez a természetes számokat használjuk Ugyanabban a memóriában van: a programkód a végrehajtáshoz használt verem (stack) az adattárolásra használt halomterület (heap)
Neumann-architektúra
A memória címzése - 4GB RAM esetén 0xFFFFFFFF program számláló verem teteje 0x00000002 0x00000001 0x00000000 verem alja
A referencia-operátor: & double a = 5 ; double p = &a ; A & operátor egy, a változó kezdőcímére mutató pointert ad vissza a változó lehet a veremben is ekkor a cím csak a függvényhíváson belül érvényes! csak hívott függvények adható át visszatérési érték nem lehet maga a pointer is egy változó a stack-en verem teteje p = 0x0 p a = 5
A mutató és a mutató típusa Mutató: olyan változó, amiben egy memóriacím van 32 vagy 64 bites szám (x86 vagy x64 architektúra) alapesetben ugyanúgy a stack-en foglal helyet, mint minden más változó A mutatónak van típusa A mutató ugyan csak egy memóriacím, de a fordító tudja, hogy a mutató milyen típusú adatra mutat double*, int*, Matrix* nem mindegy!
Mutató feloldása operátor: * Pointer által mutatott érték kiolvasása: double a = 5 ; double p = &a ; double b = p ; A pointer által mutatott memória írása: double a = 5 ; double p = &a ; p = 6 ; p r i n t f ( %l f, a ) ; Mit fog kíırni az utolsó sorban a printf?
Figyelem! Ez nem működik: double p ; p = 5 ; Sőt, még ez sem: double a = 5 ; double p ; p = a ; A pointer alapból nem mutat sehova! Ugyanúgy be kell álĺıtani az értékét (azaz a memóriacímet), mint más változónál
Helyfoglalás a heap-en Lefoglalunk valamennyi memóriát: double p ; p = ( double ) m a l l o c (100 s i z e o f ( double ) ) ; p = 5 ; A malloc függvény lefoglalja az előírt számú bájtot visszatér a memóriaterület kezdetének címével????? p 5
Pointerek és tömbök: [ ] operátor A mutatott címhez képest relatív: double p ; p = ( double ) m a l l o c (100 s i z e o f ( double ) ) ; p [ 0 ] = 5 ; p [ 1 ] = 6 ; A [] operátor a tömbön belüli elemet adja vissza tudja, hogy mennyit kell lépni a memóriában???? p[1] = 6 p p[0] = 5
Tömbök és pointerek Ez is működik: double a [ 1 0 ] ; double p ; p = a ; p [ 5 ] = 1 0 ; Sőt, ez is: double a [ 1 0 ] ; a = 5 ; De vajon lehet-e a tömb második elemét címezni tisztán pointeres írásmóddal?
A pointer valójában csak egy memóriacím Vajon ez jelent valamit? double p ; p = ( double ) m a l l o c (100 s i z e o f ( double ) ) ; ( p + 1) = 5 ; Naivan azt gondolnánk, hogy a q + 1 kifejezés a pointerben tárolt memóriacímet növeli eggyel A C fordító valójában okosabb, mert tudja, hogy a q pointer double típusú adatra mutat, így a memóriacímhez nem 1-et, hanem rögtön 8-at hozzá A következők egyenértékűek: *(p + i) p[i] p + i &p[i]
Pointereken értelmezett aritmetikai műveletek Értelmes dolog pointert egész számmal növelni és csökkenteni: double a [ 1 0 ] ; double p ; p = a + 5 ; p = 3 ; p++; Vagyis ez is működik: double a [ 1 0 ] ; double p = a ; f o r ( i = 0 ; i < 1 0 ; i ++) { p++ = i ; }
A pointer tisztában van a mutatott típus méretével Figyelem! A típusok mérete platform- és fordító függő!
Pointerek kasztolása Megszoktuk, és működik: double d = 1 1 2 3 4 ; i n t i = ( i n t ) d ; Vajon a ez a program mit ír ki? double d = 1 1 2 3 4 ; i n t p ; p = ( i n t )&d ; p r i n t f ( %d, p ) ; Válasz: hülyeséget Ugyanis a itt azt feltételezzük, hogy a p által mutatott címen integer van, pedig ott egy double szám van, ami teljesen más formátumban tárolódik a memóriában
Csupasz pointer: void* A void* a pointerek egy univerzális típusa olyankor használjuk, amikor a mutatott adat típusa mindegy például memóriafoglaláskor nem használható rá a mutató feloldása operátor: double d = 1 1 2 3 4 ; void p = &d ; // ez megy p = 5 ; // h i b a Akkor mégis mikor? például ilyen pointert ad vissza a malloc függvény emiatt kell a (double*) minden malloc elé ilyet vár a free függvény is
Tömbök másolása pointerekkel i n t i ; double a [ 1 0 ], b [ 1 0 ] ; double pa, pb ; pa = a ; pb = b ; f o r ( i = 0 ; i < 1 0 ; i ++) { pa++ = pb++; }
Pointer pointerre double a ; double pa, pb ; pa = &a ; pa = 5 ; pb = &pa ; pb = &a ; pb = 6 ;