C memóriakezelés. Mutató típusú változót egy típus és a változó neve elé írt csillag karakterrel hozhatjuk létre.

Hasonló dokumentumok
8. gyakorlat Pointerek, dinamikus memóriakezelés

Programozás I gyakorlat. 10. Stringek, mutatók

C programozási nyelv Pointerek, tömbök, pointer aritmetika

10. gyakorlat. Pointerek Tárolási osztályok

Mutatók és mutató-aritmetika C-ben március 19.

A C programozási nyelv V. Struktúra Dinamikus memóriakezelés

Struktúrák (struct) A struktúra szerkezetét meghatározó deklaráció általános formája:

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós április 4. Széchenyi István Egyetem, Gy r

Programozás alapjai. 10. előadás

Programozas 1. Strukturak, mutatok

5. Gyakorlat. struct diak {

Alkalmazott modul: Programozás 8. előadás. Strukturált programozás: dinamikus memóriakezelés. Dinamikus memóriakezelés. Dinamikus memóriakezelés

Járműfedélzeti rendszerek II. 3. előadás Dr. Bécsi Tamás

Alkalmazott modul: Programozás 10. fejezet. Strukturált programozás: dinamikus memóriakezelés. Giachetta Roberto

OOP #14 (referencia-elv)

1. Alapok. Programozás II

1.1. A forrásprogramok felépítése Nevek és kulcsszavak Alapvető típusok. C programozás 3

Programozás I gyakorlat

Miről lesz ma szó? A PROGAMOZÁS ALAPJAI 1. Dinamikus változók. Dinamikus változók. Dinamikus változók. Dinamikus változók. 7.

Bevezetés a programozásba I.

Programozás C nyelven (9. ELŐADÁS) Sapientia EMTE

Bevezetés a programozásba I 10. gyakorlat. C++: alprogramok deklarációja és paraméterátadása

Programozási nyelvek a közoktatásban alapfogalmak II. előadás

10. gyakorlat Struktúrák, uniók, típusdefiníciók

C++ referencia. Izsó Tamás február 17. A C++ nyelvben nagyon sok félreértés van a referenciával kapcsolatban. A Legyakoribb hibák:

Programozási Nyelvek: C++

3. Osztályok II. Programozás II

Programozás II. 4. Dr. Iványi Péter

A verem (stack) A verem egy olyan struktúra, aminek a tetejéről kivehetünk egy (vagy sorban több) elemet. A verem felhasználása

1. Template (sablon) 1.1. Függvénysablon Függvénysablon példányosítás Osztálysablon

5. gyakorlat. Konstansok Tömbök Stringek

Programozás 5. Dr. Iványi Péter

Függvény pointer. Feladat: Egy tömbben soroljunk fel függvényeket, és hívjuk meg valahányszor.

Programozás alapjai gyakorlat. 4. gyakorlat Konstansok, tömbök, stringek

C string műveletek (string.h alkalmazása)

Programozás II gyakorlat. 6. Polimorfizmus

Programozási nyelvek Java

Maximum kiválasztás tömbben

Programozás alapjai. (GKxB_INTM023) Dr. Hatwágner F. Miklós augusztus 29. Széchenyi István Egyetem, Gy r

Adatszerkezetek I. 1. előadás

Programozás I gyakorlat

tétel: különböző típusú adatokat csoportosít, ezeket egyetlen adatként kezeli, de hozzáférhetünk az elemeihez is

C programozás. 6 óra Függvények, függvényszerű makrók, globális és

Programozás alapjai C nyelv 8. gyakorlat. Mutatók és címek (ism.) Indirekció (ism)

Mutatók és címek (ism.) Programozás alapjai C nyelv 8. gyakorlat. Indirekció (ism) Néhány dolog érthetőbb (ism.) Változók a memóriában

7. fejezet: Mutatók és tömbök

Hatékony memóriakezelési technikák. Smidla József Operációkutatási Laboratórium január 16.

Programozás alapjai gyakorlat. 2. gyakorlat C alapok

Szövegek C++ -ban, a string osztály

3 A C programozási nyelv szintaktikai egységei

Programozás C++ -ban

Bevezetés a C++ programozási nyelvbe

C++ programozási nyelv Konstruktorok Gyakorlat

A C programozási nyelv III. Pointerek és tömbök.

Programozás II. 2. Dr. Iványi Péter

Programozás 6. Dr. Iványi Péter

Pénzügyi algoritmusok

A C programozási nyelv III. Pointerek és tömbök.

Dinamikus mátrixok. Dinamikus többdimenziós tömbök

Programozási nyelvek Java

Programozás II. segédlet

6. gyakorlat Egydimenziós numerikus tömbök kezelése, tömbi algoritmusok

Programozás alapjai C nyelv 5. gyakorlat. Írjunk ki fordítva! Írjunk ki fordítva! (3)

Programozás I gyakorlat

Készítette: Nagy Tibor István

Memóriakezelés, dinamikus memóriakezelés

Programozás alapjai 9.Gy: Struktúra 2.

Programozás I gyakorlat

Programozási segédlet

Függvények. Programozás alapjai C nyelv 7. gyakorlat. LNKO függvény. Függvények(2) LNKO függvény (2) LNKO függvény (3)

Programozás alapjai C nyelv 7. gyakorlat. Függvények. Függvények(2)

Programozás alapjai 2.Gy: A C nyelv alapjai P R O

Programozás alapjai. 7. előadás

Felvételi tematika INFORMATIKA

STL gyakorlat C++ Izsó Tamás május 9. Izsó Tamás STL gyakorlat/ 1

C++ programozási nyelv Konstruktorok-destruktorok

Bevezetés a programozásba. 8. Előadás: Függvények 2.

HORVÁTH ZSÓFIA 1. Beadandó feladat (HOZSAAI.ELTE) ápr 7. 8-as csoport

1. Jelölje meg az összes igaz állítást a következők közül!

Tömbök kezelése. Példa: Vonalkód ellenőrzőjegyének kiszámítása

Stack Vezérlés szerkezet Adat 2.

Bevezetés a programozásba II. 5. Előadás: Másoló konstruktor, túlterhelés, operátorok

Bevezetés a Programozásba II 10. előadás. Dinamikus memóriakezelés

Bánsághi Anna 2014 Bánsághi Anna 1 of 33

A memóriák típusairól és a memóriakezelésről

Programozás I. gyakorlat

1. Egyszerű (primitív) típusok. 2. Referencia típusok

Mintavételes szabályozás mikrovezérlő segítségével

Mérnöki programozás 7. Szerkesztette: dr. Vass Péter Tamás

500. AA Megoldó Alfréd AA 500.

Pénzügyi algoritmusok

Feladatgyűjtemény a C programozási nyelvhez

Java II. I A Java programozási nyelv alapelemei

1. Feladat: beolvas két számot úgy, hogy a-ba kerüljön a nagyobb

/* Az iter függvény meghívása és a visszatérő érték átadása a gyok változóba */ gyok = iter( n, a, e ) ;

Járműfedélzeti rendszerek II. 1. előadás Dr. Bécsi Tamás

Függvények. Programozás I. Hatwágner F. Miklós november 16. Széchenyi István Egyetem, Gy r

Programozás alapjai II. (7. ea) C++ Speciális adatszerkezetek. Tömbök. Kiegészítő anyag: speciális adatszerkezetek

Speciális adatszerkezetek. Programozás alapjai II. (8. ea) C++ Tömbök. Tömbök/2. N dimenziós tömb. Nagyméretű ritka tömbök

- 1 - Konstansok használata. Döntsük el, van-e fordítási idejű hiba az alábbi programrészletekben! a) const char * str="zh"; str[0]++;

