Definicja, deklaracja, inicjalizacja - ważne pojęcia w języku C++

Wprowadzenie

Ten rozdział będzie trochę nietypowy. Nie poznasz w nim w zasadzie żadnych nowych elementów języka C++. Rozdział ten ma na celu wyjaśnienie Ci pewnych pojęć, których znajomość będzie konieczna przy poznawaniu nowych elementów języka.

Wielu z tych pojęć używałem już w poprzednich lekcjach, jednak dopiero teraz nadszedł odpowiedni moment na ich wyjaśnienie.

Deklaracja

Deklaracja informuje kompilator, że dana nazwa jest już znana. Pamięć dla obiektu nie zostaje jednak przydzielona. Do obiektu nie możemy się odwoływać, nie możemy mu przypisywać wartości, bowiem on tak naprawdę jeszcze nie istnieje.

Ważne jest, że w programie może być kilka deklaracji tego samego elementu. Deklaracji używamy w przypadku zmiennych, funkcji oraz typów danych.

Pomyślisz sobie - no dobrze, ale po co mi np. taka zmienna, której nazwę znam, a i tak nie mogę się do niej odwołać? No cóż - na początkowym etapie nauki rzeczywiście nie będziesz z tego zbyt często korzystać.

Musisz jednak wiedzieć, że programy w języku C++ mogą się składać z wielu plików i wtedy w niektórych plikach możemy być zmuszeni napisać tylko deklarację tej zmiennej, a tylko w jednym pliku pojawi się definicja zmiennej (co to jest definicja - o tym za chwilę).

Jeśli chcemy napisać deklarację zmiennej piszemy schematycznie:

extern nazwaTypu nazwaZmiennej;

czyli jeśli chcemy zadeklarować zmienną o nazwie liczba typu int, to napiszemy wówczas:

extern int liczba;

Jak już wspomniałem, na początku z deklaracji zmiennej nie będziesz zbyt często korzystać, więc nie musisz się tym tak bardzo przejmować.

Deklaracje mają jednak dużo większe znaczenie. Jeśli piszemy program, w którym wykorzystujemy funkcje (o tym w najbliższych lekcjach), wtedy właśnie będziemy bardzo często korzystać z deklaracji.

Definicja

Podczas gdy deklaracja ma jedynie informować czym jest dany identyfikator w programie, to celem definicji jest dokładne określenie, czym jest dany identyfikator.

Definicja rezerwuje miejsce w pamięci dla danej zmiennej. Dla jakiej zmiennej? No właśnie - zmienna musi być przecież gdzieś zadeklarowana, żeby była znana jej nazwa oraz typ. Otóż jest w tym pewna pułapka, bowiem każda definicja jest jednocześnie deklaracją (ale nie odwrotnie).

Definicje występowały w zasadzie w każdym programie, które Ci tu przedstawiałem jednak wtedy nie nazwaliśmy zazwyczaj rzeczy po imieniu.

Jeśli chcemy napisać definicję zmiennej piszemy schematycznie:

nazwaTypu nazwaZmiennej;

czyli jeśli chcemy zdefiniować zmienną o nazwie liczba typu int napiszemy:

int liczba;

Jak więc widzisz to nie jest tak naprawdę nic nowego. Definicje, podobnie jak deklaracje, będziemy wykorzystywać przy poznawaniu funkcji.

Gdy w poprzednich lekcjach tworzyliśmy typ strukturalny, to tak naprawdę pisaliśmy definicję danej struktury. Pisaliśmy zatem definicję struktury Osoba, Samochod, Ksiazka itd.

Inicjalizacja (inicjowanie)

Inicjalizacja (inicjowanie) polega na przypisaniu wartości do danej zmiennej w momencie jej deklaracji.

Aby zainicjalizować zmienną piszemy schematycznie:

nazwaTypu nazwaZmiennej=wartosc;

czyli na przykład dla zmiennej o nazwie liczba, którą inicjalizujemy wartością 44, inicjalizacja będzie wyglądała następująco:

int liczba=44;

Musisz zapamiętać, że inicjalizacja następuje jedynie w przypadku przypisania wartości w momencie deklaracji. Przypisanie wartości danej zmiennej w dalszej części programu (nawet w następnej instrukcji) nie jest już inicjalizacją, tylko zwykłym przypisaniem.

Przykładowo jest inicjalizacją:

string nazwisko="Iksinski"; // to jest inicjalizacja

a nie jest:

string nazwisko;
nazwisko="Iksinski"; // to NIE jest inicjalizacja

Nasuwa się pytanie do czego służy inicjalizacja i czy zawsze musimy inicjalizować zmienne. Inicjalizacja służy do przypisania początkowej wartości zmiennej. Oczywiście dokładnie taki sam efekt można uzyskać za pomocą zwykłego przypisania.

Przy okazji pragnę Ci przypomnieć, że wszystkie zmienne z modyfikatorem const muszą właśnie zostać zainicjalizowane. W przeciwnym przypadku kompilator zgłosi błąd.

Wróćmy jednak do problemu, a mianowicie do sytuacji, w których warto dokonać inicjalizacji (lub przypisania) zmiennej. W niektórych przypadkach to kompilator dokona za Ciebie inicjalizacji, a w innych nie. Na razie nie będę poruszał tego tematu, bowiem moim zdaniem to w Twojej intencji powinno być zainicjalizowanie zmiennej.

Oczywiście to, czy zmienna powinna zostać zainicjalizowana zależy od sytuacji. Jeśli tworzymy zmienną i za moment żądamy od użytkownika podania jej wartości, to inicjalizacja jest zupełnie zbędna. Natomiast jeśli zmienną używamy jako zmienną pomocniczą do obliczeń, niekiedy kluczową sprawą może być to, czy ją zainicjalizujemy czy też nie.

