6. gyakorlat
Téma: Memória és pointerek (part 1)
Memória
- Minden program a memóriában van futás közben
- Mindene: változók, függvények stb.
- A memóriának minden byte-ja rendelkezik címmel, azaz a memóriában elfoglalt hellyel
Mi az a pointer?
- Pointer (vagy pointerváltozó) = mutató (vagy mutatóváltozó)
- A memória közvetlen elérését teszi lehetővé
- C-ben és C++-ban eszköz a memória kezelésre
- Pointerváltozó: Egy memóriacímet jelentő változó
- Egy pointerváltozónak is van memóriacíme
Memóriakezelő operátorok
| Név | Operátor | Funkció |
|---|---|---|
| Címfeloldás | * |
A pointerváltozó által mutatott memória olvasható és írható közvetlenül. Azaz visszaadja a mutatott változó értékét |
| Cím lekérés | & |
Lekéri a memóriacímet |
Pointerhez általában használt % karakter: %lu
Példa
Kimenet pl:
Néhány futtatás után látható, hogy a változó mindig más memóriacímre kerül
Pointerváltozó deklarálása, definiálása és értékadás
- A pointer típusa meg kell, hogy egyezzen annak a változónak a típusával, amire mutat
- A deklarációban lévő
*NEM címfeloldó operátor! - A
sizeof()függvénnyel lekérhető a pointer mérete - Megjegyzés: Bármennyi white space lehet az utasítások között
- Ezért az alábbi példák megegyeznek
Általános szintax:
Példa
#include <stdio.h>
int main()
{
int a = 19;
printf("Memóriacím: %lu\n", &a);
// a 'p' egy pointerváltozó, amely az 'a' változó memóriacímét tárolja
int *p = &a;
printf("Memóriacím: %lu\n", p);
// címfeloldás
printf("Címfeloldás: %d\n", *p);
// pointerváltozó mérete
printf("Pointerváltozó mérete: %ld\n", sizeof(p));
return 0;
}
Kimenet:
Pointer default értéke
- Pointernek mindig adjunk értéket!
- Ha nincs inicializálva vagy az értéke 0, akkor feloldásnál instant segfaultot kapunk
- Ilyenkor nem létező memóriacímen vagy memóriaszeméttel dolgoznánk
Pointer pointere
- A pointerváltozó is el van tárolva a memóriában => lekérhető a memóriacíme
- Egy pointer címét is el tudjuk tárolni egy pointerben => pointerre mutató pointer
- Lehetséges a végtelenségig, de már a 3-szoros pointernek is kevés gyakorlati gyakorlati van
- A típusnak itt is meg kell egyeznie a mutatott változó típusával
Deklaráció, definíció, értékadás általános szintaxa:
Címlekérés példa
#include <stdio.h>
int main()
{
int a = 19;
printf("'a' memóriacíme: %lu\n", &a);
int *p = &a;
printf("'p' értéke azaz 'a' memóriacíme: %lu\n", p);
int **p2 = &p;
printf("'p' memóriacíme: %lu\n", &p);
printf("Azaz 'p2' értéke: %lu\n", p2);
return 0;
}
Kimenet:
'a' memóriacímw: 140722784218724
'p' értéke azaz 'a' memóriacím: 140722784218724
'p' memóriacíme: 140722784218728
Azaz 'p2' értéke: 140722784218728
Címfeloldás példa
(Visszajutunk vele az 'a' értékéhez)
#include <stdio.h>
int main()
{
int a = 19;
printf("a = %d\n", a);
int *p = &a;
printf("*p = %d\n", *p);
int **p2 = &p;
printf("**p2 = %d\n", **p2);
return 0;
}
Kimenet:
Műveletek pointerekkel
- A pointerek unsigned long objektumok
- Korlátozott műveleteket végezhetünk velük
Aritmetikai műveletek
- Hozzádni nem negatív számot
- Kivonni nem negatív számot
- Inkrementálni
- Dekrementálni
Nem biztos, hogy ki tudjuk írni a 'b' változót, mert nem garantált, hogy a két változó egymás mellé kerül a memóriában
Példa:
#include <stdio.h>
int main()
{
int a = 42;
int b = 137;
int *p = &a;
printf("'a' memóriacíme: %lu\n", p);
printf("a = %d\n", *p);
++p;
printf("Inkrementált p: %lu\n", p);
printf("Reméljük, hogy 'b' = %d\n", *p);
return 0;
}
Kimenet:
Logikai műveletek
- A memóriacímek értékeit össze tudjuk hasonlítani a logikai műveletekkel
- (Megjegyzés: majd fontos lesz a dinamikus memória kezelésnél)
Példa:
#include <stdio.h>
int main()
{
int a = 1;
int b = 2;
int *pa = &a;
int *pb = &b;
if(pb > pa)
{
printf("Az 'a' változó kisebb memóriacímre került\n");
}
else
{
printf("A 'b' változó kisebb memóriacímre került\n");
}
return 0;
}
Tömbök és pointerek
- Tömb: A memóriában folytonosan lefoglalt memóriablokkok
- Egy mutatóval végig lehet haladni ezen a memóriaterületen
- Biztos, hogy a tömbhöz tartozó memórián fogunk végighaladni
Tömb első elemére mutató pointer
#include <stdio.h>
int main()
{
char charTomb[5] = { 'a', 'b', 'c', 'd', 'e' };
char *p1 = charTomb;
printf("%c\n", *p1);
char *p2 = &charTomb[0];
printf("%c\n", *p2);
return 0;
}
Tömb harmadik elemére mutató pointer
#include <stdio.h>
int main()
{
char charTomb[5] = { 'a', 'b', 'c', 'd', 'e' };
char *p1 = &charTomb[3];
printf("%c\n", *p1);
char *p2 = charTomb + 3;
printf("%c\n", *p2);
return 0;
}
Egy tömb elemeinek kiíratása pointerekkel
#include <stdio.h>
int main()
{
char charTomb[5] = { 'a', 'b', 'c', 'd', 'e' };
// Módszer 1
for (int i = 0; i < 5; i++)
{
char *p1 = charTomb + i;
printf("%c\n", *p1);
}
// Módszer 2
for (int i = 0; i < 5; i++)
{
char *p2 = &charTomb[i];
printf("%c\n", *p2);
}
return 0;
}
Teljes char tömb kiíratása
- Itt gyakorlatilag egy a tömb 0. elemére mutató fel nem oldott pointert adunk át
- Ilyenkor addig megy, amíg meg nem találja a
\0-t => azaz kiírja a teljes tömböt