Wskaźniki (typ wskaźnikowy) - część trzecia. Operacje na kilku wskaźnikach

Wprowadzenie

Mimo że przedstawiłem Ci już trochę informacji o wskaźnikach, to nadal tak naprawdę nie wiesz o nich zbyt wiele. W tej lekcji postaram Ci się zademonstrować kilka użytecznych zastosowań wskaźników i pokazać, w jaki sposób nie popełniać błędów, które nas mogą drogo kosztować.

Kilka wskaźników - przykład 1

We wszystkich do tej pory przykładach mieliśmy do czynienia tylko z jednym wskaźnikiem. Nawet jeśli w programie pojawiały się dwa wskaźniki, to były one od siebie zupełnie niezależne i tak naprawdę nie miały na siebie żadnego wpływu.

Jako jednak, że wskaźniki dają bardzo duże możliwości, często stosuje się ich co najmniej kilka w jednym programie i dokonuje wielu operacji na kilku wskaźnikach, modyfikując wartości wskaźników lub wartości zmiennych przez wskaźniki pokazywanych.

Przejdźmy od razu do jakiegoś przykładowego programu, a dopiero później zastanowimy się, co się w programie dzieje. Oto program:

#include <iostream>

using namespace std;

int main()
{  
  double liczba=95.21; // zmienna typu double
  double *wskaznik1, *wskaznik2; //wskazniki do typu double
 
  wskaznik1 = &liczba; // ustawiamy wskaznik na zmienna typu double  
 
  cout <<"Wartosc zmiennej liczba wynosi: "<<liczba<<endl;  
  cout <<"Wyluskana wartosc ze wskaznika1 wynosi: "<< *wskaznik1 <<endl;
 
  // wskaznik2 = *wskaznik1; //BLAD!!! (1)
  // *wskaznik2 = wskaznik1; // BLAD!!! (2)
  wskaznik2 = wskaznik1;
  cout <<endl<<"Wartosc zmiennej liczba wynosi: "<<liczba<<endl;  
  cout <<"Wyluskana wartosc ze wskaznika1 wynosi: "<< *wskaznik1 <<endl;      
  cout <<"Wyluskana wartosc ze wskaznika2 wynosi: "<< *wskaznik2 <<endl;      
 
  *wskaznik2 = 5.789;  
  cout <<endl<<"Wartosc zmiennej liczba wynosi: "<<liczba<<endl;  
  cout <<"Wyluskana wartosc ze wskaznika1 wynosi: "<< *wskaznik1 <<endl;      
  cout <<"Wyluskana wartosc ze wskaznika2 wynosi: "<< *wskaznik2 <<endl;
 
  *wskaznik1 = 2.23;
  cout <<endl<<"Wartosc zmiennej liczba wynosi: "<<liczba<<endl;  
  cout <<"Wyluskana wartosc ze wskaznika1 wynosi: "<< *wskaznik1 <<endl;      
  cout <<"Wyluskana wartosc ze wskaznika2 wynosi: "<< *wskaznik2 <<endl;
 
  liczba=-15.88;
  cout <<endl<<"Wartosc zmiennej liczba wynosi: "<<liczba<<endl;  
  cout <<"Wyluskana wartosc ze wskaznika1 wynosi: "<< *wskaznik1 <<endl;      
  cout <<"Wyluskana wartosc ze wskaznika2 wynosi: "<< *wskaznik2 <<endl;    
       
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();  
  return 0;
}
program nr 29.1

W programie mamy do czynienia z jedną zmienną i dwoma wskaźnikami. Najpierw ustawiamy jeden ze wskaźników na zmienną, a potem usiłujemy ustawić drugi wskaźnik na pierwszy wskaźnik. Tu pojawiają się pierwsze problemy, jak coś takiego zrobić.

W linijce opatrzonej komentarzem (1), próbujemy do wartości wskaźnika, czyli adresu (wiesz już przecież, że wskaźniki przechowują adresy), przypisać wartość wyłuskaną z drugiego wskaźnika, czyli zwykłą liczbę, w tym przypadku typu double (nie jest to adres). Oczywiście jest to nieprawidłowe, a już na pewno nie o to nam chodziło. Nie powinniśmy do adresu przypisywać zwykłej wartości liczbowej.