Átírás:

C memóriakezelés Ez a kis segédanyag az adatszerkezetek órán használt eszközök megértését hivatott elősegíteni. A teljesség igénye nélkül kerül bemutatásra a mutató típus és a dinamikus memóriakezelés. A mutató típusú változó A változóknak van név, érték, attribútum (pl: típus, const, ) és cím komponensük. A mutató típusú változók memóriacímek tárolására szolgálnak. Speciális elem a NULL, mely azt jelzi, hogy a mutató nem tartalmaz érvényes címet, nem mutat semmire. Mutató típusú változót egy típus és a változó neve elé írt csillag karakterrel hozhatjuk létre. <típus> *<név> [=kezdőérték] [,*<név> [=kezdőérték]] ; A mutató típusú változóban tárolt címet a megadott típusnak megfelelően fogja felhasználni a rendszer. Ez dönt például arról, hogy hány bájtról olvassunk ki/vagy hány bájtra írjunk adatot, a címet felhasználva és persze arról is, hogy az ott talált bitsorozatot hogyan értelmezzük. Nézzünk pár példát, hogy könnyebben megérthessük, hogyan kell a fentieket érteni: 1. int x = 300; //reprezentációja: 00000000 00000000 00000001 00101100 2. int *p = &x; //A * a típusmegadás része -> p egy mutató 3. char *p2 = &x; //A * a típusmegadás része -> p2 egy mutató 4. 5. printf("%d ", x); // kiírja a 300-as értéket 6. printf("%p ", &x); // kiírja x címét 7. 8. printf("%d ", *p); // kiírja a 300-as értéket (p címen lévő értéket) 9. printf("%p ", p); //kiírja p értékét, vagyis x címét 10. 11. printf("%d ", *p2); //kiírja 44-es értéket 12. printf("%p ", p2); //kiírja x címét Az x egy egész típusú 300-as kezdőértékkel rendelkező változó, p egy egész típusú változóra mutató, mutató típusú változó (röviden int típusú mutató). Kezdőértéket is adtunk neki a & (címe operátor, prefix) segítségével, mely egy változó neve elé írva annak címét adja vissza. Az prefix * jel az & inverz operátora, úgynevezett indirekciós operátor. Ez egy mutató elé írva, visszaadja, a mutató által hivatkozott címen lévő értéket. (A változó létrehozásakor csak a mutató típus jelzésére szolgál a csillag.) A p címen lévő érték feldolgozásakor a p címtől kezdődő 4 bájton (egészen pontosan sizeof(int) bájton) lévő bitsorozatot előjeles egészként fogjuk értelmezni. A p2 viszont karakter típusú mutató, ezért hiába adtuk meg egész típusú változó címét, p2-n keresztül feldolgozva a címen lévő bitsorozat 1 bájtos előjeles egészként lesz értelmezve. Ezért van az, hogy a 11. sor 44-es értéket ír ki a 300-as helyett, hiszen az elért 1 bájt tartalma a 00101100, ami egészként értelmezve pont 44.

