Programowanie strukturalne i obiektowe C++ Robert Nowak Programowanie strukturalne i obiektowe C++ Zmienne referencyjne i zmienne wskaźnikowe
Zmienne typu referencyjnego Poza podstawowymi typami w języku C++ istnieje tzw. typ referencyjny. Zmienne typu referencyjnego służą do reprezentacji innych zmiennych w programie. Operacje na zmiennej x są równoważne operacjom na zmiennej referencyjnej związanej z tą zmienną. W praktyce typy i zmienne referencyjne są wykorzystywane podczas przekazywania parametrów do funkcji oraz zwracania wartości funkcji.
Deklaracja zmiennej referencyjnej Deklaracja zmiennej referencyjnej przedstawia się następująco: typ &identyfikator_ref=identyfikator_zmiennej;
Przykład programu 1 #include <iostream> using namespace std; int main() { float waga=68.5; float &wartosc = waga; cout <<"Wartosc zmiennej waga wynosi "<<waga<<'\n'; cout <<"Wartosc referencji wynosi "<<wartosc<<'\n'; waga=90; wartosc=23; cout <<"\nNacisnij ENTER aby zakonczyc...\n"; getchar(); return 0; }
Referencja - ważne zasady i cechy Referencja musi zostać zainicjalizowana - nie możemy zadeklarować zmiennej typu referencyjnego, a później dokonać przypisania, połączenia jej z jakąś inną zmienną. Musi to być koniecznie inicjalizacja. Referencja jest w swojej istocie stała - referencja wskazuje zawsze na konkretną zmienną i nie możemy nagle jej powiedzieć, że ma pokazywać na inną zmienną; referencja jest na zawsze związana ze zmienną, którą została zainicjalizowana.
Referencja - ważne zasady i cechy Referencja musi zawsze być dokładnie takiego samego typu jak zmienna, z którą jest powiązana Referencją poza linijką deklaracji (i jednocześnie inicjalizacji) posługujemy się jak zwykłą zmienną Wartość zmiennej typu referencyjnego jest równa wartości zmiennej, z którą referencja jest powiązana - ponieważ referencja jest tylko dodatkową nazwą dla danej zmiennej, to jej wartość jest dokładnie taka sama jak wartość zmiennej, której dotyczy referencja.
Zmienne w pamięci operacyjnej Każda zmienna, która jest zadeklarowana w programie zostaje umieszczona w pamięci operacyjnej na czas działania programu. Pamięć operacyjna to zbiór komórek pamięci. Każda komórka w pamięci ma określone położenie - adres. Adres jest liczbą, która jednoznacznie określa położenie komórki w pamięci. Każda zmienna, którą deklarujemy w programie jest umieszczana w komórkach pamięci. W zależności, jakiego typu jest ta zmienna, może ona zostać umieszczona w jednej, dwóch lub większej liczbie komórek pamięci. Jednak adres zmiennej pokazuje zawsze na pierwszą komórkę pamięci - tam zaczyna się właśnie nasza zmienna.
Operator pobrania adresu w C++ Do pobierania adresu zmiennej dowolnego typu służy operator pobrania adresu – w języku C++ takim operatorem jest &. W rzeczywistości z operatora & – operatora pobrania adresu korzystaliśmy już w przypadku referencji. Kiedy deklarowaliśmy (i jednocześnie inicjowaliśmy) zmienną typu referencyjnego, mówiliśmy kompilatorowi tak naprawdę, że adres referencji ma być równy adresowi zmiennej, z którą została związana referencja. Zapis jednak w tym przypadku był nieco mylący, bowiem operator pobrania adresu znajdował się tylko i wyłącznie po stronie referencji, a po stronie zmiennej operatora tego już nie było.
Przykład programu 2 #include <iostream> using namespace std; int main() { int mojaLiczba=23; cout <<"Wartosc zmiennej to "<<mojaLiczba<<'\n'; cout <<"Adres zmiennej to "<< &mojaLiczba<<'\n'; cout <<"\nNacisnij ENTER aby zakonczyc...\n"; getchar(); return 0; }
Pojęcie wskaźnika W języku C++ istnieje możliwość definiowania zmiennych zawierających adres jakiegoś obszaru w pamięci, przy czym obszar ten może być interpretowany jako zmienna określonego typu. Zmienne zawierające adres obszaru pamięci nazywamy zmiennymi wskaźnikowymi lub krótko wskaźnikami. Wskaźnik więc, jest zmienną, przechowującą adres pamięci.
Deklaracja wskaźnika Schematycznie wskaźnik deklarujemy następująco: typ *nazwa_wskaznika; Jak widać wskaźnik oznaczamy za pomocą gwiazdki pojawiającej się przed nazwą zmiennej. Deklarację taką odczytujemy od końca. Na widok gwiazdki mówimy: „jest wskaźnikiem do pokazywania na zmienne typu…”.
Przykład wskaźnika int *wska; Jest to deklaracja wskaźnika wska mogącego pokazywać na zmienne (obiekty) typu int. wska – jest wskaźnikiem do pokazywania na zmienne typu int.
Powiązanie wskaźnika ze zmienną Wskaźniki przechowują adresy! Wartością każdego wskaźnika jest adres zmiennej, na którą ten wskaźnik wskazuje o ile tylko wskaźnik został ustawiony na daną zmienną. Ustawienia takiego dokonujemy następująco: nazwa_wskaznika=&nazwa_zmiennej; przy czym typ wskaźnika i typ zmiennej muszą być zgodne.
Deklaracja wskaźnika wraz z inicjalizacją Schematycznie deklaracja wskaźnika wraz z jego inicjalizacją wygląda następująco: typ *nazwa_wskaznika = &nazwa_zmiennej; Jest to równoważne: typ *nazwa_wskaznika; nazwa_wskaznika = &nazwa_zmiennej;
Operator wyłuskania Operator wyłuskania oznaczamy za pomocą * i poprzedzając nazwę wskaźnika tym operatorem, uzyskujemy wartość zmiennej, na którą dany wskaźnik wskazuje.
Przykład programu 3 #include <iostream> using namespace std; int main() { int liczba=6; // zmienna typu int int *wskaznik; // wskaznik do typu int wskaznik=&liczba; // powiazanie wskaznika ze zmienna liczba cout <<"Wartosc zmiennej liczba wynosi "<<liczba<<'\n'; cout <<"Adres zmiennej wynosi "<< &liczba <<'\n'; cout <<"Wartosc wskaznika wynosi "<<wskaznik<<'\n'; cout <<"Wyluskana wartosc ze wskaznika wynosi "<< *wskaznik <<'\n'; // porownajmy adres wskaznika i adres zmiennej if (&liczba==wskaznik) cout <<"Obie zmienne wskazuja na ten sam adres\n"; else cout <<"Zmienne wskazuja na rozne adresy\n"; // porownajmy wyluskana wartosc i wartosc zmiennej if (liczba == *wskaznik) cout <<"Obie wartosci sa identyczne\n"; cout <<"Wartosci sa inne\n"; cout <<"\nNacisnij ENTER aby zakonczyc...\n"; getchar(); return 0; }
Następny przykład programu 4 #include <iostream> using namespace std; int main() { float a=6.23; // zmienna typu float float *wsk; // wskaznik do typu float wsk=&a; // powiazanie wskaznika ze zmienna a cout <<"Wartosc zmiennej a wynosi "<<a<<'\n'; cout <<"Adres zmiennej a wynosi "<< &a <<'\n'; cout <<"Wartosc wskaznika wynosi "<<wsk<<'\n'; cout <<"Wyluskana wartosc ze wskaznika wynosi "<< *wsk <<'\n'; a=25.98; cout <<"\nWartosc zmiennej a wynosi "<<a<<'\n';
Ciąg dalszy programu 4 // wsk=21; // UWAGA - BLAD !!! *wsk=21; cout <<"\nWartosc zmiennej a wynosi "<<a<<'\n'; cout <<"Adres zmiennej a wynosi "<< &a <<'\n'; cout <<"Wartosc wskaznika wynosi "<<wsk<<'\n'; cout <<"Wyluskana wartosc ze wskaznika wynosi "<< *wsk <<'\n'; *wsk=*wsk+1; // lub ++(*wsk); cout <<"Wyluskana wartosc ze wskaznika wynosi "<< *wsk <<'\n'; cout <<"\nNacisnij ENTER aby zakonczyc...\n"; getchar(); return 0; }
Program 5 #include <iostream> #include <string> using namespace std; int main() { string a="Zmienna a",b="Zmienna b",c="Zmienna c";//zmienne string string *wsk; // wskaznik do typu string wsk=&a; // powiazanie wskaznika ze zmienna a cout <<"Wartosc zmiennej a wynosi: "<<a<<'\n'; cout <<"Wyluskana wartosc ze wskaznika wynosi: "<< *wsk <<'\n'; *wsk="Tu byla zmienna a, ale teraz zmienilismy jej wartosc"; cout <<'\n'<< *wsk << '\n'; cout << a <<'\n'; wsk = &b; // powiazanie wskaznika ze zmienna b cout <<"\nWartosc zmiennej a wynosi: "<<a<<'\n'; cout <<"Wartosc zmiennej b wynosi: "<<b<<'\n'; // nie wypisujemy a, bo na razie a sie nie zmieni
Ciąg dalszy programu 5 *wsk=c; // przypisanie za pomoca wskaznika, rownowazne b=c cout <<"\nWyluskana wartosc ze wskaznika wynosi: "<< *wsk <<'\n'; cout <<"Wartosc zmiennej b wynosi: "<<b<<'\n'; cout <<"Wartosc zmiennej c wynosi: "<<c<<'\n'; wsk = &c; // powiazanie wskaznika ze zmienna c *wsk="Tu kiedys byla zmienna c"; cout <<"Wartosc zmiennej c wynosi: "<<c<<'\n'; // nie wypisujemy juz b i c - ich wartosci sie nie zmienia wsk = &a; // powiazanie wskaznika ze zmienna a (PONOWNIE) *wsk="Przykladowy testowy tekst"; cout <<"Wartosc zmiennej a wynosi: "<<a<<'\n'; cout <<"\nNacisnij ENTER aby zakonczyc...\n"; getchar(); return 0; }