Z kolei w linijce opatrzonej komentarzem (2) próbujemy zrobić coś innego - do wartości wyłuskanej ze wskaźnika (czyli wartości liczbowej), próbujemy przypisać adres drugiego wskaźnika. O to na pewno też nam nie chodziło.

W tym momencie pragnę zauważyć, że w nowszych kompilatorach, oba z wymienionych przypadków nie powinny się w ogóle skompilować. Niestety nie jest tak zawsze, zwłaszcza w starszych kompilatorach i program się skompiluje, jednak albo będzie działał nieprawidłowo albo tuż po uruchomieniu poinformuje Cię o błędzie. Dlatego też lepiej zapamiętaj, jak poprawnie operować wskaźnikami.

A poprawny sposób ustawienia jednego wskaźnika na drugi wskaźnik uzyskujemy przypisując po prostu wartość jednego wskaźnika do wartości drugiego wskaźnika. W takiej sytuacji, zarówno po lewej jak i po prawej stronie mamy adresy (bo wartości wskaźników to adresy), więc wszystko jest w porządku i działa dokładnie tak, jak tego oczekiwaliśmy.

Ponadto analizując wszystkie fragmenty, w których wypisujemy wartości zmiennej i wartości wyłuskane ze wskaźnika, nie napotykamy żadnych niespodzianek. Wszystko wygląda na takie, jak być powinno i jak się spodziewaliśmy.

Kilka wskaźników - przykład 2

Teraz pokażę Ci małą pułapkę w pracy z kilkoma wskaźnikami, żeby uświadomić Ci, że wskaźniki naprawdę nie są zbyt proste i nieumiejętnie używane, mogą powodować błędy w programie. Oto przykład:

#include <iostream>

using namespace std;

int main()
{  
  double liczba1=95.21, liczba2=0.23; // zmienne typu double
  double *wskaznik1, *wskaznik2; //wskazniki do typu double
 
  wskaznik1 = &liczba1; // ustawiamy wskaznik na zmienna typu double  
 
  cout <<"Wartosc zmiennej liczba wynosi: "<<liczba1<<endl;  
  cout <<"Wyluskana wartosc ze wskaznika1 wynosi: "<< *wskaznik1 <<endl;
 
  wskaznik2 = wskaznik1; // (1)
  cout <<endl<<"Wartosc zmiennej liczba wynosi: "<<liczba1<<endl;  
  cout <<"Wyluskana wartosc ze wskaznika1 wynosi: "<< *wskaznik1 <<endl;      
  cout <<"Wyluskana wartosc ze wskaznika2 wynosi: "<< *wskaznik2 <<endl;
 
  // "podejrzyjmy" wszystkie adresy (2)
  /*cout <<endl<<"Adres zmiennej liczba wynosi: "<< &liczba1<<endl;  
  cout <<"Wartosc wskaznika1 wynosi: "<<wskaznik1<<endl;      
  cout <<"Wartosc wskaznika2 wynosi: "<<wskaznik2<<endl; */

 
  wskaznik1 = &liczba2; // (3)
  cout <<endl<<"Wartosc zmiennej liczba wynosi: "<<liczba1<<endl;  
  cout <<"Wyluskana wartosc ze wskaznika1 wynosi: "<< *wskaznik1 <<endl;      
  cout <<"Wyluskana wartosc ze wskaznika2 wynosi: "<< *wskaznik2 <<endl;  
 
  // "podejrzyjmy" jeszcze raz wszystkie adresy (4)
  /* cout <<endl<<"Adres zmiennej liczba wynosi: "<< &liczba1<<endl;  
  cout <<"Wartosc wskaznika1 wynosi: "<<wskaznik1<<endl;      
  cout <<"Wartosc wskaznika2 wynosi: "<<wskaznik2<<endl; */

       
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();  
  return 0;
}
program nr 29.2

Jak na razie proponuję Ci nie usuwać żadnych komentarzy i nie sprawdzać, co zostanie wypisane. Postaramy się zastanowić, czemu program działa tak jak działa i zlokalizować ewentualny błąd.

No to zaczynamy - na początku programu deklarujemy i inicjalizujemy dwie zmienne typu double i deklarujemy dwa wskaźniki do typu double. Następnie wskaznik1 ustawiamy na zmienną liczba1. Wypisujemy wartość zmiennej liczba1 i wartość wyłuskaną ze wskaźnika i jak na razie wszystko jest dokładnie tak jak się tego spodziewaliśmy.

