Professional Documents
Culture Documents
deklaruje tablic skadajc si z dwudziestu piciu wartoci typu long, noszc nazw
LongArray. Gdy kompilator natrafi na t deklaracj, zarezerwuje miejsce do przechowania
wszystkich dwudziestu piciu elementw. Poniewa kada warto typu long wymaga czterech
bajtw pamici, ta deklaracja rezerwuje sto bajtw cigego obszaru pamici, tak jak pokazano na
rysunku 13.1.
Elementy tablicy
Do kadego z elementw tablicy moemy si odwoa, podajc przesunicie (ang. offset)
wzgldem nazwy tablicy. Elementy tablicy s liczone od zera. Tak wic pierwszym elementem
tablicy jest arrayName[0]. W przykadzie z tablic LongArray, pierwszym elementem jest
LongArray[0], drugim LongArray[1], itd.
Moe to by nieco mylce. Tablica SomeArray[3] zawiera trzy elementy. S to: SomeArray[0],
SomeArray[1] oraz SomeArray[2]. Tablica SomeArray[n] zawiera n elementw
ponumerowanych od SomeArray[0] do SomeArray[n-1].
Elementy tablicy LongArray[25] s ponumerowane od LongArray[0] do LongArray[24].
Listing 13.1 przedstawia sposb zadeklarowania tablicy piciu wartoci cakowitych i
wypenieniau jej wartociami.
Listing 13.1. Uycie tablicy wartoci cakowitych
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
Wynik
Wartosc elementu myArray[0]: 3
Wartosc
Wartosc
Wartosc
Wartosc
0: 3
1: 6
2: 9
3: 12
4: 15
elementu
elementu
elementu
elementu
myArray[1]:
myArray[2]:
myArray[3]:
myArray[4]:
6
9
12
15
Analiza
W linii 5. jest deklarowana tablica o nazwie myArray, zawierajca pi zmiennych cakowitych.
W linii 7. rozpoczyna si ptla zliczajca od 0 do 4, czyli przeznaczona dla wszystkich elementw
picioelementowej tablicy. Uytkownik jest proszony o podanie kolejnych wartoci, ktre s
umieszczane w odpowiednich miejscach tablicy.
Pierwsza warto jest umieszczana w elemencie myArray[0], druga w elemencie myArray[1] , i
tak dalej. Druga ptla, for, suy do wypisania na ekranie wartoci kolejnych elementw tablicy.
UWAGA Elementy tablic liczy si od 0, a nie od 1. Z tego powodu pocztkujcy programici
jzyka C++ czsto popeniaj bdy. Zawsze, gdy korzystasz z tablicy, pamitaj, e tablica
zawierajca 10 elementw jest liczona od ArrayName[0] do ArrayName[9]. Element
ArrayName[10] nie jest uywany.
0: //Listing 13.2
1: // Demonstruje, co si stanie, gdy zapiszesz
2: // warto za kocem tablicy
3:
4: #include <iostream>
5: using namespace std;
6:
7: int main()
8: {
9:
// wartownicy
10:
long sentinelOne[3];
11:
long TargetArray[25]; // tablica do wypenienia
12:
long sentinelTwo[3];
13:
int i;
14:
for (i=0; i<3; i++)
15:
sentinelOne[i] = sentinelTwo[i] = 0;
16:
17:
for (i=0; i<25; i++)
18:
TargetArray[i] = 0;
19:
20:
cout << "Test 1: \n"; // sprawdzamy biece wartoci
(powinny by 0)
21:
cout << "TargetArray[0]: " << TargetArray[0] << "\n";
22:
cout << "TargetArray[24]: " << TargetArray[24] << "\n\n";
23:
24:
for (i = 0; i<3; i++)
25:
{
26:
cout << "sentinelOne[" << i << "]: ";
27:
cout << sentinelOne[i] << "\n";
28:
cout << "sentinelTwo[" << i << "]: ";
29:
cout << sentinelTwo[i]<< "\n";
30:
}
31:
32:
cout << "\nPrzypisywanie...";
33:
for (i = 0; i<=25; i++)
34:
TargetArray[i] = 20;
35:
36:
cout << "\nTest 2: \n";
37:
cout << "TargetArray[0]: " << TargetArray[0] << "\n";
38:
cout << "TargetArray[24]: " << TargetArray[24] << "\n";
39:
cout << "TargetArray[25]: " << TargetArray[25] << "\n\n";
40:
for (i = 0; i<3; i++)
41:
{
42:
cout << "sentinelOne[" << i << "]: ";
43:
cout << sentinelOne[i]<< "\n";
44:
cout << "sentinelTwo[" << i << "]: ";
45:
cout << sentinelTwo[i]<< "\n";
46:
}
47:
48:
return 0;
49: }
Wynik
Test 1:
TargetArray[0]: 0
TargetArray[24]: 0
sentinelOne[0]:
sentinelTwo[0]:
sentinelOne[1]:
sentinelTwo[1]:
sentinelOne[2]:
sentinelTwo[2]:
0
0
0
0
0
0
Przypisywanie...
Test 2:
TargetArray[0]: 20
TargetArray[24]: 20
TargetArray[25]: 20
sentinelOne[0]:
sentinelTwo[0]:
sentinelOne[1]:
sentinelTwo[1]:
sentinelOne[2]:
sentinelTwo[2]:
20
0
0
0
0
0
Analiza
W liniach 10. i 12. deklarowane s dwie tablice, zawierajce po trzy zmienne cakowite, ktre
peni rol wartownikw (ang. sentinel) wok docelowej tablicy (TargetArray). Tablice
wartownikw s wypeniane zerami. Gdy dokonamy zapisu do pamici poza tablic
TargetArray, najprawdopodobniej zmodyfikujemy zawarto wartownikw. Niektre
kompilatory zliczaj pami do gry, inne w d. Z tego powodu umiecilimy wartownikw po
obu stronach tablicy.
Linie od 20. do 30. potwierdzaj wartoci wartownikw w tecie 1. W linii 34. elementy tablicy s
wypeniane wartoci 20, ale licznik zlicza a do elementu 25, ktry nie istnieje w tablicy
TargetArray.
Linie od 37. do 39. wypisuj wartoci elementw tablicy TargetArray w drugim tecie. Zwr
uwag, e element TargetArray[25] wypisuje warto 20. Jednak gdy wypisujemy wartoci
wartownikw sentinelOne i sentinelTwo, okazuje si, e warto elementu
sentinelOne[0] ulega zmianie. Stao si tak, poniewa pami pooona o 25 elementw dalej
od elementu TargetArray[0] zajmuje to samo miejsce, co element sentinelOne[0]. Gdy
odwoujemy si do nieistniejcego elementu TargetArray[0], w rzeczywistoci odwoujemy si
do elementu sentinelOne[0].
Taki bd moe by bardzo trudny do wykrycia, gdy warto elementu sentinelOne[0] zostaje
zmieniona w miejscu programu, ktre pozornie nie jest zwizane z zapisem wartoci do tej tablicy.
W tym programie uyto magicznych liczb, takich jak 3 dla rozmiarw tablic wartownikw i 25
dla rozmiaru tablicy TargetArray. Bezpieczniej jednak jest uywa staych tak, aby mona byo
zmienia te wartoci w jednym miejscu.
Pamitaj, e poniewa kompilatory rni si od siebie, otrzymany przez ciebie wynik moe by
nieco inny.
Bd supka w pocie
Zapisanie wartoci o jedn pozycj za kocem tablicy jest tak czsto popenianym bdem, e
otrzyma on nawet swoj wasn nazw. Nazywany jest bdem supka w pocie. Nazwa ta
nawizuje do problemu, jaki wiele osb ma z obliczeniem iloci supkw potrzebnych do
utrzymania dziesiciometrowego potu, z supkami rozmieszonymi co metr. Wikszo osb
odpowie, e potrzeba dziesiciu supkw, ale oczywicie potrzebnych jest ich jedenacie. Wyjania
to rysunek 13.2.
Rys. 13.2. Bd supka w pocie
Typ zliczania o jeden wicej moe by pocztkowo udrk programisty. Jednak z czasem
przywykniesz do tego, e elementy w dwudziestopicioelementowej tablicy zliczane s tylko do
elementu numer dwadziecia cztery, oraz do tego, e wszystko liczone jest poczwszy od zera.
UWAGA Niektrzy programici okrelaj element ArrayName[0] jako element zerowy. Nie
naley si na to zgadza, gdy jeli ArrayName[0] jest elementem zerowym, to czym jest
ArrayName[1]? Pierwszym? Jeli tak, to czy bdziesz pamita, gdy zobaczysz
ArrayName[24], e nie jest to element dwudziesty czwarty, ale dwudziesty pity? Lepiej jest
powiedzie, e element ArrayName[0] ma zerowy offset i jest pierwszym elementem.
Inicjalizowanie tablic
Deklarujc po raz pierwszy prost tablic wbudowanych typw, takich jak int czy char, moesz
j zainicjalizowa. Po nazwie tablicy umie znak rwnoci (=) oraz ujt w nawiasy klamrowe
list rozdzielonych przecinkami wartoci. Na przykad
int IntegerArray[5] = { 10, 20, 30, 40, 50 };
przypisuje staej IntegerArrayLength typu USHORT wynik dzielenia rozmiaru caej tablicy
przez rozmiar pojedynczego jej elementu. Wynik ten odpowiada iloci elementw w tablicy.
Nie mona inicjalizowa wicej elementw ni wynosi rozmiar tablicy. Tak wic zapis
int IntegerArray[5] = { 10, 20, 30, 40, 50, 60 };
TAK
NIE
Deklarowanie tablic
Tablica moe mie dowoln nazw, zgodn z zasadami nazywania zmiennych, ale nie moe mie
takiej samej nazwy jak zmienna lub inna tablica wewntrz danego zakresu. Dlatego nie mona
mie jednoczenie tablicy o nazwie myCats[5] oraz zmiennej myCats.
Rozmiar tablicy mona okreli, uywajc staej lub wyliczenia. Ilustruje to listing 13.3.
Listing 13.3. Uycie staej i wyliczenia jako rozmiaru tablicy
0:
1:
2:
3:
4:
// Listing 13.3
// Uycie staej i wyliczenia jako rozmiaru tablicy
#include <iostream>
int main()
5:
6:
7:
8:
9:
10:
11:
12:
{
enum WeekDays { Sun, Mon, Tue,
Wed, Thu, Fri, Sat, DaysInWeek };
int ArrayWeek[DaysInWeek] = { 10, 20, 30, 40, 50, 60, 70 };
std::cout << "Wartoscia Wtorku jest: " << ArrayWeek[Tue];
return 0;
}
Wynik
Wartoscia Wtorku jest: 30
Analiza
Linia 6. tworzy typ wyliczeniowye o nazwie WeekDays (dni tygodnia). Zawiera ono osiem
skadowych. Staej Sun (od sunday niedziela) odpowiada warto 0, za staej DaysInWeek
(dni w tygodniu) odpowiada warto 7.
W linii 10. wyliczeniowa staa Tue (od tuesday wtorek) peni rol offsetu tablicy. Poniewa
staa Tue odpowiada wartoci dwa, w linii 10. zwracany i wypisywany jest trzeci element tablicy,
ArrayWeek[2].
Tablice
Aby zadeklarowa tablic, zapisz typ przechowywanego w niej obiektu, nazw tablicy oraz jej
rozmiar, okrelajcy ilo obiektw, ktre powinny by przechowane w tej tablicy.
Przykad 1
int MyIntegerArray[90];
Przykad 2
long * ArrayOfPointersToLong[8];
Przykad 1
int theNinethInteger = MyIntegerArray[8];
Przykad 2
long * pLong = ArrayOfPointersToLongs[8];
Elementy tablic s liczone od zera. Tablica n elementw zawiera elementy liczone od zera do
n1.
Tablice obiektw
W tablicach mona przechowywa dowolne obiekty, zarwno wbudowane, jak i te zdefiniowane
przez uytkownika. Deklarujc tablic, informujesz kompilator o typie przechowywanych
obiektw oraz iloci obiektw, dla jakiej ma zosta zaalokowane miejsce. Kompilator, na
podstawie deklaracji klasy, zna ilo miejsca zajmowanego przez kady z obiektw. Klasa musi
posiada domylny konstruktor nie posiadajcy argumentw (aby obiekty mogy zosta stworzone
podczas definiowania tablicy).
Na proces dostpu do danych skadowych w tablicy obiektw skadaj si dwa kroki. Waciwy
element tablicy jest wskazywany za pomoc operatora indeksu ([]), po czym dodawany jest
operator skadowej (.), wydzielajcy okrelon zmienn skadow obiektu. Listing 13.4
demonstruje sposb tworzenia i wykorzystania tablicy piciu obiektw typu CAT.
Listing 13.4. Tworzenie tablicy obiektw
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
Wynik
Kot
Kot
Kot
Kot
Kot
nr
nr
nr
nr
nr
1:
2:
3:
4:
5:
1
3
5
7
9
Analiza
Linie od 5. do 17. deklaruj klas CAT. Klasa CAT musi posiada domylny konstruktor, aby w
tablicy mogy by tworzone jej obiekty. Pamitaj, e jeli stworzysz jakikolwiek inny konstruktor,
domylny konstruktor nie zostanie dostarczany przez kompilator; bdziesz musia stworzy go
sam.
Pierwsza ptla for (linie 23. i 24.) ustawia wiek dla kadego z piciu obiektw CAT w tablicy.
Druga ptla for (linie od 26. do 30.) odwouje si do kadego z obiektw i wywouje jego funkcj
skadow GetAge().
Metoda GetAge() kadego z poszczeglnych obiektw jest wywoywana poprzez okrelenie
elementu tablicy, Litter[i], po ktrym nastpuje operator kropki (.) oraz nazwa funkcji
skadowej.
Tablice wielowymiarowe
Tablice mog mie wicej ni jeden wymiar. Kady wymiar jest reprezentowany przez oddzielny
indeks tablicy. Na przykad, tablica dwuwymiarowa posiada dwa indeksy; tablica trjwymiarowa
posiada trzy indeksy, i tak dalej. Tablice mog mie dowoln ilo wymiarw, cho
najprawdopodobniej wikszo tworzonych przez ciebie tablic bdzie miaa tylko jeden lub dwa
wymiary.
Dobrym przykadem tablicy dwuwymiarowej jest szachownica. Jeden wymiar reprezentuje osiem
rzdw, za drugi wymiar reprezentuje osiem kolumn. Ilustruje to rysunek 13.3.
Rys. 13.3. Szachownica oraz tablica dwuwymiarowa
Przypumy e mamy klas o nazwie SQUARE (kwadrat). Deklaracja tablicy o nazwie Board
(plansza), ktra j reprezentuje, mogaby wic mie posta:
SQUARE Board[8][8];
pierwsze trzy elementy trafiaj do theArray[0], nastpne trzy do theArray[1], i tak dalej.
Tablic t moemy zainicjalizowa, piszc:
int theArray[5][3] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
Wynik
SomeArray[0][0]:
SomeArray[0][1]:
SomeArray[1][0]:
SomeArray[1][1]:
SomeArray[2][0]:
SomeArray[2][1]:
SomeArray[3][0]:
SomeArray[3][1]:
SomeArray[4][0]:
SomeArray[4][1]:
0
0
1
2
2
4
3
6
4
8
Analiza
Linia 7. deklaruje SomeArray jako tablic dwuwymiarow. Pierwszy wymiar skada si z piciu
liczb cakowitych, za drugi z dwch liczb cakowitych. Powstaje wic siatka o rozmiarach 52,
co ilustruje rysunek 13.4.
Rys. 13.4. Tablica 5 x 2
Wartoci s inicjalizowane w parach, cho rwnie dobrze mogyby zosta obliczone. Linie 8. i 9.
tworz zagniedon ptl for. Ptla zewntrzna przechodzi przez kady element pierwszego
wymiaru. Odpowiednio, dla kadego elementu w tym wymiarze, wewntrzna ptla przechodzi
przez kady element drugiego wymiaru. Jest to zgodne z wydrukiem. Po elemencie
SomeArray[0][0] nastpuje element SomeArray[0][1]. Pierwszy wymiar jest
inkrementowany tylko wtedy, gdy drugi wymiar zostanie wczeniej zwikszony o jeden. Wtedy
zaczyna si ponowne zliczanie drugiego wymiaru.
Tablice wskanikw
W przedstawianych dotd tablicach wszystkie ich elementy byy skadowane na stosie. Zwykle
pami stosu jest do ograniczona, podczas gdy pami na stercie jest duo bardziej obszerna.
Istnieje moliwo zadeklarowania wszystkich obiektw na stercie i przechowania w tablicy tylko
wskanika do kadego z obiektw. Powoduje to znaczne zmniejszenie iloci pamici stosu
zajmowanej przez tablic. Listing 13.6 zawiera zmodyfikowan wersj listingu 13.4, w ktrej
wszystkie obiekty przechowywane s na stercie. W celu podkrelenia faktu, e umoliwia ona
lepsze wykorzystanie pamici, rozmiar tablicy zosta zwikszony z piciu do piciuset elementw,
za jej nazwa zostaa zmieniona z Litter (miot) na Family (rodzina).
Listing 13.6. Tablica wskanikw do obiektw
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
Wynik
Kot
Kot
Kot
...
Kot
Kot
nr 1: 1
nr 2: 3
nr 3: 5
nr 499: 997
nr 500: 999
Analiza
Obiekt CAT zadeklarowany w liniach od 5. do 17. jest identyczny z obiektem CAT
zadeklarowanym na listingu 13.4. Tym razem jednak tablica zadeklarowana w linii 21. ma nazw
Family i zawiera 500 wskanikw do obiektw typu CAT.
W pocztkowej ptli for (linie od 24. do 29.) na stercie tworzonych jest piset nowych obiektw
typu CAT; dla kadego z nich wiek jest ustawiany jako podwojony indeks plus jeden. Tak wic
pierwszy CAT ma wiek 1, drugi ma wiek 3, trzeci ma 5, i tak dalej. Na zakoczenie, w tablicy
umieszczany jest wskanik kolejnego stworzonego obiektu.
Poniewa tablica zostaa zadeklarowana jako zawierajca wskaniki, dodawany jest do niej
wskanik a nie obiekt wyuskany zspod tego wskanika.
Druga ptla for (linie od 31. do 35.) wypisuje kad z wartoci. Dostp do wskanika uzyskuje
si przez uycie indeksu elementu, Family[i]. Otrzymany adres umoliwia dostp do metody
GetAge().
W tym przykadzie tablica Family i wszystkie zawarte w niej wskaniki s przechowywane na
stosie, ale piset stworzonych przedtem obiektw CAT znajduje si na stercie.
//
//
//
//
Deklarujemy tu now tablic piciuset obiektw typu CAT oraz wskanik wskazujcy pocztek tej
tablicy. Uywajc tego wskanika, wywoujemy funkcj SetAge() pierwszego obiektu,
przekazujc jej warto 10. Nastpnie wskanik jest inkrementowany i automatycznie wskazuje
nastpny obiekt w tablicy, po czym wywoywana jest metoda SetAge()nastpnego obiektu.
FamilyOne jest tablic piciuset obiektw typu CAT. FamilyTwo jest tablic piciuset
wskanikw do obiektw typu CAT. FamilyThree jest wskanikiem do tablicy piciuset
obiektw typu CAT.
Rnice pomidzy tymi trzema liniami kodu zasadniczo wpywaj na dziaanie tych tablic. Jeszcze
bardziej dziwi fakt, i FamilyThree jest po prostu wariantem deklaracji FamilyOne (i bardzo si
rni od FamilyTwo).
Mamy tu do czynienia ze zoonym zagadnieniem powiza tablic ze wskanikami. W trzecim
przypadku, FamilyThree jest wskanikiem do tablicy, czyli adres w zmiennej FamilyThree jest
adresem pierwszego elementu w tej tablicy, co dokadnie odpowiada przypadkowi ze zmienn
FamilyOne.
Family jest wskanikiem do &Family[0], ktre jest adresem pierwszego elementu w tablicy
Family.
Uywanie nazw tablic jako staych wskanikw (i odwrotnie) jest dozwolone. Tak wic Family +
4 jest poprawnym sposobem odwoania si do danych w elemencie Family[4].
Podczas dodawania, inkrementowania lub dekrementowania wskanikw wszystkie dziaania
arytmetyczne wykonuje kompilator. Adres, do ktrego odwoujemy si, piszc Family + 4, nie
jest adresem pooonym o cztery bajty od adresu wskazywanego przez Family, lecz adresem
pooonym o cztery obiekty dalej. Gdyby kady z obiektw zajmowa cztery bajty, wtedy Family
+ 4 odnosioby si do miejsca pooonego o szesnacie bajtw za pocztkiem tablicy. Gdyby
kady obiekt typu CAT zawiera cztery skadowe typu long, zajmujce po cztery bajty kada, oraz
dwie skadowe typu short, po dwa bajty kada, wtedy kady obiekt tego typu zajmowaby
dwadziecia bajtw, za Family + 4 odnosioby si do adresu pooonego o osiemdziesit
bajtw od pocztku tablicy.
Deklarowanie i wykorzystanie tablicy zadeklarowanej na stercie ilustruje listing 13.7.
Wynik
Kot
Kot
Kot
...
Kot
Kot
nr 1: 1
nr 2: 3
nr 3: 5
nr 499: 997
nr 500: 999
Analiza
Linia 25. deklaruje tablic Family zawierajc piset obiektw typu CAT. Caa tablica jest
tworzona na stercie, za pomoc wywoania new CAT[500].
NIE
Tablice znakw
acuch w jzyku C jest tablic znakw, zakoczon znakiem null. Jedyne acuchy w stylu C, z
jakimi mielimy dotd do czynienia, to nienazwane stae acuchowe, uywane w instrukcjach
cout, takie jak:
cout << "hello world.\n";
acuchy w stylu C moesz deklarowa i inicjalizowa tak samo, jak wszystkie inne tablice. Na
przykad:
char Greeting[] =
{ 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0' };
Ostatni znak, '\0', jest znakiem null, ktry jest rozpoznawany przez wiele funkcji C++ jako znak
koczcy acuch w stylu C. Cho inicjalizowanie znak po znaku przynosi efekty, jest jednak
do mudne i daje wiele okazji do bdw. C++ pozwala wic na uywanie dla poprzedniej
deklaracji formy skrtowej:
char Greeting[] = "Hello World";
acuch Hello World, przechowywany w stylu C, ma dwanacie znakw. Sowo Hello zajmuje
pi bajtw, spacja jeden bajt, sowo World pi bajtw, za koczcy znak null zajmuje jeden
bajt.
Moesz take tworzy nie zainicjalizowane tablice znakw. Tak jak w przypadku wszystkich
tablic, naley upewni si, czy w buforze nie zostanie umieszczone wicej znakw, ni jest
miejsca.
Listing 13.8 demonstruje uycie nie zainicjalizowanego bufora.
Listing 13.8. Wypenianie tablicy
0: //Listing 13.8 bufory znakowe
1:
2: #include <iostream>
3:
4: int main()
5: {
6:
char buffer[80];
7:
std::cout << "Wpisz lancuch: ";
8:
std::cin >> buffer;
9:
std::cout << "Oto zawartosc bufora:
std::endl;
10:
return 0;
11: }
Wynik
Wpisz lancuch: Hello World
Oto zawartosc bufora: Hello
Analiza
W linii 6. deklarowany jest bufor, mogcy pomieci osiemdziesit znakw. Wystarcza to do
przechowania 79znakowego acucha w stylu C oraz koczcego znaku null.
W linii 7. uytkownik jest proszony o wpisanie acucha w stylu C, ktry jestw linii 8. jest
wprowadzany do bufora. Obiekt cin automatycznie dopisuje do acucha w buforze znak
koczcy null.
W przypadku programu z listingu 13.8 pojawiaj si dwa problemy. Po pierwsze, jeli uytkownik
wpisze wicej ni 79 znakw, cin dokona zapisu poza kocem bufora. Po drugie, gdy uytkownik
wpisze spacj, cin potraktuje j jako koniec acucha i przestanie zapisywa reszt znakw do
bufora.
Aby rozwiza te problemy, musisz wywoa specjaln metod obiektu cin: metod get().
Metoda cin.get() posiada trzy parametry:
bufor do wypenienia,
Domylnym znakiem koczcym jest znak nowej linii. Uycie tej metody ilustruje listing 13.9.
Listing 13.9. Wypenianie tablicy
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
znaku
10:
11:
12:
Wynik
Wpisz lancuch: Hello World
Oto zawartosc bufora: Hello World
Analiza
Linia 9. wywouje metod get() obiektu cin. Bufor zadeklarowany w linii 7. jest przekazywany
jako jej pierwszy argument. Drugim argumentem jest maksymalna ilo znakw do pobrania, w
tym przypadku musi ni by 79 (tak, aby bufor mg pomieci take koczcy znak null). Nie ma
potrzeby podawania take dodawania znaku koczcego wpis, gdy robi to warto
wystarczydomylna ejdla przejcia do nowej linii.
Wynik
String1: Zaden czlowiek nie jest samoistna wyspa
String2: Zaden czlowiek nie jest samoistna wyspa
Analiza
W linii 3. jest doczany plik nagwkowy string.h. Ten plik zawiera prototyp funkcji strcpy().
Funkcja otrzymuje dwie tablice znakw docelow oraz rdow. Gdyby tablica rdowa bya
wiksza ni tablica docelowa, funkcja strcpy() dokonaaby zapisu poza koniec bufora.
Aby nas przed tym zabezpieczy, biblioteka standardowa zawiera take funkcj strncpy(). Ta
wersja funkcji posiada dodatkowy argument, okrelajcy maksymaln ilo znakw do
skopiowania. Funkcja strncpy() kopiuje znaki, a do napotkania pierwszego znaku null albo do
osignicia dozwolonej maksymalnej iloci znakw.
Listing 13.11 ilustruje uycie funkcji strncpy().
Listing 13.11. Uycie funkcji strncpy()
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
Wynik
String1: Zaden czlowiek nie jest samoistna wyspa
String2: Zaden czlowiek nie jest samoistna wyspa
Analiza
W linii 12. wywoanie funkcji strcpy() zostao zmienione na wywoanie funkcji strncpy().
Funkcja ta posiada take trzeci parametr, okrelajcy maksymaln ilo znakw do skopiowania.
Bufor String2 ma dugo MaxLength+1 (maksymalna dugo + 1) znakw. Dodatkowy znak
jest przeznaczony do przechowania znaku null, ktry jest automatycznie umieszczany na kocu
acucha zarwno przez funkcj strcpy(), jak i strncpy().
Klasy acuchw
C++ przejo z jzyka C zakoczone znakiem null acuchy oraz bibliotek funkcji, zawierajc
take funkcj strcpy(), ale funkcje tej biblioteki nie s zintegrowane z bibliotekami
zorientowanymi obiektowo. Biblioteka standardowa zawiera klas String, obejmujc zestaw
danych i funkcji przeznaczonych do manipulowania acuchami, oraz zestaw akcesorw, dziki
ktrym same dane s ukryte przed klientami tej klasy.
W ramach wiczenia potwierdzajcego waciwe zrozumienie omawianych zagadnie,
sprbujemy teraz stworzy wasn klas String. Nasza klasa String powinna likwidowa
podstawowe ograniczenia tablic znakw. Podobnie jak wszystkie tablice, tablice znakw s
statyczne. Sami definiujemy, jaki maj rozmiar. Tablice te zawsze zajmuj okrelon ilo pamici,
bez wzgldu na to, czy jest to naprawd potrzebne. Z kolei dokonanie zapisu za kocem tablicy
moe mie katastrofalne skutki.
UWAGA Przedstawiona tu klasa String jest bardzo ograniczona i w adnym przypadku nie
moe by uwaana za nadajc si do powanych zastosowa. Wystarczy jednak na potrzeby
naszego wiczenia, gdy biblioteka standardowa zawiera pen i stabiln klas String.
Dobra klasa String alokuje tylko tyle pamici, ile potrzebuje (aby zawsze wystarczao na
przechowanie tego, co powinna zawiera). Jeli nie moe zaalokowa wystarczajcej iloci
pamici, powinna poprawnie to zgosi.
Pierwsz prb utworzenia naszej klasy String przedstawia listing 13.12.
Listing 13.12. Uycie klasy String
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
class String
{
public:
// konstruktory
String();
String(const char *const);
String(const String &);
~String();
// przecione operatory
char & operator[](unsigned short offset);
char operator[](unsigned short offset) const;
String operator+(const String&);
void operator+=(const String&);
String & operator= (const String &);
// oglne akcesory
unsigned short GetLen()const { return itsLen; }
const char * GetString() const { return itsString; }
private:
String (unsigned short);
char * itsString;
unsigned short itsLen;
};
// prywatny konstruktor
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
itsString[i] = rhs[i];
itsString[itsLen] = '\0';
}
// destruktor, zwalnia zaalokowan pami
String::~String ()
{
delete [] itsString;
itsLen = 0;
}
// operator rwnoci, zwalnia istniejc pami,
// po czym kopiuje acuch i rozmiar
String& String::operator=(const String & rhs)
{
if (this == &rhs)
return *this;
delete [] itsString;
itsLen=rhs.GetLen();
itsString = new char[itsLen+1];
for (unsigned short i = 0; i<itsLen;i++)
itsString[i] = rhs[i];
itsString[itsLen] = '\0';
return *this;
}
// nie stay operator indeksu, zwraca
// referencj do znaku, dziki czemu moe on
// by zmieniony!
char & String::operator[](unsigned short offset)
{
if (offset > itsLen)
return itsString[itsLen-1];
else
return itsString[offset];
}
// stay operator offsetu doindeksu dla uycia dla
// staych obiektw (patrz konstruktor kopiujcyi!)
char String::operator[](unsigned short offset) const
{
if (offset > itsLen)
return itsString[itsLen-1];
else
return itsString[offset];
}
// tworzy nowy acuch przez dodanie biecego
// acucha do rhs
String String::operator+(const String& rhs)
{
unsigned short totalLen = itsLen + rhs.GetLen();
String temp(totalLen);
unsigned short i;
for ( i= 0; i<itsLen; i++)
temp[i] = itsString[i];
for (unsigned short j = 0; j<rhs.GetLen(); j++, i++)
temp[i] = rhs[j];
temp[totalLen]='\0';
return temp;
}
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
Wynik
S1:
poczatkowy test
S1:
Hello World
tempTwo:
; milo tu byc!
S1:
Hello World; milo tu byc!
S1[4]: o
S1:
Hellx World; milo tu byc!
S1[999]:
!
S3:
Hellx World; milo tu byc! Inny lancuch
S4:
Dlaczego to dziala?
Analiza
Linie od 7. do 31. zawieraj deklaracj prostej klasy String. Linie od 11. do 13. zawieraj trzy
konstruktory: konstruktor domylny, konstruktor kopiujcyi oraz konstruktor otrzymujcy
istniejcy acuch, zakoczony znakiem null (w stylu C).
Klasa String przecia operator indeksu ([]), operator plus (+) oraz operator plus-rwna si
(+=). Operator indeksu jest przeciony dwukrotnie: raz jako funkcja const zwracajca znak;
drugi raz jako funkcja nie const zwracajca referencj do znaku. Wersja nie const jest uywana
w wyraeniach takich, jak:
SomeString[4] = 'x';
tak, jak wida zielimyw linii 161. Dziki temu mamy bezporedni dostp do kadego znaku w
acuchu. Zwracana jest referencja do znaku, dziki czemu funkcja wywoujca moe nim
manipulowa.
Wersja const jest uywana w przypadkach, gdy nastpuje odwoanie do staego obiektu typu
String, na przykad w implementacji konstruktora kopiujcegoi (linia 63.). Zauwa, e nastpuje
odwoanie do rhs[i],; jednake cho rhs jest zadeklarowane jako const String &. Dostp do
tego obiektu za pomoc funkcji skadowej, nie bdcej funkcj const, jest zabroniony. Dlatego
operator indeksu musi by przeciony za pomoc akcesora const.
Jeli zwracane obiekty byyby bardzo due, mgby zechcie zadeklarowa zwracan warto
jako referencj const. Jednak poniewa znak zajmuje tylko jeden bajt, nie ma takiej potrzeby.
Domylny konstruktor jest zaimplementowany w liniach od 33. do 39. Tworzy on acuch, ktrego
dugo wynosi zero znakw. Zgodnie z konwencj, klasa String zwraca dugo acucha bez
kocowego znaku null. Tworzony acuch domylny zawiera wic jedynie kocowy znak null.
Konstruktor kopiujcyi zosta zaimplementowany w liniach od 63. do 70. Ustawia on dugo
nowego acucha zgodnie z dugoci acucha istniejcego, plus jeden bajt dla kocowego znaku
null. Kopiuje kady znak z istniejcego acucha do nowego acucha, po czym koczy nowy
acuch znakiem null.
W liniach od 53. do 60. znajduje si implementacja konstruktora otrzymujcego istniejcy acuch
w stylu C. Ten konstruktor jest podobny do konstruktora kopiujcegoi. Dugo istniejcego
acucha wyznaczana jest w wyniku wywoania standardowej funkcji bibliotecznej strlen().
W linii 28. zosta zadeklarowany jeszcze jeden konstruktor, String(unsigned short),
stanowicy prywatn funkcj skadow. Odpowiada on zamierzeniom projektanta, zgodnie z
ktrymi, aden z klientw klasy nigdy nie powinien tworzy acuchw typu String o okrelonej
dugoci. Ten konstruktor istnieje tylko po to, by pomc przy wewntrznym tworzeniu
egzemplarzy acuchw, na przykad w funkcji operator+= w linii 130. Opiszemy to dokadniej
przy okazji omawiania dziaania funkcji operator+=.
Konstruktor String(unsigned short) wypenia kady element swojej tablicy wartoci NULL.
Dlatego w ptli dokonujemy sprawdzenia i <= len, a nie i < len.
zwracana jest referencja. Operator indeksu jest przeciany dwukrotnie. W obu przypadkach
przeprowadzane jest podstawowe sprawdzanie zakresw. Jeli uytkownik prbuje odwoa si do
znaku pooonego poza kocem tablicy, zwracany jest ostatni znak znak (znajdujcy si na pozycji
len-1).
Linie od 117. do 127. implementuj operator plus (+) jako operator konkatenacji (czenia
acuchw). Dziki temu moemy napisa:
String3 = String1 + String2;
przypisujc acuchowi String3 poczenie dwch pozostaych acuchw. W tym celu funkcja
operatora plus oblicza poczon dugo obu acuchw i tworzy tymczasowy acuch temp. To
powoduje wywoanie prywatnego konstruktora, ktry otrzymuje warto cakowit i tworzy
acuch wypeniony znakami null. Nastpnie znaki null s zastpowane przez zawarto obu
acuchw. acuch po lewej stronie (*this) jest kopiowany jako pierwszy; acuch po prawej
stronie (rhs) kopiowany jest pniej.
Pierwsza ptla for przechodzi przez acuch po lewej stronie i przenosi kady jego znak do
nowego acucha. Druga ptla for przetwarza acuch po prawej stronie. Zauwa, e zmienna i
cay czas wskazuje miejsce w acuchu docelowym, nawet wtedy, gdy zmienna j zlicza znaki
acucha rhs.
Operator plus zwraca acuch tymczasowy poprzez warto, ktra jest przypisywana acuchowi
po lewej stronie przypisania (string1). Operator += dziaa na istniejcym acuchu tj. na
acuchu po lewej stronie instrukcji string1 += string2. Dziaa on tak samo, jak operator
plus, z tym, e warto tymczasowa jest przypisywana do biecego acucha (*this = temp w
linii 142.).
Funkcja main() (w liniach od 145. do 175.) suy jako program testujcy t klas. Linia 147.
tworzy obiekt String za pomoc konstruktora, otrzymujcego acuch w stylu C zakoczony
znakiem null. Linia 148. wypisuje jego zawarto za pomoc funkcji akcesora GetString().
Linia 150. tworzy kolejny acuch w stylu C. Linia 151. sprawdza operator przypisania, za linia
152. wypisuje wyniki.
Linia 154. tworzy trzeci acuch w stylu C, tempTwo. Linia 155. wywouje funkcj strcpy() (w
celu wypenienia bufora znakami ; milo tu byc!). Linia 156. wywouje operator += i docza
tempTwo do istniejcego acucha s1. Linia 158. wypisuje wyniki.
W linii 160. odczytywany jest i wypisywany pity znak acucha s1. W linii 161. jest mu
przypisywana nowa warto. Powoduje to wywoanie operatora indeksu (operatora []; w wersji
nie const). Linia 162. wypisuje wynik, ktry pokazuje, e warto znaku rzeczywicie ulega
zmianie.
Linia 164. prbuje odwoa si do znaku za kocem tablicy. Ostatni znak w tablicy jest zwracany,
zgodnie z projektem klasy.
Linie 166. i 167. tworz kolejne dwa obiekty String, za linia 168. wywouje operator
dodawania. Wynik jest wypisywany w linii 169.
Linia 171. tworzy nowy obiekt String o nazwie s4. Linia 172. wywouje operator przypisania.
Linia 173. wypisuje wyniki. By moe zastanawiasz si: Skoro operator przypisania jest
zdefiniowany w linii 21. jako otrzymujcy sta referencj do obiektu String, ale to dlaczego w
tym miejscu program przekazuje acuch w stylu C. Jak to moliwe?
A oto odpowied na to pytanie: kompilator oczekuje obiektu String, lecz otrzymuje tablic
znakw. W zwizku z tym sprawdza, czy moe stworzy obiekt String z tego, co otrzyma. W
linii 12. zadeklarowalimy konstruktor, ktry tworzy obiekt String z tablicy znakw. Kompilator
tworzy tymczasowy obiekt String z tablicy znakw i przekazuje go do operatora przypisania.
Proces ten nazywa si rzutowaniem niejawnym lub promocj. Gdyby nie zosta zadeklarowany i
zaimplementowany konstruktor przyjmujcy tablic znakw, to takie przypisanie spowodowaoby
bd kompilacji.
drzewo.
W licie poczonej pojedynczo kady wze wskazuje na wze nastpny (nie wskazuje
poprzedniego). Aby odszuka okrelony wze, musimy zacz od pocztku listy, tak jak w
zabawie w poszukiwanie skarbw (Nastpny wze jest pod fotelem). Lista poczona
podwjnie umoliwia poruszenie si wzdu acucha wzw do przodu i do tyu. Drzewo jest
zoon struktur zbudowan z wzw. Kady wze moe wskazywa w dwch lub wicej
kierunkach. Te trzy podstawowe struktury przedstawia rysunek 13.5.
Rys. 13.5. Listy poczone
Przeniesienie odpowiedzialnoci
Podstawowym celem programowania zorientowanego obiektowo jest to, by kady obiekt
wykonywa dobrze jedn rzecz, za wszystkie inne czynnoci przekazywa innym obiektom.
Doskonaym przykadem zastosowania tej idei w praktyce jest samochd: zadaniem silnika jest
dostarczanie siy. Jej dystrybucja nie jest ju zadaniem silnika, ale ukadu napdowego. Skrcanie
nie jest zadaniem ani silnika, ani ukadu napdowego, tylko k.
Dobrze zaprojektowana maszyna skada si z mnstwa maych, dobrze okrelonychprzemylanych
czci, z ktrych kada wykonuje swoje zadanie i wsppracuje z innymi czciami w celu
osignicia wsplnego celu. Dobrze zaprojektowany program dziaa bardzo podobnie: kada klasa
wykonuje swoje niewielkie operacje, ale w poczeniu z innymi moe wykona naprawd
skomplikowane zadanie.
Czci skadowe
Lista poczona skada si z wzw. Pojcie klasy wza bdzie abstrakcyjne; do wykonania
zadania uyjemy trzech podtypw. Lista Bbdzie teo zawieraa wze gowyczoowy, ktrego
zadaniem bdzie zarzdzanie gow listy, wze ogona (domyl si, do czego posuy!) oraz zero
lub wicej wzw wewntrznych. Wzy wewntrzne bd odpowiedzialne za dane
przechowywane wewntrz listy.
Zauwa, e dane i lista s od siebie zupenie niezalene. Teoretycznie, moesz przechowywa w
licie dane dowolnego rodzaju, poniewa to nie dane s ze sob poczone, ale wzy, ktre je
przechowuj.
Program sterujcy nie wie niczego o wzach, poniewa operuje na licie. Jednak sama lista
wykonuje niewiele pracy, delegujc wikszo zada na wzy.
Kod programu przedstawia listing 13.13; za moment omwimy jego szczegy.
Listing 13.13. Lista poczona
0:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
// ***********************************************
//
PLIK:
Listing 13.13
//
//
PRZEZNACZENIE: Demonstruje list poczon
//
UWAGI:
//
// COPYRIGHT: Copyright (C) 1998 Liberty Associates, Inc.
//
All Rights Reserved
//
// Demonstruje obiektowo zorientowane podejcie do list
// poczonych. Lista deleguje prac na wzy.
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
public:
TailNode(){}
~TailNode(){}
virtual Node * Insert(Data * theData);
virtual void Show() { }
private:
};
// Gdy dane trafiaj do mnie, musz by wstawione wczeniej,
// gdy jestem ogonem i za mn NIC nie ma.
Node * TailNode::Insert(Data * theData)
{
InternalNode * dataNode = new InternalNode(theData, this);
return dataNode;
}
// Wze gowy nie zawiera danych; wskazuje jedynie
// na sam pocztek listy.
class HeadNode : public Node
{
public:
HeadNode();
~HeadNode() { delete myNext; }
virtual Node * Insert(Data * theData);
virtual void Show() { myNext->Show(); }
private:
Node * myNext;
};
// Gdy tylko gowa zostanie stworzona,
// natychmiast tworzy ogon.
HeadNode::HeadNode()
{
myNext = new TailNode;
}
// Przed gow nic nie wstawiamy nic, zatem
// po prostu przekazujemy dane do nastpnego wza.
Node * HeadNode::Insert(Data * theData)
{
myNext = myNext->Insert(theData);
return this;
}
// Odbieram sowa uznania, a sama nic nie robi.
class LinkedList
{
public:
LinkedList();
~LinkedList() { delete myHead; }
void Insert(Data * theData);
void ShowAll() { myHead->Show(); }
private:
HeadNode * myHead;
};
// Przy narodzinach tworz wze gowy.
// Tworzy on wze ogona.
// Tak wic pusta lista wskazuje na gow, ktra
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
Jaka
Jaka
Jaka
Jaka
Jaka
Jaka
Jaka
2
3
5
8
9
10
wartosc?
wartosc?
wartosc?
wartosc?
wartosc?
wartosc?
wartosc?
Wynik
(0
(0
(0
(0
(0
(0
(0
aby
aby
aby
aby
aby
aby
aby
zakonczyc):
zakonczyc):
zakonczyc):
zakonczyc):
zakonczyc):
zakonczyc):
zakonczyc):
5
8
3
9
2
10
0
Analiza
Pierwsz rzecz, jak naley zauway, jest instrukcja wyliczeniowae definiujca zawierajce trzy
stae: kIsSmaller (jest mniejsze), kIsLarger (jest wiksze) oraz kIsSame (jest takie same).
Kady obiekt, ktry moe by przechowywany na tej licie poczonej, musi obsugiwa metod
Compare(). Te stae s zwracane wanie przez t metod.
Dla przykadu, w liniach od 30. do 39. zostaa stworzona klasa Data (dane), za jej metoda
Compare() zostaa zaimplementowana w liniach od 41. do 51. Obiekt typu Data przechowuje
warto i moe porwnywa si z innymi obiektami Data. Oprcz tego obsuguje metod
Show(), ktra wywietla warto obiektu Data.
Najprostszym sposobem na zrozumienie dziaania listy poczonej jest przeanalizowanie
ilustrujcego j przykadu. W linii 203. rozpoczyna si testowy program sterujcy; w linii 206.
deklarowany jest wskanik do obiektu Data, za w linii 208. definiowana jest lokalna lista
poczona.
Gdy tworzona jest lista poczona, wywoywany jest jej konstruktor, zaczynajcy si w linii 192.
Jedyn prac wykonywan w tym konstruktorze jest zaalokowanie obiektu HeadNode (wze
gowy) i przypisanie mujego adresu do wskanika przechowywanego w poczonej licie w linii
185.
Tworzenie obiektu HeadNode powoduje wywoanie konstruktora klasy HeadNode zawartego w
liniach od 163. do 166. To z kolei powoduje zaalokowanie obiektu TailNode (wze gowy) i
przypisanie jego adresu do wskanika myNext (mj nastpny) w wle gowy. Tworzenie obiektu
TailNode powoduje wywoanie konstruktora tej klasy zdefiniowanego w linii 131., ktry jest
funkcj inline i nie robi nic.
Dziki zwykemu zaalokowaniu listy poczonej na stosie, tworzona jest sama lista, wzy gowy i
ogona oraz ustanawiane s powizania pomidzy nimi. Ilustruje to rysunek 13.6.
Rys. 13.6. Lista poczona po jej utworzeniu
Linia 212. rozpoczyna ptl nieskoczon. Uytkownik jest proszony o wpisanie wartoci
dodawanych do listy poczonej. Moe on doda dowoln ilo wartoci tyle wartoci, ile chce;
wpisanie wartoci 0 powoduje zakoczenie pobierania danych. Kod w linii 216. sprawdza
wprowadzan warto; po natrafianiu na warto 0 powoduje on wyjcie z ptli.
Jeli warto jest rna od zera, w linii 218. tworzony jest nowy obiekt typu Data, ktry w linii
219. jest wstawiany do listy. Dla zilustrowania tego przykadu zamy, e uytkownik
wprowadzi warto 15. Powoduje to wywoanie metody Insert() (wstaw) w linii 198.
Lista poczona (klasa LinkedList) natychmiast przenosi odpowiedzialno za wstawienie
obiektu na swj wze gowy. To wywouje metod Insert() z linii 170. Z kolei Wwze gowy
natychmiast przekazuje odpowiedzialno za wstawienie obiektu do wza wskazywanego przez
skadow myNext (mj nastpny). W tym (pierwszym) przypadku, skadowa ta, wskazuje ona na
wze ogona (pamitajmy, e podczas tworzenia wza gowy zostao stworzone cze do wza
ogona). Tak wic zostaje wywoana metoda Insert() z linii 142.
Po wstawieniu pierwszego wza, sterowanie programu powraca do linii 214., gdzie wprowadzane
s kolejne dane. Dla przykadu zamy, e uytkownik wpisa warto 3. Powoduje to stworzenie
w linii 218. nowego obiektu typu Data, ktry jest wstawiany do listy w linii 219.
W linii 200. lista ponownie przekazuje dane do swojego wza gowy. Z kolei metoda
HeadNode::Insert() przekazuje now warto do wza wskazywanego przez swj wskanik
myNext. Jak wiemy, w tym momencie wskanik ten wskazuje wze zawierajcy obiekt Data o
wartoci 15. Powoduje to wywoanie metody InternalNode::Insert() z linii 99.
W linii 103. obiekt InternalNode uywa wskanika myData, aby dla wasnego obiektu Data
(tego o wartoci 15) wywoa za pomoc otrzymanego nowego obiektu Data (tego o wartoci 3)
metod Compare(). To powoduje wywoanie metody InternalNode::Compare()
zdefiniowanej w linii 43.
Obie wartoci zostaj porwnane, a poniewa myValue ma warto 15, za
theOtherData.myValue ma warto 3, zwrcon wartoci jest kIsLarger. To powoduje, e
program przechodzi do linii 112.
Dla nowego obiektu Data tworzony jest nowy wze InternalNode. Nowy wze bdzie
wskazywa na biecy obiekt InternalNode, a metoda InternalNode::Insert() zwrci do
obiektu HeadNode adres nowego wza. Zatem nowy wze, ktrego warto obiektu danych jest
mniejsza od wartoci obiektu danych wza biecego, zostanie wstawiony do listy przed wzem
biecym. Caa lista wyglda w tym momencie tak, jak na rysunku 13.8.
Rys. 13.8. Lista poczona po wstawieniu drugiego wza
W trakcie trzeciego wykonania ptli uytkownik wpisa warto 8. Jest ona wiksza od 3, ale
mniejsza od 15, wic powinna by wstawiona pomidzy dwa istniejce ju wzy. Dziaanie
programu bdzie podobne do przedstawionego w poprzednim przykadzie, z t rnic, e gdy
dojdzie do porwnania wartoci danych z wartoci 3, zamiast zwrci sta kIsLarger, funkcja
zwrci warto kIsSmaller (co oznacza, e obiekt o wartoci 3 jest mniejszy od nowego
obiektu, ktrego warto wynosi 8).
Klasy tablic
Napisanie wasnej klasy tablicowejy ma wiele zalet w porwnaniem z korzystaniem z tablic
wbudowanych. Jako pocztkujcy programista, moesz zabezpieczy program przed
przepenieniem tablicy. Moesz take wzi pod uwag stworzenie wasnej klasy tablicowej,y
dynamicznie zmieniajcej rozmiar: tu po utworzeniu mogaby ona zawiera tylko jeden element i
zwiksza rozmiar w miar potrzeb, podczas dziaania programu.
W przypadku, gdy zechcesz posortowa lub uporzdkowa elementy tablicy w jaki inny sposb,
moesz wykorzysta kilka rnych przydatnych odmian tablic. Do najpopularniejszych z nich
nale:
rzadka tablica (sparse array): umoliwia uywanie bardzo szerokiego zakresu indeksw, ale
pami zajmuj tylko te elementy, ktre rzeczywicie zostay dodane do tablicy. Moesz
poprosi o element SparseArray[5] lub SparseArray[200], a mimo to pami zostanie
zaalokowana tylko dla niewielkiej iloci elementw,
Przeciajc operator indeksu ([]), moesz zamieni list poczon w zbir uporzdkowany.
Odrzucajc duplikaty, moesz zamieni zbir w zestaw. Jeli kady obiekt na licie posiada par
dopasowanych wartoci, moesz uy listy poczonej do zbudowania sownika lub rzadkiej
tablicy.