Na potwierdzenie moich słów, przedstawię Ci prosty program, który oblicza sumę liczb od 0 aż do podanej przez użytkownika liczby i następnie tę sumę wypisuje. Postaraj się napisać teraz ten program na własną rękę, nie patrząc na rozwiązanie.

Oto prosty program liczący sumę, w którym mogłoby się wydawać, że nie ma żadnego błędu:

#include <iostream>

using namespace std;

int main()
{
  unsigned long int suma; // suma liczb
  unsigned int pom; // zmienna pomocnicza
  cout <<"Podaj liczbe do ktorej bedzie liczona suma: ";
  cin >>pom;
  cin.ignore();
 
  // obliczamy sume
  for (unsigned int i=0;i<=pom;++i)
     suma+=i;
 
  cout <<"Suma liczb od 0 do "<<pom<<" wynosi "<<suma<<endl;
 
  cout <<endl<<"Nacisnij ENTER aby zakonczyc..."<<endl;
  getchar();  
  return 0;
}
program nr 23.1

Jestem bardzo ciekawy, czy napisany przez Ciebie program wygląda identycznie jak ten tutaj przedstawiony. Uruchom program i przetestuj jego działanie. Czy program działa zgodnie z oczekiwaniami?

Jako liczbę podawaną z klawiatury wpisz na przykład 5. U mnie dla takiej liczby pojawił się następujący wynik: Suma liczb od 0 do 5 wynosi 4009031. Zgodnie jednak z moimi obliczeniami suma liczb 0+1+2+3+4+5 powinna wynosić 15. Jeśli Ty podasz jako liczbę 5, na pewno otrzymasz inny wynik. Czy wiesz już o co może chodzić? Czemu tak wydawało by się prosty program "nie działa"?

No dobrze prześledźmy działanie programu razem. Podajemy jako liczbę z klawiatury 5. Zatem zmienna pom wynosi 5. Czy na pewno? Spójrz na efekt wypisania programu jeśli pisze tam Suma liczb od 0 do 5 tzn. że wszystko w porządku, bowiem została wypisana liczba 5. Zatem to "nie wina" zmiennej pom.

Czas zatem prześledzić pętlę. Zmienna i ma na początku wartość 0. Dodajemy ją do zmiennej suma, czyli suma ma wartość 0. Następnie zmienna i ma wartość 1, dodajemy ją do zmiennej suma, czyli suma ma wartość 1. Następnie i ma wartość 2 i dodajemy ją do zmiennej suma, czyli suma ma wartość 3. W ten sposób dochodzimy do liczby 5 i pętla się kończy. Później już tylko wypisujemy wartość zmiennej suma na ekran (nic w niej nie zmieniamy). O co zatem chodzi?

Jak to zwykle w programowaniu bywa, diabeł tkwi w szczegółach. Jeśli już teraz wiesz gdzie jest błąd w programie, to moje wielkie gratulacje. Jeśli nadal nie wiesz - no cóż, mam nadzieję, że nigdy więcej nie popełnisz podobnego błędu (swoją drogą już teraz radzę Ci wydrukować ten przykład na czerwono, dopisać za moment sensowny komentarz i powiesić tuż nad monitorem).

Prześledźmy program jeszcze raz. Przy pobieraniu wartości zmiennej jest wszystko w porządku. Przejdźmy zatem do pętli. Zmienna i ma wartość 0, a do zmiennej suma mamy dodać wartość zmiennej i. Dodajemy 0, czyli wartość zmiennej suma wynosi 0. Czy oby na pewno? No właśnie - a jaką wartość wcześniej miała zmienna suma? Patrzymy na początek programu i widzimy, że nigdzie wcześniej zmiennej suma wartości nie przypisaliśmy.

Tak się złożyło, że zmiennej suma wartości na początku programu nie przypisaliśmy (ani poprzez inicjalizację ani poprzez przypisanie) i w rezultacie wartość tej zmiennej jest zupełnie przypadkowa. Nawet w tak prostym programie, błąd nie jest tak łatwy do wychwycenia. Pomyśl zatem, jak łatwo popełnić błąd tego typu w programie, który liczy kilka czy kilkanaście tysięcy linii kodu.

Mam nadzieję, że już wiesz, co należy poprawić w programie, żeby działał zgodnie z oczekiwaniami, ale dla formalności napiszę, że zamiast linii:

  unsigned long int suma; // suma liczb

należy napisać:

  unsigned long int suma=0; // suma liczb

Jak więc widzisz, inicjalizacja jest bardzo ważną czynnością w programie i jeśli masz wątpliwości, czy jej użyć czy nie, lepiej jej użyj. Zwróć ponadto uwagę, że w przykładowym programie zmienna pętli również jest zainicjalizowana (gdybyśmy jej nie zainicjalizowali, było by to niewątpliwie kolejnym źródłem nieoczekiwanego działania programu).

Podsumowanie

W tym rozdziale przedstawiłem Ci bardzo ważne pojęcia: deklaracja, definicja i inicjalizacja. Pojęcia te mają bardzo duże znaczenie w dalszej nauce programowania dlatego radzę Ci je utrwalić.

Ponadto po tej lekcji Twojej uwadze nigdy nie powinna umknąć już inicjalizacja ważnych zmiennych, bowiem jak Cię, mam nadzieję, przekonałem, ma ona kluczowe znaczenie dla poprawnego działania programu.

powrót