Idźmy dalej. W linii opatrzonej komentarzem (1) wchodzi do działania wskaznik2. Wskaźnik ten zostaje ustawiony na wskaznik1. Od tej pory, wskaznik2 powinien wskazywać tam gdzie wskazuje wskaznik1.

Wypisujemy zatem wartość zmiennej liczba1 oraz wartości z obu wskaźników i widzimy, że rzeczywiście wszystko idzie po naszej myśli. Wskaźnik wskaznik2 został ustawiony na wskaznik1 i dzięki temu wyłuskana z niego wartość jest równa wartości wyłuskanej ze wskaźnika wskaznik1.

Decydujemy się jednak w linii oznaczonej komentarzem (3) na ustawienie wskaźnika wskaznik1 na zmienną liczba2. Zgodnie z naszymi intencjami, po tej zmianie, również wskaznik2 powinien wskazywać na zmienną liczba2, bo przecież, wskaznik2 cały czas jest ustawiony na wskaznik1. Skoro wskaznik1 pokazuje na zmienną liczba2, to także wskaznik2 powinien pokazywać w takiej sytuacji na zmienną liczba2.

Przyglądając się jednak rezultatom wypisania zmiennej liczba2 i wartości wyłuskanych ze wskaźników, okazuje się jednak, że oto mamy niespodziankę. Wartość wyłuskana ze wskaźnika wskaznik2 jest inna niż wartość wyłuskana ze wskaźnika wskaznik1, chociaż, co dla nas prawie oczywiste, wartości te powinny być identyczne.

Jeśli ponownie przeanalizujemy kod (nie licząc miejsc, które są na razie otoczone komentarzami), nie znajdziemy niczego, co mogłoby powodować ten "błąd". Cały kod wygląda poprawnie, a jednak coś najwidoczniej jest źle.

Usuń zatem komentarze znajdujące się poniżej linii (2) i (4), skompiluj program i uruchom go jeszcze raz. Teraz dodatkowo zostają wypisane wartości wskaźników i adres zmiennej.

Jak widać poniżej linii (2) wartości wskaźników są takie same (czyli wskaźniki pokazują dokładnie na to samo miejsce w pamięci operacyjnej), jednak już za drugim razem, poniżej linii (4), wartości wskaźników są inne, co oznacza, że wskaźniki pokazują na inne miejsca w pamięci. Stąd też pojawiły się inne wartości wyłuskane ze wskaźników.

Co zatem poszło nie tak? Co zrobiliśmy źle? Po chwili namysłu dojdziesz do przekonania, że musi chodzić o linię opatrzoną komentarzem (3), bo przecież wszystko wcześniej było w porządku. Tak naprawdę, problem tkwi w innym miejscu, a ta linia powoduje po prostu uaktywnienie się problemu, czy też pułapki.

W rzeczywistości cały problem pojawia się w linii opatrzonej komentarzem (1). Co prawda, wskaźnik wskaznik2 ustawiamy na wskaźnik wskaznik1, ale co to w rzeczywistości oznacza? Tak naprawdę oznacza to coś innego, niż się wydaje.

Otóż w tym miejscu, wskaźnik wskaznik1 wskazywał na zmienną liczba1. Oznacza to tyle, że w tym momencie wartość wskaźnika wskaznik1 była równa adresowi zmiennej liczba1. Skoro tak, to linię (1) możemy równie dobrze zapisać następująco:

  wskaznik2 = & liczba1; // (1)

Mam nadzieję, że teraz już rozumiesz. Wskaźnik wskaznik2 został w rzeczywistości, mimo dość mylnego zapisu, powiązany ze zmienną liczba1 i dlatego też, żadne zmiany wskaźnika wskaznik1 nie odzwierciedlają się w zmianach wskaźnika wskaznik2.

To co powinniśmy wynieść z przykładu, to to, że wskaźniki mimo swojej potęgi są bardzo niebezpieczne. Gdyby wartości wskaźników nie były wypisywane, znalezienie błędu mogłoby zająć znacznie więcej czasu, zwłaszcza w dużym programie.

Dodatkowo powinno udać Ci się zapamiętać, że przypisywanie wartości wskaźników, chociaż przydatne, dotyczy tylko aktualnej wartości wskaźnika po prawej stronie przypisania, a późniejsze modyfikacje nie są już odzwierciedlane.

