7. gyakorlat
Memória és pointerek (part 2)
(Az előző gyakorlat folytatása)
Figyeljünk a zárójelekre
#include <stdio.h>
int main()
{
int szamok[] = {1, 2, 3, 4, 5};
int* p = szamok;
for (int i = 0; i < 5; i++)
{
// 1)
printf("%d\n", *p + i);
// 2)
printf("%d\n", *(p + i));
}
return 0;
}
Különbség:
Az 1. esetben előbb kiolvassuk a pointer értékét (vagyis a tömb 0. elemét) és utána hozzáadjuk a ciklusváltozó értékét
A 2. esetben előbb léptetjük a pointert és utána olvassuk ki az értéket (vagyis végighaladunk a tömbön)
Típuskonverzió pointerekre
Nem összekeverendő a kettő!
1) Pointerváltozó típusának konverziója
A csillagnak a zárójelen belül kell lennie!
2) A mutatott memóriaterület (az eredeti változó) típusának konverziója
Fel kell oldani hozzá a pointert => a csillag a zárójelen kívülre kerül
Felhasználói típusok és pointerek
- Felhasználói (user-defined) típusokra is lehet pointert állítani
- Használatuk ugyanaz
- A címfeloldás is hasonló, de van rá külön operátor is
- Nyíl (->) operátor: Adattag elérése egy pointeren keresztül
Általánosan:
struct T
{
típus adat;
};
struct T s = ...;
struct T* p = &s;
típus a = (*p).adat;
típus b = p->adat;
Példa:
#include <stdio.h>
struct Ido
{
int ora;
int perc;
};
int main()
{
struct Ido i = {2, 10};
struct Ido* p = &i;
// Ugyanazt csinálja mindkettő
int a = (*p).ora;
printf("a = %d\n", a);
int b = p->ora;
printf("b = %d\n", b);
return 0;
}
Értékadás pointeren keresztül példa:
#include <stdio.h>
struct T
{
int a;
};
int main()
{
struct T szamok[2];
struct T* p = szamok;
for (int i = 0; i < 2; i++)
{
p->a = i;
p++;
}
for (int i = 0; i < 2; i++)
{
printf("%d\n", szamok[i].a);
}
return 0;
}
Típusmódosító pointerek
A const a legfontosabb, így ez van részletezve
| Deklaráció | Mit jelent? |
|---|---|
const type* p vagy type const* p |
A hivatkozott adat a pointeren keresztül nem módosítható |
type* const p |
A pointer értéke nem módosítható |
const type* const p |
Sem a pointer értéke, sem a hivatkozott adat nem módosítható |
Pointer, mint függvényargumentum
- Egy függvénynek lehet (akár többszörös) pointer argumentuma
- Ha el akarjuk kerülni a változó megváltozását a függvényben, akkor érdemes használni a
constkulcsszót - Ha egy olyan adatot akarunk megváltoztatni egy függvényben, ami a hívó fél oldalán van (lokális), akkor a memóriacímét adjuk meg a hívott függvénynek (lásd. példa)
- A függvényekben az argumentumként kapott pointereket ugyanúgy kell kezelni, mint a lokális pointereket
- Általánosságban a beépített típusoknál nem éri meg pointereket használni, de a nagyobb felhasználói objektumok (struct, union, tömb) esetén igen
- Oka: A függvény argumentumok lemásolódnak a függvényen belül lokális változóként
- Nagyobb objektumok esetén a pointerek "költséghatékonyabbak". Pl. nem 100 bájt másolódik le, hanem csak 8 bájt
- Vigyázat: Függvényben lokálisan definiált változóra mutató pointer visszaadása segfaultot okozhat!
Példa:
#include <stdio.h>
void swap(int* pA, int* pB)
{
int h = *pA;
*pA = *pB;
*pB = h;
}
void swap2(int* pA, int* pB)
{
*pA = *pA + *pB;
*pB = *pA - *pB;
*pA = *pA - *pB;
}
int main()
{
int a = 5;
int b = 9;
printf("Original:\na = %d\nb = %d\n", a, b);
swap2(&a, &b);
printf("After swap:\na = %d\nb = %d\n", a, b);
return 0;
}
Önhivatkozó struktúrák
- Önhivatkozás: Az összetett típus (pl. struct) tartalmazza önmagának egy példányát, vagyis egy arra mutató változót
- Avagy: Olyan struktúra, amely tartalmaz 1 vagy több pointert, amely egy ugyanolyan típusú struktúrára mutat
- Unionnál is lehet ilyet, de nem sok haszna van
- Structoknál használatos pl.:
- bináris fa (left és right)
- láncolt lista (prev és next)
- Tetszőleges mennyiségű másik ugyanolyan típusú struktúrára mutató adattagot tartalmazhat (általában 1-2 szokott lenni)
Áltlánosan:
Példa:
Az általános mutató
- Általános pointer:
void* - Akkor használjuk, amikor a hitkozott adat típusa érdektelen
- Pl.: Memória bitenkénti másolása
Mutatótömbök
Egy tömb lehet pointer típusú is
Általánosan:
Példa feladat pointer tömbbel:
#include <stdio.h>
void printToConsole(int** p)
{
for (int i = 0; i < 3; i++)
{
printf("%d\n", **(p + i));
}
}
void modify(int** p)
{
for (int i = 0; i < 3; i++)
{
printf("Új érték: ");
scanf("%d", *(p + i));
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int* szamok[] = {&a, &b, &c};
printToConsole(szamok);
modify(szamok);
printToConsole(szamok);
return 0;
}