Megj.: Ha a mutatóra hivatkozunk, annak akarunk értéket adni, akkor * nélkül hivatkozunk rá. A deklarációban a típusmegadás miatt kell csak a *. int x, *p; p = &x; //p innentől x-re mutat. (x címét p-be másoltuk) Mégis mire jó ez? A változók fizikai tárolása A tárolás szempontjából a programunk által használt memóriát több részre fogjuk osztani. Az egyik rész, a statikus memóriaterület. Erre a részre kerülnek a konstansok, melyek értéke az egész program futása során állandó. Ezen kívül van egy dinamikus memóriaterület. Ezen a részen foglalhatunk le területet a változók számára. Ami most még érdekes számunkra, a hívási láncot tartalmazó verem. Ez azért fontos, mert minden meghívott függvénynél (a főprogram az első meghívott) a verembe kerül egy elem, mely az adott függvény futtatásához szükséges információkat tartalmazza. Ebbe a verembe kerülnek tárolásra a függvények lokális változói is. Ha a függvény lefutott, akkor a verem legfelső eleme törlődik, vagyis megszűnnek a lokális változók. Feladat 1.: Cseréljünk fel két változó értékét egy függvény segítségével! Először lássuk azt a kódot, ami nem oldja meg a feladatot: void csereldfel(int a, int b){ int tmp = a; a = b; b = tmp; int x = 2, y = 4; printf( eredeti: %d %d\n, x, y); /*2 4 jelenik meg*/ csereldfel( x, y ); printf( felcserelt: %d %d\n, x, y); /*2 4 jelenik meg */ A C-ben kizárólag érték szerinti paraméterátadás van, tehát az x és y változók értéke kerül át a a csereldfel függvény a és b paraméterébe, és annak változtatása az eredeti példányokra nincs hatással. A csereldfel függvényt ebben a formájában akár két konstanssal is meghívhatnánk, hiszen úgyse azok értékét próbálná felcserélni. Ahhoz, hogy elérjük célunkat, meg kell oldani, hogy a csereldfel függvény ismerje az x és y változóink címét. A címek ismeretében, már tudná módosítani a változók értékét. Címszerinti paraméterátadás hiányában ezt úgy tudjuk megoldani, hogy x és y címét, mint értékeket adjuk át. Ehhez alakítsuk át úgy a csereldfel függvényt, hogy cím típusú értékeket tudjon fogadni, és a híváskor x és y értéke helyett a cím operátor segítségével azok címeit adjuk át. Ennyivel sajnos nem ússzuk meg, hiszen a csereldfel függvény belső részében is gondoskodnunk kell

