Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00694 010506 11034318 na godz. na dobę w sumie
C++. Potęga języka. Od przykładu do przykładu - książka
C++. Potęga języka. Od przykładu do przykładu - książka
Autor: , Liczba stron: 432
Wydawca: Helion Język publikacji: polski
ISBN: 83-7361-374-9 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c++ - programowanie
Porównaj ceny (książka, ebook, audiobook).

Nie ucz się C++ -- naucz się programować w C++

Książka ta ma pomóc Czytelnikowi w szybkim nauczeniu się języka C++ poprzez pisanie w nim przydatnych programów. Ta strategia wydaje się oczywista, jednak jest odmienna od powszechnie przyjętej metodologii nauczania. Autorzy nie będą uczyć Cię języka C, choć wielu uważa, że jest to niezbędne. W prezentowanych przykładach od razu wykorzystane zostaną wysokopoziomowe struktury, a prezentacja sposobu ich zastosowania będzie często wyprzedzać omówienie ich fundamentów. Dzięki takiemu podejściu zaczniesz szybko pisać programy wykorzystujące idiomy C++.

Zastosowany w książce schemat autorzy wypróbowali podczas kursów prowadzonych na Uniwersytecie Stanforda, na których studenci uczą się pisać programy już na pierwszych zajęciach.

Poznaj:

O autorach:
Andrew Koenig jest członkiem działu badającego systemy oprogramowania w Shannon Laboratory firmy AT&T oraz redaktorem projektu komitetów standaryzacyjnych języka C++. [więcej...\

Barbara Moo jest konsultantką z dwudziestoletnim doświadczeniem programistycznym, zarządzała projektem pierwszego kompilatora C++. [więcej...\

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

IDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ SPIS TREĎCI SPIS TREĎCI KATALOG KSI¥¯EK KATALOG KSI¥¯EK KATALOG ONLINE KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK TWÓJ KOSZYK DODAJ DO KOSZYKA DODAJ DO KOSZYKA CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWOĎCIACH O NOWOĎCIACH ZAMÓW CENNIK ZAMÓW CENNIK CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: helion@helion.pl C++. Potêga jêzyka. Od przyk³adu do przyk³adu Autorzy: Andrew Koenig, Barbara E. Moo T³umaczenie: Przemys³aw Szeremiota ISBN: 83-7361-374-9 Tytu³ orygina³u: Accelerated C++. Practical Programming by Example Format: B5, stron: 422 Przyk³ady na ftp: 122 kB Ksi¹¿ka ta ma pomóc Czytelnikowi w szybkim nauczeniu siê jêzyka C++ poprzez pisanie w nim przydatnych programów. Ta strategia wydaje siê oczywista, jednak jest odmienna od powszechnie przyjêtej metodologii nauczania. Autorzy nie bêd¹ uczyæ Ciê jêzyka C, choæ wielu uwa¿a, ¿e jest to niezbêdne. W prezentowanych przyk³adach od razu wykorzystane zostan¹ wysokopoziomowe struktury, a prezentacja sposobu ich zastosowania bêdzie czêsto wyprzedzaæ omówienie ich fundamentów. Dziêki takiemu podejġciu zaczniesz szybko pisaæ programy wykorzystuj¹ce idiomy C++. Zastosowany w ksi¹¿ce schemat autorzy wypróbowali podczas kursów prowadzonych na Uniwersytecie Stanforda, na których studenci ucz¹ siê pisaæ programy ju¿ na pierwszych zajêciach. Poznaj: • Podstawowe cechy C++ • Operacje na ci¹gach • Pêtle i liczniki • Przetwarzanie danych „porcja po porcji” • Organizacjê programów i danych • Kontenery sekwencyjne i analiza ci¹gów tekstowych • Algorytmy biblioteki standardowej • Kontenery asocjacyjne • Funkcje uogólnione i definiowanie w³asnych typów • Zarz¹dzanie pamiêci¹ i niskopoziomowymi strukturami danych • Pó³automatyczne zarz¹dzanie pamiêci¹ • Programowanie zorientowane obiektowo Andrew Koenig jest cz³onkiem dzia³u badaj¹cego systemy oprogramowania w Shannon Laboratory firmy AT T oraz redaktorem projektu komitetów standaryzacyjnych jêzyka C++. Jako programista z trzydziestoletnim sta¿em (piêtnaġcie lat poġwiêconych C++) opublikowa³ ponad 150 artyku³ów i wyg³osi³ mnóstwo odczytów o tym jêzyku. Barbara E. Moo jest konsultantk¹ z dwudziestoletnim doġwiadczeniem programistycznym. Pracuj¹c przez 15 lat dla AT T wspó³tworzy³a jeden z pierwszych komercyjnych produktów tworzonych w jêzyku C++, zarz¹dza³a projektem pierwszego kompilatora C++ firmy AT T i kierowa³a rozwojem uznanego systemu AT T WorldNet Internet Service. Jest wspó³autork¹ ksi¹¿ki „Ruminations on C++”. Wyk³ada na ca³ym ġwiecie. Spis treści Przedmowa......................................................................................... 9 Wstęp .............................................................................................. 15 Zaczynamy ...................................................5...................................................5..................15 W.1. Komentarze...................................................5...................................................5.........16 W.2. Dyrektywa #include...................................................5...............................................16 W.3. Funkcja main ...................................................5...................................................5......16 W.4. Nawiasy klamrowe ...................................................5................................................17 W.5. Wykorzystanie biblioteki standardowej do realizacji operacji wyjścia ...................17 W.6. Instrukcja return...................................................5...................................................5..18 W.7. Nieco głębsza analiza ...................................................5............................................19 W.8. Podsumowanie...................................................5...................................................5....21 Rozdział 1. Operacje na ciągach ......................................................................... 25 1.1. Wejście programu ...................................................5...................................................525 1.2. Ozdabianie powitania...................................................5..............................................28 1.3. Podsumowanie ...................................................5...................................................5.....32 Rozdział 2. Pętle i liczniki................................................................................... 37 2.1. Zadanie ...................................................5...................................................5.................37 2.2. Ogólna struktura programu ...................................................5.....................................38 2.3. Wypisywanie nieznanej z góry liczby wierszy ...................................................5.......38 2.4. Wypisywanie wierszy ...................................................5.............................................43 2.5. Połączenie fragmentów programu...................................................5...........................48 2.6. Zliczanie ...................................................5...................................................5...............52 2.7. Podsumowanie ...................................................5...................................................5.....54 Rozdział 3. Przetwarzanie porcji danych ............................................................... 61 3.1. Obliczanie średniej ocen z egzaminów ...................................................5...................61 3.2. Mediana zamiast średniej ...................................................5........................................68 3.3. Podsumowanie ...................................................5...................................................5.....77 Rozdział 4. Organizacja programów i danych ....................................................... 81 4.1. Organizacja przetwarzania ...................................................5......................................82 4.2. Organizacja danych ...................................................5.................................................93 4.3. Połączenie fragmentów programu...................................................5...........................98 4.4. Podział programu wyznaczającego oceny semestralne............................................101 4.5. Ostateczna wersja programu ...................................................5.................................103 4.6. Podsumowanie ...................................................5...................................................5...105 6 C++. Potęga języka. Od przykładu do przykładu Rozdział 5. Kontenery sekwencyjne i analiza ciągów tekstowych ....................... 109 5.1. Dzielenie studentów na grupy ...................................................5...............................109 5.2. Iteratory ...................................................5...................................................5..............114 5.3. Wykorzystanie iteratorów w miejsce indeksów...................................................5....118 5.4. Ulepszanie struktury danych pod kątem większej wydajności ................................120 5.5. Kontener typu list ...................................................5..................................................121 5.6. Wracamy do ciągów typu string...................................................5............................124 5.7. Testowanie funkcji split ...................................................5........................................127 5.8. Kolekcjonowanie zawartości ciągu typu string...................................................5.....129 5.9. Podsumowanie ...................................................5...................................................5...134 Rozdział 6. Korzystanie z algorytmów biblioteki standardowej........................... 141 6.1. Analiza ciągów znakowych...................................................5...................................142 6.2. Porównanie metod wyznaczania ocen...................................................5...................151 6.3. Klasyfikacja studentów — podejście drugie...................................................5.........159 6.4. Algorytmy, kontenery, iteratory...................................................5............................163 6.5. Podsumowanie ...................................................5...................................................5...164 Rozdział 7. Stosowanie kontenerów asocjacyjnych ........................................... 169 7.1. Kontenery obsługujące szybkie wyszukiwanie...................................................5.....169 7.2. Zliczanie wyrazów ...................................................5................................................171 7.3. Generowanie tabeli odsyłaczy...................................................5...............................173 7.4. Generowanie prostych zdań ...................................................5..................................176 7.5. Słowo o wydajności ...................................................5..............................................184 7.6. Podsumowanie ...................................................5...................................................5...185 Rozdział 8. Pisanie funkcji uogólnionych............................................................... 189 8.1. Czym jest funkcja uogólniona? ...................................................5.............................189 8.2. Niezależność od struktur danych...................................................5...........................194 8.3. Iteratory wejściowe i wyjściowe ...................................................5...........................202 8.4. Wykorzystanie iteratorów do zwiększenia elastyczności programów................................204 8.5. Podsumowanie ...................................................5...................................................5...205 Rozdział 9. Definiowanie własnych typów .......................................................... 209 9.1. Rewizja typu Student_info ...................................................5....................................209 9.2. Typy definiowane przez użytkownika ...................................................5..................210 9.3. Ochrona składowych ...................................................5.............................................214 9.4. Klasa Student_info ...................................................5................................................219 9.5. Konstruktory..................................................5...................................................5........219 9.6. Stosowanie klasy Student_info ...................................................5.............................222 9.7. Podsumowanie ...................................................5...................................................5...223 Rozdział 10. Zarządzanie pamięcią i niskopoziomowymi strukturami danych........ 227 10.1. Wskaźniki i tablice ...................................................5..............................................228 10.2. Literały łańcuchowe — powtórka ...................................................5.......................235 10.4. Argumenty funkcji main ...................................................5.....................................238 10.5. Odczyt i zapis plików...................................................5..........................................239 10.6. Trzy tryby zarządzania pamięcią...................................................5.........................242 10.7. Podsumowanie ...................................................5...................................................5.245 Rozdział 11. Definiowanie abstrakcyjnych typów danych ........................................ 249 11.1. Klasa Vec ...................................................5...................................................5.........249 11.2. Implementacja klasy Vec ...................................................5....................................250 11.3. Kontrola operacji kopiowania ...................................................5.............................258 11.4. Pamięć dynamiczna w klasie Vec ...................................................5.......................267 11.5. Elastyczne zarządzanie pamięcią ...................................................5........................269 11.6. Podsumowanie ...................................................5...................................................5.275 Spis treści 7 Rozdział 12. Obiekty typów definiowanych przez użytkownika jako wartości........ 279 12.1. Prosta klasa ciągów ...................................................5.............................................280 12.2. Konwersje automatyczne ...................................................5....................................281 12.3. Operacje wykonywane na klasie Str ...................................................5...................283 12.4. Ryzykowne konwersje ...................................................5........................................290 12.5. Operatory konwersji...................................................5............................................292 12.6. Konwersje a zarządzanie pamięcią...................................................5.........................293 12.7. Podsumowanie ...................................................5...................................................5.295 Rozdział 13. Dziedziczenie i wiązanie dynamiczne............................................... 299 13.1. Dziedziczenie ...................................................5...................................................5...299 13.2. Polimorfizm i funkcje wirtualne ...................................................5.........................305 13.3. Rozwiązanie zadania z użyciem dziedziczenia ...................................................5...310 13.4. Prosta klasa manipulatora...................................................5....................................316 13.5. Stosowanie klasy manipulatora...................................................5...........................321 13.6. Niuanse...................................................5...................................................5.............323 13.7. Podsumowanie ...................................................5...................................................5.324 Rozdział 14. Automatyczne (prawie) zarządzanie pamięcią.................................. 329 14.1. Manipulatory kopiujące obiekty docelowe ...................................................5.........330 14.2. Manipulatory zliczające odwołania...................................................5..........................337 14.3. Manipulatory z opcją współużytkowania danych ..................................................340 14.4. Ulepszanie manipulatorów...................................................5..................................342 14.5. Podsumowanie ...................................................5...................................................5.346 Rozdział 15. Obrazki znakowe — podejście drugie.............................................. 347 ..348 15.1. Projekt ...................................................5...................................................5............ 15.2. Implementacja ...................................................5...................................................5..357 15.3. Podsumowanie ...................................................5...................................................5.368 Rozdział 16. Co dalej?........................................................................................ 371 16.1. Korzystaj z posiadanych narzędzi ...................................................5.......................371 16.2. Pogłębiaj wiedzę ...................................................5.................................................373 Dodatek A Tajniki języka.................................................................................. 375 A.1. Deklaracje...................................................5...................................................5..........375 A.2. Typy............................................5...................................................5..........................380 A.3. Wyrażenia...................................................5...................................................5..........388 A.4. Instrukcje ...................................................5...................................................5...........391 Dodatek B Opis biblioteki ................................................................................ 395 B.1. Wejście i wyjście ...................................................5..................................................396 B.2. Kontenery i iteratory...................................................5.............................................399 B.3. Algorytmy...................................................5...................................................5..........411 Skorowidz.......................................................................................417 Rozdział 6. Korzystanie z algorytmów biblioteki standardowej W rozdziale 5. widzieliśmy, że wiele operacji wykonywanych na kontenerach da się zastosować do więcej niż jednego typu kontenera. Przykładowo, typy XGEVQT, UVTKPI i NKUV pozwalają na realizację operacji wstawiania elementów za pośrednictwem me- tody KPUGTV i usuwania elementów metodą GTCUG. Operacje te realizowane są za po- średnictwem identycznego we wszystkich trzech przypadkach interfejsu. Dzięki temu wiele z operacji charakterystycznych dla kontenerów da się wykonać również wobec obiektów typu UVTKPI. Każdy kontener — również klasa UVTKPI — udostępnia skojarzone z danym typem kon- tenera klasy iteratorów, za pośrednictwem których można wybierać elementy z konte- nera. Tu znów biblioteka standardowa troszczy się o to, aby każdy z udostępnianych iteratorów pozwalała na realizację pewnych operacji eza pośrednictwem wspólnego dla wszystkich iteratorów interfejsu. Dla przykładu, operator daje się zastosować wobec iteratora dowolnego typu i zawsze oznacza przesunięcie iteratora do następnego elementu kontenera; operator służy z kolei do odwoływania się do elementu skojarzonego z ite- ratorem, niezależnie od typu tego ostatniego. W bieżącym rozdziale zobaczymy, w jaki sposób biblioteka standardowa wykorzystuje koncepcję wspólnego interfejsu w udostępnianiu zbioru tak zwanych standardowych algorytmów. Korzystając z tych algorytmów, unikamy pisania i przepisywania wciąż tego samego kodu dla różnych struktur danych. Co ważniejsze, możemy dzięki nim pisać programy prostsze i mniejsze niż gdybyśmy wszystkie algorytmy implementowali sami — niekiedy różnica rozmiarów i prostoty oprogramowania w wyniku zastosowania algorytmów standardowych może być ogromna. Algorytmy, podobnie jak iteratory i kontenery, również wykorzystują konwencję spój- nego interfejsu. Spójność ta pozwala nam ograniczyć naukę do kilku algorytmów i na zastosowanie zdobytych doświadczeń w pracy z pozostałymi algorytmami. W tym roz- dziale do rozwiązywania problemów związanych z przetwarzaniem ciągów typu UVTKPI i ocen studentów wykorzystamy kilka standardowych algorytmów. Przy okazji nauczy- my się korzystać z większości kluczowych koncepcji ealgorytmów biblioteki standardowej. 26 Accelerated C++. Practical Programming by Example O ile w tekście nie będzie zaznaczone inaczej, wszystkie prezentowane w tym rozdziale algorytmy definiowane będą w nagłówku CNIQTKVJO . 6.1. Analiza ciągów znakowych W §5.8.2/132 wykorzystywaliśmy do konkatenacji dwóch obrazków znakowych nastę- pującą pętlę: HQT XGEVQTUVTKPI EQPUV KVGTCVQTKVDQVVQODGIKP  KVDQVVQOGPF  KV TGVRWUJADCEM KV  Stwierdziliśmy, że pętla ta odpowiada czynności wstawienia kopii elementów kontenera DQVVQO na koniec kontenera TGV, która to czynność w przypadku kontenerów typu XGEVQT może zostać zrealizowana bezpośrednio: TGVKPUGTV TGVGPF DQVVQODGIKP DQVVQOGPF  Niniejsze zadanie da się jednak rozwiązać jeszcze bardziej ogólnie — można bowiem oddzielić kopiowanie elementów od ich wstawiania nae koniec kontenera, jak poniżej: EQR[ DQVVQODGIKP DQVVQOGPF DCEMAKPUGTVGT TGV   W tym przykładzie EQR[ jest algorytmem uogólnionym, a DCEMAKPUGTVGT jest przykła- dem adaptora. Algorytm uogólniony to algorytm, który nie jest częścią definicji jakiegokolwiek kon- kretnego kontenera, a o sposobie dostępu do przetwarzanych danych decyduje na pod- stawie typów argumentów. Algorytmy uogólnione biblioteki standardowej przyjmują zwykle w liście argumentów wywołania iteratory, za pośrednictwem których odwołują się do manipulowanych elementów w kontenerach źródłowych. Dla przykładu, algorytm EQR[ przyjmuje trzy iteratory, którym przypiszemy nazwy DGIKP, GPF i QWV i kopiuje ele- menty w zakresie =DGIKPGPF do miejsca wskazywanego przez QWV, w miarę potrze- by rozszerzając kontener docelowy. Innymi słowy, konsterukcja: EQR[ DGIKPGPFQWV  jest co do efektu równoważna konstrukcji: YJKNG DGIKPGPF  QWV  DGIKP  z tym, że powyższa instrukcja YJKNG zmienia wartości iteratorów, a algorytm EQR[ tego nie robi. Zanim przejdziemy do omawiania adaptorów iteratorów, powinniśmy zwrócić uwagę na wykorzystanie w powyższej pętli operatora inkrementacji w postaci przyrostkowej. Operatory przyrostkowe różnią się od przedrostkowych tym, że wyrażenie DGIKP zwraca kopię oryginalnej wartości DGIKP, a zwiększenie wartości DGIKP stanowi efekt uboczny operacji. Innymi słowy, kod: KVDGIKP  Rozdział 6. ♦ Korzystanie z algorytmów biblioteki standardowej 27 jest równoważny kodowi: KVDGIKP DGIKP Operator inkrementacji ma priorytet identyczny z priorytetem operatora ; oba te ope- ratory są też operatorami łącznymi prawostronnie, co eoznacza, że QWV powinno być interpretowane jako QWV . Stąd zapis: QWV  DGIKP  odpowiada zapisowi: ] QWV DGIKP QWV DGIKP_ Wróćmy teraz do adaptorów iteratorów, które są, zasadniczo rzecz biorąc, funkcjami zwracającymi iteratory, których właściwości są związane z argumentami wywołania. Adaptory iteratorów są definiowane w nagłówku KVGTCVQT . Najpowszechniej wyko- rzystywanym adaptorem jest DCEMAKPUGTVGT, który przyjmuje jako argument wywoła- nia kontener i zwraca iterator, który zastosowany w operacji wstawiania wskazuje na miejsce kolejnego elementu. Przykładowo więc DCEMAKPUGTVGT TGV jest iteratorem, któ- ry wykorzystany jako iterator elementu docelowego operacji wstawiania spowoduje wstawienie elementu na koniec kontenera. Stąd: EQR[ DQVVQODGIKP DQVVQOGPF DCEMAKPUGTVGT TGV  kopiuje wszystkie elementy kontenera DQVVQO, dołączając ich kopie na koniec kontenera TGV. Po zakończeniu działania funkcji rozmiar kontenera TGV zostanie zatem zwiększony o wielkość DQVVQOUKG . Zauważmy, że nie można wykonać wywołania: błąd — TGVnie jest iteratorem EQR[ DQVVQODGIKP DQVVQOGPF TGV  a to dlatego, że trzecim parametrem funkcji EQR[ musi być iterator, a w wywołaniu w miejsce odpowiedniego argumentu przekazano kontener. Podobnie niemożliwe jest wykonanie kodu: błąd — brak elementu pod wskazaniem GPFTGV EQR[ DQVVQODGIKP DQVVQOGPF TGVGPF  Tutaj błąd jest mniej oczywisty, ponieważ dzięki zgodności typów argumentów wywo- łanie takie zostanie przyjęte przez kompilator. Błąd ujawni się dopiero przy wykonywaniu powyższego kodu — na początek funkcja EQR[ spróbuje przypisać skopiowaną wartość do elementu wskazywanego iteratorem TGVGPF , podczas gdy wiemy, że TGVGPF to odniesienie do nieistniejącego elementu za ostatnim elementem kontenera. Sposób działania programu w takiej sytuacji jest całkowiciee niezdefiniowany. Skąd taka definicja funkcji EQR[? Otóż oddzielenie koncepcji kopiowania od zwiększania rozmiaru kontenera pozwala programistom na dokonywanie wyboru operacij w zależności od potrzeb. Przydaje się to, na przykład, w sytuacji, kiedy zachodzi potrzeba skopiowania elementów do kontenera bez zmieniania jego rozmiaru (a więc z nadpisaniem bieżącej zawartości kontenera). W innym przykładzie, prezentowanym zresztą w §6.2.2/154, dzięki adaptorowi DCEMAKPUGTVGT można dołączać do kontenera elementy, które nie są prostymi kopiami elementów innego kontenera. 28 Accelerated C++. Practical Programming by Example 6.1.1. Inna implementacja funkcji split Inną funkcją, którą moglibyśmy zmodyfikować pod kątem wykorzystania algorytmów standardowych, jest funkcja URNKV, prezentowana w §5.6/125. Najtrudniejsze w pierwot- nej wersji funkcji było kontrolowanie indeksów ograniczających kolejne wyrazy ciągu wejściowego. Indeksy te możemy zastąpić iteratorami i zaprząc do pracy algorytmy biblioteki standardowej: zwraca VTWG, jeżeli argument jest znakiem odstępu; w przeciwnyjm przypadku zwraca HCNUG DQQNURCEG EJCTE ] TGVWTPKUURCEG E  _ zwraca HCNUG, jeżeli argument jest znakiem odstępu; w przeciwnyjm przypadku zwraca VTWG DQQNPQVAURCEG EJCTE ] TGVWTPKUURCEG E  _ XGEVQTUVTKPI URNKV EQPUVUVTKPIUVT ] V[RGFGHUVTKPIEQPUVAKVGTCVQTKVGT XGEVQTUVTKPI TGV KVGTKUVTDGIKP  YJKNG KUVTGPF ] pomiń wprowadzające znaki odstępu KHKPFAKH KUVTGPF PQVAURCEG  znajdź koniec bieżącego wyrazu KVGTLHKPFAKH KUVTGPF URCEG  kopiuj znaki z zakresu =KL KH KUVTGPF TGVRWUJADCEM UVTKPI KL  KL _ TGVWTPTGV _ W kodzie nowej wersji funkcji widać sporo nowości wymagających objaśnienia. W grun- cie rzeczy jednak powyższa implementacja stanowi nieco inne wcielenie dotychcza- sowego algorytmu, wykorzystującego K i L do wyznaczania granic odszukanego wyrazu ciągu UVT, zgodnie z wytycznymi z §5.6/125. Po znalezieniu słowa, jego kopia jest do- łączana do kontenera TGV. Tym razem jednak K oraz L są iteratorami, a nie indeksami. Do wygodnego posługiwa- nia się typem iteraotra wykorzystaliśmy definicję V[RGFGH, dzięki czemu później moż- na było korzystać z nazwy typu KVGT w miejsce nazwy UVTKPIEQPUVAKVGTCVQT. I choć typ UVTKPI nie obsługuje wszystkich operacji charakterystycznych dla kontenerów, ob- sługuje iteratory, dzięki czemu możemy w stosunku do znaków umieszczonych w ciągu UVTKPI wykorzystywać algorytmy biblioteki standardowej, podobnie, jak czyniliśmy to w odniesieniu do elementów kontenera typu XGEVQT. Rozdział 6. ♦ Korzystanie z algorytmów biblioteki standardowej 29 Wykorzystywanym w tym wcieleniu funkcji algorytmem jest HKPFAKH. Pierwszymi dwoma argumentami wywołania tego algorytmu są iteratory ograniczające analizowany ciąg. Trzeci argument jest predykatem sprawdzającym przekazany argument i zwraca- jącym wartość VTWG bądź HCNUG. Funkcja HKPFAKH wywołuje predykat dla każdego ele- mentu we wskazanym zbiorze, przerywając działanie w momencie napotkania pierw- szego elementu spełniającego predykat. Biblioteka standardowa udostępnia funkcję KUURCEG, która sprawdza, czy przekazany ar- gumentem znak należy do grupy znaków odstępu. Funkcja ta jest jednak przeciążona pod kątem obsługi języków takich jak, na przykład, japoński, korzystających z rozsze- rzonego typu znaku YEJCTAV (patrz §1.3/32). Nie jest łatwo przekazać funkcję przecią- żoną jako bezpośredni argument szablonu funkcji. Kłopot z takim przekazaniem pole- ga na tym, że kompilator nie „wie”, której wersji funkcji przeciążonej użyć w wywołaniu szablonu funkcji; nie może tego rozstrzygnąć na podstawie argumentów wywołania funkcji przeciążonej, ponieważ w wywołaniu argumentów tych nie ma. Z tego wzglę- du udostępniliśmy własny predykat dla algorytmu HKPFAKH, a konkretnie dwa takie pre- dykaty: URCEG i PQVAURCEG; dzięki nim staje się jasne, której wersji funkcji KUURCEG ma użyć kompilator. Pierwsze wywołanie funkcji HKPFAKH wyszukuje znak niebędący znakiem odstępu roz- poczynający kolejny wyraz. Pamiętajmy, że znaki odstępów mogą znajdować się rów- nież przed pierwszym z wyrazów. Tych znaków nie chcemey wyprowadzać na wyjście. Po zakończeniu pierwszego wywołania funkcji HKPFAKH K wskazuje pierwszy niebędący odstępem znak ciągu UVT. Wskazanie to wykorzystywane jest w drugim wywołaniu funk- cji HKPFAKH, która z kolej wyszukuje pierwszy znak odstępu za pozycją K i przed koń- cem ciągu. Jeżeli funkcji nie uda się znaleźć znaku spełniającego predykat, zwraca dru- gi argument, który w naszym przypadku będzie miał wartość UVTGPF . Tak więc L zostanie zainicjalizowane wartością iteratora odnoszącego się do pierwszego znaku za znakiem K będącym znakiem spacji, ewentualnie wartością UVTGPF , jeżeli takiego znaku w ciągu nie było. W tej fazie wykonania K i L ograniczają kolejny znaleziony wyraz ciągu UVT. Zostało już tylko skorzystanie z wartości iteratorów do skopiowania podciągu z ciągu UVT do kontenera TGV. W poprzedniej wersji funkcji URNKV do tego zadania wytypowana została funkcja UVTKPIUWDUVT. Ponieważ jednak w nowej wersji funkcji URNKV nie mamy już indeksów, a jedynie iteratory, a funkcja UWDUVT nie jest przeciążona dla argumentów te- go typu, musimy skonstruować podciąg typu UVTKPI jako kopię ograniczonego iterato- rami ciągu UVT. Realizujemy to w wyrażeniu UVTKPI KL , które wygląda podobnie do definicji zmiennej URCEGU pokazanej w §1.2/30. W tym przykładzie obiekt typu UVTKPI inicjalizowany jest kopią znaków w zakresie =K L . Obiekt ten jest następnie za po- średnictwem metody RWUJADCEM kierowany do kontenera TGV. Warto wskazać, że nowa wersja programu pomija testowanie indeksu K pod kątem zrów- nania się z UVTUKG . Nie ma też odpowiedników tych testów porównujących itera- tory z UVTGPF . Przyczyną tego stanu rzeczy jest fakt, że algorytmy biblioteki stan- dardowej są zaprojektowane i zaimplementowane z uwzględnieniem obsługi wywołań z przekazaniem zakresu pustego. Jeżeli, na przykład, w którymś momencie pierwsze z wywołań HKPFAKH ustawi wartość iteratora K na UVTGPF , wtedy nie ma konieczności 30 Accelerated C++. Practical Programming by Example wykrywania tego faktu przed kolejnym wywołaniem funkcji HKPFAKH z tym iteratorem — HKPFAKH wykryje fakt przekazania ciągu pustego =KUVTGPF i zwróci w takim przypadku UVTGPF , sygnalizując jednocześnie brak spełnienia predykatue. 6.1.2. Palindromy Kolejnym zadaniem związanym z manipulowaniem ciągami, do którego realizacji mo- żemy wykorzystać algorytmy biblioteki standardowej, ejest sprawdzanie, czy zadany wy- raz jest palindromem. Palindromy to wyrazy, czytane tak samo w przód i wspak. Przy- kłady palindromów to: „kajak”, „oko”, „Anna”, „potop” czy „radar”. Oto rozwiązanie postawionego zadania: DQQNKUARCNKPFTQOG EQPUVUVTKPI ] TGVWTPGSWCN UDGIKP UGPF UTDGIKP  _ Wyrażenie wartości zwracanej w powyższej funkcji korzysta z wywołania GSWCN i me- tody TDGIKP; obu tych funkcji nigdy dotąd nie wykorzystywaliśmy. Podobnie jak metoda DGIKP, TDGIKP zwraca iterator, tyle że iterator ten rozpoczyna wska- zanie od ostatniego elementu kontenera, a jego zwiększanie powoduje cofanie wskazania do poprzednich elementów kontenera. Funkcja GSWCN porównuje dwie sekwencje znaków i określa, czy sekwencje te zawierają identyczne znaki. Pierwsze dwa argumenty wywołania to iteratory ograniczające pierw- szą z sekwencji. Trzeci argument to iterator odnoszący się do początku sekwencji dru- giej. Funkcja GSWCN zakłada, że sekwencja numer dwa ma rozmiar identyczny z roz- miarem sekwencji pierwszej, stąd brak konieczności określania iteratora kończącego drugą sekwencję. Jako że trzecim argumentem wywołania, a więc początkiem drugiej sekwencji porównania, jest UTDGIKP , efektem wywołania jest porównanie znaków z początku kontenera (ciągu) ze znakami końca kontenera. Funkcja GSWCN porównuje kolejno pierwszy znak ciągu U z ostatnim znakiem, następnie drugi znak ciągu ze zna- kiem przedostatnim i tak dalej. Działanie takie idealnie spełnia warunki rozwiązania postawionego zadania. 6.1.3. Wyszukiwanie w tekście adresów URL W ramach ostatniego przykładu przetwarzania ciągów zneakowych napiszemy funkcję, która w przekazanym ciągu typu UVTKPI wyszuka adresy zasobów sieci WWW, zwane też identyfikatorami URL. Funkcję taką można wykorzystać do przeglądania dokumentu (po ich uprzednim skopiowaniu do zmiennej typu UVTKPI) w poszukiwaniu zawartych w tym dokumencie identyfikatorów URL. Funkcja powinna odnaleźć wszystkie identy- fikatory URL występujące w tekście dokumentu. Identyfikator URL jest ciągiem znaków postaci: nazwa-protokołunazwa-zasobu Rozdział 6. ♦ Korzystanie z algorytmów biblioteki standardowej 31 gdzie nazwa-protokołu może zawierać wyłącznie litery, gdy nazwa-zasobu może skła- dać się z liter, cyfr oraz rozmaitych znaków przestankowych i specjalnych. Nasza funk- cja powinna przyjmować ciąg typu UVTKPI i wyszukiwać w nim wystąpienia sekwencji znaków . W przypadku odnalezienia takiego zestawu znaków funkcja powinna od- szukać poprzedzającą go nazwę protokołu i następującą po nim nazwę zasobu. Jako że projektowana funkcja powinna odnaleźć wszystkie identyfikatory URL wy- stępujące w tekście, wartością zwracaną powinien być kontener typu XGEVQTUVTKPI , w którym każdy z elementów reprezentowałby pojedynczy identyfikator URL. Dzia- łanie funkcji opiera się na przesuwaniu iteratora wzdłuż przekazanego ciągu i wyszu- kiwanie w tym ciągu znaków . W momencie odnalezienia ciągu  funkcja wyszu- kuje wstecz wyraz będący nazwą protokołu i w przód ciąg będący nazwą zasobu URL: XGEVQTUVTKPI HKPFAWTNU EQPUVUVTKPIU ] XGEVQTUVTKPI TGV V[RGFGHUVTKPIEQPUVAKVGTCVQTKVGT KVGTDUDGIKP GUGPF  przejrzyj cały ciąg wejściowy YJKNG DG ] poszukaj jednego lub kilku znaków, po których znajdujje się podciąg  DWTNADGI DG  jeśli udało się znaleźć podciąg KH DG ] pobierz resztę URL-a KVGTCHVGTWTNAGPF DG  zapamiętaj znaleziony URL TGVRWUJADCEM UVTKPI DG  zwiększ Di szukaj następnych identyfikatorów DCHVGT _ _ TGVWTPTGV _ Funkcja zaczyna się od zadeklarowania TGV jako kontenera typu XGEVQT, przechowu- jącego docelowo znalezione identyfikatory URL, oraz od zdefiniowania iteratorów ogra- niczających wejściowy ciąg typu UVTKPI. Musimy jeszcze napisać funkcje WTNADGI i WTNAGPF. Pierwsza z nich będzie wyszukiwać początek każdego z identyfikatorów URL przekazanego ciągu i ewentualnie zwracać iterator ustawiony na początek podciągu nazwa-protokołu; jeżeli w ciągu wejściowym nie uda się znaleźć URL-a, funkcja WTNA DGI powinna zwrócić drugi argument wywołania (tutaj G), sygnalizując w ten sposób niepowodzenie. Gdy WTNADGI wyszuka początek identyfikatora URL, resztą zajmuje się WTNAGPF. Funkcja ta przeszukuje ciąg od wskazanej pozycji początkowej aż do osiągnięcia końca ciągu wejściowego albo znalezienia znaku, który nie może być częścią identyfikatora URL. Funkcja zwraca iterator ustawiony na pozycję następną za pozycją ostatniego zna- ku identyfikatora. 32 Accelerated C++. Practical Programming by Example Po wywołaniu funkcji WTNADGI i WTNAGPF iterator D powinien odnosić się do początku znalezionego identyfikatora URL, a iterator CHVGT powinien wskazywać pozycję na- stępną za pozycją ostatniego znaku identyfikatora, jaek na rysunku 6.1. Rysunek 6.1. Podział obowiązków w zadaniu wyszukiwania identyfikatora URL Ze znaków znajdujących się we wskazanym iteratorami zakresie konstruowany jest nowy ciąg typu UVTKPI umieszczany w kontenerze TGV. W tym momencie można już tylko zwiększyć wartość iteratora D i przejść do wyszuki- wania następnego identyfikatora. Ponieważ identyfikatory nie mogą na siebie nachodzić, D można ustawić na znak następny za ostatnim znakiem właśnie znalezionego identyfi- katora URL; pętlę YJKNG należy kontynuować aż do przetworzenia wszystkich znaków ciągu wejściowego. Po wyjściu z tej pętli zwracany eprzez funkcję kontener TGV zawierać będzie wszystkie URL-e występujące w ciągu wejściowym. Pora na zastanowienie się nad implementacją funkcji WTNADGI i WTNAGPF. Na pierwszy ogień pójdzie funkcja prostsza, a więc WTNAGPF: UVTKPIEQPUVAKVGTCVQTWTNAGPF UVTKPIEQPUVAKVGTCVQTDUVTKPIEQPUVAKVGTCVQTG ] TGVWTPHKPFAKH DGPQVAWTNAEJCT  _ Funkcja przegląda kolejne znaki wskazanego zakresu, poddając je analizie za pośred- nictwem funkcji HKPFAKH, którą poznaliśmy w §6.1.1/144. Predykat przekazany w wy- wołaniu funkcji HKPFAKH, PQVAWTNAEJCT, musimy napisać własnoręcznie. Powinien on zwracać wartość VTWG dla znaku, który nie może znaleźć się w identyfikatoerze URL: DQQNPQVAWTNAEJCT EJCTE ] znaki (poza znakami alfanumerycznymi) dozwolone w idjentyfikatorach URL UVCVKEEQPUVUVTKPIWTNAEJ`! A   sprawdź, czy Ejest dozwolonym znakiem URL TGVWTP KUCNPWO E ^^HKPF WTNAEJDGIKP WTNAEJGPF E WTNAEJGPF  _ Powyższa funkcja, choć niepozorna, wykorzystuje kilka nowych elementów. Po pierw- sze, w definicji ciągu znaków dozwolonych w identyfikatorze URL pojawiło się słowo UVCVKE. Zmienne lokalne deklarowane jako statyczne (właśnie ze słowem UVCVKE) są zachowywane pomiędzy wywołaniami funkcji. Zmienna typu UVTKPI o nazwie WTNAEJ będzie więc konstruowana i inicjalizowana jedynie podczas realizacji pierwszego wy- wołania funkcji PQVAWTNAEJCT. Kolejne wywołania zastaną gotową wartość typu UVTKPI. Dodatkowo słowo EQPUV zapewnia niezmienność wartości zmiennej WTNAEJ po jej ini- cjalizacji. Rozdział 6. ♦ Korzystanie z algorytmów biblioteki standardowej 33 Funkcja PQVAWTNAEJCT wykorzystuje wywołanie funkcji KUCNPWO zdefiniowanej w nagłów- ku EEV[RG . Funkcja ta sprawdza, czy przekazany znak jest znakiem alfanumerycznym (czyli czy jest literą lub cyfrą). Wykorzystane w tej funkcji wywołanie HKPF jest kolejnym algorytmem biblioteki stan- dardowej. Jego działanie jest podobne do HKPFAKH z tym, że zamiast wywoływać predy- kat, funkcja HKPF samodzielnie porównuje kolejne znaki z trzecim argumentem wywo- łania. Jeżeli w sekwencji określonej dwoma pierwszymi argumentami znajduje się wartość określona argumentem trzecim, funkcja zwraca iterator ustawiony na miejsce pierwszego wystąpienia zadanej wartości w sekwencji. W przypadku nieodnalezienia za- danej wartości funkcja HKPF zwraca drugi argument. Teraz widać, jak dokładnie działa funkcja PQVAWTNAEJCT. Ponieważ wartość zwracana stanowi negację całego wyrażenia, PQVAWTNAEJCT zwraca wartość HCNUG, jeżeli zadany znak okaże się literą, cyfrą bądź znakiem dozwolonym w identyfikatorze URL, a okre- ślonym w ciągu WTNAEJ. Dla każdej innej wartości argumentu E funkcja zwraca war- tość VTWG. Pora na najtrudniejsze — implementację funkcji WTNADGI. Funkcja ta jest nieco zagma- twana, ponieważ musi obsługiwać potencjalną sytuację zawierania się w ciągu wejścio- wym sekwencji  w kontekście, który wyklucza istnienie wokół tej sekwencji identy- fikatora URL. W praktyce implementacja takiej funkcji wykorzystywałaby zapewne zdefiniowaną uprzednio listę dozwolonych nazw protokołów. My, dla uproszczenia, ograniczymy się do zagwarantowania, że sekwencję  poprzedza podciąg jednego lub więcej znaków i przynajmniej jeden znak znajdujee się za tą sekwencją. UVTKPIEQPUVAKVGTCVQTWTNADGI UVTKPIEQPUVAKVGTCVQTDUVTKPIEQPUVAKVGTCVQTG ] UVCVKEEQPUVUVTKPIUGR V[RGFGHUVTKPIEQPUVAKVGTCVQTKVGT Ksygnalizuje odnalezienie separatora  KVGTKD YJKNG KUGCTEJ KGUGRDGIKP UGRGPF G ] upewnij się, że separator nie rozpoczyna się od pocjzątku ciągu KH KDK UGRUKG G ] DGIzaznacza początek nazwy-protokołu KVGTDGIK YJKNG DGIDKUCNRJC DGI=? DGI czy za i przed separatorem znajduje się przynajmniej po jednym znaku? KH DGIKPQVAWTNAEJCT K=UGRUKG ? TGVWTPDGI _ 34 Accelerated C++. Practical Programming by Example odnaleziony separator nie jest częścią URL-a; zwiększ i poza pozycję ostatniego znaku sepraratora K UGRUKG  _ TGVWTPG _ Najprostszą częścią tej funkcji jest jej nagłówek. Wiadomo, że w wywołaniu przeka- zane zostaną dwa iteratory określające zakres przetwarzanego ciągu i że funkcja ma zwrócić iterator ustawiony na początek pierwszego z odnalezionych identyfikatorów URL. Oczywista jest też deklaracja lokalnej zmiennej typu UVTKPI, w której przecho- wywane są znaki składające się na wyróżniający identyfikator URL separator nazwy protokołu i nazwy zasobu. Podobnie, jak w funkcji PQVAWTNAEJCT (§7.1.1/148), zmienna ta jest zmienną statyczną i stałą. Nie będzie więc można zmieniać w funkcji wartości zmiennej — zostanie ona ustalona przy pierwszym wykeonaniu funkcji WTNADGI. Działanie funkcji opiera się na ustaleniu wartości dwóch iteratorów w zakresie wy- znaczanym iteratorami D i G. Iterator K ma wskazywać początek separatora URL, a ite- rator DGI początek znajdującego się przed separatorem podciągu zawierającego nazwę protokołu (rysunek 6.2). Rysunek 6.2. Pozycjonowanie iteratorów w funkcji url_beg Na początek funkcja odnajduje pierwsze wystąpienie separatora, wykorzystując wywo- łanie UGCTEJ (funkcję biblioteki standardowej), którego wcześniej nie stosowaliśmy. Funkcja UGCTEJ przyjmuje dwie pary iteratorów: pierwsza para odnosi się do sekwencji, w której następuje wyszukiwanie, druga określa sekwencję wyszukiwaną. Podobnie jak ma to miejsce w przypadku pozostałych funkcji biblioteki standardowej, jeżeli funkcji UGCTEJ nie uda się odnaleźć zadanego ciągu, zwraca iterator wskazujący na koniec prze- szukiwanego ciągu. Po zakończeniu realizacji funkcji UGCTEJ iterator K może przyjąć dwie wartości — albo będzie wskazywał element następny za ostatnim ciągu wejścio- wego, albo zawierać będzie pozycję dwukropka rozpoczynającego separator . Po odnalezieniu separatora należy odszukać litery składające się na nazwę protokołu. Najpierw należy jednak sprawdzić, czy separator nie znajduje się na samym początku albo na samym końcu przeszukiwanego ciągu; w obu tych przypadkach mamy do czy- nienia z niepełnym identyfikatorem URL, ponieważ identyfikator taki powinien zawierać przynajmniej po jednym znaku z obu stron separatora. Jeżeli separator rokuje możliwo- ści dopasowania identyfikatora URL, należy spróbować ustawić iterator DGI. W we- wnętrznej pętli YJKNG iterator DGI jest przesuwany w tył, aż do momentu, gdy dotrze do początku ciągu albo do pierwszego znaku niebędącego znakiem alfanumerycznym. Wi- dać tutaj zastosowanie dwóch nowych elementów kodu: pierwszym jest wykorzystanie faktu, że jeżeli kontener obsługuje indeksowanie, to podobną obsługę definiują iteratory tego kontenera. Innymi słowy, DGI=? jest znakiem bezpośrednio poprzedzającym znak wskazywany przez DGI. Zapis DGI=? należy tu traktować jako skróconą wersję zapisu Rozdział 6. ♦ Korzystanie z algorytmów biblioteki standardowej 35 DGI . O tego typu iteratorach powiemy więcej w §8.2.6/200. Drugi nowy element to wykorzystanie funkcji KUCNRJC zdefiniowanej w nagłówku EEV[RG biblioteki stan- dardowej; funkcja ta sprawdza, czy przekazany argument (znak) zawiera literę. Jeżeli uda się cofnąć iterator choćby o jeden znak, można założyć, że znak ten tworzy nazwę protokołu. Przed zwróceniem wartości DGI należy jednak jeszcze sprawdzić, czy przynajmniej jeden dopuszczalny znak znajduje się również po prawej stronie se- paratora . Ten test jest nieco bardziej skomplikowany. Wiadomo, że w ciągu wej- ściowym znajduje się przynajmniej jeden znak za separatorem; wiadomo to stąd, że pozytywnie wypadł test różności K  UGRUKG z wartością G wskazującą koniec ciągu. Do znaku tego możemy się odwołać za pośrednictwem K=UGRUKG ?, co od- powiada zapisowi K UGRUKG . Należy jeszcze sprawdzić, czy znak ten należy do znaków dozwolonych w identyfikatorze URL, przekazując ów znak do wywołania PQVAWTNAEJCT. Funkcja ta zwraca wartość VTWG dla znaków niedozwolonych; po zane- gowaniu wartości zwracanej dowiemy się, czy przekazany znak jest dozwolony w iden- tyfikatorze URL. Jeżeli separator nie jest częścią poprawnego identyfikatora URL, funkcja zwiększa war- tość iteratora K i kontynuuje wyszukiwanie. W prezentowanym kodzie po raz pierwszy znalazł zastosowanie operator dekrementacji (zmniejszenia o jeden) wymieniony w tabeli operatorów §2.7/54. Operator ten działa po- dobnie jak operator inkrementacji, tyle że zamiast zwiększać, zmniejsza wartość operan- du. Również ten operator można stosować jako operator przedrostkowy bądź przyrost- kowy. Zastosowana tu wersja przedrostkowa zmniejsza wartość operandu i zwraca jego nową wartość. 6.2. Porównanie metod wyznaczania ocen W §4.2/93 zaprezentowaliśmy metodę oceniania studentów w oparciu o ocenę pośred- nią, ocenę z egzaminu końcowego i medianę ocen zadań domowych. Metoda ta może zostać nadużyta przez sprytnych studentów, którzy rozmyślnie mogą nie wykonywać niektórych prac domowych. W końcu połowa gorszych ocen nie wpływa na ostateczny wynik. Wystarczy bowiem odrobić dobrze połowę zadań domowych, aby uzyskać wy- nik identyczny jak osoba, która tak samo dobrze wykonała wszystkie prace domowe. Z naszego doświadczenia wynika, że większość studentów nie będzie próbować wy- korzystywać tej luki w metodzie oceniania. Mieliśmy jednak okazję prowadzić zajęcia w grupie, której studenci czynili to otwarcie. Zastanawialiśmy się wtedy, czy średnia ocen studentów którzy omijali prace domowe, może być zbliżona do średniej studentów, któ- rzy sumiennie pracowali w czasie wolnym. Zastanawiając się nad odpowiedzią na to pytanie, uznaliśmy, że warto być może sprawdzić odpowiedź na to pytanie w kontek- ście dwóch różnych metod oceniania: 36 Accelerated C++. Practical Programming by Example  Przy użyciu średniej w miejsce mediany (zadania nieeodrobione oceniane są na 0 punktów).  Przy użyciu mediany tylko tych zadań, które student eodrobił. Dla każdego z tych schematów oceny należało porównać medianę ocen studentów, którzy oddawali wszystkie prace domowe z medianą ocen studentów, którzy pominęli jedno lub więcej zadań samodzielnych. Mający pomóc w udzieleniu odpowiedzi pro- gram powinien realizować dwa zadania: 1. Wczytywać wpisy wszystkich studentów i wyodrębniać wepisy tych studentów, którzy oddali wszystkie prace domowe. 2. Zastosować obie metody oceniania do obu grup; wypisać ena urządzeniu wyjściowym medianę ocen każdej z grup. 6.2.1. Przetwarzanie wpisów studentów Pierwszym postawionym zadaniem jest wczytanie i klasyfikacja wpisów studentów. Na szczęście dysponujemy już pewnym kodem, który rozwiązywał podobny problem postawiony w jednym z wcześniejszych rozdziałów. Do wczytania wpisów studentów możemy bowiem wykorzystać typ 5VWFGPVAKPHQ z §4.2.1/94 i związaną z obsługą tego typu funkcję TGCF (§4.2.2/94). Nie mamy natomiast funkcji, która sprawdzałaby liczbę oddanych prac domowych. Jej napisanie nie stanowi jeednak problemu: DQQNFKFACNNAJY EQPUV5VWFGPVAKPHQU ] TGVWTP HKPF UJQOGYQTMDGIKP UJQOGYQTMGPF   UJQOGYQTMGPF  _ Funkcja ta sprawdza, czy kontener JQOGYQTM wpisu studenta U zawiera jakiekolwiek wartości zerowe. Przyjęliśmy tu, że sam fakt oddania pracy domowej jest punktowany, więc wartości zerowe odpowiadają pracom niezrealizowanym w ogóle. Wartość zwra- cana przez funkcję HKPF porównywana jest z wartością JQOGYQTMGPF , jak bowiem pamiętamy, funkcja HKPF zwraca w przypadku nieodnalezienia zadanej wartości drugi argument wywołania. Dzięki dwóm wspomnianym funkcjom implementacja kodu wczytującego i klasyfiku- jącego wpisy studentów jest znacznie uproszczona. Wystarczy bowiem wczytywać ko- lejne wpisy, sprawdzać, czy student oddał wszystkie zadania domowe, i w zależności od wyniku testu dołączyć wpis do jednego z dwóch kontenerów typu XGEVQT, o nazwach FKF (dla studentów sumiennych) i FKFPV (dla leniwych). Potem należy sprawdzić, czy któryś z kontenerów nie jest przypadkiem pusty, co ueniemożliwiłoby dalszą analizę: XGEVQT5VWFGPVAKPHQ FKFFKFPV 5VWFGPVAKPHQUVWFGPV wczytaj wszystkie wpisy, pogrupuj je według kryterijum odrobienia prac domowych YJKNG TGCF EKPUVWFGPV ] KH FKFACNNAJY UVWFGPV FKFRWUJADCEM UVWFGPV  Rozdział 6. ♦ Korzystanie z algorytmów biblioteki standardowej 37 GNUG FKFPVRWUJADCEM UVWFGPV  _ sprawdź, czy oba kontenery zawierają jakieś wpisy KH FKFGORV[ ] EQWVĽCFGPGUVWFGPVÎYPKGQFTQDKđYU[UVMKEJRTCEFQOQY[EJ TGVWTP _ KH FKFPVGORV[ ] EQWV9U[UE[UVWFGPEKQFTQDKNKYU[UVMKGRTCEGFQOQYG TGVWTP _ Jedyną nowinką w powyższym kodzie jest wywoływanie metody GORV[, zwracającej wartość VTWG dla kontenera pustego i HCNUG dla kontenera zawierającego jakieś elemen- ty. Ten sposób sprawdzania zawartości kontenera jest lepszy niż porównywanie roz- miaru zwracanego przez UKG z zerem, ponieważ w przypadku niektórych rodzajów kontenerów sprawdzenie, czy w kontenerze w ogóle coś się znajduje może być reali- zowane dużo szybciej niż policzenie liczby znajdującyech się w nim elementów. 6.2.2. Analiza ocen Umiemy już wczytać wpisy studentów i sklasyfikować jee jako przynależące do kontene- ra FKF bądź do kontenera FKFPV. Następne zadanie to analiza wpisów; przed przystą- pieniem do takiej analizy wypadałoby zastanowić się enad jej założeniami. Wiemy, że trzeba będzie wykonać trzy analizy, a każdea z nich ma się składać z dwóch części, osobno dla studentów, którzy odrobili wszystkie zadania domowe i dla tych, któ- rzy to zaniedbali. Ponieważ analizy obejmować będą dwa zbiory danych, najlepiej by- łoby zaimplementować je w postaci osobnych funkcji. Jednakże niektóre operacje, takie jak wydruk zestawienia w ustalonym formacie, realizowane będą wobec par wyników analiz. Należy więc zaimplementować w postaci funkcjei wydruk zestawienia analizy par zbiorów wartości. Najgorsze, że docelowo program powinien wywoływać funkcję, która trzykrotnie (raz dla każdego rodzaju analizy) wypisywałaby na urządzeniu wyjściowym wyniki analizy. Każda z funkcji analitycznych powinna być wywołana dwukrotnie, raz dla kontenera FKF, raz dla kontenera FKFPV. Tyle że funkcja generująca zestawienie powinna za każdym ra- zem wywoływać inną funkcję analityczną! Jak to zrobić? Rozwiązaniem najprostszym jest zdefiniowanie trzech funkcji analitycznych i przeka- zywanie ich kolejno do funkcji generującej wydruk wyników. Argumentów typu funk- cyjnego już używaliśmy, między innymi przy przekazywaniu funkcji EQORCTG do funkcji bibliotecznej UQTV (§4.2.2/96). W takim przypadku funkcja generująca zestawienia po- winna przyjmować pięć argumentów:  Strumień wyjściowy, do którego zapisywane byłyby ciągi weydruku.  Ciąg UVTKPI reprezentujący nazwę analizy. 38 Accelerated C++. Practical Programming by Example  Funkcję analityczną.  Dwa argumenty będące kontenerami typu XGEVQT zawierającymi dane wejściowe analizy. Załóżmy, dla przykładu, że pierwsza analiza, wyznaczająca mediany ocen prac domo- wych, realizowana jest przez funkcję o nazwie OGFKCPACPCN[UKU. Wyprowadzenie wy- ników tej analizy w stosunku do obu grup studentów oznaczałoby realizację następu- jącego wywołania: YTKVGACPCN[UKU EQWVOGFKCPOGFKCPACPCN[UKUFKFFKFPV  Zanim zdefiniujemy funkcję YTKVGACPN[UKU powinniśmy zaimplementować funkcję OGFKCPACPCN[UKU. Funkcja ta powinna przyjmować kontener (typu XGEVQT) wpisów stu- dentów; na podstawie tych wpisów funkcja powinna obliczać oceny końcowe studen- tów zgodnie z przyjętą metodą oceniania studentów i zwrócić medianę obliczonych ocen. Funkcja taka mogłaby mieć postać: ta funkcja nie całkiem działa FQWDNGOGFKCPACPCN[UKU EQPUVXGEVQT5VWFGPVAKPHQ UVWFGPVU ] XGEVQTFQWDNG ITCFGU VTCPUHQTO UVWFGPVUDGIKP UVWFGPVUGPF DCEMAKPUGTVGT ITCFGU ITCFG  TGVWTPOGFKCP ITCFGU  _ Choć na pierwszy rzut oka funkcja może wydawać się skomplikowana, wprowadza tylko jedną nową funkcję — funkcję VTCPUHQTO. Przyjmuje ona trzy iteratory i jedną funkcję. Pierwsze dwa iteratory definiują zakres elementów do przetworzenia; trzeci iterator to iterator kontenera docelowego wyników przetwarzania — w kontenerze tym zapisywa- ne będą wyniki funkcji przetwarzającej, przekazywanej czwartym argumentem. Wywołując funkcję VTCPUHQTO, musimy zadbać o to, aby w kontenerze docelowym było dość miejsca na zachowanie wyników przetwarzania wejściowej sekwencji elementów. W tym przypadków nie jest to problemem, ponieważ kontener docelowy wskazujemy iteratorem DCEMAKPUGTVGT (patrz §6.1/142), powodującym automatyczne dołączanie wy- ników działania funkcji VTCPUHQTO do kontenera ITCFGU; kontener ten będzie dzięki zasto- sowaniu tego iteratora rozszerzany w miarę dodawania kolejnych elementów potrzeby. Czwartym argumentem wywołania funkcji VTCPUHQTO jest funkcja przekształcająca (przetwarzająca) elementy wskazane zakresem wejściowym; jest ona wywoływana dla każdego elementu z tego zakresu, a wartości zwracane przez funkcję umieszczane są w kontenerze docelowym. W powyższym przykładzie wywołanie funkcji VTCPUHQTO oznacza zastosowanie do elementów kontenera UVWFGPVU funkcji ITCFG; wyniki zwracane przez funkcję ITCFG umieszczane są w kontenerze ITCFGU. Po skompletowaniu w konte- nerze ITCFGU ocen końcowych studentów, wywołujemy funkcję OGFKCP z §4.1.1/83, obliczającą medianę wartości przechowywanych w konteneerze ITCFGU. Jest tylko jeden problem. Zgodnie z uwagą poprzedzającą kod, funkcja w tym kształ- cie niezupełnie działa. Rozdział 6. ♦ Korzystanie z algorytmów biblioteki standardowej 39 Przyczyną takiego stanu rzeczy jest to, że mamy kilka przeciążonych wersji funkcji ITCFG. Kompilator nie jest w stanie określić w wywołaniu VTCPUHQTO, o jaką wersję funk- cji ITCFG może chodzić, ponieważ w wywołaniu tym nie ma żadnych argumentów funkcji ITCFG. My wiemy, że chodzi o wersję zdefiniowaną w §4.2.2/95. Trzeba jeszcze znaleźć sposób na przekazanie tej informacji kompilatorowi. Drugą niedoskonałością powyższego kodu jest to, że funkcja ITCFG zgłasza wyjątek w przypadku, kiedy student nie ma żadnych ocen zadań domowych, tymczasem funkcja VTCPUHQTO tych wyjątków w żaden sposób nie obsługuje. Jeżeli więc zdarzy się wyją- tek, realizacja funkcji VTCPUHQTO zostanie zatrzymana, a sterowanie przeniesione do funk- cji OGFKCPACPCN[UKU. Ponieważ funkcja OGFKCPACPCN[UKU również nie przechwytuje ani nie obsługuje wyjątków, wyjątek będzie propagowany dalej w górę stosu wywołań funk- cji. W efekcie również funkcja OGFKCPACPCN[UKU zostanie przedwcześnie przerwana, przekazując sterowanie do wywołującego i tak dalej, aż wyjątek zostanie przechwycony odpowiednią klauzulą ECVEJ. Jeżeli klauzuli takiej zabraknie (z czym mielibyśmy do czynienia w proponowanej funkcji) przerywane jest działanie całego programu, a na urzą- dzeniu wyjściowym wyświetlany jest komunikat o zgłoszeniu wątku (albo i nie, zależ- nie od implementacji). Oba problemy możemy rozwiązać za pośrednictwem pomocniczej funkcji, która będzie realizować wywołanie ITCFG wewnątrz instrukcji VT[ oraz zajmie się obsługą ewentual- nych wyjątków. Ponieważ w tej funkcji wywołanie funkcji ITCFG będzie jawne, kompi- lator (na podstawie argumentów wywołania) nie będzie meiał kłopotów z wytypowaniem wersji funkcji ITCFG do realizacji wywołania: FQWDNGITCFGACWZ EQPUV5VWFGPVAKPHQU ] VT[] TGVWTPITCFG U  _ECVEJ FQOCKPAGTTQT ] TGVWTPITCFG UOKFVGTOUHKPCN  _ _ Ta funkcja przechwytuje wyjątki zgłaszane w funkcji ITCFG. W przypadku pojawienia się wyjątku zostanie on obsłużony w ramach klauzuli ECVEJ. Obsługa polega na wywo- łaniu funkcji ITCFG z trzecim argumentem o wartości  — założyliśmy przecież, że brak pracy domowej oznacza zero punktów. Jeżeli więc dany student nie odrobił żadnej z prac, wtedy ogólna ocena pracy domowej będzie wynosiła również . Do oceny końcowej liczone więc będą wyłącznie ocena z egzaminu końcowegoe i ocena pośrednia. Możemy już przepisać funkcję analityczną tak, aby korzystała z pomocniczego wywo- łania ITCFGACWZ: ta wersja działa znakomicie FQWDNGOGFKCPACPCN[UKU EQPUVXGEVQT5VWFGPVAKPHQ UVWFGPVU ] XGEVQTFQWDNG ITCFGU VTCPUHQTO UVWFGPVUDGIKP UVWFGPVUGPF DCEMAKPUGTVGT ITCFGU ITCFGACWZ  TGVWTPOGFKCP ITCFGU  _ 40 Accelerated C++. Practical Programming by Example Znając już postać funkcji analitycznej, możemy przejść do zdefiniowania funkcji YTKVGA CPCN[UKU, która wykorzystuje funkcję analityczną do porównaniae dwóch grup studentów: XQKFYTKVGACPCN[UKU QUVTGCOQWVEQPUVUVTKPIPCOG FQWDNGCPCN[UKU EQPUVXGEVQT5VWFGPVAKPHQ   EQPUVXGEVQT5VWFGPVAKPHQ FKF EQPUVXGEVQT5VWFGPVAKPHQ FKFPV ] QWVPCOGOGFKCPC ITWRCUVWFGPVÎYUQNKFP[EJ CPCN[UKU FKF OGFKCPC ITWRCUVWFGPVÎYPKGUQNKFP[EJ CPCN[UKU FKFPV GPFN _ Funkcja ta jest zaskakująco krótka, choć wprowadza kolejne nowości. Pierwszą z nich jest sposób definiowania parametru reprezentującego funkcję. Definicja parametru CPCN[UKU wygląda identycznie jak deklaracja funkcji napisanej w §4.3/100 (co prawda w §10.1.2/230 przekonamy się, że różnice są większe, niż się wydaje, możemy je jednak pominąć jako nie mające wpływu na bieżące omówienie). Druga nowinka to typ wartości zwracanej przez funkcję — void. Zastosowanie typu XQKF jest ograniczone między innymi właśnie do definiowania typu wartości zwracanej. Wi- dząc funkcję zwracającą typ XQKF, widzimy funkcję, która tak naprawdę nie zwraca żad- nej wartości. Z takiej funkcji wychodzi się za pośrednictwem instrukcji TGVWTP pozba- wionej wartości, na przykład: TGVWTP Wykonanie funkcji zwracającej typ XQKF może zostać zakończone również w wyniku dotarcia do klamry kończącej kod funkcji. W innych funkcjach takie zakończenie funk- cji jest niedozwolone; w funkcjach niezwracających wartości możemy pominąć instruk- cję TGVWTP. Teraz możemy napisać pozostały kod programu: KPVOCKP ] studenci, którzy nie odrobili wszystkich zadań domowjych XGEVQT5VWFGPVAKPHQ FKFFKFPV wczytaj wszystkie wpisy, pogrupuj je według kryterijum odrobienia prac domowych YJKNG TGCF EKPUVWFGPV ] KH FKFACNNAJY UVWFGPV FKFRWUJADCEM UVWFGPV  GNUG FKFPVRWUJADCEM UVWFGPV  _ sprawdź, czy oba kontenery zawierają jakieś wpisy KH FKFGORV[ ] EQWVĽCFGPGUVWFGPVÎYPKGQFTQDKđYU[UVMKEJRTCEFQOQY[EJ TGVWTP _ KH FKFPVGORV[ ] EQWV9U[UE[UVWFGPEKQFTQDKNKYU[UVMKGRTCEGFQOQYG TGVWTP _ Rozdział 6. ♦ Korzystanie z algorytmów biblioteki standardowej 41 przystąp do analizy YTKVGACPCN[UKU EQWVOGFKCPCOGFKCPACPCN[UKUFKFFKFPV  YTKVGACPCN[UKU EQWVħTGFPKCCXGTCIGACPCN[UKUFKFFKFPV  YTKVGACPCN[UKU EQWVOGFKCPCRTCEQFFCP[EJQRVKOKUVKEACPCN[UKUFKFFKFPV  TGVWTP _ Zostało już tylko uzupełnić program o funkcje CXGTCIGACPCN[UKU i QRVKOKUVKEAOGFKCPA CPCN[UKU. 6.2.3. Wyznaczanie ocen na podstawie średniej ocen prac domowych Funkcja CXGTCIGACPCN[UKU powinna obliczań oceny studentów przy uwzględnieniu nie mediany, ale wartości średniej ocen prac domowych. Logicznym początkiem imple- mentacji powinno być napisanie funkcji obliczającej wartość średnią elementów kon- tenera typu XGEVQT i następnie wykorzystanie jej w miejsce funkcji OGFKCP w funkcji obliczającej ocenę końcową (ITCFG): FQWDNGCXGTCIG EQPUVXGEVQTFQWDNG X ] TGVWTPCEEWOWNCVG XDGIKP XGPF  XUKG   _ Funkcja ta wywołuje funkcję CEEWOWNCVG, która — w przeciwieństwie do dotychczas stosowanych algorytmów biblioteki standardowej — definiowana jest w nagłówki PWOGTKE . Jak wskazuje nazwa tego nagłówka, udostępnia on narzędzia wykorzysty- wane w obliczeniach numerycznych. Funkcja CEEWOWNCVG dodaje serię wartości z za- kresu określonego wartościami dwóch pierwszych argumentów, zakładając początkową sumę o wartości równej wartości trzeciego argumentue. Typ wartości zwracanej zależny jest od typu trzeciego argumentu; z tego względu nie wolno w miejsce  podać wartości  — ta ostatnia jest bowiem wartością typu KPV, co przy dodawaniu zaowocowałoby obcięciem części ułamkeowych składników sumy. Po uzyskaniu sumy wszystkich elementów kontenera dzielimy ją przez wartość XUKG , a więc przez liczbę elementów kontenera. Wynikiem dzielenia jest rzecz jasna średnia arytmetyczna wartości kontenera; średnia ta zwracanea jest do wywołującego. Dysponując funkcją CXGTCIG możemy wykorzystać ją w implementacji funkcji CXGTCIGA ITCFG realizującej zmodyfikowaną metodę oceniania studentów według średnich ocen z zadań domowych: FQWDNGCXGTCIGAITCFG EQPUV5VWFGPVAKPHQU ] TGVWTPITCFG UOKFVGTOUHKPCNCXGTCIG UJQOGYQTM  _ 42 Accelerated C++. Practical Programming by Example Tutaj do obliczenia średniej ocen studenta z zadań domowych wywoływana jest funkcja CXGTCIG. Wartość zwracana przez tę funkcję przekazywana jest bezpośrednio do funkcji ITCFG (patrz §4.1/82) wyliczającej ostateczną ocenę studenta. Dysponując tak rozbudowaną infrastrukturą, w prosty sposób utworzymy funkcję CXG TCIGACPCN[UKU: FQWDNGCXGTCIGACPCN[UKU EQPUVXGEVQT5VWFGPVAKPHQ UVWFGPVU ] XGEVQTFQWDNG ITCFGU VTCPUHQTO UVWFGPVUDGIKP UVWFGPVUGPF  DCEMAKPUGTVGT ITCFGU CXGTCIGAITCFG  TGVWTPOGFKCP ITCFGU  _ Funkcję tę różni od funkcji OGFKCPACPCN[UKU (§6.2.2/155) jedynie nazwa i wywołanie CXGTCIGAITCFG w miejsce ITCFGACWZ. 6.2.4. Mediana kompletu ocen zadań domowych Ostatnia analiza, realizowana funkcją QRVKOKUVKEACPCN[UKUAUEJGOG, wyznacza ocenę stu- denta w oparciu o optymistyczne założenie, że oceny studentów z tych prac domowych, których nie oddali, są identyczne z ocenami zadań, które zrealizowali. Przy takim zało- żeniu będziemy obliczać medianę ocen tylko tych prac domowych, które zostały przez studenta oddane (przedłożone do oceny). Medianę taką nazwiemy medianą optymi- styczną. Należy oczywi
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

C++. Potęga języka. Od przykładu do przykładu
Autor:
,

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: