Wskaźniki, referencje, typy proste. Porównanie typu wskaźnikowego i referencyjnego.

Wprowadzenie

W tej lekcji postaram Ci się ułatwić zapamiętanie niektórych informacji o wskaźnikach, referencjach i typach prostych, poprzez ich zestawienie.

Lekcja, mimo że trochę krótsza i w zasadzie bez żadnych nowości, powinna okazać się dla Ciebie pomocna i przydatna. Wierzę, że tak właśnie będzie.

Deklaracja zmiennej

Deklaracja zmiennej typu prostego, typu referencyjnego czy typu wskaźnikowego wygląda zupełnie inaczej dla każdego przypadku. Oto zestawienie:

Typy proste:

typ nazwaZmiennej;

Przykłady:

int wzrost;
char znak;
string napis;

Typ referencyjny:

typ &nazwaZmiennejReferencyjnej = nazwaZmiennejTypuProstego;

Przykłady:

int & wzroscik = wzrost;
char & znaczek = znak;
string & napisik = napis;

Typ wskaźnikowy:

typ *nazwaZmiennejWskaznikowej;

Przykłady:

int *wskWzrost;
char *wskZnak;
string *wskNapis;

Inicjalizacja zmiennej

Już patrząc na powyższe deklaracje zmiennej łatwo można spostrzec, że inicjalizacja jest konieczna w przypadku referencji, natomiast nie jest wymagana w przypadku typów prostych i typu wskaźnikowego.

Oczywiście, inicjalizacja w większości przypadków jest jak najbardziej wskazana również w przypadku typów prostych, jak i typu wskaźnikowego. W ten sposób unikamy bowiem zmiennych, które mają przypadkowe wartości, co może niekiedy prowadzi do poważnych i trudnych do wykrycia błędów.

Adres przechowywanej zmiennej

Do sprawnego posługiwania się referencjami i wskaźnikami, niezbędna jest wiedza, w jaki sposób wydobywać adresy przechowywanych zmiennych. Wypisanie adresu jest identyczne w przypadku zmiennej oraz referencji, natomiast odmienne w przypadku typu wskaźnikowego.

Typy proste:

typ nazwaZmiennej;
cout << & nazwaZmiennej; // adres zmiennej

Przykłady:

int wzrost;
cout << & wzrost; // adres zmiennej
char znak;
cout << & znak; // adres zmiennej
string napis;
cout << & napis; // adres zmiennej

Typ referencyjny:

typ &nazwaZmiennejReferencyjnej = nazwaZmiennejTypuProstego;
cout << &nazwaZmiennejReferencyjnej; // adres zmiennej

Przykłady:

int & wzroscik = wzrost;
cout << &wzroscik; // adres zmiennej
char & znaczek = znak;
cout << &znaczek; // adres zmiennej
string & napisik = napis;
cout << &napisik; // adres zmiennej

Typ wskaźnikowy:

typ *nazwaZmiennejWskaznikowej = &zmiennaTypuProstego;
cout << nazwaZmiennejWskaznikowej; // adres wskazywanej zmiennej

Przykłady:

int *wskWzrost = &wzrost;
cout << wskWzrost; // adres wskazywanej zmiennej
char *wskZnak = &znak;
cout << wskZnak; // adres wskazywanej zmiennej
string *wskNapis = &napis;
cout << wskNapis; // adres wskazywanej zmiennej

Zwracam Twoją uwagę na to, że w przypadku typu wskaźnikowego nie wypisujemy adresu samego wskaźnika, chociaż taka możliwość istnieje, a tylko adres zmiennej, na którą wskaźnik pokazuje. Adres wskaźnika też można wypisać, jednak jest on znacznie mniej użyteczny na tym etapie nauki C++.

Zauważ też, że przy wskaźnikach dodałem inicjalizację, bowiem tylko wtedy jest sensowne wypisywanie adresu zmiennej na którą wskaźnik wskazuje.

Dostęp do wartości przechowywanej

Zazwyczaj interesuje nas rzeczywista wartość danej zmiennej (a nie jej adres). Dostęp do wartości przechowywanej jest identyczny w przypadku typów prostych i referencji, a inny w przypadku typu wskaźnikowego (w tym przypadku trzeba skorzystać z operatora wyłuskania).

Typy proste:

typ nazwaZmiennej;
cout << nazwaZmiennej; // wartosc zmiennej

Przykłady:

int wzrost;
cout << wzrost; // wartosc zmiennej
char znak;
cout << znak; // wartosc zmiennej
string napis;
cout << napis; // wartosc zmiennej

Typ referencyjny:

typ &nazwaZmiennejReferencyjnej = nazwaZmiennejTypuProstego;
cout << nazwaZmiennejReferencyjnej; // wartosc zmiennej

Przykłady:

int & wzroscik = wzrost;
cout <<wzroscik; // wartosc zmiennej
char & znaczek = znak;
cout <<znaczek; // wartosc zmiennej
string & napisik = napis;
cout <<napisik; // wartosc zmiennej

Typ wskaźnikowy:

typ *nazwaZmiennejWskaznikowej= &zmiennaTypuProstego;
cout << *nazwaZmiennejWskaznikowej; // wartosc przechowywanej zmiennej

Przykłady:

int *wskWzrost = &wzrost;
cout << *wskWzrost; // wartosc wskazywanej zmiennej
char *wskZnak = &znak;
cout << *wskZnak; // wartosc wskazywanej zmiennej
string *wskNapis = &napis;
cout << *wskNapis; // wartosc wskazywanej zmiennej

Zauważ, że przy wskaźnikach dodałem inicjalizację, bowiem tylko wtedy jest sensowne wypisywanie wartości zmiennej na którą wskaźnik wskazuje.

Stałe wartości zmiennych

W programach niekiedy chcemy tworzyć zmienne, których wartość przez cały czas wykonania pozostanie stała. Takie zmienne muszą być oczywiście zainicjalizowane. Poniżej zestawiono sposoby deklaracji zmiennych typów podstawowych, typu wskaźnikowego i typu referencyjnego, które nie mogą zmieniać przechowywanej wartości.

Typy proste:

const typ nazwaZmiennej=wartoscOdpowiedniaDlaTypu;

Przykłady:

const int wzrost=4;
const char znak='a';
const string napis="Napis";

Typ referencyjny:

const typ &nazwaZmiennejReferencyjnej = nazwaZmiennejTypuProstego;

Przykłady:

const int & wzroscik = wzrost;
const char & znaczek = znak;
const string & napisik = napis;

Zwróć uwagę, że w przypadku typu wskaźnikowego wskaźnik będzie mógł nadal pokazywać na różne zmienne, chociaż nie będzie mógł zmieniać ich wartości. Jeśli chcesz ograniczyć takie działanie, musisz zadeklarować stały wskaźnik, a nie wskaźnik do stałego typu lub stały wskaźnik do stałego typu.

Podsumowanie

Jeśli do tej pory nie udawało Ci się zapamiętać różnic w zapisie zmiennych typów prostych, typu referencyjnego i typu wskaźnikowego, mam nadzieję, że dzięki tej lekcji pomogłem Ci to zrobić.

Od teraz wszystkie te typy będą niemal w takim samym stopniu wykorzystywane w programach, dlatego też jeśli coś jest dla Ciebie nadal niejasne, sugeruję Ci przeczytać wybrane lekcje jeszcze raz. Wiedza o referencjach i wskaźnikach będzie bowiem niezbędna, jeśli będziesz chcieć zrozumieć, jak efektywnie wykorzystywać funkcje w C++.

powrót