9. gyakorlat
(A hosszú hétvége miatt számozásban kimarad a 8-as.)
Téma: Erőforrások kezelése (part 1)
- Az erőforrásokról
- Dinamikus memóriakezelés
Erőforrások
Minden erőforrást hasonlóan kell kezelni
Általános szabályok:
- Hozzáférést kérni az erőforráshoz
- Ellenőrizni, hogy megkaptuk-e a hozzáférést
- Ha sikertelen, akkor jogosulatlan erőforrást használnánk
- Felszabadítani az erőforrást
- Ha elmarad, akkor feleslegesen foglaljuk az erőforrást
Dinamikus memóriakezelés
Szükséges: standard library
- Az így foglalt terület bármeddig (amíg fel nem szabadítjuk) a rendelkezésünkre áll
- Az ilyen memória több függvényen keresztül is használható
- Általános típusú adat nincs => konvertálni kell a megfelelő típusra
I.) Hozzáférés kérése
malloc() allokáló függvény
malloc= memory allocation- Megadott byte-nyi méretű memóriát próbál lefoglalni
- size_t: valamilyen unsigned egész (architektúra szerint)
- Ha sikeres a foglalás: Visszatér egy a memória első címére mutató általános void pointerrel
- Ha sikertelen: null pointer
Általános szintax:
calloc() allokáló függvény
- Ritkábban használt
- Num darab size méretű objektumok foglalására
- (Nem eltétlenül a két szám szorzata)
- Ha sikeres a foglalás:
- Visszatér egy a memória első címére mutató általános void pointerrel
- Minden lefoglalt byte-ot 0-ra inicializál
- Ha sikertelen: null pointer
Általános szintax:
realloc() allokáló függvény
- (Ezzel tudunk gyakorlatilag további területet foglalni egy korábban foglalt területhez)
- A pointer által hivatkozott, már lefoglalt és fel nem szabadított memóriaterületet allokálja át egy másik memóriaterületre a megadott mérettel
- Sikertelen foglalás esetén:
- Null pointerrel tér vissza
- A régi memóriaterület megmarad
- Sikeres foglalás esetén:
- Visszatér egy a memória első címére mutató általános void mutatóval
- A régi memóriaterület felszabadul
- A régi memóriaterületen lévő adat átmásolódik az új területre
- Ha megadott méret nagyobb, mint az eredeti:
- Az eredeti méret feletti memóriában memóriaszemét lesz (nincs inicializálva)
- Ha a megadott méret kisebb, mint az eredeti:
- Csak az ekkora méretnek megfelelő adat másolódik át
- A többi elveszik
Általános szintax:
II.) Ellenőrzés
- Sikertelen memória foglalás esetén null pointert (0-t) kapunk vissza => ezt használjuk fel az ellenőrzésre
- Mit csinálhatunk? pl.:
- Hibaüzenetet írunk ki és termináljuk a programot
- Megpróbálunk újra foglalni
Példa:
if(p == 0)
{
printf("Sikertelen foglalás\n");
}
// vagy
if(!p)
{
printf("Sikertelen foglalás\n");
}
// vagy
if(p == NULL)
{
printf("Sikertelen foglalás\n");
}
III.) Felszabadítás
free()
- A memória felszabadítása a programozó dolga
- Paraméter: a felszabadítandó területre mutató pointer
- A felszabadítás mindig sikeres
- A felszabadított memóriát már nem tudjuk használni <= segfault-ot kapnánk
- Tipp: A felszabadítás után állítsuk 0-ra a pointert
Általános szintax:
Lehetséges hibák és okaik
- Memory leak (memóriaszivárgás):
- Kimarad a free() utasítás
- A memóriára mutató pointert másik memóriacímre iránytjuk át
- Double free
- Futási hibát kapunk, ha egynél többször próbáljuk felszabadítani a foglal memóriát
Példák
#include <stdio.h>
#include <stdlib.h>
int main()
{
// malloc
// 4 db int-nek foglalunk memóriát
// (int*) kasztolás a típusra
int n = 4;
int *p = (int*) malloc(n * sizeof(int));
// ellenőrzés
if (p == 0)
{
// hibaüzenet és a program terminálása
printf("Sikertelen foglalás\n");
return 0;
}
// kiíratás
printf("A lefoglalt memóriacímek:\n");
for (int i = 0; i < n; i++)
{
printf("%p\n", &p[i]);
}
// realloc
n = 6;
p = realloc(p, n * sizeof(int));
// ellenőrzés
if (p == 0)
{
// hibaüzenet és a program terminálása
printf("Sikertelen foglalás\n");
return 0;
}
// kiíratás
printf("Az új memóriacímek:\n");
for (int i = 0; i < n; i++)
{
printf("%p\n", &p[i]);
}
//felszabadítás
free(fp);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
// malloc
// 4 db int-nek foglalunk memóriát
// (int*) kasztolás a típusra
int n = 4;
int *p = (int*) malloc(n * sizeof(int));
// ellenőrzés
if (p == 0)
{
// hibaüzenet és a program terminálása
printf("Sikertelen foglalás\n");
return 0;
}
// bekérés és kiíratás
printf("Kérem az adatokat:\n");
for (int i = 0; i < n; i++)
{
scanf("%d", p+i);
}
printf("Az adatok:\n");
for (int i = 0; i < n; i++)
{
printf("%d\n", *(p+i));
}
// realloc
n = 6;
p = realloc(p, n * sizeof(int));
// ellenőrzés
if (p == 0)
{
// hibaüzenet és a program terminálása
printf("Sikertelen foglalás\n");
return 0;
}
// kiíratás
printf("Kérem az új adatokat:\n");
for (int i = 0; i < 2; i++)
{
scanf("%d", p+4+i);
}
printf("Az adatok:\n");
for (int i = 0; i < n; i++)
{
printf("%d\n", *(p+i));
}
//felszabadítás
free(fp);
return 0;
}