C pointer működése
2017-11-17T10:43:57+01:00
2017-11-17T16:38:45+01:00
2022-07-21T09:42:41+02:00
  • Amennyire eddig át tudom látni a problémád egészét, azt nem érted, hogy micsoda maga a pointer.

    A pointer ugyanúgy egy változó, mint bármilyen más változó. A szélessége az adott környezet függvénye, mint pld 32 bites programban 4 byte-osak a pointerek, 64 bites környezetben 8 byte-osak és így tovább (16 bites legacy környezettel most nem zavarlak össze).

    Lévén csak memóriában lévő byte-okról beszélünk, valójában azoknak nincsen típusa. Amikor a processzor futtat egy programot, gőze sincsen róla, hogy a C fordító absztrakt típusai közül mit kezel éppen. A processzor csak végrehajtja a gépi kód nyelvén kapott utasításokat, és kezeli a memória tartalmát. Annak folytán a byte-ok a cpu-nak csak byte-ok még akkor is, ha kötegelve (pld 32 bites program esetén 4-esével) kezeli őket, és a C programban azok signed integer vagy unsigned integer, vagy éppen integer* (pointer) típusú adatot jelöltek. Pointer típusból van például a void* típus, és szerintem azzal kellett volna kezdened a tanulást, hogy jobban megértsd. A void az univerzális típus, amit át-casting-olhatsz bármire. pld:

    unsigned a; void* p; p= (void*)&a; a= 18; printf("a: %d\n", *(unsigned*)p);
    "a" címe "unsigned*" típus, de ha akarod, univerzálisan "csak" címmé alakítod, arra van a void*. A void* típus hivatkozásként természetesen nem képvisel önálló típust, azért szokás casting-olni valamilyen típusra, ahogy a printf() kedvéért megtettem.

    A fenti példában mind "a", mind "p" ugyan úgy 4 byte-os változók (32 bites környezetben fordítva a programot). És hogy miért lesz az egyik egy változó a másik meg a címe? Mindössze azért, mert azt mondod a cpu-nak, hogy az egyik változót használja pointerként, a másikat meg adatként, és használja fel a pointerben lévő értéket indirekt címzéshez. Az indirekt címzés a cpu egyik sajátossága, a mikrokódja lévén létező címzési típus. Arra használ fel egy adatot (számot), hogy címként értelmezve arról a memória címről olvasson be egy másik adatot (számot). Az indirekt címzés létezése folytán léteznek pointerek egyáltalán. Ha abba alaposabban másznál bele, assembly-t kellene előbb tanulnod. Profi módon érteni meg a pointereket valójában az tudna nagyon sokat segíteni.

    Ami meg a pointerek ezernyi felhasználási módját illeti, nos, az már csak a pihen agyú népség fantáziájának a következménye. Példának okáért lehet pointerezni függvény behívásokat is, nem csak adatokat, mert van rá gépi kódú utasítás, ami regiszterből veszi a címet, amire ugrik, nem kell az ugrás címének fixen fordítási időben a kódban lennie. Pld:

    #include <windows.h> unsigned fuggveny(unsigned i1) { return i1+2; } int main() { //-- unsigned a, b; void* p; //-- p= (void*)fuggveny; a= 18; b= ((unsigned(*)(unsigned))p)(a); printf("b: %d\n", b); //-- system("PAUSE"); return 0;}
    (Fordítónak 32 bites Dev-C-t használtam)

    Have fun.
    Mutasd a teljes hozzászólást!
  • A printf -ben memória cím listázására %p -t kellene használni. A cimatadas2 -ben nem a pointer memória címét, hanem a pointert kellene átadni.

    #include <stdio.h> void cimatadas2(int *poC){ printf("poC memoria cime: %p poC amit tarol, amire mutat: %p poC és erre amire mutat, tartalma: %d \n",(void*)&poC,(void*)poC,*poC); poC[0] = 4; printf("atirtam a memoria cim tartalmat egy int szammal(ami a main-ben még pointer típus volt): %p %d %d %d \n",(void*)&poC[0],*poC,poC[0],poC[1]); } int main(){ int a = 42; int* poB = &a; printf("'a' memoria cime: %p \n 'a' erteke: %d ez is az erteke: %d \n poB memoria cime: %p poB amit tarol, amire mutat: %p\n",(void*)&a,a,*poB,(void*)&poB,(void*)poB); cimatadas2(poB); printf("Visszaterunk, es 'a' memoria cime: %p \n 'a' erteke: %d ez is az erteke: \n poB memoria cime: %p poB amit tarol, amire mutat: %p (itt egy memorai cimnek kene lennie elvileg) \n",(void*)&a,a,(void*)&poB,(void*)poB); printf(" ha berinam ide %%d hez hogy poB* akkor ki is kifagyna\n"); }
    Mutasd a teljes hozzászólást!
  • Hosszú leírni a könyben szereplőt, helyette egy klasszikus mű 5. fejezetét olvasd el.
    KERNIGHAN-RITCHIE: A C programozási nyelv

    Itt van ugyanez eredeti angol kiadásban: http://cs.indstate.edu/~cbasavaraj/cs559/the_c_programming_language_..
    Mutasd a teljes hozzászólást!
  • Elsősorban minden warningot javítsál ki. Ha gcc-t használsz, ezek az opciók kellenek: -W -Wall -pedantic -Werror

    És ne legyenek 60 karakternél hosszabb sorok.

    Szerk: De a lényeget jól megfogtad: 'Nyilván ez nem igaz legalábbis a programból számomra ez jön le.' Tehát nincsenek 'típusrögzített' memóriák, csak simán bitek/bájtok/szavak/etc
    Mutasd a teljes hozzászólást!
  • A memóriát tekintsük egy egydimenziós tömbnek, melynek az egyes bájtjait a MEMÓRIA módon indexelve érhetjük el (nincs ilyen tömb a C-ben, a pointerek azonban pontosan így viselkednek).
    A csatolt ábra abban segít, hogy el tudd képzelni egy számítógép memóriájának tartalmát. Korábban már láttunk gépi kódot, ez alapján nem nehéz felismerni az utasításokat reprezentáló UT cellákat. Az AD cellák adatokat (változók, konstansok) jelentenek. A Rendszerterület lehet egyrészt az operációs rendszer adatait és utasításait tároló memóriarész, másrészt a rendes memória címtartományában más, memória jellegű perifériák is megjelenhetnek, így például a videokártya memóriája közvetlenül címezhető ebben a címtartományban, pedig az valójában a videokártyán található. (Pl ez az oka annak, hogy 32 bites Windows alatt max. 3 GB memóriát lát az operációs rendszer, a maradék 1 GB a videokártya memóriájának címtartománya).

    A memóriatérkép egy-egy cellája egy-egy bájtot reprezentál, bár a valóságban általában sokkal több utasítás vagy adat található együtt. Látható, hogy nincs minden területen adat vagy utasítás, ezekkel a területekkel részben a programunk, részben az operációs rendszer gazdálkodik. Például dinamikus memóriafoglalás esetén az operációs rendszer ebből annyi bájtot ad, amennyit kérünk.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • ahhoz hogy teljesen megertsd a folyamatot assembly ismeretekkre lesz szukseged, plusz szamitogep es processzor hardver architektura ismeretre is
    Mutasd a teljes hozzászólást!
  • Sziasztok !

    A pointereket tanulom épp, és "gyakorlás" közben egy kérdés merült fel bennem, hogy amikor átadok egy pointernek a memória címét egy függvényben, akkor számomra furcsa dolgok történnek, nyilván nem tudok eleget a témával kapcsolatosan, és neten nem találtam ehhez hasonló olvasmányt, ami a választ adni erre a kérdésre.
    Remélem a program kommentekből kiderül minden, maga a kérdés is, és a gondolatmenetem hibája is.

    Intuitíven arra gondolok deklarálásnál, hogy ha én valahol a memóriában, egy bizonyos címet lefoglalok, ami (kis túlzással örökre) csak azt a fajta típust tudom benne tárolni, (int, char, vagy pl pointer típusnál, csak memória címet tárolhatok). Nyilván ez nem igaz legalábbis a programból számomra ez jön le. Hogy is van ez?

    Jó nyilván nem kell ilyet csinálni, hogy egy pointer típusnak a memória címét akarok átadni a függvénynek, ez csak puszta tanulás céljából tett kísérlet.


    Előre is köszönöm aki kicsit írna erről, hogy pontosan mi is játszódik itt le a háttérben. 

    Előre is köszönöm a válaszokat.

    #include <stdio.h> void cimatadas2(int *poC){ printf("poC memoria cime: %d poC amit tarol, amire mutat: %d poC és erre amire mutat, tartalma: %d \n",&poC,poC,*poC); poC[0] = 4; printf("atirtam a memoria cim tartalmat egy int szammal(ami a main-ben még pointer típus volt): %d %d %d %d \n",&poC[0],*poC,poC[0],poC[1]); } int main(){ int a = 42; int* poB = &a; printf("'a' memoria cime: %d \n 'a' erteke: %d ez is az erteke: %d \n poB memoria cime: %d poB amit tarol, amire mutat: %d \n",&a,a,*poB,&poB,poB); cimatadas2(&poB); printf("Visszaterunk, es 'a' memoria cime: %d \n 'a' erteke: %d ez is az erteke: \n poB memoria cime: %d poB amit tarol, amire mutat: %d (itt egy memorai cimnek kene lennie elvileg) \n",&a,a,&poB,poB); printf(" ha berinam ide %%d hez hogy poB* akkor ki is kifagyna"); }
    Mutasd a teljes hozzászólást!
abcd