Co jednak jeśli chcielibyśmy utworzyć wskaźnik, który pokazywałby dokładnie w to samo miejsce co inny wskaźnik i to niezależnie, ile razy ten pierwszy wskaźnik zmieniałby zmienną, na którą pokazuje? No cóż, rozwiązanie oczywiście jest możliwe, jednak nie chcę Cię na razie przerażać bardziej skomplikowanymi wskaźnikami, dlatego też pozwól, że nie będziemy się teraz nad tym zastanawiać.

Kilka wskaźników - przykład 3

To już ostatni przykład dotyczący kilku wskaźników wykorzystywanych jednocześnie. Mam nadzieję, że po jego zrozumieniu, będziesz już doskonale pamiętać wszystko to, co Ci do tej pory na temat wskaźników przedstawiałem. Oto przykład:

#include <iostream>

using namespace std;

int main()
{  
  int liczba=76;
  int *wsk=&liczba; // (0) wsk wskazuje na liczba
  cout <<liczba<<' '<<*wsk<<endl;  
 
  int *wsk2;
  wsk2=wsk; // (1) wsk2 wskazuje na liczba
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<endl;
  cout <<"Adresy: "<< &liczba<<' '<<wsk<<' '<<wsk2<<endl;
 
  int x=78;
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;  
 
  wsk=&x; // (2) wsk wskazuje na x
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;  
  cout <<"Adresy: "<< &liczba<<' '<<wsk<<' '<<wsk2<<' '<<&x<<endl;
 
  *wsk2=100; // (3)
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;  
 
  x=45; // (4)
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;  
   
  wsk2=&liczba; //(5) nic sie nie zmieni
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;  
  cout <<"Adresy: "<< &liczba<<' '<<wsk<<' '<<wsk2<<' '<<&x<<endl;  
 
  *wsk2=99; // (6)  
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;  
             
  wsk=wsk2; //(7) wsk i wsk2 wskazuja na liczba liczba
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;  
  cout <<"Adresy: "<< &liczba<<' '<<wsk<<' '<<wsk2<<' '<<&x<<endl;  
       
  x=77; // (8)        
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;
 
  liczba=-1; // (9)  
  cout <<endl<<liczba<<' '<<*wsk<<' '<<*wsk2<<' '<<x<<endl;    
       
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();  
  return 0;
}
program nr 29.3

Sugeruję Ci skompilować i uruchomić program i postarać się dokładnie przeanalizować pojawiające się na ekranie wyniki, porównując wyniki z kodem programu. Dopiero po dokładnej analizie, przeczytaj znajdujące się poniżej wyjaśnienia.

W linii (0) ustawiamy wskaźnik wsk na zmienną, którą wcześniej utworzyliśmy i zainicjowaliśmy. Wskaźnik jest ustawiony, o czym przekonujemy się wypisując odpowiednie wartości na ekran.

W linii (1) nowy wskaźnik wsk2 ustawiamy na wskaźnik wsk. Ponieważ jednak wskaźnik wsk wskazywał do tej pory na zmienną liczba, to wynika z tego, że wsk2 wskazuje obecnie również na zmienną liczba. Wypisujemy odpowiednie wartości i adresy i przekonujemy się, że wszystko jest w porządku.

Następnie tworzymy nową zmienną x, z którą nie jest powiązany żaden wskaźnik. Potwierdza się to, gdy wypisujemy odpowiednie wartości - wszystkie wartości poza nową wartością zmiennej, są takie jak poprzednio.

W (2) ustawiamy wskaźnik wsk na przed momentem utworzoną zmienną x. Zgodnie z wiedzą z poprzedniego programu, po wypisaniu widzimy, że zmiana ma wpływ tylko na wyłuskaną wartość wsk, natomiast mimo że w (1) wsk2 był ustawiony na wsk, to wskaźnika wsk te zmiany już nie dotyczą.

Kiedy w (3) modyfikujemy wyłuskaną wartość z wsk2, zmienia się również wartość zmiennej liczba, bowiem wskaźnik wsk2 ostatnio (czyli w 1) był ustawiony na zmienną liczba.

