null pointer (tsz. null pointers)
A pointer egy olyan változó, amely egy másik változó memóriacímét tárolja. Ha például van egy int a = 5;
, és egy int* ptr = &a;
, akkor a ptr
változó a a
címét tárolja.
int a = 5;
int* ptr = &a;
Ebben a példában a ptr
mutatóként funkcionál. A *ptr
dereferálással elérhetjük azt az értéket, amelyre mutat (azaz 5
-öt).
A null pointer egy speciális pointer, amely nem mutat semmilyen érvényes memóriacímre. Általában azt jelenti: „ez a pointer jelenleg nincs beállítva egyetlen objektumra sem”.
int* ptr = nullptr;
A nullptr
C++11 óta használható kulcsszó, amelyet azelőtt a NULL
vagy a 0
érték helyettesített:
int* ptr = NULL; // régi stílus (C és C++98)
int* ptr = 0; // szintén használható, de nem ajánlott
A null pointer célja az, hogy egyértelműen jelezze: a mutató jelenleg nem mutat semmire. Ez segíti a hibakeresést és a feltételes logikát:
if (ptr == nullptr) {
std::cout << "A pointer nincs inicializálva.\n";
}
Ez különösen fontos dinamikusan lefoglalt memória kezelésekor, például:
int* arr = new int;
// használat
delete arr;
arr = nullptr; // fontos: így tudjuk jelezni, hogy a memória már felszabadult
Végzetes hiba: ha egy null pointert dereferálunk (*ptr
), akkor a program összeomlik — undefined behavior, ami legtöbbször segmentation fault
-hoz vezet.
int* ptr = nullptr;
std::cout << *ptr; // ⚠️ HIBA! Null pointer dereferálása
Ezért mindig ellenőrizni kell, hogy a pointer nem nullptr
, mielőtt használjuk.
Inicializáláskor:
int* p = nullptr;
Memória felszabadítás után:
delete p;
p = nullptr;
Hibás függvényhívás eredményeként:
int* keres(int arr, int size, int keresett) {
for (int i = 0; i < size; ++i)
if (arr == keresett) return &arr;
return nullptr; // ha nem található
}
nullptr
vs NULL
vs 0
nullptr
(C++11): típusos null pointer literál (std::nullptr_t
)NULL
: makró, tipikusan #define NULL 0
, nem típusos0
: numerikus érték, amely szintaktikusan elfogadott pointerként, de nem kifejezőPéldául az alábbi túlterhelt függvény esetén nullptr
nélkül nem tudnánk eldönteni, melyik hívódjon meg:
void f(int);
void f(int*);
f(0); // az int verzió hívódik meg
f(nullptr); // az int* verzió hívódik meg (típus alapján)
Sok függvény visszatérési értéke lehet null pointer, ha valamilyen hibát vagy hiányt jelez:
char* strchr(const char* str, int ch);
// ha a karakter nem található meg, visszatér nullptr-rel
class Node {
public:
int data;
Node* next;
Node(int d) : data(d), next(nullptr) {}
};
C++-ban nincs beépített kivételmechanizmus a legtöbb nyelvi elemhez, így gyakori minta, hogy egy hiba esetén nullptr
-t ad vissza a függvény:
User* findUserById(int id) {
if (adatbazisban_van(id))
return new User(id);
return nullptr;
}
És ezt így ellenőrizzük:
User* u = findUserById(42);
if (u == nullptr) {
std::cerr << "Nincs ilyen felhasználó!";
}
A modern C++ programozásban inkább okos pointereket használunk (std::unique_ptr
, std::shared_ptr
). Ezek is támogathatják a null értéket:
std::unique_ptr<int> ptr;
if (!ptr) {
std::cout << "Üres unique_ptr\n";
}
int* arr = nullptr;
if (arr) {
for (int i = 0; i < 10; ++i)
std::cout << arr; // biztonságos, mert csak ha nem nullptr
}
Dupla delete:
delete ptr;
delete ptr; // ha nem nullptr-re állítod be előtte, ez undefined behavior
→ Megoldás:
delete ptr;
ptr = nullptr;
Elfelejtett inicializálás:
int* p; // nem inicializált, lehet szemét érték!
→ Megoldás:
int* p = nullptr;
std::nullptr_t
típusstd::nullptr_t x = nullptr;
Ez akkor hasznos, ha sablonokkal, típusspecifikus függvényekkel dolgozunk, ahol konkrétan null pointer típusra akarunk túlterhelni.
Fogalom | Jelentés |
---|---|
nullptr
|
Típusos null pointer literál (C++11-től) |
NULL
|
Hagyományos, típus nélküli null pointer (ne használd modern C++-ban) |
0
|
Numerikus érték, amit a fordító pointerként is értelmez |
Null pointer dereferálása | Súlyos hiba, vezethet crash-hez |
Védekezés | Mindig ellenőrizd, hogy pointer nem nullptr , mielőtt dereferálnád
|
Modern alternatíva | Használj std::unique_ptr , std::shared_ptr , és sose kell delete-tel bajlódni
|