Najczęściej popełnione błędy
twonek
Baśń o wskaźniku
Wyobraź sobie, że Twój komputer ma tylko 4 komórki pamięci, każda zdolna pomieścić jeden int.
Komórki mają adresy 1
, 2
, 3
, 4
.
[ ? ] [ ? ] [ ? ] [ ? ]
Teraz jeśli masz:
int foo;
Zmienna foo zostaje utworzona w którejś komórce pamięci (decyzja należy do systemu operacyjnego), powiedzmy w komórce 3.
Wartość foo nie została inicjalizowana, więc jest nieznana i nie wolno do niej się odwołać. Czyli: foo ma adres 3 i niezainicjalizowaną wartość.
[ ? ] [ ? ] [foo = ?] [ ? ]
foo = -14545;
Teraz foo ma wartość -14545, inaczej mówiąc w komórce 3 jest teraz liczba -14545.
[ ? ] [ ? ] [foo = -14545] [ ? ]
int* ptr;
Zmienna ptr (wskaźnik to też tylko zmienna jak każda inna) zostaje utworzona powiedzmy w komórce 1. Ma niezainicjalizowaną wartość, czyli na nic nie wskazuje. W C++ przyjmuje się również, że jeśli wskaźnik ma wartość 0 (albo jako makro NULL) to oznacza że też na nic nie wskazuje, bo żadna zmienna nie ma takiego adresu.
[ptr = ?] [ ? ] [foo = -14545] [ ? ]
ptr = &foo;
ptr ma teraz wartość 3, czyli wskazuje na komórkę, w której jest zmienna foo (albo w skrócie wskazuje na foo). Czyli zmienna ptr ma adres 1 i wartość 3.
[ptr = 3] [ ? ] [foo = -14545] [ ? ]
koniec baśni
Wskaźnik to zmienna. Wszystkie podstawowe operacje typu odczyt, przypisanie zachowują się tak samo jak w przypadku zmiennych niewskaźnikowych.
int zmienna;
zmienna = <wartosc_typu_int>;
funkcja_oczekujaca_int(zmienna);
int* wskaznik;
wskaznik = <wartosc_typu_wskaznik_do_int>;
funkcja_oczekujaca_wskaznika_int(wskaznik);
Wskaźnik **nie** alokuje pamięci dla obiektu, na który ma wskazywać. ```cpp int* wskaznik; *wskaznik = 5; // hola hola, a skąd masz pamięć na przechowywanie liczby 5? ``` Pomijamy tutaj inny błąd związany z odczytem niezainicjalizowanej zmiennej.
Od alokacji pamięci jest `new`, którego używania należy unikać (korzystając zamiast tego ze zmiennych na stosie, inteligentnych wskaźników itd.)
int* wskaznik = new int;
*wskaznik = 5; // był new, więc pamięć jest
delete wskaznik; // zawsze pamiętaj o delete jeśli używasz new
Analogicznie w przypadku używania wskaźnika jako "tablicy"
int* tab;
tab[1] = 5; // no halo, a pamięć to gdzie została zaalokowana?
int* tab = new int[50];
tab[1] = 5; // alokowano pamięć, wszystko ok
delete[] tab;
[Ciągle w rozbudowie]