Z kolei w (4) dokonujemy zawartość zmiennej x. Ponieważ wskaźnik wsk wskazuje na x (patrz (2), to gdy wyłuskujemy z niego wartość, zmiana jest również widoczna.

W (5) ustawiamy wsk2 na zmienną liczba. Nie powoduje to jednak żadnych zmian, bowiem od (1) wsk2 już wskazywał na zmienną liczba (mimo, że tam to ustawienie było mniej czytelne).

W linii (6) dokonujemy zmiany wartości wyłuskanej z wsk2. Ponieważ jednak wsk2 wskazuje na zmienną liczba (linia (5)), to zmiana powoduje również zmianę wartości zmiennej liczba, o czym się przekonujemy.

Kiedy w linii (7) ustawiamy wskaźnik wsk na wskaźnik wsk2, powodujemy w rzeczywistości ustawienie wsk na zmienną liczba (bo wsk2 od kroku (5) pokazuje na zmienną liczba). Wszystko potwierdza się po wypisaniu adresów i odpowiednich wartości.

W linii (8) zmieniamy wartość zmiennej x. Na zmienną x nie pokazuje jednak żaden wskaźnik (wsk pokazuje na zmienną liczba i również wsk2 pokazuje na zmienną liczba), więc zmiana następuje jedynie dla samej zmiennej x.

W (9) dokonujemy zmiany wartości zmiennej liczba. Ponieważ zarówno wsk, jak i wsk2 wskazują na tę zmienną, to wyłuskując wartości ze wskaźników, widzimy że zmiana została odzwierciedlona.

W ten oto sposób, przeanalizowaliśmy cały program. Mam nadzieję, że udało Ci się wszystko zrozumieć już wcześniej, bez czytania wyjaśnień. Jednak jeśli nie, teraz nadeszła pora, aby jeszcze raz uruchomić program i spróbować przeanalizować go na własną rękę.

Nieustawiony wskaźnik

Ten paragraf będzie bardzo krótki, ale ma Ci uświadomić kolejną ważną rzecz. Najpierw przyjrzyj się poniższemu programowi:

#include <iostream>

using namespace std;

int main()
{  
  int liczba=76;
  int *wsk;
  *wsk=5; // UWAGA - BLAD !!!
  cout <<"Wartosc wyluskana ze wskaznika to: "<<*wsk<<endl;
       
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();  
  return 0;
}
program nr 29.4

Program możesz spróbować uruchomić, jednak rezultaty mogą być różne, więc lepiej tego nie rób. W programie został popełniony bardzo poważny błąd. Czy wiesz jaki?

Problemem jest to, że co prawda utworzyliśmy zmienną i wskaźnik, jednak wskaźnika nie ustawiliśmy. Mało tego, próbujemy przypisać wartości wyłuskanej ze wskaźnika wartość i tę wyłuskaną wartość wypisać.

Taki błąd może być tragiczny w skutkach. Nie dość, że oczywiście nie uzyskujemy tego, czego byśmy sobie nie życzyli, to powodujemy zatarcie wartości jakiejś innej zmiennej w pamięci operacyjnej.

Dzieje się tak dlatego, że jak Ci już kiedyś wspominałem, wszystkie zmienne niezainicjowane mają wartość przypadkową. Skoro wartość przypadkową, to w tym przypadku mogło się zdarzyć, że przypadkowa wartość wskaźnika jest równa adresowi innej zmiennej w programie i teraz nieświadomie przypisaliśmy tamtej zmiennej wartość 5.

Co prawda w naszym programie, nie spowodowałoby to żadnej tragedii. Wyobraź sobie jednak taki błąd w oprogramowaniu samolotu pasażerskiego lub maszyny sterującej produkcją samochodów. Taki błąd mógłby kosztować poważne straty finansowe, a nawet zagrożenie życia wielu osób.

Niestety w zasadzie nie istnieją bezbłędne programy przeznaczone do użytku. W prawie każdym programie jest jakiś błąd, albo bardziej albo mniej poważny. Programiści są tylko ludźmi i każdy się z nich w końcu pomyli. Niektóre błędy mogą zostać wykryte w fazie testów, inne już na początku użytkowania, niektóre mogą się pojawić po kilku latach, a niektóre wręcz nigdy, mimo że tak naprawdę istnieją.

Aby zapewnić względne bezpieczeństwo operacji na wskaźnikach inicjalizuje się (lub ewentualnie przypisuje tuż po deklaracji) wartości wskaźnika, wartość 0. Wartość 0 symbolizuje w przypadku wskaźników, że wskaźnik na żadną zmienną nie pokazuje. Dodatkowo oczywiście wykonując później krytyczne operacje, należy sprawdzać czy wartość wskaźnika jest równa 0 czy też nie. Przykładowy ulepszony program, wyglądałby następująco:

#include <iostream>

using namespace std;

int main()
{  
  int liczba=76;
  int *wsk=0;
   
  if (wsk) // czyli if (wsk!=0)
  {
    *wsk=5;
    cout <<"Wartosc wyluskana ze wskaznika to: "<<*wsk<<endl;
  }
  else
    cout <<"Uwaga - wskaznik jest niezainicjalizowany!!!"<<endl;
 
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();  
  return 0;
}
program nr 29.5

W tym przypadku, ograniczyliśmy akcję zaradczą, kiedy wskaźnik jest niezaincjalizowany, do wypisania komunikatu na ekranie. Oczywiście w praktyce postąpilibyśmy raczej inaczej - albo przerwali program albo usiłowali pokazać wskaźnikiem na zmienną i wykonać te instrukcje, które byśmy wykonali dla poprawnej wartości wskaźnika.

Szczególny wskaźnik

Szczególny wskaźnik w języku C++ stanowi wskaźnik do typu char. Wskaźnik ten możemy traktować tak jak wszystkie poznane do tej pory wskaźniki, przykładowo:

#include <iostream>

using namespace std;

int main()
{  
  char litera='M';
  char *wsk=&litera;
  cout <<*wsk<<' '<<litera<<endl;
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();  
  return 0;
}
program nr 29.6

W rzeczywistości jednak wskaźnik do typu char był wykorzystywany w języku C, poprzedniku języka C++ jako typ służący do przechowywania napisów. W języku C++ typ ten również jest tak wykorzystywany, ale dzięki nowemu typowi string, nieobecnemu w języku C, znacznie rzadziej.

To na co chcę Cię uczulić, zawarte jest w poniższym programie:

#include <iostream>

using namespace std;

int main()
{  
  char *napis="Dobre wykorzystanie typu char *";  
  cout <<"Napis to: "<<napis<<endl;
 
  /* napis="Zle wykorzystanie typu char *"; // UWAGA - ZLE !!!
  cout <<"Napis to: "<<napis<<endl; */

 
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();  
  return 0;
}
program nr 29.7

Zauważ przede wszystkim, że w tym przypadku typ char * nie jest na pierwszy rzut oka w ogóle wykorzystywany jak wskaźnik. Na dodatek przypisujemy do niego wartość, a konkretnie pewien napis, mimo że wskaźnik nie wskazuje na żadną zmienną.

Wypisanie napisu jest również nietypowe, bowiem nie używamy tutaj w ogóle operatora wyłuskania. Rzeczywiście wygląda to dość dziwnie.

Mimo że wszystko to wygląda trochę dziwnie, to działa i jest zupełnie poprawne. Jest jednak mała pułapka. Przypisanie napisu do zmiennej typu char * jest możliwe tylko podczas inicjalizacji. Część opatrzona komentarzem jest już niepoprawna mimo że jeśli usuniesz komentarz, skompilujesz program i uruchomisz go, najprawdopodobniej błąd będzie niewidoczny.

Gdyby jednak Twój program był nieco bardziej skomplikowany, błąd ten ujawniłby się prędzej lub później, a znalezienie go, zajęłoby Ci na pewno bardzo dużo czasu. Dlatego też uczulam Cię na tę kwestię mimo że tak naprawdę odradzam w miarę możliwości używanie typu char * jako typu do przechowywania napisów.

Podsumowanie

Ta lekcja kończy serię trzech lekcji o wskaźnikach, w których przedstawiłem Ci zupełnie podstawowe informacje o wskaźnikach. Mam nadzieję, że wiesz już czym są wskaźniki i jak ich używać.

W kolejnej lekcji znajduje się zestawienie informacji o referencji, wskaźnikach i zmiennych, które sugeruję Ci dokładnie przeczytać. Jednak jeśli nie czujesz się jeszcze zbyt pewnie w tematyce wskaźników, radzę Ci przeczytać wszystkie lekcje na ich temat raz jeszcze. To na pewno pomoże Ci w ich zrozumieniu, a za kilka lekcji zobaczysz, że temat wskaźników powróci i wiedza tu zdobyta na pewno Ci się przyda.

powrót