arról, hogy ne az a és b értéke (az x és y változók címei) legyenek felcserélve a függvényen belül, hanem az a és b címen lévő értékek (vagyis x és y változó tartalma). Ehhez a függvényen belül az indirekciós operátort kell használnunk az a és b paraméterek előfordulásainál. void csereldfel(int *a, int *b){ /*memóriacím fogadására felkészítve*/ int tmp = *a; /* az a címen lévő érték kerül tmp-be*/ *a = *b; /*a b címen lévő érték kerül az a-ban lévő címre*/ *b = tmp; /*a b-ben lévő címre kerül a tmp-ben lévő érték*/ int x = 2, y = 4; printf( eredeti: %d %d\n, x, y); /*2 4 jelenik meg*/ csereldfel( &x, &y ); /*x és y címét adjuk át, mint értékeket*/ printf( felcserelt: %d %d\n, x, y); /*2 4 jelenik meg */ Feladat 2.: Készítsünk függvényt, mely létrehoz és visszaad egy 10 elemű egész típusú tömböt és feltölti 1 és 10 között lévő számokkal. Lássuk az alábbi kódot, mely nem oldja meg a feladatot! int[] ujtomb(){ int tomb[10], i; for(i = 0; i<10; ++i) tomb[i] = i; return tomb; /*ajjaj, mi lesz itt?*/ int[] t = ujtomb(); printf( %d, t[3]); Eddig a változók memóriabeli tárolásával nem kellett foglalkoznunk. A változók definiálásánál megadott típus szerint automatikusan lefoglalódott a memóriában a hely a változó számára, ahol a változó értéke tárolásra került. Nos, most éppen ez az eddig hasznos segítség okozza számunkra a problémát, hiszen a tomb az ujtomb függvény lokális változója, ezért a rendszer nem csak lefoglalja számára a helyet de a függvény befejeztével gondosan fel is szabadítja azt, így hiába kapjuk meg a tömb címét, a mainben már nem sok mindent tudunk kezdeni vele. A dinamikus memóriakezelés használatával orvosolhatjuk a problémát. Ismerkedjünk meg néhány függvénnyel: void *malloc(int size); A malloc függvény a paraméterben megadott bájtnyi memóriablokkot foglal le. Egy void* típusú mutatót ad vissza, mely a lefoglalt terület elejére mutat. Sikertelen memóriafoglalás esetén NULL értéket ad vissza.

void *calloc(int, int); A calloc függvény első paramétere egy elemszám, a második paramétere egy elem mérete. Az elemszámnak és típusnak megfelelő memóriablokkot foglal le és egy void* típusú mutatót ad vissza, mely a lefoglalt terület elejére mutat. Sikertelen memóriafoglalás esetén NULL értéket ad vissza. void free(void *ptr); A dinamikusan lefoglalt terület felszabadítására szolgál. Egy mutatót vár, ami a felszabadítandó memóriablokk elejére mutat. (NULL érték átadása nem okoz hibát.) Példa: //10 int típusú elemnek megfelelő hely int *t = (int*) malloc(10*sizeof(int)); //12 bájtnyi terület lefoglalása és int típusra konvertálása int *t2 = (int *) malloc(12); //5 karakternek megfelelő hely (5 bájt lefoglalása) char *s = (char *) malloc(5*sizeof(char)); //10 valós típusú elem számára szükséges hely lefoglalása, kinullázása double *t3 = (double*)calloc(10, sizeof(double)); //a 10 int típusú elem számára foglalt hely felszabadítása free(t); Láthatjuk, hogy a malloc és calloc függvény is void* típussal tér vissza, melyet konvertáltunk, amit a számunkra megfelelő típusra konvertálhatunk. A tanultak ismeretében alakítsuk át a fenti újelem függvényt, hogy megfelelően működjön! int* ujtomb(){ int i, *tomb = (int *)malloc(10*sizeof(int)); for(i = 0; i<10; ++i) tomb[i] = i; //amint látjuk a mutatóknál is használható az index return tomb; int* t = ujtomb(); printf( %d, t[3]); free(t); //ha már nincs szükség a tömbre, a helyet felszabadítjuk

Mutató aritmetika A mutatók növelése, csökkentése mindig függ a mutató típusától. Ha egy mutatót léptetünk, automatikusan annyival nő vagy csökken az értéke (annyi bájttal arrébb lévő címre mutat), ahány bájt kell a típus reprezentálására. Pl.: Legyen char *p1, és egy int * p2 mutatónk, akkor ++p1 hatására p1 eggyel nő (egy bájttal arrébb lévő címre mutat), a ++p2 hatására a p2 néggyel (egészen pontosan sizeof(int)- tel) nő (ennyi bájttal odébb mutat). int *p, *q; int t[10]; p = t; //A tömb neve a tömb címét adja meg, ezért nem kell & Mutatókhoz hozzáadhatunk konstansokat, kivonhatunk belőlük konstansokat. Futtassuk képzeletben a következő kódot! *(p+1); p[1]; p[-3]; ++p; *p; *p-1; *(p-1); *p[-1]; //a p+1 címen lévő érték, ami t[1] //a p+1 címen lévő érték, ami szintén t[1] //hibás, mivel t tömb negatív indexű elemére hivatkozik //p egy elemmel arrébb lép! //t[1] elem (az előző sor miatt) //t[1]-1 //t[0] //t[0] Azonos tömbre mutató mutatókat kivonhatunk egymásból. Ez egy egész számot fog adni eredményül! Lássunk egy példát a használatára! char s[] = Gyűlölöm a mutatókat! ; char *p; int index = -1; // ha nincs a betű, akkor -1 lesz az index //keressük meg az első a betű helyét! for(p = t; *p; ++p) if(*p == a ) break; if(*p){ //A stringnél a \0 az tényleges nulla index = p-s; //Ahol megtaláltuk az a -t mínusz a tömb kezdőcíme. (Egyéb műveletek is végezhetők, de nem mindennek van értelme.) Feladatok: Hozzunk létre egy x valós változót, és egy mutatót, mely a deklarációtól kezdve rá mutat!

Hozzunk létre egy x valós változót, és egy mutatót, mely a deklarációt követő sor után fog rá mutatni! Hozzunk létre két olyan mutatót, mely ugyan arra a memóriacímre hivatkozik! Foglaljunk le helyet 5 elemű karakterekből álló tömb számára! Foglaljunk le helyet 15 hosszúságú szöveg tárolására! Foglaljunk le helyet 10 elemű egészek számára, úgy, hogy az elemeknek nulla legyen a kezdőértéke! Foglaljunk le helyet 15 hosszúságú szöveg tárolására! Számoljuk össze kétféle módon, hogy hány b betű áll a tömbben! (Indexel, és mutató léptetéssel!) A program végén szabadítsuk fel a lefoglalt memóriát! Írjunk függvényt, mely paraméterként átadott n darab int típusú elem számára foglal helyet, és visszatér a tömb kezdőcímével! Írjunk függvényt, mely paraméterként átadott n darab, szintén paraméterként adott m méretű elem számára foglal helyet, és visszatér a tömb kezdőcímével! Hozzunk létre olyan 5 elemű tömböt, mely int típusú mutatókat tartalmaz! Hozzunk létre dinamikusan olyan 5 elemű tömböt, mely int típusú mutatókat tartalmaz! Hozzunk létre dinamikusan egy NxM es mátrixot! Töltsük fel az előbbi mátrixot, majd összegezzük a főátlóban lévő elemeket! Számoljuk ki az előbbi mátrix oszlopösszegeinek átlagát! Hozzunk létre egy sztring típusú változót, és egy p mutatót. Index használata nélkül döntsük el, hogy az adott sztring tartalmaz-e két azonos karaktert egymás mellett!