You are on page 1of 142

SPIS

LEKCJA 1. Co o C i C++ ka dy wiedzie powinien.


LEKCJA 2. Jak korzysta z kompilatora BORLAND C++?
LEKCJA 3. Główne menu i inne elementy IDE.
LEKCJA 4. Jeszcze o IDE C++ .
LEKCJA 5 - DZIAŁANIA PRZY POMOCY MYSZKI I BŁ DY W PROGRAMIE
LEKCJA 6 - NAST PNY PROGRAM - KOMPUTEROWA ARYTMETYKA
LEKCJA 7. Z czego składa si program
LEKCJA 8. Jakich słów kluczowych u ywa C++.
LEKCJA 9: O SPOSOBACH ODWOŁYWANIA SI DO DANYCH
LEKCJA 10 Jakie operatory stosuje C++.
LEKCJA 11. Jak deklarowa zmienne. Co to jest wska nik
LEKCJA 12. Wska niki i tablice w C i C++.
LEKCJA 13. Jak tworzy w programie p tle i rozgał zienia
LEKCJA 14. Jak tworzy i stosowa struktury
LEKCJA 15. Jak posługiwa si funkcjami.
LEKCJA 16 - ASEMBLER TASM i BASM.
LEKCJA 17: TROCH SZCZEGÓLÓW TECHNICZNYCH
LEKCJA 18 - O ŁA CUCHACH TEKSTOWYCH
LEKCJA 19: KILKA INNYCH PRZYDATNYCH FUNKCJI
LEKCJA 20 - JE LI PROGRAM POWINIEN URUCHOMI INNY PROGRAM...
LEKCJA 21: KILKA PROCESÓW JEDNOCZE NIE.
LEKCJA 22. NA ZDROWY CHŁOPSKI ROZUM PROGRAMISTY.
LEKCJA 23 - Co nowego w C++?
LEKCJA 24 : SK D WZI ŁY SI KLASY I OBIEKTY W C++.
LEKCJA 25: PRZYKŁAD OBIEKTU.
LEKCJA 26: CO TO JEST KONSTRUKTOR.
LEKCJA 27: O DZIEDZICZENIU.
LEKCJA 28: DZIEDZICZENIE ZŁO ONE.
LEKCJA 29: FUNKCJE I OVERLOADING.
LEKCJA 30: WYMIANA DANYCH MI DZY OBIEKTAMI.
LEKCJA 31: PRZEKAZANIE OBIEKTÓW JAKO ARGUMENTÓW DO FUNKCJI
LEKCJA 33: WSKA NIKI DO OBIEKTÓW.
LEKCJA 34 OVERLOADING OPERATORÓW.
LEKCJA 35: O ZASTOSOWANIU DZIEDZICZENIA
LEKCJA 36: FUNKCJE WIRTUALNE i KLASY ABSTRAKCYJNE.
LEKCJA 37: KA DY DYSK JEST ZA MAŁY, A KA DY PROCESOR ZBYT WOLNY...
LEKCJA 38: O C++, Windows i małym Chi czyku. czyli: KTO POWIEDZIAŁ, E PROGRAMOWANIE DLA WINDOWS JEST TRUDNE?!!!
LEKCJA 39: KORZYSTAMY ZE STANDARDOWYCH ZASOBÓW Windows.
LEKCJA 40: STRUKTURA PROGRAMU PROCEDURALNO - ZDARZENIOWEGO PRZEZNACZONEGO DLA WINDOWS.
LEKCJA 41: JAK TWORZY SI APLIKACJ DLA Windows?
LEKCJA 42: KOMPILATORY "SPECJALNIE DLA Windows".
LEKCJA 43: Elementy steruj ce i zarz dzanie programem.
LEKCJA 44: O Okienkach dialogowych.
LEKCJA 45: Doł czanie zasobów - menu i okienka dialogowe.
LEKCJA 46: O PROGRAMACH OBIEKTOWO - ZDARZENIOWYCH.
LEKCJA 47: APLIKACJA OBIEKTOWA - RYSOWANIE W OKNIE.
LEKCJA 48: O PAKIETACH BORLAND C++ 4/4.5.

1
LEKCJA 1. Co o C i C++ ka dy wiedzie powinien. * Jest najlepszy. Ostro niej - jest najch tniej stosowanym
narz dziem profesjonalnych programistów.

Ma oczywi cie konkurentów. Visual Basic (do małych aplikacji


W trakcie tej lekcji dowiesz si , dlaczego pora na C++. okienkowych), Turbo Pascal (do nauki podstaw - elementów
____________________________________________________ programowania sekwencyjnego, proceduralno-strukturalnego),
QuickBasic (programowanie strukturalne w rodowisku DOS),
Fortran 90, ADA, SmallTalk, itp, itd.
J zyk C++ jest uniwersalnym, nowoczesnym j zykiem programowania.
Stosowane przez USA i inne kraje wobec Polski wieloletnie Sam wielki Peter Norton przyznaje, e pocz tkowe wersje swojego
embargo COCOM'u (przeszkody w dost pie do nowoczesnej słynnego pakietu Norton Utilities pisał w Pascalu, ale dopiero
technologii) sprawiły m. in., e popularno OS2, UNIXa i C/C++ przesiadka na C/C++ pozwoliła mu doprowadzi NU do dzisiejszej
jest w Polsce do dzi nieproporcjonalnie mała, a Basica, Pascala doskonało ci. Jakie s programy Petera Nortona - ka dy widzi...
i DOSa nieproporcjonalnie du a. W USA C++ ju od kilku lat
stanowi podstawowe narz dzie programistów. Zapewne masz na swoim komputerze kilka ró nych aplikacji (np.
TAG, QR-Tekst, Word, itp.) - je li zajrzysz do nich do rodka
Ju słysz oburzenie (A co mnie obchodzi historia (View), mo esz sam przekona si , e wi kszo z nich została
"komputerologii" i koligacyjki!). Otó obchodzi, bo wynikaj z napisana wła nie w C++ (Kompilatory C++ pozostawiaj w kodzie
niej pewne "grzechy pierworodne" j zyka C/C++, a dla Ciebie, wynikowym .EXE swoj wizytówk zwykle czyteln przy pomocy
szanowny Czytelniku - pewne wnioski praktyczne. przegl darki; przekonasz si o tym tak e zagl daj c przez [View]
do własnych programów); stosowane narz dzia mo esz rozpozna
Grzech Pierwszy: tak e po obecno ci dynamicznych bibliotek - np. BWCC.DLL -
* Kompilator j zyka C/C++ jest standardowym wyposa eniem systemu biblioteka elementów steruj cych - klawiszy, itp - Borland
operacyjnego UNIX. Custom Controls for Windows).

Skutki praktyczne: Skutki praktyczne:

Ka dy PC jest w momencie zakupu (co cz sto wchodzi w cen zakupu Nauczywszy si j zyka C/C++ mo esz nie ba si ani systemu
komputera) wyposa any w system operacyjny DOS - np. DR DOS, PC UNIX/XENIX a ich rodowiska okienkowego - X Windows, ani OS2,
DOS, PTS DOS lub MS DOS. Standardowo w zestaw systemu MS DOS ani Windows 95 (dotychczasowe testy starych 16-bitowych
wchodzi interpreter j zyka BASIC (w MS-DOS - QBasic.EXE). Mo esz aplikacji wykazały b. wysoki stopie kompatibilno ci), ani
wi c by pewien, e je li jest DOS, to musi by i BASIC. stacji roboczych, ani du ych komputerów klasy mainframe. J zyk
Podobnie rzecz ma si z C/C++. Je li jest na komputerze system C/C++ dosłu ył si bowiem ogromnej ilo ci tzw. implementacji
UNIX (za wyj tkiem najubo szych wersji systemu XENIX), masz tam czyli swoich odmian, przeznaczonych dla ró nych komputerów i dla
do dyspozycji kompilator C/C++, za to BASICA ani Pascala prawie ró nych systemów operacyjnych. Windows NT i Windows 95 równie
na pewno tam nie ma. Podobnie coraz popularniejszy OS/2 zostały napisane w C++.
wyposa ony jest w kompilator (całkiem niezły) C++ i dodatkowo Czytaj c pras (np. Computer World, PC-Kurier i in.) zwró
jeszcze w pewne gotowe-firmowe biblioteki. uwag , e najwi cej ofert pracy jest wła nie dla programistów
posługuj cych si C++ (i tak zapewne b dzie jeszcze przez kilka
Grzech drugi: lat, póki nie wymy l czego lepszego - np. jakiego C+++).
* J zyk C/C++ powstał jeszcze zanim wymy lono PC, DOS, GUI Z Grzechu Trzeciego (cho nie tylko) wynika tak e po rednio
(Graficzny Interfejs U ytkownika), Windows i inne tym podobne. Grzech Czwarty.

Dwa najwa niejsze skutki praktyczne: J zyka C++ Grzech Czwarty - ANSI C, C++, czy Turbo C++, Visual
C++, czyli mała wie a BABEL.
I. W zało eniach twórców j zyk C++ miał by szybki (i jest) i
zajmowa mało miejsca w pami ci (bo ówczesne komputery miały jej Nie jestem pewien, czy "wie a BABEL" jest okre leniem
bardzo mało!). Zawiera wi c ró ne, niezrozumiałe dla nas z trafniejszym ni "kamie filozoficzny", b d "perpetuum mobile".
dzisiejszego punktu widzenia skróty. Np. to co w Pascalu czy To co w ci gu ostatnich lat stało si z j zykiem C++ ma co
Basicu wygl da zrozumiale: wspólnego z ka dym z tych utopijnych symboli. A w du ym
uproszczeniu było to tak.
i:=i+1; (Pascal)
10 I=I+1 lub inaczej NEXT I (Basic) Podobnie, jak mechanikom od zarania dziejów marzyło si
perpetuum mobile, tak informatykom zawsze marzyło si stworzenie
to w j zyku C++ wygl da dziwacznie: jednego SUPER-UNIWERSALNEGO j zyka programowania. Takiego, który
byłby zupełnie niezale ny od sprz tu tzn., aby program napisany
i++; albo jeszcze dziwniej ++i; w takim j zyku mógł by przeniesiony BEZ ADNYCH ZMIAN na
dowolny komputer I DZIAŁAŁ. Do takiej roli pretendowały kolejno
Tym niemniej zwró uwag , e w Pascalu zajmuje to 7 znaków, w FORTRAN, Algol a potem przyszła pora na C/C++. Gdyby informatycy
Basicu - 8 znaków (spacja to te znak!), a w C++ tylko 4. nie okazali si zbyt zachłanni, mo e co by z tego wyszło. Ale,
jak to w yciu, programi ci (podobnie jak ona rybaka z bajki "O
Inny przykład: rybaku i złotej rybce") chcieli wszystkiego naraz:

X=X+5 (Basic, 5 znaków), * eby program dał si przenie na komputer innego typu i
X:=X+5 (Pascal, 6 znaków), działał,
X+=5 (C++, tylko 4 znaki). * eby działał szybko i optymalnie wykorzystywał sprz t,
* eby umiał wszystko, co w informatyce tylko wymy lono (tj. i
Z takiej wła nie filozofii wynika i sama nazwa - najkrótsza z grafika, i obiekty, i obsługa peryferii i...).
mo liwych. Je li bowiem i++ miało znaczy mniej wi cej tyle samo
co NEXT I (nast pne I) to C++ znaczy mniej wi cej tyle samo co I stało si . W pomy lanym jako uniwersalny j zyku zacz ły
"NAST PNA WERSJA C". powstawa odmiany, dialekty, mutacje, wersje itp. itd.

II. Nie ma nic za darmo. W j zyku C/C++, podobnie jak w Je li C++ nie jest Twoim pierwszym j zykiem, z pewno ci
samochodzie wy cigowym formuły I, za szybko i skuteczno zauwa yłe Czytelniku, e pomi dzy GW Basic a Quick Basic s
płaci si komfortem. Konstrukcje stosowane w j zyku C/C++ s pewne drobne ró nice. Podobnie Turbo Pascal 7.0 troch ró ni si
maksymalnie dostosowane do "wygody" komputera. Pozwala to na od Turbo Pascala 5.0. Mimo to przykład poni ej pewnie Ci troch
uzyskiwanie ˙niezwykle szybkich "maszynowo-zorientowanych" kodów zaskoczy. Dla zilustrowania skali problemu przedstawiam poni ej
wykonywalnych programu, ale od programisty wymaga dwie wersje TEGO SAMEGO PROGRAMU napisanego w dwu ró nych
przyzwyczajenia si do "komputerowo-zorientowanego sposobu wersjach TEGO SAMEGO J ZYKA C++. . Obydwa programy robi
my lenia". dokładnie to samo. Maj za zadanie wypisa na ekranie napis
"Hello World" (czyli "Cze wiecie!").
Grzech Trzeci (i chyba najci szy):
2
Program (1)
Ameryka ski Instytut Standardów ANSI od lat prowadzi walk z
main() wiatrakami. Stoi na stra y jednolitego standardu j zyka, który
{ nazywa si standardem ANSI C i ANSI C++. Wielcy producenci od
printf("Hello World\n"); czasu do czasu organizuj konferencje i spotkania gdzie w
} ciepłych krajach i uzgadniaj niektóre standardy - czyli wspólne
dla nich i zalecane dla innych normy, ale niektórzy bywaj
zazdro ni o własne tajemnice i nie publikuj wszystkich
Program (2) informacji o swoich produktach. Dlatego wszelkie "słuszne i
uniwersalne" standardy typu ODBC, Latin 2, Mazovia, LIM, OLE,
#include <windows.h> DDE, BGI, itp., itd. maj niestety do dzi ograniczony zakres
#include <iostream.h> stosowalno ci a wszelkie zapewnienia producentów o całkowitej
zgodno ci ich produktu z... (tu wpisa odpowiednie) nale y
LPSTR p = "Hello World\n"; niestety nadal traktowa z pewn rezerw .

main(void) W niniejszej ksi ce zajmiemy si kompilatorem Borland C++ w


{ jego wersjach 3.0 do 4.5, jest to bowiem najpopularniejszy w
cout << "Hello World" << endl; Polsce kompilator j zyka C/C++ przeznaczony dla komputerów IBM
MessageBox(0, p, "Aplikacja dla Windows", MB_OK); PC. Nie bez znaczenia dla tej decyzji był tak e fakt, e Borland
return (0); C++ i Turbo C++ bez konfliktów współpracuje z:
}
* Turbo Pascal i Borland Pascal;
Có za uderzaj ce podobie stwo, prawda? Ale arty na bok. Je li * Assemblerami: TASM, BASM i MASM;
zaistnieje jaki problem, zawsze mamy co najmniej trzy wyj cia. * Turbo Debuggerem i Turbo Profilerem;
Mo emy: * bibliotekami Turbo Vision, ObjectVision, Object Windows
Library, Database Tools, itp.
1. Udawa , e go nie ma. * pakietami innych producentów - np. Win/Sys Library, Object
Tak post puje wielu autorów podr czników na temat C/C++. Professional, CA-Visual Objects, Clipper, itp.
2. Krzycze , e nam si to nie podoba.
Mamy pełne prawo obrazi si i wróci do Basica lub Pascala. i in. produktami "ze stajni" Borlanda popularnymi w ród
3. Spróbowa porusza si w tym g szczu. programistów. Programy TASM/BASM, Debugger, Profiler a tak e
niektóre biblioteki (np. Object Windows Library, Turbo Vision
Wyj cie trzecie ma jedn wad - jest najtrudniejsze, ale i Library, itp. wchodz w skład pakietów instalacyjnych BORLANDA,
efekty takiego wyboru s najbardziej obiecuj ce. ale UWAGA - niestety nie wszystkich). Borland C++ 4+ pozwala,
dzi ki obecno ci specjalnych klas VBX w bibliotece klas i
Je li chcesz zaryzykowa i wybra wyj cie trzecie, spróbujmy obiektów Object Windows Library na wykorzystanie programów i
zrobi pierwszy krok w tej "d ungli". Wyja nijmy kilka nazw, zasobów tworzonych w rodowisku Visual Basic'a. Podobnie
poj i zasad gry obowi zuj cych w tym obszarze. kompilatory C++ firmy Microsoft (szczególnie Visual C++)
bezkonfliktowo współpracuj z zasobami innych aplikacji - np.
J zyki programowania posługuj si pewnymi specyficznymi grupami Access, Excel, itp..
słów i symboli. S to m. in.:
Warto tu zwróci uwag na jeszcze jeden czynnik, który mo e sta
* słowa kluczowe si Twoim, Czytelniku atutem. Je li znasz ju kompilatory Turbo
(tu pomi dzy wersjami C++ rozbie no ci s niewielkie), Pascal, b d Borland Pascal, zwró uwag , e wiele funkcji
zaimplementowanych w Turbo Pascal 6.0. czy 7.0 ma swoje
* operatory (po prostu znaki operacji - np. +), odpowiedniki w BORLAND C++ i Turbo C++. Odpowiedniki te zwykle
(tu zgodno jest niemal 100 %-owa) działaj dokładnie tak samo, a ró ni si najcz ciej
nieznacznie pisowni nazwy funkcji. Wynika to z błogosławie stwa
* dyrektywy "lenistwa" (pono homo sapiens najwi cej wynalazków popełniał
(polecenia dla kompilatora JAK tworzy program wynikowy; wła nie ze strachu, b d z lenistwa...). Firmie Borland "nie
tu ju jest gorzej, szczególnie dyrektywa #pragma w ka dej chciało si " wymy la od nowa tego, co ju sprawdziło si
wersji kompilatora C++ jest inna) wcze niej i do czego przyzwyczaili si klienci! I odwrotnie.
Poznawszy Borland/Turbo C++ z łatwo ci zauwa ysz te same
* nazwy funkcji funkcje w Borland/Turbo Pascalu.
(z tym gorzej, bo ka dy producent ma własne funkcje i własne
upodobania) [!!!]UWAGA!
________________________________________________________________
* nazwy stałych
(gdyby chodziło tylko o PI i e - wszystko byłoby proste) O Kompilatorach BORLAND C++ 4 i 4.5 napisz nieco pó niej,
poniewa s bardziej skomplikowane i wymagaj troch wi kszej
* nazy zasobów (FILE, PRN, CONSOLE, SCREEN itp. itd) znajomo ci zasad tworzenia i uruchamiania programów (projekty).
(tu jest lepiej, ale te rozbie no ci s zauwa alne)
To prawda, e zawieraj narz dzia klasy CASE do automatycznego
Autor programu mo e jeszcze nadawa zmiennym (liczbom, zmiennym generowania aplikacji i jeszcze kilka innych ułatwie , ale miej
napisom, obiektom, itp.) własne nazwy, wi c czasem nawet troch cierpliwo ci...
wytrawny programista ma kłopoty ze zrozumieniem tekstu ________________________________________________________________
ródłowego programu...
[???] C.A.S.E.
W j zyku C a nast pnie C++ przyj to pewne maniery nadawania nazw ________________________________________________________________

CASE - Computer Aided Software Engineering - in ynieria


- identyfikatorów ułatwiaj ce rozpoznawanie tych grup słów: programowa wspomagana komputerowo. Najnowsze kompilatory C++
wyposa one s w narz dzia nowej generacji. W ró nych wersjach
* nazwa() - funkcja nazywaj si one AppExpert, ClassExpert, AppWizard, VBX
* słowa kluczowe i nazwy zmiennych - małymi literami Generator, itp. itd, które pozwalaj w du ym stopniu
* STAŁE - nazwy stałych najcz ciej du ymi literami zautomatyzowa proces tworzenia aplikacji. Nie mo na jednak
* long/LONG - typy danych podstawowe/predefiniowane dla Windows zaczyna kursu pilota u od programowania autopilota - a kursu
_NAZWA - nazwy stałych predefiniowanych przez producenta programowania od automatycznych generatorów aplikacji dla
__nazwa lub __nazwa__ - identyfikatory charakterystyczne dla Windows...
danej wersji kompilatora ________________________________________________________________

itp., których to zwyczajów i ja postaram si przestrzega w


tek cie ksi ki. Zaczynamy zatem od rzeczy najprostszych, maj c jedynie t
3
krzepi c wiadomo , e gdy ju przyst pimy do pisania WYBORY95 - prosta gra zr czno ciowa (dla Windows)
aplikacji konkurencyjnej wobec Worda, QR-Tekst'a, czy Power FOR*.CPP - przykłady zastosowania p tli
Point'a - mo e nas wspomaga system wspomaganina CASE doł czony BGI*.CPP - przykłady grafiki DOS/BGI
do najnowszych wersji BORLAND C++ 4 i 4.5. Je li mamy ju gotowe oraz programik ułatwiaj cy kurs - MEDYT.EXE wyposa ony w
aplikacje w Visual Basic'u - Borland C++ 4+ pozwoli nam dodatkowe pliki tekstowe.
skorzysta z elementów tych programów (ale pracowa te aplikacje
po przetransponowaniu do C++ b d od kilku do kilkuset razy I. URUCHOMIENIE KOMPILATORA.
szybciej).
_______________________________________________________________ Aby uruchomi kompilator, powiniene w linii rozkazu po
DOS'owskim znaku zach ty (zwykle C> lub C:\>) wyda polecenie:

LEKCJA 2. Jak korzysta z kompilatora BORLAND C++? BC

________________________________________________________________ i nacisn [Enter].


W trakcie tej lekcji poznasz sposoby rozwi zania typowych (UWAGA: w ró nych wersjach kompilatorów mo e to by np.:
problemów wyst puj cych przy uruchomieniu kompilatora Borland BC, TC, a dla Windows np. BCW - sprawd swoj wersj )
C++.
________________________________________________________________ Je li Twój komputer odpowiedział na to:

UWAGA: Bad command or file name


Z A N I M rozpoczniesz prac z dyskietk doł czon do niniejszej
ksi ki radzimy Ci SPORZ DZI ZAPASOW KOPI DYSKIETKI przy * na Twoim komputerze nie ma kompilatora BORLAND C++:
pomocy rozkazu DISKCOPY, np. ROZWI ZANIE: Zainstaluj C++.

DISKCOPY A: A: lub DISKCOPY B: B: * w pliku AUTOEXEC.BAT nie ma cie ki dost pu do katalogu, w


którym zainstalowany jest kompilator C++.
Unikniesz dzi ki temu by mo e wielu kłopotów, których mo e Ci
narobi np. przypadkowy wirus lub kropelka kawy. ROZWI ZANIE:

INSTALACJA DYSKIETKI. 1. Zmieni bie cy katalog (i ewentualnie dysk) na odpowiedni,


np.:
Na dyskietce doł czonej do niniejszej ksi ki, któr najlepiej D:[Enter]
zainstalowa na dysku stałym (z dyskiem pracuje si znacznie CD D:\BORLANDC\BIN[Enter]. //UWAGA: Podkatalog \BIN
szybciej, a prócz tego jest tam znacznie wi cej miejsca), w jej Albo
katalogu głównym znajduje si programik instalacyjny o nazwie:
2. Ustawi cie k dost pu przy pomocy rozkazu np:
INSTALUJ.BAT PATH C:\BORLANDC\BIN
(lub D:\TURBOC\BIN stosownie do rozmieszczenia plików na Twoim
napisany jako krótki plik wsadowy w j zyku BPL (Batch komputerze; najlepiej zasi gnij rady lokalnego eksperta).
Programming Language - j zyk programowania wsadowego). Aby
zainstalowa programy z dyskietki na własnym dysku powiniene : [???] NIE CHCE USTAWI CIE KI ?
________________________________________________________________
* sprawdzi , czy na dysku (C:, D:, H: lub innym) jest co Tak czasem si zdarza - zwykle wtedy, gdy pracujesz w DOS-ie z
najmniej 2 MB wolnego miejsca, programem Norton Commander. Musisz pozby si "na chwil "
* wło y dyskietk do nap du i wyda rozkaz: programu NC. Naci nij [F10] - Quit i potwierd przez [Y] lub
[Enter]. Po ustawieniu cie ek mo esz powtórnie uruchomi NC.
<-- patrz tekst ksiazki ________________________________________________________________

* po naci ni ciu [Entera] rozpocznie si nstalacja. O Albo


zako czeniu instalacji zostaniesz poinformowany napisem na
ekranie. 3. Doda do pliku AUTOEXEC.BAT dodatkow cie k . Jest to
wyj cie najlepsze. Na ko cu linii ustawiaj cej cie ki - np.:
UWAGI:
* Je li korzystasz z nap du dyskietek B:, lub chcesz PATH C:\; C:\DOS; C:\NC; C:\WINDOWS
zainstalowa programy z dyskietki na innym dysku ni C: -
wystarczy napisa rozkaz - np. B:\INSTALUJ AMC48 D: i nacisn dodaj cie k do kompilatora C++, np.:
[Enter].
* Program instalacyjny zadziała poprawnie tylko wtedy, gdy masz PATH C:\; C:\DOS; C:\NC; D:\BORLANDC\BIN;
system operacyjny DOS 6+ (6.0 lub nowszy) na dysku C: w katalogu
Załatwi to problem "raz na zawsze". Po uruchomieniu komputera
C:\DOS. cie ka b dzie odt d zawsze ustawiana automatycznie.
* Mo esz zainstalowa programy z dyskietki z poziomu rodowiska Poniewa kompilator C++ wymaga w trakcie pracy otwierania i
Windows. W oknie Mened era Programów: ł czenia wielu plików, ró ne wersje (program instalacyjny
- rozwi menu Plik INSTALL.EXE podaje t informacj w okienku pod koniec
- wybierz rozkaz Uruchom... instalacji) wymagaj dodania do pliku konfiguracyjnego
- do okienka wpisz <-- patrz tekst ksi ki CONFIG.SYS wiersza:

Program instalacyjny utworzy na wskazanym dysku katalog FILES = 20


\C-BELFER
i tam skopiuje cał zawarto dyskietki oraz dokona dekompresji (dla ró nych wersji warto ta wacha si w granicach od 20 do
(rozpakowania) plików. Je li chcesz skopiwa zawarto dyskietki 50). Najbezpieczniej, je li nie masz pewno ci doda 50. Je li
do własnego katalogu roboczego, wystarczy "wskaza " programowi wybrałe wariant trzeci i ewentualnie zmodyfikowałe swój
instalacyjnemu wła ciwy adres: CONFIG.SYS, wykonaj przeładowanie systemu [Ctrl]-[Alt]-[Del].
Teraz mo esz wyda rozkaz
<-- patrz tekst ksi ki
BC[Enter]
Zostanie utworzony katalog: F:\USERS\ADAM\TEKSTY\C-BELFER
Mam nadziej , e tym razem si udało i oto jeste my w IDE
UWAGA: Borland C++. Je li nie jeste jedynym u ytkownikiem, na ekranie
Prócz przykładów opisanych w ksi ce dyskietka zawiera dodatkowo rozwinie si cała kaskada okienek roboczych. Skonsultuj z
kilka przykładowych aplikacji, na które zabrakło miejsca, mi dzy wła cicielem, które z nich mo na pozamyka a które pliki mo na
innymi: skasowa lub przenie . Pami taj "primo non nocere" - przede
wszystkim nie szkodzi !
4
potrzebne do pracy wła nie teraz.
[S!] IDE = Integrated Development Environment, ________________________________________________________________

IDE, czyli Zintegrowane rodowisko Uruchomieniowe. Bardziej


prozaicznie - poł czony EDYTOR i KOMPILATOR. Zapewne znasz ju [Z] - Propozycje zada do samodzielnego wykonania.
co podobnego z Pascala lub Quick Basica. Od dzi b dzie to ----------------------------------------------------------------
Twoje rodowisko pracy, w którym b dziesz pisa , uruchamia i
modyfikowa swoje programy. 1.1 Sprawd ile bajtów ma plik .EXE w tej wersji kompilatora
C++, której u ywasz.
[???] DISK FULL! 1.2. Posługuj c si rozkazem DOS Shell z menu File sprawd gdzie
________________________________________________________________ znajduje si i jakiej jest wielko ci plik tymczasowy .SWP. Ile
Co robi , je li przy próbie uruchomienia kompilator C++ masz wolnego miejsca na dysku ?
odpowiedział Ci: ________________________________________________________________
EOF
Disk full! Not enough swap space.

Program BC.EXE (TC.EXE) jest bardzo długi. Je li wydasz rozkaz


(wariant 1: Turbo C++ 1.0, ni ej BORLAND C++ 3.1): LEKCJA 3. Główne menu i inne elementy IDE.
________________________________________________________________
DIR TC.EXE W trakcie tej lekcji dowiesz si jak porusza si w
uzyskasz odpowied , jak poni ej: zintegrowanym rodowisku (IDE) Turbo C++.
________________________________________________________________
C:>DIR TC.EXE
Directory of D:\TC\BIN Najwa niejsz rzecz w rodowisku IDE jest GŁÓWNE MENU (ang.
MENU BAR), czyli pasek, który widzisz w górnej cz ci ekranu.
TC EXE 876480 05-04-90 1:00a Działa to podobnie, jak główne menu w programie Norton Commander
1 file(s) 876480 bytes (dost pne tam przez klawisz [F9]).
17658880 bytes free
KRÓTKI PRZEGL D GŁÓWNEGO MENU.
C:>DIR BC.EXE
Directory of C:\BORLANDC\BIN Przyci nij klawisz [F10].
Główne menu stało si aktywne. Teraz przy pomocy klawiszy
BC EXE 1410992 06-10-92 3:10a kursora (ze strzałkami [<-], [->]) mo esz porusza si po menu i
1 file(s) 1410992 bytes
18926976 bytes free wybra t grup polece , która jest Ci potrzebna. A oto nazwy
poszczególnych grup:

Poniewa plik kompilatora nie mie ci si w 640 K pami ci musi [S!] GRUPY POLECE - NAZWY POSZCZEGÓLNYCH
dokonywa tzw. SWAPOWANIA i tworzy na dysku dodatkowy plik "ROZWIJANYCH" MENU.
tymczasowy (ang. swap file). Na dysku roboczym powinno
pozostawa najmniej 500 KB wolnego miejsca. Je li mo esz, = Bez nazwy (menu systemowe).
pozostaw na tym dysku wolne nie mniej ni 1 MB. Ułatwi to i File Operacje na plikach.
przyspieszy prac . Edit Edycja plików z tekstami ródłowymi programów.
________________________________________________________________ Search Przeszukiwanie.
Run Uruchomienie programu.
Tworzony tymczasowo plik roboczy wygl da tak: Compile Kompilacja programu.
Debug "Odpluskwianie", czyli wyszukiwanie bł dów w
Volume in drive D has no label programie.
Directory of D:\SIERRA Project Tworzenie du ych, wielomodułowych programów.
Options Opcje, warianty IDE i kompilatora.
TC000A SWP 262144 12-13-94 5:42p (13-XII to dzi !) Window Okna (te na ekranie).
1 file(s) 262144 bytes Help Pomoc, niestety po angielsku.
11696320 bytes free
UWAGA:
[!!!] UWAGA: __________________________________________________________
W niektórych wersjach kompilatora na pasku głównego menu pojawi
Kompilator C++ b dzie próbował tworzy plik tymczasowy zawsze w si jeszcze Browse - przegl danie (funkcji, struktury klas i
bie cym katalogu, tzn. tym, z którego wydałe rozkaz obiektów). Zwró uwag , e w okienkowych wersjach niektóre
TC lub BC. rozkazy "zmieniaj " menu i trafiaj do
Browse, Debug, Project.
II. WNIOSKI PRAKTYCZNE. W BC++ 4 menu Run brak (!). Tworzenie aplikacji sprowadza si
tam do nast puj cych kroków:
* Lepiej nie uruchamia C++ "siedz c" na dyskietce, poniewa
mo e mu tam zabrakn miejsca na plik tymczasowy. Project | Open project lub | AppExpert
* Dla u ytkowników Novella: Uruchamiajcie kompilator C++ tylko Debug | Run
we własnych katalogach - do innych mo ecie nie mie praw zapisu.

Plik .SWP jest tworzony tylko podczas sesji z kompilatorem C++ i ROZWIJAMY MENU.

usuwany natychmiast po jej zako czeniu. Mo esz go zobaczy tylko Z takiego kr cenia si w kółko po pasku (a propos, czy
zauwa yłe , e pasek pod wietlenia mo e by "przewijany w
wychodz c "na chwil " do systemu DOS przy pomocy rozkazu DOS kółko"?) jeszcze niewiele wynika. Robimy wi c nast pny krok.
Shell (menu File).
Wska w menu głównym nazw "File" i naci nij [Enter].
[S!] SWAP - Zamiana. Rozwin ło si menu File zawieraj ce list rozkazów dotycz cych
________________________________________________________________ operacji na plikach. Po tym menu te mo esz si porusza przy
Je li wszystkie dane, potrzebne do pracy programu nie mieszcz pomocy klawiszy kursora ze strzałkami gór lub w dół. Masz do
si jednocze nie w pami ci operacyjnej komputera, to program - wyboru dwie grupy rozkazów rozdzielone poziom lini :
"wła ciciel", (lub system operacyjny - DOS, OS2, Windows) mo e
dokona tzw. SWAPOWANIA. Polega to na usuni ciu z pami ci [S!]
operacyjnej i zapisaniu na dysk zb dnej w tym momencie cz ci ______________________________________________________________
danych, a na ich miejsce wpisaniu odczytanej z dysku innej Open - Otwórz istniej cy ju plik z programem (np. w celu
cz ci danych, zwykle takich, które s programowi pilnie dopisania czego nowego).
5
New - Utwórz nowy plik (zaczynamy tworzy nowy program). zamiast napisu
Save - Zapisz bie cy program na dysk. Pami taj: Pliki z
dysku nie znikaj po wył czeniu komputera. Zawsze "NONAME00.CPP" (ang. no mame - bez nazwy)
lepiej mie o jedn kopi za du o ni o jedn za mało.
jest teraz nazwa Twojego programu - PIERWSZY.CPP. Kursor miga w lewym
oraz górnym rogu okna edytora. Mo emy zaczyna .
Print - Wydrukuj program.
Get Info - Wy wietl informacje o stanie IDE. Pierwsze podej cie do programu zrobimy troch "intuicyjnie".
Dos Shell - Wyj cie "na chwil " do systemu DOS z mo liwo ci Zamiast wyja nia wszystkie szczegóły posłu ymy si analogi do
powrotu do IDE przez rozkaz EXIT. konstrukcji w Pascalu i Basicu (zakładam, e napisałe ju
Quit - Wyj cie z IDE Turbo C++ i powrót do DOSa. Inaczej - cho by jeden program w którym z tych j zyków). Szczegóły te
KONIEC PRACY. wyja ni dokładniej pocz wszy od nast pnej lekcji.
_______________________________________________________________

Skoro ju wiemy jak rozpocz prac nad nowym programem, WPISUJEMY PROGRAM "PIERWSZY.CPP".
zacznijmy przygotowanie do uruchomienia naszego pierwszego
programu. Wpisz nast puj cy tekst programu:

Wybierz z menu File rozkaz Open... (otwórz plik). Poniewa /* Program przykładowy - [P-1] */
rozkaz taki jest niejednoznaczny, wymaga przed wykonaniem
podania dodatkowych informacji. Gdyby Twój komputer mówił, #include <stdio.h>
zapytałby w tym momencie "który plik mam otworzy ?". Pytanie main()
zada musi, b dzie wi c prowadził dialog z Tob przy pomocy {
OKIENEK DIALOGOWYCH. Je li wybrałe z menu rozkaz OPEN i printf("Autor: ..........."); /*tu wpisz imie Twoje!*/
nacisn łe [Enter], to masz wła nie na ekranie takie okienko printf(" TO JA, TWOJ PROGRAM - PIERWSZY.CPP");
dialogowe. Okienko składa si z kilku charakterystycznych printf("...achoj !!!");
elementów: }

OKIENKO TEKSTOWE - (ang. Text Box lub Input Box) w którym mo esz I ju . Jak widzisz nie jest to a takie straszne. Gdyby nie to,
e zamiast znajomego PRINT"TO JA...", albo writeln(".."); jest
pisa (klawisz BackSpace [<-] pozwoli Ci printf("...");, byłoby prawie całkiem zrozumiałe. Podobny
skasowa wprowadzony tekst, je li si program w Pascalu mógłby wygl da np. tak:
rozmy lisz). Okienko to zawiera tekst "*.C".
# include <stdio.h> uses Crt;
OKIENKO Z LIST - (ang. List Box) zawiera list plików, z której main() /* pocz tek */ program AHOJ; {pocz tek}
mo esz wybra plik z programem. { Begin
printf("Autor"); write('Autor');
KLAWISZE OPCJI/POLECE - (ang. Command Button) kiedy ju printf("TO JA"); write('TO JA');
dokonasz wyboru, to mo esz wskazuj c printf("ahoj"); write('ahoj');
taki klawisz np. potwierdzi [OK], } end.
zrezygnowa [Cancel], otworzy plik
[Open] itp..
a w BASICU:
Pomi dzy elementami okienka dialogowego mo esz porusza si przy
pomocy klawiszy kursora i klawisza [Tab] lub kombinacji klawiszy 10 PRINT "Autor" : REM Pocz tek
20 PRINT "TO JA"
[Shift]-[Tab] (spróbuj!). 30 PRINT "ahoj"
40 END
Mo esz tak e posługiwa si myszk .
Wi cej o okienkach i menu dowiesz si z nast pnych lekcji, a na
razie wró my do naszego podstawowego zadania - tworzenia [!!!]UWAGA
pierwszego programu. ______________________________________________________________
Zwró uwag , e działanie funkcji:
Zanim zaczniemy tworzy program włó do kieszeni nap du A: (lub PRINT (Basic),
B:) dyskietk doł czon do niniejszej ksi ki. Mo e ona sta si printf() (C++),
Twoj dyskietk robocz i pomocnicz zarazem na okres tego Write i Writeln (Pascal)
kursu. nie jest identyczne, a TYLKO PODOBNE.
________________________________________________________________
Je eli zainstalowałe zawarto dyskietki na dysku - przejd do
stosownego katalogu - C:\C-BELFER (D:\C-BELFER) i odszukaj tam Sprawdzimy, czy program działa. Tam, gdzie s kropki wpisz Twoje
programy przykładowe. Je li nie - mo esz nadal korzysta z imi - np. Ewa, Marian, Marcin. Pami taj o postawieniu na ko cu
dyskietki (jest na niej troch miejsca). znaków cudzysłowu ("), zamkni ciu nawiasu i redniku (;) na
ko cu linii (wiersza).
Wpisz do okienka tekstowego nazw A:\PIERWSZY (lub odpowiednio
np. C:\C-BELFER\PIERWSZY). Rozszerzeniem mo esz si nie Naci nij kombinacj klawiszy [Alt]-[R]. Jest to inny, ni
przejmowa - zostanie nadane automatycznie. Plik roboczy z Twoim opisano poprzednio sposób dost pu do menu. Kombinacja klawiszy
programem zostanie utworzony na dyskietce w nap dzie A:. [Alt]-[Litera] powoduje uaktywnienie tego menu, którego nazwa
zaczyna si na podan liter . Przy takiej konwencji litera nie
Wska klawisz [Open] w okienku dialogowym i naci nij [Enter] na musi by zawsze pierwsz liter nazwy opcji. Mo e to by tak e
klawiaturze. litera wyró niona w nazwie przez podkre lenie lub wy wietlenie
np. w innym kolorze. I tak:
UWAGA!
________________________________________________________________ [Alt]+[F] menu File (Plik)
_ [Alt]+[C] menu Compile (Kompilacja
Dopóki manipulujesz okienkiem tekstowym i okienkiem z list [Alt]+[R] menu Run (Uruchamianie)
klawisz polecenia [Open] jest wyró niony (pod wietlony) i [Alt]+[W] menu Window (Okna)
traktowany jako tzw. OPCJA DOMY LNA (ang. default). W tym itd., itd..
stadium aby wybra [Open] WYSTARCZY NACISN [Enter].
________________________________________________________________ Kombinacja [Alt]+[R] wybiera wi c menu Run (uruchomienie
__ programu). Menu Run daje Ci do wyboru nast puj ce polecenia:

[S!]
Wrócili my do IDE. zmieniło si tyle, e w nagłówku okna edytora ________________________________________________________________
6
Run - Uruchomienie programu (Utwórz plik .EXE i Wykonaj). *WARNING A:\PIERWSZY.C 4: Function should return a value in
Program Reset - "Wyzerowanie" zmiennych programu. function main
Go to Cursor - Wykonanie programu do miejsca wskazanego kursorem
w tek cie. (Uwaga: Funkcja main powinna zwróci warto .)
Trace Into - Uruchom ledzenie programu.
Step Over - ledzenie programu z mo liwo ci pomini cia funkcji. Na razie zadowolimy si spostrze eniem, e:
* Bł dy UNIEMO LIWIAJ KOMPILACJ i powoduj komunikat
(dosł. tzw. "Przekraczanie" funkcji). ERRORS.
Arguments - Uruchom program z zadanymi argumentami. * Ostrze enia NIE WSTRZYMUJ KOMPILACJI i powoduj komunikat
________________________________________________________________ WARNINGS.

Wybierz "Run". Je li nie zrobiłe adnego bł du, program Jaki jest sens powy szego ostrze enia i jak go unikn dowiesz
powinien si skompilowa z komentarzem "Success" i wykona si z nast pnych lekcji.
(kompilacja zako czona sukcesem; napis mignie tak szybko, e ________________________________________________________________
mo esz tego nie zauwa y ). Je li chcesz spokojnie obejrze
wyniki działania swojego programu powiniene wykona Pozostaje nam w ramach tej lekcji:
nast puj ce czynno ci: * Zapisa Twój pierwszy program na dysku i
* Wyj z IDE C++.
1. Rozwi menu Window naciskaj c klawisze [Alt]-[W].
2. Wybierz z menu rozkaz User screen (ekran u ytkownika). JAK ST D WYJ ?
Mo esz wykona to samo bez rozwijania menu naciskaj c kombinacj
Aby zapisa plik PIERWSZY.CPP z Twoim programem (ko cow
klawiszy [Alt]-[F5]. ostateczn wersj ) na dysk nale y wykona nast puj ce czynno ci:
3. Po przejrzeniu wydruku naci nij [Enter]. Wrócisz do okna
edytora. 1. Naci nij klawisz [F10].
W głównym menu pojawi si pasek wyró nienia sygnalizuj c, e
Je li zrobiłe bł dy - kompilacja si nie uda i program nie menu stało si aktywne.
zostanie wykonany, w okienku natomiast pojawi si napis "Errors"
2. Naci nij klawisz [F].
(czyli "Bł dy"). Je li tak si stało naci nij [Enter] Pasek wyró nienia przesunie si pod wietlaj c menu File
dwukrotnie. Popraw ewentualne niezgodno ci i spróbuj jeszcze (operacje na plikach). Rozwinie si menu File.
raz.
3. Naci nij klawisz [S] - wybierz polecenie Save (je li chcesz
Bł dów zwykle bywa nie wi cej ni dwa. Najcz ciej jest to brak zapisa program w bie cym katalogu i pod bie c nazw ) lub
lub przekłamanie której litery (w słowie main lub printf) i rozkaz Save As... (zapisz jako...), podaj nowy dysk/katalog i
brak rednika na ko cu linii. W okienku komunikatów (Message) now nazw pliku.
mog pojawi si napisy - np.:
Tekst Twojego programu został zapisany na dysku/dyskietce. Teraz
Error: Statement missing ;
(Bł d: Zgubiony znak ;) mo emy wyj z C++.

[S] Error Messages - Komunikaty o bł dach. Aby to zrobi , wykonaj nast puj ce czynno ci:
________________________________________________________________
Najcz ciej w komunikatach o bł dach b d na pocz tku pojawia 1. Naci nij klawisz [F10]. Uaktywni si główne menu.
si nast puj ce słowa: 2. Rozwi menu File naciskaj c klawisz [F].
3. Wybierz z menu polecenie "Exit/Quit" i naci nij [Enter].
Error - bł d
Warning - ostrze enie [!!!] SAVE szybciej.
Syntax - składnia (składniowy) ________________________________________________________________
Expression - wyra enie Zwróc uwag , e zamiast rozwija kolejne menu, mo esz korzysta
never used - nie u yte (nie zastosowane) z kombinacji klawiszy, które pozwalaj Ci wyda rozkaz bez
assign - przypisywa , nadawa warto /znaczenie rozwijania menu. Takie kombinacje klawiszy (ang. hot keys lub
value - warto shortcut keys) znajdziesz w menu obok rozkazu, np.:
statement - operator, operacja, wyra enie
________________________________________________________________ [Alt]-[X] - Quit/Exit
[F2] - Save
[???] Co z tym rednikiem? [F3] - Open
[Alt]-[F5] - User screen (Podgl danie działania programu) itp.
________________________________________________________________ ________________________________________________________________
Zwró uwag , e po pd wietleniu komunikatu o bł dzie (pasek
wyró nienia pod wietlenia mo esz przesuwa po li cie przy pomocy [Z]
klawiszy ze strzałkami w gór i w dół) i po naci ni ciu [Entera] ________________________________________________________________
kompilator poka e ten wiersz programu, w którym jego zdaniem 1. Spróbuj napisa i uruchomi kilka własnych programów
jest co nie w porz dku. Brak rednika zauwa a zwykle dopiero po wypisuj cych ró ne napisy. W swoich programach zastosuj funkcj
przej ciu do nast pnego wiersza (i ten e wiersz poka e), co bywa printf() według nast puj cego wzoru:
na pocz tku troch myl ce.
________________________________________________________________ printf("....tu wpisz napis do wydrukowania...");

zastosuj znaki przej cia do nowego wiersza według wzoru:


[???] CZEGO ON JESZCZE CHCE ?
________________________________________________________________ printf("...napis...\n");
Nawet po usuni ciu wszystkich bł dów C++ nie "uspokoi si "
całkiem i b dzie wy wietlał ci gle komunikat ostrzegawczy: porównaj działanie.

* w OKIENKU KOMPILACJI: (bardzo typowa sytuacja) Swoim programom staraj si nadawa łatwe do rozpoznania nazwy
typu PIERWSZY, DRUGI, ADAM1, PRZYKLAD itp.
Errors: 0 (Bł dy: 0)
Warnings: 1 (Ostrze enia: 1) [???] NIE CHCE DZIAŁA ?
________________________________________________________________
Pami taj, e dla j zyka C i C++ (w przeciwie stwie np. do
* W OKIENKU KOMUNIKATÓW - (Messages - tym w dolnej cz ci Basica) PRINTF i printf to nie to samo! Słowa kluczowe i nazwy
ekranu): standardowych funkcji
MUSZ BY PISANE MAŁYMI LITERAMI !!!
7
________________________________________________________________ Alt+H Rozwini cie menu Help (pomoc)
Alt+B Rozwini cie menu przegl darki - Browse (Win)
[???] GDZIE MOJE PROGRAMY ? Alt+X Wyj cie z kompilatora DOS'owskiego - Exit
________________________________________________________________ Alt+F4 Wyj cie z kompilatora dla Windows
B d spokojny. Zapisz wersje ródłowe programów na dyskietk ________________________________________________________________
(dysk). Swoje programy skompilowane do wykonywalnej wersji *.EXE
znajdziesz najprawdopodobniej w katalogu głównym tego dysku, na
którym zainstalowany został C++ lub w katalogu Rozkazy w trybie edycji tekstu programu:
\BORLANDC\BIN\.... Je li ich tam nie ma, zachowaj zimn krew i ________________________________________________________________
przeczytaj uwa nie kilka nast pnych stron. Shift+Delete Wytnij wybrany blok tekstu (Cut) i umie w
________________________________________________________________ przechowalni (Clipboard)
Shift+Insert Wstaw blok tekstu z przechowalni (Paste)
Ctrl+Insert Skopiuj zaznaczony blok tekstu do przechowalni
PAMI TAJ: (Copy)
________________________________________________________________ Ctrl+Y Skasuj wiersz tekstu (Delete a line)
Je li masz oryginalny tekst programu, nazywany WERSJ RÓDŁOW Ctrl+Delete Skasuj zaznaczony blok tekstu
PROGRAMU, zawsze mo esz uzyska ten program w wersji "roboczej", Shift+[-->] Zaznaczanie bloku tekstu w prawo
tzn. skompilowa go na plik wykonywalny typu *.EXE (ang. Shift+[<--] Zaznaczanie bloku tekstu w lewo
EXEcutable - wykonywalny). Shift+[Down Arrow] Zaznaczanie bloku tekstu w dół (strzałka w
________________________________________________________________ dół)
Shift+[Up Arrow] Zaznaczanie bloku tekstu w gór (strzałka w
gór )
[S!] printf() - PRINTing Function - Funkcja DRUKuj ca Alt+Backspace Anuluj ostatni operacj (Undo)
________________________________________________________________ Ctrl+L Powtórz przeszukiwanie (Repeat search)
na ekranie (dokładniej - na standardowym urz dzeniu wyj cia). ________________________________________________________________
Odpowiednik PRINT w Basicu lub write w Pascalu. Dla ułatwienia
rozpoznawania nazw funkcji w tek cie wi kszo autorów pisz ca o
j zyku C++ umieszcza zawsze po nazwie funkcji par nawiasów (tak Rozkazy ogólnego przeznaczenia:
te musi j stosowa programista w programach w C++). Ja tak e ________________________________________________________________
b d stosowa dalej t zasad . F1 Wy wietl pomoc - Help screen
________________________________________________________________ F2 Zapisz bie cy stan tekstu na dysk (Save)
F3 Otwórz nowy plik (Open)
F4 Uruchom i wykonaj program do pozycji wskazanej
[???] A JE LI NIE MA C++ ??? kursorem
________________________________________________________________ F5 Powi ksz (maximize) bie ce aktywne okno
W przeciwie stwie do INTERPRETERÓW (np. QBasic), które musz by F6 Przejd do nast pnego okna (next window)
obecne, by program zadziałał, KOMPILATORY tworz wersje F7 Wykonaj program krok-po-kroku
wykonywalne programów, które mog pracowa niezale nie. W F8 Wykonaj program krok-po-kroku z pomini ciem
katalogu głównym tego dysku, na którym jest zainstalowany Twój ledzenia funkcji
BORLAND/Turbo C++ znajdziesz swoje programy PIERWSZY.EXE, F9 Skompiluj i skonsoliduj program (Compile/Make)
DRUGI.EXE itp. Aby te programy uruchomi nie musisz uruchamia F10 Uaktywnij pasek głównego menu
kompilatora C++. Wystarczy: Shift+F1 Wy wietl spis tre ci Help - tzw. Help index
Shift+F2 Wybierz rozkaz Arguments... z menu Run
1. Przej na odpowiedni dysk przy pomocy polecenia: (uruchamianie programu z parametrami w
D: (E: lub F:) DOS'owskim wierszu rozkazu)
Ctrl+F1 Podpowiedzi kontekstowe (help topic search)
2. Przej do odpowiedniego katalogu - np. głównego: Ctrl+F2 Wyzeruj bie cy program
CD \ Ctrl+F5 Zmie pozycj aktywnego okna
Ctrl+F7 Wy wietl okienko dialogowe "Add Watch"
3. Wyda polecenie: Ctrl+F8 Zaznacz punkt krytyczny (Toggle breakpoint)
PIERWSZY[Enter] Ctrl+F9 Uruchom program (Run)
________________________________________________________________ Ctrl+PgUp Skocz na pocz tek pliku
Ctrl+PgDn Skocz na koniec pliku
[!!!]UWAGA: Alt+F1 Poka poprzedni ekran Help
________________________________________________________________ Alt+F2 Zmniejsz okno
Je li nie jeste jedynym u ytkownikiem kompilatora C++ i na tym Alt+F3 Zamknij aktywne okno
samym komputerze pracuje jeszcze kto inny, sprawd , czy inny Alt+F4 Dokonaj inspekcji (inspect)
u ytkownik nie ustawił inaczej katalogu wyj ciowego (Options | Alt+F5 Poka DOS'owski ekran roboczy (User screen)
Directories | Output Directory). Katalog wyj ciowy (ang. output Alt+F7 Przejd do poprzedniego bł du (previous error)
directory) to ten katalog, w którym C++ zapisuje pliki *.EXE po Alt+F8 Przejd do nast pnego bł du (next error)
wykonaniu kompilacji. Je li jeste skazany na własne siły - ________________________________________________________________
patrz - nast pne lekcje.
________________________________________________________________ ________________________________________________________________
EOF

SPECJALNE KLAWISZE, które warto pozna .


LEKCJA 4. Jeszcze o IDE C++ .
Oto skrócona tabela z najwa niejszymi kombinacjami klawiszy
słu cymi do "nawigacji" (czyli pro ciej - poruszania si ) w _______________________________________________________________
rodowisku IDE kompilatorów BORLAND C++ i Turbo C++. W trakcie tej lekcji:
1. Dowiesz si wi cej o menu i okienkach w rodowisku IDE.
Przydatne w Borland C++ i Turbo C++ kombinacje klawiszy. 2. Poznasz troch technik "myszologicznych".
________________________________________________________________ 3. Napiszesz i uruchomisz swój drugi program.
Wybór rozkazów z menu: ________________________________________________________________
Alt+F Rozwini cie menu File (operacje na plikach)
Alt+E Rozwini cie menu Edit (edycja tekstu programu)
Alt+S Rozwini cie menu Search (przeszukiwanie) W dolnej cz ci ekranu jest podobny pasek do paska menu,
Alt+R Rozwini cie menu Run (uruchamianie programu) niemniej wa ny, cho o innym przeznaczeniu. Pasek ten jest to
Alt+C Rozwini cie menu Compile (kompilacja) tzw. WIERSZ STATUSOWY (ang. Status Line). Jak wynika z nazwy w
Alt+D Rozwini cie menu Debug (diagnostyka i bł dy) tym wierszu wy wietlane s informacje dotycz ce bie cego stanu
Alt+P Rozwini cie menu Project (program wielomodułowy) (i bie cych mo liwo ci) rodowiska IDE. Zaryzykuj tez , e
Alt+O Rozwini cie menu Option (opcje, konfiguracja) cz sto jeden prosty, własny eksperyment mo e by wi cej wart ni
Alt+W Rozwini cie menu Window (zarz dzanie oknami)
8
wiele stron opisów. Poeksperymentujmy zatem chwil z wierszem [???] ZNIKN Ł PROGRAM ???
statusowym. ________________________________________________________________
C++ chce Ci uchroni przed utrat programu, ale uwa aj! Je li
[???] NIE CHCE SI URUCHOMI ??? odpowiesz Yes - Tak ([Y] lub [Enter]), to nowa wersja programu
________________________________________________________________ zostanie nadpisana na star !
Je li przy starcie kompilatora C++ nast pi komunikat: ________________________________________________________________

System Message [!!!] ZAMYKANIE OKIEN.


Disk is not ready in drive A ________________________________________________________________
[Retry] [Cancel] Mo esz szybciej zamkn okno naciskaj c kombinacj klawiszy
[Alt]-[F3].
(Komunikat systemu C++: Dyskietka w nap dzie A nie gotowa do ________________________________________________________________
odczytu; Jeszcze raz? Zrezygnowa ?)
[!!!]UWAGA
to znaczy, e C++ nie mo e odtworzy ostatniego ekranu ________________________________________________________________
roboczego, poniewa nie udost pniłe mu dyskietki z programami, B d ostro ny podejmuj c decyzj o zapisie wersji programu na
nad którymi ostatnio pracowałe . dysk. Okienko z ostrze eniem pojawi si za ka dym razem przed
________________________________________________________________ zamkni ciem okna edycyjnego z tekstem programu. Je li przy
zamykaniu okna nie pojawi si ostrze enie, to znaczy, e program
w tej wersji, któr widzisz na ekranie został ju zapisany na
W wierszu statusowym wyja nione jest działanie klawiszy dysk.
funkcyjnych F1, F2, itd. Mog tam równie pojawia si ________________________________________________________________
krótkie napisy-wyja nienia dotycz ce np. rozkazu wyró nionego
wła nie w menu. Powinien tam by napis:
A JE LI NIE CHC ZAMYKA OKIEN?
F1 Help F2 Save F3 Load AltF9 Compile F9 Make F10 Menu
W porz dku, nie musisz. W menu Window ([Alt]-[W]) masz do
znaczy to: dyspozycji rozkaz Next (nast pne okno). Mo esz go wybra albo
naciskaj c klawisz [N], albo przy pomocy klawiszy kursora. Ka de
[F1] - Pomoc z okien na Twoim roboczym ekranie ma nazw - nagłówek - np.
[F2] - Zapami tanie bie cego pliku na dysku pod bie c nazw NONAME00.CPP, PIERWSZY.CPP, ale nie tylko. Pierwsze dziesi
(nawet je li t nazw jest NONAME01.CPP, tzn. została nadana okien ma równie swoje numery - podane blisko prawego - górnego
automatycznie i znaczy - o ironio - "BEZNAZWY01.CPP") i w rogu okna w nawiasach kwadratowych - np. [1], [2] itd.
bie cym katalogu. Posługuj c si tym rozkazem mo esz przechodzi od okna do okna
[F3] - Załadowanie do okienka edycyjnego nowego pliku tekstowego nie zamykaj c adnego z okien. Spróbuj!
(np. nowego programu).
[Alt]-[F9] - Kompilacja w trybie "Compile". Jest jeszcze inny sposób przej cia od okna do okna. Je li chcesz
[F9] - Kompilacja w trybie "Make" (jednoczesnej kompilacji i przej do okna o numerze np. [1], [2], [5] itp. powiniene
konsolidacji). nacisn kombinacj klawiszy [Alt]-[1], [Alt]-[5] itp..
[F10] - Uaktywnienie głównego menu. Niestety, tylko pierwsze 9 okien ma swoje numerki.

Mo esz korzysta z listy okien (Window | List) lub klawisza


JAK ZROBI PORZ DEK? funkcyjnego [F6].

W trakcie uruchamiania kompilator korzysta z plików [S] ACTIVE WINDOW - AKTYWNE OKNO.
zewn trznych. C++ stara si by USER FRIENDLY (przyjazny wobec ________________________________________________________________
u ytkownika) i odtworzy taki stan ekranu, w jakim ostatnio Na ekranie mo e si znajdowa jednocze nie wiele okien, ale w
przerwałe prac , co nie zawsze jednak jest korzystne. W wierszu danym momencie tylko jedno z nich mo e by AKTYWNE. Aktywne
okno, to to, w którym miga kursor i w którym aktualnie
statusowym pojawiaj si napisy informuj ce o tym (np: pracujesz. Aktywne okno jest dodatkowo wyró nione podwójn
ramk .
Loading Desktop File . . . ________________________________________________________________

- ładuj plik zawieraj cy konfiguracj ostatniego ekranu


roboczego...). Je li chcesz by na pocz tku [???] Robi "na szaro"?
sesji z C++ ekran był "dziewiczo" czysty, powiniene : ________________________________________________________________

* zmieni nazw pliku [D:]\BORLANDC\BIN\TCDEF.DSK Zwró uwag , e dopóki bie cym aktywnym oknem jest okienko
komunikatów (Message - to w dolnej cz ci ekranu), nie mo esz
na dowoln inn , np. STARY.DSK lub STARY1.DSK, stosuj c np. powtórzy kompilacji programu. Rozkazy Compile | Compile i
polecenie systemu DOS RENAME. [D:] oznacza odpowiedni dla Run | Run b d "zrobione na szaro" (ang. grayed out) - czyli
Twojego komputera dysk. C++ wystartuje wtedy z czystym ekranem i nieaktywne. Najpierw trzeba przej do okna edycji tekstu
programu (np. poprzez klikni cie myszk ).
utworzy nowy plik TCDEF.DSK. ________________________________________________________________

* Plików TCDEF nie nale y usuwa . Kiedy nabierzesz troch wprawy


Rozwi menu Options (opcje).
pliki te znacznie przyspiesz i ułatwi Ci prac z C++. Mo esz to zrobi na wiele sposobów. Najszybciej chyba naciskaj c:

Aby zamkn zb dne okna mo esz zastosowa równie rozkaz Close [Alt]+[O]
(ang. Close - zamknij) z menu Window (okna). Zwró uwag , e
polecenie Close odnosi si do bie cego okna wyró nionego przy Rozwin ło si menu, udost pniaj c nast puj c list polece :
pomocy podwójnej ramki. Aby zamkn bie ce okno, powiniene :
FULL MENUs - Pełne Menu ("s" oznacza, e chodzi o "te" menu w
1. Nacisn klawisze [Alt]-[W] liczbie mnogiej, a nie o pojedyncze menu).
Rozwinie si menu Windows. COMPILER - Kompilator.
2. Wybra z menu rozkaz Close - [C]. MAKE... - dosł. "ZRÓB", dotyczy tworzenia "projektów" (zwró
uwag na wielokropek [...]).
Mo e pojawi si okienko z ostrze eniem: DIRECTORIES... - KATALOGI (znów wielokropek !).
ENVIRONMENT... - OTOCZENIE lub inaczej RODOWISKO.
WARNING: A:\PIERWSZY.CPP not saved. Save? SAVE - ZAPAMI TAJ (UWAGA: To jest zupełnie inne SAVE ni
(UWAGA: plik A:\PIERWSZY.CPP nie zapisany na dysku. Zapisa ?). w menu File. Nie wolno myli tych polece .
Pomyłka grozi utrat tekstu programu!).
9
________________________________________________________________
Popatrz na lini statusow . Je li b dziesz porusza si po menu * Je li zainstalowałe zawarto dyskietki na dysku i wolisz
Option, pod wietlaj c kolejne rozkazy, w wierszu statusowym posługiwa si własnym katalogiem roboczym - wpisz tam
b dzie wy wietlany krótki opis działania wskazanego rozkazu. I odpowiedni cie k dost pu - np. C:\C-BELFER. Je li Twój
tak, powiniene zobaczy kolejno nast puj ce napisy: katalog zagnie d ony jest gł biej (np. w przypadku u ytkowników
sieci Novell) - podaj pełn cie k dost pu - np.:
Full Menus [Off/On]- Use or don't use full set of menu commands. F:\USERS\ADAM\C-BELFER
* Wsz dzie, gdzie w tre ci ksi ki odwołuj si do dyskietki A:
(Stosuj lub nie stosuj pełnego zestawu rozkazów w menu - mo esz konsekwentnie po zainstalowaniu stosowa odpowiedni
domy lnie przyjmowane jest Off/Nie). katalog na dysku stałym, b d na dysku sieciowym.
________________________________________________________________
Compiler - Set compiler defaults for code generation, error
messages and names. 4. Naci nij [Enter].

(Ustaw domy lne parametry pracy kompilatora dotycz ce Spróbuj teraz, znan z poprzedniej lekcji metod , wczyta do
generowania kodu programu, komunikatów o bł dach i nazw). okienka edytora Twój pierwszy program. Musisz wykona
nast puj ce czynno ci:
Make... - Set condition for project-makes.
(Ustawianie warunków do tworzenia projektu). 1. Włó do nap du A: dyskietk z programem PIERWSZY.CPP (je li
jeszcze jej tam nie ma).
Directories... - Set path for compile, link and executable 2. Rozwi menu File, naciskaj c kombinacj klawiszy [Alt]-[F].
files. 3. Wybierz z menu rozkaz Open, naciskaj c klawisz [O].
(Wybierz katalogi i ustaw cie ki dost pu dla kompilacji, Pojawi si znane Ci okienko dialogowe. Zwró uwag na wiersz
konsolidacji i WSKA MIEJSCE - GDZIE ZAPISA PLIK TYPU *.EXE po statusowy. Napis:
kompilacji).
Enter directory path and file mask
Environment... - Make environment wide settings (eg, mouse znaczy:
settings). Wpisz cie k dost pu do katalogu i "wzorzec" nazwy pliku.
(Ustawienie parametrów rozszerzonego otoczenia, np. parametrów
pracy myszki). U yte słowo "wzorzec" oznacza, e wolno Ci wpisa do okienka
tekstowego tak e nazwy wieloznaczne, zawieraj ce znaki "*" i
Save - Save all the settings you've made in the Options menu. "?", np.:

(Powoduje zapami tanie na dysku wszystkich zmian parametrów *.C


roboczych IDE, które ustawiłe , korzystaj c z rozkazów A:\???.C
dost pnych za po rednictwem menu Options.). D:\BORLANDC\SOURCE\P*.*

Ten rozkaz pozwala Ci ustawi konfiguracj IDE "raz na zawsze". itp. (Spróbuj!, zawsze mo esz si wycofa lub zmieni zdanie,
posługuj c si klawiszami [BackSpace], [Shift], [Tab] i [Esc].).
Przygotujmy si do powtórzenia kompilacji programu PIERWSZY.CPP.
Klawisz [Tab] umo liwia Ci skok od okienka do okienka "do
Je li masz na ekranie rozwini te menu Options, wybierz z menu przodu", a [Shift]-[Tab] - "do tyłu". Zgodnie z nazw (ang.
polecenie Directories... . ESCape - ucieka ), klawisz [Esc] pozwala Ci wycofa si z
niewygodnych sytuacji - np. zamkn okienko dialogowe lub zwin
KOMPILACJA ZE WSKAZANIEM ADERSU. rozwini te menu bez adnej akcji.

1. Wska w menu polecenie Directories i naci nij [Enter]. Je li wpiszesz wzorzec nazwy, to w okienku z list zobaczysz
Po poleceniu umieszczony jest wielokropek. Znaczy to, e rozkaz wszystkie pliki wybrane z podanego dysku i z podanego katalogu
nie zostanie wykonany, zanim komputer nie uzyska od Ciebie według zadanego wzorca. Aby wybra plik z listy nale y klawiszem
pewnych dodatkowych informacji. Wiesz ju , e praktycznie
oznacza to dla Ciebie konieczno "wypełnienia" okienka [Tab] przej do okienka z list , klawiszami kursora wskaza
dialogowego. Po wybraniu polecenia Directories ukazało si potrzebny plik i nacisn [Enter].
okienko dialogowe ju "wst pnie wypełnione". Takie "wst pne
wypełnienie" okienka daje Ci pewne dodatkowe informacje. Wynika 4. Wpisz do okienka tekstowego
z niego mianowicie JAKIE PARAMETRY S PRZYJMOWANE A:\PIERWSZY.CPP
DOMY LNIE 5. Naci nij [Enter].
(default).
[!!!]FAST START - SZYBKI START.
W okienku dialogowym masz trzy okienka tekstowe: ________________________________________________________________
Je li chcesz by C++ automatycznie wczytał Twój program do
* Include Directories (Katalog zawieraj cy pliki nagłówkowe, np. okienka edytora, to mo esz zada nazw pliku z tekstem programu
jako parametr w wierszu polecenia, uruchamiaj c C++ np. tak:
STDIO.H, CONIO.H, GRAPHICS.H itp. doł czane do programów).
BC A:\PIERWSZY.CPP
* Library Directories (Katalog zawieraj cy gotowe biblioteki,
zawarte w plikach typu *.LIB,). Je li korzystasz z programu Norton Commander, to mo esz doda do

* Output Directory (Katalog wyj ciowy, w którym po kompilacji pliku NC.EXT nast puj cy wiersz:
b d umieszczane Twoje programy w wersji *.EXE).
C: TC !.!
Pierwsze dwa zostawimy w spokoju. cpp: bc !.!

2. Naci nij dwukrotnie klawisz [Tab]. Kursor wskazuje teraz wówczas wystarczy tylko wskaza odpowiedni plik typu *.C lub
okienko tekstowe Output Directory. .CPP z tekstem programu i nacisn [Enter].
________________________________________________________________
3. Wpisz do okienka tekstowego Output Directory:
A:\ lub C:\C-BELFER Kompilatory Borlanda mog w ró nych wersjach nazywa si ró nie:

znaczy to, e od teraz po wykonaniu kompilacji i utworzeniu TC.EXE, BC.EXE, BCW.EXE (dla Windows), itp.. Sprawd swoj
pliku wykonywalnego typu *.EXE, plik taki zostanie zapisany we wersj kompilatora i wpisz wła ciwe nazwy dodaj c ewentualnie
wskazanym katalogu i na wskazanym dysku/dyskietce. cie ki dost pu - np.:

UWAGA: C: D:\BORLANDC\BIN\BC !.!


10
CPP: WIN C:\BORLANDC\BIN\BCW !.! naci nij [Enter].

[!!!]UWAGA Mo emy teraz wyj z programu C++. Rozwi menu File naciskaj c
________________________________________________________________ klawisze [Alt]-[F] i wybierz z menu rozkaz Quit. Pojawi si
Rozkazy uruchamiaj ce kompilator mog by zło one nawet z 4 okienko z ostrze eniem:
parametrów - np.:
WARNING: A:\PIERWSZY.CPP not saved. Save?
WIN /3 C:\BORLANDC\BIN\BCW C:\C-BELFER\PROGRAMY\P027.CPP (UWAGA: plik A:\PIERWSZY.CPP nie zapisany na dysku. Zapisa ?).

spowoduje: W ten sposób C++ ZNOWU chce Ci uchroni przed utrat programu,
* uruchomienie Windows w trybie rozszerzonym 386 ale uwa aj! Je li odpowiesz Tak ([Y] lub [Enter]), to nowa
* uruchomienie kompilatora w wersji dla Windows - BCW.EXE wersja programu zostanie nadpisana na star ! Je li odpowiesz Nie
* załadowanie pliku z programem - P27.CPP z wskazanego katalogu
________________________________________________________________ [N]

na dysku pozostanie stara wersja programu a nowa


[P002.CPP] zniknie.

Dokonaj w swoim programie nast puj cych zmian: Po wyj ciu z C++ znajdziesz si w jego katalogu roboczym, lub w
________________________________________________________________ tym katalogu bie cym, z którego wydałe rozkaz uruchomienia
#include (stdio.h> kompilatora C++. Aby uruchomi swój program musisz zatem wyda
#include <conio> nast puj cy rozkaz:

main() A:\PIERWSZY.EXE
{ lub krócej
printf("\n"); A:\PIERWSZY
printf("Autor: np. Antoni Kowalski\n");
printf("program: PIERWSZY.CPP \n - wersja II \n"); a je li chcesz si przekona , czy Twój program jest tam, gdzie
getch(); powinien by , mo esz go zobaczy . Napisz rozkaz
}
________________________________________________________________ DIR A:\
lub
******Uwaga: Je li pracujesz w Windows - Z TEGO MIEJSCA******** DIR A:\*.EXE

przy pomocy rozkazów Edit | Copy Aby upewni si całkowicie, e to wła nie ten program, zwró
mo esz przenie program do okna kompilatora uwag na dat i czas utworzenia pliku. Je li masz prawidłowo
poprzez schowek Windows (Clipboard). ustawiony zegar w swoim komputerze, data powinna by dzisiejsza
W oknie kompilatora nale y: a czas - kilka minut temu. Je li co jest nie tak, powiniene
1. Otworzy nowe okno edytora tekstowego: przy pomocy rozkazów systemu DOS: DATE i TIME zrobi porz dek w
File | New swoim systemie. O takich drobiazgach warto pami ta . Pozwoli Ci
2. Wstawi plik ze schowka: to w przyszło ci odró ni nowsze i starsze wersje programów,
Edit | Paste unikn pomyłek i zaoszcz dzi wiele pracy.
--- To okno (AM-Edit) i całego BELFRA mo esz w tym czasie zredukowa
--- Do ikonki.------------------------------------------------------ [Z] 1. - Propozycja zadania - wiczenia do samodzielnego wykonania.
**************************************************************** -------------------------------------------------------------------
****
Spróbuj odszuka plik ródłowy .CPP i plik wynikowy .EXE
Dzi ki dodaniu do tekstu programu funkcji getch(), program nie wychodz c "na chwil " z IDE przy pomocy rozkazu File | DOS
powinien ju tak szybko mign na ekranie i znikn . Zatrzyma Shell.
si teraz i zaczeka na przyci ni cie klawisza. Funkcja getch(), -------------------------------------------------------------------
działa podobnie do:
A teraz zajrzyjmy do rodka do pliku PIERWSZY.EXE. Je li
10 IF INKEY$="" GOTO 10 korzystasz z programu Norton Commander, to masz do dyspozycji
opcje [F3] - View (przegl danie) i [F4] - Edit (edycja). Je li
w Basicu lub Readln w Pascalu. nie korzystasz z NC, musisz wyda nast puj cy rozkaz:

Nazwa pochodzi od GET CHaracter (POBIERZ ZNak, z klawiatury). TYPE A:\PIERWSZY.EXE | C:\DOS\MORE
lub
Skompiluj program PIERWSZY.CPP. Aby to zrobi , powiniene : C:\DOS\EDIT A:\PIERWSZY.EXE

1. Rozwin menu Compile - [Alt]-[C]. Jak widzisz na ekranie, napisy zawarte w programie pozostały
2. Wybra z menu rozkaz Compile - [C]. czytelne, ale to co wida dookoła nie wygl da najlepiej. Na
podstawie tego co widzisz, mo na (na razie ostro nie) wysnu
Ostrze enie WARNING na razie ignorujemy. wniosek, e ani Viewer (przegl darka), ani Edytor, które
doskonale spisuj si przy obróbce plików tekstowych, nie nadaj
Wykonaj kompilacj programu powtórnie przy pomocy rozkazu Run z si do analizy i obróbki programów w wersji *.EXE. Narz dziami,
menu Run. Naci nij kolejno klawisze: które b dziemy musieli stosowa , mog by programy typu
DEBUGGER, PROFILER, LINKER (konsolidator), kompilator i in..
[Alt]-[R], [R]
lub Mam nadziej , e czujesz si w rodowisku IDE ju troch
[Alt]-[R], [Enter] swobodniej, a wi c bierzemy si za drugi program.
__________________________________________________________
Ten sam efekt uzyskasz naciskaj c kombinacj klawiszy EOF
[Ctrl]-[F9].

Uruchom program powtórnie naciskaj c kombinacj klawiszy LEKCJA 5 - DZIAŁANIA PRZY POMOCY MYSZKI I BŁ DY W
[Alt]-[R], [R]. Zwró uwag , e teraz kompilacja nast pi PROGRAMIE.
znacznie szybciej. Tak naprawd C++ stwierdzi tylko, e od ________________________________________________________________
ostatniej kompilacji nie dokonano adnych zmian w programie i Z tej lekcji dowiesz si ,
odst pi od zb dnej kompilacji. Takie wła nie znaczenie ma * Jak posługiwa si myszk w rodowisku IDE (DOS)
komunikat "Checking dependences" (sprawdzam zale no ci, który * O czy nale y pami ta , przy tworzeniu i uruchamianiu
mignie w okienku kompilacji. Po korekcie programu napisy programów.
wygl daj znacznie przyzwoiciej, prawda? Po obejrzeniu napisów * Jak poprawia bł dy w programie.
11
________________________________________________________________ void main(void)

Ka dy program w C++ składa si z instrukcji. Wiele takich


Zanim b dzie mo na kontynuowa eksperymenty, trzeba co zrobi , instrukcji to wywołania funkcji. W C++ rozkaz wywołania i
by robocze okno edytora było puste. Aby otworzy takie nowe wykonania funkcji polega na wpisaniu nazwy funkcji (bez adnego
puste okno edytora nale y: dodatkowego słowa typu run, execute, load, itp.). Tych funkcji
mo e by w programie jedna, b d wi cej. Tworzenie programu w
* Rozwin menu File; C++ z zastosowaniem funkcji (takich jakgdyby mini-programików)
* Wybra z menu rozkaz New (nowy). przypomina składanie wi kszej cało ci z klocków.

Na ekranie monitora otworzy si nowe puste okno zatytułowane Nale y podkre li , e:


"NONAME00.CPP", "NONAME01.CPP", itp (lub "bez nazwy" i o
kolejnym numerze). Ró ne edytoro-podobne aplikacje maj zwyczaj ka dy program w C++ musi zawiera funkcj main() (ang. main -
otwierania okna dla nowego pliku tekstowego i nadawanie mu na główna).
pocz tku jednej z dwóch nazw:
Wykonanie ka dego programu rozpoczyna si wła nie od pocz tku
[S] SŁOWNICZEK: UFO w trybie Edycji funkcji main(). Innymi słowy - miejsce zaznaczone w programie
________________________________________________________________ przy pomocy funkcji main() to takie miejsce, w które komputer
Untitled - niezatytułowany zagl da zawsze na pocz tku wykonania programu i od tego wła nie
Noname - bez nazwy miejsca rozpoczyna poszukiwanie i wykonywanie rozkazów.
(Tak na marginesie UFO to skrót od Unidentified Flying Object -
Niezidentyfikowany Obiekt Lataj cy, gdy przejdziemy do
programowania obiektowego, znajomo tego terminu te Ci si [S] Entry Point
przyda). ________________________________________________________________
________________________________________________________________ ___
Punkt wej cia do programu nazywa si :
Nadanie plikowi dyskowemu z tekstem ródłowym programu jego Program Entry Point
wła ciwej nazwy i zapisanie go na dysku stałym komputera w Taki wła nie punkt wej cia wskazuje słowo main().
okre lonym miejscu nast puje w tym momencie, kiedy po napisaniu Punk wej cia mog mie nie tylko programy .EXE ale tak e biblioteki
programu zapisujesz go na dysk rozkazem: (.DLL - dynamicznie doł czanie biblioteki).
________________________________________________________________
File | Save lub File | Save As... ____

Zapis File | Save oznacza "Rozkaz Save z menu File". Gdy po


opracowaniu programu rozwiniesz menu File i wybierzesz rozkaz Ka da funkcja powinna mie pocz tek i koniec. Pocz tek funkcji w
Save as... (zapisz jako...), pojawi si okienko dialogowe "Save C/C++ zaznacza si przez otwarcie nawiasów klamrowych { a koniec
File as" (zapis pliku jako...). funkcji poprzez zamkni cie } . Pocz tek głównej funkcji main()
to zarazem pocz tek całego programu. Zaczynamy zwykle od
Do okienka edycyjnego "Name" (nazwa) mo esz wpisa nazw , któr umieszczenia w oknie edytora C++ znaków pocz tku i ko ca
chcesz nada swojemu nowemu programowi. Zwró uwag , e mo esz programu.
poda nazw pliku i jednocze nie wskaza miejsce - np.:
main()
Name: {
F:\USERS\ADAM\PROBY\PROGRAM.CPP <-- tu rozbudowuje si tekst programu
}
Po wpisaniu nazwy naci nij klawisz [Enter] lub wybierz klawisz
[OK] w okienku dialogowym myszk . Tytuł okna edytora zmieni si Najpierw naci nij [Enter] i przejd do pocz tku nowej linii.
na wybran nazw . Umie w tej nowej linii znak pocz tku programu - nawias { (lewy
nawias klamrowy). Nast pnie naci nij [Enter] powtórnie i umie
Mo esz równie (je li odpowiedni katalog ju istnieje), wskaza w nast pnej linii prawy nawias klamrowy - }.
wła ciwy katalog w okienku z list "Files" i dwukrotnie
"klikn " lewym klawiszem myszki. [!!!] NAJPIERW Save !!!
________________________________________________________________
Mo esz wskaza myszk okienko edycyjne i nacisn lewy klawisz Zanim jeszcze sko czysz redagowanie programu i si gniesz do
myszki, b d naciska klawisz [Tab] a do momentu, gdy kursor klawiszy [Alt]+[R], pami taj, e przed próbami kompilacji i
zostanie przeniesiony do okienka edycyjnego. Okienko edycyjne to uruchomienia programu zawsze NAJPIERW nale y zapisa program na
to okienko, do którego wpisujesz nazw pliku. W okienku dysk. Je li przy próbach uruchomienia co pójdzie nie tak - masz
edycyjnym (Save File As) naciskaj klawisz [BackSpace] a do pewno , e Twoja praca nie pójdzie na marne. Czasami przy
chwili skasowania zb dnej nazwy pliku i pozostawienia tam tylko próbach uruchamiania programów zdarza si , e bł dy mog
cie ki dost pu - np. A:\PROBY\. Wpisz nazw programu - np. spowodowa zawieszenie komputera. Programista jest wtedy
PROG1.CPP. Po wpisaniu nazwy mo esz nacisn [Enter] lub wskaza zmuszony do restartu komputera, przy wył czeniu komputera to, co
myszk klawisz [OK] w okienku i nacisn lewy klawisz myszki. było tylko na ekranie i tylko w pami ci operacyjnej - niestety
Je li tak zrobisz w przypadku pustego okienka NONAME00.CPP - znika bezpowrotnie.
kompilator utworzy na dysku we wskazanym katalogu plik o zadanej ________________________________________________________________
nazwie - np. A:\PROBY\PROGR1.CPP (na razie pusty). Zmieni si
tak e nagłówek (nazwa) okienka edycyjnego na ekranie roboczym. Aby zapisa tekst programu na dysk nale y:

[!!!]UWAGA. * Wybra z menu rozkaz File | Save As... albo


________________________________________________________________ * Nacisn klawisz funkcyjny [F2] (działa jak File | Save)
Wszystkie pliki zawieraj ce teksty programów w j zyku C++
powinny ˙mie charakterystyczne rozszerzenie *.CPP (CPP to skrót Po wydaniu rozkazu Save mo esz by pewien, e Twój program jest
od C Plus Plus), lub .C. Po tym rozszerzeniu rozpoznaje te bezpieczny i komputer mo e si spokojnie "ZAWIESI " nie czyni c szkody.
programy kompilator. Nadanie rozszerzenia .C lub .CPP mo e Aby skompilowa i uruchomi ten program nale y:
dodatkowo wpływa na sposób kompilacji programu. Zanim wyja nimy
te szczegóły, b dziemy zawsze stosowa rozszerzenie .CPP. * Wybra rozkaz Run | Run
Wszelkie inne rozszerzenia (.BAK, .TXT, .DEF, itp.) nie * Nacisn kombinacj klawiszy [Ctrl]+[F9]
przeszkadzaj w edycji i kompilacji programu, ale mog w
niejawny sposób wpłyn na sposób kompilacji. Podobnie jak wcze niej, kompilator wy wietli na ekranie okienko
________________________________________________________________ zawieraj ce komunikaty o przebiegu kompilacji. Po zako czeniu
kompilacji nast pi wykonanie programu. Na moment mignie roboczy
Je li masz puste robocze okno edytora - mo esz wpisa tam ekran u ytkownika. Na nieszcz cie program nic nie robi, wi c
swój własny nowy program. Wpisz: nic si tam nie wydarzy.

12
Aby przeanalizowa , jak kompilator C++ reaguje na bł dy w Twojego programu, lecz s zawarte w jednym z "fabrycznych"
programach, zmie tekst w pierwszej linii programu na bł dny: plików bibliotecznych zainstalowanych wraz z kompilatorem C++.

vod main(void)
{ [S]
} Function - Funkcja
Fuction call - Wywołanie funkcji
Spróbuj powtórnie skompilowa i uruchomi program. ________________________________________________________________

Kompilator wy wietli okienko, w którym pojawi si komunikat o Funkcja to co przypominaj ce mini-program. Funkcja zawiera
bł dach. W taki wła nie sposób kompilator taktownie informuje list rozkazów słu cych do wykonania typowych operacji (np.
programist , e nie jest a taki dobry, jak mu si czasami czyszczenie ekranu, wy wietlanie menu, wydruk, czy sortowanie
wydaje. Komputer jest niestety pedantem. Oczekuje (my, ludzie listy imion). W programach posługujemy si zwykle wieloma
tego nie wymagamy) absolutnej dokładno ci i elaznego funkcjami. Poznałe ju najwa niejsz funkcj główn - main(). W
przestrzegania pewnych zasad. "Zjadaj c" jedn liter naruszyłe C/C++ mo esz posługiwa si gotowymi funkcjami (tzw.
takie zasady, co zauwa ył kompilator. bibliotecznymi) a tak e tworzy nowe własne funkcje. Na razie
b dziemy posługiwa si gotowymi funkcjami dostarczanymi przez
W górnej cz ci ekranu kompilator wyró nił paskiem pod wietlenia producenta wraz z kompilatorem C++.
ten wiersz programu, który zawiera bł d. W dolnej cz ci ekranu, ________________________________________________________________
w tzw. okienku komunikatów (ang. Message window) pojawił si
komunikat, jaki rodzaj bł du został wykryty w Twoim programie. W
Wł cz kompilacj i prób uruchomienia programu.
danym przypadku komunikat brzmi: Kompilator stwierdzi, e program zawiera bł dy.
Naci nij dowolny klawisz, by znikn ło okienko kompilacji.
Declaration syntax error - Bł d w składni deklaracji Kompilator napisał:

Co to jest deklaracja? Error: Function 'clrscr' should have a prototype

Pierwsza linia (wiersz) funkcji nazywa si deklaracj funkcji. (Funkcja 'clrscr' powinna mie prototyp)
Taka pierwsza linia zawiera informacje wa ne dla kompilatora:
nazw funkcji oraz tzw. typy warto ci u ywanych przez funkcj . [???] O co mu chodzi?
Komunikat o bł dzie oznacza, e nieprawidłowo została napisana ________________________________________________________________
nazwa funkcji lub nazwy typów warto ci, którymi posługuje si Tzw. PROTOTYP funkcji to co bardzo podobnego do deklaracji
funkcja. W naszym przypadku słowo void zostało przekr cone na funkcji. Prototyp słu y do przekazania kompilatorowi pewnych
"vod", a słowo to ma w C++ specjalne znaczenie. Słowo "void" informacji o funkcji jeszcze przed u yciem tej funkcji w
jest cz ci j zyka C++, a dokładniej - słowem kluczowym (ang. programie. Dla przykładu, gdy pisałe pierwsz lini programu:
keyword).
void main(void)
[S] Function declaration - Deklaracja funkcji.
Keyword - Słowo kluczowe. podałe nie tylko nazw funkcji - main, lecz tak e umie cili my
________________________________________________________________ tam dwukrotnie słowo void. Dokładnie o znaczeniu tych słów
napiszemy w dalszej cz ci ksi ki. Na razie zwró my jedynie
Function declaration - Deklaracja funkcji. uwag , e podobnych "dodatkowych" informacji dotycz cych funkcji
Pierwszy wiersz funkcji jest nazywany deklaracj funkcji. Ten clrscr() w naszym programie nie ma.
wiersz zawiera informacje dla kompilatora C++ pozwalaj ce ________________________________________________________________
poprawnie przetłumaczy funkcj na kod maszynowy.

Keyword - Słowo kluczowe. Zwró uwag , e zapisy:


to specjalne słowo wchodz ce w skład j zyka programowania. Słowa
main() int main(void) main(void) {
kluczowe to słowa o zastrze onym znaczeniu, które mo na stosowa { { } }
w programach wył cznie w przewidzianym dla nich sensie.
________________________________________________________________ }

s całkowiecie równowa ne. Fakt, e słowa kluczowe void (w nawiasie)


Popraw bł d w tek cie. Aby robocze okienko edytora stało si i int (przed funkcj i tylko tam!) mog zosta pomini te wskazuje, e s
oknem aktywnym, wska kursorem myszki dowolny punkt w oknie to warto ci domy lne (default settings) przyjmowane automatycznie.
edytora i naci nij lewy klawisz myszki, albo naci nij klawisz
[F6]. Zmie słowo "vod" na "void". Przy pomocy klawiszy ze Funkcja clrscr() została napisana przez programistów z firmy
strzałkami umie migaj cy kursor po prawej stronie nawiasu { BORLAND i znajduje si gdzie w osobnym pliku doł czonym do
sygnalizuj cego ˙pocz tek programu i naci nij [Enter]. Spowoduje kompilatora C++. Aby móc spokojnie posługiwa si t funkcj w
to wstawienie pomi dzy pocz tek a koniec programu nowej pustej swoich programach, powiniene doł czy do swojego programu
linii i umieszczenie kursora na pocz tku nowego wiersza. Wpisz informacj w jakim pliku dyskowym znajduje si opis funkcji
do nowego wiersza instrukcj oczyszczenia ekranu (odpowiednik clrscr(). Taki (do szczegółowy) opis funkcji nazywa si
instrukcji CLS w Basicu): wła nie prototypem funkcji. Aby doda do programu t (niezb dn )
informacj
clrscr();
* naci nij [F6] by przej do okna edytora
W C++ clrscr() oznacza wywołanie funkcji czyszcz cej roboczy * ustaw migaj cy kursor na pocz tku tekstu programu
ekran programu (User screen). Nazwa funkcji pochodzi od skrótu: * naci nij [Enter] dwukrotnie, by doda dwie nowe puste linie do

CLeaR SCReen - czy ekran. tekstu programu


* na samym pocz tku programu wpisz:
e to funkcja - mo na rozpozna po dodanej za nazw parze
nawiasów okr głych - (). W tym jednak przypadku wiersz: #include <conio.h>

clrscr(); Takie specjalne linie (zwró uwag na pod wietlenie)


rozpoczynaj ce si od znaku # (ASCII 35) nie s wła ciwie
stanowi nie deklaracj funkcji, lecz wywołanie funkcji (ang. normaln cz ci składow programu. Nie stanowi one jednej z
function call). C++ znalazłszy w programie wywołanie funkcji instrukcji programu, mówi cej komputerowi CO NALE Y ROBI , lecz
wykona wszystkie rozkazy, które zawiera wewn trz funkcja stanowi tzw. dyrektyw (rozkaz) dla kompillatora C++ - W JAKI
clrscr(). Nie musisz przejmowa si tym, z jakich rozkazów SPOSÓB KOMPILOWA PROGRAM. Dyrektywa kompilatora (ang.
składa si funkcja clrscr(). Te rozkazy nie stanowi cz ci compiler
13
directive) powoduje dokonanie okre lonych działa przez 6. Wpisz do okienka edytora tekst programu:
kompilator na etapie tłumaczenia programu na kod maszynowy. W
danym przypadku dyrektywa [P003.CPP ]
/* Program przykladowy: _DRUGI.CPP */
#include ....

(ang. include - wł cz, doł cz) powoduje wł czenie we wskazane # include <conio.h> /* zwró uwag , e tu NIE MA [;] ! */
miejsce zawarto ci zewn trznego tekstowego pliku dyskowego - np.: # include <stdio.h> /* drugi plik nagłówkowy */

CONIO.H, int main() /* tu tez nie ma rednika [;] ! */


{
(plik CONIO.H float x, y;
nazywany ˙tak e "plikiem nagłówkowym" znajduje si w podkatalogu float wynik;
\INCLUDE). Kompilator doł cza zawarto pliku CONIO.H jeszcze
przed rozpocz ciem procesu kompilacji programu. clrscr();
printf("Zamieniam ulamki zwykle na dziesietne\n");
Naci nij kombinacj klawiszy [Ctrl]+[F9]. Spowoduje to printf("\nPodaj licznik ulamka: ");
kompilacj i uruchomienie programu (Run). Przykładowy program scanf("%f", &x); /* pobiera liczb z klawiatury */
powinien tym razem przekompilowa si bez bł dów. Po dokonaniu printf("\nPodaj mianownik ulamka: ");
kompilacji powinien szybko błysn ekran u ytkownika. Po tym scanf( "%f", &y);
błysku powinien nast pi powrót do roboczego rodowiska IDE
kompilatora C++. Je li nie zd yłe si przyjrze i chcesz wynik = x / y; /* tu wykonuje sie dzielenie */
spokojnie sprawdzi , co zrobił Twój program - naci nij
kombinacj klawiszy [Alt]+[F5]. printf("\n %f : %f = %f", x, y, wynik);
Dzi ki działaniu funkcji clrscr() ekran b dzie całkowicie printf("\n nacisnij dowolny klawisz...\n");
czysty.
getch(); /* program czeka na nacisniecie klawisza. */
[S] Compiler directive - DYREKTYWA KOMPILATORA
________________________________________________________________ return 0; //<-- zwrot zera do systemu
}
Dyrektywa kompilatora to rozkaz wyja niaj cy kompilatorowi C++ w
jaki sposób dokonywa kompilacji programu. Dyrektywy kompilatora
zawsze rozpoczynaj si od znaku # (ang. hash). UWAGA:
Kompilatory C++ posiadaj pewien dodatkowy program nazywany ________________________________________________________________
PREPROCESOREM. Preprocesor dokonuje przetwarzania tekstu _
programu jescze przed rozpocz ciem wła ciwej kompilacji. * Komentarze uj te w [/*.....*/] mo esz pomin . Komentarz jest
Dokładniej rzecz bior c #include jest wła ciwie dyrektyw przeznaczony dla człowieka. Kompilator ignoruje całkowicie
preprocesora (szczegóły w dalszej cz ci ksi ki). komentarze i traktuje komentarz jak puste miejsce, a dokładniej
________________________________________________________________ - tak samo jak pojedyncz spacj . Komentarz w C++ mo e mie dwie
formy:

[Z] - Propozycje zada do samodzielnego wykonania. /* Tekst komentarza */


________________________________________________________________ // Tekst komentarza
1. Spróbuj poeksperymentowa "zjadaj c" kolejno ró ne elementy w
w drugim przypadku ogranicznikiem pola komentarza jest koniec
poprawnie działaj cym na pocz tku programie: wiersza.

- litera w nazwie funkcji * Spacjami i TABami mo esz operowa dowolnie. Kompilator


- rednik na ko cu wiersza ignoruje tak e puste miejsca w tek cie. Nie nale y natomiast
- cudzysłów obejmuj cy tekst do wydrukowania stosowa spacji w obr bie słów kluczowych i identyfikatorów.
- nawias ( lub ) w funkcji printf() ________________________________________________________________
- nawias klamrowy { lub }
- znak dyrektywy #
- cał dyrektyw #include <stdio.h> 7. Skompiluj program [Alt]-[C], [M] lub [Enter].

Porównaj komunikaty o bł dach i zgłaszan przez kompilator 8. Popraw ewentualne bł dy.


liczb bł dów. Czy po przekłamaniu jednego znaku kompilator
zawsze zgłasza dokładnie jeden bł d? 9. Uruchom program rozkazem Run, naciskaj c [Alt]-[R], [R].
________________________________________________________________
10. Zapisz wersj ródłow programu DRUGI.CPP na dyskietk A:\
________________________________________________________________ stosuj c tym razem SHORTCUT KEY - klawisz [F2].
______
EOF [S!] scanf() - SCANing Function - Funkcja SKANuj ca.
________________________________________________________________
Funkcja pobiera ze standardowego urz dzenia wej cia- zwykle z
klawiatury podan przez u ytkownika liczb lub inny ci g znaków.
LEKCJA 6 - NAST PNY PROGRAM - KOMPUTEROWA
ARYTMETYKA. Działa podobnie do funkcji INPUT w Basicu, czy readln w Pascalu.
________________________________________________________________
W trakcie tej lekcji napiszesz i uruchomisz nast pny program * float - do Floating Point - "Pływaj cy" - zmienny przecinek.
wykonuj cy proste operacje matematyczne. Słowo kluczowe słu ce do tzw. DEKLARACJI TYPU ZMIENNEJ lub
________________________________________________________________ funkcji. Oznacza liczb rzeczywist np.: float x = 3.14;

Aby przyst pi po wyja nieniach do pracy nad drugim programem, * int - od Integer - całkowity.
powiniene wykona nast puj ce czynno ci: Słowo kluczowe słu ce do deklaracji typu zmiennej lub funkcji.
Oznacza liczb całkowit np.: 768.
1. Zrób porz dek na ekranie. Zamknij rozkazem Close z menu
Window zb dne okna (mo esz posłu y si kombinacj [Alt]-[F3]). * #include - Wł cz.
2. Rozwi menu File. Dyrektywa wł czaj ca cały zewn trzny plik tekstowy. W tym
3. Wybierz z menu rozkaz Open... przypadku wł czone zostały dwa tzw. pliki nagłówkowe:
4. Wpisz do okienka tekstowego: CONIO.H i STDIO.H.
A:\DRUGI.CPP
5. Naci nij [Enter]. * CONIO.H - CONsole Input/Output.
14
Plik nagłówkowy zawieraj cy prototypy funkcji potrzebnych do main()
obsługi standardowego Wej cia/Wyj cia na/z konsoli (CONsole). {
Plik zawiera mi dzy innymi prototyp funkcji clrscr(), potrzebnej int i;
nam do czyszczenia ekranu.
printf("Dziesi liczb pseudo-losowych od 0 do 99\n\n");
*STDIO.H - STanDard Input/Output for(i=0; i<10; i++)
Plik nagłówkowy zawieraj cy prototypy funkcji potrzebnych do printf("%d\n", rand() % 100);
obsługi standardowego Wej cia/Wyj cia na/z konsoli (Input - return 0;
Wej cie, Output - Wyj cie). Plik zawiera mi dzy innymi prototyp }
funkcji printf(), potrzebnej nam do drukowania wyników na
ekranie. Przykad3
--------------------
return - słowo kluczowe: Powrót, zwrot. #include <stdlib.h>
#include <stdio.h>
Po wykonaniu programu liczba 0 (tak kazali my programowi #include <time.h>
rozkazem return 0;) jest zwracana do systemu operacyjnego, w
naszym przypadku do DOSa. Zwró uwag , e nie pojawiło si tym void main()
razem ostrze enie WARNING podczas kompilacji. {
________________________________________________________________ randomize();
printf("Liczby pseudolosowe z zakresu: 0-99 --> %d\n", random (100));
}
OPERATORY ARYTMETYCZNE C++.
Przykład 4
C++ potrafi oczywi cie nie tylko dzieli i mno y . Oto tabela -----------------
operatorów arytmetycznych c i C++. #include <stdlib.h>
#include <stdio.h>
OPERATORY ARYTMETYCZNE j zyka C++. #include <time.h>
________________________________________________________________
int main(void)
Operator Nazwa Tłumaczenie Działanie {
________________________________________________________________ int i;

+ ADDition Dodawanie Suma liczb randomize();


- SUBstraction Odejmowanie Ró nica liczb printf("Liczby pseudolosowe: 0 to 99\n\n");
* MULtiplication Mno enie Iloczyn liczb for(i=0; i<10; i++)
/ DIVision Dzielenie Iloraz liczb printf("%d\n", rand() % 100);
% MODulus Dziel Modulo Reszta z dzielenia return 0;
________________________________________________________________ }

Zwró uwag , e to randomize() uruchamia generator liczb pseudolosowych,


Przykładowe wyniki niektórych operacji arytmetycznych. czyli jakgdyby "wł cza b ben maszyny losuj cej".
________________________________________________________________ ________________________________________________________________

Działanie (zapis w C++) Wynik działania


________________________________________________________________ Wykonaj z programem DRUGI.CPP kilka eksperymentów.

5+7 12 [Z]
12 - 7 5 ________________________________________________________________
3*8 24 1. Zamie operator dzielenia na operator mno enia [*]:
10 / 3 3.333333
10 % 3 1 wynik = x * y; /* tu wykonuje sie mno enie */
________________________________________________________________
i napis w pierwszej funkcji printf() na np. taki:

printf( "Wykonuje mnozenie liczb" );


[???] Czym ró ni si dzielenie / od % ?
________________________________________________________________ Uruchom program. Sprawd poprawno działania programu w
Operator dzielenia modulo % zamiast wyniku dzielenia - daje szerokim zakresie liczb. Przy jakiej wielko ci liczb pojawiaj
rzeszt z dzielenia. Dla przykładu, dzielenie liczby 14 przez si bł dy?
liczb 4 daje wynik 3, reszta z dzielenia 2. Wynik operacji
2. Zmie nazwy zmiennych x, y, wynik na inne, np.:
14%4 to_jest_liczba_pierwsza,
to_jest_liczba_druga,
b dzie wi c wynosi 2. Operator ten jest niezwykle przydatny np. itp.
przy sprawdzaniu podzielno ci, skalowaniu, okre laniu zakresów Czy C++ poprawnie rozpoznaje i rozró nia takie długie nazwy?
liczb przypadkowych, itp.. Kiedy zaczynaj si kłopoty? Sprawd , czy mo na w nazwie
zmiennej u y spacji? Jaki komunikat wy wietli kompilator?
Przykłady generacji liczb pseudolosowych wybiegaj nieco w przyszło , ________________________________________________________________
ale postanowiłem w Samouczku umie ci je razem. Po przestudiowaniu
tworzenia p tli programowych mo esz wróci do tej lekcji i rozwa y [???] PRZEPADŁ PROGRAM ???
przykłady po raz wtóry. ________________________________________________________________
Nie przejmuj si . Wersja pocz tkowa programu DRUGI.CPP jest na
Przykład 1: dyskietce doł czonej do niniejszej ksi ki (tam nazywa si
DRUGI.CPP).
randomize(); Zwró uwag , e kompilator C++ tworzy automatycznie kopie
int X=ramdom(); zapasowe plików ródłowych z programami i nadaje im standardowe
X = X % 10; rozszerzenie *.BAK. Zanim zatem zaczniesz si denerwowa ,
sprawd , czy kopia np. DRUGI.BAK nie jest wła nie t wersj
Przykład 2: programu, która Ci "przepadła".
--------------------- ________________________________________________________________
#include <stdlib.h> /* Zwróc uwag na doł czony plik */
#include <stdio.h> ________________________________________________________________
__
15
EOF # include <a:\poltekst.h>
LEKCJA 7. Z czego składa si program. program
_______________________________________________________________ poczatek
W trakcie tej lekcji: czysty_ekran
* Dowiesz si co robi , je li t sknisz za Pascalem. drukuj ("Ten program - POKUS.CPP ");
* Zapoznasz si wst pnie z preprocesorem C++. drukuj ("Jest napisany po polsku ");
* Poznasz dokładniej niektóre elementy j zyka C++. drukuj ("a mimo to Turbo C++ go rozumie!");
_______________________________________________________________ czekaj;
koniec
Zanim zagł bimy si w szczegóły działania preprocesora i
kompilatora, dla zilustrowania mechanizmu działania dyrektyw 5. Uruchom program [Alt]-[R], [R]. Je li wyst pi bł dy,
popełnimy art programistyczny. Nie ma nic gorszego ni spali skoryguj ewentualne niezgodno ci z oryginałem. Ostrze enie
dobry art, upewnijmy si wi c najpierw, czy nasza "WARNING" mo esz zignorowa .
"czarodziejska kula" jest gotowa do magicznych sztuczek. UWAGA: MUSI ZOSTA ZACHOWANA IDEALNA ZGODNO !
Sprawd , czy na dyskietce znajduj si pliki
6. Zamknij okno edytora rozkazem Close (z menu Window). Zapisz
A:\PASCAL.H program HOKUS.C w wersji ródłowej na dyskietk A:.
A:\POLTEKST.H
WYJA NIENIE SZTUCZEK - PREPROCESOR C++ CPP.EXE.
Je li nie, to przed zabaw w magiczne sztuczki programistyczne
musisz odtworzy te pliki z zapasowej kopii dyskietki, któr A teraz wyja nienie naszych magicznych sztuczek. Je li jeste
sporz dziłe przed rozpocz ciem LEKCJI 1. niecierpliwy, na pewno ju sam zajrzałe do plików PASCAL.H i
POLTEKST.H, bo jest chyba oczywiste od pocz tku, e to tam
Je li masz ju oba pliki, to wykonaj nast puj ce czynno ci: wła nie musi ukrywa si to wszystko, co pozwala nam robi nasze

1. Włó do nap du A: dyskietk z plikami PASCAL.H i POLTEKST.H. hokus-pokus. Skorzystali my z pewnej nie wyst puj cej ani w
2. Uruchom kompilator C++. Pascalu, ani w Basicu umiej tno ci j zyków C i C++ - a
mianowicie z PREPROCESORA.
PROGRAMY HOKUS.EXE i POKUS.EXE - czyli sztuczki z Preprpcesorem
C++ Najcz ciej stosowanymi dyrektywami preprocesora s :

1. Zrób porz dek na ekranie - pozamykaj zb dne okna. # include - wł cz


2. Naci nij klawisz [F3]. Pojawi si znajome okienko dialogowe i
"Open". # define - zdefiniuj
3. Wpisz do okienka tekstowego nazw nowego programu:
A:\HOKUS.C Do rozpoznania dyrektyw preprocesora słu y znak (#) - HASH.
i naci nij [Enter].
4. Wpisz nast puj cy tekst programu: Zwró uwag , e zapisy

[P004.CPP] #include
# include
#include <a:\pascal.h>
s całkowicie równowa ne. Poza tym dyrektywy preprocesora nie
Program ko cz si rednikiem.
Begin
Write("Ten program jest podobny"); Działanie preprocesora (czyli wst pne przetwarzanie tekstu
Write(" do Turbo Pascala "); programu jeszcze przed przyst pieniem do kompilacji) polega na
Write(" tak tez mozna pisac w BORLAND C++ !"); zast pieniu w tek cie programu jednych ła cuchów znaków przez
Readln; inne. Takie pary mo emy "zada " preprocesorowi wła nie dyrektyw
End
#define. Nasze nagłówki wygl daj nast puj co:

5. Uruchom program [Ctrl]-[F9]. Je li wyst pi bł dy, skoryguj PASCAL.H:


ewentualne niezgodno ci z oryginałem. Ostrze enie "WARNING" _______________________________________________________________
mo esz zignorowa . # include <stdio.h>
# define Program main()
UWAGA: MUSI ZOSTA ZACHOWANA IDEALNA ZGODNO z # define Begin {
tekstem # define Writeln printf
oryginału! # define Readln getch()
# define End }
6. Uruchom program rozkazem Run [Alt]-[R], [Enter]. Zwró uwag , ________________________________________________________________

e powtórna kompilacja przebiega szybciej, je li w mi dzyczasie POLTEKST.H:


nie dokonałe zmian w programie. ________________________________________________________________
7. Zamknij okno edytora rozkazem Close (z menu Window). Zapisz # include <stdio.h>
program HOKUS.CPP w wersji ródłowej na dyskietk A:. # define program main()
# define poczatek {
A teraz nast pna sztuczka, na któr pozwala C++. # define koniec }
# define czysty_ekran clrscr();
Utworzymy nast pny program POKUS.CPP. # define drukuj printf
# define czekaj getch()
1. Wykonaj czynno ci z pp. 1 i 2 z poprzedniego przykładu. ________________________________________________________________
2. Otwórz okienko nowego programu - File | Open (np. klawiszem
[F3]) i wpisz nazw programu. Mo esz zastosowa równie File | Zwró uwag , e warunkiem poprawnego zadziałania preprocesora
New. jest zrezygnowanie ze spacji wewn trz ła cuchów znakowych,
spacje bowiem w preprocesorze rozdzielaj dwa ła cuchy znaków - np.
A:\POKUS.CPP
"drukuj"
3. Naci nij [Enter].
4. Wpisz tekst programu: - ten ZA KTÓRY CHCEMY CO PODSTAWI oraz np.

[P005.CPP] "printf"

16
- ten, KTÓRY NALE Y PODSTAWIA . Cz sto w programach - a poszczególne pliki - modułami lub elementami składowymi
zauwa ysz ła cuchy znaków pisane w do specjalny sposób: projektu:

napisy_w_których_unika_si _spacji. * plik nagłówkowy - NAZWA.H


* moduł główny - NAZWA.CPP (ten i tylko ten zawiera funkcj
ELEMENTY PROGRAMU W J ZYKU C++. main())
* moduły pomocnicze - NAZWA2.CPP, NAZWA3.CPP, itp
Uogólniaj c, program w j zyku C++ składa si z nast puj cych * pliki z zasobami typu menu, okienka dialogowe, itp - NAZWA.RC,
elementów:
NAZWA.DLG
1. Dyrektyw preprocesora. Przykład: * wreszcie plik instrukta owy - jak z tego wszystkiego zrobi
ko cow aplikacj . W zale no ci od wersji kompilatora pliki
#define drukuj printf instrukta owe mog mie nazwy: NAZWA.PRJ (Project - BORLAND),
NAZWA.IDE, a dla programu MAKE - MAKEFILE, NAZWA.MAK,
Działanie: W tek cie programu PONI EJ niniejszej dyrektywy NAZWA.NMK,
zast p wszystkie ła cuchy znaków "drukuj" ła cuchami znaków
"printf". itp.
W rodowisku Windows wyst puje jeszcze zwykle w składzie
#include <D:\KATALOG\nazwa.roz> projektów aplikacji tzw. plik definicji sposobu wykorzystania
zasobów - NAZWA.DEF.
Działanie: W to miejsce pliku wstaw zawarto pliku tekstowego ________________________________________________________________
NAZWA.ROZ z katalogu KATALOG na dysku D:.
[S!] void - czyli nijaki.
2. Komentarzy. Przykład: ________________________________________________________________
Słowa kluczowe:
// Tu obliczamy sum lub /*To jest komentarz*/ void - pusty, wolny, nieokre lony, avoid - unika .
main - główny, główna.
3. Deklaracji. Przykład: return - powrót, zwrot.
KA DY PROGRAM musi zawiera deklaracj funkcji main (ang. main - Nazwa funkcji:
główna). Funkcja ta cz sto jest bezparametrowa, co mo na exit() - wyj cie.
zaakcentowa wpisuj c w nawiasy słowo kluczowe void: ________________________________________________________________

main(void) Po nazwie funkcji main() NIE NALE Y stawia rednika (;).


Przy pomocy tej funkcji program kontaktuje si z systemem
lub pisz c puste nawiasy: operacyjnym. Parametry funkcji main, to te same parametry z
którymi uruchamiamy nasz program w systemie DOS. Np. rozkaz
main()
FORMAT A:
4. Instrukcji.
oznacza, e do programu przekazujemy parametr A:.
i++;
Poniewa w ka dym programie oprócz nagłówka funkcji:
Działanie: Dokonaj inkrementacji zmiennej i, tzn. wykonaj
operacj i:=i+1 main(void)

[???] Dla dociekliwych - kilka słów o funkcji main() podajemy równie tzw. ciało funkcji, np.:
________________________________________________________________
Funkcja main() wyst puje najcz ciej w nast puj cych {
(równowa nych) postaciach: printf("wydrukuj cokolwiek");
return 0;
main() int main() int main(void) }

- program w momencie uruchomienia nie pobiera adnych argumentów jest to jednocze nie DEFINICJA FUNKCJI main().
Zwró uwag , e funkcja printf() nie jest w powy szym
z wiersza rozkazu --> () lub (void) przykładzie w aden sposób ani deklarowana ani definiowana.
- program zwraca po zako czeniu jedn liczn (int = integer - Wiersz:
liczba całkowita) do systemu operacyjnego informuj c go w taki
sposób, czy wykonał si do ko ca i bezbł dnie i czy mo na go printf("pisz!");
usun z pami ci (bywaj tak e programy rezyduj ce w pami ci -
tzw. TSR, o czym system operacyjny powinien "wiedzie "). stanowi WYWOŁANIE funkcji printf() z parametrem 'pisz!' -
ła cuchem znaków, który nale y wydrukowa .
void main() void main(void) W C++ nawet je li nawiasy przeznaczone w funkcji na przekazanie
jej argumentów s puste - musz by obecne. Poprawne wywołanie
- program nie pobiera i nie zwraca adnych paramatrów. funkcji w j zyku C++ mo e mie nast puj c form :
Główna funkcja main() mo e w rodowisku okienkowym przeobrazi
si w główn funkcj okienkow : nazwa_funkcji();

WinMain(.....) nazwa_funkcji(par1, par2, par3, .....);

a w rodowisku obiektowym w zmienna = nazwa_funkcji(par1, par2, ...);

OwlMain(....) Funkcja w momencie jej wywołania uzyskuje przekazane jej


parametry. S to tzw. ARGUMENTY FUNKCJI. Aby to wszystko
OWL - biblioteka obiektów dla Windows - Object Windows Library. bardziej przypominało to, co znasz ze szkoły popatrzmy na
analogi . W zapisie:
W nawiasach funkcji main(), WinMain() i OwlMain() mog pojawi
si parametry (argumenty) pobierane przez program w momencie y = sin(x) lub y = sin(90)
uruchomienia z wiersza rozkazu lub od rodowiska operacyjnego
(szczegóły w dalszej cz ci ksi ki). x - oznacza argument funkcji, który mo e by zmienn (w szkole
Programy w C++ mog składa si z wielu plików dyskowych. Typowy nazywałe zmienne "niewiadomymi")
y - oznacza warto zwracan "po zadziałaniu" funkcji
program zawiera. Nazywa si to zwykle projektami wielomodułowymi sin() - oznacza nazw funkcji. Zastosowanie funkcji b dziemy w
programach nazywa "wywołaniem funkcji".
17
teraz wykona nast puj ce czynno ci:
J zyk C++ operuje wył cznie poj ciem FUNKCJI. W C ani w C++ nie
ma podziału na FUNKCJE i PROCEDURY. * posługuj c si klawiszami kursora (ze strzałkami) odszuka w
spisie nazw funkcji
Ka da funkcja mo e by w programie wywoływana wielokrotnie. albo
Ka de wywołanie funkcji mo e nast powa z innymi argumentami. * rozpocz pisanie nazwy funkcji na klawiaturze (system Help
Funkcja mo e w wyniku swojego działania zmienia warto jakiej sam wyszuka w spisie wypisan w ten sposób nazw )
* nacisn [Enter]
zmiennej wyst puj cej w programie. Mówimy wtedy, e funkcja Przeniesiesz si do okienka opisu danej funkcji. Na samym
ZWRACA warto do programu. Funkcja main() jest funkcj pocz tku w okienku ka dej funkcji podana jest nazwa pliku
szczególn , która "zwraca" warto do systemu operacyjnego, w nagłówkowego, w którym znajduje si prototyp funkcji. Nawet
którym pracuje program. Zapis: je li nie jeste biegłym anglist , łatwo rozpoznasz pliki
nagłówkowe - po charakterystycznych rozszerzeniach .H (rzadziej
main() lub int main() .HPP. Charakterystyczne rozszerzenie *.H pochodzi od "plik
{ { nagłówkowy" - ang. Header file).
return 5; exit(5); ________________________________________________________________
} }
Funkcja printf() zwraca warto całkowit typu int:
oznacza:
1. Funkcja main jest bezparametrowa (nie przyjmuje adnych * liczb bajtów przesłanych na standardowe urz dzenie wyj cia;
argumentów z zewn trz). * w przypadku wyst pienia bł du - kod znaku EOF.
2. Funkcja main zwraca jako wynik swojego działania liczb
całkowit typu int (ang. INTeger - całkowita). Zwró uwag , e [S!]
jest to domy lny sposób działania funkcji main(). Je li nie EOF - End Of File - znak ko ca pliku.
napiszemy przed funkcj main() słowa "int" - kompilator C++ doda EOL - End Of Line - znak ko ca linii.
Indicator - znak, wska nik (nie myli z pointerem !)
je sobie automatycznie. Je li wiadomie nie zamierzamy zwraca
do systemu operacyjnego adnych informacji - musimy wyra nie [???] SK D TO WIADOMO ?
napisa tam "void". ________________________________________________________________
3. Funkcja zwróci do systemu DOS warto 5. Zwró uwag na Kody EOF, EOL s tzw. predefiniowanymi stałymi. Ich szyfrowanie
istotn ró nic formaln , Słowo "return" jest słowem kluczowym (przypisywanie tym identyfikatorom okre lonej stałej warto ci
j zyka C, natomiast słowo "exit" jest nazw funkcji exit(). liczbowej) dokonuje si z zastosowaniem preprocesora C++.
Zastosowanie tej funkcji w programie wymaga doł czenia pliku To, e nie musisz si zastanawia ile to wła ciwie jest EOF
nagłówkowego z jej prototypem. (zero ? czy -1 ?) zawdzi czamy te doł czanym plikom typu *.H, w

Poniewa nasz kurs j zyka C++ rozpocz li my od programu z których np. przy u yciu dyrektywy #define zostały PREDEFINIOWANE
funkcj printf() i zapewne b dzie nam ona towarzyszy jeszcze
długo, pora po wi ci jej troch uwagi. (zdefiniowane wst pnie) niektóre stałe. Je li jeste bardzo
dociekliwy, zajrzyj do wn trza pliku STDIO.H (view, edit, type).
FUNKCJA printf().
Znajdziesz tam mi dzy innymi taki wiersz:
Jest to funkcja FORMATOWANEGO wyj cia na standardowe urz dzenie
wyj cia (ang. stdout - STandarD OUTput). Definicja - ci lej #define EOF (-1) //End of file indicator
tzw. PROTOTYP tej funkcji znajduje si w pliku nagłówkowym ________________________________________________________________
STDIO.H. Wniosek praktyczny: Ka dy program korzystaj cy z
funkcji printf() powinien zawiera dyrektyw preprocesora: Składnia prototypu (ang. syntax):

#include <stdio.h> int printf(const char *format [arg1, arg2,.....]);

zanim nast pi wywołanie funkcji printf(). lub troch pro ciej:

[???] A JE LI ZAPOMNIAŁEM O <STDIO.H> ??? printf(format, arg1, arg2,.....argn);


________________________________________________________________
Mo esz nada plikowi z tekstem ródłowym programu rozszerzenie Liczba argumentów mo e by zmienna.
.C zamiast .CPP. W kompilatorach Borlanda powoduje to przy
domy lnych ustawieniach kompilatora wywołanie kompilatora C C++ oferuje wiele funkcji o podobnym działaniu - np.:
zamiast C++. C jest bardziej tolerancyjny i dokona kompilacji
(wy wietli jedynie komunikat ostrzegawczy - Warning). Kompilator cprintf(), fprintf(), sprintf(), vprintf(), vsprintf(), itp.

C++ jest mniej tolerancyjny. Je li zapomnisz doł czy odpowiedni Poniewa FORMAT brzmi mo e troch obco, nazwijmy go WZORCEM. Jak

plik nagłówkowy mo e pojawi si komunikat: wiesz, wszystkie informacje przechowywane s w pami ci komputera

Error: Function printf() should have a prototype in function jako ci gi zer i jedynek. Jest to forma troch niewygodna dla
main człowieka, wi c zanim informacja trafi na ekran musi zosta
(Funkcja printf() powinna mie prototyp) zamieniona na posta dla nas wygodniejsz - np. na cyfry
dziesi tne, litery itp.. Taki proces nazywany jest KONWERSJ , a
Wi cej o zawarto ci i znaczeniu plików nagłówkowych *.h dowiesz podany w funkcji printf() FORMAT - WZORZEC to upraszczaj c,
si z nast pnych lekcji. Na razie postaraj si pomi ta o rozkaz dokonania takiej wła nie konwersii. Mo esz wi c zarz da
doł czeniu wskazanego w przykładzie pliku. przedstawienia liczby na ekranie w postaci np. SZESNASTKOWEJ lub
________________________________________________________________
DZIESI TNEJ - tak, jak Ci wygodniej. Wzorce konwersji w
[???] Sk d to wiadomo? najprostszym przypadku maj posta %s, %d, %f, itp.:
________________________________________________________________ I tak:
Je li masz w tpliwo ci, jaki plik nagłówkowy nale ałoby doł czy
%s - wyprowad ła cuch znaków (s - String - ła cuch)
- najpro ciej zajrze do systemu pomocy - Help. Na pasku Przykład:
głównego menu w IDE masz napis Help. Menu Help mo esz rozwin
myszk lub naciskaj c kombinacj klawiszy [Alt]+[H]. Je li w printf("%s","jakis napis");
menu wybierzesz rozkaz Index (Spis) przeniesiesz si do okienka ale tak e
z alfabetycznym spisem haseł. S tam słowa kluczowe, nazwy printf("Jakis napis");
funkcji i jeszcze wiele innych interesuj cych rzeczy. Powiniene
poniewa format "%s" jest formatem domy lnym dla funkcji
18
printf(). }

Przykład: Ten program pozwala zamieni dziesi tne liczby całkowite na


liczby szesnastkowe. Zakres dost pnych liczb wynika z
printf("%39s","jakis napis"); zadeklarowanego typu int. Wi cej na ten temat dowiesz si z
nast pnych lekcji. Spróbujmy odwrotnie:
spowoduje uzupełnienie napisu spacjami do zadanej długo ci 39
znaków (Sprawd !). Funkcja printf() operuje tzw. POLEM [P007.CPP]
WYJ CIOWYM. Długo pola wyj ciowego mo emy okre li przy pomocy
// Program przykladowy 16na10.CPP
liczb wpisanych pomi dzy znaki % oraz typ - np. s. Mo emy tak e //UWAGA: Sam doł cz pliki nagłówkowe
okre li ilo cyfr przed i po przecinku.
int liczba;
%c - wyprowad pojedynczy znak (c - Character - znak)
Przykład: int main()
{
printf("%c",'X'); clrscr();
printf("Podaj liczbe SZESNASTKOWA-np. AF - DUZE LITERY: \n");
(spowoduje wydrukowanie litery X) scanf("%X", &liczba);
printf("%s","\nDziesietnie to wynosi: ");
%d - wyprowad liczb całkowit typu int w postaci dziesi tnej printf("%d",liczba);
(d - Decimal - dziesi tny). getch();
Przykład: return 0;
}
printf("%d", 1994);
My l , e program 16NA10.CPP mo na pozostawi bez dodatkowego
%f - wyprowad liczb rzeczywist typu float w postaci komentarza. Zwró uwag , e funkcja scanf() "formatuje" dane
dziesi tnej (f - Floating point - zmienny przecinek). wej ciowe bardzo podobnie do funkcji printf(). Pewnie dziwi Ci
troch "dualny" zapis:
Przykład:
liczba i &liczba.
printf("%f", 3.1416);
printf("%f3.2", 3.14159); Zagadka zostanie niebawem wyja niona. W trakcie nast pnych
Lekcji zajmiemy si dokładniej zmiennymi, i ich rozmieszczeniem
%o - wyprowad liczb całkowit typu int w postaci ósemkowej w pami ci a na razie wracamy do funkcji printf().
(o - Octal - ósemkowa).
Przykład: Jako si rzekło wcze niej - funkcja printf() mo e mie wiele
argumentów. Pozwala nam to przy pomocy jednego wywołania funkcji
printf("%o", 255);
wyprowadza zło one napisy.
%x - wyprowad liczb całkowit typu int w postaci szesnastkowej
Przykład:
(x - heXadecimal - szesnastkowa).
%x lub %X - cyfry szesnastkowe a,b,c,d,e,f lub A,B,C,D,E,F. printf("Iloczyn 3 %c 5 %8s %d", '*', "wynosi ",15);

%ld - liczba całkowita "długa" - long int. Działanie:


"Iloczyn_3_ - wyprowad jako ła cuch znaków.
%Lf - liczba rzeczywista poczwórnej precyzji typu long double %c - tu wyprowad pojedynczy znak - '*'.
float. _5_ - wyprowad jako ła cuch znaków.
%8s - wyprowad ła cuch "wynosi_" uzupełniaj c go z przodu
%e - liczba w formacie wykładniczym typu 1.23e-05 (0.0000123) spacjami do długo ci 8 znaków.
%d - wyprowad 15 jako liczb dziesi tn .
%g - automatyczny wybór formatu %f albo %e.
UWAGA: Znakiem podkre lenia w tek cie ksi ki "_" oznaczyłem
Po przytoczeniu przykładów uogólnijmy sposób zastosowania wzorca spacj , spacja to te znak.

formatu: Przykład:

%[przeł czniki][szeroko _pola][.precyzja][rozmiar]Typ printf("Iloczyn 3 %c 5 %9s %f", 'x', "wynosi ", 3*5);

Posługuj c si ró nymi sposobami formatowania liczb mo emy Zwró uwag , e tym razem kazali my komputerowi samodzielnie
za da wydrukowania liczb w najwygodniejszej dla nas formie. W policzy ile wynosi nasz iloczyn, tzn. zastosowali my jako
programie przykładowym dokonujemy zamiany liczb dziesi tnych na argument funkcji printf() nie stał , a WYRA ENIE. Działanie
szesnastkowe. mo esz prze ledzi przy pomocy programu przykładowego:

[P006.CPP] [P008.CPP]

// Program przykladowy 10na16.CPP // Program WYRAZ.CPP - Doł cz pliki nagłówkowe

#include <stdio.h> int main()


#include <conio.h> {
clrscr();
int liczba; printf("Skomplikowany napis:\n");
printf("Iloczyn 3 %c 5 %8s %d", '*', "wyniosi ", 15);
int main() getch();
{ printf("\nWyrazenie jako argument:\n");
clrscr(); printf("Iloczyn 3 %c 5 %9s %d", 'x', "wynosi ", 3*5);
printf("Podaj liczbe dziesietna calkowita ? \n"); printf("\n\n\n");
scanf("%d", &liczba); printf("Przyjrzyj sie i nacisnij klawisz...");
printf("\nSzesnastkowo to wynosi: "); getch();
printf("%x",liczba); return 0;
getch(); }
return 0;
19
Wyja nijmy jeszcze jedno "dziwactwo" - znaki steruj ce Podobnie jak wi kszo edytorów tekstu zintegrowany edytor
rozmieszczeniem napisów na ekranie. Oto tabelka z najcz ciej rodowiska IDE pozwala manipulowa fragmentami blokami tekstu i
u ywanymi znakami specjalnymi: wykonywa typowe operacje edytorskie zarówno w obr bie
pojedynczego okna, jak i pomi dzy ró nymi okienkami. Słu do
________________________________________________________________ tego celu nast puj ce operacje:

Znak Nazwa Działanie * Select/Mark text block - zaznaczenie fragmentu tekstu.


________________________________________________________________ Mo esz dokona tego klawiszami- np.: [Shift]+[-->], b d
naciskaj c i przytrzymuj c lewy klawisz myszki i "przeje d aj c
\n New Line Przej cie na pocz tek nowego wiersza nad odpowiednim fragmentem tekstu". Wybrany fragment tekstu
zostanie wyró niony pod wietleniem.
\b BackSpace Cofni cie kursora o jeden znak * Edit | Cut - wytnij.
\f Form feed O stronic w dół Zaznaczony wcze niej fragment tekstu zostanie skopiowany do
\r Carriage return Powrót na pocz tek bie . wiersza Schowka i jednocze nie usuni ty z ekranu.
\t Horizontal Tab Tabulacja pozioma * Edit | Copy - skopiuj.
\v Vertical Tab Tabulacja pionowa Zaznaczony wcze niej fragment tekstu zostanie skopiowany do
\a Sound a beep Pisk gło niczka Schowka i bez usuwania z ekranu.
\\ Displ. backslash Wy wietl znak \ * Edit | Paste - wstaw.
\' Display ' Wy wietl znak ' (apostrof) Zaznaczony wcze niej w Schowku fragment tekstu zostanie
\" Display " Wy wietl znak " (cudzysłów) skopiowany na ekran pocz wszy od miejsca wskazanego w danej
________________________________________________________________ chwili kursorem.

UWAGA: Trzy ostatnie "backlash-kody" pozwalaj wyprowadzi na


ekran znaki specjalne \ ' i ", co czasami si przydaje. LEKCJA 8. Jakich słów kluczowych u ywa C++.
Szczególnie \\ jest cz sto przydatny.
W trakcie tej lekcji dowiesz si :
[Z] * Jakie znaczenie maj słowa kluczowe j zyka C++.
Spróbuj samodzielnie: * Jakie jeszcze dziwne słowa mog pojawia si w programach w
pisanych C++.
1. Napisa i uruchomi program wykonuj cy konwersj liczb * Troch wi cej o wczytywaniu i wyprowadzaniu danych.
ósemkowych na dziesi tne i odwrotnie. * Co to jest i do czego słu y zmienna.
2. Przy pomocy pojedynczego wywołania funkcji printf() _______________________________________________________________
wydrukowa kilka zło onych napisów typu:
* suma 2+4 to 6 Ka dy j zyk musi operowa tzw. słownikiem - zestawem słów
* działanie 5*7*27+6-873 daje wynik...( wła nie, ile?). zrozumiałych w danym j zyku. Jak wiesz z do wiadczenia, komputer
3. Sprawd działanie tabulacji pionowej \v. Ile to wierszy? jest pedantem i wymaga dodatkowo (my, ludzie, tego nie
wymagamy), aby znaczenie słów było absolutnie jednoznaczne i
[???] DYSKIETKA NIE JEST Z GUMY !!! precyzyjne. Aluzje, kalambury i zabawne niedomówienia s na
________________________________________________________________ razie w dialogu z komputerem niedopuszczalne. Pami ci
Je li podczas kompilacji programów w okienku b dzie si asocjatywne (oparte na skojarzeniach), sieci neuronowe (neural
uporczywie, bez widocznego powodu pojawiał napis "Errors" - networks), tworzone bardzo cz sto wła nie przy pomocy C++
bł dy, a w okienku komunikatów "Message" pojawi si napis: - systemy expertowe,
- systemy z tolerancj bł dów - np. OCR - systemy optycznego
Fatal A:\PROGRAM.C: Error writing output file rozpoznawania pisma,
(Fatalny bł d podczas kompilacji pliku A:\PROGRAM.C: Bł d przy - "rozmyta" arytmetyka i logika (fuzzy math)
zapisie pliku wyj ciowego), - logika wi kszo ciowa i mniejszo ciowa
- algorytmy genetyczne (genetic algorithms)
to znak, e na dyskietce zabrakło miejsca. Pora zmieni katalog i inne pomysły matematyków oraz informatyków rozpocz ły ju
wyj ciowy kompilatora C++. Aby to zrobi nale y: proces "humanizowania" komputerowego my lenia. Powstała nawet
1. Rozwin menu Option - [Alt]-[O]. specjalna "mutacja" neural C i neural C++, ale to temat na
2. Wybra rozkaz Directories... - [D]. oddzieln ksi k . Na razie traktujemy nasz komputer jako
3. Przej do okienka "Output Directory" - 2 razy [Tab]. automat cyfrowy pozbawiony całkowicie wyobra ni i poczucia
4. Wpisa do okienka katalog z dysku stałego, np.: C:\ humoru, a j zyk C++, jako rodek porozumiewania si z tym
5. Nacisn [Enter]. "ponurakiem".
6. Powtórzy kompilacj programu, przy której nast piło
przepełnienie dyskietki. Podobnie do słów j zyka naturalnego (rzeczowników, czasowników)
7. Usun z dyskietki A: zb dne pliki *.EXE (TYLKO *.EXE !!!). i słowa j zyka programowania mo na podzieli na kilka grup
ró ni cych si przeznaczeniem. Takie niby - słowa czasem nazywa
Oczywi cie lepiej posługiwa si własnym katalogiem na dysku si równie tokenami lub JEDNOSTKAMI LEKSYKALNYMI (leksykon -
stałym, ale dysk te niestety nie jest z gumy. Zło liwi twierdz inaczej słownik) a sposoby tworzenia wyra e (expressions)
nazywane s syntaktyk j zyka (st d bierze si typowy komunikat
nawet, e ka dy dysk jest za mały a ka dy procesor zbyt wolny o bł dach "Syntax Error" - bł d syntaktyczny, czyli niewła ciwa
(to pono tylko kwestia czasu...). składnia). Słownik j zyka C++ składa si z:
________________________________________________________________
* Słów kluczowych
* Identyfikatorów
[!!!] Dla dociekliwych - Przykłady programów. * Stałych liczbowych i znakowych
________________________________________________________________ * Stałych tekstowych (ła cuchów znaków - napisów)
Je li zajrzysz ju do systemu Help, przwi cierpliwie tekst * Operatorów (umownych znaków operacji)
opisu funkcji do ko ca. W wi kszo ci funkcji na ko cu * Znaków interpunkcyjnych
umieszczony jest krótki "firmowy" program przykładowy. * Odst pów
Nie musisz go przepisywa !
W menu Edit IDE masz do dyspozycji rozkaz UWAGA: Zarówno pojedyncza spacja czy ci g spacji, tabulator
Edit | Copy Example (Skopiuj przykład) poziomy, znak nowej linii, jak i komentarz dowolnej długo ci (!)
Przykład zostanie skopiowany do Schowka (Clipboard). s traktowane przez kompilator jak pojedyncza spacja.
Po wyj ciu z systemu pomocy warto rozkazem Od zarania dziejów informatyki twórcy uniwersalnych j zyków
File | New programowania starali si upodobni słowa tych j zyków do
otworzy nowe okno robocze a nast pnie rozkazem zrozumiałych dla człowieka słów j zyka naturalnego - niestety -
Edit | Paste (Wstaw) angielskiego (swoj drog , mo e to i lepiej, e C++ nie
wstawi program przykładowy ze schowka. Mo esz go teraz wymy lili Japo czycy...). Najwa niejsz cz ci słownika s tzw.
uruchamia , modyfikowa a nawet wstawi jako fragment do swojego
SŁOWA KLUCZOWE (keywords).
programu.
20
SŁOWA KLUCZOWE w C++. private - prywatna, wewn trzna, niedost pna z zewn trz.

Oto pełna lista słów kluczowych Turbo C++ v 1.0 z krótkim protected - chroniona, cz danych i funkcji, do których
wyja nieniem ich znaczenia. Zaczynam od listy podstawowej wersji dost p. jest ograniczony.
kompilatora, poniewa rozwa ania o niuansach dotycz cych kilku
specyficznych słów kluczowych (np. friend, template) pozostawiam public - publiczna, dost pna z zewn trz.
sobie na pó niej. Krótkie wyja nienie - jak to krótkie
wyja nienie - pewnie nie wyja ni wszystkiego od razu, ale na register - zmienn przechwaj nie w pami ci a w rejestrze CPU.
pewno pomo e zrozumie znaczenie wi kszo ci słów kluczowych.
return - powrót, zwrot warto ci.
[S] Keywords - słowa kluczowe.
_saveregs - save registers, zachowaj zawarto rejestrów a
asm nast pnie odtwórz rejestry przed powrotem.
Pozwala wstawi kod w ASEMBLERZE bezpo rednio do programu
napisanego w C lub C++. _seg - segment.

auto - zmienna lokalna. Przyjmowane domy lnie. short - krótka (mała ilo cyfr).

break - przerwij. signed - ze znakiem (+/-).

case - w przypadku. unsigned - bez znaku (+/-).

cdecl - spec. konwencja nazewnictwa/przekazania parametrów sizeof - podaj wielko .


zgodna ze standardem j z. C.
static - statyczna.
char - znak, typ zmiennej - pojedynczy bajt.
struct - struktura.
class - klasa.
switch - przeł cz.
const - stała, konstanta.
this - ten, wstazanie bie cego, własnego obiektu (tylko C++).
continue - kontynuuj.
typedef - definicja typu.
default - przyjmij domy lnie.
union - unia, zmienna wariantowa.
delete - skasuj obiekt.
virtual - wirtualna, pozorna.
do - wykonaj.
void - nieokre lona.
double - podwójna (długo /precyzja).
volatile - ulotna.
else - w przeciwnym wypadku.
while - dopóki.
enum - wylicz kolejno.

_export - dotyczy tylko OS/2, ignorowany. Panuje mnienanie, e j zyk C++ posługuje si stosunkowo skromnym
zestawem słów kluczowych. To prawda, ale nie cała prawda o
extern - zewn trzna. j zyku C++. Zauwa yłe zapewne, e nie ma tu:

far - dalekie. Wska nik - podwójne słowo (w zakresie do 1 MB). define, include, printf

float - zmiennoprzecinkowy, rzeczywisty. i innych znanych Ci ju słów. To po prostu jeszcze nie cały
słownik j zyka. Zdaj c sobie spraw z nieprecyzyjno ci tego
for - dla (wskazanie zmiennej roboczej w p tli). porównania mo esz przyj , e to co na kształt listy
czasowników. A s przecie jeszcze i inne słowa - o innej roli i
friend - zaprzyja niona funkcja z dost pem do prywatnych i przeznaczeniu.
chronionych członków danej klasy.
[???] A GDZIE SI PODZIAŁY REJESTRY ???
goto - skocz do (skok bezwarunkowy).
Nazwy rejestrów mikroprocesora Intel 80X86:
huge - daleki, podobnie do far.
_AX _AL _AH _SI _CS
if - je eli (pod warunkiem, e...). _BX _BL _BH _SP _DS
_CX _CL _CH _BP _ES
inline - funkcja z rozwini tym wstawionym kodem _DX _DL _DH _DI _SS
_FLAGS
int - typ zmiennej, liczba całkowita, dwa bajty
Takie oznaczenia wynikaj z architektury konkretnej rodziny
interrupt - przerwanie. mikroprocesorów, nie mog stanowi uniwersalnego standardu
j zyka C++. Efekt dostosowania C++ do IBM PC to np. odnosz ce
_loadds - podobne do huge, ustawia rejestr DS (Data Segment). si do modeli pami ci słowa kluczowe near, far i huge.
Wymóg zgodno ci ze standardem ANSI C spowodował, e w C++ nazwy
long - długi. rejestrów pozostaj nazwami o zastrze onym znaczeniu, ale
nazywaj si PSEUDOZMIENNYMI REJESTROWYMI (ang.: Register
near - bliski, wska nik o dł. 1 słowa. Obszar max. 64 K. Pseudovariables).

new - nowy, utwórz nowy obiekt. Próba u ycia słowa o zastrze onym znaczeniu w jakiejkolwiek
innej roli (np. jako nazwa Twojej zmiennej) mo e spowodowa
operator - operator, okre la nowy sposób działania operatora. wadliwe działanie programu lub uniemo liwi kompilacj . Unikaj
przypadkowego zastosowania słów o zastrze onym znaczeniu!
pascal - deklar. funkcji zgodnej ze standardem przekazywania
parametrów przyj tym w Pascalu. [???] A SK D MAM WIEDZIEC ?

21
List nazw, które maj ju nadane ci le okre lone znaczenie w Ła cuch znaków to taki ci g znaków, który komputer mo e
C++ znajdziesz w Help. Dost p do spisu uzyskasz przez: rozpatrywa wył cznie jako cało i posługiwa si nim tylko
tak, jak go wpisałe . Aby komputer poprawnie rozpoznawał
* Rozwini cie menu Help [Alt]-[H]; ła cuchy tekstowe - nale y ujmowa je w cudzysłów. Ła cuch
* Wybranie z menu Help rozkazu Index (spis). znaków mo e by nazywany równie literałem, b d literałem
ła cuchowym.
Wróci do edytora IDE C++ mo esz przez [Esc].
[!!!] Dla dociekliwych - jak C++ zapami tuje tekst?
SŁOWA TYPOWE DLA PROGRAMÓW OBIEKTOWYCH.
Pojedyncze znaki mo na zapisywa w C++ tak:
W porównaniu z klasycznym j zykiem C (wobec którego C++ jest
nadzbiorem - ang. superset), w nowoczesnych programach 'A' - pojedynczy znak reprezentowany w pami ci komutera jako
obiektowych i zdarzeniowych pisanych w C++ mog pojawia si i jeden bajt zawieraj cy liczb - numer litery A według kodu
inne słowa. Przyjrzyjmy si na troch inn technik ASCII. W tym przypadku byłaby to liczba 65 (dwójkowo i
programowania - bardziej charakterystyczn dla C++. szesnastkowo- odpowiednio: 0100 0001 i 41).
"A" - jednoelementowy ła cuch znaków zajmuj cy w pami ci dwa
Procesy wprowadzania i wyprowadzania danych do- i z- komputera bajty (kod litery A i znak ko ca ła cucha - \0). Reprezentacja w
nazywaj si Input i Output - w skrócie I/O (lub bardziej
swojsko We/Wy). Obsługa We/Wy komputera to sała obszerna wiedza, pami ci wygl dałaby tak:
na pocz tek b dzie nam jednak potrzebne tylko kilka najbardziej
istotnych informacji. Bajt Nr X 0100 0001 - kod ASCII litery A
Bajt Nr X+1 0000 0000 - kod ASCII 0 - znak ko ca
PROBLEM ˙WEJ CIA/WYJ CIA W PROGRAMACH - troch bardziej
ogólnie.
Wiesz ju , e clrscr(); stanowi wywołanie gotowej funkcji (tzw.
Operacje wej cia i wyj cia s zwykle kontrolowane przez funkcji bibliotecznej). Informacja dotycz ca tej funkcji (tzw.
pracuj cy wła nie program. Je li uruchomiłe program, który nie prototyp funkcji) znajduje si w pliku CONIO.H, dlatego
korzysta z klawiatury i nie oczekuje na wprowadzenie przez doł czyli my ten plik nagłówkowy na pocz tku programu dyrektyw
u ytkownika adnych informacji - mo esz naciska dowolne #include. A có to za dziwol g ten "cout" ?
klawisze - program i tak ma to w nosie. Podobnie, je li w Po cout nie ma pary nawiasów okr głych (gdyby to była
programie nie przewidziano wykorzystania drukarki, cho by funkcja - powinno by cout()) - nie jest to zatem wywołanie
"wyłaził ze skóry", adne informacje nie zostan przesłane do funkcji. ˙Strumie danych wyj ciowych cout - JEST OBIEKTEM (ang.
drukarki, dla programu i dla u ytkownika drukarka pozostanie I/O stream object - obiekt: strumie Wej cia/Wyj cia). Ale nie
niedost pna. Aby programy mogły zapanowa nad Wej ciem i przestrasz si . Popularne wyobra enie, e programowanie
Wyj ciem informacji, wszystkie j zyki programowania musz obiektowe jest czym bardzo skomplikowanym nie ma z prawd
zawiera specjalne rozkazy przeznaczone do obsługi wi cej wspólnego, ni powszechny do pogl d, e baba z pustym
Wej cia/Wyj cia (ang. Input/Output commands, lub I/O wiadrem jest gorsza od czarnego kota. W gruncie rzeczy jest
instructions). Bez umiej tno ci obsługi We/Wy, czyli bez to proste. Strumie to nic innego jak zwyczajny przepływ
mo liwo ci porozumiewania si ze wiatem zewn trznym psu na bud informacji od jednego urz dzenia do innego. W tym przypadku
zdałby si ka dy j zyk programowania. Ka dy program musi w strumie (przepływ) danych oznacza przesłanie informacji
wi kszym, b d mniejszym stopniu pobiera informacje ze wiata (tekstu) z pami ci komputera na ekran monitora. Trójk tne
zewn trznego do komputera i wysyła informacje z komputera na nawiasy (<< lub >>) wskazuj kierunek przepływu informacji.
zewn trz. Przesyłanie nast puje w naszym przypadku z pami ci do strumienia

Podobnie, jak wszystkie uniwersalne j zyki programowania - j zyk Pojawiło si tu wa ne słowo - OBIEKT. Obiekt podobnie jak
C++ zawiera pewn ilo rozkazów przeznaczonych do zarz dzania program komputerowy jest to grupa danych i funkcji działaj cych
obsług wej cia i wyj cia. Dla przykładu, mo emy w j zyku C++ wspólnie i przeznaczonych razem do wykonania jakich zada . Dla
zastosowa OBIEKT cout obsługuj cy strumie danych wyj ciowych. przykładu obiekt cout słu y do obsługi przesyłania danych na
Obiekt cout (skonstruowany przez producenta i zdefiniowany w ekran monitora. Słowo "obiekt" jest cz sto u ywane w opisach
pliku nagłówkowym IOSTREAM.H) pozwala programi cie nowoczesnych technik programowania - tzw. PROGRAMOWANIA
przesła dane tekstowe i/lub numeryczne do strumienia wyj ciwego OBIEKTOWEGO. Programowanie obiektowe, ta "wy sza szkoła jazdy"
i umie ci tekst na ekranie monitora. dla programistów z lat 80-tych jest ju wła ciwie w naszych
czasach norm . Zreszt widzisz sam - napisałe program obiektowy
Wczytaj plik ródłowy z programem COUT1.CPP lub wpisz i co - i nic strasznego si nie stało. Na pocz tek musisz
samodzielnie nast puj cy program przykładowy. Program drukuje wiedzie tylko tyle, e aby posługiwa si obiektami -
tekst na ekranie monitora. strumieniami wej cie i wyj cia - nale y doł czy w C++ plik
nagłówkowy IOSTREAM.H. Dlatego dyrektywa #include <iostream.h>
[P009.CPP] znajduje si na pocz tku przykładowego programu.

#include <iostream.h> <-- zwró uwag na inny, nowy plik KILKA ARGUMENTÓW FUNKCJI w praktyce.
#include <conio.h>
Jak starałem si wykaza w przykładzie z sinusem, funkcja mo e
void main(void) otrzymac jako argument stał - np. okre lon liczb , b d
{ zmienn (niewiadom ). Niektóre funkcje mog otrzymywa w
clrscr(); momencie ich wywołania (u ycia w programie) wi cej ni jeden
cout << "Stosujemy obiekt cout:\n"; argument. Rozwa my to dokładniej na przykładzie funkcji
cout << "Tekst pierwszy\n"; fprintf() zbli onej w działaniu do printf(), lecz bardziej
cout << "Tekst drugi...\n"; uniwersalnej. Funkcja fprintf() pozwala wyprowadza dane nie
getch(); tylko na monitor, ale tak e na drukark . Skoro urz dzenia
} wyj cia mog by ró ne, trzeba funkcji przekaza jako jeden z
jej argumentów informacj o tym - na które urz dzenie yczymy
Jak widzisz, ka dy rozkaz z u yciem obiektu cout tworzy sobie w danej chwili wyprowadza dane.
pojedyncz lini tekstu (wiersz) na ekranie monitora. Kompilator
j zyka C++ wie, e chcesz wysła tekst na ekran monitora dzi ki Słowo stdout jest pierwsz informacj (tzw. parametrem, b d
słowu cout i znakowi << (znak << to tzw. operator przesyłania do argumentem funkcji) przekazanym do funkcji fprintf(). Słowo
strumienia). Wysłany na ekran zostaje tekst umieszczony po stdout jest skrótem od Standard Output - standardowe wyj cie.
operatorze << i (obowi zkowo, podobnie jak w funkcji printf()) Oznacza to w skrócie typowe urz dzenie wyj ciowe podł czone do
uj ty w cudzysłów ("). Tekst uj ty w cudzysłów nazywa si komputera ˙i umo liwiaj ce wyprowadzenie informacji z komputera.
ła cuchem znakowym (ang. string literal).
W komputerach osobistych zgodnych ze standardem IBM PC tym
[S] String literal - ła cuch znaków. typowym urz dzeniem wyj ciowym jest prawie zawsze ekran
monitora.
Ła cuch znaków to grupa znaków alfanumerycznych (tekstowych).
22
Tekst, który ma zosta wydrukowany na ekranie monitora jest Ilo tych komórek w Twoim komputerze zale y od tego ile pami ci
drug informacj przekazywan do funkcji fprintf() - inaczej -
stanowi drugi parametr funkcji. Tekst - ła cuch znaków - musi zainstalujesz (np. 4MB RAM to 4x1024x124x8 bitów - chcesz -
zosta uj ty w znaki cudzysłowu. policz sam ile to bitów). Przeliczaj c zwró uwag , e kilobajt
(KB to nie 1000 - lecz 1024 bajty a megabajt - 1024 kB).
A je li zechcesz wyprowadzi tekst na drukark ?
W C++ zapisuje si to bardzo łatwo. Wystarczy słowo stdout Zastanówmy si , sk d program mo e wiedzie gdzie, w której
(oznaczaj ce monitor) zamieni na słowo stdprn. Słowo stdprn to komórce zostały umieszczone dane i jak si do nich dobra , gdy
skrót od Standard Printer Device - standardowa drukarka. Oto stan si potrzebne. Wła nie do takich celów potrzebne s
przykład praktycznego u ycia funkcji fprintf(). Program przesyła programowi ZMIENNE (ang. variables).
tekst na drukark . Przed uruchomieniem programu pami taj o
wł czeniu drukarki. Dawno, dawno temu rozwi zywałe zapewne zadania typu:

[P010.CPP] 3+[]=5

#include <stdio.h> Otó to [ ] było pierwszym sposobem przedstawienia Ci zmiennej.


#include <conio.h> Jak wida - zmienna to miejsce na wpisanie jakiej (czasem
nieznanej w danej chwili warto ci). Gdy przeszedłe do nast pnej
int main(void)
{ klasy, zadania skomplikowały si :
clrscr();
fprintf(stdout, "Drukuje...\n"); 3+[]=5
fprintf(stdprn, "Pierwsza proba drukowania\n"); 147.968 + [ ] = 123876.99875
fprintf(stdprn, "Autor: ....................");
fprintf(stdout, "Koniec drukowania."); Na ró ne zmienne mo e by potrzeba ró na ilo miejsca i na
fprintf(stdout, "Skonczylem, nacisnij cosik..."); kartce i w pami ci komputera. Gdy "zestarzałe si " jeszcze
getch(); troch - te same zadania zacz to Ci zapisywa tak:
return 0;
} 3+x=5
147.968 + y = 123876.99875
Gdyby w programie nie było wiersza:
Jak wida , zmienne mog posiada tak e swoje nazwy -
fprintf(stdout, "Drukuje...\n"); identyfikatory (z których ju niestety nie wynika jasno, ile
miejsca potrzeba do zapisania bie cej warto ci zmiennej).
- u ytkownik przez pewien czas nie mógłby si zorientowa ,
czym ˙wła ciwie zajmuje si komputer. Wszystko stałoby si jasne
[???] Jak C++ wskazuje adres w pami ci?
dopiero wtedy, gdy drukarka rozpocz łaby drukowanie tekstów.
Jest uznawane za dobre maniery praktyczne stosowanie dwóch Podobnie, jak w bajeczce o zabawie w chowanego kotka i myszki
prostych zasad: (myszka mówiła: "Gdyby mnie długo nie mógł znale - b d
czeka na czwartej półce od góry..."), niektórzy producenci gier
BZU - Bez Zb dnych Udziwnie
DONU - Dbaj O Nerwy U ytkownika komputerowych ycz sobie czasem przy uruchamianiu gry podania
hasła umieszczonego:
Je li efekty działania programu nie s natychmiast zauwa alne, "W instrukcji na str. 124 w czwartym wierszu do góry"
nale y poinformowa u ytkownika CO PROGRAM ROBI. Je li No có . Zamiast nazywa zmienne - niewiadome x, y, czy z, b d
u ytkownik odnosi wra enie, e komputer nic nie robi - ma zaraz rezerwowa dla nich puste miejsce [ ], mo emy jeszcze
w tpliwo ci. Cz sto próbuje wtedy wykona reset komputera i wskaza miejsce, w którym nale y ich szuka . Takie wskazanie to
wypowiada mnóstwo słów, których nie wypada mi tu zacytowa . trzeci sposób odwoływania si do danych. W C++ mo e si to
nazywa referencj do zmiennej lub wskazaniem adresu zmiennej w
Nietrudno zgadn , e C++ powinien posiada tak e rodki obsługi pami ci przy pomocy wska nika. Wska nik w C++ nazywa si
"pointerem". Pointerem mo na wskaza tak e funkcje - podaj c ich
wej cia. W C++ jest specjalny obiekt (ang. input stream object) adres startowy (pocz tek kodu funkcji w pami ci RAM).
o nazwie cin słu cy do pobierania od u ytkownika tekstów i
liczb. Zanim zajmiemy si dokładniej obiektem cin i obsług
strumienia danych wej ciowych - powiniene zapozna si ze Zmienne mo esz sobie wyobrazi jako przegródki w pami ci
ZMIENNYMI (ang. variables). komputera zaopatrzone w nazw - etykietk . Poniewa nazwy dla
tych przegródek nadaje programista w programie - czyli Ty sam,
ZMIENNE. mo esz wybra sobie prawie ka d , dowoln nazw . Zwykle nazwy
nadaje si w taki sposób, by program stał si bardziej czytelny
Gdy wprowadzisz jakie informacje do komputera - komputer i łatwiejszy do zrozumienia. Dla przykładu, by nie przepadły z
umieszcza je i przechowuje w swojej pami ci (ang. memory - pami ci komputera wyniki gier komputerowych cz sto stosuje si
pami ). Pami komputera mo e by jego pami ci stał . Taka zmienn o nazwie WYNIK (ang. Score). Za ka dym razem, gdy
pami "tylko do odczytu" nazywa si ROM (read only memory - to zmienia si wynik gracza (ang. player's score) w pami ci
wła nie "tylko do odczytu"). Pami o swobodnym dost pie, do komputera (w to samo miejsce) zostaje zapisana nowa liczba. W
której i komputer i Ty mo ecie zapisywa wszystko, co Wam si taki sposób pewien niewielki (a zawsze ten sam) fragment pami ci
spodoba - nazywa si RAM (od Random Access Memory - pami o komputera przechowuje dane potrzebne do pracy programu.
swobodnym dost pie). Pami ci ROM i RAM podzielone s na małe
"komóreczki" nazywane Bajtami, Ka dy bajt w pami ci ma swój PRZYPISYWANIE ZMIENNYM KONKRETNEJ WARTO CI.
numer. Ten numer nazywany jest adresem w pami ci. Poniewa nie
wszystko da si pomie ci w jednym bajcie (to tylko 8 bitów - Aby komputer mogł pobra informacje od u ytkownika, mo esz
miejsca wystarczy na zapami tanie tylko jednej litery), bajty zastosowa w programie np. obiekt - strumie wej ciowy - cin
(zwykle kolejne) mog by ł czone w wi ksze komórki - tzw. pola (ang. input stream object). Obiekt cin i zmienne chodz zwykle
pami ci (ang. memory fields). Najcz ciej ł czy si bajty: parami. Przy obiekcie cin musisz zawsze poda operator
pobierania ze strumienia wej ciowego >> i nazw zmiennej. Zapis
2 Bajty = 16 bitów = Słowo (WORD)
4 Bajty = 32 bity = Podwójne słowo (DOUBLE WORD - DWORD) cin >> nazwa_zmiennej;

W uproszczeniu mo esz wyobrazi sobie pami komputera jako oznacza ˙w C++ : pobierz dane ze strumienia wej ciowego i umie
miliony pojedynczych komórek, a w ka dej z komórek jaka jedna w zmiennej o nazwie "nazwa_zmiennej".Te informacje, które
warto (ang. value) zakodowana w postaci ZER i JEDYNEK. Ka da zostan ˙wczytane, C++ przechowuje w przgródce oznaczonej nazw ,
taka "szara" komórka ma numer-adres. Numeracja komórek któr nadajesz zmiennej. Oto program przykładowy ilustruj cy
rozpoczyna si nie od 1 lecz od zera (pierwsza ma numer 0). zapami tywanie danych wprowadzonych przez u ytkownika z
23
klawiatury, wczytanych do programu przy pomocy obiektu cin i zastosowa nawet w rodku wiersza tekstu - sprawd ).
zapami tanych w zadeklarowanej wcze niej zmiennej x: Zwró uwag w jaki sposób C++ rozpoznaje ró nic pomi dzy:

[P011.CPP] - ła cuchem znaków - napisem (napis powinien by podany tak):


cout << "x, 2x, 3x";
#include <iostream.h> - warto ci zmiennej:
#include <conio.h> cout << x;

void main(void) Wida tu wyra nie, dlaczego znak cudzysłowu jest dla kompilatora
{ istotny. Je li pominiemy cudzysłów, C++ b dzie próbował
int x; zinterpretowa liter (tekst) jako nazw zmiennej a nie jako
cout << "Podaj liczbe calkowita 0 - 1000 do zapamietania: "; napis.
cin >> x;
cout << "Pamietam! "; RODZAJE ZMIENNYCH: ZMIENNE NUMERYCZNE I ZMIENNE
cout << "Wielokrotnosci liczby: \n": TEKSTOWE.
cout << "x, 2x, 3x: " << x << " " << 2*x << " " << 3*x;
cout << "\n ...Nacisnij dowolny klawisz..."; Zmienne mog w C++ by bardzo elastyczne. Dokładnie rzecz
getch(); bior c, zmienne mog by :
}
RÓ NYCH TYPÓW - mog by liczbami, mog tak e by tekstami.

Zapis cin >> x oznacza: "pobierz dane ze strumienia danych Uruchom program jeszcze raz i zamiast liczby naci nij w
wej ciowych i umie je w pami ci przeznaczonej dla zmiennej x". odpowiedzi na pytanie klawisz z liter . Program wydrukuje jakie
bzdury. Dzieje si tak dlatago, e program oczekuje podania
x - to nazwa (identyfikator) zmiennej. Ta nazwa jest stosowana liczby i zakłada, e wprowadzone przez u ytkownika dane s
przez komputer do identyfikacji przegródki w pami ci, w której liczb .
b dzie przechowywana liczba wpisana przez u ytkownika jako
odpowied na zadane pytanie. Kompilator C++ zarezerwuje dla [???] A je li u ytkownik nie czyta uwa nie???
zmiennej x jak komórk pami ci i umie ci tam wpisan przez
Ciebie liczb . W trakcie pracy kompilator C++ tworzy dla C++ zakłada, e u ytkownik wie co robi gdy podaje warto
własnego u ytku tzw. tablic symboli, któr posługuje si do zmiennej. Je li wprowadzone zostan dane niewła ciwego typu -
rozmieszczania danych w pami ci. Je li chcesz, mo esz sprawdzi C++ nie przerywa działania programu i nie ostrzega przed
przy pomocy Debuggera (Debug | Inspect) w których bajtach RAM niebezpiecze stwem bł du. Sam dokonuje tzw. konwersji typów -
C++ umie cił Twoj zmienn . tzn. przekształca dane na warto typu zgodnego z zadeklarowanym
w programie typem zmiennej. To programista musi dopilnowa , by
[???] Ile miejsca trzeba zarezerwowa ? pobrane od u ytkownika dane okazały si warto ci odpowiedniego,
oczekiwanego przez program typu, lub przewidzie w programie
To, ile miejsca trzeba zarezerwowa dla danej zmiennej sposób obsługi sytuacji bł dnych.
kompilator "wie" dzi ki Twojej deklaracji, jakiego typu dane
b d przechowywane w miejscu przeznaczonym dla zmiennej. Dla
przykładu: Mo na utworzy zmienn przeznaczon do przechowywania w pami ci
- je li napiszesz int x; tekstu - napisu. Aby to zrobi musimy zadeklarowa co
Kompilatoer zarezerwuje 2 bajty jako ciowo nowego tzw. TABLIC ZNAKOW (ang. character array).
- je li napiszesz float y; Jest to nazwa, przy pomocy której komputer lokalizuje w pami ci
Kompilatoer zarezerwuje 4 bajty zbiór znaków. Aby zadeklarowa zmienn (tablic ) znakow w C++
itp...(szczegóły - patrz ni ej). musimy zacz od słowa kluczowego char (ang. CHARacter - znak).
Nast pnie podajemy nazw zmiennej a po nazwie w nawiasach
Zwykle nie musisz si przejmowa tym, w którym miejscu kwadratowych ilo znaków, z których mo e składa si zmienny
kompilator rozmie cił Twoje dane. Wszystkie czynno ci C++ wykona tekst, który zamierzamy przechowywa w pami ci pod t nazw .
automatycznie. Aby jednak wszystko przebiegało poprawnie - zanim
zastosujesz jak kolwiek zmienn w swoim programie - musisz W programie poni ej zmienna x nie jest ju miejscem w pami ci
ZADEKLAROWA ZMIENN . Deklaracja zmiennej to informacja dla słu cym do przechowywania pojedynczej liczby. Tym razem nazwa
kompilatora, ile i jakich zmiennych b dziemy stosowa w (identyfikator zmiennej) x oznacza tablic znakow , w której
programie. Deklaracja zawiera nie tylko nazw zmiennej, ale mo na przechowywa tekst o długo ci do 20 znaków. W C++ ostatnim
równie typ warto ci, jakie ta zmienna mo e przybiera . znakiem w ła cuchu znakowym (tek cie) b d w tablicy znakowej
Przykładem deklaracji jest wiersz: zwykle jest tzw. NULL CHARACTER - niewidoczny znak o kodzie
ASCII 0 (zero). W C++ znak ten podaje si przy pomocy szyfru
int x; '\0'. Przy pomocy tego znaku C++ odnajduje koniec tekstu,
ła cucha znaków, b d koniec tablicy znakowej. Tak wi c w
Słowo kluczowe int okre la typ danych. Tu oznacza to, e zmienna tablicy x[20] w rzeczywisto ci mo na przechowa najwy ej 19
x mo e przechowywa jako warto ci liczby całkowite (ang. INTeger dowolnych znaków plus na ko cu obowi zkowy NULL (wartownik).
- całkowity) o wielko ci zawartej w przedziale - 32768...+32767.
Po okre leniu typu danych nast puje w deklaracji nazwa zmiennej [P012.CPP]
i rednik.
#include <conio.h>
[S] Variable Declaration - Dekaracja Zmiennej. #include <iostream.h>

Deklaracja zmiennej w C++ to okre lenie typu warto ci zmiennej i void main(void)
podanie nazwy zmiennej. {
char x[20]; //<---- deklaracja tablicy znakowej.

Zwró uwag w przykładowym programie, e kieruj c kolejno dane clrscr();


do strumienia wyj ciwego cout mo emy je poustawia w tzw. cout << "Podaj mi swoje imie: : ";
ła cuch (ang. chain). Przesyłanie danych do obiektu cout cin >> x;
operatorem << jest bardzo elastyczne. Wysyłamy na ekran zarówno cout << "\nNazywasz sie " << x << ", ladne imie!\n";
tekst jak i liczb - bie c warto zmiennej x oraz wyniki cout << "...Nacisnij dowolny klawisz...";
obliczenia warto ci wyra e ( 2*x i 3*x). Posługuj c si getch();
ł czonym w "ła cuch" operatorem << mo na wyprowadza na ekran }
wiersz zbudowany z ró nych elementów. Operator przesyłania
danych do strumienia wyj ciowego << (ang. insertor - dosł. - [Z]
operator wstawiania) powoduje przesłanie do obiektu cout kolejno
wszystkich (ró nego typu) elementów. Zwró uwag na u ycie znaku 1. Spróbuj w przykładowych programach z poprzednich lekcji
\n na pocz tku nowego wiersza, na ko cu wiersza tekstu (mo na go zast pi funkcje obiektami - strumieniami We/Wy:
24
przekaza jej ARGUMENT. Argument funkcji to numer koloru. Zwró
printf() - cout << jednak uwag , e zamiast prostego, zrozumiałego zapisu:
scanf() - cin >>
textcolor(4); /* 4 oznacza kolor czerwony */
2. Spróbuj napisa program zawieraj cy i funkcje i obiekty. Czy
program pracuje bezkonfliktowo? Pami taj o doł czeniu mamy w programie podany argument w postaci wyra enia (sumy dwu
odpowiednich plików nagłówkowych. liczb):

textcolor(4+128); // to samo, co: textcolor(132);

LEKCJA 9: O SPOSOBACH ODWOŁYWANIA SI DO DANYCH. Wbrew pierwszemu mylnemu wra eniu te dwie liczby stanowi jeden
________________________________________________________________ argument funkcji. C++ najpierw dokona dodawania 4+128 a dopiero
W trakcie tej lekcji poznasz: uzyskany wynik 132 przeka e funkcji textcolor jako jej argument
* sposoby wyprowadzania napisów w ró nych kolorach (parametr). Liczba 4 to kod koloru czerwonego, a zwi kszenie
* sposoby zapami tywania tekstów kodu koloru o 128 powoduje, e tekst b dzie migał.
* sposoby odwoływania si do danyc i zmiennych przy pomocy ich
nazw - identyfikatorów. Numery (kody) kolorów, które mo esz przekaza jako argumenty
________________________________________________________________ funkcji textcolor() podano w tabeli poni ej. Je li tekst ma
miga - nale y doda 128 do numeru odpowiedniego koloru.
Mo emy teraz po wi ci chwil na zagadnienie kolorów, które
pojawiaj si na monitorze. Po uruchomieniu program przykładowy Kod koloru przekazywany do funkcji textcolor().
poni ej wygeneruje krótki d wi k i zapyta o imi . Po wpisaniu ________________________________________________________________
imienia program zapiszczy jeszcze raz i zapyta o nazwisko. Po
wpisaniu nazwiska program zmieni kolor na ekranie monitora i Kod Kolor (ang) Kolor (pol) Stała
wypisze komunikat kolorowymi literami. Ró ne kolory zobaczysz n (przykład)
oczywi cie tylko wtedy, gdy masz kolorowy monitor. Dla ________________________________________________________________
popularnego zestawu VGA mono b d to ró ne odcienie szaro ci.
Tekst powinien zmienia kolor i "miga " (ang. - blinking text). 0 Black Czarny BLACK
1 Blue Niebieski BLUE
[P012.CPP] 2 Green Zielony GREEN
3 Cyan Morski CYAN
#include <conio.h> 4 Red Czerwony
#include <iostream.h> 5 Magenta Fioletowy
6 Brown Br zowy
main() 7 White Biały
{ 8 Gray Szary
char imie[20]; 9 Light blue Jasno niebieski
char nazwisko[20]; 10 Light green Jasno zielony
11 Light cyan Morski - jasny
clrscr(); 12 Light red Jasno czerwony
cout << "\aPodaj imie: "; 13 Light magenta Jasno fio;etowy (fiol-ró owy)
cin >> imie; 14 Yellow ółty
cout << "\aPodaj nazwisko: "; 15 Bright white Biały rozja niony
cin >> nazwisko; 128 + n Blinking Migaj cy BLINK
cout << '\n' << imie << ' ' << nazwisko << '\n'; ________________________________________________________________
textcolor(4+128);
cprintf("\nPan(i), %s %s? Bardzo mi milo!", imie, nazwisko);
getch(); [!!!]UWAGA:
cout << '\a'; ________________________________________________________________
return 0; * W pliku CONIO.H s predefiniowane stałe (skrajna prawa kolumna
}
- przykłady), które mo esz stosowa jako argumenty funkcji.
Wyja nijmy kilka szczegółów technicznych: Kolor tła mo esz ustawi np. przy pomocy funkcji
textbackground() - np. textbacground(RED);
cout << "\aPodaj nazwisko? ";
/* \a to kod pisku gło niczka (beep) */ * Manipuluj c kolorem tekstu musisz pami ta , e je li kolor
napisu:
cin >> nazwisko; - foreground color, text color
textcolor(4+128); <---- funkcja zmienia kolor tekstu i kolor tła:
- background color
cprintf("\nPan(i), %s %s? Bardzo mi milo!", imie, nazwisko); oka si identyczne - tekst zrobi si NIEWIDOCZNY. Je li ka esz
___ tu funkcja wstawi "string" nazwisko
| |________ a tu wstawi "string" imie komputerowi pisa czerwonymi literami na czerwonym tle -
|_________ funkcja wyprowadza tekst na ekran w kolorach komputer wykona rozkaz. Jednak e wi kszo ludzi ma kłopoty z
(cprintf = Color PRINTing Function) odczytywaniem czarnego tekstu na czarnym tle. Jest to jednak
metoda stosowana czasem w praktyce programowania do kasowania
tekstów i elementów graficznych na ekranie.
Operator >> pobiera ze strumienia danych wej ciowych cin wpisane ________________________________________________________________

przez Ciebie imi i zapisuje ten tekst do tablicy znakowej


imie[20]. Po wypisaniu na ekranie nast pnego pytania nast puje Powołuj c si na nasze wcze niejsze porównanie (NIE TRAKTUJ GO
pobranie drugiego ła cucha znaków (ang. string) wpisanego przez ZBYT DOSŁOWNIE!),zajmiemy si teraz czym , co troch przypomina
Ciebie jako odpowied na pytanie o nazwisko i umieszczenie tego rzeczowniki w normalnym j zyku.
ła cucha w tablicy znakowej nazwisko[]. Wywołana nast pnie
funkcja textcolor() powoduje zmian roboczego koloru O IDENTYFIKATORACH - DOKŁADNIEJ.
wyprowadzanego tekstu. Tekst nie tylko zmieni kolor, lecz tak e
b dzie "miga " (blink). Funkcja cprintf() wyprowadza na ekran Identyfikatorami (nazwami) mog by słowa, a dokładniej ci gi
ko cowy napis. Funkcja cprintf() to Color PRINTing Function - liter, cyfr i znaków podkre lenia rozpoczynaj ce si od litery
funkcja drukowania w kolorze. lub znaku podkre lenia (_). Za wyj tkiem słów kluczowych, (które

Funkcja textcolor() pozwala na zmian koloru tekstu to słowa kluczowe - MUSZ ZAWSZE BY PISANE MAŁYMI LITERAMI)
wyprowadzanego na monitor. Mo na przy pomocy tej funkcji tak e mo na stosowa i małe i du e litery. Litery du e i małe s
"zmusi " tekst do migotania. Aby funkcja zadziałała - musimy rozró niane. Przykład:
25
* Dziesi tne (przyjmowane domy lnie - default);
[P013.CPP] * Ósemkowe - zapisywane z zerem na pocz tku:
017 = 1*8 + 7 = 15 (dziesi tnie);
#include <stdio.h> * Szesnastkowe - zapisywane z 0x na pocz tku:
#include <conio.h> 0x17 = 1*16 + 7 = 23 (dziesi tnie);
0x100 = 16^2 + 0 + 0 = 256 .
float PI = 3.14159; <-- stała PI
float r; <-- zmienna r Liczby rzeczywiste mog zawiera cz ułamkow lub by zapisane

int main(void) w postaci wykładniczej (ang. scientific format) z liter "e"


{ poprzedzaj c wykładnik pot gi.
clrscr();
printf("Podaj promien ?\n"); Przykład:
scanf("%f", &r);
printf("\nPole wynosi P = %f", PI*r*r ); Zapis liczby Warto dziesi tna
getch();
return 0; .0123 0.0123
} 123e4 123 * 10^4 = 1 230 000
1.23e3 1.23 * 10^3 = 1230
* U yte w programie słowa kluczowe: 123e-4 0.0123
int, float, void, return.
Literały składaj ce si z pojedynczych znaków maj jedn z
* Identyfikatory trzech postaci:
- nazwy funkcji (zastrze one):
main, printf, scanf, getch, clrscr. * 'z' - gdzie z oznacza znak "we własnej osobie";
- nazwy zmiennych (dowolne): * '\n' - symboliczne oznaczenie znaku specjalnego - np.
PI, r. steruj cego - tu: znak nowej linii;
* '\13' - nr znaku w kodzie ASCII.
* Dyrektywy preprocesora:
# include UWAGA:
'\24' - kod Ósemkowy ! (dziesi tnie 20)
Zwró uwag , e w wierszu: '\x24' - kod SZESNASTKOWY ! (dziesi tnie 36)
float PI = 3.14159;
nie tylko DEKLARUJEMY, zmienn PI jako zmiennoprzecinkow , ale
tak e od razu nadajemy liczbie PI jej warto . Jest to tzw. [S] SLASH, BACKSLASH.
ZAINICJOWANIE zmiennej. Kreska "/" nazywa si SLASH (czyt. "slasz") - łamane,
uko nik zwykły. Kreska "\" nazywa si BACKSLASH (czyt.
[Z] "bekslasz") - uko nik odwrotny.
________________________________________________________________
1. Uruchom program przykładowy. Spróbuj zamieni identyfikator Uzupełnimy teraz list symboli znaków z poprzedniej lekcji.
zmiennej PI na pisane małymi literami pi. Powinien wyst pi
bł d. Znak ÓSEMKOWO ASCII (10) ZNACZENIE
________________________________________________________________ \a '\7' 7 - sygn. d wi kowy BEL
\n '\12' 10 - nowy wiersz LF
Dla porównania ten sam program w wersji obiektowo-strumieniowej: \t '\11' 9 - tabulacja pozioma HT
\v '\13' 11 - tabulacja pionowa VT
\b '\10' 8 - cofni cie kursora o 1 znak
[P013-1.CPP] \r '\15' 13 - powrót do pocz tku linii CR
\f '\14' 12 - nowa strona (form feed) FF
#include <stdio.h> \\ '\134' 92 - poprostu znak backslash "\"
#include <conio.h> \' '\47' 39 - apostrof "'"
\" '\42' 34 - cudzysłów (")
const float PI = 3.14159; <-- stała PI \0 '\0' 0 - NULL (znak pusty)
float r; <-- zmienna r
Komputer przechowuje znak w swojej pami ci jako "krótk ", bo
int main(void) zajmuj c tylko jeden bajt liczb całkowit (kod ASCII znaku).
{ Na tych liczbach wolno Ci wykonywa operacje arytmetyczne !
clrscr(); (Od czego mamy komputer?) Przekonaj si o tym uruchamiaj c
cout << "Podaj promien ?\n"; nast puj cy program.
cin >> r;
cout << "\nPole wynosi P = " << PI*r*r; [P014.CPP]
getch();
return 0; # include <stdio.h> //prototypy printf() i scanf()
} # include <conio.h> //prototypy clrscr() i getch()
int liczba; //deklaracja zmiennej "liczba"
LITERAŁY.
int main(void)
Literałem nazywamy reprezentuj cy dan NAPIS, na podstawie {
którego mo na jednoznacznie zidentyfikowa dan , jej typ, clrscr();
warto i inne atrybuty. W j zyku C++ literałami mog by : printf("Wydrukuje A jako \nLiteral znakowy:\tKod ASCII:\n");
* ła cuchy znaków - np. "Napis"; printf("%c", 'A');
* pojedyncze znaki - np. 'X', '?'; printf("\t\t\t\t%d", 'A');
* liczby - np. 255, 3.14 printf("\nPodaj mi liczbe ? ");
scanf("%d", &liczba);
[!!!] Uwaga: BARDZO WA NE !!! printf("\n%c\t\t\t\t%d\n", 'A'+liczba, 'A'+liczba);
________________________________________________________________ scanf("%d", &liczba);
* Rol przecinka dziesi tnego spełnia kropka. Zapis Pi=3,14 jest printf("\n%c\t\t\t\t%d", 'A'+liczba, 'A'+liczba);
getch();
nieprawidłowy. return 0;
* Próba zastosowania przecinka w tej roli SPOWODUJE BŁ DY ! }
________________________________________________________________
Uruchom program kilkakrotnie podaj c ró ne liczby całkowite z
Liczby całkowite mog by : zakresu od 1 do 100.
26
- Rozwi menu Options [Alt]-[O],
Przyjrzyj si sposobowi formatowania wyj cia: - Otwórz okienko Directories... [D],
%c, %d, \t, \n - Sprawd zawarto okienka tekstowego Output Directory.
Teraz wiesz ju gdzie szuka swojego programu w wersji *.EXE.
Je li pami tasz, e kody ASCII kolejnych liter A,B,C... i
kolejnych cyfr 1, 2, 3 s kolejnymi liczbami, to zauwa , e - Uruchom program poza rodowiskiem IDE.
wyra enia: - Sprawd reakcj programu na klawisze:
[Esc], [Ctrl]-[C], [Ctrl]-[Break].
'5' + 1 = '6' oraz 'A' + 2 = 'C'
(czytaj: kod ASCII "5" + 1 = kod ASCII "6") Uruchom powtórnie kompilator C++ i załaduj program rozkazem:
s poprawne. BC A:\GOTOTEST.CPP

[!!!]Jak sprawdzi kod ASCII znaku? Wykonaj od nowa kompilacj programu [F9].
________________________________________________________________
Mo na oczyw cie nauczy si tabeli kodów ASCII na pami (dla [???] ... is up to date...
pocz tkowych i najwa niejszych stronic kodowych - przede ________________________________________________________________
wszystkom od 0 do 852). Dla hobbystów - stronica kodowa 1250 i Je li C++ nie zechce powtórzy kompilacji i odpowie Ci:
1252 te czasem si przydaje.
(to oczywi cie art - autor nie zna ani jednego faceta o tak Making
genialnej pami ci) A:\GOTOTEST.CPP
Mo na skorzysta z edytora programu Norton Commander. W trybie
Edit [F4] po wskazaniu kursorem znaku w górnym wierszu po prawej is up to date

stronie zostanie wy wietlony jego kod ASCII. (Program w takiej wersji ju skompilowałem, wi cej nie b d !)
________________________________________________________________
nie przejmuj si . Dokonaj jakiejkolwiek pozornej zmiany w
CZY PROGRAM NIE MÓGŁBY CHODZI W KÓŁKO? programie (np. dodaj spacj lub pusty wiersz w dowolnym
miejscu). Takich pozornych zmian wystarczy by oszuka C++. C++
Twoja intuicja programisty z pewno ci podpowiada Ci, e gdyby nie jest na tyle inteligentny, by rozró nia zmiany rzeczywiste
zmusi komputer do pracy w p tli, to nie musiałby przykładowych w pliku ródłowym od pozornych.
________________________________________________________________
programów uruchamia wielokrotnie. Spróbujmy nakaza programowi
przykładowemu chodzi "w kółko". To proste - dodamy do programu:
Powtórz kompilacj programu. Nie musisz uruchamia programu.
Zwró uwag tym razem na pojawiaj ce si w okienku komunikatów
* na ko cu rozkaz skoku bezwarunkowego goto (id do...), ostrze enie:
* a eby wiedział dok d ma sobie i - na pocz tku programu
zaznaczymy miejsce przy pomocy umownego znaku - ETYKIETY. Warning: A:\GOTOTEST.CPP 14: Unreachable code in function main.
(Uwaga: Kod programu zawiera takie rozkazy, które nigdy nie
Zwró uwag , e pisz c pliki wsadowe typu *.BAT w j zyku BPL zostan wykonane inaczej - "s nieosi galne").
(Batch Programming Language - j zyk programowania wsadowego)
stawiasz dwukropek zawsze na pocz tku etykiety: O co chodzi? Przyjrzyj si tekstowi programu. Nawet je li po
rozkazie skoku bezwarunkowego:
:ETYKIETA (BPL)
goto etykieta;
a w j zyku C++ zawsze na ko cu etykiety:
dopiszesz jakikolwiek inny rozkaz, to program nigdy tego rozkazu
ETYKIETA: (C/C++)
nie wykona. Wła nie o to chodzi. Program nie mo e nawet nigdy
Przyst pujemy do opracowania programu. wykona rozkazu "return 0", który dodali my "z przyzwyczajenia".

[P015.CPP] P tla programowa powinna by wykonywana w niesko czono . Taka


p tla nazywa si p tl niesko czon (ang. infinite loop).
# include <stdio.h>
Mimo to i w rodowisku IDE (typowy komunikat: User break) i w
short int liczba; rodowisku DOS t p tl uda Ci si przerwa .
Kto wobec tego przerwał działanie Twojego programu? Niesko czon
int main(void)
{ p tl programow przerwał DOS. Program zwrócił si do systemu
clrscr(); DOS, a konkretnie do której z DOS'owskich funkcji obsługi
printf("Wydrukuje A jako \nLiteral znakowy:\tKod ASCII:\n"); WEJ CIA/WYJ CIA i to DOS wykrył, e przycisn łe klawisze
printf("%c", 'A'); [Ctrl]-[C] i przerwał obsług Twojego programu. Nast pnie DOS
printf("\t\t\t\t%d", 'A'); "wyrzucił" twój program z pami ci operacyjnej komputera i
etykieta: zgłosił gotowo do wykonania dalszych Twoich polece - swoim
printf("\npodaj mi liczbe ? "); znakiem zach ty C:\>_ lub A:\>_.
scanf("%d", &liczba);
printf("\n%c\t\t\t\t%d\n", 'A'+liczba, 'A'+liczba); Spróbujmy wykona taki sam "face lifting" i innych programów
goto etykieta; przykładowych, dodaj c do nich najprostsz p tl . Zanim jednak
return 0; omówimy szczegóły techniczne p tli programowych w C++ rozwa my
} prosty przykład. Wyobra my sobie, e chcemy wydrukowa na
ekranie kolejne liczby całkowite od 2 do np. 10. Program
Skompiluj program do wersji *.EXE: powinien zatem liczy ilo wykonanych p tli, b d sprawdza ,
Compile | Make czy liczba przeznaczona do drukowania nie stała si zbyt du a.
(rozkazem Make EXE file z menu Compile). Musisz nacisn
nast puj ce klawisze: W C++ do takich konstrukcji u ywa si kilku bardzo wa nych słów
[Alt]-[C], [M]. (lub [F9]) kluczowych:

* Je li wyst piły bł dy, popraw i powtórz prób kompilacji. [S] some important keywords - kilka wa nych słów kluczowych
* Uruchom program [Alt]-[R], [R] (lub [Ctrl]-[F9]). ________________________________________________________________
* Podaj kilka liczb: np. 1,2,5,7,8 itp. for - dla (znaczenie jak w Pascalu i BASICu)
* Przerwij działanie programu naciskaj c kombinacj klawiszy while - dopóki
[Ctrl]+[Break] lub [Ctrl]+[C]. do - wykonuj
* Sprawd , jaki jest katalog wyj ciowy kompilatora. if - je eli
27
break - przerwij wykonywanie p tli p tki for, lecz przerwa p tl w jej wn trzu (po osi gni ciu
continue - kontynuuj p telkowanie okre lonego stanu) przy pomocy rozkazu break:
goto - skocz do wskazanej etykiety
________________________________________________________________ [LOOP-6]

Nasz program mógłby przy zastosowaniu tych słów zosta napisany #include <iostream.h>
np. tak: int main(void)
{
[LOOP-1] for(;;)
{
#include <iostream.h> cout << x << '\n';
void main() x++;
{ if( x > 10) break;
int x = 2; }
petla: return 0;
cout << x << '\n'; }
x = x + 1;
if (x < 11) goto petla; Wszytkie te p tle (sprawd !) b d działa tak samo. Spróbuj przy
}
ich pomocy, zanim przejdziesz dalej, wydrukowa np. liczby od 10
Mo emy zastosowa rozkaz goto w postaci skoku bezwarunkowego, a
p telkowanie przerwa rozkazem break: do 100 i wykonaj jeszcze kilka innych eksperymentów.
Dokładniejszy opis znajdziesz w dalszej cz ci ksi ki, ale
[LOOP-2] przykład - to przykład.

#include <iostream.h> Wró my teraz do "face-liftingu" naszych poprzednich programów.


void main() Poniewa nie mo emy sprecyzowa adnych warunków, ka emy
{ programowi przykładowemu wykonywa p tl bezwarunkowo.
int x = 2;
petla: Wpisz tekst programu:
cout << x << '\n';
x = x + 1; [P016.CPP]
if(x > 10) break;
goto petla; // Przyklad FACELIFT.CPP
} // Program przykladowy 10na16.CPP / 16na10.CPP FACE LIFTING.

Mo emy zastosowa p tl typu for: # include <stdio.h>

[LOOP-3] int liczba;

#include <iostream.h> int main()


int main(void) {
{ clrscr();
for(int x = 2; x < 11; x = x + 1) printf("Kropka = KONIEC \n");
{ for(;;)
cout << x << '\n'; {
} printf("Podaj liczbe dziesietna calkowita ? \n");
return 0; scanf("%d", &liczba);
} printf("Szesnastkowo to wynosi:\n");
printf("%X",liczba);
Mo emy zastosowa p tl typu while: getch();
printf("Podaj liczbe SZESNASTKOWA-np.DF- DUZE LITERY: \n");
[LOOP-4] scanf("%X", &liczba);
printf("%s","Dziesietnie to wynosi: ");
#include <iostream.h> printf("%d",liczba);
int main(void) if(getch() == '.') break;
{ }
int x = 2; return 0;
while (x < 11) }
{
cout << x << '\n'; - Uruchom program Run, Run.
x = x + 1; - Dla przetestowania działania programu:
} * podaj kolejno liczby o ró nej długo ci 1, 2, 3, 4, 5, 6
return 0; cyfrowe;
} * zwró uwag , czy program przetwarza poprawnie liczby dowolnej
długo ci?
Mo emy tak e zastosowa p tl typu do-while: - Przerwij program naciskaj c klawisz z kropk [.]
- Zapisz program na dysk [F2].
[LOOP-5] - Wyjd z IDE naciskaj c klawisze [Alt]-[X].

#include <iostream.h> Zwró uwag na dziwny wiersz:


int main(void)
{ if(getch() == '.') break;
int x = 2;
do C++ wykona go w nast puj cej kolejno ci:
{ 1) - wywoła funkcj getch(), poczeka na naci ni cie klawisza i
cout << x << '\n'; wczyta znak z klawiatury:
x = x + 1; getch()
}while (x < 11); 2) - sprawdzi, czy znak był kropk :
return 0; (getch() == '.') ?
} 3) - je li TAK - wykona rozkaz break i przerwie p tl ,
if(getch() == '.') break;
Mo emy wreszcie nie precyzowa warunków p telkowania w nagłówku - je li NIE - nie zrobi nic i p tla "potoczy si " dalej.
28
if(getch() != '.') ...--> printf("Podaj liczbe dziesietna... {L->R} | | grupuje argumenty funkcji.
|--------------|--------------------------------------
[Z] | [] | zawarto jedno- lub wielowymiarowych
|Brackets | tablic
________________________________________________________________ |--------------|--------------------------------------
2. Opracuj program pobieraj cy znak z klawiatury i podaj cy w |. |(direct component selector)
odpowiedzi kod ASCII pobranego znaku dziesi tnie. | -> |(indirect, or pointer, selection)
3. Opracuj program pobieraj cy liczb dziesi tn i podaj cy w | | Bezpo rednie lub po rednie wskazanie
odpowiedzi: | | elementu unii b d struktury.
* kod ósemkowy, |--------------|--------------------------------------
* kod szesnastkowy, | :: | Operator specyficzny dla C++.
* znak o zadanym | | Pozwala na dost p do nazw GLOBALNYCH,
** dziesi tnie | | nawet je li zostały "przysłoni te"
** szesnastkowo | | przez LOKALNE.
kodzie ASCII. ----------|--------------|--------------------------------------
_______________________________________________________________ 2. |! | Negacja logiczna (NOT)
Jednoar- |--------------|------------------------------------
gumentowe | ~ | Zamiana na kod KOMPLEMENTARNY bit po
LEKCJA 10 Jakie operatory stosuje C++. (Unary) | | bicie. Dotyczy liczb typu int.
_______________________________________________________________ {L<<-R} |--------------|--------------------------------------
Podczas tej lekcji: |+ | Bez zmiany znaku (Unary plus)
* Poznasz operatory j zyka C++. |--------------|--------------------------------------
* Przetestujesz działanie niektórych operatorów. |- | Zmienia znak liczby / wyra enia
* Dowiesz si wi cej o deklarowaniu i inicjowaniu zmiennych. | | (Unary minus)
_______________________________________________________________ |--------------|--------------------------------------
| ++ | PREinkrementacja/POSTinkrementacja
Słów kluczowych jest w j zyku C++ stosunkowo niewiele, za to |--------------|--------------------------------------
operatorów wyra nie wi cej ni np. w Basicu. Z kilku operatorów | -- | PRE/POSTdekrementacja
ju korzystałe w swoich programach. pełn list operatorów |--------------|--------------------------------------
wraz z krótkim wyja nieniem przedstawiam poni ej. Operatory C++ |& | Operator adresu(Referencing operator)
s podzielone na 16 grup i mo na je scharakteryzowa : |--------------|--------------------------------------
|* | Operator wskazania
* priorytetem | | (Dereferencing operator)
** najwy szy priorytet ma grupa 1 a najni szy grupa 16 - |--------------|--------------------------------------
przecinek, np. mno enie ma wy szy priorytet ni dodawanie; | sizeof | Zwraca wielko argumentu w bajtach
** wewn trz ka dej z 16 grup priorytet operatorów jest równy; |--------------|--------------------------------------
* ł czno ci (wi zaniem). | new | Dynamiczne zarz dzanie pami ci :
| delete | new - przydziela pami ,
[S!] Precedence - kolejno , priorytet. | | delete - likwiduje przydział pami ci
________________________________________________________________ ----------|--------------|--------------------------------------
Dwie cechy opertorów C++ priorytet i ł czno decyduj o 3. Multi- | * | Mno enie (UWAGA: Druga rola "*")
sposobie obliczania warto ci wyra e . plikatywne|--------------|--------------------------------------
Precedence - kolejno , priorytet. {L->R} | / | Dzielenie
Associativity - asocjatywno , ł czno , wi zanie. Operator jest |--------------|--------------------------------------
ł czny lewo/prawo-stronnie, je li w wyra eniu zawieraj cym na |% | Reszta z dzielenia (modulo)
tym samym poziomie hierarchii nawiasów min. dwa identyczne ----------|--------------|--------------------------------------
operatory najpierw jest wykonywany operator lewy/prawy. Operator 4. Dost pu| .* | Operatory specyficzne dla C++.
jest ł czny, je li kolejno wykonania nie wpływa na wynik. (Member |(dereference) | Skasowanie bezpo redniego wskazania
________________________________________________________________ access) | | na członka klasy (Class Member).
{L->R} |--------------|--------------------------------------
Przykład: | ->* | Skasowanie po redniego wskazania typu
a+b+c+d = (a+d)+(c+b) objektowe | | "wska nik do wska nika"
----------|--------------|--------------------------------------
[S] 5. Addy - | + | Dodawanie dwuargumentowe.
________________________________________________________________ tywne |--------------|--------------------------------------
ASSIGN(ment) - Przypisanie. {L->R} | - | Odejmowanie dwuargumentowe.
EQAL(ity) - Równy, odpowiadaj cy. ----------|--------------|--------------------------------------
BITWISE - bit po bicie (bitowo). 6. Przesu-| << | Binarne przesuni cie w lewo.
REFERENCE - odwołanie do..., powołanie si na..., wskazanie ni cia |--------------|--------------------------------------
na... . (Shift) | >> | Binarne przesuni cie w prawo.
{L->R} | | (bit po bicie)
Funkcje logiczne: ----------|--------------|--------------------------------------
OR - LUB - suma logiczna (alternatywa). 7. Relacji| < | Mniejsze ni ...
AND - I - iloczyn logiczny. {L->R} |--------------|--------------------------------------
XOR (eXclusive OR) - ALBO - alternatywa wył czaj ca. |> | Wi ksze ni ....
NOT - NIE - negacja logiczna. |--------------|--------------------------------------
________________________________________________________________ | <= | Mniejsze lub równe.
|--------------|--------------------------------------
| >= | Wi ksze lub równe.
Oznaczenia ł czno ci przyj te w Tabeli: ----------|--------------|--------------------------------------
8.Równo ci| == | Równe (równa si ).
{L->R} (Left to Right) z lewa na prawo. {L->R} | != | Nie równe.
{L<<-R} (Right to Left) z prawa na lewo. ----------|--------------|--------------------------------------
9. |& | AND binarnie (Bitwise AND)
{L->R} | | UWAGA: Druga rola "&".
Lista operatorów j zyka C++. ----------|--------------|--------------------------------------
________________________________________________________________ 10. |^ | XOR binarnie (Alternatywa wył czna).
Kategoria | Operator | Co robi / jak działa {L->R} | | UWAGA: To nie pot ga !
----------|--------------|-------------------------------------- ----------|--------------|-------------------------------------
11.{L->R} | | | OR binarnie (bit po bicie)
1. Highest| () | * ogranicza wyra enia, ----------|--------------|-------------------------------------
(Najwy szy|Parentheses | * izoluje wyra enia warunkowe, 12.{L->R} | && | Iloczyn logiczny (Logical AND).
priorytet)| | * wskazuje na wywołanie funkcji, ----------|--------------|-------------------------------------
29
13.{L->R} | || | Suma logiczna (Logical OR). for(;;)
----------|--------------|-------------------------------------- {
14. Oper. | ?: | Zapis a ? x : y oznacza: printf("\n Podaj liczbe...\n");
Warunkowy | | "if a==TRUE then x else y" scanf("%f", &x);
Conditional | gdzie TRUE to logiczna PRAWDA "1". printf("\n%f\t%f\t%f\n", x, +x, -x );
{L<<-R} | | printf("\n%f", --x );
----------|--------------|-------------------------------------- printf("\t%f", x );
15. Przy- | = | Przypisz warto (jak := w Pascalu) printf("\t%f", ++x);
pisania |--------------|-------------------------------------- if(getch() = '.') break;
{L<<-R} | *= | Przypisz iloczyn. Zapis X*=7 };
| | oznacza: X=X*7 (o 1 bajt krócej!). }
|--------------|--------------------------------------
| /= | Przypisz iloraz.
|--------------|-------------------------------------- Zwró uwag , e po nawiasie zamykaj cym p tl nie ma tym razem
| %= | Przypisz reszt z dzielenia. adnego rozkazu. Nie wyst pi tak e ostrze enie (Warning:) przy
|--------------|-------------------------------------- kompilacji.
| += | Przypisz sum X+=2 oznacza "X:=X+2"
|--------------|-------------------------------------- Uruchom program Run | Run. Popraw ewentualne bł dy.
| -= | Przypisz ró nic X-=5 ozn. "X:=X-5"
|--------------|-------------------------------------- Podaj c ró ne warto ci liczby x:
| &= | Przypisz iloczyn binarny ( Bitwise - dodatnie i ujemne,
| | AND) - całkowite i rzeczywiste,
| | bit po bicie. przeanalizuj działanie operatorów.
|--------------|-------------------------------------- Przerwij program naciskaj c klawisz [.]
| ^= | Przypisz XOR bit po bicie.
|--------------|-------------------------------------- Zmodyfikuj w programie deklaracj typu zmiennej X wpisuj c
| |= | Przypisz sum log. bit po bicie. kolejno:
|--------------|-------------------------------------- - float x; (rzeczywista)
| <<= | Przypisz wynik przesuni cia o jeden - int x; (całkowita)
| | bit w lewo. - short int x; (krótka całkowita)
|--------------|-------------------------------------- - long int x; (długa całkowita)
| >>= | j. w. o jeden bit w prawo.
----------|--------------|-------------------------------------- Zwró uwag , e zmiana deklaracji zmiennej bez JEDNOCZESNEJ
16. Prze- | , | Oddziela elementy na li cie argu - zmiany formatu w funkcjach scanf() i printf() spowoduje
cinek | | mentów funkcji, komunikaty o bł dach.
(Comma) | | Stosowany w specjalnych wyra eniach
{L->R} | | tzw. "Comma Expression". Spróbuj samodzielnie dobra odpowiednie formaty w funkcjach
----------|--------------|------------------------------------- scanf() i printf(). Spróbuj zastosowa zamiast funkcji printf()
UWAGI: i scanf() strumienie cin i cout. Pami taj o doł czeniu
* Operatory # i ## stosuje si tylko w PREPROCESORZE. wła ciwych plików nagłówkowych.
* Operatory << i >> mog w C++ przesyła tekst do obiektów cin i
Je li miałe kłopot z dobraniem stosownych formatów, nie
cout dzi ki tzw. Overloadingowi (rozbudowie, przeci eniu) przejmuj si . Przyjrzyj si nast pnym przykładowym programom.
operatorów. Takiego rozszerzenia ich działania dokonali ju Zajmijmy si teraz dokładniej INKREMENTACJ , DEKREMENTACJ i
programi ci producenta w pliku nagłówkowym IOSTREAM.H> OPERATORAMI PRZYPISANIA.

1. Zamknij zb dne okna na ekranie. Pamui taj o zapisaniu


Gdyby okazało si , e oferowane przez powy szy zestaw operatory programów na dyskietk /dysk w tej wersji, która poprawnie działa
nie wystarczaj Ci lub niezbyt odpowiadaj , C++ pozwala na tzw.
OVERLOADING, czyli przypisanie operatorom innego, wybranego lub w ostatniej wersji roboczej.
przez u ytkownika działania. Mo na wi c z operatorami robi 2. Otwórz plik:
takie same sztuczki jak z identyfikatorami. S dz jednak, e ten ASSIGN.CPP
zestaw nam wystarczy, w ka dym razie na kilka najbli szych 3. Wpisz tekst programu:
lekcji.
[P018.CPP]
Podobnie, jak pieni dze na bezludnej wyspie, niewiele warta jest
wiedza, której nie mo na zastosowa praktycznie. Przejd my wi c # include <stdio.h>
do czynu i przetestujmy działanie niektórych operatorów w # include <conio.h>
praktyce.
long int x;
TEST OPERATORÓW JEDNOARGUMENTOWYCH. short int krok;
char klawisz;
Otwórz plik nowego programu:
* Open [F3], int main()
* Wpisz: {
clrscr();
A:\UNARY.CPP printf("Test operatora przypisania += \n");
x=0;
* Wybierz klawisz [Open] w okienku lub naci nij [Enter]. printf("Podaj KROK ? \n");
scanf("%d",&krok);
Wpisz tekst programu: for(;;)
{
[P017.CPP ] printf("\n%d\n", x+=krok);
printf("[Enter] - dalej [K] - Koniec\n");
// UNARY.CPP - operatory jednoargumentowe klawisz = getch();
if (klawisz=='k'|| klawisz=='K') goto koniec;
# include <stdio.h> }
# include <conio.h> koniec:
float x; printf("\n Nacisnij dowolny klawisz...");
getch();
void main(void) return 0;
{ }
clrscr();
30
W tym programie ju sami "r cznie" sprawdzamy, czy nie pora INKREMENTACJA oznacza zwi kszenie liczby o jeden,
przerwa p tl . Zamiast u y typowej instrukcji break (przerwij) DEKREMENTACJA oznacza zmniejszenie liczby o jeden.
PRE oznacza wykonanie in/de-krementacji przed u yciem zmiennej,
stosujemy nielubiane goto, gdy jest bardziej uniwersalne i w POST - in/de-krementacj po u yciu zmiennej.
przeciwie stwie do break pozwala wyra nie pokaza dok d ________________________________________________________________
nast puje skok po przerwaniu p tli. Zwró uwag na nowe elementy
Działanie mo esz prze ledzi na wydruku, który powinien Ci da
w programie: program przykładowy INDEKREM.CPP:

* DEKLARACJE ZMIENNYCH: Demonstruje dzialanie


long int x; (długa, całkowita) PREinkrementacji POSTinkrementacji
short int krok; (krótka, całkowita) Nr --X ++X X-- X++
char klawisz; (zmienna znakowa) 1 99 101 100 100
2 98 102 99 101
* INSTRUKCJ WARUNKOW : 3 97 103 98 102
if (KLAWISZ=='k'|| KLAWISZ=='K') goto koniec; 4 96 104 97 103
(JE ELI zmienna KLAWISZ równa si "k" LUB równa si "K" 5 95 105 96 104
id do etykiety "koniec:")
* Warunek sprawdzany po słowie if jest uj ty w nawiasy. JAK KORZYSTA Z DEBUGGERA?
* Nadanie warto ci zmiennej znakowej char klawisz przez funkcj :
Uruchom program powtórnie naciskaj c klawisz [F7]. Odpowiada to
klawisz = getch(); poleceniu Trace into (wł cz ledzenie) z menu Run. Prze ledzimy
działanie programu przy pomocy Debuggera.
4. Skompiluj program. Popraw ewentualne bł dy.
5. Uruchom program. Podaj c ró ne liczby (tylko całkowite!) Po wykonaniu kompilacji (lub odst pieniu od kompilacji, je li
prze led działanie operatora. nie dokonałe zmian w programie) pojawił si na ekranie pasek
6. Zapisz poprawn wersj programu na dysk/dyskietk [F2]. wyró nienia wokół funkcji main(), bo to od niej rozpoczyna si
7. Je li masz ju do , wyjd z TC - [Alt]-[X], je li nie, zawsze wykonanie programu. Naci nij powtórnie [F7].
pozamykaj tylko zb dne okna i mo esz przej do zada do
samodzielnego rozwi zania -> [Z]! Pasek przesun ł si na funkcj clrscr();. Mign ł na chwil ekran

[Z] u ytkownika, ale na razie nie ma po co tam zagl da , wi c


________________________________________________________________ wykonamy kolejne kroki. Podam klejno: [Klawisz]-[wiersz].
1. Do programu przykładowego wstaw kolejno ró ne operatory
przypisania: [F7] - printf("Demonstruj ...");

*=, -=, /= itp. Zagl damy na ekran u ytkownika [Alt]-[F5].....[Enter] - wracamy


do edytora.
Prze led działanie operatorów.
[F7],[F7]... doszli my do wiersza
2. W programie przykładowym zmie typ zmiennych: b=c=d=e=STO;
long int x; na float x;
short int KROK; float KROK; Zapraszamy teraz debugger do pracy wydaj c mu polecenie "Wykonaj
Przetestuj działanie operatorów w przypadku liczb Inspekcj " [Alt]-[D] | Inspect. Pojawia si okienko dialogowe
zmiennoprzecinkowych. "Inspect".
* Wpisz do okienka tekstowego nazw zmiennej b i naci nij
3. Zapisz w j zyku C++ [Enter].
* negacj iloczynu logicznego,
* sum logiczn negacji dwu warunków. Pojawiło si okienko dialogowe "Inspecting b" zawieraj ce
________________________________________________________________ fizyczny adres pami ci RAM, pod którym umieszczono zmienn b i
warto zmiennej b (zero; instrukcja przypisania nada jej
TEST OPERATORÓW PRE/POST-INKREMENTACJI. warto 100). Naci nij [Esc]. Okienko znikn ło.

W nast pnym programie zilustrujemy działanie wszystkich pi ciu [F7] - for(i=1; i<6; i++);
operatorów inkrementacji (dekrementacja to te inkrementacja
tylko w przeciwn stron ). * Naprowad kursor na zmienn d w tek cie programu i wykonaj
inspekcj powtórnie [Alt]-[D], [I]. Jak widzisz w okienku
[P019.CPP] zmiennej d została nadana warto 100. Naci nij [Esc].

# include <stdio.h> Dokonamy teraz modyfikacji warto ci zmiennej przy pomocy


# include <conio.h> polecenia Evaluate and Modify (sprawd i zmodyfikuj) z menu
Debug.
int b,c,d,e; * Naci nij klawisze [Alt]-[D], [E]. Pojawiło si okienko
int i; dialogowe "Evaluate and Modify". W okienku tekstowym
int STO = 100; "Expression" (wyra enie) widzisz swoj zmienn d.
* Przejd przy pomocy [Tab] do okienka tekstowego "New Value"
void main(void) (nowa warto ) i wpisz tam liczb 1000. Naci nij [Enter] a
{ nast pnie [Esc]. Okienko zamkn ło si . Zmiana warto ci zmiennej
clrscr(); została dokonana.
printf("Demonstruje dzialanie \n");
printf(" PREinkrementacji POSTinkrementacji"); [F7] - printf("...") - wn trze p tli for.
printf("\nNr --X ++X X-- X++ \n");
[F7] - wykonała si p tla.
b = c = d = e = STO;
for(i=1; i<6; i++) Obejrzyjmy wyniki [Alt]-[F5].
{
printf("%d\t%d\t%d\t\t%d\t%d\t\n", i,--b,++c,d--,e++); W czwartej kolumnie widzisz efekt wprowadzonej zmiany:
}
getch(); Demonstruje dzialanie
} PREinkrementacji POSTinkrementacji
Nr --X ++X X-- X++
[S!] PRE / POSTINKREMENTACJA. 1 99 101 1000 100
________________________________________________________________ 2 98 102 999 101
31
3 97 103 998 102 Przykład :
4 96 104 997 103
5 95 105 996 104 float x,y,z; (DEKLARACJA)
const float TEMP = 36.6; (DEFINICJA)
Zwró uwag w programie przykładowym na: x = 42; (ZAINICJOWANIE zmiennej)

* Zliczanie ilo ci wykonanych przez program p tli. [S!] constant/variable - STAŁA czy ZMIENNA.
________________________________________________________________
int i; (deklaracja, e i b dzie zmienn całkowit ) const - (CONSTant) - stała. Deklaracja stałej, słowo kluczowe w
... j zyku C.
i=1; (zainicjowanie zmiennej, nadanie pocz tkowej warto ci) var - (VARiable) - zmienna. W j zyku C przyjmowane domy lnie.
... Słowo var (stosowane w Pascalu) NIE JEST słowem kluczowym j zyka
i++; (powi kszanie i o 1 w ka dej p tli)
... C ani C++ (!).
i<6 (warunek kontynuacji) ________________________________________________________________

Skutek praktyczny:
* Mo liwo grupowej deklaracji zmiennych tego samego typu: * Ma sens i jest poprawna deklaracja:
int b,c,d,e; const float PI = 3.1416;
* Niepoprawna natomiast jest deklaracja:
[Z] var float x;
________________________________________________________________ Je li nie zadeklarowano stałej słowem const, to "zmienna" (var)
4. Zmie w programie przykładowym warto pocz tkow STO na przyjmowana jest domy lnie.
dowoln inn - np. zero. Przetestuj działanie programu.
5. Sprawd , czy mo na wszystkie zmienne u ywane w programie Definicja powoduje nie tylko okre lenie, jakiego typu
przykładowym zadeklarowa wspólnie (jeden wiersz zamiast warto ciami mo e operowa dana zmienna b d funkcja, która
trzech). zostaje od tego momentu skojarzona z podanym identyfikatorem,
________________________________________________________________ ale dodatkowo powoduje:
* w przypadku zmiennej - przypisanie jej warto ci,
* W przypadku funkcji - przyporz dkowanie ciała funkcji.
Zdefiniujmy dla przykładu kilka własnych funkcji.
LEKCJA 11. Jak deklarowa zmienne. Co to jest wska nik.
________________________________________________________________ Przykład:

W trakcie tej lekcji: void UstawDosErrorlevel(int n) /* nazwa funkcji*/


1. Dowiesz si wi cej o deklaracjach. {
2. Poprawisz troch system MS DOS. exit(n); /* skromne ciało funkcji */
3. Dowiesz si co to jest wska nik i do czego słu y. }
________________________________________________________________
Przykład

Wi cej o deklaracjach. int DrukujAutora(void)


{
Deklarowa mo na w j zyku C++: printf("\nAdam MAJCZAK AD 1993/95 - C++ w 48 godzin!\n");
* zmienne; printf("\n Wydanie II Poprawione i uzupełnione.")
* funkcje; return 0;
* typy (chodzi oczywi cie o typy "nietypowe"). }

Zmienne w j zyku C++ mog mie charakter: Przykład


* skalarów - którym przypisuje si nierozdzielne dane np.
całkowite, rzeczywiste, wskazuj ce (typu wska nik) itp. void Drukuj_Pytanie(void)
* agregatów - którym przypisuje si dane typu strukturalnego np. {
printf("Podaj liczbe z zakresu od 0 do 255");
obiektowe, tablicowe czy strukturowe. printf("\nUstawie Ci ERRORLEVEL\t");
}
Powy szy podział nie jest tak całkiem precyzyjny, poniewa
pomi dzy wska nikami a tablicami istnieje w j zyku C++ do W powy szych przykładach zwró uwag na:
specyficzna zale no , ale wi cej na ten temat dowiesz si z * sposób deklarowania zmiennej, przekazywanej jako parametr do
pó niejszych lekcji. funkcji - n i err;
* definicje funkcji i ich wywołanie w programie (podobnie jak w
Zmienne mog by : Pascalu).

* deklarowane, Zilustrujemy zastosowanie tego mechanizmu w programie


* definiowane i przykładowym. Funkcje powy sze s PREDEFINIOWANE w pliku
* inicjowane. FUNKCJE1.H na dyskietce doł czonej do ksi ki. Wpisz i uruchom
program:
Stała to to taka zmienna, której warto mo na przypisa tylko [P020.CPP]
raz. Z punktu widzenia komputera niewiele si to ró ni, bo
miejsce w pami ci i tak, stosownie do zadeklarowanego typu # include "stdio.h"
zarezerwowa trzeba, umie ci w tablicy i zapami ta sobie # include "A:\funkcje1.h"
identyfikator i adres te . Jedyna praktyczna ró nica polega na
tym, e zmiennej zadeklarowanej jako stała, np.: int err;

const float PI = 3.142; void main(void)


{
nie mo na przypisa w programie adnej innej warto ci, innymi DrukujAutora();
słowy zapis: Drukuj_Pytanie();
scanf("%d", &err);
const float PI = 3.14; UstawDosErrorlevel(err);
}
jest jednocze nie DEKLARACJ , DEFINICJ i ZAINICJOWANIEM stałej
PI. Wykorzystajmy te funkcje praktycznie, by zilustrowa sposób
przekazywania informacji przez pracuj cy program do systemu DOS.
32
model SMALL. Zatem kompilacja, któr wykonujesz z IDE daje taki
Zmienna otoczenia systemowego DOS ERRORLEVEL mo e by z wn trza sam efekt, jak zastosowanie kompilatora bcc/tcc w nast puj cy
programu ustawiona na zadan - zwracan do systemu warto . sposób:

[Z] tcc -ms -ls program.c


________________________________________________________________
1. Sprawd , w jakim pliku nagłówkowym znajduje si prototyp Mog wyst pi kłopoty z przerobieniem z EXE na COM tych
funkcji exit(). Opracuj najprostszy program PYTAJ.EXE programów, w których wyst puj funkcje realizuj ce arytmetyk
ustawiaj cy zmienn systemow ERRORLEVEL według schematu: zmiennoprzecinkow (float). System DOS oferuje Ci do takich
celów program EXE2BIN, ale lepiej jest "panowa " nad tym
main() problemem na etapie tworzenia programu.
{
printf("....Pytanie do u ytkownika \n..."); PODSTAWOWE TYPY DANYCH W J ZYKU C++.
scanf("%d", &n);
exit(n); J zyk C/C++ operuje pi cioma podstawowymi typami danych:
}
* char (znak, numer znaku w kodzie ASCII) - 1 bajt;
2. Zastosuj program PYTAJ.EXE we własnych plikach wsadowych typu * int (liczba całkowita) - 2 bajty;
* float (liczba z pływaj cym przecinkiem) - 4 bajty;
*.BAT według wzoru: * double (podwójna ilo cyfr znacz cych) - 8 bajtów;
* void (nieokre lona) 0 bajtów.
@echo off
:LOOP Zakres warto ci przedstawiono w Tabeli poni ej.
cls
echo 1. Wariant 1 Podstawowe typy danych w C++.
echo 2. Wariant 2 ________________________________________________________________
echo 3. Wariant 3
echo Wybierz wariant działania programu...1,2,3 ? Typ Znak Bajtów Zakres warto ci
PYTAJ ________________________________________________________________
IF ERRORLEVEL 3 GOTO START3
IF ERRORLEVEL 2 GOTO START2 char signed 1 -128...+127
IF ERRORLEVEL 1 GOTO START1 int signed 2 -32768...+32767
echo Chyba zartujesz...? float signed 4 +-3.4E+-38 (dokładno : 7 cyfr)
goto LOOP double signed 8 1.7E+-308 (dokładno : 15 cyfr)
:START1 void nie dotyczy 0 bez okre lonej warto ci.
'AKCJA WARIANT 1 ________________________________________________________________
GOTO KONIEC
:START2 signed - ze znakiem, unsigned - bez znaku.
'AKCJA WARIANT 2
GOTO KONIEC Podstawowe typy danych mog by stosowane z jednym z czterech
:START3 modyfikatorów:
'AKCJA WARIANT 3
:KONIEC * signed / unsigned - ze znakiem albo bez znaku
* long / short - długi albo krótki
'AKCJA WARIANT n - oznacza dowolny ci g komend systemu DOS, np.
COPY, MD, DEL, lub uruchomienie dowolnego programu. Do Dla IBM PC typy int i short int s reprezentowane przez taki sam
utworzenia pliku wsadowego mo esz zastosowa edytor systemowy
EDIT. wewn trzny format danych. Dla innych komputerów mo e by
inaczej.
3. Skompiluj program posługuj c si oddzielnym kompilatorem
TCC.EXE. Ten wariant kompilatora jest pozbawiony zintegrowanego Typy zmiennych w j zyku C++ z zastosowaniem modyfikatorów
edytora. Musisz uruchomi go pisz c odpowiedni rozkaz po (dopuszczalne kombinacje).
DOS-owskim znaku zach ty C:\>. Zastosowanie przy kompilacji ________________________________________________________________
małego modelu pami ci pozwol Ci uzyska swój program w wersji
*.COM, a nie *.EXE. Wydaj rozkaz: Deklaracja Znak Bajtów Warto ci Dyr. assembl.
________________________________________________________________
c:\borlandc\bin\bcc -mt -lt c:\pytaj.cpp
char signed 1 -128...+127 DB
Je li pliki znajduj si w ró nych katalogach, podaj wła ciwe int signed 2 -32768...+32767 DB
cie ki dost pu (path). short signed 2 -32768...+32767 DB
________________________________________________________________ short int signed 2 -32768...+32767 DB
long signed 4 -2 147 483 648... DD
+2 147 483 647
[???] CO TO ZA PARAMETRY ??? long int signed 4 -2 147 483 648... DW
________________________________________________________________ +2 147 483 647
Przez sw "ułomno " - 16 bitow szyn i segmentacj pami ci unsigned char unsigned 1 0...+255 DB
komputery IBM PC wymusiły wprowadzenie modeli pami ci: unsigned unsigned 2 0...+65 535 DW
TINY, SMALL, COMPACT, MEDIUM, LARGE, HUGE. Wi cej informacji unsigned int unsigned 2 0...+65 535 DW
na unsigned short unsigned 2 0...+65 535 DW
ten temat znajdziesz w dalszej cz ci ksi ki. signed int signed 2 -32 768...+32 767 DW
Parametry dotycz sposobu kompilacji i zastosowanego modelu signed signed 2 -32 768...+32 767 DW
pami ci: signed long signed 4 -2 147 483 648... DD
-mt - kompiluj (->*.OBJ) wykorzystuj c model TINY +2 147 483 647
-lt - konsoliduj (->*.COM) wykorzystuj c model TINY i zatem enum unsigned 2 0...+65 535 DW
odpowiednie biblioteki (do ka dego modelu jest odpowiednia float signed 4 3.4E+-38 (7 cyfr) DD
biblioteka *.LIB). double signed 8 1.7E+-308 (15 cyfr) DQ
Mo esz stosowa tak e: long double signed 10 3.4E-4932...1.1E+4932 DT
ms, mm, ml, mh, ls, lm, ll, lh. far * (far pointer, 386) 6 unsigned 2^48 - 1 DF, DP
________________________________________________________________ ________________________________________________________________

UWAGI:
Po instalacji BORLAND C++/Turbo C++ standardowo jest przyjmowany * DB - define byte - zdefiniuj bajt;
DW - define word - zdefiniuj słowo (16 bitów);
33
DD - double word - podwójne słowo (32 bity); STDIO.H i CONIO.H.
DF, DP - define far pointer - daleki wska nik w 386;
DQ - quad word - poczwórne słowo (4 * 16 = 64 bity); [P021.CPP]
DT - ten bytes - dziesi bajtów. //UWAGA: Doł cz wła ciwe pliki nagłówkowe !
* zwró uwag , e typ wyliczeniowy enum wyst puje jako odr bny
typ danych (szczegóły w dalszej cz ci ksi ki). void main()
________________________________________________________________ {
float A, B;
clrscr();
scanf("%f %f", &A, &B);
Poniewa nie ma liczb ani short float, ani unsigned short float, printf("\n%f\t%d", A,B);
getch();
słowo int mo e zosta opuszczone w deklaracji. Poprawne s zatem }

deklaracje: [Z]
________________________________________________________________
short a; 3 Zmie w programie przykładowym, w funkcji printf() wzorce
unsigned short b; formatu na %s, %c, itp. Porównaj wyniki.
________________________________________________________________
Zapis +-3.4E-38...3.4E+38 oznacza:
-3.4*10^+38...0...+3.4*10^-38...+3.4*10^+38 Adres w pami ci to taka sama liczba, jak wszystkie inne i wobec
Dopuszczalne s deklaracje i definicje grupowe z zastosowaniem tego mo na ni manipulowa . Adresami rz dz jednak do
listy zmiennych. Zmienne na li cie nale y oddzieli przecinkami: specyficzne prawa, dlatego te w j zyku C++ wyst puje jeszcze
jeden specjalny typ zmiennych - tzw. ZMIENNE WSKAZUJ CE (ang.
int a=0, b=1, c, d; pointer - wska nik). Twoja intuicja podpowiada Ci zapewne, e s
float PI=3.14, max=36.6;
to zmienne całkowite (nie ma przecie komórki pami ci o adresie
Po wi cimy teraz chwil drugiej funkcji, któr ju wielokrotnie 0.245 ani 61/17). Poj cia "komórka pami ci" a nie np. "bajt"
stosowali my - funkcji wej cia - scanf(). u ywam wiadomie, poniewa obszar zajmowany w pami ci przez
zmienn mo e mie ró n długo . Aby komputer wiedział ile
FUNKCJA scanf(). kolejnych bajtów pami ci zajmuje wskazany obiekt (liczba długa,
krótka, znak itp.), deklaruj c wska nik trzeba poda na co
Funkcja formatowanego wej cia ze standardowego strumienia b dzie wskazywał. W sposób "nieoficjalny" ju w funkcji scanf
wej ciowego (stdin). Funkcja jest predefiniowana w pliku STDIO.H korzystali my z tego mechanizmu. Jest to zjawisko specyficzne
dla j zyka C++, wi c zajmijmy si nim troch dokładniej.
i korzystaj c z funkcji systemu operacyjnego wczytuje dane w
postaci tekstu z klawiatury konsoli. Interpretacja pobranych POJ CIE ZMIENNEJ WSKAZUJ CEJ I ZMIENNEJ WSKAZYWANEJ.
przez funkcj scanf znaków nast pi zgodnie z yczeniem
programisty okre lonym przez zadany funkcji format (%f, %d, %c Wska nik to zmienna, która zawiera adres innej zmiennej w
itp.). Wywołanie funkcji scanf ma posta : pami ci komputera. Istnienie wska ników umo liwia po rednie
odwoływanie si do wskazywanego obiektu (liczby, znaku, ła cucha
scanf(Format, Adres_zmiennej1, Adres_zmiennej2...);
znaków itp.) a tak e stosunkowo proste odwołanie si do obiektów
dla przykładu
s siaduj cych z nim w pami ci. Załó my, e:
scanf("%f%f%f", &X1, &X2, &X3);
x - jest umieszczon gdzie w pami ci komputera zmienn
wczytuje trzy liczby zmiennoprzecinkowe X1, X2 i X3. całkowit typu int zajmuj c dwa kolejne bajty pami ci, a

Format decyduje, czy pobrane znaki zostan zinterpretowane np. px - jest wska nikiem do zmiennej x.
jako liczba całkowita, znak, ła cuch znaków (napis), czy te w
inny sposób. Od sposobu interpretacji zale y i rozmieszczenie Jednoargumentowy operator & podaje adres obiektu, a zatem
ich w pami ci i pó niejsze "si gni cie do nich", czyli odwołanie instrukcja:

do danych umieszczonych w pami ci operacyjnej komputera. px = &x;

Zwró uwag , e podaj c nazwy (identyfikatory) zmiennych nale y przypisuje wska nikowi px adres zmiennej x. Mówimy, e:
poprzedzi je w funkcji scanf() operatorem adresowym [&].
Zapis: px wskazuje na zmienn x lub
px jest WSKA NIKIEM (pointerem) do zmiennej x.
int X;
... Jednoargumentowy operator * (naz. OPERATOREM WYŁUSKANIA)
scanf("%d", &X); powoduje, e zmienna "potraktowana" tym operatorem jest
traktowana jako adres pewnego obiektu. Zatem, je li przyjmiemy,
oznacza, e zostan wykonane nast puj ce działania: e y jest zmienn typu int, to działania:
* Kompilator zarezerwuje 2 bajty pomi ci w obszarze pami ci
danych programu na zmienn X typu int; y = x;
* W momencie wywołania funkcji scanf funkcji tej zostanie
przekazany adres pami ci pod którym ma zosta umieszczona oraz
zmienna X, czyli tzw. WSKAZANIE DO ZMIENNEJ;
* Znaki pobrane z klawiatury przez funkcj scanf maj zosta px = &x;
przekształcone do postaci wynikaj cej z wybranego formatu %d - y = *px;
tzn. do postaci zajmuj cej dwa bajty liczby całkowitej ze
znakiem. b d mie identyczny skutek. Zapis y = x oznacza:
"Nadaj zmiennej y dotychczasow warto zmiennej x";
[???] A JE LI PODAM INNY FORMAT ? a zapis y=*px oznacza:
________________________________________________________________ "Nadaj zmiennej y dotychczasow warto zmiennej, której adres w
C++ wykona Twoje rozkazy najlepiej jak umie, niestety nie
sprawdzaj c po drodze formatów, a z zer i jedynek zapisanych w pami ci wskazuje wska nik px" (czyli wła nie x !).
pami ci RAM aden format nie wynika. Otrzymasz bł dne dane.
________________________________________________________________ Wska niki tak e wymagaj deklaracji. Poprawna deklaracja w
opisanym powy ej przypadku powinna wygl da tak:
Poni ej przykład skutków bł dnego formatowania. Doł cz pliki
34
int x,y; Zwró uwag , e kolejno {L<<-R} dotyczy WSZYSTKICH operatorów
int *px; jednoargumentowych.
main() ________________________________________________________________
......

Zapis int *px; oznacza: Je li dwa wska niki wskazuj zmienne takiego samego typu, np. po
"px jest wska nikiem i b dzie wskazywa na liczby typu int".
zadeklarowaniu:
Wska niki do zmiennych mog zamiast zmiennych pojawia si w
wyra eniach po PRAWEJ STRONIE, np. zapisy: int *pX, *pY;
int X, Y;
int X,Y;
int *pX; i zainicjowaniu:
...
pX = &X; pX = &X; pY = &Y;
.......
Y = *pX + 1; /* to samo, co Y = X + 1 */ mo na zastosowa operator przypisania:
printf("%d", *pX); /* to samo, co printf("%d", X); */
Y = sqrt(*pX); /* pierwiastek kwadrat. z X */ pY = pX;
......
Spowoduje to skopiowanie warto ci (adresu) wska nika pX do pY,
s w j zyku C++ poprawne. dzi ki czemu od tego momentu wska nik pY zacznie wskazywa
zmienn X. Zwró uwag , e nie oznacza to bynajmniej zmiany
Zwró uwag , e operatory & i * maj wy szy priorytet ni warto ci zmiennych - ani wielko c X, ani wielko Y, ani ich
operatory arytmetyczne, dzi ki czemu adresy w pami ci NIE ULEGAJ ZMIANIE. Zatem działanie
* najpierw nast puje pobranie spod wskazanego przez instrukcji:
wska nik adresu zmiennej;
* potem nast puje wykonanie operacji arytmetycznej; pY = pX; i *pY = *pX;
(operacja nie jest wi c wykonywana na wska niku, a na
wskazywanej zmiennej!). jest RÓ NE a wynika to znowu z priorytetu operatorów:

W j zyku C++ mo liwa jest tak e sytuacja odwrotna: najpierw * wyłuskanie zmiennych spod podanych adresów,
potem = przypisanie warto ci (ale ju zmiennym a nie
Y = *(pX + 1); wska nikom!)

Poniewa operator () ma wy szy priorytet ni * , wi c: C++ ch tnie korzysta ze wskazania adresu przy przekazywaniu
danych - parametrów do/od funkcji.
najpierw wska nik zostaje zwi kszony o 1;
potem zostaje pobrana z pami ci warto znajduj ca si pod Asekuruj c si na całej linii i podkre laj c, e nie zawsze
wskazanym adresem (w tym momencie nie jest to ju adres zmiennej wygl da to tak prosto i ładnie, posłu si do zademonstrowania
działania wska ników przykładowym programem. Wpisz i uruchom
X, a obiektu "nast pnego" w pami ci) i przypisana zmiennej Y. nast puj cy program:

Taki sposób poruszania si po pami ci jest szczególnie wygodny, [P022-1.CPP wersja 1]


je li pod kolejnymi adresami pami ci rozmie cimy np. kolejne
wyrazy z tablicy, czy kolejne znaki tekstu. # include "stdio.h"
# include "conio.h"
Przyjrzyjmy si wyra eniom, w których wska nik wyst puje po
LEWEJ STRONIE. Zapisy: int a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,x=9,y=10,i;
int *ptr1;
*pX = 0; i X = 0; long int *ptr2;
*pX += 1; i X += 1;
(*pX)++; i X++; /*3*/ void main()
{
maj identyczne działanie. Zwró uwag w przykładzie /*3*/, e clrscr();
ze wzgl du na priorytet operatorów ptr1=&a;
ptr2=&a;
() - najwy szy - najpierw pobieramy wskazan zmienn ; printf("Skok o 2Bajty Skok o 4Bajty");
++ - ni szy, potem zwi kszmy wskazan zmienn o 1;
for(i=0; i<=9; i++)
Gdyby zapis miał posta : {
printf("\n%d", *(ptr1+i));
*pX++; printf("\t\t%d", *(ptr2+i));
}
najpierw nast piłoby getch();
- zwi kszenie wska nika o 1 i wskazanie "s siedniej" zmiennej, }
potem
- wyłuskanie, czyli pobranie z pami ci zmiennej wskazanej przez [P022-2.CPP wersja 2]
nowy, zwi kszony wska nik, zawarto pami ci natomiast, tj.
wszystkie zmienne rozmieszczone w pami ci pozostałyby bez zmian. int a=11,b=22,c=33,d=44,e=55,f=66,g=77,h=88,x=99,y=10,i;
int *ptr1;
long int *ptr2;
[???] JAK TO WŁA CIWIE JEST Z TYM PRIORYTETEM ?
________________________________________________________________ void main()
Wszystkie operatory jednoargumentowe (kategoria 2, patrz Tabela) {
clrscr();
maj taki sam priorytet, ale s PRAWOSTRONNIE Ł CZNE {L<<-R}. ptr1=&a;
Oznacza to, e operacje b d wykonywane Z PRAWA NA LEWO. W ptr2=&a;
wyra eniu *pX++; oznacza to: for (i=0; i<=9; i++)
{
najpierw ++ printf("\n%d", *(ptr1+i));
potem * printf("\t%d", *(ptr2+i));
getch();
35
} INDEKSY. W j zyku C/C++
}
* KA DA OPERACJA korzystaj ca z indeksów mo e zosta wykonana
W programie wykonywane s nast puj ce czynno ci: przy pomocy wska ników;
* posługiwanie si wska nikiem zamiast indeksu na ogół
1. Deklarujemy zmienne całkowite int (ka da powinna zaj 2 przyspiesza operacj .
bajty pami ci) i nadajemy im warto ci w taki sposób aby łatwo
mo na je było rozpozna . Tablice, podobnie jak zmienne i funkcje wymagaj przed u yciem
2. Deklarujemy dwa wska nki: DEKLARACJI. Upraszczaj c problem - komputer musi wiedzie ile
ptr1 - poprawny - do dwubajtowych zmiennych typu int; miejsca zarezerwowa w pami ci i w jaki sposób rozmie ci
ptr2 - niepoprawny - do czterobajtowych zmiennych typu long int. kolejne OBIEKTY, czyli kolejne elementy tablicy.

3. Ustawiamy oba wska niki tak by wskazywały adres w pami ci [???] CO Z TYMI OBIEKTAMI ?
pierwszej liczby a=11. ________________________________________________________________
4. Zwi kszamy oba wska niki i sprawdzamy, co wskazuj . OBIEKTEM w szerokim znaczeniu tego słowa jest ka da liczba,
znak, ła cuch znaków itp.. Takimi klasycznymi obiektami j zyki
Je li kompilator rozmie ci nasze zmienne w kolejnych komórkach programowania operowały ju od dawien dawna. Prawdziwe
pami ci, to powinni my uzyska nast puj cy wydruk: programowanie obiektowe w dzisiejszym, w szym znaczeniu
rozpoczyna si jednak tam, gdzie obiektem mo e sta si tak e
Skok o 2B Skok o 4B co "nietypowego" - np. rysunek. Jest to jednak wła ciwy chyba
11 11 moment, by zwróci Ci uwag , e z punktu widzenia komputera
22 33 obiekt to co , co zajmuje pewien obszar pami ci i z czym wiadomo
33 55 jak post powa .
44 77 ________________________________________________________________
55 99
66 27475 Deklaracja:
77 28448
88 8258 int A[12];
99 27475 oznacza:
10 2844 nale y zarezerwowa 12 KOLEJNYCH komórek pami ci dla 12 liczb
całkowitych typu int (po 2 bajty ka da). Jednowymiarowa tablica
Zwró uwag , e to deklaracja wska nika decyduje, co praktycznie (wektor) b dzie si nazywa "A", a jej kolejne elementy zostan
ponumerowane przy pomocy indeksu:
oznacza operacja *(ptr + 1). W pierwszym przypadku wska nik - zwró uwag , e w C zaczynamy liczy OD ZERA A NIE OD JEDYNKI;
powi ksza si o 2 a w drugim o 4 bajty. Te odpowiednio 2 i 4
bajty stanowi długo komórki pami ci lub precyzyjniej, pola
pami ci przeznaczonego dla zmiennych okre lonego typu. A[0], A[1], A[2], A[3], .... A[11].
Warto ci pojawiaj ce si w drugiej kolumnie po 99 s
przypadkowe i u Ciebie mog okaza si inne. Je li chcemy zadeklarowa :
- indeks i;
C++ pozwala wska nikom nie tylko wskazywa adres zmiennej w - wska nik, wskazuj cy nam pocz tek (pierwszy, czyli zerowy
pami ci. Wska nik mo e równie wskazywa na inny wska nik. Takie element) tablicy;
- sam tablic ;
wskazania: to takie deklaracje powinny wygl da nast puj co:

int X; int pX; int ppX; int i;


pX = &X; ppX = &pX; int *pA;
oznaczamy: int A[12];
*pX - pX wskazuje BEZPO REDNIO zmienn X;
**ppX - ppX skazuje PO REDNIO zmienn X (jest wska nikiem do Aby wska nik wskazywał na pocz tek tablicy A[12], musimy go
wska nika). jeszcze zainicjowa :
***pppX - pppX wskazuje po rednio wska nik do zmiennej X itd.
pA = &A[0];
[Z]
________________________________________________________________ Je li poszczególne elementy tablicy s zawsze rozmieszczane
4 Wybierz dowolne dwa przykładowe programy omawiane wcze niej i KOLEJNO, to:
przeredaguj je posługuj c si zamiast zmiennych - wska nikami do
*pA[0]
tych zmiennych. Pami taj, e przed u yciem wska nika nale y:
* zadeklarowa na jaki typ zmiennych wskazuje wska nik; oznacza:
* przyporz dkowa wska nik okre lonej zmiennej. "wyłuskaj zawarto komórki pami ci wskazanej przez wska nik",
czyli inaczej - pobierz z pami ci pierwszy (zerowy!) element
5 Zastanów si , co oznacza ostrze enie wypisywane podczas tablicy A[]. Je li deklaracja typów elementów tablicy i
uruchomienia programu przykładowego: deklaracja typu wska nika s zgodne i poprawne, nie musimy si
Warning 8: Suspicious pointer conversion in function main. dalej martwi ile bajtów zajmuje dany obiekt - element tablicy.
________________________________________________________________ Zapisy:

*pA[0]; *pA; A[0]


*(pA[0]+1) *(pA+1) A[1]
LEKCJA 12. Wska niki i tablice w C i C++. *(pA[0]+2) *(pA+2) A[2] itd.
________________________________________________________________
s równowa ne i oznaczaj kolejne wyrazy tablicy A[].
W czasie tej lekcji:
1. Dowiesz si wi cej o zastosowaniu wska ników. Je li tablica jest dwu- lub trójwymiarowa, pocz tek tablicy
2. Zrozumiesz, co maj wspólnego wska niki i tablice w j zyku oznacza zapis:
C/C++.
________________________________________________________________ A[0][0];
A[0][0][0];
itd.
WSKA NIKI I TABLICE W C i C++.
Zwró uwag , e wska nik do tablicy *pA oznacza praktycznie
W j zyku C/C++ pomi dzy wska nikami a tablicami istnieje bardzo wska nik do POCZ TKOWEGO ELEMENTU TABLICY:
cisły zwi zek. Do ponumerowania elementów w tablicy słu tzw.
36
*pA == *pA[0] kompilator obliczy jego domnieman zawarto w oparciu o podan
zawarto tablicy. Nie spowoduje wi c bł du zapis:
To samo mo na zapisa w j zyku C++ w jeszcze inny sposób. Je li
A jest nazw tablicy, to zapis: char D[]="Jakis napis"
int A[][2]={{1,2}, {3,4}, {5,6}}
*A
Je li nie podamy ani wymiaru, ani zawarto ci:
oznacza wskazanie do pocz tku tablicy A, a zapisy:
int A[];
*(A+1) *(pA+1) A[1]
*(A+8) *(pA+8) A[8] itd. kompilator "zbuntuje si " i wyka e bł d.

s równowa ne. Podobnie identyczne znaczenie maj zapisy: Dla przykładu, skompiluj program przykładowy. Zwró uwag na
sposób zainicjowania wska nika.
x = &A[i] x=A+i
*pA[i] *(A+i) [P023.CPP]

Nale y jednak podkre li , e pomi dzy nazwami tablic (w naszym # include "stdio.h"
przykładzie A) a wska nikami istnieje zasadnicza ró nica. # include <conio.h>
Wska nik jest ZMIENN , zatem operacje: int a[][2]={ {1,2},{3,4},{5,6},{7,8},{9,10},{11,12} };
char b[]={ "Poniedzialek" };
pA = A; int i;
pA++; int *pa;
char *pb;
s dopuszczalne i sensowne. Nazwa tablicy natomiast jest STAŁ ,
zatem operacje: void main()
{
A = pA; LE ! pa = &a[0][0];
A++; LE ! pb = b; // lub pb = b[0];
clrscr();
s niedopuszczalne i próba ich wykonania spowoduje bł dy ! for (i=0; i<12; i++)
printf("%d\t%c\n", *(pa+i), *(pb+i));
DEKLAROWANIE I INICJOWANIE TABLIC. getch();
}
Elementom tablicy, podobnie jak zmiennym mo emy nadawa
watro ci. Warto ci takie nale y podawa w nawiasach klamrowych, Zwró uwag , e w C++ ka dy wymiar tablicy musi mie swoj par
a wielko tablicy - w nawiasach kwadratowych. nawiasów kwadratowych. Dla przykładu, tablic trójwymiarow
nale y deklarowa nie tak TAB3D[i, j, k] lecz tak:
Przykład
int i, j, k;
int WEKTOR[5]; ...
Tablica WEKTOR jest jednowymiarowa i składa si z 5 elementów TAB3D[i][j][k];
typu int: WEKTOR[0]....WEKTOR[4].
Jest w dobrym stylu panowa nad swoimi danymi i umieszcza je w
Przykład tzw. BUFORACH, czyli w wydzielonych obszarach pami ci o znanym
adresie, wielko ci i przeznaczeniu. W nast pnym programie
float Array[10][5]; przykładowym utworzymy taki bufor w postaci tablicy bufor[20] i
Tablica Array jest dwuwymiarowa i składa si z 50 elementów typu zastosujemy zamiast funkcji scanf() czytaj cej bezpo rednio z
klawiatury par funkcji:
float: Array[0][0], Array[0][1]......Array[0][4]
Array[1][0], Array[1][1]......Array[1][4] gets() - GET String - pobierz ła cuch znaków z klawiatury do
........................................... bufora;
Array[9][0], Array[9][1]......Array[9][4] sscanf(bufor) - odczytaj z bufora (z pami ci).

Przykład Aby unikn nielubianego goto stosujemy konstrukcj for - break.

const int b[4]={1,2,33,444}; Dokładniej p tl for omówimy w trakcie nast pnej lekcji.
Elementom jednowymiarowej tablicy (wektora) b przypisano Poniewa mam nadziej , e "podstawow " posta p tli for
warto i: b[0]=1; b[1]=2; b[2]=33; b[3]=444; pami tasz z przykładów LOOP-n:

Przykład for(i=1; i<100; i++)


{
int TAB[2][3]={{1, 2, 3},{2, 4, 6}}; ...
TAB[0][0]=1 TAB[0][1]=2 TAB[0][2]=3 }
TAB[1][0]=2 TAB[1][1]=4 TAB[1][2]=6
pozwalam sobie troch wyprzedzaj co zastosowa j w programie.
Przykład : Tablica znakowa. Obie formy zapisu daj ten sam Niepodobny do Pascala ani do Basica zapis wynika wła nie z tego,
efekt.
e skok nast puje bezwarunkowo. Nagłówek p tli for
char hej[5]="Ahoj";
char hej[5]={'A', 'h', 'o', 'j'}; * nie inicjuje licznika p tli (zb dne typowe i=1);
hej[0]='A' hej[1]='h' hej[2]='o' itp. * nie sprawdza adnego warunku (zb dne i<100),
* nie liczy p ti (i=i+1 lub i++ te zb dne !).
Przykład : Tablica uzupełniona zerami przez domniemanie.
[P024.CPP]
float T[2][3]={{1, 2.22}, {.5}};
kompilator uzupełni zerami do postaci: # include <stdio.h>
# include <conio.h>
T[0][0]=1 T[0][1]=2.22 T[0][2]=0
T[1][0]=0.5 T[1][1]=0 T[1][2]=0 int liczba, ile = 0, suma = 0;

Je li nawias kwadratowy zawieraj cy wymiar pozostawimy pusty, to void main()


{
37
char bufor[20];
clrscr(); int TABLICA[4][6];
printf("podaj liczby - ja oblicze SREDNIA i SUMA\n");
printf("ZERO = KONIEC\n"); Pami tajmy, e C++ liczy nie od jedynki a od zera, zatem

for(;;) // Wykonuj petle BEZWARUNKOWO TABLICA[0][0] = a11 = 11,


{ TABLICA[2][3] = a34 = 34 itd.
gets(bufor);
sscanf(bufor, "%d", &liczba); Znaj c zawarto tablicy mo emy j zdefiniowa /zainicjowa :
suma += liczba;
ile++; int TABLICA[4][6]={{11,12,13,14,15,16},{21,22,23,24,25,26}
if (liczba == 0) break; // JESLI ==0 PRZERWIJ PETLE {31,32,33,34,35,36},{41,42,43,44,45,46}};
}
printf("Suma wynosi: %d\n", suma); Taki sposób inicjowania tablicy, aczkolwiek pomaga wyja ni
printf("Srednia wynosi: %d\n", (suma / ile)); metod , z punktu widzenia programistów jest troch
getch(); "nieelegancki". Liczb przypisywan danemu elementowi tablicy
} mo na łatwo obliczy .

Poni ej troch bardziej "elegancka wersja" z zastosowaniem p tli TABLICA[i][j] = (i+1)*10 + (j+1);

typu while. Wi cej o p tlach dowiesz si z nast pnej Lekcji. Przykładowo:

[P025.CPP] TABLICA[2][5] = (2+1)*10 +(5+1) = 36

# include <stdio.h> Najbardziej oczywistym rozwi zaniem byłoby napisanie p tli


# include <conio.h>
int i, j;
int liczba, ile=1, suma=0; for (i=0; i<=3; i++)
{ for (j=0; j<=5; j++)
void main() { TABLICA[i][j] = (i+1)*10 + (j+1);}
{ }
char bufor[20];
clrscr(); Spróbujmy prze ledzi rozmieszczenie elementów tablicy w pami ci
printf("podaj liczby - ja oblicze SREDNIA i SUMA\n");
printf("ZERO = KONIEC\n"); i odwoła si do tablicy na kilka sposobów.

gets(bufor); [P026.CPP]
sscanf(bufor, "%d", &liczba);
int TABLICA[4][6]={{11,12,13,14,15,16},{21,22,23,24,25,26},
while (liczba != 0) {31,32,33,34,35,36},{41,42,43,44,45,46}};
{ # include <stdio.h>
suma += liczba; # include <conio.h>
gets(bufor); int *pT;
sscanf(bufor, "%d", &liczba); int i, j;
if(liczba == 0) void main()
printf("I to by bylo na tyle...\n"); {
else clrscr();
ile++; printf("OTO NASZA TABLICA \n");
} for (i=0; i<=3; i++)
printf("Suma wynosi: %d\n", suma); {
printf("Srednia wynosi: %d\n", suma / ile); for (j=0; j<=5; j++)
getch(); printf("%d\t", TABLICA[i][j]);
} printf("\n");
}
Program powy szy, cho operuje tablic , robi to troch jakby za printf("\n\Inicjujemy wska nik na poczatek tablicy\n");
kulisami. Utwórzmy zatem inn - bardziej "dydaktyczn " tablic , printf("i INKREMENTUJEMY wska nik *pT++ \n");
której elementy byłyby łatwo rozpoznawalne.
pT=&TABLICA[0][0];
PRZYKŁADY TABLIC WIELOWYMIAROWYCH. for (i=0; i<4*6; i++)
printf("%d ", *(pT+i));
Dzi ki matematyce bardziej jeste my przyzwyczajeni do zapisu
tablic w takiej postaci: getch();
}
a11 a12 a13 a14 a15 a16
a21 a22 a23 a24 a25 a26 Zwró uwag , e je li tablica ma wymiary A * B (np. 3 * 4) i
a31 a32 a33 a34 a35 a36 składa si z k=A*B elementów, to w C++ zakres indeksów wynosi
a41 a42 a43 a44 a45 a46 zawsze 0, 1, 2, .....A*B-2, A*B-1. Tak wi c tablica 10 x 10
(stuelementowa) b dzie składa si z elementów o numerach
gdzie a i,j /** indeks**/ oznacza element tablicy zlokalizowany 0...99, a nie 1...100.
w:
- wierszu i [P027.CPP]
- kolumnie j
Przypiszmy kolejnym elementom tablicy nast puj ce warto ci: # include <stdio.h>
# include <conio.h>
11 12 13 14 15 16 int TABLICA[4][6];
21 22 23 24 25 26 int *pT;
31 32 33 34 35 36 int i, j;
41 42 43 44 45 46
void main()
Jest to tablica dwuwymiarowa o wymiarach 4WIERSZE X 6KOLUMN, {
czyli krócej 4X6. Liczby b d ce elementami tablicy s typu clrscr();
całkowitego. Je li zatem nazwiemy j TABLICA, to zgodnie z printf("Inicjujemy tablice\n");
zasadami przyj tymi w j zyku C/C++ mo emy j zadeklarowa : for (i=0; i<4; i++)
38
for (j=0; j<6; j++) dwucyfrowych dwie spacje. Po dziesi ciu kolejnych wynikach
{ TABLICA[i][j] = (i+1)*10 + (j+1); } // INDEKS! trzeba wstawi znak nowego wiersza. Sprawdzamy te warunki:
printf("OTO NASZA TABLICA \n");
for (i=0; i<=3; i++) if (*(pT+k) < 10) - je li wynik jest mniejszy ni 10...
{ lub if (T[i][j] < 10);
for (j=0; j<=5; j++) if ((k+1) % 10 == 0) - je li k jest całkowit wielokrotno ci
printf("%d\t", TABLICA[i][j]); 10, czyli - je li reszta z dzielenia równa si zero...
printf("\n");
} Zastosowane w powy szych programach nawiasy klamrowe {}
printf("\n\Inicjujemy wska nik na poczatek tablicy\n"); spełniaj rol INSTRUKCJI GRUPUJ CEJ i pozwalaj podobnie jak
printf("i INKREMENTUJEMY wska nik *pT++ \n"); para BEGIN...END w Pascalu zamkn w p tli wi cej ni jedn
pT=&TABLICA[0][0]; instrukcj . Instrukcje uj te w nawiasy klamrowe s traktowane
for (i=0; i<4*6; i++) jak pojedyncza instrukcja prosta.
printf("%d ", *(pT+i));
Tablice mog zawiera liczby, ale mog zawiera tak e znaki.
getch(); Przykład prostej tablicy znakowej zawiera nast pny program
} przykładowy.

R CZNE I AUTOMATYCZNE GENEROWANIE TABLIC [P029.CPP]


WIELOWYMIAROWYCH.
# include <stdio.h>
Aby nabra wprawy, spróbujmy pomanipulowa inn tablic , znan # include <conio.h>
Ci prawie "od urodzenia" - tabliczk mno enia. Jest to
kwadratowa tablica 10 x 10, której ka dy wyraz opisuje si char T[7][12]={"Poniedzialek",
prost zale no ci T(i,j)=i*j. Je li przypomnimy sobie, e "Wtorek",
indeksy w C++ zaczn si nie od jedynki a od zera, zapis ten "Sroda",
przybierze nast puj c form : "Czwartek",
"Piatek",
int T[10][10]; "Sobota",
T[i][j] = (i+1)*(j+1); "Niedziela"};

Do pełni szcz cia brak jeszcze wska nika do tablicy: char *pT;
int i, j, k;
int *pT; char spacja=' ';
void main()
i jego zainicjowania {
clrscr();
pT = &T[0][0]; pT =&T[0][0];
printf("\t TABLICA znakowa (ineksy)\n\n");
I ju mo emy zaczyna . Mogliby my oczywi cie zainicjowa tablic
for (i=0; i<7; i++)
"na piechot ", ale to i nieeleganckie, i pracochłonne, i o {
pomyłk łatwiej. Pami taj, e komputer myli si rzadziej ni for (j=0; j<12; j++)
programista, wi c zawsze lepiej jemu zostawi mo liwie jak printf("%c ", T[i][j] );
najwi cej roboty. printf("\n");
}
[P028.CPP] printf("\n\t Przy pomocy wska nika \n\n");

# include <stdio.h> for (k=0; k<7*12; k++)


# include <conio.h> {
int T[10][10]; printf("%d ", *(pT+k) ); //TU! - opis w tek cie
int *pT; if ((k+1)%12 == 0) printf("\n");
int i, j, k; }
char spacja = ' '; getch();
void main() }
{
clrscr(); Nazwy dni maj ró n długo , czym wi c wypełniane s puste
printf("\t TABLICZKA MNOZENIA (ineksy)\n"); miejsca w tablicy? Je li w miejscu zaznaczonym komentarzem //TU!
for (i=0; i<10; i++)
{ zmienisz format z
for (j=0; j<10; j++)
{ T[i][j] = (i+1)*(j+1); printf("%c ", *(pT+k) ); na printf("%d ", *(pT+k) );
if (T[i][j]<10)
printf("%d%c ", T[i][j], spacja); uzyskasz zamiast znaków kody ASCII.
else
printf("%d ", T[i][j]); TABLICA znakowa (ineksy)
}
printf("\n"); Poniedzialek
} Wtorek
printf("\n Inicjujemy i INKREMENTUJEMY wska nik *pT++ \n\n"); Sroda
pT=&T[0][0]; Czwartek
for (k=0; k<10*10; k++) Piatek
{ Sobota
if (*(pT+k) < 10) Niedziela
printf("%d%c ", *(pT+k) , spacja);
else Przy pomocy wska nika:
printf("%d ", *(pT+k));
if ((k+1)%10 == 0) printf("\n"); 80 111 110 105 101 100 122 105 97 108 101 107
} 87 116 111 114 101 107 0 0 0 0 0 0
getch(); 83 114 111 100 97 0 0 0 0 0 0 0
} 67 122 119 97 114 116 101 107 0 0 0 0
80 105 97 116 101 107 0 0 0 0 0 0
Po wynikach jednocyfrowych dodajemy trzy spacje a po 83 111 98 111 116 97 0 0 0 0 0 0
39
78 105 101 100 122 105 101 108 97 0 0 0
1. Wykonanie JEDEN raz WYRA ENIA INICJUJ CEGO.
2. Obliczenie warto ci LOGICZNEJ wyra enia logicznego.
Oka e si , e puste miejsca zostały wypełnione zerami. Zero w 3. Je li W_logiczne ma warto PRAWDA (TRUE) nast pi wykonanie
kodzie ASCII - NUL - '\0' jest znakiem niewidocznym, nie było Instrukcji.
wi c widoczne na wydruku w formie znakowej printf("%c"...). 4. Obliczenie wyra enia kroku.
5. Powtórne sprawdzenie warunku - czy wyra enie logiczne ma
[Z] warto ró n od zera. Je li wyra enie logiczne ma warto zero,
________________________________________________________________ nast pi zako czenie p tli.
1. Posługuj c si wska nikiem i inkrementuj c wska nik z ró nym
krokiem - np. pT += 2; pT += 3 itp., zmodyfikuj programy Warunek jest testowany PRZED wykonaniem instrukcji. Je li zatem
przykładowe tak, by uzyska wydruk tylko cz ci tablicy. nie zostanie spełniony warunek, instrukcja mo e nie wykona si
2. Spróbuj zast pi inkrementacj wska nika pT++ dekrementacj , ANI RAZ.
odwracaj c tablic "do góry nogami". Jak nale ałoby poprawnie
zainicjowa wska nik? Instrukcja mo e by INSTRUKCJ GRUPUJ C , składaj c si z
3. Napisz program drukuj cy tabliczk mno enia w układzie instrukcji prostych, deklaracji i definicji zmiennych lokalnych:
szesnastkowym - od 1 * 1 do F * F.
4. Wydrukuj nazwy dni tygodnia pionowo i wspak.
5. Zinterpretuj nast puj ce zapisy: { ci g deklaracji lub definicji;
ci g instrukcji; }
int *pt_int;
float *pt_float; Ogromnie wa ny jest fakt, e C++ ocenia warto logiczn
int p = 7, d = 27; wyra enia według zasady:
float x = 1.2345, Y = 32.14;
void *general; 0 - FALSE, FAŁSZ, inaczej ZERO LOGICZNE je li WYRA ENIE == 0 lub

pt_int = &p; jest fałszywe w znaczeniu logicznym;


*pt_int += d; 1 - TRUE, PRAWDA, JEDYNKA LOGICZNA, je li wyra enie ma
DOWOLN
general = pt_int; WARTO NUMERYCZN RÓ N OD ZERA (!) lub jest prawdziwe w
sensie
pt_float = &x; logicznym.
Y += 5 * (*pt_float);
Przykład:
general = pt_float;
"Klasycznie" zastosowana p tla for oblicza pierwiastki
const char *name1 = "Jasio"; // wska nik do STALEJ kwadratowe kolejnych liczb całkowitych.
char *const name2 = "Grzesio"; // wska nik do STALEGO ADRESU
________________________________________________________________ #include <math.h>
#include <stdio.h>

void main()
LEKCJA 13. Jak tworzy w programie p tle i rozgał zienia. {
_______________________________________________________________ int n;
W trakcie tej lekcji: for (n=0; n<=100; n++) printf("%f\t", sqrt(n));
1. Dowiesz si znacznie wi cej o p tlach. getch();
2. Przeanalizujemy instrukcje warunkowe i formułowanie warunków. }

_______________________________________________________________ Wyra enie inicjuj ce mo e zosta pomini te. Innymi słowy zmienna

Zaczniemy t lekcj nietypowo - od słownika, poniewa dobrze mo e zosta zainicjowana na zewn trz p tli, a p tla przejmie j
jest rozumie dokładnie co si pisze. Tym razem słownik jest tak jaka jest w danym momencie. Przykładowo:
troch obszerniejszy. Pozwalam sobie przytoczy niektóre słowa .....
powtórnie - dla przypomnienia i Twojej wygody. Do organizacji {
p tli b d nam potrzebne nast puj ce słowa: float n;
n=(2*3)/(3*n*n - 1.234);
[S!] conditional expressions - wyra enia warunkowe ......
structural loops - p tle strukturalne for (; n<=100; n++) printf("%f4.4\t", sqrt(n));
________________________________________________________________
if - je eli (poprzedza warunek do sprawdzenia); Przykład:
else - a je li nie, to (w przeciwnym wypadku...);
for - dla; Warunek przerwania p tli mo e mie tak e inny charakter. W
while - dopóki (dopóki nie spełnimy warunku); przykładzie p tla zostanie przerwana, je li ró nica pomi dzy
do - wykonaj, wykonuj; kolejnymi pierwiastkami przekroczy 3.0.
break - przerwij (wykonanie p tli);
switch - przeł cz; void main()
case - przypadek, wariant (jedna z mo liwo ci); {
goto - id do... float y=0, n=0;
default - domy lny, (automatyczny, pozostały); for (; (sqrt(n)-y)<=3.0; n++)
continue - kontynuuj (p tl ); { y=sqrt(n);
________________________________________________________________ printf("%f2.3\t", y);
UWAGA: W C/C++ nie stosuje si słowa THEN. }
getch();
P TLA TYPU for. }

Ogólna posta p tli for jest nast puj ca: UWAGA:


Sprawd , czy nawias (sqrt(n)-y)<=3 mo na pomin ? Jaki jest
for (W_inicjuj ce; W_logiczne; W_kroku) Instrukcja; priorytet operatorów w wyra eniach:
(sqrt(n)-y)<=3.0 i sqrt(n)-y<=3.0
gdzie skrót W_ oznacza wyra enie. Ka de z tych wyra e mo e Jaki b dzie wynik? Dlaczego?
zosta pomini te (patrz --> for(;;)).
Przykład:
Wykonanie p tli for przebiega nast puj co:
40
Instrukcja stanowi ca ciało p tli mo e by instrukcj pust a printf("%c",*Pt++);
wszystkie istotne czynno ci mog zosta wykonane w ramach samego getch();
}
"szkieletu" for. Program przykładowy sprawdza ile kolejnych
liczb całkowitych trzeba zsumowa by uzyska sum nie mniejsz
ni tysi c. AUTOMATYCZNE GENEROWANIE TABLIC W P TLI for

void main() Na dyskietce znajdziesz jeszcze kilka przykładów FORxx.CPP


{ u ycia p tli. A teraz, zanim b dziemy kontynuowa nauk -
float SUMA=0, n=0; przykładowy program do zabawy. P tla for słu y do wykrywania
for (; SUMA < 1000; SUMA+=(++n)); zgodno ci klawisza z elementami tablicy TABL[]. W tablicy D[]
printf("%f", n); umieszczone zostały cz stotliwo ci kolejnych d wi ków, które
getch(); program oblicza sam, wykorzystuj c przybli ony współczynnik.
}
[P030.CPP]
[???] CZY NIE MO NA JA NIEJ ???
________________________________________________________________ # include "conio.h"
Mo na, ale po nabraniu wprawy takie skróty pozwol Ci # include "dos.h"
przyspieszy tworzenie programów. Zmniejszenie wielko ci pliku # include "math.h"
tekstowego jest w dzisiejszych czasach mniej istotne. # include "stdio.h"
Rozszyfrujmy zapis SUMA+=(++n). Preinkrementacja nast puje PRZED
char TABL[27]={"zsxdcvgbhnjm,ZSXDCVGBHNJM<"};
u yciem zmiennej n, wi c: char k;
1. Najpierw ++n, czyli n=n+1. float D[26];
2. Potem SUMA=SUMA+ (n+1). int i;
Dla wyja nienia przedstawiam dwie wersje (obie z p tl for):
void main()
void main() { void main() {
float SUMA=0; { float SUMA=0, n=0; clrscr();
int n; for (; SUMA < 1000; SUMA+=(++n)); } printf("[A]- KONIEC, dostepne klawisze: \n");
clrscr(); printf(" ZSXDCVGBHNJM,i [Shift]");
for (n=0; SUMA<=1000; n++) D[0]=200.0;
{ for(i=1; i<26; i++) D[i]=D[i-1]*1.0577;
SUMA=SUMA+n; for (;;) //patrz przyklad {*}
} {
} k = getch();
________________________________________________________________ for(i=0; i<27; i++)
{ if (k==TABL[i])
To jeszcze nie koniec pokazu elastyczno ci C/C++. W p tli for { sound(D[i]); delay(100); nosound(); }
wolno nam umie ci wi cej ni jedno wyra enie inicjuj ce i };
wi cej ni jedno wyra enie kroku oddzielaj c je przecinkami. if (k=='a'|| k=='A') break; //Wyj cie z p tli.
k = '0';
flat a, b, c; };
const float d=1.2345; }
void main()
{ Po uruchomieniu programu klawisze działaj w sposób
for (a=5,b=3.14,c=10; c; ++a,b*=d,c--) przypominaj cy prosty klawiszowy instrument muzyczny.
printf("\n%f\t%f\t%f", a,b,c);
getch(); Automatyczne zainicjowanie tablicy wielowymiarowej mo emy
} pozostawi C++. Wielko tablicy mo e by znana na etapie
kompilacji programu, lub okre lona w ruchu programu.
Zwró uwag , e zapisy warunku:
C++ traktuje stał (const) jako szczególny przypadek wyra enia
if (c)...; i if (c != 0)...; stałowarto ciowego (ang. true constant expression). Je li
zadeklarowali my zmienn wymiar jako stał , mo emy zastosowa j
s w C++ równowa ne.
np. do zwymiarowania tablicy TAB[]. Przykład poni ej przedstawia
Przykład:
takie wła nie zastosowanie stałych w C++.
Program b dzie pisał kropki a do naci ni cia dowolnego
klawisza, co wykryje funkcja kbhit(), b d ca odpowiednikem [P031.CPP]
KeyPressed w Pascalu. Zapis !kbhit() oznacza "NIE NACI NI TO /* Inicjowanie tablicy przy pomocy stałej */
KLAWISZA", czyli w buforze klawiatury nie oczekuje znak. Zwró
uwag , e funkcja getch() mo e oczekiwa na klawisz w # include <iostream.h>
niesko czono . Aby unikn kłopotliwych sytuacji, czasem
znacznie wygodniej jest zastosowa kbhit(), szczególnie, je li main()
czekamy na DOWOLNY klawisz. {
const int wymiar = 7; //Deklaracja stałej
void main() char TAB[wymiar]; //Deklaracja tablicy
{
for (; !kbhit(); printf(".")); cout << "\n Wielkosc tablicy TAB[] wynosi: " << sizeof TAB;
} cout << " bajtow.";
return 0;
Przykład: }

Wska nik w charakterze zmiennej roboczej w p tli typu for. P tla Umo liwia to dynamiczne inicjowanie tablic pod warunkiem
rygorystycznego przestrzegania zasady, e do zainicjowana stałej
powoduje wypisanie napisu.
mo emy zastosowa wył cznie wyra enie stałowarto ciowe. .
char *Ptr = "Jakis napis";
void main() [S] sizeof - wielko w bajtach.
{
for (; (*Ptr) ;) DANE PREDEFINIOWANE.
41
Dla ułatwienia ycia programi cie producenci kompilatorów C++ void main()
stosuj stałe predefiniowane w plikach nagłówkowych, np.: {
do
_stklen - wielko stosu, {printf(".");}
O_RDONLY - tryb otwarcia pliku "tylko do odczytu", while (!kbhit());
GREEN - numer koloru w palecie, itp., itp. printf("Koniec petli....");
}
Predefiniowanych stałych mo emy u ywa do deklarowania
indeksów/rozmiarów tablic. INSTRUKCJA WARUNKOWA if, if...else i if...else...if..

Instrukcja warunkowa ma posta :

P TLA TYPU while. if (Wyra enie) Instrukcja;


if (Wyra enie) Instrukcja1 else Instrukcja2;
P tl typu while stosuje si na ogół "do skutku", tj. do momentu
Je li Wyra enie ma warto ró n od zera (LOGICZN b d
spełnienia warunku, zwykle wtedy, gdy nie jeste my w stanie NUMERYCZN !) to zostanie wykonana Instrukcja1, w przeciwnym
przewidzie potrzebnej ilo ci cykli. Konstrukcja p tli while razie wykonana zostanie Instrukcja2. Instrukcje mog by
wygl da nast puj co: instrukcjami grupuj cymi. Słowa kluczowe if i else mog by
stosowane wielokrotnie. Pozwala to tworzy np. tzw. drzewa
while (Wyra enie_logiczne) Instrukcja; binarne.

Je li Wyra enie_logiczne ma warto ró n od zera, to zostanie Przykład:


wykonana Instrukcja. Sprawdzenie nast puje PRZED wykonaniem
Instrukcji, tote Instrukcja mo e nie zosta wykonana ANI RAZU. void main()
Instrukcja mo e by INSTRUKCJ GRUPUJ C . {
float a;
Przykład scanf("%f", &a);
if (a<0) printf("Ujemna!");
Stosujemy p tl while do programu pisz cego kropki (patrz else if (a==0) printf("Zero!");
wy ej). else printf("Dodatnia!");
}
void main()
{ Przykład:
while (!kbhit()) printf(".");
} if (a>0) if (a<100) printf("Dwucyfrowa"); else printf("100+");

Przykład inaczej:

Stosujemy p tl while w programie obliczaj cym sum . if(a>0) {if(a<100) printf("Dwucyfrowa"); else printf("100+");}

void main(){ Wyra enie mo e zawiera operatory logiczne:


float SUMA=0, n=0;
clrscr(); if (a>0 && a<100) printf("Dwucyfrowa"); else printf("100+");
while (SUMA<1000) SUMA+=(++n);
printf("SUMA: %4.0f ostatnia liczba: %3.0f", Zapis 100+ oznacza "sto i wi cej".
SUMA, n);
getch(); Przykład:
}
C++ pozwala na krótszy zapis instrukcji warunkowej:
[P032.CPP]
(a>b)? MAX=a : MAX=b;
char *Pointer1="Koniec napisu to \0, *Pointer==0 ";
char *Pointer2="Koniec napisu to \0, *Pointer==0 "; inaczej:

void main(){ if (a>b) MAX=a; else MAX=b;


clrscr();
while (*Pointer1) INSTRUKCJE break i continue.
printf("%c", *Pointer1++);
printf("\nZobacz ten NUL na koncu lancucha znakow\n"); Instrukcja break powoduje natychmiastowe bezwarunkowe
while (*Pointer2) opuszczenie p tli dowolnego typu i przej cie do najbli szej
printf("%c", *Pointer2++); instrukcji po zako czeniu p tli. Je li w p tli for opu cimy
printf("%d", *Pointer2); wyra enie logiczne, to zostanie automatycznie przyj te 1. P tla
getch(); b dzie zatem wykonywana bezwarunkowo w niesko czono . W
} przykładzie poni ej niesko czon p tl przerywa po podaniu z
kalwiatury zera instrukcja break.
P TLA do...while.
Przykład:
Konstrukcja dwuczłonowa do...while tworzy p tl , która:
float a, sigma=0;
* jest wykonywana zawsze CO NAJMNIEJ JEDEN RAZ, poniewa warunek void main(){
for (;;)
jest sprawdzany nie na wej ciu do p tli, a na wyj ciu z p tli; {
* przerwanie p tli powodowane jest przez NIESPEŁNIENIE WARUNKU. printf("\n Podaj liczbe do sumowania\n");
scanf("%f", &a);
Schemat p tli do...while jest nast puj cy: if (a==0) break;
sigma+=a;
do Instrukcja while (Wyra enie_logiczne); printf("\n SUMA: %f",sigma);
}
Instrukcja mo e by instrukcj grupuj c . printf("Nastapil BREAK");
getch();
Przykład: }
42
[P034.CPP]
Instrukcja continue.
# define pisz printf
Instrukcja continue powoduje przedwczesne, bezwarunkowe # include <stdio.h>
zako czenie wykonania wewn trznej instrukcji p tli i podj cie
próby realizacji nast pnego cyklu p tli. Próby, poniewa void main()
najpierw zostanie sprawdzony warunek kontynuacji p tli. Program {
z przykładu poprzedniego zmodyfikujemy w taki sposób, by int Numer_Dnia;
pisz("\nPodaj numer dnia tygodnia\n");
* je li liczba jest dodatnia - dodawał j do sumy sigma; scanf("%d", &Numer_Dnia);
* je li liczba jest ujemna - nie robił nic, pomijał bie c switch(Numer_Dnia)
p tl przy pomocy rozkazu continue; {
(Poniewa warunek wej ciowy p tli jest zawsze spełniony, to case 1: pisz("PON."); break;
p tl zawsze uda si kontynuowa .) case 2: pisz("WTOR"); break;
* je li liczba równa si zero - przerywał p tl instrukcj break case 3: pisz("SRO."); break;
case 4: pisz("CZW."); break;
case 5: pisz("PIO."); break;
Przykład: case 6: pisz("SOB."); break;
case 7: pisz("NIEDZ."); break;
float a, sigma=0; default: pisz("\n ?????");
void main() }
{ }
for (;;)
{ Instrukcja break przerywa wykonanie. Wariant default zostanie
printf("\n Sumuje tylko liczby dodatnie\n"); wykonany TYLKO w przypadku podania liczby wi kszej ni 7.
scanf("%f", &a);
if (a<0) continue; INSTRUKCJA POWROTU return.
if (a==0) break;
sigma+=a; Słu y do zako czenia wykonania zawieraj cej j funkcji i mo e
printf("\n SUMA: %f",sigma); mie posta :
}
printf("Nastapil BREAK"); return;
getch(); return stała;
} return Wyra enie;
return (wyra enie);
INSTRUKCJE switch i case.
Przykład:
Instrukcja switch dokonuje WYBORU w zale no ci od stanu
wyra enia przeł czaj cego (selector) jednego z mo liwych Definiujemy funkcj _dodaj() zwracaj c , poprzez instrukcj
przypadków - wariantów (case). Ka dy wariant jest oznaczony przy return warto przekazanego jej w momencie wywołania argumentu
powi kszon o 5.
pomocy stałej - tzw. ETYKIETY WYBORU. Wyra enie przeł czaj ce
mo e przyjmowa warto ci typu int. Ogólna posta istrukcji jest float _dodaj(float x)
nast puj ca: {
x+=5;
switch (selector) return x;
{ }
case STAŁA1: Ci g_instrukcji-wariant 1;
case STAŁA2: Ci g_instrukcji-wariant 2; Funkcja _dodaj() zwraca warto i nadaje t warto zmiennej
............................... wynik zadeklarowanej nazewn trz funkcji i znanej w programie
case STAŁAn: Ci g_instrukcji-wariant n; głównym. A oto program w cało ci.
default : Ostatni_ci g_instrukcji;
} [P035.CPP]

Nale y podkre li , e po dokonaniu wyboru i skoku do etykiety float funkcja_dodaj(float x)


wykonane zostan równie WSZYSTKIE INSTRUKCJE PONI EJ DANEJ {
ETYKIETY. Je li chcemy tego unikn , musimy doda rozkaz break. x += 5;
return x;
[P033.CPP] }
float dana = 1, wynik = 0;
# define pisz printf //dla przypomnienia
# include <stdio.h> void main()
void main() {
{ clrscr();
int Numer_Dnia; wynik = funkcja_dodaj(dana);
pisz("\nPodaj numer dnia tygodnia\n"); printf("%f", wynik);
scanf("%d", &Numer_Dnia); }
switch(Numer_Dnia)
{ INSTRUKCJA SKOKU BEZWARUNKOWEGO goto I ETYKIETY.
case 1: pisz("PONIEDZIALEK.");
case 2: pisz("WTOREK"); Składnia instrukcji skoku goto jest nast puj ca:
case 3: pisz("SRODA.");
case 4: pisz("CZWARTEK."); goto Identyfikator_etykiety;
case 5: pisz("PIATEK.");
case 6: pisz("SOBOTA."); UWAGA: Po ka dej etykiecie musi wyst pi CO NAJMNIEJ JEDNA
case 7: pisz("NIEDZIELA."); INSTRUKCJA. Je li etykieta oznacza koniec programu, to musi po
default: pisz("\n *********************"); niej wyst pi instrukcja pusta. Instrukcja goto nie cieszy si
} powodzeniem ani dobr sław (niesłusznie!). Ostro ne i umiej tne
}
jej stosowanie jeszcze nikomu nie zaszkodziło. Nale y tu
Zwró uwag , e w przykładzie wariant default zostanie wykonany zaznaczy , e etykieta nie wymaga deklaracji.
ZAWSZE, nawet je li podasz liczb wi ksz ni 7.
43
Przykład:
ZMIENNE AUTOMATYCZNE - auto.
Program poni ej generuje d wi ki i "odlicza".
Otrzymuj przydział miejsca w pami ci dynamicznie - na stosie
[P036.CPP] procesora, w momencie rozpocz cia wykonania tego bloku programu,

#include <dos.h> w którym zmienne te zostały zadeklarowane. Przydzielenie pami ci


#include <stdio.h>
nie zwalnia nas z obowi zku zainicjowania zmiennej (wcze niej
void main() warto zmiennej jest przypadkowa). Zmienne automatyczne
{ "znikaj " po zako czeniu wykonywania bloku. Pami im
int czestotliwosc=5000, n=10, milisekundy=990; przydzielona zostaje zwolniona. Przykład: auto long suma;
printf("\n");
start: ZMIENNE REJESTROWE - register.
{
sound(czestotliwosc); Zmienne rejestrowe s tak e zmiennymi lokalnymi, widocznymi
delay(milisekundy); tylko wewn trz tego bloku programu, w którym zostały
nosound(); zadeklarowane. C++ mo e wykorzysta dwa rejestry mikroprocesora
czestotliwosc/=1.2; - DI i SI do przechowywania zmiennych. Je li zadeklarujemy w
printf("%d\b", --n); programie wi cej zmiennych jako zmienne rejestrowe - zostan one
if (n) goto start; //petle strukturalne zrob sam(a)
} umieszczone na stosie. Znaczne przyspieszenie działania programu

koniec: ; powoduje wykorzystanie rejestru do przechowywania np. licznika


} // Tu jest instrukcja pusta. p tli.

[S!] DOS API function names - nazwy funkcji z interfejsu DOS Przykład:
________________________________________________________________
sound - d wi k; register int i;
delay - opó nienie, zwłoka; .....
nosound - bez d wi ku (wył cz d wi k); for (i=1; i<1000; i++) {.....}
________________________________________________________________
ZMIENNE ZEWN TRZNE - extern.
[Z]
________________________________________________________________ Je li zmienna została - raz i TYLKO RAZ - zadeklarowana w
1. Bior c pod uwag , e iloraz cz stotliwo ci kolejnych d wi ków pojedynczym segmencie du ego programu, zostanie w tym e
segmencie umieszczona w pami ci i potraktowana podobnie do
jest stały tzn. Fcis/Fc=Ffis/Ff=....=const oraz, e oktawa to zmiennych typu static. Po zastosowaniu w innych segmentach
podwojenie cz stotliwo ci, opracuj program i oblicz deklaracji extern zmienna ta mo e by dost pna w innym segmencie
cz stotliwo ci poszczególnych d wi ków.
2. Spróbuj zastosowa w programie przykładowym kolejno p tle programu.
for, while, do...while.
3. Zastosuj we własnym programie do wiadczalnym instrukcj Przykład: extern int NUMER;
switch.

STRUKTURY.

LEKCJA 14. Jak tworzy i stosowa struktury. Poznane wcze niej tablice mog zawiera wiele danych, ale
wszystkie te dane musz by tego samego typu. Dla zgrupowania
________________________________________________________________ powi zanych ze sob logicznie danych ró nego typu C/C++ stosuje
STRUKTURY, deklarowane przy pomocy słowa struct. Kolejne pola
W trakcie tej lekcji poznasz poj cia: struktury s umieszczane w pami ci zgodnie z kolejno ci ich
* Klasy zmiennej. deklarowania. Struktur , podobnie jak zmienn , MUSIMY
* Struktury. ZADEKLAROWA . Struktura jest objektem bardziej zło onym ni
* Pola bitowego. pojedyncza zmienna, wi c i deklaracja struktury jest bardziej
* Unii. skomplikowana. Deklaracja struktury składa si z nast puj cych
Dowiesz si tak e wi cej o operacjach logicznych. elementów:
________________________________________________________________
1. Słowo kluczowe struct (obowi zkowe).
2. Nazwa (opcjonalna). Je li podamy nazw , to nazwa ta b dzie
CO TO JEST KLASA ZMIENNEJ? oznacza dany typ struktury.
3. Nawias klamrowy {
W j zyku C i C++ programista ma wi kszy wpływ na rozmieszczenie 4. Deklaracje kolejnych składników struktury.
zmiennych w pami ci operacyjnej komputera i w rejestrach 5. Nawias klamrowy }
mikroprocesora. Mo e to mie decyduj cy wpływ na dost pno 6. Lista nazw struktur okre lonego powy ej typu (mo e zosta
danych z ró nych miejsc programu i szybko działania programu. zadeklarowana oddzielnie).
Nale y podkre li , e TYP ZMIENNEJ (char, int, float itp.)
decyduje o sposobie interpretacji przechowywanych w pami ci zer Przykład. Deklaracja ogólnego typu struktury i okre lenie
i jedynek, natomiast KLASA ZMIENNEJ decyduje o sposobie wewn trznej postaci struktury.
przechowywania zmiennej w pami ci. W C++ wyst puj cztery klasy
zmiennych. struct Ludzie
{
ZMIENNE STATYCZNE - static. char Imiona[30];
char Nazwisko[20];
Otrzymuj stał lokalizacj w pami ci w momencie uruchamiania int wiek;
programu. Zachowuj swoj warto przez cały czas realizacji char pokrewienstwo[10]
programu, chyba, e wiadomie za damy zmiany tego stanu - np. };
instrukcj przypisania.
Przykład deklaracji: static float liczba; Je li okre limy ju typ struktury - czyli rodzaj, wielko i
przeznaczenie poszczególnych pól struktury, mo emy dalej tworzy
W wi kszo ci kompilatorów C++ zmienne statyczne, które nie
zostały jawnie zainicjowane w programie, otrzymuj po - deklarowa i inicjowa konkretne struktury danego typu.
zadeklarowaniu warto ZERO.
44
Przykład. Deklaracja zmiennych - struktur tego samego typu.
return 0;
struct Ludzie Moi, Twoi, Jego, Jej, Szwagra; }

Deklaracj struktur mo na poł czy . Tablice mog by elementami struktur, ale i odwrotnie - ze
struktur, jak z cegiełek mo na tworzy konstrukcje o wy szym
Przykład. Poł czona deklaracja struktur. stopniu zło ono ci - struktury struktur i tablice struktur.
Je li tablica składa si z liczb typu int, to deklarujemy j :
struct Ludzie
{ char pokrewienstwo[10]; int TABLICA[10];
char Imiona[30];
int wiek; je li tablica składa si ze struktur, to deklarujemy j :
} Moi, Twoi, Szwagra;
struct TABLICA[50];
Struktury statyczne
W przykładzie poni ej przedstawiono
* maj stałe miejsce w pami ci w trakcie całego programu;
* s "widoczne" i dost pne w całym programie. * deklaracj jednowymiarowej tablicy LISTA[50],
* elementami tablicy s struktury typu SCzlowiek,
Zadeklarujemy teraz typ struktury i zainicjujemy dwie struktury. * jednym z elementów ka dej struktury SCzlowiek jest struktura
"ni szego rz du" typu Adres;

Przykład. Zainicjowanie dwu struktur statycznych. [P038.CPP]

struct Ludzie int main()


{ char pokrewienstwo[10]; {
char Imiona[30];
int wiek; struct Adres
}; {
char Ulica[30];
struct Ludzie Moi, Szwagra; int Nr_Domu;
static struct Ludzie Moi = { "Stryjek", "Walenty", 87 }; int Nr_Mieszk;
static struct Ludzie Szwagra = { "ciotka", "Ala", 21 }; };

Zapis struct SCzlowiek


{
static struct Ludzie Szwagra; char Imie[20];
int Wiek;
oznacza: struct Adres Mieszkanie;
statyczna struktura typu "Ludzie" pod nazw "Szwagra". };

Do struktury w cało ci mo emy odwoływa si za pomoc jej nazwy struct SCzlowiek LISTA[50];
a do poszczególnych elementów struktury poprzez nazw struktury
i nazw pola struktury - ROZDZIELONE KROPK ".". Zademonstrujmy LISTA[1].Wiek=34;
to na przykładzie. Zwró uwag na ró ne sposoby przekazywania LISTA[1].Mieszkanie.Nr_Domu=29;
danych pomi dzy strukturami: printf("%d", LISTA[1].Mieszkanie.Nr_Domu);

C4.Wiek=Czlowiek2.Wiek; - przekazanie zawarto ci pojedynczego return 0;


pola numerycznego; }
C4=Czlowiek3; - przekazanie zawarto ci całej struktury Czlowiek3
Zapis
do C4.
printf("%d", LISTA[1].Mieszkanie.Nr_Domu
Przykład. Program manipuluj cy prost struktur .
oznacza:
[P037.CPP] * wybierz element nr 1 z tablicy LISTA;
(jak wynika z deklaracji tablicy, ka dy jej element b dzie miał
int main() wewn trzn struktur zorganizowan tak, jak opisano w deklaracji
{
struktury SCzlowiek);
struct Ludzie * wybierz ze struktury typu SCzlowiek pole Mieszkanie;
{ (jak wynika z deklaracji, pole Mieszkanie b dzie miało
char Imie[20]; wewn trzn organizacj zgodn ze struktur Adres);
int Wiek; * ze struktury typu Adres wybierz pole Nr_Domu;
char Status[30]; * Wydrukuj zawarto pola pami ci interpretuj c j jako liczb
char Tel_Nr[10]; typu int - w formacie %d.
};
Słowo struktura tak doskonale pasuje, e chciałoby si
static struct Ludzie powiedzie :
Czlowiek1={"Ala", 7, "Ta, co ma Asa","?"}, je li struktura struktur jest wielopoziomowa, to podobnie, jak
Czlowiek2={"Patrycja", 13, "Corka", "8978987"}, przy wielowymiarowych tablicach, ka dy poziom przy nadawaniu
Czlowiek3={"Krzysztof", 27, "Kolega z przedszkola", "23478"}; warto ci musi zosta uj ty w dodatkow par nawiasów klamrowych.

struct Ludzie C4, C5;


[???] A CO Z ŁA CUCHAMI ZNAKOWYMI ?
C4=Czlowiek3; ________________________________________________________________
C4.Wiek=Czlowiek2.Wiek; J zyk C++ oferuje do kopiowania ła cuchów znakowych specjaln
C5=Czlowiek1; funkcj strcpy(). Nazwa funkcji to skrót STRing CoPY (kopiuj
ła cuch). Sposób wykorzystania tej funkcji:
clrscr();
strcpy(Dok d, Sk d); lub
printf("%s %d %s\n", C4.Imie, C4.Wiek, C4.Status); strcpy(Dok d, "ła cuch znaków we własnej osobie");
printf("%s %s",C5.Imie, C5.Status);
45
Szczegóły - patrz Lekcja o ła cuchach znakowych. lub 1. Wiek rzadko przekracza 255 lat a liczba dzieci zwykle nie
________________________________________________________________
jest wi ksza ni 15. Nawet najbardziej niestali panowie nie
zd o eni si i rozwie wi cej ni 7 razy. Gdyby my zatem
STRUKTURY I WSKA NIKI. chcieli zapisa informacje

Wska niki mog wskazywa struktur w cało ci lub element * płe 0 - m czyzna, 1 - kobieta ( 1 bit );
struktury. J zyk C/C++ oferuje specjalny operator -> który * wiek 0 - 255 lat (8 bitów);
pozwala na odwoływanie si do elementów struktury. W przykładzie * ilo dzieci 0 - 15 (4 bity);
* kolejny numer mał e stwa 0 - 7 (3 bity);
poni ej przedstawiono ró ne sposoby odwołania si do elementów
trzech identycznych struktur STA, STB, STC. to przecie wszystkie te informacje mog nam si zmie ci w
jednym szesnastobitowym rejestrze lub w dwu bajtach pami ci.
[P039.CPP] Takie kilka bitów wydzielone i maj ce okre lone znaczenie to
wła nie pole bitowe. C++ pozwala tak e na uwzgl dnianie znaku w
int main() polach bitowych. Pola bitowe mog by typu int i unsigned int
{ (czyli takie jak w przykładzie poni ej). Je li jakie dane
chcemy przechowywa w postaci pola bitowego, w deklaracji
struct struktury sygnalizujemy to dwukropkiem. Stwarza to dwie istotne
{ mo liwo ci:
char Tekst[20]; * bardziej ekonomicznego wykorzystania pami ci;
int Liczba1; * łatwego dodatkowego zaszyfrowania danych.
float Liczba2;
} STA, STB, STC, *Pointer; [P040.CPP]

STA.Liczba1 = 1; //Pamietaj o dolaczeniu plikow naglowkowych !


STA.Liczba2 = 2.2;
strcpy(STA.Tekst, "To jest tekst"); int main()
{
STB=STA;
struct USC {
Pointer = &STC; int Sex : 1;
Pointer->Liczba1 = 1; unsigned Wiek : 8;
Pointer->Liczba2 = 2.2; unsigned Dzieci : 4;
strcpy(Pointer->Tekst, STA.Tekst); unsigned Ktora : 3; } Facet;

printf("\nLiczba1-STA Liczba2-STB Tekst-STC\n\n"); int bufor;


printf("%d\t", STA.Liczba1); clrscr();
printf("%f\t", STB.Liczba2); Facet.Sex = 0;
printf("%s", Pointer->Tekst); printf("\n Ile ma lat ? : ");
scanf("%d", &bufor); Facet.Wiek = bufor;
return 0; printf("\n Ktore malzenstwo ? : ");
} scanf("%d", &bufor); Facet.Ktora = bufor;
printf("\n Ile dzieci ? : ");
Rozszyfrujmy zapis: scanf("%d", &bufor); Facet.Dzieci = bufor;
printf("\n\n");
strcpy(Pointer->Tekst, STA.Tekst); if (Facet.Ktora) printf("Facet ma %d zone", Facet.Ktora);
printf("\nPlec: Dzieci: Wiek (lat): \n\n");
Skopiuj ła cuch znaków z pola Tekst struktury STA do pola Tekst printf("%d\t%d\t%d", Facet.Sex, Facet.Dzieci, Facet.Wiek);
struktury wskazywanej przez pointer. Prawda, e to całkiem getch();
proste?
return 0;
[???] CZY MUSIMY TO ROZDZIELA ? }
________________________________________________________________
Jak zauwa yłe , liczby mogliby my zapisywa tak e jako ła cuchy Uruchom program i sprawd co si stanie, je li Facet b dzie miał
znaków, ale wtedy nie mogliby my wykonywa na tych liczbach
działa . Konwersj liczba - ła cuch znaków lub odwrotnie ła cuch np. 257 lat lub 123 on . Przekroczenie zadeklarowanego zakresu
powoduje obci cie cz ci bitów.
znaków - liczba wykonuj w C specjalne funkcje np.:
atoi() - Ascii TO Int.; Aby uzyska "wyrównanie" pola bitowego do pocz tku słowa nale y
itoa() - Int TO Ascii itp. przed interesuj cym naspolem bitowym zdefiniowa tzw. pole
Wi cej informacji na ten temat i przykłady znajdziesz w dalszej puste:
cz ci ksi ki.
________________________________________________________________ * pole bitowe bez nazwy;
* długo pola pustego powinna wynosi 0.

Elementami struktury mog by zmienne dowolnego typu, ł dznie z Poni ej przedstawiam przykład pola bitowego zajmuj cego trzy
innymi strukturami. kolejne słowa 16 bitowe. Dodanie pola pustego wymusza
rozpocz cie pola pole_IV od pocz tku trzeciego słowa maszynowego
Ciekawostka:
________________________________________________________________ (zakładamy, e pracujemy z komputerem 16 bitowym).
Wska nik do deklarowanej struktury mo e by w j zyku C/C++ jak
jeden z jej WŁASNYCH elementów. Je li wska nik wchodz cy w skład struct
{
struktury wskazuje na WŁASN struktur , to nazywa si to unsigned pole_I:4;
AUTOREFERENCJ STRUKTURY. unsigned pole_II:10;
________________________________________________________________ unsigned pole_III:4;
unsigned :0; /* to jest pole puste */
POLA BITOWE. unsigned pole_IV:5;
} pole_przykladowe;
Cz sto zdarza si , e jaka zmienna ma zaw ony zakres warto ci.
Zwró uwag , e cz bitów w drugim i trzecim słowie maszynowym
Dla przykładu zmienne logiczne (tzw. flagi) to zawsze tylko 0
46
nie zostanie wykorzystana.
Miło byłoby poogl da to troch dokładniej w przykładowych
UNIE czyli ZMIENNE WARIANTOWE. programach, ale potrzebne nam do tego b d funkcje. Zajmijmy si
wi c uwa niej funkcjami.
Unie to specyficzne struktury, w których pola pami ci
przeznaczone na objekty ró nego typu nakładaj si . Je li jaka
zmienna mo e by reprezentowana na kilka sposobów (wariantów) to LEKCJA 15. Jak posługiwa si funkcjami.
________________________________________________________________
sensowne jest przydzielenie jej nie struktury a unii. W danej
chwili pole pami ci nale ce do unii mo e zawiera TYLKO JEDEN W trakcie tej lekcji dowiesz si wi cej o:
WARIANT. W przykładzie - albo cyfr (która znakowo jest widziana * funkcjach i prototypach funkcji;
* przekazywaniu argumentów funkcji;
jako znak ASCII o kodzie 2,3,4 itd.) albo napis. Do * współpracy funkcji ze wska nikami.
zadeklarowania unii słu y słowo kluczowe union. _______________________________________________________________

[P041.CPP] Aby przedstawi działanie operatorów logicznych opracujemy


własn funkcj Demo() i zastosujemy j w programie przykładowym
#include "string.h" [najwa niejszy fragment].
#include "stdio.h"
int Demo(int Liczba)
int BUFOR, i; {
int MaxNr=15;
int main() for (; MaxNr>=0; MaxNr--)
{ {
if ((Liczba>>MaxNr)&1)
union printf("1");
{ else
int Cyfra; printf("0");
char Napis[20]; }
} Unia; return 0; //Funkcja nie musi nic zwracac
}
for (i=1; i<11; i++)
{ Funkcja przesuwa liczb o kolejno 15, 14, 13 itd. bitów w prawo
printf("\n Podaj liczbe jednocyfrowa: "); i sprawdza, czy 16, 15, 14 bit jest jedynk , czy zerem. Iloczyn
scanf("%d", &BUFOR); logiczny z jedynk ( 0000000000000001 ) gwarantuje nam, e wpływ
if (BUFOR<0 || BUFOR>9) na wynik operacji b dzie miał tylko ten jeden bit (patrz wy ej -
strcpy(Unia.Napis, "TO NIE CYFRA !"); jak działaj operatory logiczne).
else
Unia.Cyfra = BUFOR; [P042.CPP]
printf("\n Pole jako Cyfra Pole jako Napis \n");
# include <stdio.h>
/* Tu wyswietlimy warianty: Pole jako cyfra i jako napis*/ int Demo(int Liczba)
/* Petla pozwoli Ci przeanalizowac wszystkie cyfry 0...9 */ {
int MaxNr=15;
printf(" %d\t\t\t%s", Unia.Cyfra, Unia.Napis); for (; MaxNr>=0; MaxNr--)
} if ((Liczba>>MaxNr)&1) printf("1");
return 0; else printf("0");
} return 0;
}

P tla w przykładzie nie ma znaczenia. Słu y tylko dla Twojej char odp;
wygody - dzi ki niej nie musisz uruchamia programu
przykładowego wielokrotnie. Podobnie zmienne BUFOR oraz i maj int main()
znaczenie pomocnicze. Zwró uwag , e nieprawidłowa {
interpretacja zawarto ci pola unii mo e spowodowa wadliwe int X, Y;
działanie programu. clrscr();
printf("\nPodaj dwie liczby calkowite od -32768 do +32767\n");
[Z] printf("\nLiczby X i Y rozdziel spacja");
________________________________________________________________ printf("\nPo podaniu drugiej liczby nacisnij [Enter]");
1. W programie przykładowym zamie uni na struktur . Porównaj printf("\nLiczby ujemne sa w kodzie dopelniajacym");
działanie. printf("\nskrajny lewy bit oznacza znak 0-Plus, 1-Minus");
2 Przydziel na Wiek w strukturze Facet o jeden bit mniej. Ile for(;;)
lat mo e teraz mie Facet ? {
3. Zmodyfikuj program przykładowy tak, by napis o liczbie printf("\n");
m ów/ on zale ał od płci - pola Sex. scanf("%d %d", &X, &Y);
4. Zamieniwszy uni na struktur w programie, sprawd , czy printf("\nX:\t"); Demo(X);
wpływa to na wielko pliku *.EXE. printf("\nY:\t"); Demo(Y);
________________________________________________________________ printf("\n~Y:\t"); Demo(~Y);
printf("\nX&Y:\t"); Demo(X&Y);
OPERACJE LOGICZNE. printf("\nX|Y:\t"); Demo(X|Y);
printf("\nX^Y:\t"); Demo(X^Y);
Zaczniemy od operacji logicznych na pojedynczych bitach liczb printf("\nY:\t"); Demo(Y);
całkowitych. W C++ mamy do dyspozycji nast puj ce operatory: printf("\nY>>1:\t"); Demo(Y>>1);
printf("\nY<<2:\t"); Demo(Y<<2);
~ Zaprzeczenie (NOT) ~0=1; ~1=0; printf("\n\n Jeszcze raz? T/N");
| Suma (OR) 0|0=0; 0|1=1; 1|0=1; 1|1=1; odp=getch();
& Iloczyn (AND) 0&0=0; 0&1=0; 1&0=0; 1&1=1; if (odp!='T'&& odp!='t') break;
^ Alternatywa wył czna ALBO...ALBO (XOR) }
0^0=0; 0^1=1; 1^0=1; 1^1=0; return 0;
<< Przesuni cie bitów w lewo (Shift Left) }
<< 00001000 = 00010000 dzie . 8<<1=16
>> Przesuni cie bitów w prawo (Shift Right) Je li operacje maj by wykonywane nie na bitach a na logicznej
>> 00001000 = 00000100 dzie . 8>>2=2 warto ci wyra e :
47
|| oznacza sum (LUB); Po pierwsze:
&& oznacza iloczyn (I);
! oznacza negacj (NIE). C/C++ mo e sam dokonywa konwersji, czyli zmiany typów danych
naogół zgodnie z zasad nadawania zmiennej "mniej pojemnego"
Przykłady: rodzaju typu zmiennej "bardziej pojemnego" rodzaju przed
wykonaniem operacji;
(x==0 || x>5) - x równa si 0 LUB x wi kszy ni 5;
(a>5 && a!=11) - a wi ksze ni 5 I a nie równe 11; Po drugie:
(num>=5 && num!=6 || a>0)
my sami mo emy zmusi C++ do zmiany typu FORSUJ C typ wiadomie
num nie mniejsze ni 5 I num nie równe 6 LUB a dodatnie; w programie.
Wyra enia logiczne sprawdzane instrukcj if MUSZ by uj te w W przykładzie poni ej podaj c w nawiasach dany typ zmiennej
nawiasy okr głe. forsujemy zmian typu int na typ float.

Do wytworzenia warto ci logicznej wyra enia mo e zosta u yty [P044.CPP]


operator relacji: < <= == >= > != . Je li tak si nie
stanie, za warto logiczn wyra enia przyjmowane jest: # include "stdio.h"
void main()
1, PRAWDA, TRUE, je li warto numeryczna wyra enia jest ró na {
od zera. int a=7;
0, FAŁSZ, FALSE, je li warto numeryczna wyra enia jest równa printf("%f", (float) a);
zero. }

Porównaj: Konwersja typów nazywana bywa tak e "rzutowaniem" typów (ang.


type casting). A oto kilka przykładów "forsowania typów":
if (a<=0) ...
if (a) ... int a = 2;
if (a+b) ... float x = 17.1, y = 8.95, z;
char c;
Konwersja - przykłady.
c = (char)a + (char)x;
C++ dysponuje wieloma funkcjami wykonuj cymi takie działania, c = (char)(a + (int)x);
np: c = (char)(a + x);
c = a + x;
itoa() - Integer TO Ascii - zamiana liczby typu int na ła cuch
znaków ASCII; z = (float)((int)x * (int)y);
ltoa() - Long int TO Ascii - zamiana long int -> ASCII; z = (float)((int)x * (int)y);
atoi() - zamiana Ascii -> int; z = (float)((int)(x * y));
atol() - zamiana Asdii -> long int . z = x * y;

Wszystkie wymienione funkcje przekształcaj c liczby na ła cuchy c = char(a) + char(x);


znaków potrzebuj trzech parametrów: c = char(a + int(x));
c = char(a + x);
p1 - liczby do przekształcenia; c = a + x;
p2 - bufora, w którym b d przechowywa wynik - ła cuch ASCII;
p3 - podstawy (szesnastkowa, dziesi tna itp.). z = float(int(x) * int(y));
z = float(int(x) * int(y));
Je li chcemy korzysta z tych funkcji, powinni my doł czy plik z = float(int(x * y));
nagłówkowy z ich prototypami - stdlib.h (STandarD LIBrary - z = x * y;
standardowa biblioteka). A oto przykład.
FUNKCJE BIBLIOTECZNE I WŁASNE W J ZYKU C/C++ .
[P043.CPP]
Poj cie funkcji obejmuje w C/C++ zarówno pascalowe procedury,
# include "stdio.h" jak i basicowe podprogramy. Funkcji zdefiniowanych w C++ przez
# include "stdlib.h" prducenta jest bardzo du o. Dla przykładu, funkcje arytmetyczne,

main() które mo esz wykorzysta do oblicze numerycznych to np.:


{
int i; abs() - warto bezwzgl dna,
char B10[10], B2[20], B16[10]; //BUFORY cos() - cosinus, sin() - sinus, tan() - tangens,
for (i=1; i<17; i++) asin(), atan(), acos(), - funkcje odwrotne ARCUS SINUS...
printf("%s %s %s\n", funkcje hiperboliczne: sinh(), cosh(), tanh(),
itoa(i, B10[i], 10), wykładnicze i logarytmiczne:
itoa(i, B2[i], 2), exp() - e^x
itoa(i, B16[i], 16)); log() - logarytm naturalny,
return 0; log10() - logarytm dziesi tny.
}
Je li skorzystasz z systemu Help i zajrzysz do pliku math.h
[Z] (Help | Index | math.h), znajdziesz tam jeszcze wiele
________________________________________________________________ przydatnych funkcji.
1. Opracuj program testuj cy działanie funkcji atoi().
________________________________________________________________ Funkcja mo e, ale nie musi zwraca warto do programu -
dokładniej do funkcji wy szego poziomu, z której została
KILKA SŁÓW O TYPACH DANYCH i KONWERSJI W C/C++ . wywołana. W ciele funkcji słu y do tego instrukcja return.
U ytkownik mo e w C++ definiowa własne funkcje. Funkcja mo e
Przed przyst pieniem do obszernego zagadnienia "funkcje w C" by bezparametrowa. Oto przykład bezparametrowej funkcji,
krótko zasygnalizujemy jeszcze jedno zjawisko. Wiesz z zwracaj cej zawsze liczb całkowit trzyna cie:
pewno ci , e wykonywane na liczbach dwójkowych mno enie mo e
da wynik o długo ci znacznie wi kszej ni mno na i mno nik. W int F_Trzynascie()
programach mo e si poza tym pojawi konieczno np. mno enia {
liczb zmiennoprzecinkowych przez całkowite. Jak w takich return 13;
przypadkach post puje C++ ? }
48
double A=0, B=3.14;
Poprawne wywołanie naszej funkcji w programie głównym miałoby printf("Wynik działania funkcji: \n");
posta : printf("%lf", FUNKCJA(A,B));
return 0; }
int main()
{ double FUNKCJA(double X, double Y)
...... {
int X; return ((1+X)*Y);
........ // Funkcja typu int nie musi byc deklarowana. }
X = F_Trzynascie();
...... Prototyp mógłby równie dobrze wygl da tak:
}
double FUNKCJA(double, double);
Je li funkcja musi pobra jakie parametry od programu (funkcji
wy szego poziomu, wywołuj cej)? Zwró uwag , e program główny w nazwy parametrów formalnych nie s istotne i mo na je pomin .
Je li prototyp funkcji wygl da tak:
C/C++ to te funkcja - main(). Przykład nast pny pokazuje
definicj funkcji obliczaj cej pi t pot g pobranego argumentu int Funkcja(int, char*, &float)
i wywołanie tej funkcji w programie głównym.
oznacza to, e parametrami funkcji s wska niki do zmiennych,
Przykład: b d referencje do zmiennych. Przy rozszyfrowywaniu takiej
"abrakadabry" warto wiedzie , e
int F_XdoPiatej(int argument)
{ char* oraz char *
int robocza; //automatyczna wewnetrzna zmienna funkcji int& oraz int &
robocza = argument * argument;
robocza = robocza * robocza * argument; ma w tym przypadku identyczne znaczenie.
return (robocza);
} W C++ wolno nie zwraca warto ci funkcjom typu void. To dlatego
wła nie cz sto rozpoczynali my programy od
int main()
{ void main()
int Podstawa, Wynik, a, b;
... /* Funkcja nie jest deklarowana przed uzyciem */ Skutek praktyczny: Je li w ciele funkcji typu void wyst puje
Wynik = F_XdoPiatej(Podstawa); instrukcja return (nie musi wyst pi ) to instrukcja ta nie mo e
..... mie argumentów.
a = F_XdoPiatej(b);
..... Oto przykład prototypu, definicji i wywołania funkcji typu void:
return 0;
}
[P046.CPP]
Zwró uwag , e definiuj c funkcj podajemy nazw i typ
ARGUMENTU FORMALNEGO funkcji - tu: argument. W momencie #include <stdio.h>
wywołania na jego miejsce podstawiany jest rzeczywisty bie cy #include <conio.h>
argument funkcji.
void RYSUJPROSTOKAT( int Wys, int Szer, char Wzorek);
Aby zapewni wysok dokładno oblicze wymienione wy ej funkcje
void main()
biblioteczne sqrt(), sin() itp. "uprawiaj " arytmetyk na {
długich liczbach typu double. Funkcj tak przed u yciem w swoim clrscr();
RYSUJPROSTOKAT(5, 20, ' '); // klocek ASCII 176 - [Alt]-[176]
programie MUSISZ ZADEKLAROWA . Przykład: getch();
RYSUJPROSTOKAT(15, 15, ' '); //[Alt]-[177]
[P045.CPP] getch();
}
main()
{ void RYSUJPROSTOKAT( int Wys, int Szer, char Wzorek)
double a, b; {
double sqrt(); // tu skasuj deklaracje funkcji sqrt() int i, j; // automatyczne zmienne wewn trzne funkcji
// a otrzymasz bledny wynik ! for(i=1; i<=Wys; i++)
clrscr(); {
printf("Podaj liczbe\n"); for(j=1; j<=Szer; j++) printf("%c",Wzorek);
scanf("%lf", &a); printf("\n");
b = sqrt(a); }
printf("\n %Lf", (long double) b); }
getch();
return 0; Prototypy wszystkich funkcji standardowych znajduj si w
} plikach nagłówkowych *.H (ang. Header file).

PROTOTYPY FUNKCJI, czyli jeszcze o deklaracjach funkcji. Skutek praktyczny:


JE LI DOŁ CZYSZ DO PROGRAMU STOSOWNE PLIKI
Prototyp funkcji to taka deklaracja, która: NAGŁÓWKOWE *.h,mo esz

* została umieszczona na pocz tku programu poza funkcj main(), ZREZYGNOWA Z DEKLARACJI FUNKCJI. Dodaj c do programu wiersz:
* zawiera deklaracj zarówno typu funkcji, jak i typów
argumentów. #include <math.h>

Przykład prototypu (funkcja2.cpp): doł czaj cy plik zawieraj cy prototyp funkcji sqrt(), mo esz
napisa program tak:
double FUNKCJA( double X, double Y);
#include <stdio.h>
main() #include <math.h>
{ main()
49
{
Próba wydrukowania zmiennej Argument gdziekolwiek poza wn trzem
double a, b; FUNKCJI() nie uda si i spowoduje komunikat o bł dzie. Oznacza
clrscr(); to, e POZA FUNKCJ zmienna Argument NIE ISTNIEJE. Jest tworzona
printf("Podaj liczbe\n");
scanf("%lf", &a); na stosie jako zmienna automatyczna na wył czny u ytek funkcji,
b = sqrt(a); w której została zadeklarowana i znika po wyj ciu z funkcji.
printf("\n %Lf", (long double) b); Przy takiej organizacji funkcji i programu funkcja otrzymuje
getch(); kopi zmiennej, na niej wykonuje swoje działania, natomiast
zmienna (zmienne) wewn trzna funkcji znika po wyj ciu z funkcji.
return 0;
} Problem przekazania parametrów pomi dzy funkcjami wywołuj cymi
("wy szego rz du" - tu: main) i wywoływanymi (tu: FUNKCJA) mo na

PRZEKAZYWANIE PARAMETRÓW DO FUNKCJI. rozwi za przy pomocy

W C++ cz sto przekazuje si parametry do funkcji przy pomocy * instrukcji return (zwrot do programu jednej warto ci) lub
wska ników. Aby prze ledzi co dzieje si wewn trz funkcji wpisz * wska ników.

i uruchom podany ni ej program przykładowy. Najpierw Mo emy przecie funkcji przekaza nie sam zmienn , a wska nik
skonstruujemy sam program a nast pnie zmodyfikujemy go w taki do zmiennej (robili my to ju w przypadku funkcji scanf() -
sposób, aby mógł sobie popodgl da cały proces. Przy pomocy dlatego, e samej zmiennej jeszcze nie było - miała zosta
funkcji printf() ka emy wydrukowa kolejne stany zmiennych, stan dopiero pobrana, ale istniało ju przeznaczone na t now
zmienn - zarezerwowane dla niej miejsce. Mogł zatem istnie
programu i funkcji, a funkcja getch() pozwoli Ci obejrze to wska nik wskazuj cy to miejsce). wska nik nale y oczywi cie
"krok po kroku". Mogłoby si wydawa , e program poni ej zadeklarowa . Nasz program przybrałby zatem now posta .
skonstruowany jest poprawnie... Wska nik do zmiennej nazwiemy *Argument.

void FUNKCJA( int ); //Prototyp, deklaracja funkcji [P048.CPP]

void main() //Pamietaj o plikach naglowkowych !


{ void FUNKCJA( int *Argument); //Prototyp
int Zmienna; //Zmienna funkcji main, rzeczywisty argument int Zmienna;
clrscr(); void main()
Zmienna = 7; {
clrscr();
FUNKCJA( Zmienna); //Wywolanie funkcji printf("Stadium: \tZmienna Argument");
printf("\nStadium 1\t%d\tnie istnieje\n", Zmienna);
printf("%d", Zmienna); //Wydruk wyniku Zmienna = 7;
} printf("Stadium 2\t%d\tnie istnieje\n", Zmienna );
FUNKCJA( &Zmienna); //Pobierz do funkcji ADRES Zmiennej
void FUNKCJA( int Argument) //Definicja funkcji printf("Stadium 3\t%d", Zmienna);
{ // printf("%d", Argument);
Argument = 10 * Argument + Argument; // taka proba sie NIE UDA !
} getch();
}
FUNKCJA() jest jak wida trywialna. b dzie zamienia np. 2 na
22, 3 na 33 itp. tylko w tym celu, by łatwo było stwierdzi , czy void FUNKCJA( int *Argument) // Definicja funkcji
{
funkcja zadziałała czy nie. printf("jestesmy wewnatrz funkcji\n");
printf("Nastapilo kopiowanie ADRESOW a nie zmiennej\n" );
Rozbudujmy program tak by prze ledzi kolejne stadia. printf("ADRESY:\t\t %X\t%X\n", &Zmienna, Argument);
getch();
[P047.CPP] *Argument = 10* *Argument + *Argument; /* DZIALANIE */
printf("\t\t%d\t%d\n", Zmienna, *Argument);
void FUNKCJA( int ); //Prototyp getch();
}
int Zmienna;
void main()
{ W linii /* DZIALANIE */ mno ymy i dodajemy to, co wskazuje
clrscr(); wska nik, czyli Zmienn . Funkcja działa zatem nie na własnej
printf("Stadium: \tZmienna Argument"); kopii zmiennej a bezpo rednio na zmiennej zewn trznej. Zwró
printf("\nStadium 1\t%d\tnie istnieje\n", Zmienna); uwag na analogi w sposobie wywołania funkcji:
Zmienna = 7;
printf("Stadium 2\t%d\tnie istnieje\n", Zmienna ); FUNKCJA( &Zmienna );
FUNKCJA( Zmienna); scanf( "%d", &Zmienna );
printf("Stadium 3\t%d", Zmienna);
// printf("%d", Argument); A je li argumentem funkcji ma by tablica? Rozwa przykładowy
// taka proba sie NIE UDA ! program. Program zawiera pewn nadmiarowo (ku wi kszej
getch(); jasno ci mechanizmów).
}
[P049.CPP]
void FUNKCJA( int Argument) //Definicja funkcji
{ # include <conio.h>
printf("jestesmy wewnatrz funkcji\n"); # include <stdio.h>
printf("Nastapilo kopiowanie Zmienna -> Argument\n" );
printf("\t\t%d\t%d\n", Zmienna, Argument); SUMA( int k, int Tablica[] )
getch(); {
Argument = 10*Argument + Argument; int i, SumTab=0;
printf("\t\t%d\t%d\n", Zmienna, Argument); for (i=0; i<k; i++)
getch(); {
} SumTab = SumTab + Tablica[i];
printf("%d + ", Tablica[i]);
50
} według wielko ci.
printf("\b\b= %d", SumTab);
return SumTab; [P051.CPP]
}
int BALAGAN[10];
int suma=0, N; char Odp; int PORZADEK[10]; // Tablica koncowa - uporzadkowana
int TAB[10] = {1,2,3,4,5,6,7,8,9,10}; int k, *pointer , MAX=10000 ;

main() int *Minimum(int Ilosc, int *TABL);


{
clrscr(); main()
do {
{ clrscr();
printf("\n Ile wyrazow tablicy dodac ??? \n"); printf("Podaj 10 liczb calkowitych od -10000 do 10000\n");
scanf("%d", &N); for (k=0; k<=9; k++) scanf("%d", &BALAGAN[k]);
if (N>10) printf("Po kolei: \n\n");
{ printf("TO ZA DUZO ! - max. 10"); for ( k=0; k<=9; k++ )
continue; {
} pointer=Minimum(10, BALAGAN);
suma = SUMA( N,TAB ); PORZADEK[k]=*pointer;
printf("\nTO JEST suma z progr. glownego %d", suma); *pointer=MAX;
printf("\n Jeszcze raz ? T/N"); }
Odp = getch(); for(k=0; k<=9; k++) printf("%d ", PORZADEK[k]);
}
while (Odp!='N' && Odp!='n'); getch();
return 0; return 0;
} }

int *Minimum( int Ilosc, int *TABL )


Kompilacja w C++ jest wieloprzebiegowa (PASS 1, PASS 2), wi c {
definicja funkcji mo e by zarówno na pocz tku jak i na ko cu. int *pMin; int i;
pMin=TABL;
A oto nast pny przykład. Operuj c adresem - wska nikiem do for (i=1; i<Ilosc; i++)
obiektu (tu wska nikami do dwu tablic) funkcja Wypelniacz() {
zapisuje pod wskazany adres ci g identycznych znaków. Na ko cu if (*(TABL+i) < *pMin) pMin=(TABL+i);
ka dego ła cucha znaków zostaje dodany NUL - (\0) jako znak }
ko ca. Taki format zapisu ła cuchów znakowych nazywa si ASCIIZ. return (pMin);
}

[P050.CPP]
WSKA NIKI DO FUNKCJI.
void Wypelniacz(char *BUFOR, char Znak, int Dlugosc);
W C++ mo emy nie tylko podstawi dan w miejsce zmiennej (co
char TAB2D[5][10]; // Tablica 5 X 10 = 50 elementow jest trywialn i oczywist operacj we wszystkich j zykach
char TAB_1D[50]; // Tablica 1 X 50 = 50 elementow programowania), ale mo emy tak e podstawia na miejsce funkcji
int k; stosowanej w programie t funkcj , która w danym momencie jest
nam potrzebna. Aby wskaza funkcj zastosujemy, jak sama nazwa
main() wskazuje - WSKA NIK DO FUNKCJI. Aby unikn deklarowania funkcji
{
clrscr(); standardowych i by w zgodzie z dobrymi manierami nie zapomnimy
Wypelniacz( TAB_1D, 'X', 41); //Wypelnia X-ami o doł czeniu pliku z prototypami. Deklaracj
printf("%s\n\n", TAB_1D);
for (k=0; k<5; k++) Wypelniacz( TAB2D[k], 65+k, 9); double ( *FUNKCJA ) (double);
//ASCII 65 to 'A'; 66 to 'B' itd.
nale y rozumie :
for (k=0; k<5; k++) printf("%s\n", TAB2D[k]); "Przy pomocy wska nika do funkcji *FUNKCJA wolno nam wskaza
getch(); takie funkcje, które
return 0; * pobieraj jeden argument typu double float;
} * zwracaj do programu warto typu double float. "
Dost pne s dla nas zatem wszystkie standardowe funkcje
void Wypelniacz( char *BUFOR, char Znak, int Dlugosc ) arytmetyczne z pliku MATH.H (MATH pochodzi od MATHematics -
{ matematyka.)
int i;
for ( i=0; i<=(Dlugosc-1); i++) *(BUFOR+i) = Znak; [P052.CPP]
*(BUFOR+Dlugosc) = '\0';
} # include <conio.h>
# include <math.h>
Zwró uwag , e: double NASZA( double ); //Deklaracja zwyklej funkcji
* NAZWA TABLICY (tu: TAB_1D i TAB2D) funkcjonuje jako wska nik
PIERWSZEGO ELEMENTU TABLICY. double (*Funkcja)(double ARG); //pointer do funkcji

FUNKCJE TYPU WSKA NIKOWEGO. double Liczba, Wynik; //Deklaracje zmiennych


int WYBOR;
Funkcje mog zwraca do programu zarówno warto ci typu int, czy
float, jak i warto ci typu ADRESU. Podobnie jak wska nik wymaga main()
deklaracji i podania w deklaracji na jakiego typu obiekty b dzie {
clrscr();
wskazywał, podobnie funkcja takiego typu wymaga w deklaracji printf("Podaj Liczbe \n");
okre lenia typu wskazywanych obiektów. Wiesz ju , e zale y od scanf("%lf", &Liczba);
tego tzw. krok wska nika. W przykładzie poni ej funkcja printf("CO MAM ZROBIC ?\n");
Minimum() poszukuje najmniejszego elementu tablicy i zwraca printf("1 - Sinus \n");
wska nik do tego elementu. Znaj c lokalizacj najmniejszego printf("2 - Pierwiastek\n");
elementu mo emy utworzy now tablic , ale ju uporz dkowan printf("3 - Odwrotnosc 1/x\n");
51
scanf("%d", &WYBOR);
switch(WYBOR) [P053.CPP]
{
case 1: Funkcja=sin; break; # include "stdio.h"
case 2: Funkcja=sqrt; break; # include "stdlib.h"
case 3: Funkcja=NASZA; break;
} main(int argc, char *argv[], char *env[])
Wynik=Funkcja(Liczba); // Wywolanie wybranej funkcji {
printf("\n\nWYNIK = %lf", Wynik); printf("Parametry srodowiska DOS: \n");
int i = 0;
getch(); do
return 0; {
} printf("%s \n", env[i]);
i++;
double NASZA(double a) };
{ while (env[i] != NULL);
printf("\n A TO NASZA PRYWATNA FUNKCJA\n"); printf("Lista parametrow programu: \n");
if (a!=0) a=1/a; else printf("???\n"); for(i=1; i<= argc - 1; i++)
return a; printf("%s \n", argv[i]);
} printf("Nazwa programu: \n");
printf("%s", argv[0]);
main() - FUNKCJA SPECJALNA. return 0;
}
Ta ksi ka sił rzeczy, ze wzgl du na swoj skromn obj to i
skal zagadnienia o którym traktuje (autor jest zdania, e j zyk Poniewa C++ traktuje nazw tablicy i wska nik do tablicy w
specjalny sposób, nast puj ce zapisy s równowa ne:
C to cała filozofia nowoczesnej informatyki "w pigułce") pełna
jest skrótów. Nie mo emy jednak pozostawi bez, krótkiego *argv[] oraz **argv
cho by, opisu pomijanego dyskretnie do tej pory problemu *env[] oraz **env
PRZEKAZANIA PARAMETRÓW DO PROGRAMU.
Nazwy argumentów argc, argv i env s zastrze one i musz
Konwencja funkcji w j zyku C/C++ wyra nie rozgranicza dwa ró ne wyst powa zawsze w tej samej kolejno ci. Argumenty nie musz
punkty widzenia. Funkcja pozwala na swego rodzaju separacj wyst powa zawsze w komplecie. Dopuszczalne s zapisy:
wiata wewn trznego (lokalnego, własnego) funkcji od wiata
zewn trznego. Nie zdziwi Ci wi c zapewne, e i sposób widzenia main(int argc, char **argv, char **env)
parametrów przekazywanych programowi przez DOS i sposób widzenia main(int argc, char *argv[])
main(int argc)
"od wewn trz" argumentów pobierabych przez funkcj main() jest main()
diametralnie ró ny.
ale niedopuszczalny jest zapis:
To, co DOS widzi tak:
main(char *env[])
PROGRAM PAR1 PAR2 PAR3 PAR4 PAR5 [...][Enter]
Nawet je li nie zamierzamy wykorzysta "wcze niejszych"
funkcja main() widzi tak: parametrów - MUSIMY JE PODA .

main(int argc, char **argv, char **env)


[Z]
lub tak: ________________________________________________________________
1. Spróbuj tak zmodyfikowa funkcj Demo(), by liczba w formie
main(int argc, char *argv[], char *env[]) dwójkowej była pisana "od tyłu". Do cofania kursora w funkcji
printf u yj sekwencji \b\b.
[???]CO TO JEST ???
________________________________________________________________ 2. Zinterpretuj zapis:
Zapisane zgodnie z obyczajami stosowanymi w prototypach funkcji: if (MIANOWNIK) printf("%f", 1/MIANOWNIK); else exit(1);

int argc - liczba całkowita (>=1, bo parametr Nr 1 to nazwa 3 Spróbuj przeprowadzi rzutowanie typu we własnym programie.
samego programu, za po rednictwem której DOS wywołuje funkcj
main). Liczba argumentów - parametrów mo e by zmienna. 4 Przeka warto w programie przykładowym posługuj c si
instrukcj :
UWAGA: J zyk programowania wsadowego BPL przyjmuje nazw return (10*Argument + Argument);
programu za parametr %0 a C++ uznaje j za parametr o numerze 5 Rozszerz zestaw funkcji do wyboru w programie przykładowym.
argv[0], tym niemniej, nawet je li nie ma adnych parametrów
argc = 1.
LEKCJA 16 - ASEMBLER TASM i BASM.
argv - to tablica zawieraj ca wska niky do ła cuchów tekstowych ________________________________________________________________
reprezentowanych w kodzie ASCIIZ - nazw kolejnych paramentrów, z W trakcie tej lekcji:
* dowiesz si , jak ł czy C++ z assemblerem
którymi został wywołany program. * poznasz wewn trzne formaty danych
Pierszy element tej tablicy to nazwa programu. Ostatni element ________________________________________________________________
tej tablicy, o numerze argv - 1 to ostatni niezerowy parametr
wywołania programu. WEWN TRZNY FORMAT DANYCH I WSPÓŁPRACA Z
ASSEMBLEREM.
env - to tak e tablica zawieraj ca wska niki do ła cuchów
znakowych w kodzie ASCIIZ reprezentuj cych parametry rodowiska W zale no ci od wybranej wersji kompilatora C++ zasady
(environment variables). Wska nik o warto ci NUL sygnalizuje współpracy z asemblerem mog si troch ró ni . Generalnie,
koniec tablicy. W Turbo C++ istnieje tak e predefiniowana kompilatory współpracuj z tzw. asemblerami in-line (np. BASM),
zmienna globalna (::), przy pomocy której mo na uzyska dost p lub asemblerami zewn trznymi (stand alone assembler np. MASM,
do rodowiska operacyjnego - environ . TASM). Wstawki w programie napisane w assemblerze powinny zosta
________________________________________________________________
poprzedzone słowem asm (BORLAND/Turbo C++), b d _asm (Microsoft
Przykłady poni ej przedstawiaj sposób wykorzystania parametrów
wej ciowych programu.
52
C++). Przy kompilacji nale y zatem stosownie do wybranego MOV DX, OFFSET NAPIS
kompilatora przestrzega specyficznych zasad współpracy. Np. dla MOV AH, 9
INT 21H ;Drukowanie
BORLAND/Turbo C++ mo na stosowa do kompilacji BCC.EXE/TCC.EXE KONIEC:
przy zachowaniu warunku, e TASM.EXE jest dost pny na dysku w MOV AH, 4CH
bie cym katalogu. INT 21H ;Zako czenie programu
END START
Typowymi sposobami wykorzystania assemblera z poziomu C++ s :
Inne typy danych mo emy stosowa podobnie. Wygodn taktyk jest
* umieszczenie ci gu instrukcji assemblera bezpo rednio w deklarowanie danych w tej cz ci programu, która została
ródłowym tek cie programu napisanym w j zyku C/C++, napisana w C++, aby inne fragmenty programu mogły si do tych
* doł czeniu do programu zewn trznych modułów (np. funkcji) danych odwoływa . Mo emy we wstawce asemblerowskiej odwoływa
napisanych w assemblerze. si do tych danych w taki sposób, jakgdyby zostały zadeklarowane

W C++ w tek cie ródłowym programu blok napisany w asemblerze przy u yciu dyrektyw DB, b d DW.
powinien zosta poprzedzony słowem kluczowym asm (lub _asm):
WEWN TRZNE FORMATY DANYCH W C++.
# pragma inline
LICZBY CAŁKOWITE typów char, short int i long int.
void main()
{ Liczba całkowita typu short int stanowi 16-bitowe słowo i mo e
asm mov dl, 81 zosta zastosowana np. w taki sposób:
asm mov ah, 2
asm int 33 [P056.CPP]
}
#pragma inline
Program b dzie drukował na ekranie liter "Q" (ASCII 81). void main()
{
JAK POSŁUGIWA SI DANYMI W ASEMBLERZE. char *napis = "\nRazem warzyw: $";
int marchewki = 2, pietruszki = 5;
Napiszemy w asemblerze program drukuj cy na ekranie napis "tekst asm {
MOV DX, napis
- test". Rozpczynamy od zadeklarowania ła cucha znaków: MOV AH, 9
INT 33
void main() MOV DX, marchewki
{ ADD DX, pietruszki
char *NAPIS = "tekst - test$"; /* $ - ozn. koniec */ ADD DX, '0'
MOV AH, 2
Umie cili my w pami ci ła cuch, b d cy w istocie tablic INT 33
składaj c si z elementów typu char. Wska nik do ła cucha mo e }
zosta zast piony nazw -identyfikatorem tablicy. Zwró uwag , e }

po ła cuchu znakowym dodali my znak '$'. Dzi ki temu mo emy Zdefiniowali my dwie liczby całkowite i ła cuch znaków - napis.
skorzysta z DOS'owskiej funkcji nr 9 (string-printing DOS Poniewa obie zmienne (ła cuch znków jest stał ) maj długo
service 9). Mo emy utworzy kod w asemblerze: jednego słowa maszynowego, to efekt jest taki sam, jakgdyby
zmienne zostały zadeklarowane przy pomocy dyrektywy asemblera DW
asm mov dx, NAPIS
asm mov ah, 9 (define word). Mo emy pobra warto zmiennej marchewki do
asm int 33 rejestru instrukcj

Cały program b dzie wygl dał tak: MOV DX, marchewki ;marchewki -> DX

[P054.CPP] W rejestrze DX dokonujemy dodawania obu zmiennych i wyprowadzamy

# pragma inline na ekran sum , posługuj c si funkcj 2 przerywania DOS 33


void main() (21H).
{
char *NAPIS = "\n tekst - test $"; W wyniku działania tego programu otrzymamy na ekranie napis:

asm { Razem warzyw: 7


MOV DX, NAPIS
MOV AH, 9 Jeczsze jeden szczegół techniczny. Poniewa stosowana funkcja
INT 33 DOS pracuje w trybie znakowym i wydrukuje nam znak o kodzie
} ASCII przechowywanym w rejestrze, potrzebna jest manipulacja:
}
ADD DX, '0' ;Dodaj kod ASCII "zera" do rejestru
Zmienna NAPIS jest pointerem i wskazuje adres w pami ci, od
którego rozpoczyna si ła cuch znaków. Mo emy przesła zmienn Mo esz sam sprawdzi , e po przekroczeniu warto ci 9 przez sum
NAPIS bezpo rednio do rejestru i przekaza wprost przerywaniu wszystko si troch skomplikuje (kod ASCII zera - 48). Z równym
Int 33. Program assemblerowski (tu: TASM) mógłby wygl da np. skutkiem mo naby zastosowa rozkaz
tak:
ADD DX, 48
[P055.ASM]
Je li prawidłowo dobierzemy format danych, fragment programu
.MODEL SMALL ;To zwylke robi TCC napisany w asemblerze mo e korzysta z danych dokładnie tak
.STACK 100H ;TCC dodaje standardowo 4K samo, jak ka dy inny fragment programu napisany w C/C++. Mo emy
.DATA zastosowa dane o jednobajtowej długo ci (je li drugi, pusty
NAPIS DB 'tekst - test','$' bajt nie jest nam potrzebny). Zwró uwag , e posługujemy si w
.CODE tym przypadku tylko "połówk " rejestru DL (L - Low - młodszy).
START:
MOV AX, @DATA [P057.CPP]
MOV DS, AX ;Ustawienie segmentu danych
ASM: #pragma inline
53
void main() oznacza , e liczba jest ujemna - je li zechcemy j potraktowa
{ jako liczb ze znakiem.
const char *napis = "\nRazem warzyw: $";
char marchewki = 2, pietruszki = 5; Filozofia post powania z liczbami ujemnymi opiera si na
asm { banalnym fakcie:
MOV DX, napis
MOV AH, 9 (-1) + 1 = 0
INT 33
MOV DL, marchewki Twój PC "rozumuje" tak: -1 to taka liczba, która po dodaniu 1
ADD DL, pietruszki stanie si 0. Czy mo na jednak e wyobrazi sobie np.
ADD DL, '0' jednobajtow liczb dwójkow , która po dodaniu 1 da nam w
MOV AH, 2 rezultacie 0 ? Wydawałoby si , e w dowolnym przypadku wynik
INT 33 powinien by conajmniej równy 1.
}
} A jednak. Je li ograniczymy swoje rozwa ania do o miu bitów
jednego bajtu, mo e wyst pi taka, absurdalna tylko z pozoru
W tej wersji zadeklarowali my zmienne marchewki i pietruszki sytuacja. Je li np. dodamy 255 + 1 (dwójkowo 255 = 11111111):
jako zmienne typu char, co jest równoznaczne zadeklarowaniu ich
przy pomocy dyrektywy DB. 1111 1111 hex FF dec 255
+ 1 +1 + 1
Zajmijmy si teraz maszynow reprezentacj liczb typu unsigned ___________ _____ _____
long int (długie całkowite bez znaku). Ze wzgl du na specyfik 1 0000 0000 100 256
zapisu danych do pami ci przez mikroprocesory rodziny Intel
80x86 długie liczby całkowite (podwójne słowo - double word) np.
otrzymamy 1 0000 0000 (hex 100). Dla Twojego PC oznacza to, e w
12345678(hex) s przechowywane w pami ci w odwróconym szyku.
Zamieniony miejscami zostaje starszy bajt z młodszym jak równie o miobitowym rejestrze pozostanie 0000 0000 , czyli po prostu 0.

starsze słowo z młodszym słowem. Liczba 12345678(hex) zostanie Nast pi natomiast przeniesienie (carry) do dziewi tego (nie
zapisana w pami ci komputera IBM PC jako 78 56 34 12. zawsze istniej cego sprz towo bitu).

Gdy inicjujemy w programie zmienn Wyst pienie przeniesienia powoduje ustawienie flagi CARRY w
rejestrze FLAGS. Je li zignorujemy flag i b dziemy bra pod
long int x = 2; uwag tylko te osiem bitów w rejestrze, oka e si , e
otrzymali my wynik 0000 0000. Krótko mówi c FF = (-1), poniewa
zostaje ona umieszczona w pami ci tak: 02 00 00 00 (hex). FF + 1 = 0.
Młodsze słowo (02 00) jest umieszczone jako pierwsze. To wła nie
Aby odwróci wszystkie bity bajtu, b d słowa mo emy w
słowo zawiera interesuj c nas informacj , mo emy wczyta to asemblerze zastosowa instrukcj NOT. Je li zawarto rejestru
słowo do rejestru rozkazem AX wynosiła np. 0000 1111 0101 0101 (hex 0F55), to instrukcja
NOT AX zmieni j na 1111 0000 1010 1010 (hex F0AA). Dokładnie
MOV DX, X tak samo działa operator bitowy ~_AX w C/C++. W zestawie
rozkazów mikroprocesorów rodziny Intel 80x86 jest tak e
Je li b dzie nam potrzebna druga połówka zmiennej - starsze instrukcja NEG, powoduj ca zamian znaku liczby (dokonuj c
słowo (umieszczone w pami ci jako nast pne), mo emy zastosowa konwersji liczby na kod komplementarny). Instrukcja NEG robi to
pointer (czyli poda adres nast pnego słowa pami ci). samo, co NOT, ale po odwróceniu bitów dodaje jeszcze jedynk .
Je li rejestr BX zawierał 0000 0000 0000 0001 (hex 0001), to po
[P058.CPP] operacji NEG AX zawarto rejestru wyniesie 1111 1111 1111 1111
(hex FFFF).
# pragma inline
void main() Zastosujmy praktycznie uzupełnienia dwójkowe przy współdziałaniu
{
unsigned long marchewki = 2, pietruszki = 5; asemblera z C++:
const char *napis = "\nRazem warzyw: $";
asm [P059.CPP]
{
MOV DX, napis #pragma inline
MOV AH, 9 void main()
INT 33 {
MOV DX, marchewki const char *napis = "\nRazem warzyw: $";
ADD DX, pietruszki int marchewki = -2, pietruszki = 5;
ADD DX, '0' asm {
MOV AH, 2 MOV DX, napis
INT 33 MOV AH, 9
} INT 33
} MOV DX, marchewki
NEG DX
W przypadku liczb całkowitych ujemnych C++ stosuje zapis w ADD DX, pietruszki
kodzie komplementarnym. Aby móc manipulowa takimi danymi ka dy ADD DX, '0'
szanuj cy si komputer powinien mie mo liwo stosowania liczb MOV AH, 2
ujemnych. INT 33
}
Najstarszy bit w słowie, b d bajcie (pierwszy z lewej) mo e }
spełnia rol bitu znakowego. O tym, czy liczba jest ze znakiem,
Dzi ki zamianie (-2) na 2 przy pomocy instrukcji NEG DX
czy te bez decyduje wył cznie to, czy zwracamy uwag na ten otrzymamy wynik, jak poprzednio równy 7.
bit. W liczbach bez znaku, oboj tnie, czy o długo ci słowa, czy
bajtu, ten bit równie jest (i był tam zawsze!), ale Przypomnijmy prezentacj działania operatorów bitowych C++.
traktowali my go, jako najstarszy bit nie przydaj c mu poza tym Wykorzystaj program przykładowy do przegl du bitowej
adnego szczególnego znaczenia. Aby liczba stała si liczb ze reprezentacji liczb typu int (ze znakiem i bez).
znakiem - to my musimy zacz j traktowa jako liczb ze
znakiem, czyli zacz zwraca uwag na ten pierwszy bit. [P060.CPP]
Pierwszy, najstarszy bit liczby ustawiony do stanu 1 b dzie
54
/* Program prezentuje format liczb i operatory bitowe */ char *TEKST = "\ntekst - test$";

# include "iostream.h" void drukuj(void); //Prototyp funkcji


# pragma inline
void main()
void demo(int liczba) //Definicja funkcji {
{ drukuj(); //Wywołanie funkcji drukuj()
int n = 15; }
for (; n >= 0; n--)
if ((liczba >> n) & 1) void drukuj(void) //Definicja funkcji
cout << "1"; {
else asm MOV DX, TEKST
cout << "0"; asm MOV AH, 9
} asm INT 33
}
char odp;
char *p = "\nLiczby rozdziel spacja $"; Funkcja mo e oczywi cie nie tylko zgłosi si napisem, ale tak e

int main() zrobi dla nas co po ytecznego. W kolejnym programie


{ przykładowym czy cimy bufor klawiatury (flush), co czasami si
int x, y; przydaje, szczególnie na starcie programów.

cout ˙<< "\nPodaj dwie liczby calkowite od -32768 do +32767\n"; [P062.CPP]

asm { # pragma inline


mov dx, p
mov ah, 9 char *TEKST = "\nBufor klawiatury PUSTY. $";
int 33
} void czysc_bufor(); //Te prototyp funkcji
cout << "\nPo podaniu drugiej liczby nacisnij [Enter]";
cout << "\nLiczby ujemne sa w kodzie dopelniajacym"; void main()
cout << "\nSkrajny lewy bit oznacza znak 0-Plus, 1-Minus"; {
czysc_bufor(); //Czyszczenie bufora klawiatury
for(;;) }
{
cout << "\n"; void czysc_bufor(void) //Definicja funkcji
cin >> x >> y; {
cout << "\nX: "; demo(x); START:
cout << "\t\tY: "; demo(y); asm MOV AH, 11
cout << "\n~X: "; demo(~x); asm INT 33
cout << "\t\t~Y: "; demo(~y); asm OR AL, AL
cout << "\nX & Y: "; demo(x & y); asm JZ KOMUNIKAT
cout << "\nX | Y: "; demo(x | y); asm MOV AH, 7
cout << "\nX ^ Y: "; demo(x ^ y); asm INT 33
cout << "\n Y: "; demo(y); asm JMP START
cout << "\nY >> 1: "; demo(y >> 1); KOMUNIKAT:
cout << "\nY << 2: "; demo(y << 2); asm MOV DX, TEKST
asm MOV AH, 9
cout << "\n\n Jeszcze raz? T/N: "; asm INT 33
cin >> odp; }
if (odp!='T'&& odp!='t') break;
} Póki nie wyst pi problem przekazania parametrów, napisanie dla
} C++ funkcji w asemblerze jest banalnie proste. Zwró uwag , e
zmienne wskazywane w programach przez pointer *TEKST zostały
Wstawka asemblerowa nie jest w programie niezb dna, ale w tym zadeklarowane poza funkcj main() - jako zmienne globalne.
miejscu wydaje si by "a propos". Przy pomocy programu Dzi ki temu nasze funkcje drukuj() i czysc_bufor() maj dost p
przykładowego mo esz zobaczy "na własne oczy" jak wygl da do tych zmiennych.
reprezentacja bitowa liczb całkowitych i ich kody
komplementarne. Spróbujemy przekaza funkcji parametr. Nazwiemy nasz funkcj
wyswietl() i b dziemy j wywoływa przekazuj c jej jako argument
Praca bezpo rednio ze zmiennymi jest jednym ze sposobów
komunikowania si z programem napisanym w C++. Mog jednak znak ASCII przeznaczony do wydrukowania na ekranie:
wyst pi sytuacje bardziej skomplikowane, kiedy to nie b dziemy wyswietl('A'); . Pojawia si zatem problem - gdzie program
zna nazwy zmiennej, przekazywanej do funkcji. Je li napiszemy w "pozostawia" argumenty przeznaczone dla funkcji przed jej
wywołaniem? W Tabeli poni ej przedstawiono w skrócie "konwencj
asemblerze funkcj w celu zast pienia jakiej funkcji wywoływania funkcji" (ang. Function Calling Convention) j zyka
bibliotecznej C++ , program wywołuj c funkcj przeka e jej C++.
parametry i b dzie oczekiwał, i funkcja pobierze sobie te
parametry ze stosu. Rozwa my si to zagadnienie dokładniej. Konwencje wywołania funkcji.
Typow sytuacj jest pisanie w asemblerze tylko kilku funkcji ________________________________________________________________
(zwykle takich, które powinny działa szczególnie szybko). Aby
to zrobi , musimy nauczy si odczytywa parametry, które J zyk Argumenty na stos Posta Typ wart. zwrac.
program przekazuje do funkcji w momencie jej wywołania. ________________________________________________________________
Zaczynamy od trywialnej funkcji, która nie pobiera w momencie
wywołania adnych parametrów. W programie mo e to wygl da np. BASIC Kolejno offset adresu Return n
tak: C++ Odwrotnie warto ci Return
Pascal Kolejno warto ci Return n
[P061.CPP] ________________________________________________________________

//*TEKST to znany funkcji zewn trzny wska nik Return n oznacza liczb bajtów zajmowanych ł cznie przez
wszystkie odło one na stos parametry.
#pragma inline
W C++ parametry s odkładane na stos w odwróconej kolejno ci.
55
Je li chcemy, by parametry zostały odło one na stos kolejno, dwubajtowe słowo maszynowe.
powinni my zadeklarowa funkcj jako "funkcj z Pascalowskimi
manierami" - np.: # include <....
....
pascal void nazwa_funkcji(void); # pragma inline
void main()
Dodatkowo, w C++ argumenty s przekazywane poprzez swoj {
warto , a nie przez wskazanie adresu parametru, jak ma to float liczba = 3.5;
miejsce np. w BASICU. Istnieje tu kilka wyj tków przy ....
przekazywaniu do funkcji struktur i tablic - bardziej
szczegółowo zajmiemy si tym w dalszej cz ci ksi ki. Je eli zajrzymy do pami ci naszego PC, oka e si , e liczba 3.5
została tam "zaszyfrowana" jako 00 00 60 40. Dlaczego? Format
Rozbudujemy nasz przykładowy program w taki sposób, by do liczb zmiennoprzecinkowych jest znacznie bardziej skomplikowany.
funkcji były przekazywane dwa parametry - litery 'A' i 'B'
przeznaczone do wydrukowania na ekranie przez funkcj : Liczba dziesi tna w rodzaju 123.4 to

# pragma inline 1*102 + 2*101 + 3*100 + 4*10-1


void wyswietl(char, char); //Prototyp funkcji
{* !UWAGA SKLAD tu cyfry potegi wyzej *}
void main()
{ Ale PC mo e posługiwa si wył cznie zerami i jedynkami, i
wyswietl('A', 'B'); //Wywolanie funkcji liczy wył cznie w systemie dwójkowym. Liczb dziesi tn 3.5
} mo naby przedstawi dwójkowo np. tak:

void wyswietl(char x, char y) //Definicja (implementacja) 1*21 + 1*20 + 1*2-1 = 2 + 1 + 1/2 {* !UWAGA SKLAD: potegi *}
{
.... czyli 0000 0000 0000 0011.1000 0000 0000 0000

Parametry zostan odło one na stos: Kropka oznacza przecinek oddzielaj cy cz całkowit od cz ci
ułamkowaj - "przecinek dwójkowy" (a nie dziesi tny!). Ka d
PUSH 'B' liczb dziesi tna mo na zamieni na liczb dwójkow .
PUSH 'A' Przykładowodziei tne 7.75 mo na zamieni na

Ka dy parametr (mimo typu char) zajmie na stosie pełne słowo. 4 + 2 + 1 + 1/2 + 1/4 = 0000 0000 0000 0111.1100 (dwójkowo)
C++ nie potrafi niestety układa na stosie bajt po bajcie.
Funkcja wyswietl() musi uzyska dost p do przekazanych jej Pozostaje jednak pewien problem. Komputer nie ma mo liwo ci
argumentówów. Odwołamy si do zmiennych C++ w taki sposób, jak zaznaczenia przecinka, dlatego te przecinek musi by ustawiany
robiłaby to ka da inna funkcja w C++: zawsze w tej samej pozycji - blisko pocz tku liczby.

[P063.CPP] Liczby zmiennoprzecinkowe s poddawane "normalizacji" (ang.


noralized). Nasza liczba 0000 0000 0000 0011.1000 po
# pragma inline normalizacji b dzie wygl da tak: 1.110 0000 0000... * 2^1.
void wyswietl(char, char); //Prototyp funkcji Odbywa si to zupełnie tak samo, jak normalizacja liczb
void main() dziesi tnych. Przesuni cie przecinka powoduje, e 12345.67 =
{ 1.234567 * 10^4. Aby wróciła do swojej starej "zwykłej" postaci
_AH = 2; //BEEEEE ! (jest to tzw. "rozwini cie" liczby - ang. expand) nale y
wyswietl('A', 'B'); //Wywolanie funkcji przesun przecinek o jedno miejsce w prawo - otrzymamy znowu
} 11.1 . W liczbach dziesi tnych pierwsza cyfra mo e by ró na
(tylko nie zero), a w dowolnej poddanej normalizacji
void wyswietl(char x, char y) //Definicja (implementacja) zmiennoprzecinkowej liczbie dwójkowej pierwsz cyfr jest zawsze
{
_DH = 0; // To C++ nie TASM, to samo, co asm MOV DH, 0 1. Skoro w formacie liczb zmiennoprzecinkowych pierwsza jedynka
_DL = x; // asm MOV DL, x jest przyjmowana "z definicji" (ang. implicit), wi c mo na j
asm INT 33 pomin . Zostanie nam zatem zamiast 1.11 tylko 11 i ta
_DH = 0; // asm MOV DH, 0 przechowywana cz liczby jest nazywana jej cz ci znacz c
_DL = y; // asm MOV DL, y (ang. significant). To jeszcze nie wszystko - powinien tam by
asm INT 33 wykładnik pot gi. Wystarczy zapami ta wykładnik, bo podstawa
} jest zawsze ta sama - 2. Niestety wykładniki s przechowywane
nie w sposób naturalny, a po dodaniu do nich tzw. przesuni cia
Aby pokaza jak dalece BORLAND C++ jest elastyczny wymieszali my (ang. offset lub bias). Pozwala to unikn kłopotów z
okre laniem znaku wykładnika pot gi.
tu w jednaj funkcji instrukcje C++ (wykorzystuj c pseudozmienne)
Dla liczb typu float offset wykładnika wynosi +127 a dla liczb
i instrukcje assemblera. Mo e tylko przesadzili my troch double float +1023. Wrócmy do naszej przykładowej liczby. Je li
ustawiaj c rejestr AH - numer funkcji DOS dla przerywania int 33 nasza liczba 3.5 = 11.1(B) ma by zapisana w postaci
zmiennoprzecinkowej - float, zapisany w pami ci wykładnik pot gi
przed wywołaniem funkcji wyswietl() w programie głównym. To
brzydka praktyka (ozn. //BEEEE), której autor nie zaleca. wyniesie:
Jak widzisz, przekazanie parametrów jest proste.
1 + 127 = 128 = 80 (hex)

LEKCJA 17: TROCH SZCZEGÓLÓW TECHNICZNYCH. A teraz znak liczby. Pierwszy bit ka dej liczby
________________________________________________________________ zmiennoprzecinkowej okre la znak liczby (ang. sign bit). Liczby
W trakcie tej lekcji dowiesz si wi cej o szczegółach działania zmiennoprzecinkowe nie s przechowywane w postaci dwójkowych
komputera widzianych z poziomu assemblera. uzupełnie . Je li pierwszy bit - bit znaku równy jest 1 - liczba
________________________________________________________________
jest ujemna. natomiast je eli 0, liczba jest dodatnia. Jest to
LICZBY ZMIENNOPRZECINKOWE TYPU float. jedyna ró nica pomi dzy dodatnimi a ujemnymi liczbami
zmiennoprzecinkowymi. Nasza liczba 3.5 = 11.1 zostanie
To, e C++ przy wywołaniu funkcji jest "przyzwyczajony" do zakodowana jako:
odkładania argumentów na stos zawsze po dwa bajty mo e nam
sprawi troch kłopotów, gdy zechcemy zastosowa argument typu znak liczby -0
float, double, b d long - znacznie przekraczaj cy długo ci wykładnik pot gi - 1000 0000
56
cyfry znacz ce liczby - 110000000.... double AX = Adres (je li far to DX:AX)
struct AX = Adres (je li far to DX:AX)
Poniewa wiemy, e mamy do dyspozycji dla liczb float 4 bajty near pointer AX
(mo esz to sprawdzi sizeof(float x=3.5)), uzupełnijmy brakuj ce far pointer DX:AX
________________________________________________________________
do 32 bity zerami:

3.5 = 0100 0000 0110 0000 0000 0000 0000 0000 = 40 60 00 00 Zale nie od typu warto ci zwracanej przez funkcj (okre lonej w
prototypie funkcji), C++ odczytuje zawarto odpowiedniego
zapis 40600000 to oczywi cie szesnastkowa posta naszej liczby. rejestru: AL, AX lub DX:AX. Je li funkcja ma np. zwróci warto
Je li teraz we miemy pod uwag , e nasz PC zamieni miejscami
starsze słowo z młodszym 00 00 40 60 a nast pnie w obr bie o długo ci jednego bajtu, to przed wyj ciem z funkcji nale y j
ka dego słowa dodatkowo starszy bit z młodszym, to zrozumiemy, "zostwi " w rejestrze AL. Je li wywołuj c funkcj C++ oczekuje
dlaczego nasza liczba "siedziała" w pami ci w zaszyfrowanej zwrotu warto ci jednobajtowej, to po powrocie z funkcji
postaci 00 00 60 40. automatycznie pobierze bajt z rejestru AL. Krótkie warto ci
(typu short int) s "pozostawiane" przez funkcj w AX, a długie
Rozpatrzmy szkielet programu wykorzystuj cego funkcj z "długim" w parze rejestrów: DX - starsze, AX - młodsze słowo.

argumentem. Aby zapanowa nad zapisem liczby zmiennoprzecinkowej Zastosujmy to w programie. Funkcja b dzie odejmowa dwie liczby
całkowite. Pobierze dwa argumenty typu int, wykona odejmowanie i
do pami ci naszego PC mo emy na poziomie assemblera post pi np.
zwróci wynik typu int (return (_AX)). Dla modelu pami ci small
tak: b dzie to wygl da tak:

[P064.CPP]
# include <.....
# pragma inline # include <iostream.h>
void funkcja(long int) //Prototyp funkcji # pragma inline
main() int funkcja(int, int); //Prototyp funkcji
{
long liczba = 0xABCDCDEF; //Deklaracja argumentu void main()
..... {
funkcja(liczba); //Wywołanie w programie cout << "\nWynik 7 - 8 = " << funkcja(7, 8);
.... }
}
int funkcja(int x, int y) //Implementacja funkcji
void funkcja(long int x) //Implementacja funkcji {
{ ..... } // x - argument formalny asm {
MOV AX, x
Argument przekazywany funkcji() jest zmienn 4 - bajtow typu SUB AX, y
long int. Mo emy j zamieni na dwa słowa, zanim przeka emy j }
do wykorzystania w asemblerowskiej cz ci programu. return (_AX); //Zwró zawarto rejestru AX
}
funkcja(long int x)
{ Zwró uwag , e po return(_AX); stawiamy rednik, natomiast po
int x1starsze, x2mlodsze; //Wewn trzne zmienne pomocnicze instrukcjach assemblera nie:
x2mlodsze = (int) x;
x >> 16; asm MOV AX, DX
x1starsze = (int) x;
_DX = x1starsze; chyba, e chcemy umie ci kilka instrukcji assemblera w jednej
_BX = x2mlodsze; linii (patrz ni ej).
asm {
...... //Tu funkcja ju mo e działa C++ i assembler s równoprawnymi partnerami. C++ mo e odwoływa
si do zmiennych i funkcji assemblera, je li zostały
Forsuj c konwersj typu na (int), spowodujemy, e młodsze słowo zadeklarowane, jako publiczne (public) oraz zewn trzne
zostanie przypisane zwyczajnej krótkiej zmiennej x2mlodsze. (EXTeRNal) i vice versa. C++ oczekuje, e zewn trzne
Nast pnie zawarto długiej zmiennej zostanie przesuni ta o 16 identyfikatory b d si rozpoczyna od znaku podkre lenia "_".
bitów w prawo (starsze słowo zostanie przesuni te na miejsce Je li w programie pisanym w BORLAND C++ zastosujemy zewn trzne
młodszego). Powtórzenie operacji przypisania spowoduje zmienne i funkcje, C++ sam automatycznie doda do identyfikatorów
przypisanie zmiennej x1starsze starszej połówki słowa. Od tej
chwili mo emy odwoła si do tych zmiennych w naszym fragmencie znak podkre lenia. Turbo Assembler nie robi tego automatycznie i
napisanym w asemblerze. Post pujemy tak, by to C++ martwił si o
musimy zadba o to "r cznie". Przykładowo, współpraca pomi dzy
szczegóły techniczne i sam manipulował stosem i jednocze nie programem P .CPP i modułem MODUL.ASM b dzie przebiega
pilnował poprawno ci konwersji danych. poprawnie:

ZWROT WARTO CI PRZEZ FUNKCJ . [P065.CPP]

A teraz kilka słów o tym, co si dzieje, gdy funkcja zapragnie extern int UstawFlage(void); //Prototyp funkcji
zwróci jak warto do programu. int Flaga;
void main()
Wykorzystanie przez funkcje rejestrów do zwrotu warto ci. {
________________________________________________________________ UstawFlage();
}
Typ warto ci Funkcja u ywa rejestru (lub pary)
________________________________________________________________ [MODUL.ASM]
signed char / unsigned char AL
short AX .MODEL SMALL
int AX .DATA
enum AX EXTRN _Flaga:WORD
long para DX:AX (starsze słowo DX, młodsze .CODE
AX) PUBLIC _UstawFlage
float AX = Adres (je li far to DX:AX) _UstawFlage PROC
57
CMP [_Flaga], 0
JNZ SKASUJ_Flage Posługuj c si systemowym debuggerem DEBUG mo esz łatwo
MOV [_Flaga], 1 przejrze tablic wektorów przerywa własnego komputera. Je li
JMP SHORT KONIEC wydasz rozkaz:
SKASUJ_Flage: MOV [_Flaga], 0
KONIEC: C:\DOS\DEBUG
RET -D 0:0
_UstawFlage ENDP
END zobaczysz zawarto pierwszych 32 wektorów int #0...int#31,
czyli pierwsze 128 bajtów pami ci:
Kompilacja mo e przebiega oddzielnie wg schematu:
-d 0:0
PROGRAM.CPP --> PROGRAM.OBJ
MODUL.ASM --> MODUL.OBJ 0000:0000 FB 91 32 00 F4 06 70 00-78 F8 00 F0 F4 06 70 00
TLINK PROGRAM.OBJ MODUL.OBJ --> PROGRAM.EXE 0000:0010 F4 06 70 00 54 FF 00 F0-53 FF 00 F0 53 FF 00 F0
0000:0020 A5 FE 00 F0 87 E9 00 F0-23 FF 00 F0 23 FF 00 F0
Lub mo emy powierzy t prac kompilatorowi, który sam wywoła 0000:0030 23 FF 00 F0 CE 02 00 C8-57 EF 00 F0 F4 06 70 00
TASM i TLINK: 0000:0040 D1 0C BD 1B 4D F8 00 F0-41 F8 00 F0 74 07 70 00
0000:0050 39 E7 00 F0 4A 08 70 00-2E E8 00 F0 D2 EF 00 F0
TCC PROGRAM.CPP MODUL.ASM 0000:0060 00 00 FF FF FB 07 70 00-5D 0C 00 CA 9F 01 BD 1B
0000:0070 53 FF 00 F0 A0 7C 00 C0-22 05 00 00 2F 58 00 C0
W BORLAND C++ 3.1 mamy do dyspozycji zintegrowany assembler
(ang. in-line) - BASM. Ma on jednak w stosunku do Po zdeszyfrowaniu oka e si , e pierwszy wektor (przerywanie 0)
"wolnostoj cego" Turbo Assemblera pewne ograniczenia: wskazuje na adres startowy: 0032:91FB (adres absolutny 0951B).
Generalnie mo liwe s cztery sytuacje. Wektor mo e wskazywa :
* ma zaw ony w stosunku do TASM zestaw dyrektyw (tylko DB, DD,
DW, EXTRN); * adres startowy procedur ROM-BIOS: blok F - Fxxx:xxxx,
* nie pozwala na stosowanie składni typowej dla trybu "Ideal * adres funkcji DOS,
mode"; * adres funkcji działaj cego wła nie debuggera (DEBUG przejmuje
* nie pozwala na zastosowanie makra; obsług niektórych przerywa ), lub innego programu rezyduj cego
* nie pozwala stosowa instrukcji charakterystycznych dla 386 w pami ci - np. NC.EXE,
ani 486. * wektor mo e by pusty - 00 00:00 00 je li dane przerywanie nie

Mo esz stosowa kilka rozkazów assemblera w jednej linii, ale jest obsługiwane.
powiniene rozdziela je wewn trz linii rednikami:
Je li zechcesz sprawdzi , jak obsługiwane jest dane przerywanie
asm { mo esz znów zastosowa debugger, wydaj c mu rozkaz
POP AX; POP DX; POP DS zdezasamblowania zawarto ci pami ci pocz wszy od wskazanego
IRET adresu:
}
-u 32:91FB
Komentarz we wstawce assemblerowskiej musi zosta poprzedzony
typowym dla C - /* (sam rednik, jak w TASM jest 0032:91FB BE6B47 MOV SI,476B
niedopuszczalny): 0032:91FE 2E CS:
0032:91FF 8B1E7E47 MOV BX,[477E]
asm { 0032:9203 2E CS:
MOV DX, 1 ;TAK NIE MO NA W BASM ! 0032:9204 8E16D73D MOV SS,[3DD7]
... 0032:9208 BCA007 MOV SP,07A0
asm { 0032:920B ˙˙˙˙˙˙˙˙˙˙˙E80200 ˙˙˙˙˙˙˙˙˙˙CALL ˙˙˙˙˙˙˙˙˙˙9210
ADD AX, BX; /* Taki komentarz mo e by */
0032:920E EBDA JMP 91EA
[???] KŁOPOTY Z REJESTRAMI ? 0032:9210 ˙˙˙˙˙˙˙˙˙˙˙16 ˙˙˙˙˙˙˙˙˙˙˙PUSH ˙˙˙˙˙˙˙˙˙˙˙SS
________________________________________________________________
Je li zastosujesz rejestry DI i SI we wstawce assemblerowaj, 0032:9211 07 POP ES
kompilator C++ nie b dzie miał gdzie umie ci zmiennych klasy 0032:9212 ˙˙˙˙˙˙˙˙˙˙˙16 ˙˙˙˙˙˙˙˙˙˙˙PUSH ˙˙˙˙˙˙˙˙˙˙˙SS
register z programu głónego. Zastanów si - co si bardziej
opłaca. 0032:9213 1F POP DS
________________________________________________________________ 0032:9214 C606940308 MOV BYTE PTR [0394],08
0032:9219 C606920316 MOV BYTE PTR [0392],16
O WEKTORACH PRZERYWA DOS
Z poziomu assemblera do wektora i odpowiednio do funkcji
Mikroprocesory Intel 80X86 rezerwuj w pami ci naszych PC obsługuj cej przerywanie mo esz odwoła si instrukcj INT
pocz tkowe 1024 Bajty (adresy fizyczne 00000...00400 hex) na 256 numer.

wektorów przerywa (ka dy wektor składa si z dwu słów i mo e Zmienna numer mo e tu przyjmowa warto ci od 00 do FF. Je li
by traktowany jako DW, b d far pointer). Nast pne 256 bajtów wydasz taki rozkaz, komputer zapisze na stos ( eby sobie nie
(00400...00500 hex) zajmuje BIOS, a kolejne 256 (00500...00600 zapomnie ) zawarto rejestrów CS - bie . segment rozkazu, IP -
hex) wykorzystuje DOS i Basic. bie cy offset rozkazu i FLAGS. Nast pnie wykona daleki (far
jump) skok do adresu wskazanego przez wektor.
Wektor to w samej rzeczy pełny adres pocz tku procedury
obsługuj cej przerywanie o danym numerze Je li jednak cz przerywa jest "niewykorzystana", lub w Twoim

UWAGA: programie trzeba je obsługiwa inaczej - niestandardowo ? W


Wektor zapisywany jest w pami ci w odwrotnej kolejno ci: BORLAND C++ masz do dyspozycji specjalny typ funkcji: interrupt.

Adres pami ci: 0000:0000 [OFFSET Wekt. int 0] Aby Twoja funkcja mogła sta si "handlerem" przerywania, mo esz
0000:0002 [SEGMENT int 0]
0000:0004 [OFFSET Wekt. int 1] zadeklarowa j tak:
0000:0006 [SEGMENT int 1]
0000:0008 [OFFSET int 2] void interrupt MojaFunkcja(bp, di, si, ds .....)
.... ....
Procesory 80X86 zamieniaj jeszcze dodatkowo starszy bajt z Do funkcji klasy interrupt przekazywane s jako argumenty
młodszym. rejestry, nie musisz zatem stosowa pseudozmiennych _AX, _FLAGS
58
itp.. Je li zadeklarujesz funkcj jako handler przy pomocy słowa {
Instaluj(Piszczek, 10);
"interrupt", funkcja automatycznie zapami tuje stan rejestrów: Start(5, 10);
AX, BX, CX, DX, SI, DI, BP, ES i DS. }
Po powrocie z funkcji rejestry zostan automatycznie odtworzone.
Nale y do dobrych manier odtworzy po wykorzystaniu oryginaln
Przykładem funkcji obsługuj cej przerywanie mo e by piszczek() zawarto wektora przerywania, który "unowocze nili my". W
posługuj cy si wbudowanym gło niczkiem i portem: bibliotece BORLAND C++ masz do dyspozycji m. in. funkcje

# define us unsigned getvect() - pobierz wektor (ten stary) i


# include <iostram.h> setvect() - ustaw wektor (ten nasz - nowocze niejszy).
# include <dos.h>
Je li zechcemy korzysta z rejestrów 386/486?
void InstalujWektor(void interrupt (*adres)(), int numer_wekt);
Je li mamy komputer z 32 bitowymi rejestrami, to wypadałoby z
void interrupt Piszczek(us bp, us di, us si, us ds, us es, tego korzysta . Na poziomie assemblera masz do dyspozycji
us ax, us bx, us cx, us dx); dyrektywy:

void main() .386, .386P i .386C


{ (P oznacza pełny zestaw instrukcji wraz z trybem
..... uprzywilejowanym - 386 privileged instruction set).
}
Mikroprocesor Intel 80386 mo e obsługiwa pami zgodnie z
.... tradycyjnym podziałem na 64 kilobajtowe segmenty (tryb USE16),
lub podzielon na ci głe segmenty po 4 GB (tryb USE32).
Po zadeklarowaniu prototypów dwu funkcji:
Piszczek() - nasz handler przerywania; Rejestry ogólnego przeznaczenia rozrosły si z 16 do 32 bitów i
InstalujWektor() - funkcja instaluj ca nasz handler; zyskały w nazwie dodatkow liter E (Extended - rozszerzony).
mo emy przyst pi do zdefiniowania oby funkcji. Posłu ymy si "Stare" rejestry stały si młodsz połówk nowych. I tak:
zmiennymi
nowe_bity, stare_bity. Wydawanie d wi ku polega na wł czaniu i EAX = 0...15 to stary AX, 16...31 to rozbudowa do EAX
wył czaniu gło niczka. Pusta p tla posłu y nam do zwłoki w (dokładniej: 0..7 = AL, 8..15 = AH, 0...15 = AX, 0...31 = EAX)
czasie. BX -> 0...31 EBX: 0...7 BL, 8...15 BH, 0...15 BX
CX -> 0...31 ECX
void interrupt Piszczek(us bp, us di, us si, us ds, us es, DX -> 0...31 EDX
us ax, us bx, us cx, us dx) wszystkie z dodatkowym podziałem na połówki H i L (np.
{ DX = DH:DL).
char nowe_bity, stare_bity, i; SI -> 0...31 ESI w tym (SI = 0..15)
int n; DI -> 0...31 EDI w tym (DI = 0..15)
unsigned char licznik = ax >> 8; BP -> 0...31 EBP w tym (BP = 0..15)
SP -> 0...31 ESP w tym (SP = 0..15)
stare_bity = inportb(0x61); IP -> 0...31 EIP w tym (IP = 0..15)
FLAGS -> 0...31 EFLAGS w tym (FLAGS = 0..15)
for(nowe_bity = stare_bity, n = 0; n <= licznik; n++)
{ Wszystkie "stare" połówki dost pne pod star nazw .
outportb(0x61, 0xFC & nowe_bity); //Wylacz Rejestry segmentowe pozostały 16 bitowe, ale jest ich o dwa
for(i = 1; i < 255; i++) ; //Czekaj wi cej: CS, DS, ES, SS oraz nowe FS i GS.
outportb(0x61, nowe_bity / 2); //WLACZ
for(i = 1; i < 255; i++) ; //Czekaj Nowe 32 bitowe rejestry działaj według tych samych zasad:
}
outportb(0x61, stare_bity); //Stan poczatkowy .386
...
} MOV EAX, 1 ;zapisz 1 do rejestru EAX
SUB EBX, EBX ;wyzeruj rejestr EBX
Funkcja instaluj ca handler korzysta z bibliotecznej funkcji C++ ADD EBX, EAX ;dodaj (EAX)+(EBX) --> EBX

setvect() (ustaw wektor przerywania) i potrzebuje dwu Dost p do starszej połowy rejestru mo na uzyska np. poprzez
argumentów: przesuwanie (rotation):

* numeru wektora przerywania (numer * 4 = adres), .386


* adresu funkcji - handlera - *faddr. ...
MOV AX, Liczba_16_bitowa
void InstalujWektor(void interrupt (*adres)(), int ROR EDX, 16
numer_wektora) MOV AX, DX
{ ROR EDX, 16
cout << "\nInstaluje wektor" << numer_wektora << "\n"; ... itp.
setvect(numer_wektora, adres);
} W assemblerze mo esz stosowa wobec procesora 386 nowe
instrukcje (testowania nie istniej cych wcze niej bitów,
Pozostało nam wygenerowa przerywanie. Załatwimy to funkcj przenoszenia krótkich liczb do 32 bitowych rejestrów z
Start(): uwzgl dnieniem zaku i uzupełnieniem zerami itp.):

void Start(unsigned char licznik, int numer_wektora) BSF, BSR, BTR, BTS, LFS, LGS, MOVZX, SETxx,
{ BT, BTC, CDQ, CWDE, LSS, MOVSX, SHLD i SHRD.
_AH = licznik;
geninterrupt(numer_wektora); //generuj przerywanie Przy pomocji instrukcji MOV w trybie uprzywilejowanym (tzw.
} most-privileged level 0 - tylko w trybie .386P) mo esz dodatkowo

Nasz główny program b dzie zatem wygl da tak: uzyska dost p do specjalnych rejestrów mikroprocesora 80386.

# include <... CR0, CR2, CR3,


... DR0, DR1, DR2, DR3, DR6, DR7
void main() TR6, TR7
59
________________________________________________________________
Wyst puje tu typ danych - FWORD - 48 bitów (6 bajtów). Obok
znanych dyrektyw DB i DW pojawia si zatem nowa DF, a oprócz Upewnij si , czy kompilator zarezerwował (a Ty zadeklarowałe )
znajomych wska ników BYTE PTR, WORD PTR pojawia si nowy FWORD wystarczaj co du o miejsca dla Twoich tekstów. C++ niestety nie
PTR. Przy pomocy dyrektywy .387 mo esz skorzysta z koprocesora. sprawdza tego w trakcie działania programu. Je li b dziesz
próbował umie ci w pami ci tekst o zbyt du ej długo ci (dłu szy
Jak wynika z zestawu dodatkowych insrukcji:
ni zadeklarowałe w programie), C++ posłusznie zapisze go do
FCOS, FSINCOS, FUCOMP, FPREM1, FUCOM, FUCOMPP, FSIN pami ci, ale mo e to spowodowa nieprawidłowe działanie, b d
nawet "zawieszenie" programu.
warto dysponowa koprocesorem, je li cz sto korzystasz z ________________________________________________________________
grafiki, animacji i funkcji trygonometrycznych (kompilacji nie
przyspieszy to niestety ani o 10% - tam odbywaj si operacje Inn przydatn w praktyce programowania cech j zyka C++ jest
stałoprzecinkowe). mo liwo zadeklarowania zawarto ci zmiennej tekstowej w
momencie zadeklarowania samej zmiennej. Takie nadanie
Zwró uwag , e procesory 386 i wcze niejsze wymagały instalacji pocz tkowej warto ci nazywa si zdefiniowaniem, b d
zainicjowaniem zmiennej. W programie zapisuje si to tak:
dodatkowego układu 387 zawieraj cego koprocesor
zmiennoprzecinkowy. Procesory 486 je li maj rozszerzenie DX - char napis[] = "To jest jakis napis";
zawieraj ju koprocesor wewn trz układu scalonego.
Powoduje to przypisanie zmiennej tekstowej "napis" konkretnego
ła cucha tekstowego "To jest jaki napis". Zwró uwag , e w
nawiasach nie podajemy ilo ci znaków, z których składa si
tekst. Kompilator sam policzy sobie ilo znaków (tu 19) i
zarezerwuje miejsce w pami ci dla napisu. Je li wolisz sam
zadecydowa , mo esz zapisa deklaracj tak:

LEKCJA 18 - O ŁA CUCHACH TEKSTOWYCH char napis[35] = "To jest jakis napis";


________________________________________________________________
W trakcie tej lekcji dowiesz si , Je li to zrobisz, kompilator C++ zarezerwuje w pami ci miejsce
* jak manipulowa ła cuchami tekstowymi i poznasz kilka dla 35 znaków, a nie dla 19.
specjalnych funkcji, które słu w C++ wła nie do takich celów;
* jak wykonuj si operacje plikowo-dyskowe. W programach cz sto inicjuje si teksty posługuj c si nie
________________________________________________________________ tablic znakow - lesz wska nikiem do tekstu. Deklaracja i
zainicjowanie wska nika (wska nik wskazuje pierwszy element
OPERACJE NA ŁA CUCHACH TEKSTOWYCH. ła cucha znakowego) wygl da wtedy tak:

String, czyli ła cuch - to gupa znaków "pisarskich" (liter, cyfr char *p = "Jakis tam napis";

i znaków specjalnych typu ?, !, _ itp.). Poniewa C++ nie ma Rzu my okiem na kilka gotowych funkcji, które do manipulowania
odzielnego typu danych "string" - ła cuchy znaków to tablice tekstami oferuje C++.
zło one z pojedynczych znaków (typowe elementy typu char).
Technik obiektow mo na utworzy klas - nowy typ danych Ł CZENIE TEKSTÓW.
"string". W bibliotekach Microsoft C++ istnieje predefiniowana
klasa CString, ale zanim przejdziemy do programowania [S] String Concatenation - ł czenie ła cuchów tekstowych.
obiektowego i zdarzeniowego - rozwa my manipulowanie tekstami w Zlepek/skrót. Słowo strcat w j zyku C++ znaczy sklej.
sposób najprostszy.
W praktycznych programach zapewne cz sto pojawi si dwa lub
Maksymaln mo liw długo napisu nale y poda wtedy, gdy w wi cej tekstów, które trzeba b dzie poł czy w jeden napis.
programie deklaruje si zmienn tekstow : Wyobra my sobie, e imi i nazwisko u ytkownika mamy zapisane
jako dwa oddzielne ła cuchy tekstowe. Aby poł czy te dwa teksty
char tekst1[40];
w jeden trzeba przeprowadzi tzw. sklejanie (ang. concatenation)
Jest to poprawna deklaracja zmiennej tekstowej o nazwie
(identyfikator) tekst1. Maksymalna długo tekstu, który mo na tekstów. W j zyku C++ mamy w tym celu do dyspozycji specjaln
umie ci w tej zmiennej tekstowej to - 40 znaków (liter, cyfr, funkcj :
itp.). A je li chc zastosowa tylko pojedynczy znak zamiast
całego napisu? To proste: strcat() - STRing conCATenation - sklejanie ła cuchów.

char napis[1]; Aby poł czy dwa ła cuchy tekstowe napis1 i napis2 w jeden
nale y zastosowa t funkcj w taki sposób:
Skoro długo ła cucha wynosi 1, to przecie nie jest aden
ła cuch! Informacja o długo ci (size - wielko ) wpisywana w strcat(napis1, napis2);
nawiasy jest zb dna. Uproszczona wersja utworzenia zmiennej
jednoznakowej i nadania zmiennej nazwy wygl da w tak: Funkcja strcat() zadziała w taki sposób, e ła cuch znaków
napis2 zostanie doł czony do ko ca ła cucha napis1. Po
char znak; zako czeniu działania funkcji zmienna napis1 zawiera "swój
własny" napis i doł czony na ko cu napis zawarty uprzednio w
Nie jest to ju jednak deklaracja zmiennej ła cuchowej - lecz zmiennej napis2.
deklaracja zmiennej znakowej. Ła cuch znaków (string) to grupa
znaków (dokł. tablica znakowa) zako czona zwykle przez tzw. Program poni ej przedstawia praktyczny przykład zastosowania
"wartownika" - znak NULL (zero). A pojedynczy znak to tylko funkcji strcat().
pojedynczy znak. Nie ma tu miejsca (i sensu) dodawanie po
pojedynczym znaku "wartownika" ko ca tekstu - zera. [P066.CPP]

Gdy w deklaracjach zmiennych tekstowych rezerwujesz miejsce w #include <conio.h>


pami ci dla napisów - zawsze mo esz za da od kompilatora C++ #include <iostream.h>
zarezerwowania wi kszej ilo ci miejsca - na zapas. Zawsze lepiej #include <string.h> //W tym pliku jest prototyp strcat()

mie zbyt du o miejsca, ni zbyt mało. int main(void)


{
[???] LEPIEJ MIE NI NIE MIE . char imie[50], nazwisko[30];

60
clrscr(); starych, zb dnych danych.
cout << "Podaj imie: ";
cin >> imie; Mo liwo sprawdzenia, jak długo ma ła cuch tekstowy mo e si

cout << "Podaj nazwisko: "; to przyda np. do rozmieszczenia napisów na ekranie. Dla
cin >> nazwisko; przykładu, pozycja na ekranie, od której rozpocznie si
wy wietlanie napisu zale y od długo ci tekstu, który został
strcat(imie, " "); wy wietlony wcze niej. Do okre lania długo ci tekstu masz w C++
strcat(imie, nazwisko); do dyspozycji gotow funkcj :

cout << "\nNazywasz sie: " << imie << '\n'; strlen() - STRing LENgth - długo ła cucha znakowego.
cout << "Naci nij dowolny klawisz";
getch(); Funkcj strlen() stosuje si w nast puj cy sposób:
return 0;
} unsigned int dlugosc;
char tekst[...];
...
Program zapyta najpierw o imi a nast pnie o nazwisko. Po dlugosc = strlen(tekst);
wpisaniu przez Ciebie odpowiedzi program doda do siebie oba
teksty i wypisze na ekranie Twoje imi i nazwisko w cało ci. Funkcja ma jeden argument - napis, którego długo nale y
Interesuj xe w programie jest poł czenie przy pomocy funkcji C++ okre li (tu: zmienna nazywa si tekst). Funkcja strlen() w
wyniku swojego działania ZWRACA długo ła cucha tekstowego jako
strcat() dwu ła cuchów tekstowych w jeden ła cuch z dodaniem
spacji rozdzielaj cej ła cuchy znaków. Najistotniejszy fragment liczb całkowit bez znaku (nieujemn ). Liczba zwrócona jako
programu wraz z komentarzem - poni ej. wynik przez funkcj strlen() mo e zosta u yta w dowolny sposób
- jak ka da inna warto numeryczna.
strcat(imie, " "); <-- dodaj do ko ca tekstu spacj
strcat(imie, nazwisko); <-- po doł czonej spacji dodaj Funkcja strlen() nie podaje w odpowiedzi na wywołanie (m drze
drugi tekst - nazwisko nazywa si to "zwraca do programu warto ") długo ci ła cucha
tekstowego, która została zadeklarowana (maksymalnej
Poniewa prototyp funkcji strcat() znajduje si w pliku STRING.H teoretycznej), lecz FAKTYCZN DŁUGO tekstu. Je li, dla
przykładu, zadeklarujemy zmienn tekstow tak:
- nale y doł czy ten plik nagłówkowy dyrektyw #include.
char string1[30] = "Lubie C++ ";
DŁUGO ŁA CUCHA TEKSTOWEGO.
zadeklarowana maksymalna długo ła cucha znakowego wynosi 30,
Ka dy tekst ma swoj długo : liczb znaków, z których si natomiast faktyczna długo ła cucha znakowego wynosi 10 znaków.
składa. Dla przykładu ła cuch znaków:
Je li wywołamy strlen() i ka emy jej okre li długo ła cucha
"Przychodzi katecheta do lekarza i płacze, a lekarz na to: Bóg znakowego string1:
dał - Bóg wzi ł..."
unsigned int dlugosc = strlen(string1);
ma dla długo 71, poniewa składa si z 71 znaków (odst p -
spacja to te znak). Ła cuch znaków funkcja przypisze zmiennej dlugosc warto 10 a nie 30.

"Ile diabłów mie ci si w łebku od szpilki?" Je li wpisałe poprzedni program program przykładowy do okienka
edycyjnego - wystarczy doda dwa nowe wiersze.
ma długo 42. Teoretycznie długo ła cuchów znakowych mo e
wynosi od 0 do niesko czono ci, ale w Borland/Turbo C++ [P067.CPP]
wyst puje ograniczenie: ła cuch znaków mo e mie długo zawart
#include <conio.h>
w przedziale od 0 do 65536 znaków. Taki np. ła cuch znaków jest #include <iostream.h>
całkiem do przyj cia: #include <string.h>

"Nie wa ne, czy Polska b dzie bogata, czy biedna - wa ne, eby main()
była katolicka (czyli nasza), bo nasze b d wtedy pieni dze, {
urz dy i nasza władza. Lepiej by pół-Bogiem w ród n dzarzy char imie[50], nazwisko[20];
(oczywi cie za ich pieni dze, z ich podatków), ni zarabia na int dlugosc;
chleb własn prac ."
clrscr();
[S] Null string - Ła cuch zerowy. cout << "Podaj imie: ";
________________________________________________________________ cin >> imie;
cout << "Podaj nazwisko: ";
Ła cuch zerowy (dokładniej: ła cuch tekstowy o zerowej długo ci) cin >> nazwisko;
strcat(imie, " ");
to taki ła cuch, który zawiera 0 (zero) znaków. Jak to mo liwe, strcat(imie, nazwisko);
by ła cuch tekstowy zawierał zero znaków? W C++ ła cuchy znaków cout << "\nNazywasz sie: " << imie << '\n';
zawieraj na ko cu znak '\0' (zero) jako "wartownika" ko ca dlugosc = strlen(imie);
tekstu. Je li pierwszy element tablicy znakowej b dzie zerem - cout<<"Imie i nazwisko sklada sie z: "<<dlugosc<<"znakow\n";
powstanie wła nie ła cuch znakowy o zerowej długo ci. Mo na to cout << "Nacisnij dowolny klawisz";
zrobi np. tak: getch();
return 0;
char napis[0] = 0; }
char *p = "";
char napis[50] = ""; W programie z Listingu 5.2 nie musisz stosowa dodatkowej
________________________________________________________________ zmiennej dlugosc. Taki sam efekt uzyskasz pisz c zamiast dwu
wierszy jeden:

Kiedy C++ wyznacza długo ła cucha znaków - zlicza kolejne cout << "Wszystkich znakow bylo: " << strlen(imie) << '\n';
znaki, a dojdzie do zera. W przykładzie ju pierwszy znak jest
zerem, wi c C++ uzna, e długo takiego ła cucha wynosi zero. POBIERANIE I WYSZUKIWANIE WYCINKA TEKSTU - substring.
Czasem w praktyce programowania zainicjowanie takiego pustego
ła cucha pozwala mie pewno , e tablica nie zawiera jakich Podobnie łatwo do ł czenia ła cuchów mo esz dokona podziału
61
wi kszych tekstów na mniejsze fragmenty. "Du e" pierwone
ła cuchy nazywaj si "string", a te mniejsze fragmenty - clrscr();
"substring". Do podziału ła cuchów na "podła cuchy" j zyk C++ cout << "Wpisz jakis tekst: ";
dysponuje specjalnymi funkcjami: gets(napis1);

strncpy() i strcpy() - STRiNg CoPY - kopiuj string. strcpy(napis2, napis1);


strncpy(napis3, napis1, 3);
[S] Substring - Cz składowa wi kszego ła cucha znaków.
________________________________________________________________ cout << "\nKopia tekstu: ";
Substring to mniejszy ła cuch znaków stanowi cy cz wi kszego cout << '*' << napis2 << "*\n";
ła cucha znaków. Np. substring BAB jest cz ci wi kszego cout << "Pierwsze 3 znaki tekstu: ";
ła cucha BABCIA. cout << '\'' << napis3 << '\'' << '\n';
source - ródło (miejsce pochodzenia);
destination - miejsce przeznaczenia. cout << "\n\n...dowolny klawisz...";
________________________________________________________________ getch();
return 0;
}
Funkcja strncpy() kopiuje we wskazane miejsce tylko pewn -
zadan liczb pocz tkowych znaków ła cucha. Funkcj strncpy()
mo esz zastosowa w swoich programach w nast puj cy sposób: [???] A je li zabraknie znaków?
________________________________________________________________
char tab_A[80] = "BABCIA";
char tab_B[80] = ""; Spróbuj uruchomi program podaj c mu ła cuch tekstowy krótszy
ni 5 znaków. Jest to próba oszukania funkcji, która oczekuje,
strncpy(tab_B, tab_A, 3); /* kopiuj 3 pierwsze znaki */ e kopiowane 3 znaki powinny istnie , mało tego, powinny by
zaledwie cz ci wi kszego ła cucha.
W tym przykładzie wywołujemy funkcj strncpy() przekazuj c jej Jak widzisz, program nie "zawiesza si ". W j zyku C++ funkcje
przy wywołaniu trzy argumenty: opracowane s zwykle w taki sposób, e nawet otrzymuj c
bezsensowne parametry potrafi jako tam wybrn z sytuacji. Tym
tab_B - destination string - wynikowy ła cuch tekstowy (ten
nowy, który powstanie); niemniej, nawet je li program si nie zawiesza, nie oznacza to,
tabn_A - source string - ła cuch ródłowy (ten, z którego e wyniki działania przy bezsensownych danych wej ciowych b d
b dziemy "obcina " kawałek); mie jakikolwiek sens. Jako programista powiniene wystrzega
3 - maksymalna liczba znaków, któr nale y obci . Obci te si takich bł dów (dane z poza zakresu, dane bez sensu
znaki utworz "substring" - "BAB". merytorycznego) nie licz c na to, e C++ jako z tego wybrnie.
________________________________________________________________
Pobieranie i "wycinanie" znaków rozpocznie si od pierwszego
znaku ła cucha ródłowego tab_A[80], wi c funkcja wywołana w Najwa niejszy fragment tekstu programu wraz z komentarzem:
taki sposób:
char napis1[80] = ""; <-- deklaracje zmiennych tekstowych
strncpy(string1, string2, 3); char napis2[80] = ""; <-- i nadanie im zerowej zawarto ci
char napis3[80] = ""; <-- długo pustego napisu - zero.
spowoduje pobranie pierwszych 3 znaków z ła cucha string2 i ...
skopiowanie ich do ła cucha string1. gets(napis1); <-- GET String - pobierz string
strcpy(napis2, napis1); <-- kopiowanie całego tekstu
Funkcja strcpy() (Uwaga! bez "n") powoduje skopiowanie całego strncpy(napis3, napis1, 3); <-- kopiowanie cz ci tekstu
ła cucha znaków. Sposób zastosowania funkcji jest podobny do ...
przykładu z strncpy(), z tym, e nie trzeba podawa liczby
całkowitej okre laj cej ilo znaków do kopiowania. Jak Zwró uwag , e program do pobrania danych (tekstu) od
wszystkie, to wszystkie (jak mawiała babcia), zatem wywołanie u ytkownika posługuje si funkcj gets() (ang. GET String -
funkcji: pobierz ła cuch znaków). Obiekt cin jest bardzo wygodnym
rodkiem słu cyn do wczytywania danych, ale nie pozwala
strcpy(string1, string2); wprowadza napisów zawieraj cych spacje. Je li zastosowaliby my
w programie
spowoduje skopiowanie całego ła cucha znaków zawartego w
zmiennej string2 do zmiennej string1. Je li, dla przykładu, cin >> string1;
zmiennej string2 przypiszemy ła cuch tekstowy
i wpisali tekst zawieraj cy spacje, np.:
string2 = "BABCIA";
To nie wa ne, czy Polska...
to po zadziałaniu funkcji strcpy(string1, string2) zmiennej
string1 zostanie przypisany dokładnie taki sam ła cuch. wczytane zostałyby tylko znaki To (do pierwszej spacji). Z kolei

Rozwa my program przykładowy. Po uruchomieniu program poprosi o funkcja gets() pozwala wczyta wiersz tekstu zawieraj cy dowolne
wpisanie ła cucha tekstowego. Wpisz dowolny tekst. Tekst
powinien zawiera wi cej ni 3 znaki. Po pobraniu znaki uznaj c za koniec znak CRLF (powrót karetki, zmiana
wyj ciowego/ ródłowego tekstu od u ytkownika, program pobierze z wiersza) generowany po naci ni ciu [Entera]. Przeciwn ,
symetryczn funkcj do gets() jest funkcja puts() (ang. PUT
tego tekstu kilka mniejszych ła cuchów tekstowych typu String - wyprowad wiersz tekstu). Prototypy funkcji gets() i
"substring" i wy wietli je na ekranie. puts() znajduj si w pliku nagłówkowym STDIO.H. Dlatego ten
plik nagłówkowy został doł czony na pocz tku dyrektyw #include.
[P068.CPP]

#include <conio.h> WYSZUKIWANIE TEKSTÓW.


#include <iostream.h>
#include <string.h> Wyobra my sobie, e mamy list imion i chcemy na tej li cie
#include <stdio.h> odszuka znajome imi np. Alfons. Specjalnie do takich celów C++

main() dysponuje funkcj :


{
char napis1[80] = ""; strstr() - STRing's subSTRing - cz ła cucha tekstowego
char napis2[80] = "";
char napis3[80] = ""; Aby wyszuka w wi kszym tek cie mniejszy fragment, powinni my
62
wywołuj c funkcj przekaza jej dwie informacje: #include <conio.h>
#include <iostream.h>
GDZIE SZUKA - wskaza ła cuch tekstowy do przeszukiwania; #include <string.h>
i #include <stdio.h>
CZEGO SZUKA - poda ten tekst, który nas interesuje i który
funkcja powinna dla nas odnale . main()
{
Funkcja strstr(), powinna zatem mie dwa argumenty: char str1[80], str2[80];
char *ptr;
char Lista[] = "Adam, Buba, Adolf, Magda";
... clrscr();
gdzie = strstr(Lista, "Adolf"); cout << "Wpisz tekst do przeszukania:\n ";
gets(str1);
Funkcja strstr() wyszukuje pierwsze wyst pienie danego tekstu.
Po wyszukaniu, funkcja powinna nam w jaki sposób wskaza , gdzie cout << "Co mam wyszukac?\n--> ";
gets(str2);
znajduje si interesuj cy nas tekst. Jak wiesz, do wskazywania
ró nych interesuj cych rzeczy słu w C++ WSKA NIKI (pointer). W ptr = strstr(str1, str2); <-- wyszukiwanie tekstu
cout << "Znalazlem: " << '\'' << str1 << '\'' << " w ";
przykładzie powy ej funkcja strstr() w wyniku swojego działania cout << '\'' << str2 << '\'' << '\n';
zwraca wska nik do szukanego tekstu "Alfons". Aby wska nik nam cout << ptr;
nie przepadł, trzeba go zapami ta . Funkcja zatem przypisuje cout << "\n\n ...Nacisnij klawisz...";
wska nik zmiennej "gdzie". W miejscu przeznaczonym dla tej getch();
zmiennej w pami ci b dzie odt d przechowywany wska nik, return 0;
wskazuj cy nam - gdzie w pami ci kmputera znajduje si }
interesuj cy nas tekst "Alfons\0".

Aby komputer zarezerwował miejsce w pami ci dla wska nika, DU E I MAŁE LITERY.
trzeba go o to "poprosi " na pocz tku programu, deklaruj c, e w
Litery mog by małe i du e. Du e litery nazywaj si
programie zamierzamy posługiwa si wska nikiem. Deklaracja "capitals". Od słowa CAPitalS pochodzi skrót na klawiszu [Caps
wska nika do zmiennej tekstowej wygl da tak: Lock]. Innym, u ywanym do okre lenia tego samego słowem jest
"upper case" (du e litery) lub "lower case" (małe litery).
char *wskaznik; Czasami pojawia si potrzeba zaminy du ych liter na małe, b d
odwrotnie. W C++ słu tego celu funkcje:
Przykładowy program pni ej demonstruje sposób zadeklarowania
wska nika i wyszukiwanie tekstu. Program nie oczekuje adnej strupr() - STRing to UPpeR case - zamie litery wła cuchu
informacji wej ciowej od u ytkownika. Uruchom program i tekstowym na du e.
przeanalizuj wydruk na ekranie porównuj c go z tekstem programu. strlwr() - STRing to LoWeR case - zamie litery w ła cuchu na
małe.

[P069.CPP] Program przykładowy poni ej demonstruje działanie tych funkcji.

#include <conio.h> [P071.CPP]


#include <iostream.h>
#include <string.h> #include <conio.h>
#include <iostream.h>
main() #include <string.h>
{ #include <stdio.h>
char string1[] = "Ala, Magda, Adam, Alfons, Jasiek, Alfons, As";
main()
char *pointer; {
char string1[80];
clrscr();
cout << "Lista:\n" << string1; clrscr();
cout << "Wpisz tekst do zamiany:\n";
pointer = strstr(string1, "Alfons"); gets(string1);

cout << "Tekst 'Alfons' wystapil po raz pierwszy:\n"; cout << "\nNormalnie: " << string1 << '\n';
cout << " " << pointer << '\n'; cout << "TYLKO DUZE: " << strupr(string1) << '\n';
cout << "tylko male: " << strlwr(string1) << '\n';
pointer = strstr(ptr, "Jasiek"); cout << "\n\n...Nacisnij klawisz...";
cout << "Tekst 'Jasiek' wystapil po raz pierwszy:\n"; getch();
cout << " " << pointer << '\n'; return 0;
}
pointer = strstr(pointer, "As");
cout << "Tekst 'As' wystapil:\n";
cout << " " << ptr << '\n' << "\n\nNacisnij cokolwiek"; [???] DLA DOCIEKLIWYCH.
________________________________________________________________
getch();
return 0; * Argumenty funkcji - zawsze w tej samej kolejno ci!
} Kiedy wywołujesz gotow funkcj - np. strstr(), argumenty
funkcji musz by podane zawsze w tej samej kolejno ci (tak, jak
Inn metod zastosowania funkcji manipuluj cych ła cuchami
tekstowymi mo e by "obróbka" tekstu wprowadzonego przez funkcja "si spodziewa"). Wywołanie funkcji:
u ytkownika. Nast pny program przykładowy pozwala u ytkownikowi
wprowadzi tekst do przeszukiwania (odpowiednik listy) i tekst pointer = strstr(string, substring, 3);
do wyszukania (odpowiednik imienia). W wyniku wyszukania
wskazanego ła cucha program wy wietla list pocz wszy od powiedzie si i funkcja zadziała zgodnie z oczekiwaniami.
wyszukanego pierwszego wyst pienia zadanego ła cucha znaków. Natomiast wywołanie funkcji tak:

[P070.CPP] pointer = strstr(3, substring, string);

63
spowoduje bł d przy kompilacji programu. identyfikacyjny pliku).

* Przy manipulacji stringami kłopoty mog sprawia spacje, b d Zestaw "narz dzi" potrzebnych nam do pracy to:
ich brak. Dla przykładu przy sklejaniu dwóch ła cuchów
tekstowych warto dla czytelno ci doda spacj , by nie uzyskiwa IO.H - prototypy funkcji obsługi WEj cia/WYj cia (ang.
napisów typu: WaldekKowalski. Łatwo mo na przegapi i inne Input/Output=IO);
ograniczniki (ang. delimiter).
FCNTL.H - plik zawieraj cy definicje wymienionych poni ej
* Ocena długo ci tekstu. stałych:
Szczególnie przewiduj cy i ostro ny musi by programista wtedy, O_BINARY - otwarcie pliku w trybie binarnym;
gdy ła cuch b dzie wprowadzany przez u ytkownika programu. O_TEXT - otwarcie pliku w trybie tekstowym;
O_RDONLY (Open for Read Only) - otwórz tylko do odczytu;
O_WRONLY (...Write Only) - tylko dla zapisu;
LEKCJA 19: KILKA INNYCH PRZYDATNYCH FUNKCJI. O_RDWR (Reading and Writing) dozwolony zapis i odczyt;
________________________________________________________________
STAT.H - zawiera definicje stałych
W trakcie tej lekcji dowiesz si , jak zapisa teksty na dysku i S_IREAD - plik tylko do odczytu (przydatne dla funkcji creat);
jak jeszcze mo na nimi manipulowa przy pomocy gotowych funkcji S_IWRITE - tylko zapis (przydatne dla funkcji creat);
Borland C++.
________________________________________________________________ FUNKCJE:
int open(p1, p2, p3) - trójparametrowa funkcja otwieraj ca plik;

Program poni ej demonstruje zastosowanie trzech przydatnych (parametry patrz przykład) zwraca do programu Wynik = -1
funkcji: (operacja zako czona niepowodzeniem - np. nie ma pliku)
lub Wynik = File Descriptor - numer pliku przekazany przez DOS.
[P072.CPP] int creat(p1, p2) - funkcja tworz ca nowy plik;
int read(...) - funkcja czytaj ca z pliku;
#include <conio.h> int write(...) - funkcja zapisu do pliku;
imt close(...) - zamkni cie pliku.
int main(void)
{ Po uruchomieniu program otwiera automatycznie trzy standardowe
int i, x = 0, y = 0; pliki, zwi zane z urz dzeniami:
clrscr(); 0 - stdin - standardowy plik wej ciowy (norm. klawiatura
for (i = 1; i < 10; i++) konsoli);
{ 1 - stdout - standardowy plik wyj ciowy (norm. monitor);
y = i; 2 - stderr - standardowy plik wyj ciowy - diagnostyczny
x = 5*i; (komunikaty o bł dach).
textbackground(16-i);
textcolor(i); [S] STD...
gotoxy(x, y); STandarD INput - standardowe wej cie.
cprintf("Wspolrzedne: x=%d y=%d", x, y); STD OUTput - standardowe wyj cie.
getch(); STD ERRors - plik diagnostyczny.
}
return 0; //[P072-2.CPP]
}
# include <stdio.h>
textbackground() - ustaw kolor tła pod tekstem # include <conio.h>
texcolor() - ustaw kolor tekstu # include <SYS\STAT.H> //Duze litery tylko dla podkreslenia
gotoxy() - rozpocznij drukowanie tekstu od punktu o # include <FCNTL.H>
współrz dnych ekranowych # include <IO.H>
x - numer kolumny (w normalnym trybie: 1-80)
y - numer wiersza (w normalnym trybie: 1-25) char *POINTER;
int IL_znakow, DLUG_pliku, TRYB_dostepu, Wynik, i;
[Z] int Plik_1, Plik_2;
________________________________________________________________ char BUFOR[20] = {"TEKST DO PLIKU"};
1. Rozmie na ekranie napisy i znaki semigraficzne tworz ce char STOS[3], ZNAK='X';
rysunek tabelki.
2. Opracuj program, w którym pojedyncze znaki, b d napisy b d main()
porusza si po ekranie. {
3. Spróbuj przyspieszy działanie swojego programu z POINTER = &BUFOR[0];
poprzedniego zadania poprzez wstawk w assemblerze.
________________________________________________________________ printf("Wloz dyskietke do A: i nacisnij cos...\n");

OPERACJE PLIKOWE - NIEOBIEKTOWO. Plik_1 = creat( "a:\\plik1.dat", S_IWRITE);

W systemia DOS dane i programy s zgrupowane w pliki. Pliki if (Plik_1 == -1)


(ang. file) mog by TEKSTOWE i BINARNE. Najcz stszymi printf("\n Nie udalo sie zalozyc plik1.dat...");
operacjami na plikach s :
Plik_2 = creat( "a:\\plik_2.dat", S_IWRITE);
* Utworzenie nowego pliku (ang. CREATE); if (Plik_2 == -1)
* Odczyt z pliku (ang. READ); printf("\n Klops przy Plik2.dat");
* Zapis do pliku (WRITE);
* Otwarcie pliku (OPEN); _fmode = O_BINARY; //Bedziemy otwierac w trybie binarnym
* Zamkni cie pliku (CLOSE);
* Wyszukanie danej w pliku (SEEK); Wynik = open( "a:\\plik1.dat", O_WRONLY );
if (Wynik == -1)
W kontaktach z urz dzeniami - np. z dyskiem po rednicz DOS i printf("\n Nie udalo sie otworzyc pliku...");
BIOS. To system DOS wie, gdzie na dysku szuka pliku (katalogu)
o podanej nazwie i w których sektorach dysku znajduj si IL_znakow = 15; //Ilosc znakow do zapisu
fizycznie dane nale ce do danego pliku. Operacje z plikami
opieraj si o odwoływanie do systemu operacyjnego za Wynik =write( Plik_1, POINTER, IL_znakow );
po rednictwem tzw. Deskryptora pliku (File Descriptor - numer
printf("Zapisalem %d znakow do pliku.", Wynik);
64
int Numer = 0;
close( Plik_1 ); int Plik, L, M, i;
long int Dlug_Pliku;
Plik_1 = open("a:\\Plik1.dat", O_RDONLY );
Plik_2 = open("a:\\Plik_2.dat", O_WRONLY ); main()
{
POINTER = &STOS[0]; clrscr();
creat("A:\PROBA.DAT", S_IWRITE);
for (i=1; ZNAK; i++) //Kopiuje plik + spacje printf("\nPodaj liczbe rozna od zera, zero - KONIEC");
{ _fmode=O_BINARY;
STOS[1] = ZNAK; Plik=open("A:\PROBA.DAT", O_WRONLY);
write( Plik_2, POINTER, 2); do
read( Plik_1, &ZNAK, 1); {
} printf("\n Nr liczby \t%d\t\t", Numer++);
scanf("%d", &L);
close(Plik_1); close(Plik_2); if (L) write(Plik, &L, 2);
}
getch(); while (L != 0);
return 0;
} close(Plik);
getch();

Przykładowy program wykonuje nast puj ce czynno ci: printf("\n Teraz odczytam te liczby z pliku \n");
Plik=open("A:\PROBA.DAT", O_RDONLY);
1. Tworzy plik a:\plik1.dat (potrzebny dost p do dyskietki a:). Dlug_Pliku=lseek(Plik, 0, SEEK_END);
2. Tworzy plik a:\plik_2.dat. for (i=Dlug_Pliku-dwa_bajty; i>=0; i-=2)
3. Otwiera plik a:\plik1.dat w trybie binarnym tylko do zapisu. {
(ZWRÓ UWAG , e tryb binarny nie przeszkadza zapisa tekstu.) lseek(Plik, i, SEEK_SET);
4. Dokonuje zapisu do pliku. read(Plik, &M, dwa_bajty);
5. Zamyka plik a:\plik1.dat. printf("%d, ", M);
6. Otwiera plik1.dat w trybie binarnym tylko do odczytu. }
7. Otwiera plik_2.dat tylko do zapisu. close(Plik);
8. Kopiuje plik1.dat do plik_2.dat dodaj c spacje. getch();

Zwró uwag na konstrukcj : return 0;


}
for(i=1; ZNAK; i++)
[Z]
Wyja nienie. Póki jest znak wykonuj kopiowanie. Przypominam, e ________________________________________________________________
koniec to NUL - '\0'. Opracuj program wykonuj cy operacje na tekstach opisane
wcze niej na ła cuchach tekstowych pobieranych z zewn trznych
plików dyskowych i umieszczanych w wynikowych plikach
Je li czytamy i piszemy po kolei - wszystko jest proste. Je eli tekstowych.
natomiast chcemy wyszuka w pliku okre lone miejsce, to b dzie
nam jeszcze dodatkowo potrzebny mechanizm do okre lenia pozycji
w pliku - tzw. WSKA NIK PLIKOWY. Pozycj mo na okre la wzgl dem

pocz tku pliku: LEKCJA 20 - JE LI PROGRAM POWINIEN URUCHOMI INNY


PROGRAM...
SEEK_SET - stała okre laj ca pozycjonowanie wzgl dem pocz tku ________________________________________________________________
pliku; W trakcie tej lekcji dowiesz si , jak w C++ mo na programowa
SEEK_CUR - wzgl dem poło enia bie cego (ang. Current - * procesy potomne
bie cy); * pisa programy rezyduj ce w pami ci (TSR)
SEEK_END - okre lenie pozycji wzgl dem ko ca pliku; ________________________________________________________________
EOF - End Of File - znak ko ca pliku.
O programach rezydentnych (TSR) i procesach potomnych.
Funkcja lseek():
WSK_PLK = long int lseek( plik, o_ile, kierunek); Warunek zewn trznej zgodno ci z poprzednimi wersjami DOS
słu y do pozycjonowania w pliku. wyra nie hamuje ewolucj systemu MS DOS w kierunku "powa nych"
Liczba typu long int okre laj ca pozycj w pliku nazywana jest systemów operacyjnych umo liwjaj cych prac wieloprogramow w
WSKA NIKIEM PLIKOWYM ( w programie przykładowym została trybie "multiuser", "multitasking" i "time sharing". Pewn
oznaczona long int WSK_PLK). namiastk pracy wieloprocesowej daj nam ju DOS 5/6 i Windows
3.1. Mo na ju otwiera wiele okien programów jednocze nie,
W programie przykładowym wykonywane jest kolejno: mo na np. drukowa "w tle", mo na wreszcie pisa rezyduj ce
* utworzenie na dysku pliku PROBA.DAT; stale w pami ci programy klasy TSR (ang. Terminated and Stay
* zapis do pliku wprowadzonych z klawiatury liczb całkowitych Resident) uaktywniaj ce si "od czasu do czasu".
typu int;
* zamkni cie pliku; O bloku PSP.
* otwarcie pliku do odczytu;
* ustawienie wska nika na ko cu pliku; System DOS przydziela programom blok - "nagłówek" wst pny
* odczyt z pliku od ko ca; nazywany PSP (ang. Program Segment Prefix). Blok ten zawiera
* wyprowadzenie odczytanych z pliku danych na ekran. informacje o stanie systemu DOS w momencie uruchamiania programu
[P073.CPP] (nazywanego tu inaczej procesem). Znajduj si tam informacje o
bie cym stanie zmiennych otoczenia systemowego (ang.
# include "sys\stat.h" environment variables) i parametrach uruchomieniowych. Blok PSP
# include "conio.h" zajmuje 256 bajtów na pocz tku kodu programu w zakresie adresów:
# include "stdio.h"
# include "io.h"
# include "fcntl.h" CS:0000 ... CS:0100 (hex)
# define Cofnij_o_Zero 0
# define dwa_bajty 2 Wła ciwy kod programu zaczyna si zatem od adresu CS:0100.

65
Interpreter rozkazów systemu DOS ładuje programy do pami ci
posługuj c si funkcj systemow nr 75 (4B hex). Wszystko jest /* Funkcje grupy spawn...() : spawnl() */
proste dopóki mamy do czynienia z programem "krótkim" typu
*.COM. Je li jednak e program uruchamiany jest w wersji # include <process.h>
"długiej" - *.EXE, dowolna mo e by nie tylko długo pliku, ale # include <stdio.h>
# include <conio.h>
tak e pocz tkowa zawarto rejestrów CS, SS, SP i IP. W plikach
typu *.EXE pocz tek bloku PSP wskazuj rejestry DS (DS:0000) i void main()
ES. W Borland C++ masz do dyspozycji specjaln funkcj getpsp() {
przy pomocy której mo esz uzyska dost p do bloku PSP programu. int rezultat;
Krótki przykład zastosowania tej funkcji poni ej: rezultat = spawnl(P_WAIT, "program.exe", NULL);
if (rezultat == -1)
/* Przykład zastosowania funkcji getpsp(): */ {
perror(" Fiasko !");
# include <stdio.h> exit(1);
# include <dos.h> }
}
main()
{
static char TAB[128]; /* Funkcja spawnle() */
char far *ptr;
int dlugosc, i; # include <process.h>
# include <stdio.h>
printf("Blok PSP: %u \n", getpsp()); # include <conio.h>

ptr = MK_FP(_psp, 0x80); void main()


dlugosc = *ptr; {
int rezultat;
for (i = 0; i < dlugosc; i++)
TAB[i] = ptr[i+1]; rezultat = spawnle(P_WAIT, "program.exe", NULL, NULL);
if (rezultat == -1)
printf("Parametry uruchomieniowe: %s\n", TAB); {
perror("Fiasko !");
} exit(1);
}
W normalnych warunkach po wykonaniu "swojej roboty" program }
zostaje usuni ty z pami ci operacyjnej (czym zajmuje si funkcja
Zagadnienie uruchamiania programów potomnych (ang. child
systemowa nr 76 - 4C (hex)). Aby tak si nie stało, program process) przez programy macie yste (ang. parent process) jest
mo e: rozpracowane w C++ do dokładnie i zarazem obszernie. Istnieje
wiele gotowych funkcji bibliotecznych, z usług których mo esz tu
* uruchomi swój proces (program) potomny;
* wyj "na chwil " do systemu DOS - tj. uruchomi jako swój skorzysta . Wszystko to nie jest jednak "prawdziwym" programem
proces potomny interpreter COMMAND.COM; TSR. Przyjrzyjmy si zatem dokładniej dopuszcalnym przez system
* przekaza sterowanie programowi COMMAND.COM pozostaj c w DOS sposobom zako czenia programu nie powoduj cym usuni cia
pami ci w postaci "u pionej" oczekuj c na uaktywninie. programu z pami ci.

Poni ej kilka prostych przykładów uruchamiania jednych procesów Je li program rezydentny jest niewielki (kod < 64 K), mo emy
przez inne w Borland C++: zako czy program posługuj c si przerywaniem INT 39 (27 hex).
Je li natomiast zamierzamy posługiwa si dłu szymi programami,
/* Funkcja execv(): uruchomienie programu "potomnego"*/ mamy do dyspozycji funkcj systemow nr 49 (31 hex). Nale y tu
zwróci uwag , e zako czenie programu w taki sposób (z
# include <process.h> pozostawieniem w pami ci) nie spowoduje automatycznego
# include <stdio.h> zamkni cia plików, a jedynie opró nienie buforów. Programy
# include <errno.h> rezydentne dzieli si umownie na trzy kategorie:

void main(int argc, char *argv[]) [BP] - background process - procesy działaj ce "w tle";
{ [SV] - services - programy usługowe - np. PRINT;
int i; [PP] - pop up programs - uaktywniane przez okre lon kombinacj
klawiszy;
printf("Parametry uruchomieniowe:");
for (i=0; i<argc; i++) System DOS dysponuje tzw. przerywaniem multipleksowym
printf("\n%d) %s", i, argv[i]); (naprzemiennym) wykorzystywanym cz sto przez programy
rezydentne. Jest to przerywanie nr INT 47 (2F hex). MS DOS
printf("Przekazuje parametry do procesu 2 par_1, par_2...\n"); załatwia takie problemy funkcjami nr 37 (25 hex) - zapisanie
execv("CHILD.EXE", argv); wektora przerywania i 53 (35 hex) - odczytanie wektora
.... przerywania.
exit (2);
} Z jakich funkcji C++ mo na skorzysta ?

[P074.CPP] W C++ masz do dyspozycji par funkcji getvect() i setvect()


(ang. GET/SET VECTor - pobierz/ustaw wektor przerywania).
/* Funkcja system() - na chwil do DOS */ Poni ej krótkie przykłady zastosowa tych funkcji.

# include <stdlib.h> /* Opcja: Options | Compiler | Code generation | Test Stack


# include <stdio.h> Overflow powinna zosta wył czona [ ] (off) */

void main() # include "stdio.h"


{ # include "dos.h"
printf("Wyjscie do DOS i wykonanie jednego rozkazu:\n"); # include "conio.h"
system("dir > c:\plik.dir");
} /* INT 28 (1C hex) - Przerywanie zegarowe */

66
void interrupt ( *oldhandler)(void); 183 - APPEND.EXE
int licznik = 0;
Identyfikator programu TSR jest przekazywany za po rednictwem
void interrupt handler(void) rejestru AH.
{
/* Inkrementacja globalnej zmiennej licznik */ System DOS jest na razie systemem w zasadzie jednozadaniowym i
licznik++; jednou ytkownikowym, w którym zasoby s przydzielane procesom
kolejno (ang. serially reusable resources). Aby uchroni si
/* Wywolujemy stary "handler" zegara */ przed potencjalnym konfliktem, powinni my upewni si , czy DOS
oldhandler(); "nic nie robi". Cz sto stosowan "sztuczk techniczn " jest
} zastosowanie flag ErrorMode i InDos systemu oraz wykorzystanie
mechanizmów przerywa nr 36 i 40 (24 i 28 hex). Przydatn
void main() informacj jest tak e identyfikator programu - PID. Na tak
{ ewntualno Borland C++ dysponuje makrem getpid zdefiniowanym w
/* Zapami taj poprzedni wektor przerywania 28 */ pliku nagłówkowym <PROCESS.H>:
oldhandler = getvect(28);
# define getpid() (_psp)
/* Zainstaluj now funkcje obslugi przerywania */
setvect(28, handler); Inn przydatn funkcj mo e okaza si keep() (ang. keep
resident - pozosta rezydentny). Oto krótki przykład
/* Inkrementuj licznik */ zastosowania tej funkcji - znów z wykorzystaniem przerywa
for (; licznik < 10; ) printf("licznik: %d\n",licznik); zegarowych.

//odtworz stara funkcje obslugi przerywania: interrupt handler # include <dos.h>

setvect(28, oldhandler); # define INTR 0x1C /* przerywanie INT 28 */


} # define ATTR 0x7900

/* ograniczenie wielko ci sterty (heap length) i stosu (stack


# include <stdio.h> length): */
# include <dos.h> extern unsigned _heaplen = 1024;
extern unsigned _stklen = 512;
void interrupt nowa_funkcja(); // prototyp funkcji - handlera
void interrupt ( *oldhandler)(void);
void interrupt (*oldfunc)(); /* interrupt function pointer */
void interrupt handler(void)
int warunek = 1; {
unsigned int (far *ekran)[80];
main() static int licznik;
{
printf("\n [Shift]+[Print Screen] = Quit \n"); // Adres pamieci dla monitora barwnego: B800:0000.
printf("Zapamietaj, i nacisnij cosik...."); // Dla monitora monochromatycznego: B000:0000.
while(!kbhit());
ekran = MK_FP(0xB800,0);
/* zapamietaj stary wektor */
oldfunc = getvect(5); // piloksztaltna zmiana licznika w przedziale 0 ... 9
/* INT 5 to przerywanie Sys Rq, albo Print Screen */
licznik++;
/* zainstaluj nowa funkcje obslugi: interrupt handler */ licznik %= 10;
setvect(5, nowa_funkcja);
ekran[0][79] = licznik + '0' + ATTR;
while (warunek) printf(".");
// wywołaj stara funkcje obslugi - old interrupt handler:
/* Odtworz stary wektor przerywania */ oldhandler();
setvect(5, oldfunc); }

printf("\n Udalo sie... nacisnij cosik..."); void main()


while(!kbhit()); {
}
oldhandler = getvect(INTR);
/* Definicja nowego handlera */
void interrupt nowa_funkcja() // zainstaluj nowa funkcje interrupt handler
{ setvect(INTR, handler);
warunek = 0;
/* jesli warunek == 0, petla zostanie przerwana*/ /* _psp - to adres pocz tku programu, SS:SP to adres stosu,
} czyli koniec programu. Biorac pod uwage przesuniecie
SEGMENT/OFFSET o jedna tetrade: SS:SP = SS + SP/16; */
Je li nasz program zamierza korzysta z przerywania
multipleksowego INT 47 (2F hex), nale y pami ta , e przerywanie keep(0, (_SS + (_SP/16) - _psp));
}
to wykorzystuj tak e inne programy systemowe. Rozró nia te
programy mo na przy pomocy identyfikatorów (podaj dziesi tnie): Kilka istotnych drobiazgów technicznych.

01 - PRINT.EXE W Borland C++ masz do dyspozycji predefiniowane struktury


06 - ASSIGN.COM BYTEREGS (rejestry jednobajtowe - "połówki") i WORDREGS
16 - SHARE.EXE (10 hex) (rejestry dwubajtowe). Mo esz po tych strukturach dziedziczy i
26 - ANSI.SYS np. tak metod wbudowa je do swoich własnych klas. Nic nie
67 - HIMEM.SYS stoi na przeszkodzie, by utworzy np. klas
72 - DOSKEY.COM
75 - TASK SWITCHER class REJESTRY : public WORDREGS
173 - KEYB.COM {
174 - APPEND.EXE ...
176 - GRAFTABL.COM };
67
inregs.x.dx = FP_OFF(nazwapliku);
czy te własn struktur : segregs.ds = FP_SEG(nazwapliku);
int86x(0x21, &inregs, &outregs, &segregs);
struct REJESTRY : WORDREGS { ... }; printf("\n Atrybuty pliku: %X\n", outregs.x.cx);
}
Definicje tych struktur w Borland C++ wygl daj nast puj co:
# include <stdio.h>
struct BYTEREGS # include <dos.h>
{ int SkasujPlik(char far*) // Prototyp
unsigned int al, ah, bl, bh, cl, ch, dl, dh;
}; void main()
{
struct WORDREGS int error;
{ err = SkasujPlik("PLIK.DAT");
unsigned int ax, bx, cx, dx, si, di, cflag, flags; if (!error) printf("\nSkasowalem plik PLIK.DAT");
}; else
printf("\nNie moge skasowac pliku PLIK.DAT");
Rejestry segmentowe maj własn struktur : }

struct SREGS int SkasujPlik(char far *nazwapliku)


{ {
unsigned int es, cs, ss, ds; union REGS regs; struct SREGS sregs;
}; int wynik;
regs.h.ah = 0x41; // Funkcja kasowania pliku
Pole WORDREGS::cflag odpowiada stanowi flagi przeniesienia (ang. regs.x.dx = FP_OFF(nazwapliku);
sregs.ds = FP_SEG(nazwapliku);
Carry Flag) rejestru flags mikroprocesora, a pole wynik = intdosx(&regs, &regs, &sregs);
WORDREGS::flags odpowiada stanowi cało ci rejestru (w wersji 16 return(regs.x.cflag ? wynik : 0);
- bitowej). Poniewa rejestry mog by widziane alternatywnie // Jesli CF == 1, nastapilo fiasko operacji
jako podzielone na miezale ne połówki - lub jako cało , to }
wła nie "albo - albo" wyra a w C++ unia. W Borland C++ taka
predefiniowana unia nazywa si REGS: I wreszcie na zako czenie szczegóły techniczne działania funkcji

union REGS systemowej nr 49 (31 hex) odpowiedzialnej za obsług programów


{ rezyduj cych w pami ci (załadowanie procesu z pozostawieniem w
struct WORDREGS x; pami ci).
struct BYTEREGS h;
}; 1. Wywołanie funkcji:
AL = kod powrotu (ang. return code);
Z tych predefiniowanych struktur danych korzystaj m. in. AH = 0031 (hex) - nr funkcji;
funkcje int86() intdosx() i int86x() ("x" pochodzi od eXtended - DX = długo programu TSR w paragrafach - Size/16 [Bajtów];
2. Działanie:
rozszerzony). Oto krótkie przykłady zastosowania tych funkcji. * funkcja nie zamyka plików, lecz opró nia bufory;
* funkcja odtwarza wektory przerywa nr 34, 35, 36 (hex 21, 22,
# include <stdio.h> 23);
# include <conio.h> * proces macie ysty mo e uzyska kod powrotu przy pomocy funkcji
# include <dos.h>
nr 77 (4D hex).
# define INT_NR 0x10 // 10 hex == 16 (Nr przerywania) VIDEO
Wykorzystanie struktury SDA (ang. Swappable Data Area - obszar
void UstawKursor(int x, int y) wymiennych danych) nie jest praktyk zalecan .
{
union REGS regs; Tworz c programy rezydentne b d bardzo ostro ny i pami taj o
jednej z podstawowych zasad - NIE JESTE (tzn Twój program nie
regs.h.ah = 2; // ustaw kursor jest) SAM.
regs.h.dh = y; // Wspolrzedne kursora na ekranie
regs.h.dl = x;
regs.h.bh = 0; // Aktywna stronica ekranu --> video page 0 LEKCJA 21: KILKA PROCESÓW JEDNOCZE NIE.
int86(INT_NR, &regs, &regs); ________________________________________________________________
}
W trakcie tej lekcji dowiesz si , jak to zrobi , by Twój PC mógł
void main() wykonywa kilka rzeczy jednocze nie.
{ ________________________________________________________________
clrscr();
UstawKursor(30, 12);
printf("Tekst - Test"); Procesy współbie ne.
while(!kbhit());
} Sprz t, czyli PC ma mo liwo ci zdecydowanie pozwalaj ce na
techniczn realizacj pracy wielozadaniowej. Nie ma te adnych
# include <dos.h> przeciwskaza , by zamiast koprocesora umo liwi w PC instalacj
# include <process.h> drugiego (trzeciego) równoległego procesora i uprawia na PC
# include <stdio.h> powa ne programowanie współbie ne. Po co? To proste. Wyobra
sobie Czytelniku, e masz procesor pracuj cy z cz stotliwo ci
void main() 25 MHz (to 25 MILIONÓW elementarnych operacji na sekund !).
{ Nawet, je li wzi pod uwag , e niektóre operacje (dodawanie,
char nazwapliku[40]; mno enie, itp.) wymagaj wielu cykli - i tak mo na w
union REGS inregs, outregs; uproszczeniu przyj , e Twój procesor mógłby wykona od
struct SREGS segregs; kilkuset tysi cy do kilku milionów operacji w ci gu sekundy.
Je li pracujesz np. z edytorem tekstu i piszesz jaki tekst -
printf("\nPodaj nazwe pliku: "); znacznie ponad 99% czasu Twój procesor czeka KOMPLETNIE
gets(nazwapliku); // gets() == GET String BEZCZYNNIE (!) na naci ni cie klawisza. Przecie Twój komputer
inregs.h.ah = 0x43; mogłby w tym samym czasie np. i formatowa dyskietk (dyskietka
inregs.h.al = 0x21;
68
te jest powolna), i przeprowadza kompilacj programu, i {
drukowa dokumenty, i przeprowadzi defragmentacj drugiego clrscr();
dysku logicznego, itp. itd.. proces1();
proces2();
Nawet taka pseudowspółbie no realizowana przez DOS, Windows, return 0;
czy sie jest ofert dostatecznie atrakcyjn , by warto było }
przyjrze si mechanizmom PSEUDO-współbie no ci w C i C++.
Współbie no procesów, mo e by realizowana na poziomie Ale tu nie ma adnej współbie no ci! Oczywi cie. Aby
zrealizowa współbie no musimy zadeklarowa bufor na bie cy
* sprz towym (architektura wieloprocesorowa), stan rejestrów i zastosowa funkcje setjmp():
* systemowym (np. Unix, OS/2),
* nakładki (np. sieciowej - time sharing, token passing) #include <setjmp.h>
* aplikacji (podział czasu procesora pomi dzy ró ne
funkcje/moduły tego samego pojedynczego programu). void proces1(void);
void proces2(void);
My zajmiemy si tu współbie no ci widzian z poziomu aplikacji.
jmp_buf bufor1;
Funkcje setjmp() (ang. SET JuMP buffer - ustaw bufor
umo liwiaj cy skok do innego procesu) i longjmp() (ang. LONG int main(void)
JuMP - długi skok - poza moduł) wchodz w skład standardu C i w {
zwi zku z tym zostały "przeniesine" do wszystkich kompilatorów clrscr();
C++ (nie tylko Borlanada). if(setjmp(bufor1) != 0) proces1(); //Powrót z procesu2 był?
proces2();
Porozmawiajmy o narz dziach. return 0;
}
Zaczniemy od klasycznego zestawu narz dzi oferowanego przez
Borlanda. Aby zapami ta stan przerwanego procesu stosowana jest Po wywołaniu funkcji setjmp() zostanie utworzony bufor1, w
którym zostanie zapami tany stan programu. Funkcja, jak zawsze
w C/C++ struktura PSS (ang. Program Status Structure) o nazwie przy pierwszym wywołaniu zwróci warto ZERO, wi c warunek
jmp_buf (JuMP BUFfer - bufor skoku). W przypadku współbie no ci
wielu procesów (wi cej ni dwa) stosuje si tablic zło on ze if(setjmp(bufor1) != 0) ...
struktur typu
nie b dzie spełniony i proces1() nie zostanie wywołany. Program
struct jmp_buf TablicaBuforow[n]; pójdzie sobie dalej i uruchomi proces2():

Struktura słu y do przechowywania informacji o stanie procesu void proces2(void)


(rejestrach procesora w danym momencie) i jest predefiniowana w {
pliku SETJMP.H: for(;;)
{
typedef struct gotoxy(10,20);
{ printf("PROCES 2: ");
unsigned j_sp, j_ss, j_flag, j_cs; for(int i = 1; i<40; i++)
unsigned j_ip, j_bp, j_di, j_es; {
unsigned j_si, j_ds; printf(".2\b");
} jmb_buf[1]; delay(5); //UWAGA: delay() tylko dla DOS!
}
Prototypy funkcji: longjmp(bufor1, 1); <--- wró
} ____________ t jedynk zwróci setjmp()
int setjmp(jmp_buf bufor); }
void longjmp(jmp_buf bufor, int liczba);
Proces 2 b dzie drukował "biegaj c dwójk " (zwolnion przez
W obu przypadkach jmp_buf bufor oznacza ten sam typ bufora opó nienie delay(5); o pi milisekund), poczym funkcja
(niekoniecznie ten sam bufor - mo e ich by wiele), natomiast longjmp() ka e wróci z procesu do programu głównego w to
int liczba oznacza tzw. return value - warto zwracan po miejsce:
powrocie z danego procesu. Liczba ta mo e zawiera informacj , z
int main(void)
którego procesu nast pił powrót (lub inn przydatn w {
programie), ale nie mo e by ZEREM. Je li funkcja longjmp() clrscr();
otrzyma argument int liczba == 0 - zwróci do programu warto 1. if(setjmp(bufor1)) proces1(); <--- tu powrót
proces2();
return 0;
Warto całkowita zwracana przez funkcj setjmp() przy pierwszym }

wywołaniu jest zawsze ZERO a przy nast pnych wywołaniach (po Zmieni si tylko tyle, e powtórnie wywołana funkcja setjmp()
powrocie z procesu) jest równa parametrowi "int liczba" zwróci tym razem warto 1, zatem warunek b dzie spełniony i
przekazanemu do ostatnio wywołanej funkcji longjmp(). rozpocznie si proces1():

Przyjrzyjmy si temu mechanizmowi w praktyce. Wyobra my sobie, void proces1(void)


e chcemy realizowa współbie nie dwa procesy - proces1 i {
proces2. Proces pierwszy b dzie na ladował w uproszczeniu while(kbhit())
wymieniony wy ej edytor tekstu - pozwoli na wprowadzanie tekstu, {
gotoxy(1,1);
który b dzie powtarzany na ekranie. Proces drugi b dzie printf("PROCES1, Pisz tekst: [Kropka - Koniec]");
przesuwał w dolnej cz ci ekranu swój numerek - cyferk 2 (tylko gotoxy(pozycja,2);
znak = getch();
po to, by było wida , e działa). Program główny wywołuj cy oba printf("%c", znak);
procesy powinien wygl da tak: pozycja++;
}
... if(znak == '.') exit (0);
void proces1(void); }
void proces2(void);
Proces 1 sprawdzi przy pomocy funkcji kbhit() czy w buforze
int main(void) klawiatury oczekuje znak (czy co napisałe ). Je li tak -
69
wydrukuje znak, je li nie - zako czy si i program przejdzie do
procesu drugiego. A oto program w cało ci: char znak;
int pozycja = 1;
[P075.CPP]
int main(void)
#include <stdio.h> {
#include <process.h> clrscr();
#include <setjmp.h> if(setjmp(bufor1)) proces1();
#include <conio.h> if(setjmp(bufor2)) proces2();
#include <dos.h> proces3();
return 0;
void proces1(void); }
void proces2(void);
void proces1(void)
jmp_buf bufor1, bufor2; {
while(kbhit())
char znak; {
int pozycja = 1; gotoxy(1,1);
printf("PROCES1, Pisz tekst: [Kropka - Koniec]");
int main(void) gotoxy(pozycja,2);
{ znak = getch();
clrscr(); printf("%c", znak);
if(setjmp(bufor1)) proces1(); pozycja++;
proces2(); }
return 0; if(znak == '.') exit (0);
} }

void proces1(void) void proces2(void)


{ {
while(kbhit()) for(;;)
{ {
gotoxy(1,1); gotoxy(10,20);
printf("PROCES1, Pisz tekst: [Kropka - Koniec]"); printf("PROCES 2: ");
gotoxy(pozycja,2); for(int i = 1; i<40; i++)
znak = getch(); {
printf("%c", znak); printf(".2\b");
pozycja++; delay(5);
} }
if(znak == '.') exit (0); longjmp(bufor1, 1);
}
}
void proces2(void) }
{
for(;;)
{ void proces3(void)
gotoxy(10,20); {
printf("PROCES 2: "); for(;;)
for(int i = 1; i<40; i++) {
{ gotoxy(10,23);
printf(".1\b"); printf("PROCES 3: ");
delay(5); for(int i = 1; i<40; i++)
} {
longjmp(bufor1,1); printf(".3\b");
} delay(2);
} }

[!!!] UWAGA longjmp(bufor2,2);


________________________________________________________________ }
Funkcja delay() u yta dla opó nienia i zwolnienia procesów }
b dzie funkcjonowa tylko w rodowisku DOS. Przy uruchamianiu
prykładowego programu pod Windows przy pomocy BCW nale y t Procesy odbywaj si z ró n pr dko ci . Kolejno uruchamiania
funkcj poprzedzi znakiem komentzrza // . procesów b dzie:
________________________________________________________________
- proces3()
- proces2()
- proces1()
Wyobra my sobie, e mamy trzy procesy. Przykład współbie no ci
trzech procesów oparty na tej samej zasadzie zawiera program Po uruchomieniu programu zauwa ysz, e proces pierwszy (pisania)
poni ej
został spowolniony. Mo na jednak temu zaradzi przez ustawienie
[P076.CPP] flag i priorytetów. Je li dla przykładu uwa amy, e pisanie jest

#include <stdio.h> wa niejsze, mo emy wykrywa zdarzenie - naci ni cie klawisza w


#include <process.h> ka dym z mniej wa nych procesów i przerywa wtedy procesy mniej
#include <setjmp.h> wa ne. Wprowadzanie tekstu w przykładzie poni ej nie b dzie
#include <conio.h> spowolnione przez pozostałe procesy.
#include <dos.h>
[P077.CPP]
void proces1(void);
void proces2(void); #include <stdio.h>
void proces3(void); #include <process.h>
#include <setjmp.h>
jmp_buf bufor1, bufor2; #include <conio.h>
70
#include <dos.h> powrocie z procesu identyfikowa - z którego procesu nast pił
powrót i podejmowa stosown decyzj np. przy pomocy instrukcji
void proces1(void); switch:
void proces2(void);
void proces3(void); switch(setjmp(bufor))
{
jmp_buf BuforStanu_1, BuforStanu_2; case 1 : proces2();
case 2 : proces3();
char znak; .....
int pozycja = 1; default : proces0();
}
int main(void)
{ [!!!]UWAGA
clrscr(); ________________________________________________________________
if(setjmp(BuforStanu_1)) proces1(); * Zmienne steruj ce przeł czaniem procesów powinny by zmiennymi
if(setjmp(BuforStanu_2)) proces2();
proces3(); globalnymi, b d statycznymi. Tak e dane, które nie mog ulec
return 0; nadpisaniu bezpieczniej potraktowa jako globalne.
} ________________________________________________________________

void proces1(void) W przypadku wielu procesów celowe jest utworzenie listy, b d


{ kolejki procesów. Przydatny do tego celu bywa mechanizm tzw.
while(kbhit()) "ła cuchowej referencji". W obiektach klasy PozycjaListy nale y
{ umie ci pole danych - struktur i pointer do nast pnego
gotoxy(1,1); procesu, któremu (zgodnie z ustalonym priorytetem) nale y
printf("PROCES1, Pisz tekst: [Kropka - Koniec]"); przekaza sterowanie:
gotoxy(pozycja,2);
znak = getch(); static jmp_buf Bufor[m]; <-- m - ilo procesów
printf("%c", znak); ...
pozycja++;
} class PozycjaListy
if(znak == '.') exit (0); {
public:
} jmp_buf Bufor[n]; <-- n - Nr procesu
PozycjaListy *nastepna;
void proces2(void) }
{
for(;;) Wyobra my sobie sytuacj odrobin ró n od powy szych przykładów
{
gotoxy(10,20); (w której zreszt para setjmp() - longjmp() równie cz sto
printf("PROCES 2: "); wyst puje.
for(int i = 1; i<40; i++)
{ #include <setjmp.h>
if(kbhit()) break;
printf(".2\b"); jmp_buf BuforStanu;
delay(5); int Nr_Bledu;
}
longjmp(BuforStanu_1, 1); int main(void)
{
} Nr_Bledu = setjmp(BuforStanu) <-- tu nast pi powrót
} if(Nr_Bledu == 0) <-- za pierwszym razem ZERO
{
/* PRZED powrotem z procesu (ów) */
void proces3(void) ....
{ Proces(); <-- Wywołanie procesu
for(;;) }
{ else
gotoxy(10,23); {
printf("PROCES 3: "); /* PO powrocie z procesu (ów) */
for(int i = 1; i<40; i++) ErrorHandler(); <-- obsługa bł dów
{ }
if(kbhit()) break; ....
printf(".3\b"); return 0;
delay(2); }
}
Taka struktura zapewnia działanie nast puj ce:
longjmp(BuforStanu_2,2);
} - Był powrót z procesu?
} NIE: Wywołujemy proces!
TAK: Obsługa bł dów, które wyst piły w trakcie procesu.
[!!!]UWAGA
________________________________________________________________ Je li teraz proces zaprojektujemy tak:
W pierwszych dwu przykładach trzymanie stale wci ni tego
klawisza spowoduje tylko automatyczn repetycj wprowadzanego void Proces()
znaku. W przykładzie trzecim spowoduje to przerwanie procesów 2 {
i 3, co b dzie wyra nie widoczne na monitorze (DOS). int Flaga_Error = 0;
Zwró uwag , e kbhit() nie zmienia stanu bufora klawiatury. ...
________________________________________________________________ /* Je li nast piły bł dy, flaga w trakcie pracy procesu jest
ustawiana na warto ró n do zera */

W bardziej rozbudowanych programach mo na w oparciu o drugi if(Error) Flaga_Error++;


parametr funkcji longjmp() zwracany przez funkcj setjmp(buf) po ...
if(Fllaga_Error != 0) longjmp(BuforStanu, Flaga_Error);
71
... T[i++] = i - 1; p(T[i-1]); cout << "\t" << i << "\n";
} T[i++] = i - 1; p(T[i-1]); cout << "\t" << i << "\n";
while (!kbhit());
proces przeka e sterowanie do programu w przypadku wyst pienia }
bł dów (jednocze nie z informacj o ilo ci/rodzaju bł dów).
return 0;
[Z] }
________________________________________________________________
1. Napisz samodzielnie program realizuj cy 2, 3, 4 procesy Aby nie spowodowa próby odwołania do nieistniej cego elementu
współbie ne. Je li chcesz, by jednym z procesów stał si tablicy, mo emy zadeklarowa tablic T[max + 1]. W przypadku,
całkowivie odr bny program - skorzystaj z funkcji grupy gdy max jest liczb nieparzyst , tablica wynikowa posiada
spawn...() umo liwiaj cych w C++ uruchamianie procesów parzyst liczb elementów. Je li natomiast max jest parzyste,
potomnych. tworzymy jeden zb dny element tablicy, który pó niej zostanie
u yty, ale kompilator ani program nie b dzie nam si "buntował".

Mo na spróbowa zast pi w programie bardziej czasochłonne


operacje - szybszymi. Dla przykładu, w p tli

for(i = 1; i <= 100; i++)


LEKCJA 22. NA ZDROWY CHŁOPSKI ROZUM PROGRAMISTY. {
________________________________________________________________ n = i * 10;
W trakcie tej lekcji dowiesz si : ...
* jak przyspiesza działanie programów w C++
* jakie dodatkowe narz dzia zyskujesz "przesiadaj c si " na mo na wyeliminowa czasochłonne mno enie np. tak:
nowoczesny kompilator C++
________________________________________________________________ for(i = 1, n = 10; i <= 100; i++, n += 10)
{
...
UNIKAJMY P TLI, które nie s NIEZB DNE !
lub wr cz wprost, je li dwie zmienne robocze nie s niezb dne:
Unikanie zb dnych p tli nazywa si fachowo "rozwini ciem p tli"
(ang. loop unrolling). Zwró uwag , e zast puj c p tl jej for(n = 10; n <= 1000; n += 10)
rozwini ciem (ang. in-line code): {
...
* zmniejszamy ilo oblicze ,
* zmniejszamy ilo zmiennych. Je li wiadomo, e jaka p tla powinna wykona si z definicji
cho by raz, warto wykorzystywa konstrukcj do...while, zamiast
Wyobra my sobie p tl : analizowa niepotrzebnie warunek.

for (i = 0; i < max; i++) Je li stosujemy w programie p tle zagnie d one (ang. nested
T[i] = i; loops), to p ta zorganizowana tak:

Je li "unowocze nimy" j tak: for(i = 1; i < 5; i++) (1)


for(j = 1; j < 1000; j++)
for (i = 0; i < max; ) { A[i][j] = i + j; }
{
T[i++] = i - 1; zadziała szybciej ni
T[i++] = i - 1;
} for(j = 1; j < 1000; j++) (2)
for(i = 1; i < 5; i++)
ilo powtórze p tli zmniejszy si dwukrotnie. Czai si tu { A[i][j] = i + j; }
jednak pewne niebezpiecze stwo: tablica mo e mie NIEPARZYST
liczb elementów. Np. dla 3-elementowej tablicy (max = 3) W przypadku (1) zmienna robocza p tli wewn trznej b dzie
nast piłyby w pierwszym cyklu operacje: inicjowana pi razy, a w przypadku (2) - tysi c (!) razy.

i = 0; Czasami zdarza si , e w programie mo na poł czy kilka p tli w


0 < 3 ? == TRUE --> T[0] = 0 // Tu nastepuje i++; // jedn .
T[1] = 1 itd...
for(i = 1; i < 5; i++)
To, co nast puje w tak "spreparowanej" tablicy mo esz TAB_1[i] = i;
prze ledzi uruchamiaj c program: ...
for(k = 0; k < 5; k++)
[P078.CPP] TAB_2[k] = k;

# include <iostream.h> Zmniejsza to i ilo zmiennych, i tekst programu i czas pracy


# include <stdio.h> komputera:
# include <conio.h>
TAB_2[0] = 0;
# define p(x) printf("%d\t", x) for(i = 1; i < 5; i++)
TAB_1[i] = i;
int T[99+1], i, max; TAB_2[i] = i;

main() Czasami wykonywanie p tli do ko ca pozbawione jest sensu.


{ Przerwa p tl w trakcie wykonywania mo na przy pomocy
cout << "\nPodaj ilosc elem. tablicy T[] - 2...99 \n"; instrukcji break (je li p tle s zagnie c one, cz sto lepiej
cin >> max; u y niepopularnego goto przerywaj cego nie jedn - a wszystkie
p tle). Stosuj c umiej tnie break, continue i goto mo esz
cout << "T[i]\t\ti\n\n"; zaoszcz dzi swojemu komputerowi wiele pracy i czasu. Rutynowym
"szkolno-strukturalnym" zap tlaniem programu
for (i = 0; i < max; )
{ main() {
char gotowe = 0;
72
... NIE MNÓ I NIE DZIEL BEZ POTRZEBY.
while (!gotowe)
{ Prawa MATEMATYKI pozostaj w mocy dla IBM PC i pozostan zawsze,
znak = wybrano_z_menu();
if (znak == 'q' || znak == 'Q') gotowe = 1; nawet dla zupełnie nieznanych nam komputerów, które skonstruuj
else nasze dzieci i wnuki. Znajomo praw de Morgana i zasad
....... arytmetyki jest dla programisty wiedz niezwykle przydatn . Jako
gotowe = 1;
} próbk zapiszmy kilka trywialnych to samo ci przetłumaczonych na

powodujesz cz sto zupełnie niepotrzebne dziesi tki operacji, C++:


które ju niczemu nie słu .
2 * a == a + a == a << 1
char gotowe; 16 * a == a << 4
main() { a * b + a * c == a * (b + c)
... ~a + ~b == ~(a + b)
while (!gotowe)
{ Mo naby jeszcze doda , e a / 2 == a >> 1, ale to nie zawsze
znak = wybrano_z_menu(); prawda. Przesuni cie w prawo liczb nieparzystych spowoduje
if (znak == 'q' || znak == 'Q') break; //Quit ! obci cie cz ci ułamkowej. W przypadku wyra e logicznych:
else
....... (x && y) || (x && z) == x && (y || z)
gotowe = 1; (x || y) && (x || z) == x || (y && z)
}
W arytmetycznej sumie i iloczynie NIE MA takiej symetrii.
Tym razem to, co nast puje po else zostanie pomini te.
!x && !y == !(x || y)
Wska niki działaj w C++ szybciej, ni indeksy, stosujmy je w !x || !y == !(x && y)
miar mo liwo ci w p tlach, przy manipulowaniu tablicami i w
funkcjach. Je li w skomplikowanych wyra eniach arytmetycznych i logicznych
zastosujemy zasady arytmetyki i logiki, zwykle staj si krótsze
INSTRUKCJE STERUJ CE I WYRA ENIA ARYTMETYCZNE.
i prostsze. Podobnie jak licz c na kartce, mo emy zastosowa
Na "chłopski rozum" programisty wiadomo, e na softwarowych zmienne pomocnicze do przechowywania cz sto powtarzaj cych si
rozstajach, czyli na rozgał zieniach programów wyra e składowych. Wyra enie
prawdopodobie stwo wyboru ka dwgo z wariantów działania programu
wynik = (x * x) + (x * x);
z reguły bywa ró ne. Kolejno sprawdzania wyra e warunkowych
nie jest zatem oboj tna. Wyobra my sobie lekarza, który mo emy przekształci do postaci
zwiezionego na toboganie narciarza pyta, czy kto w rodzinie
chorował na ółtaczk , koklusz, reumatyzm, podagr , itp. zamiast zm_pomocn = x * x;
wynik = zm_pomocn << 1;
zaj si najpierw wariantem najbardziej prawdopodobnym - czyli
zagipsowaniem nogi nieszcz nika. Absurdalne, prawda? Ale Cz sto napisane "na logik " wyra enia da si łatwo
przecie (uderzmy si w piersi) nasze programy czasami post puj zoptymalizowa . Jako przykład zastosujmy funkcj biblioteczn
strcmp() (string compare - porównaj ła cuchy znaków). Porównanie
w taki wła nie sposób...
ła cuchów
NAJPIERW TO, CO NAJBARDZIE PRAWDOPODOBNE I NAJPROSTSZE.
if (strcmp(string1, string2) == 0) cout << "identyczne";
Je li zmienna x w naszym programie mo e przyjmowa (równie else if (strcmp(string1, string2) < 0) cout << "krotszy";
prawdopodobne) warto ci 1, 2, 3, 4, 5, to "przesiew" else
cout << "dluzszy";
if (x >= 2) { ... }
else if (x == 1) { ... } mo na skróci tak, by funkcja strcmp() była wywoływana tylko
else { ... } raz:

oka e si w praktyce skuteczniejszy, ni wynik = strcmp(string1, string2);


if (wynik == 0)
if (x == 0) { ... } cout << "identyczne"; break;
else if (x == 1) { ... } else if (wynik < 0)
else { ... } cout << "krotszy";
else
Nale y pami ta , e w drabince if-else-if po spełnieniu cout << "dluzszy";
pierwszego warunku - nast pne nie b d ju analizowane.
Je li pracuj c nad programem nie b dziemy zapomina , e PC
Zasada ta stosuje si tak e do wyra e logicznych, w których operuje arytmetyk dwójkow , wiele operacji dzielenia i mno enia
stosuje si operatory logiczne || (lub) i && (i). W wyra eniach
tych, których ocen C++ prowadzi tylko do uzyskania pewno ci, (długich i pracochłonnych) b dziemy mogli zast pi operacjami
jaka b dzie warto logiczna (a nie koniecznie do ko ca przesuni cia w lewo, b d w prawo (ang. shift), które nasz PC
wyra enia) nale y zastosowa kolejno : wykonuje znacznie szybciej. Dla liczb całkowitych dodatnich

MAX || W1 || W2 || W3 ... x * 2 == x << 1; x * 4 == x << 2 itp. ....


MIN && W1 && W2 && W3 ...
[???] UWAGA:
gdzie MAX - oznacza opcj najbardziej prawdopodobn , a MIN - ________________________________________________________________
najmniej prawdopodobn . Takich skrótów nie mo na stosowa w stosunku do operandów typu
double, ani float.
Podobnie rzecz ma si z pracochłonno ci (zatem i ________________________________________________________________
czso-chłonno ci ) poszczególnych wariantów. Je li wariant
najprostszy oka e si prawdziwy, pozostałe mo liwo ci mo emy Podobnie w przypadku dzielenia przez pot g dwójki mo na
pomin . zast pi dzielenia znacznie szybsz operacj iloczynu
logicznego.
73
wynik = 6.28 * x;
x % 16 == x & 0xF;
co spowoduje zmniejszenie ilo ci operacji w ruchu programu. Aby
Je li w programie warto zmiennej powinna zmienia si w sposób ułatwi takie działanie kompilatora trzeba umie ci stałe obok
siebie.
piłokształtny (tj. cyklicznie wzrasta do MAXIMUM i po
osi gni ciu MAXIMUM spada do zera), najprostszym rozwi zaniem
jest
LEKCJA 23 - Co nowego w C++?
x = (x + 1) % (MAXIMUM + 1); ________________________________________________________________
Z tej lekcji dowiesz si , jakie mechanizmy C++ pozwalaj na
ale dzielenie trwa. Poni szy zapis spowoduje wygenerowanie kodu stosowanie nowoczesnego obiektowego i zdarzeniowego stylu
znacznie szybszego: programowania i co programy robi z pami ci .
________________________________________________________________
if (x == MAXIMUM) x = 0;
else x++; W porównaniu z klasycznym C - C++ posiada:

stosuj c zamiast if-else operator ? : mo emy to zapisa tak: * rozszerzony zestaw słów kluczowych (ang. keywords):
** nowe słowa kluczowe C++:
(x == MAXIMUM) ? (x = 0) : (x++);
class - klasa,
Mno enie jest zwykle troch szybsze ni dzielenie. Zapis delete - skasuj (dynamicznie utworzony obiekt),
friend - "zaprzyja nione" funkcje z dost pem do danych,
a = b / 10; inline - wpleciony (funkcje przeniesione w formie rozwini tej
do programu wynikowego),
mo na zatem zast pi szybszym: new - utwórz nowy obiekt,
operator - przyporz dkuj operatorowi nowe działanie,
a = b * .1; private - dane i funkcje prywatne klasy (obiektu), do których
zewn trzne funkcje nie maj prawa dost pu,
Je li mamy do czynienia ze stał STALA, to zapis w programie protected - dane i funkcje "chronione", dost pne z
ograniczeniami,
y = x / STALA; --> y = x * (1.0 / STALA); public - dane i funklcje publiczne, dost pne bez ogranicze ,
template - szablon,
z pozoru bzdurny spowoduje w wi kszo ci implementacji this - ten, pointer wskazuj cy bie cy obiekt,
wyznaczenie warto ci mno nika 1.0/STALA przez kompilator na virtual - funkcja wirtualna, abstrakcyjna, o zmiennym
etapie kompilacji programu (compile-time), a w ruchu (run-time) działaniu.
b dzie obliczany iloczyn zamiast ilorazu.
* nowe operatory (kilka przykładów ju widzieli my), np.:
W programach cz sto stosuje si flagi binarne (jest-nie ma). C++ << - wy lij do strumienia wyj ciowego,
>> - pobierz ze strumienia wej ciowego.
stosujemy jako flagi zmienne typu int lub char a w Windows BOOL. * nowe typy danych:
klasy,
Je li we miemy pod uwag fakt, e operatory relacji generuj obiekty,
warto ci typu TRUE/FALSE, typowy zapis: abstrakcyjne typy danych (ang. ADT).
* nowe zasady posługiwania si funkcjami:
if (a > b) funkcje o zmiennej liczbie argumentów,
Flaga = 1; funkcje "rozwijane" inline,
else funkcje wirtualne, itp.;
Flaga = 0;
Przede wszystkim (i od tego wła nie rozpoczniemy) zobaczymy
zast pimy krótszym funkcje o nowych mo liwo ciach.

Flaga = (a > b); ROZSZERZENIE C - FUNKCJE.

Taki krótszy zapis NIE ZAWSZE powoduje wygenerowanie szybszego Funkcje uzyskuj w C++ znacznie wi cej mo liwo ci. Przegl d
kodu. Jest to zale ne od specyfiki konkretnej implementacji. rozpoczniemy od sytuacji cz sto wyst puj cej w praktyce
Je li natomiast upro cisz swój program tak: programowania - wykorzystywania domy lnych (ang. default)
parametrów.
if (x > 1) a = 3; --> a = 3 * (x > 1);
else a = 0; FUNKCJE Z DOMY LNYMI ARGUMENTAMI.

spowoduje to wyra ne spowolnienie programu (mno enie trwa). Prototyp funkcji w C++ pozwala na podanie deklaracji domy lnych
warto ci argumentów funkcji. Je li w momencie wywołania funkcji
Kompilator C++ rozró nia dwa rodzaje wyra e : w programie jeden (lub wi cej) argument (ów) zostanie pomini te,

* general expressions - wyra enia ogólne - zawieraj ce zmienne i kompilator wstawi w puste miejsce domy ln warto argumentu.

wywołania funkcji, których warto ci nie jest w stanie okre li Aby uzyska taki efekt, prototyp funkcji powinien zosta
na etapie kompilacji i zadeklarowany w programie np. tak:
* constant expressions - wyra enia stałe, których warto mo na
wyznaczy na etapie kompilacji. void Funkcja(int = 7, float = 1.234);

Zapis Efekt takiego działania b dzie nast puj cy:

wynik = 2 * x * 3.14; Wywołanie w programie: Efekt:


________________________________________________________________
mo esz zatem przekształci do postaci
Funkcja(99, 5.127); Normalnie: Funkcja(99, 5.127);
wynik = 2 * 3.14 * x; Funkcja(99); Funkcja(99, 1.234);
Funkcja(); Funkcja(7, 1.234);
Kompilator przekształci to wyra enia na etapie kompilacji do ________________________________________________________________
postaci

74
[!!!] Argumentów mo e ubywa wył cznie kolejno. Sytuacja: {
int x = 22; //Zmienna lokalna funkcji main
Funkcja(5.127); // LE cout << ::x << " <-- To jest globalny ::x \n";
Funkcja(99); //DOBRZE cout << x << " <-- A to lokalny x \n";
daj_x();
jest w C++ niedopuszczalna. Kompilator potraktuje liczb 5.127
jako pierwszy argument typu int i wyst pi konflikt. return 0;
}
[P079.CPP]
void daj_x(void)
#include <iostream.h> {
cout << "To ja funkcja daj_x(): \n";
void fun_show(int = 1234, float = 222.00, long = 333L);
cout << ::x << " <-- To jest globalny ::x \n";
main() cout << x << " <-- A to lokalny x \n";
{
fun_show(); // Trzy arg. domyslne int x = 333;
fun_show(1); // Pierwszy parametr cout << "A to moja zmienna lokalna - automatyczna ! \n";
fun_show(11, 2.2); // Dwa parametry cout << x << " <-- tez x ";
fun_show(111, 2.22, 3L); // Trzy parametry }
return 0;
} Program wydrukuje tekst:

void fun_show(int X, float Y, long Z) 1 <-- To jest globalny ::x


{ 22 <-- A to lokalny x
cout << "\nX = " << X; To ja funkcja daj_x():
cout << ", Y = " << Y; 1 <-- To jest globalny ::x
cout << ", Z = " << Z; 1 <-- A to lokalny x
} A to moja zmienna lokalna - automatyczna !
333 <-- tez x
Uruchom program i przekonaj si , czy wstawianie argumentów
domy lnych przebiega poprawnie. Zwró uwag , e zmienne deklarowane wewn trz funkcji (tu:
main()) nie s widoczne dla innych funkcji (tu: daj_x()).
W KTÓRYM MIEJSCU UMIESZCZA DEKLARACJE ZMIENNYCH. Operator :: (ang. scope) pozwala nam wybiera pomi dzy zmiennymi

C++ pozwala deklarowa zmienne w dowolnym miejscu, z globalnymi a lokalnymi.


zastrze eniem, e deklaracja zmiennej musi nast pi przed jej
u yciem. Umieszczanie deklaracji zmiennych mo liwie blisko TYP WYLICZENIOWY enum JAKO ODR BNY TYP ZMIENNYCH.
miejsca ich u ycia znacznie poprawia czytelno (szczególnie
du ych "wieloekranowych") programów. Klasyczny sposób deklaracji W C++ od momentu zdefiniowania typu wyliczeniowego enum staje
si on równoprawnym ze wszystkimi innymi typem danych. Program
zmiennych: poni ej demonstruje przykład wykorzystania typu enum w C++.

int x, y, z; [P081.CPP]
...
main() # include <iostream.h>
{
... enum ciuchy
z = x + y + 1; {
... niewymowne = 1, skarpetka, trampek, koszula, marynarka,
} czapa, peruka, koniec
};
mo e zosta zast piony deklaracj w miejscu zastosowania (w tym
np. wewn trz p tli): main()
{
main() ciuchy n;
{ do
... {
for ( int i = 1; i <= 10; i++) cout << "\nNumer ciucha ? --> (1-7, 8 = quit): ";
cout << "Biezace i wynosi: " << i; cin >> (int) n;
...
} switch (n)
{
Nale y jednak pami ta o pewnym ograniczeniu. Zmienne case niewymowne: cout << "niewymowne";
deklarowane poza funkcj main() s traktowane jako zmienne break;
globalne i s widoczne (dost pne) dla wszystkich innych case skarpetka: cout << "skarpetka";
elementów programu. Zmienne deklarowane wewn trz bloku/funkcji break;
s zmiennymi lokalnymi i mog "przesłania " zmienne globalne. case trampek: cout << "trampek";
Je li wielu zmiennym nadamy te same nazwy-identyfikatory, mo emy break;
case koszula: cout << "koszula";
prze ledzi mechanim przesłaniania zmiennych w C++. W break;
przykładzie poni ej zastosowano trzy zmienne o tej samej nazwie case marynarka: cout << "marynarka";
"x": break;
case czapa: cout << "czapa";
[P080.CPP] break;
//Program demonstruje przesłanianie zmiennych case peruka: cout << "peruka";
break;
#include <iostream.h> case koniec: break;
default:
int x = 1; //Zmienna globalna cout << "??? Tego chyba nie nosze...";
void daj_x(void); //Prototyp funkcji }
} while (n != koniec);
main()
75
return 0; int n = rand() % 100;
} ...
________________________________________________________________
Zwró uwag w programie na forsowanie typu (int) przy pobraniu
odpowiedzi-wyboru z klawiatury. Poniewa w C++ "ciuchy" stanowi W programie przykładowym funkcje z STDLIB.H zostan skompilowane

nowy (zdefiniowany przed chwil ) typ danych, do uto samienia ich przez kompilator C. Okre lenie trybu kompilacji deklaracj
extern "C" jest umieszczane zwykle nie wewn trz programu
z typem int niezb dne jest wydanie takiego polecenia przy głównego a w doł czanych plikach nagłówkowych *.H. Jest to
pobieraniu danych ze strumienia cin >> . W opcjach pracy mo liwo szczególnie przydatne, je li dysponujesz bibliotekami
kompilatora mo esz wł czy /wył czy opcj "Treat enums as int" funkcji dla C a nie masz ch ci, czasu, b d mo liwo ci
(traktuj typ enum jak int) i wtedy pomin forsowanie typu w przerabiania ich na wersj przystosowan do wymaga C++. Drugi
programie. przykład poni ej zajmuje si sortowaniem krewnych przy pomocy
funkcji C qsort().
JEDNOCZESNE ZASTOSOWANIE DWU KOMPILATORÓW.
[P082.CPP]
Jak ju wspomnieli my wcze niej kompilator C++ składa si w
istocie z dwu ró nych kompilatorów: # include <iostream.h>
# include <stdlib.h>
* kompilatora C wywoływanego standardowo dla plików *.C, # include <string.h>
* kompilatora C++ wywoływanego standardowo dla plików *.CPP.
extern "C" int comp(const void*, const void*);
Oba kompilatory stosuj RÓ NE metody tworzenia nazw zewn trznych
main()
(ang. external names). Je li zatem program zawiera moduł, w {
którym funkcje zostały przekompilowane w trybie int max;
charakterystycznym dla klasycznego C - C++ powinien zosta o tym for(;;)
{
poinformowany. Dla przykładu, C++ cout << "\n Ilu krewnych chcesz posortowac? (1...6): ";
cin >> max;
* kategorycznie kontroluje zgodno typów argumentów, if( max > 0 && max < 7) break;
* na swój własny u ytek dodaje do nazw funkcji przyrostki (ang. cout << "\n Nic z tego...";
suffix) pozwalaj ce na okre lenie typu parametrów, }
* pozwala na tworzenie tzw. funkcji polimorficznych (kilka static char* krewni[] =
ró nych funkcji o tej samej nazwie), itp. {
"Balbina - ciotka",
Zwykły C tego nie potrafi i nie robi. Dlatego te do "Zenobiusz - kuzyn",
wprowadzenia takiego podziału kompetencji nale y czasem "Kleofas - stryjek",
zastosowa deklaracj extern "C". Funkcja rand() w programie "Ola - kuzynka (ach)",
poni ej generuje liczb losow . "Waleria - tez niby ciotka",
"Halina - stryjenka"
[P081.CPP] };

#include <iostream.h> qsort(krewni, 6, sizeof(char*), comp);

extern "C" for (int n = 0; n < max; n++)


{ cout << "\n" << krewni[n];
# include <stdlib.h> //Prototyp rand() w STDLIB.H
} return 0;
}
main()
{ extern "C"
cout << rand(); {
return 0; int comp(const void *x, const void *y)
} {
return strcmp(*(char **)x, *(char **)y);
GENERACJA LICZB LOSOWYCH. }
}
Kompilatory C++ umo liwoaj generacj liczb pseudolosowych
u ytecznych cz sto w obliczeniach statystycznych (np. metoda Program wykonuje nast puj ce czynno ci:
Monte Carlo) i emulacji "rozmytaj" arytmetyki i logiki
(ang.fuzzy math). * deklaruje prototyp funkcji typu C,
* deklaruje statyczn tablic wska ników do ła cuchów znakowych,
[!!!] UWAGA - Liczby PSEUDO-Losowe.
________________________________________________________________ * sortuje wska niki,
* wy wietla posortowane ła cuchy znakowe,
Funkcja rand() powoduje uruchomienie generatora liczb * definiuje funkcj comp() - porównaj,
pseudolosowych. Je li chcesz uzyska liczb pseudolosow z * wykorzystuje funkcj biblioteczn C - strcmp() - String
zadanego przedziału warto ci, najlepiej zastosuj dzielenie Compare do porównania ła cuchów znaków.
modulo:
O PAMI CI.
int n = rand % 10;
Program w C++ dzieli dost pn pami na kilka obszarów o
powoduje tzw. normalizacj . Reszta z dzielenia przez 10 mo e by okre lonym z góry przeznaczeniu. Dla zaawansowanego programisty
zrozumienie i efektywne wykorzystanie mechanizmów zarz dzania
wył cznie liczb z przedziału 0...9. pami ci w C++ mo e okaza si wiedz wielce przydatn .
Aby przy ka dym urichomieniu aplikacji ci g liczb pseudolosowych Zaczniemy, jak zwykle od "elementarza".

rozpoczynał si od innej warto ci nale y uruchomi generator CO PROGRAM ROBI Z PAMI CI .


liczb wcze niej - przed u yciem funkcji rand() - np.:
W klasycznym C najcz ciej stosowanymi do zarz dzania pami ci
randomize(); funkcjami s :
...
76
* malloc() - przyporz dkuj pami , do struktury Data zawieraj cej dat urodzenia mojej córki.
* farmalloc() - przyporz dkuj odległ pami ,
* realloc() - przyporz dkuj powtórnie (zmienion ) ilo pami ci, [P083.CPP]
* calloc() - przydziel pami i wyzeruj,
* free() - zwolnij pami . # include "iostream.h"

Pami dzielona jest w obszarze programu na nast puj ce bloki: struct Data
{
___________________ int dzien;
niskie adresy --> Ngłówek programu I. int miesiac;
Adres startowy int rok;
KOD: Kod programu };
___________________
Zmienne statyczne II. void main()
DANE: 1. Zainicjowane Zmienne globalne {
___________________ Data *pointer = new Data;
Zmienne statyczne III. /* Dekl. wskaznik do struct typu Data */
DANE: 2. Niezainicjowane Zmienne globalne /* Przydziel pamiec dla struktury */
___________________
STERTA: (heap) W miar potrzeby IV. pointer -> miesiac = 11; // pole "miesiac" = 11
ro nie w dół. pointer -> dzien = 3;
Tu operuj funkcje pointer -> rok = 1979;
malloc(), free().
___________________ cout << "\n URODZINY CORKI: ";
POLE NICZYJE: V. cout << pointer -> dzien << '.';
cout << pointer -> miesiac << ". ";
___________________ cout << "co rok ! od " << pointer -> rok << " r.";
W miar potrzeby VI.
STOS: (stack) ro nie w gór . delete pointer; //Skasuj wskaznik - zwolnij pamiec.
wysokie adresy --> ___________________ }

W obszarze kodu (I.) znajduj si instrukcje. Na stosie Program tworzy w pami ci (dokł. na stercie) struktur typu Data
przechowywane s : bez nazwy. O któr struktur chodzi i gdzie jej szuka w pami ci

* zmienne lokalne, wiemy dzi ki wska nikowi do struktury *pointer. Zapis


* argumenty przekazywane funkcji w momencie jej wywołania,
* adresy powrotne dla funkcji (RET == CS:IP). Data *pointer = new Data;

Na stercie natomiast przy pomocy funkcji (a jak przekonamy si oznacza jednoczesn deklaracj i zainicjowanie wska nika.
za chwil - tak e operatorów C++) mo emy przydziela pami dla
ró nych obiektów tworzonych w czasie pracy programu (ang. TWORZENIE DYNAMICZNYCH TABLIC O ZMIENNEJ WIELKO CI.
run-time memory allocation) - np. tworzy bufory dla ła cuchów,
tablic, struktur itp.. Zwró uwag , e obszar V. - POLE NICZYJE Je li mamy dane wył cznie jednego typu (tu: int), zastosowanie
mo e by w czasie pracy programu stopniowo udost pniany dla struktury jest wła ciwie przysłowiowym "strzelaniem z armaty do
stosu (który rozrasta si "w gór "), albo dla sterty (która wróbli". Trójelementowa tablica typu
rozrasta si "w dół"). W przykładowym programie poni ej podano,
w którym obszarze pami ci zostanie umieszczony dany element int TAB[3];
programu.
zupełnie nam wystarczy. Utworzymy j jednak nie jako tablic
# include <alloc.h> globaln (b d statyczn ) w obszarze pami ci danych, lecz
int a; // III. dynamicznie - na stercie.
int b = 6; // II.
[P084.CPP]
main()
{ # include "iostream.h"
char *Dane;
... main()
float lokalna; // VI. {
... int *pointer = new int[3]; // Przydziel pamiec
Dane = malloc(16); // IV.
... pointer[0] = 3; // Tabl_bez_nazwy[0] - dzien
} pointer[1] = 11; // Tabl_bez_nazwy[1] - miesiac
pointer[2] = 1979;
OPERATORY new I delete.
cout << "Data urodzenia: ";
Operatory new i delete działaj podobnie do pary funkcji for(int i = 0; i < 3; i++)
malloc() - free(). Pierwszy przyporz dkowuje - drugi zwalnia cout << pointer[i] << '.';
pami . Dokładniej rzecz bior c
delete pointer;
- operator new mo e zosta zastosowany wraz ze wska nikiem do }
bloku danych okre lonego typu:
* struktury danych, Uwa ny Czytelnik doszedł zapewne do wniosku, e skoro tablica
* tablicy, itp. (wkrótce zastosujemy go tak e w stosunku do tworzona jest dynamicznie w ruchu programu (run-time), to
klas i obiektów); kompilator nie musi zna na etapie kompilacji programu
- przyporz dkowuje pami blokowi danych; (compile-time) wielko ci tablicy! Id c dalej, program powinien
- przypisuje pocz kowy adres bloku pami ci wska nikowi. tak technik tworzy tablice o takiej wielko i, jakiej w ruchu

- operator delete zwalnia pami przyporz dkowan poprzednio za yczy sobie u ytkownik. Spróbujmy zrealizowa to praktycznie.
blokowi danych,
[P085.CPP]
Operatory new i delete mog współdziała z danymi wieloma typami
# include <conio.h>
danych (wcale nie tylko ze strukturami), jednak e rozpoczniemy # include <stdlib.h>
77
# include <iostream.h> qsort(pointer, i, sizeof(char *), Fporownaj);

for (i = 0; i < ilosc; i++)


void main() cout << pointer[i] << '\n';
{ for (i = 0; i < ilosc; i++)
for(;;) delete pointer[i];
{
cout << "\nPodaj wielkosc tablicy (1...100) --> "; delete pointer;
int i, size;
cin >> size; return 0;
/* Na stercie tworzymy dynamiczna tablica: */ }
int *pointer = new int[size];

/* Wypelniamy tablice liczbami naturalnymi: */ Tworzymy dynamicznie przy pomocy operatora new bezimienn
for (i = 0; i < size; i++) tablic składaj c si z tablic ni szego rz du (ła cuch znaków
pointer[i] = i; to te tablica tyle, e jednowymiarowa - ma tylko długo ).
cout << "\n TABLICA: \n"; Zwró uwag , e w C++ wska nik do wska nika (**pointer)
odpowiada konstrukcji "tablica składaj ca si z tablic". Aby
/* Sprawdzamy zawartosc tablicy: */ program uczyni bardziej pogl dowym spolszczymy nazwy funkcji
for (i = 0; i < size; i++) przy pomocy preprocesora.
cout << " " << pointer[i];
[P087.CPP]
char k = getch();
if(k == 'a') break; # define Fporown_string strcmp
delete pointer; # define Fkopiuj_string strcpy
} # define Fsortuj qsort
}
# include <stdlib.h>
Twój dialog z programem powinien wygl da nast puj co: # include <string.h>
# include <iostream.h>
Podaj wielkosc tablicy (1...100) --> 20
TABLICA:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 extern "C"
18 19 {
Podaj wielkosc tablicy (1...100) --> 100 int Fporownaj(const void* x, const void* y)
TABLICA: {
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 return (Fporown_string(*(char **)x, *(char **)y));
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
main()
67 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 cout << "Wpisz maksymalna ilosc imion --> ";

Skoro dynamiczne tablice o zmiennej wielko ci "chodz ", mo emy int ilosc, i;
wykorzysta to w bardziej interesuj cy sposób. cin >> ilosc;

[P086.CPP] char **pointer = new char *[ilosc];

# include <stdlib.h> for (i = 0; i < ilosc; i++)


# include <string.h> {
# include <iostream.h> cout << "Podaj imie Nr: " << i + 1 << "--> ";
char *imie = new char[80];
cin >> imie;
extern "C" if (Fporown_string(imie, "stop") == 0) break;
{ else
int Fporownaj(const void* x, const void* y) pointer[i] = new char[strlen(imie)+1];
{ Fkopiuj_string(pointer[i], imie);
return (strcmp(*(char **)x, *(char **)y)); delete imie;
} }
} /* w tym momencie i == ilosc */
Fsortuj(pointer, i, sizeof(char *), Fporownaj);
main()
{ for (i = 0; i < ilosc; i++)
cout << "Wpisz maksymalna ilosc imion --> "; cout << pointer[i] << '\n';
for (i = 0; i < ilosc; i++)
int ilosc, i; delete pointer[i];
cin >> ilosc;
delete pointer;
char **pointer = new char *[ilosc];
return 0;
for (i = 0; i < ilosc; i++) }
{
cout << "Podaj imie Nr: " << i + 1 << "--> "; Wska nik mo e wskazywa dane o ró nym stopniu zło ono ci:
char *imie = new char[80]; zmienn , tablic , struktur , obiekt (o czym za chwil ), ale mo e
cin >> imie;
if (strcmp(imie, "stop") == 0) break; wskazywa tak e funkcj .
else
pointer[i] = new char[strlen(imie)+1]; JE LI ZABRAKNIE PAMI CI - _new_handler.
strcpy(pointer[i], imie);
delete imie; Aby obsługiwa bł dn sytuacj - brakło pami ci na stercie -
} potrzebna nam b dzie funkcja - tzw. HANDLER. Aby jedna było
wiadomo, gdzie szuka handlera, powinni my operatorowi new
78
przekaza informacj jaka funkcja obsługuje brak pami ci i gdzie
# include <stdlib.h>
jej szuka . # include <iostream.h>

Mo emy podstawia na miejsce funkcji stosowanej w programie t static void Funkcja()


funkcj , która w danym momencie jest nam potrzebna. Jest to {
praktyka cz sto stosowana w programach obiekktowych, wi c cout << "\nTo ja ... Funkcja - handler \n";
przypomnijmy raz jeszcze przykładowy program - tym razem w cout << '\a' << " ! BRAK PAMIECI ! ";
troch innym kontek cie. Aby wskaza funkcj zastosujemy exit (1);
wska nik. . Przypomnijmy deklaracj }

double ( *Funkcja ) (double); extern void (*_new_handler)();


long suma; //Automatycznie suma = 0;
[P088.CPP]
void main()
#include <conio.h> {
#include <math.h> _new_handler = Funkcja; //Inicjujemy wskaznik
#include <iostream.h>
for(;;)
double Nasza_F(double); //Deklaracja zwyklej funkcji {
double (*Funkcja)(double); //pointer do funkcji char *pointer = new char[8192];
suma += 8192;
double liczba; //zwyczajna zmienna cout << "\nMam juz " << suma << " znakow w RAM\n";
int wybor; if (pointer != 0)
cout << "Pointer != NULL";
int main(void) }
{ }
clrscr();
cout << "\nPodaj Liczbe \n";
cin >> Liczba; [!!!] SPRAWD - KONIECZNIE!
cout << "CO OBLICZYC ?\n________________\n"; ________________________________________________________________
cout<<"1 - Sin \n2 - Cos \n3 - Odwrotnosc 1/X\n"; W programach u ytkowych, a szczególnie w tych oferowanych
klientom jako produkty o charakterze komercyjnym nale y ZAWSZE
switch(cin >> wybor) sprawdza poprawno wykonania newralgicznych operacji - a
{ szczególnie poprawno zarz dzania pami ci i poprawno
case 1: Funkcja = sin; break; operacji dyskowych. Utrata danych, lub nie zauwa one i nie
case 2: Funkcja = cos; break; wykryte przez program przekłamanie mo e spowodowa przykre
case 3: Funkcja = Nasza_F; break; skutki. Raz utracone dane mog okaza sie nie do odzyskania.
}
cout << "\n\nWYNIK = " << Funkcja(liczba);
return (0);
}
LEKCJA 24 : SK D WZI ŁY SI KLASY I OBIEKTY W C++.
double Nasza_F(double x) ________________________________________________________________
{
if (x != 0) W trakcie tej lekcji dowiesz si , sk d w C++ bior si obiekty i
x = 1/x; jak z nich korzysta .
else ________________________________________________________________
cout << "???\n";
return x;
} Zajmiemy si teraz tym, z czego C++ jest najbardziej znany -
zdolno ci posługiwania si obiektami. Główn zalet
Komputer nie jest "z gumy" i nie posiada dowolnie du ej programowania obiektowego jest wy szy stopie "modularyzacji"
"rozci gliwej" pami ci. Funkcja malloc(), je li pami ci programów. "Mudularyzacja" jest tu rozumiana jako mo liwo
zabraknie, zwraca pusty wska nik (ang. NULL pointer), co mo na podziału programu na niemal niezale ne fragmenty, które mog
łatwo przetestowa w programie. Je li natomiast stosujemy opracowywa ró ne osoby (grupy) i które pó niej bez konfliktów
operator new - konsekwentnie - operator new powinien zwraca mo na ł czy w cało i uruchamia natychmiast. C++ powstał, gdy
NULL (i próbowa dokona przypisania pointerowi zero). To te programy stały si bardzo (zbyt) długie. Mo liwo skrócenia
mo na sprawdzi w programie. programów nie jest jednak e jedyn zalet C++. W długich,
rozbudowanych programach trudno spami ta szczegóły dotycz ce
W C++ istnieje jednak równie inny, przydatny do tych celów wszystkich cz ci programu. Je li grupy danych i grupy funkcji
mechanizm. C++ dysponuje globalnym wska nikiem _new_handler uda si poł czy w moduły, do których mo na pó niej si ga , jak
(wska nik do funkcji obsługuj cej operator new, je li zabraknie do pewnej odr bnej cało ci, znacznie ułatwia to ycie
pami ci). Dzi ki istnieniu tego (predefiniowanego) wska nika programi cie. Na tym, w pewnym uproszczeniu, polega idea
mo emy przyporz dkowa "handler" - funkcj obsługuj c wyj cie programowania obiektowego.
przez operator new poza dost pn pami .
JAK STRUKTURY STAWAŁY SI OBIEKTAMI.
Dopóki nie za yczymy sobie inaczej, wska nik
W C++ struktury uzyskuj "troch wi cej praw" ni w klasycznym
_new_handler == NULL // NULL == 0 C. Przykładowy program poni ej demonstruje kilka sposobów
posługiwania si struktur w C++.
i operator new w przypadku niepowodzenia próby przyporz dkowania
[P90.CPP]
pami ci zwróci warto NULL inicjuj c pusty wska nik (innymi
słowy "wska nik do nik d"). Je li jednak #include <iostream.h>
_new_handler != NULL struct Data
{
to zawarto wska nika zostanie przez operator new uznana za int dzien;
adres startowy funkcji obsługi bł dnej sytuacji (ang. addres to int miesiac;
call). int rok;
};
[P089.CPP]
79
cout << " = ";
Data NaszaStruktura = {3, 11, 1979}; //Inicjujemy strukture cout << NStruktura.dzien << " . "
Data daty[16]; //Tablca struktur << NStruktura.miesiac << " . "
Data *p = daty; //Wskaznik do tablicy << NStruktura.rok;
void Fdrukuj(Data); //Prototyp funkcji
int i; //Licznik automat. 0 for (int i=0; i < 16; i++, NStruktura.rok++)
{
int main() cout << "\nDnia ";
{ NStruktura.Fdrukuj();
for (; i < 16; i++) cout << " Patrycja ";
{ if ( !i ) cout << "urodzila sie, wiek - ";
*(p + i) = NaszaStruktura; if (i > 0 && i < 14) cout << "miala ";
daty[i].rok += i; if (i > 13) cout << "bedzie miec ";
cout << "\nDnia "; cout << i;
Fdrukuj(daty[i]); if (i == 1) cout << " roczek";
cout << " Patrycja "; else cout << " lat";
if ( !i ) cout << "urodzila sie, wiek - "; if (i > 1 && i < 5) cout << "ka";
if (i > 0 && i < 14) cout << "miala "; cout << '.';
if (i > 13) cout << "bedzie miec "; }
cout << i; return 0;
if (i == 1) cout << " roczek"; }
else cout << " lat";
if (i > 1 && i < 5) cout << "ka"; Zwró uwag , e
cout << '.'; * odk d dane stały si elementem struktury, zacz li my odwoływa
}
return 0; si do nich tak:
} nazwa_struktury.nazwa_pola;
* gdy funkcje stały si elementem struktury, zacz li my
void Fdrukuj(Data Str) odwoływa si do nich tak:
{ nazwa_struktury.nazwa_funkcji;
char *mon[] =
{ Pojawiły si równie ró nice w sposobie definiowania funkcji:
"Stycznia","Lutego","Marca","Kwietnia","Maja","Czerwca",
"Lipca","Sierpnia","Wrzesnia","Pazdziernika","Listopada", void Data::Fdrukuj() //Definicja funkcji
"Grudnia" {
}; ...
cout << Str.dzien << ". " }
<< mon[Str.miesiac-1] << ". "
<< Str.rok; oznacza, e funkcja Fdrukuj() jest upowa niona do operowania na
} wewn trznych danych struktur typu Data i nie zwraca do programu
adnej warto ci (void). Natomiast zapis:
Prócz danych struktury w C++ mog zawiera tak e funkcje. W
przykładzie poni ej struktura Data zawiera wewn trz funkcj , Data::Data(void) //Poczatkowa data - Konstruktor
która przeznaczona jest do obsługi we wła ciwy sposób danych
wchodz cych w skład własnej struktury. oznacza, e funkcja Data(void) nie pobiera od programu adnych
parametrów i tworzy (w pami ci komputera) struktur typu Data.
[P091.CPP] Takie dziwne funkcje konstruuj ce (inicjuj ce) struktur (o czym

#include <iostream.h> dokładniej w dalszej cz ci ksi ki), nazywane w C++


konstruktorami nie zwracaj do programu adnej warto ci. Zwró
struct Data //Definicja struktury uwag , e konstruktory to specjalne funkcje, które:
{
int dzien, miesiac, rok; -- maj nazw identyczn z nazw typu własnej struktury,
void Fdrukuj(); //Prototyp funkcji -- nie posiadaj wyspecyfikowanego typu warto ci zwracanej do
Data(); //Konstruktor struktury programu,
}; -- słu do zainicjowania w pami ci pól struktury,
-- nie s wywoływane w programie w sposób jawny, lecz niejawnie,
void Data::Fdrukuj() //Definicja funkcji
{ automatycznie.
char *mon[] =
{ Podstawowym praktycznym efektem dodania do struktur funkcji
"Stycznia","Lutego","Marca","Kwietnia","Maja","Czerwca", stała si mo liwo skutecznej ochrony danych zawartych na
"Lipca","Sierpnia","Wrzesnia","Pazdziernika","Listopada", polach struktury przed dost pem funkcji z zewn trz struktury.
"Grudnia" Przed dodaniem do struktury jej własnych wewn trznych funkcji -
}; wszystkie funkcje pochodziły z zewn trz, wi c "hermetyzacja"
cout << dzien << ". " danych wewn trz była niewykonalna. Zasady dost pu okre la si w
<< mon[miesiac-1] << ". " C++ przy pomocy słów:
<< rok;
} public - publiczny, dost pny,
protected - chroniony, dost pny z ograniczeniami,
Data::Data(void) //Poczatkowa data - Konstruktor private - niedost pny spoza struktury.
{
dzien = 3; Przykładowy program poni ej demonstruje tzw. "hermetyzacj "
miesiac = 11; struktury (ang. encapsulation). W przykładzie poni ej:
rok = 1979;
} * definiujemy struktur ;
* definiujemy funkcje;
int main() * przekazujemy i pobieramy dane do/od struktury typu Zwierzak.
{
Data NStruktura; //Inicjujemy strukture Zmienna int schowek powinna sugerowa ukryt przez struktur i
niedost pn dla nieuprawnionych funkcji cz danych struktury a
cout << "\n Sprawdzamy: ";
NStruktura.Fdrukuj(); //Wywolanie funkcji nie cechy anatomiczne zwierzaka.
80
void SCHOWAJ(int Xwe); //Funkcje dostepne zzewnatrz
[STRUCT.CPP] int ODDAJ(void);
};
# include "iostream.h"
void Zwierzak::SCHOWAJ(int Xwe)
//UWAGA: schowek ma status private, jest niedostepny {
schowek = Xwe;
struct Zwierzak }
{
private: int Zwierzak::ODDAJ(void)
int schowek; //DANE PRYWATNE - niedostepne {
public: return (schowek);
void SCHOWAJ(int Xwe); //Funkcje dostepne zzewnatrz }
int ODDAJ(void);
}; main()
{
void Zwierzak::SCHOWAJ(int Xwe) //definicja funkcji Zwierzak Ciapek, Azor, Kotek; // obiekty klasy "Zwierzak"
{ int Piggy; // zwykla zmienna
schowek = Xwe;
} Ciapek.SCHOWAJ(1);
Azor.SCHOWAJ(22);
int Zwierzak::ODDAJ(void) Kotek.SCHOWAJ(-333);
{ Piggy = -4444;
return (schowek);
} cout << "Ciapek ma: " << Ciapek.ODDAJ() << "\n";
cout << "Azor ma: " << Azor.ODDAJ() << "\n";
main() cout << "Kotek ma: " << Kotek.ODDAJ() << "\n";
{ cout << "Panna Piggy ma: " << Piggy << "\n";
Zwierzak Ciapek, Azor, Kotek; // Struktury "Zwierzak"
int Piggy; // zwykla zmienna return 0;
}
Ciapek.SCHOWAJ(1);
Azor.SCHOWAJ(22); Kompilator nawet nie mrugn ł. Zmiana słowa struct na słowo class
Kotek.SCHOWAJ(-333);
Piggy = -4444; nie sprawiła mu zatem widocznie przykro ci. Mało tego, zwró
uwag , e długo wynikowego pliku STRUCT.EXE i CLASS.EXE jest
cout << "Ciapek ma: " << Ciapek.ODDAJ() << "\n"; IDENTYCZNA. Wynikałoby z tego, e sposób tworzenia wynikowego
cout << "Azor ma: " << Azor.ODDAJ() << "\n"; kodu przez kompilator w obu wypadkach był identyczny.
cout << "Kotek ma: " << Kotek.ODDAJ() << "\n";
cout << "Panna Piggy ma: " << Piggy << "\n"; O KLASACH I OBIEKTACH.

return 0; Klasy słu do tworzenia formalnego typu danych. W przypadku


} klas wiadomo jednak "z definicji", e b dzie to bardziej zło ony

// Proba nieautoryzowanego dostepu do danych prywatnych obiektu: typ (tzw. agregat) zawieraj cy praktycznie zawsze i dane
// cout << Ciapek.schowek; "tradycyjnych" typów i funkcje (nazywane "metodami"). Podobnie
// printf("%d", Ciapek.schowek); jak definiuj c struktur tworzysz nowy formalny typ danych, tak
// nie powiedzie sie i tu - definiuj c klas tworzysz nowy typ danych. Je li
zadeklarujesz u ycie zmiennych danego typu formalnego, takie
Powiedzie sie natomiast próba dost pu do "zwykłej" zmiennej - zmienne to wła nnie obiekty. Innymi słowy, klasy stanowi
dowoln metod - np.: definicje formalnego typu, natomiast obiekty - to zmienne danego

printf("%d", Piggy); //Prototyp ! # include <stdio.h> typu (danej klasy).

Je li podejmiesz prób odwołania si do "zakapsułkowanych" Zamiast słowa struct stosujemy przy klasach słowo class.
danych w zwykły sposób - np.:
class Klasa
cout << Ciapek.schowek; {
int prywatna_tab[80]
kompilator wy wietli komunikat o bł dzie: public:
int dane;
Error: 'Zwierzak::schowek' is not accessible in function main() void Inicjuj(void);
(pole schowek struktury typu Zwierzak (np. str. Ciapek) nie jest int Funkcja(int arg);
};
dost pne z wn trza funkcji main(). )
Nasza pierwsza wiadomie tworzona klasa nazywa si "Klasa" i
Do klas i obiektów ju tylko male ki kroczek. Jak przekonasz si stanowi nowy formalny typ zmiennych. Je li zadeklarujesz zmienn

za chwil - struktura Ciapek jest ju wła ciwie obiektem, a typ takiej klasy (tego typu formalnego), to taka zmienna b dzie
danych Zwierzak jest ju wła ciwie klas obiektów. Wystarczy wła nie OBIEKTEM.
zamieni słowo "struct" na słowo "class".
Nasza pierwsza prawdziwa Klasa zawiera dane:
[CLASS.CPP]
prywatna_tab[80] - prywatn tablic ;
# include "iostream.h" dane - publiczn dan prost typu int;
oraz funkcje:
//w klasach schowek ma status private AUTOMATYCZNIE Inicjuj() - zainicjuj - utwórz obiekt danej klasy w pami ci;
//slowo private stalo sie zbedne Funkcja() - jaka funkcja publiczna.

class Zwierzak Gdyby była to zwykła struktura, jej definicja w programie


{ wygl dałaby tak:
int schowek;
public: struct Klasa
81
{
private: main()
int prywatna_tab[80] {
public: ...
int dane; Klasa Obiekt;
void Inicjuj(void); ...
int Funkcja(int arg);
}; Przypiszemy elementom obiektu warto ci:

main()
Je eli w dalszej cz ci programu chcieliby my zastosowa {
struktury takiego typu, deklaracja tych struktur musiałaby ...
wygl da tak: Klasa Obiekt;
Obiekt.dane = 13;
struct rodzaj_struktur ...
{
private: Tak sam metod , jak stosowali my do danych - pól struktury,
int prywatna_tab[80] mo emy odwoływa si do danych i funkcji w klasach i obiektach.
public:
int dane; main()
void Inicjuj(void); {
int Funkcja(int arg); ...
} str1, str2, .... , nasza_struktura; Klasa Obiekt;
Obiekt.dane = 13; Obiekt.Funkcja(44);
b d tak: ...

struct rodzaj_struktur Przyporz dkowali my obiektowi nie tylko dane, ale tak e funkcje
{ poprzez umieszczenie prototypów funkcji wewn trz deklaracji
private: klasy:
int prywatna_tab[80]
public: class Klasa
int dane; {
void Inicjuj(void); ...
int Funkcja(int arg); public:
}; ...
... void Inicjuj(void) /* Prototypy funkcji */
(struct) rodzaj_struktur str1, str2, .... , nasza_struktura; int Funkcja(int argument);
};
Słowo kluczowe struct jest opcjonalne. Mogliby my wi c
zadeklarowa struktur w programie, wewn trz funkcji main(): [!!!] UWAGA!
________________________________________________________________
struct rodzaj_struktur W C++ nie mo emy zainicjowa danych wewn trz deklaracji klasy:
{
private: class Klasa
int prywatna_tab[80] {
public: private:
int dane; int prywatna_tab[80] = { 1, 2, ... }; // LE !
void Inicjuj(void); public:
int Funkcja(int arg); int dane = 123; // ŁE !
}; ...
________________________________________________________________
main()
{ Inicjowanie danych odbywa si w programie głównym przy pomocy
... przypisania (dane publiczne), b d za po rednictwem funkcji
struct rodzaj_struktur nasza_struktura; nale cej do danej klasy i maj cej dost p do wewn trznych danych
//lub równowa nie:
rodzaj_struktur nasza_struktura; klasy/obiektu (dane prywatne). Inicjowania danych mog dokona
tak e specjalne funkcje - tzw. konstruktory.
Do pól struktury mo emy odwoływa si przy pomocy operatora
kropki (ang. dot operator). Podobnie dzieje si w przypadku Dane znajduj ce si wewn trz deklaracji klasy mog mie status
klas. Je li zadeklarujemy zmienn typu Klasa, to ta zmienna public, private, b d protected. Dopóki nie za dasz inaczej -
b dzie naszym pierwszym obiektem. domy lnie wszystkie elementy klasy maj status private. Je eli
cz obiektu jest prywatna, to oznacza, e aden element
class Klasa programu spoza obiektu nie ma do niej dost pu. W naszej Klasie
{ prywatn cz stanowi tablica zło ona z liczb całkowitych:
int prywatna_tab[80]
public: (default - private:) int prywatna_tab[80];
int dane;
void Inicjuj(void) Do (prywatnych) elementów tablicy dost p mog uzyska tylko
int Funkcja(int our_param); funkcje zwi zane (ang. associated) z obiektem danej klasy.
} Obiekt; Funkcje takie musz zosta zadeklarowane wewn trz definicji
danej klasy i s nazywane członkami klasy - ang. member
Podobnie jak wy ej, mo emy zadeklarowa nasz obiekt wewn trz functions. Funkcje mog mie status private i sta si dzi ki
funkcji main(): temu wewn trznymi funkcjami danej klasy (a w konsekwencji
równie prywatnymi funkcjami obiektów danej klasy). Jest to
class Klasa jedna z najwa niejszych cech nowoczesnego stylu programowania w
{ C++. Na tym polega idea hermetyzacji danych i funkcji wewn trz
int prywatna_tab[80] klas i obiektów. Gdyby jednak cała zawarto (i dane i funkcje)
public: znajduj ce si w obiekcie zostały dokładnie "zakapsułkowane", to
int dane;
void Inicjuj(void) okazałoby si , e obiekt stał si " lepy i głuchy", a w
int Funkcja(int argument); konsekwencji - niedost pny i kompletnie nieu yteczny dla
}; programu i programisty. Po co nam obiekt, do którego nie mo emy
82
odwoła si z zewn trz adn metod ? W naszym obiekcie, w
dost pnej z zewn trz cz ci publicznej zadeklarowali my zmienn definicja powinna wygl da tak:
całkowit dane oraz dwie funkcje - Inicjuj() oraz Funkcja().
Je li dane i funkcje maj status public, to oznacza, e mo emy void Inicjuj(char x) //Deklaracja zmiennej znak.
si do nich odwoła z dowolnego miejsca programu i dowolnym {
sposobem. Takie odwołania przypominaj sposób odwoływania si do licznik.znak = x; //x - wewn trzna zmienna funkcji
licznik.ile = 0;
elementów struktury: }

main() Inicjuj c struktur licznik funkcja zeruje pole "ile" struktury.


{
... Przyda nam si jeszcze jedna funkcja PlusJeden(). Ta funkcja
Obiekt.dane = 5; //Przypisanie warto ci zmiennej. powinna zwi kszy zmienn słu c do zliczania ile razy wyst pił
Obiekt.Inicjuj(); //Wywołanie funkcji Inicjuj()
... interesuj cy nas znak po ka dym pojawieniu si odpowiedniego
Obiekt.Funkcja(3); //Wywołanie funkcji z argumentem znaku (w tym przypadku "A").

[!!!] ZAWSZE PUBLIC ! void PlusJeden(void) //Definicja funkcji


________________________________________________________________ { //incrementuj cej licznik
Dane zawarte w obiekcie, podobnie jak zwykłe zmienne wymagaj licznik.ile++;
zainicjowania. Funkcja inicjuj ca dane - zawarto obiektu musi }
zawsze posiada status public aby mogła by dost pna z zewn trz
i zosta wywołana w programie głównym - funkcji main(). Funkcje Zbudowali my licznik, który składa si z danych rozmieszczonych
i dane dost pne z zewn trz stanowi tzw. INTERFEJS OBIEKTU. na polach struktury oraz dwu stowarzyszonych ze struktur
funkcji. Je li spróbujemy zastosowa to w programie, gdzie:

char znak_we - znak wczytany z klawiatury;


LEKCJA 25: PRZYKŁAD OBIEKTU.
________________________________________________________________ program b dzie wygl da tak:
W trakcie tej lekcji dowiesz si , jak praktycznie projektuje si
klasy i obiekty. Twój pierwszy obiekt zacznie działa . void main()
________________________________________________________________ {
char znak_we;
Nasz pierwszy, do wiadczalny obiekt b dzie zlicza ile razy Inicjuj('A');
u ytkownik nacisn ł okre lony klawisz - np. liter "A". Najpierw
podejdziemy do problemu "klasycznie". Utworzymy struktur cout << "\nWpisz tekst zawierajacy litery A"
Licznik, któr mo na wykorzysta do przechowywania istotnych dla cout << "\nK - oznacza Koniec zliczania: ";
nas informacji:
for(;;) //Wczytujemy znaki
char znak - znak do zliczania {
int ile - ile razy wyst pił dany znak. cin >> znak_we;
if (znak_we == 'k' || znak_we == 'K') break;
Zwró uwag , e Licznik oznacza tu typ struktur (nowy formalny if(znak_we == licznik.znak) PlusJeden();
typ danych) a licznik oznacza nasz robocz zmienn danego typu. }
....
struct Licznik //Licznik - nowy typ struktur
{ W tek cie mog wyst pi zarówno du e jak i małe litery. Je li
public: //Status public jest domy lny dla struktur zechcemy zlicza i jedne i drugie, mo emy posłu y si funkcj
char znak; biblioteczn C zamieniaj c małe litery na du e - toupper().
int ile; Najpierw poddamy wczytany zank konwersji a nast pnie porównamy z
...
} licznik; //Zmienna typu "Licznik" "zadanym" na polu licznik.znak:

Do pól struktury licznik.znak i licznik.ile mo emy odwoływa si if(licznik.znak == toupper(znak_we)) PlusJeden();

w programie w nast puj cy sposób: Po przerwaniu p tli przez u ytkownika wystarczy sprawdzi jaka
warto jest wpisana w polu licznik.ile i mo emy wydrukowa
//Przypisanie (zainicjowanie pola struktury) wynik zliczania wyst pie litery 'A' we wprowadzonym tek cie.
licznik.znak = 'A';
cin >> licznik.znak; cout << "\nLitera " << licznik.znak
<< " wyst pila " << licznik.ile
//Odczyt (wyprowadzenie) bie . zawarto ci pola struktury. << " razy.";
cout << licznik.znak;
Program w cało ci b dzie wygl dał tak:
Potrzebna nam b dzie funkcja, przy pomocy której przeka emy do
struktury informacj , jaki znak powinien by zliczany. Nazwijmy [P092.CPP]
t funkcj Inicjuj(). Funkcja Inicjuj() powinna nam zainicjowa
pole struktury tzn. po przekazaniu jej jako argumentu tego # include <iostream.h>
znaku, który ma podlega zliczaniu, funkcja powinna "przenie " # include <ctype.h> //Prototyp f. toupper()
znak i zapisa go w polu licznik.znak naszej roboczej struktury.
struct Licznik
Wywołanie funkcji w programie powinno wygl da tak: {
char znak;
main() int ile;
{ } licznik;
....
Inicjuj('A'); void Inicjuj(char x)
.... {
//UWAGA: Nie tak: licznik.znak = x;
//licznik.Inicjuj() - funkcja jest zewn trzna ! licznik.ile = 0;
}
Aby funkcja inicjuj ca pole struktury zadziałała prawidłowo, jej
void PlusJeden(void)
83
{ oznacza dla C++, e funkcja jest członkiem klasy (ang. member
licznik.ile++; function). Logika C++ w tym przypadku wygl da tak:
}
* Prototypy funkcji nale y umie ci w definicji klasy.
void main() * Definicje funkcji mog znajdowa si w dowolnym miejscu
{ programu, poniewa operator przesłaniania :: pozwala rozpatrywa
char znak_we;
Inicjuj('A'); klas podobnie jak zmienne globalne.

cout << "\nWpisz tekst zawierajacy litery A"; * Wstawiaj c operator :: pomi dzy nazw klasy i prototyp funkcji
cout << "\nPierwzse wytapienie litery k lub K";
cout << "\n - oznacza Koniec zliczania: "; informujemy C++ e dana funkcja jest członkiem okre lonej klasy.

for(;;)
{ Funkcje - członkowie klas nazywane s cz sto METODAMI.
cin >> znak_we; Definicje klas i definicje funkcji - METOD s cz sto umieszczane
if (znak_we == 'k' || znak_we == 'K') break;
if(licznik.znak == toupper(znak_we)) PlusJeden(); razem - w plikach nagłówkowych. Je li posługujemy si tak
} metod , wystarczy doł czy odpowiedni plik dyrektyw # include.
Kompilator C++ skompiluje wtedy automatycznie wszystkie funkcje,
cout << "\nLitera " << licznik.znak
<< " wystapila " << licznik.ile które znajdzie w doł czonych plikach nagłówkowych.
<< " razy.";
} Mo emy przyst pi do utworzenia programu.

Je li dane i funkcje poł czymy w jedn cało - powstanie main()


obiekt. Zawarto naszego obiektu powinna wygl da tak: {
char znak_we; //Dekl. zwyklej zmiennej
Dane: Licznik licznik; //Deklarujemy obiekt klasy Licznik
char znak; licznik.Inicjuj('A'); //Inicjujemy licznik
int ile; ...
Funkcje:
void Inicjuj(char); Mo emy teraz okre li ilo wprowadzonych z klawiatury liter 'A'
void PlusJeden(void);
oraz 'a' i wyprowadzi j na ekran monitora. Pojawia si jednak
Ł czymy w cało funkcje operuj ce pewnymi danymi i te wła nnie
dane. Co wi cej, je li zaistniej takie funkcje, które nie b d pewien problem. Nie uda si si gn z zewn trz do prywatnych
wykorzystywane przez nikogo wi cej poza własnym obiektem i poza danych obiektu tak, jak poprzednio:
jego składnikami: funkcj Inicjuj() i funkcj PlusJeden(),
funkcje te nie musz by widoczne, ani dost pne dla reszty if(licznik.znak == toupper(znak_we)) ....
programu. Takie funkcje mog wraz z danymi zosta uznane za
prywatn cz obiektu. Takie praktyki, szczególnie w programach Potrzebna nam b dzuie jeszcze jedna metoda autoryzowana do
dost pu do danych obiektu:
przeznaczonych dla rodowiska Windows s uzasadnione i
po yteczne. Rozwa my obiekt, modularyzacj i hermetyzacj char Licznik::Pokaz(void);
obiektu na konkretnych przykładach.
która nie b dzie w momencie wywołania pobiera od programu
Zacznijmy od zdefiniowania klasy. adnych argumentów (void), natomiast pobierze znak z pola char
Licznik.znak i przeka e t informacj w postaci zmiennej typu
class Licznik char do programu. Definicja takiej metody powinna by
{ nast puj ca:
char znak;
int ile; char Licznik::Pokaz(void)
public: {
void Inicjuj(char); return znak;
void PlusJeden(void); }
};
Ten sam problem wyst pi przy próbie pobrania od obiektu efektów
Nast pny krok, to zdefiniowanie obu funkcji. Zwró uwag , e jego pracy - stanu pola licznik.ile. Do tego te niezb dna jest
funkcje nie s ju definiowane "niezale nie", lecz w stosunku do autoryzowana do dost pu metoda. Nazwiemy j Efekt():

własnej klasy: int Licznik::Efekt(void)


{
void Licznik::Inicjuj(char x) return ile;
{ }
znak = x;
ile = 0; Program w wersji obiektowej b dzie wygl da tak:
}
[P093.CPP]
void Licznik::PlusJeden(void)
{ # include <ctype.h>
ile++; # include <iostream.h>
}
class Licznik
Skoro funkcje widz ju wył cznie własn klas , zapis {
char znak;
licznik.znak mo e zosta uproszczony do --> znak int ile;
i public:
licznik.ile do --> ile void Inicjuj(char);
void PlusJeden(void);
Aby wskaza , e funkcje s członkami klasy Licznik stosujemy char Pokaz(void);
operator :: (oper. widoczno ci/przesłaniania - ang. scope int Efekt(void);
resolution operator). Taki sposób zapisu definicji funkcji };
84
void main() Zdefiniujmy nasz struktur w sposób bardziej
{ "klasowo-obiektowy":
char znak_we;
Licznik licznik; struct Licznik
licznik.Inicjuj('A'); {
private:
cout << "\nWpisz tekst zawierajacy litery A"; char znak;
cout << "\nPierwsze wytapienie litery k lub K"; int ile;
cout << "\n - oznacza Koniec zliczania: "; public:
void Inicjuj(char);
for(;;) void PlusJeden(void);
{ };
cin >> znak_we;
if (znak_we == 'k' || znak_we == 'K') break; Funkcja Inicjuj() wykonuje takie działanie jakie mo e wykona
if(licznik.Pokaz() == toupper(znak_we)) konstruktor struktury (obiektu), z t jednak ró nic , e
licznik.PlusJeden(); konstruktor jest wywoływany automatycznie. Je li wyposa ymy
} struktur Licznik w konstruktor, to funkcja Inicjuj() oka e si
zb dna. Aby funkcja Inicjuj() stała si konstruktorem, musimy
cout << "\nLitera " << licznik.Pokaz() zmieni jej nazw na nazw typu struktury, do której konstruktor
<< " wystapila " << licznik.Efekt()
<< " razy."; ma nale e . Zwró uwag , e konstruktor, w przeciwie stwie do
} innych, "zwykłych" funkcji nie ma podanego typu warto ci
zwracanej:
/* Definicje wszystkich funkcji: */
struct Licznik
void Licznik::Inicjuj(char x) {
{ private:
znak = x; char znak;
ile = 0; int ile;
} public:
Licznik(void); //Konstruktor nie pobiera argumentu
void Licznik::PlusJeden(void) void PlusJeden(void);
{ };
ile++;
} Teraz powinni my zdefiniowa konstruktor. Zrobimy to tak, jak
wcze niej definiowali my funkcj Inicjuj().
char Licznik::Pokaz(void)
{ Licznik::Licznik(void) //Konstruktor nie pobiera argumentu
return znak; {
} ile = 0;
}
int Licznik::Efekt(void)
{ Je li formalny typ struktur (klasa) posiada kostruktor, to po
return ile; rozpocz ciu programu i napotkaniu deklaracji struktur danego
} typu konstruktor zostanie wywołany automatycznie. Dzi ki temu
nie musimy "r cznie" inicjowa struktur na pocz tku programu.
Przejdziemy teraz do bardziej szczegółowego omówienia Jednak e nasz przykładowy konstruktor nie załatwia wszystkich
zasygnalizowanego wcze niej problemu inicjowania struktur w problemów - nie ustawia w strukturze zmiennej (pola) int znak -
pami ci przy pomocy funkcji o specjalnym przeznaczeniu - tzw. okre laj cego, który znak powinien by zliczany w liczniku. W
KONSTRUKTORÓW. tak zainicjowanej strukturze zmienna ile jest zerowana, ale
zawarto pola znak pozostaje przypadkowa. Niby wszystko w
LEKCJA 26: CO TO JEST KONSTRUKTOR. porz dku, ale wygl da to niesolidnie. Czy nie mo naby przekaza
________________________________________________________________ parametru przy pomocy konstruktora? Mo na! Konstruktor
W trakcie tej lekcji dowiesz si , w jaki sposób w pami ci "bezparametrowy"
komputera s tworzone obiekty.
________________________________________________________________ Licznik::Licznik(void)

taki, jak powy ej to tylko szczególny przypadek - tzw.


C++ zawiera specjaln kategori funkcji - konstruktory w celu konstruktor domy lny (ang. default constructor).
automatyzacji inicjowania struktur (i obiektów). Konstruktory to
specjalne funkcje b d ce członkami struktur (kategorii member PRZEKAZYWANIE ARGUMENTÓW DO KOSTRUKTORA.
functions) które s automatycznie wywoływane i dokonuj
zainicjowania struktury zgodnie z naszymi yczeniami, po Czasem chcemy zainicjowa now struktur ju z pewnymi
napotkaniu w programie pierwszej deklaracji struktury/obiektu ustawionymi parametrami. Te pocz tkowe parametry struktury
danego typu. mo emy przekaza jako argumenty konstruktora.

PRZYKŁADOWY KONSTRUKTOR. struct Licznik


{
Struktura Licznik zawiera funkcj inicjuj c obiekt (niech private:
obiekt b dzie na razie zmienn typu struktura): char znak;
int ile;
struct Licznik //Typ formalny struktur public:
{ Licznik(char); //Konstruktor z argumentem typu char
char znak; void PlusJeden(void);
int ile; };
} licznik; //Przykladowa struktura

void Inicjuj(char x) //Funkcja inicjuj ca Licznik::Licznik(char x) //Konstruktor z jednym argumentem


{ {
licznik.znak = x; ...
licznik.ile = 0; }
}
85
main() char znak_we;
{ cin >> znak_we;
Licznik licznik('A'); //Deklaracja struktury typu Licznik if (znak_we == 'k' || znak_we == 'K') break;
// oznacza to automatyczne wywołanie konstruktora z argumentem if(licznik.Pokaz() == toupper(znak_we))
.... licznik.PlusJeden();
}
Poniew nowy konstruktor pobiera od programu argument typu
znakowego char, wi c i definicj konstruktora nale y zmieni : cout << "\nLitera " << licznik.Pokaz()
<< " wystapila " << licznik.Efekt() << " razy.";
Licznik::Licznik(char x) //Konstruktor z jednym argumentem }
{
ile = 0; /* Definicje pozostałych funkcji: */
znak = x;
} void Licznik::PlusJeden(void) { ile++; }
char Licznik::Pokaz(void) { return (znak); }
Je li parametrów jest wi cej ni jeden, mo emy je przekaza do int Licznik::Efekt(void) { return (ile); }
konstruktora, a konstruktor wykorzysta je do zainicjowania
struktury w nast puj cy sposób: Po zamianie słowa kluczowego struct na class (licznik ze
struktury stanie si obiektem, a Licznik - z formalnego typu
struct Sasiedzi //s siedzi struktur - klas ) wystarczy w programie zlikwidowa zb dne słowo
{
private: "private" i wersja obiektowa programu jest gotowa do pracy.
char Tab_imion[4];
... [P095.CPP] /* Wersja z klas i obiektem */
public:
Sasiedzi(char *s1, char *s2, char *s3, char s4); # include <ctype.h>
... # include <iostream.h>
};
class Licznik
main() {
{ char znak;
Sasiedzi chopy("Helmut", "Ulrich", "Adolf", "Walter"); int ile;
.... public:
Licznik(char); //Konstruktor
Przekazanie konstruktorowi argumentów i w efekcie automatyczne void PlusJeden(void);
ustawiamie przez konstruktor paramatrów struktury ju w momencie char Pokaz(void);
int Efekt(void);
zadeklarowania struktury w programie rozwi zuje wiele problemów. };

W C++ istnieje jednak e pewne do istotne ograniczenie - nie Licznik::Licznik(char x) //Def. konstruktora
mo emy zadeklarowa tablicy zło onej z obiektów posiadaj cych {
konstruktory, chyba e wszystkie konstruktory s bezparametrowe znak = x;
(typu default constructors). ile = 0;
}
Udoskonalmy teraz nasz program zliczaj cy wyst pienia w tek cie
litery a posługuj c si konstruktorem struktury. void main()
{
[P094.CPP] /* Wersja ze struktur */ Licznik licznik('A'); //Zainicjowanie obiektu licznik

# include <ctype.h> cout << "Sprawdzamy: znak ile? " << "\n\t\t"
# include <iostream.h> << licznik.Pokaz() << "\t";
cout << licznik.Efekt();
struct Licznik
{ cout << "\nWpisz tekst zawierajacy litery A";
private: cout << "\nPierwsze wytapienie litery k lub K";
char znak; cout << "\n - oznacza Koniec zliczania: ";
int ile; for(;;)
public: {
Licznik(char); //Konstruktor char znak_we;
void PlusJeden(void); cin >> znak_we;
char Pokaz(void); if (znak_we == 'k' || znak_we == 'K') break;
int Efekt(void); if(licznik.Pokaz() == toupper(znak_we))
}; licznik.PlusJeden();
}
Licznik::Licznik(char x) //Def. konstruktora
{ cout << "\nLitera " << licznik.Pokaz()
znak = x; << " wystapila " << licznik.Efekt()
ile = 0; << " razy.";
} }

void main() void Licznik::PlusJeden(void) { ile++; }


{ char Licznik::Pokaz(void) { return znak; }
Licznik licznik('A'); //Zainicjowanie przez konstruktor int Licznik::Efekt(void) { return ile; }

cout << "Sprawdzamy: znak ile? " << "\n\t\t" Pora w tym miejscu zaznaczy , e C++ oferuje nam jeszcze jedno
<< licznik.Pokaz() << "\t"; specjalne narz dzie podobnej kategorii. Podobnie, jak do
cout << licznik.Efekt(); tworzenia (struktur) obiektów mo emy zastosowa konstruktor, tak

cout << "\nWpisz tekst zawierajacy litery A"; do skasowania obiektu mo emy zastosowa tzw. desruktor (ang.
cout << "\nPierwsze wytapienie litery k lub K"; destructor). Nazwy konstruktora i destruktora s identyczne z
cout << "\n - oznacza Koniec zliczania: "; nazw macie ystego typu struktur (macie ystej klasy), z tym, e
for(;;) nazwa destruktora poprzedzona jest znakiem "~" (tylda).
{
86
CO TO JEST DESTRUKTOR. destruktor zostanie wywołany automatycznie zawsze wtedy, gdy
obiekt przestanie by widoczny, istnienie destruktora w
Specjalna funkcja - destruktor (je li zadeklarujemy zastosowanie definicji typu struktur Stos pozwala na automatyczne wyzerowanie

takiej funkcji) jest wywoływana automatycznie, gdy program stosu. Deklarujemy destruktor podobnie do konstruktora, dodaj c
zako czy korzystanie z obiektu. Konstruktor towrzy, a destruktor przed nazw destruktora znak ~ (tylda):

(jak sama nazwa wskazuje) niszczy struktur (obiekt) i zwalnia struct Stos
przyporz dkowan pami . Przykład poni ej to program {
manipuluj cy stosem, rozbudowany tak, by zawierał i konstruktor ...
i destruktor struktury (obiektu). Zorganizujmy zarz dzanie public:
pami ci przeznaczon dla stosu w taki sposób: ...
~Stos(void);
struct Stos ...
{ }
private:
int *bufor_danych; Je li program zako czy si lub struktura przestanie by
int licznik; widoczna, zostanie wywołany destruktor struktury nasz_stos i
public: pami zostanie zwolniona. Praktycznie oznacza to, e mo emy
Stos(int ile_RAM); /* Konstruktor zwolni pami c przyporz dkowan strukturze w taki sposób:
int Pop(int *ze_stosu);
int Push(int na_stos); Stos::~Stos(void) //Definicja destruktora
}; {
free(bufor_danych);
gdzie: cout << "\n Destruktor: Struktury juz nie ma...";
*bufor_danych - wska nik do bufora (wypełniaj cego rol stosu), }
licznik - wierzchołek stosu, je li == -1, stos jest pusty.
Stos::Stos(...) - konstruktor inicjuj cy struktur typu Stos Od momentu zdefiniowania konstruktora i destruktora nie musimy
(lub obiekt klasy Stos), si ju przejmowa technicznymi szczegółami ich działania. W
ile_RAM - ilo pami ci potrzebna do poprawnego działanie stosu, dalszej cz ci programu destruktor i konstruktor b d wywoływane
*ze_stosu - wska nik do zmiennej, której nale y przypisa
warto zdj t wła nie ze stosu, automatycznie. Pozostaje nam pami ta , e
na_stos - liczba przeznaczona do zapisu na stos.
* stos mo e si nazywa dowolnie, a deklarujemy go tak:
Zajmijmy si teraz definicj konstruktora. Wywołuj c konstruktor
Stos nazwa_struktury;
w programie (deklaruj c u ycie w programie struktury typu Stos)
przeka emy mu jako argument ilo potrzebnej nam pami ci RAM w i dalej stosem mo emy posługiwa si przy pomocy funkcji:
bajtach. Do przyporz dkowznia pami ci na stercie dla naszego
stosu wykorzystamy funkcj malloc(). nazwa_struktury.Push()
nazwa_struktury.Pop()
Stos::Stos(int n_RAM) //Konstruktor - def.
{ Wszystkie wewn trzne sprawy stos b dzie załatwiał samodzielnie.
licznik = -1; W tym konkrertnym przypadku cz "prac organizacyjnych"
bufor_danych = (int *) malloc(n_RAM); zwi zanych z utworzeniem w pami ci struktury i zainicjowaniem
} pocz tkowych warto ci pól załatwi za nas konstruktor i
destruktor. Na tym wła nie polega idea nowoczesnego
Posługuj c si funkcj malloc() przyporz dkowujemy buforowi programowania w C++. Przykładowy program umieszcza liczby na
danych, w oparciu o który organizujemy nasz obiekt (na razie w stosie a nast pnie pobiera je ze stosu i drukuje na ekranie.
formie struktury) - stos 100 bajtów pami ci, co pozwala na Pełny tekst programu w wersji ze struktur - poni ej.
rozmieszczenie 50 liczb typu int (po 2 bajty ka da). Liczb
potrzebnych bajtów pami ci - 100 przekazujemy jako argument [P096.CPP]
konstruktorowi w momencie deklaracji struktury typu Stos. Nasza
struktura w programie b dzie si nazywa nasz_stos. # include <iostream.h>
# include <alloc.h>
main()
{ /* -----------------------poczatek pliku STOS.HPP------------ */
...
Stos nasz_stos(100);
... # define OK 1

Kiedy wykorzystamy nasz struktur w programie, mo emy zwolni struct Stos


pami przeznaczon dla struktury posługuj c si funkcj {
biblioteczn C free(). Przykład przydziału pami ci przy pomocy private:
pary operatorów new - delete ju był, przedstawimy tu zatem int *bufor_danych;
tradycyjn (coraz rzadziej stosowan metod ) opart na int licznik;
"klasycznych" funkcjach z biblioteki C. Funkcj free() posłu ymy public:
Stos(int); /* Konstruktor */
si w destruktorze struktury nasz_stos - ~Stos(). Destruktory s ~Stos(void); /* Destruktor */
int Pop(int*);
wywoływane automatycznie, gdy ko czy si działanie programu, lub int Push(int);
};
te , gdy struktura (obiekt) przestaje by widoczna / dost pna w
programie. Obiekt (struktura) przestaje by widoczny (podobnie Stos::Stos(int n_RAM) //Konstruktor - def.
ja zwykła zmienna lokalna/globalna), je li opuszczamy t {
funkcj , wewn trz której obiekt został zadeklarowany. Jest to licznik = -1;
wła ciwo bardzo wa na dla naszego przykładowego stosu. W bufor_danych = (int *) malloc(n_RAM);
naszym programie przykładowym pami przydzielona strukturze cout << "Konstruktor: Inicjuje strukture. ";
stack pozostaje zarezerwowana "na zawsze", nawet wtedy, gdy nasz }

stos przestaje by "widoczny" (ang. out of scope). Obiekt mo e Stos::~Stos(void) //Definicja destruktora
przesta by widoczny np. wtedy, gdy działa funkcja "nie {
widz ca" obiektu. Id c dalej tym torem rozumowania, je li free(bufor_danych);
87
cout << "\n Destruktor: Struktury juz nie ma..."; Stos::Stos(int n_RAM) //Konstruktor - def.
} {
licznik = -1;
bufor_danych = (int *) malloc(n_RAM);
int Stos::Pop(int* ze_stosu) cout << "Konstruktor: Inicjuje obiekt klasy Stos. ";
{ }
if(licznik == -1) return 0;
else *ze_stosu = bufor_danych[licznik--]; Stos::~Stos(void) //Definicja destruktora
return OK; {
} free(bufor_danych);
cout << "\n Destruktor: Obiektu juz nie ma...";
int Stos::Push(int na_stos) }
{
if(licznik >= 49) return 0; int Stos::Pop(int* ze_stosu)
else bufor_danych[++licznik] = na_stos; {
return OK; if(licznik == -1) return 0;
} else *ze_stosu = bufor_danych[licznik--];
/* --------------------------koniec pliku STOS.HPP----------- */ return OK;
}

void main() int Stos::Push(int na_stos)


{ {
Stos nasz_stos(100); //Dekl. struktury typu Stos if(licznik >= 49) return 0;
int i, Liczba; else bufor_danych[++licznik] = na_stos;
return OK;
cout << "\nZAPISUJE NA STOS LICZBY:\n"; }
/* ------------------------koniec pliku STOSCL.HPP----------- */
for(i = 0; i < 10; i++)
{
nasz_stos.Push(i + 100); void main()
cout << i + 100 << ", "; {
} Stos nasz_stos(100); //OBIEKT Klasy Stos
cout << "\nKoniec. \n"; int i, Liczba;
cout << "ODCZYTUJE ZE STOSU:\n";
for(i = 0; i < 10; i++) cout << "\nZAPISUJE NA STOS LICZBY:\n";
{
nasz_stos.Pop(&Liczba); for(i = 0; i < 10; i++)
cout << Liczba << ", "; {
} nasz_stos.Push(i + 100);
} cout << i + 100 << ", ";
}
cout << "\nKoniec. \n";
W C++ cz st praktyk jest umieszczanie tzw. implementacji cout << "ODCZYTUJE ZE STOSU:\n";
struktur (klas) w plikach nagłówkowych. Szkielet naszego for(i = 0; i < 10; i++)
programu mógłby wygl da wtedy tak: {
nasz_stos.Pop(&Liczba);
# include <iostram.h> cout << Liczba << ", ";
# include <alloc.h> }
# include <A:\STOS.HPP> }

void main() Struktury w robi si coraz bardziej podobne do czego nowego


{ jako ciowo, zmienia si równie (dzi ki tym nowym cechom) styl
... programowania.
}
[!!!] A CO Z UNIAMI ?
Wyka emy, e zamiana struktury na klas odb dzie si całkiem ________________________________________________________________
bezbole nie. Mało tego, je li dokonamy zmian w implementacji w Unie s w C++ traktowane podobnie jak struktury, z tym, e pola
pliku nagłówkowym (struct --> class i usuniemy słowo private) unii mog si nakłada (ang. overlap) i wobec tego nie wolno
nasz program główny nie zmieni si WCALE ! stosowa słowa kluczowego private w uniach. Wszystkie elementy
unii musz mie status public. Unie mog tak e posiada
Oto plik nagłówkowy A:\INCLUDE\STOSCL.HPP: konstruktory.
________________________________________________________________
[P097.CPP]
A JE LI B DZIE WI CEJ KLAS i STRUKTUR ?
# include <iostream.h>
# include <alloc.h> Po zdefiniowaniu nowego formalnego typu struktur mo esz
zastosowa w programie wiele zmiennych danego typu. We
/* ---------------------poczatek pliku STOSCL.HPP------------ */ wszystkich przykładach powy ej stosowano pojedyncz struktur
WYŁ CZNIE DLA ZACHOWANIA JASNO CI PRZYKŁADU. Mało tego.
W C++
# define OK 1 ró ne struktury mog korzysta z funkcji o tej samej nazwie W
RÓ NY SPOSÓB. Ta ciekawa zdolno nazywa si rozbudowywalno ci
class Stos funkcji (ang. overloading - dosł. "przeci anie"). Dokładniej
{ tym problemem zajmiemy si w cz ci po wi conej klasom i
int *bufor_danych; obiektom. Teraz jedynie prosty przykład na strukturach.
int licznik;
public: [P098.CPP]
Stos(int); /* Konstruktor */
~Stos(void); /* Destruktor */ #include <iostream.h>
int Pop(int*); #include <stdio.h>
int Push(int); #include <time.h>
};
struct Data
88
{ ________________________________________________________________
int miesiac, dzien, rok;
void Display(void); //Metoda "wyswietl" Dziedziczenie (ang inheritance) jest prób na ladowania w
}; technice programowania najcenniejszego bodaj wynalazku Matki
Natury - zdolno ci przekazywania cech. Je li wyobrazimy sobie
void Data::Display(void) typy struktur konik, lew, sło , czy krokodyl, to jest oczywiste,
{ e struktury te b d posiada wiele wspólnych cech. Wspólnymi
char *mon[] = cechami mog by zarówno wspólne dane (parametry) - np. nogi =
{ 4; jak i wspólne wykonywane przez nie funkcje - np. jedz(),
"Stycznia","Lutego","Marca","Kwietnia","Maja","Czerwca", pij(), oddychaj() itd.. Mog wyst powa oczywi cie i ró nice,
"Lipca","Sierpnia","Wrzesnia","Pazdziernika","Listopada", ale wiele danych i funkcji oka e si wspólnych.
"Grudnia"
}; LOGIKA DZIEDZICZENIA.
cout << dzien << ". "
<< mon[miesiac] << ". " Rozwijaj c dalej my l naszkicowan we wst pie, w kategoriach
<< rok; obiegowego j zyka naturalnego mo na rzec, e sło Trombalski
} byłby tu struktur typu formalnego Sło . Funkcjami wewn trznymi
słonia Trombalskiego i np. krokodyla Eugeniusza mogłyby by
struct Czas wspólne czynno ci tych struktur (lub obiektów):
{
int godz, minuty, sekundy; jedz()
void Display(void); // znow metoda "wyswietl" pij()
}; oddychaj()

void Czas::Display(void) Projektanci C++ wpadli na pomysł na ladowania mechanizmu


{ dziedziczenia. Zamiast tworzy te wszystkie struktury
char napis[20]; oddzielnie, mo emy zdefiniowa w C++ jeden ogólny typ struktur
(ang. generic structure), nazywany inaczej STRUKTUR BAZOW
sprintf(napis, "%d:%02d:%02d %s", (ang. base structure). Wszystkie wymienione wy ej struktury
(godz > 12 ? godz - 12 : (godz == 0 ? 12 : godz)), (sło , krokodyl, itp.) stałyby si wtedy strukturami pochodnymi
minuty, sekundy, (ang. derived structures). Nasza struktura bazowa mogłaby
godz < 12 ? "rano" : "wieczor"); nazywa si znów np. Zwierzak.
cout << napis;
} Poniewa niektóre funkcje s wspólne dla wszystkich struktur
(wszystkie Zwierzaki musz je , spa , itp.), mogliby my
main() przyj , e ka da struktura pochodna od bazowego typu Zwierzak
{ musi zawiera funkcje jedz(), spij() i oddychaj(). Je li
zdefiniujemy struktur bazow Zwierzak i zadeklarujemy w tej
time_t curtime = time(NULL); klasie funkcje jedz(), spij() i oddychaj(), mo emy spodziewa
struct tm tim = *localtime(&curtime); si , e struktura pochodna sło powinna odziedziczy funkcje -
cechy po strukturze bazowej Zwierzak. . Sło mo e oczywi cie
Czas teraz; mie i swoje odr bne cechy - dane i funkcje - np.:
Data dzis;
Slon.flaga_ssak
teraz.godz = tim.tm_hour; Slon.trabie()
teraz.minuty = tim.tm_min; Slon.tupie()
teraz.sekundy = tim.tm_sec;
dzis.miesiac = tim.tm_mon; "Gramatyka" C++ przy opisywaniu wzajemnego pokrewie stwa
dzis.dzien = tim.tm_mday; struktur (i klas) wygl da nast puj co:
dzis.rok = 1900 + tim.tm_year;
struct NazwaStrukturyPochodnej : NazwaStrukturyBazowej
cout << "\n Jest teraz --> "; {
teraz.Display(); private:
cout << " dnia "; Lista danych i funkcji prywatnych
dzis.Display(); cout << "\a"; public:
Lista danych i funkcji publicznych
return 0; } Lista struktur danego typu;
}
a dla klas i obiektów:
Funkcja Display() wywoływana jest w programie dwukrotnie przy
pomocy tej samej nazwy, ale za ka dym razem działa w inny class NazwaKlasyPochodnej : dost p NazwaKlasyBazowej
sposób. C++ bezbł dnie rozpoznaje, która wersja funkcji ma {
zosta zastosowana i w stosunku do której struktury (których Lista danych i funkcji prywatnych
danych) funkcja ma zadziała . public:
Lista danych i funkcji publicznych
Aby struktura stała si ju całkowicie klas , pozostało nam do } Lista obiektow danej klasy;
omówienia jeszcze kilka ciekawych nowych własno ci.
Najwa niejsz chyba (wła nie dlatego, e tworz c zdecydowanie Bazowy typ struktur w C++ wygl dałaby tak:
now jako w programowaniu) jest mo liwo dziedziczenia cech
(ang. inheritance), któr zajmiemy si w nast pnej lekcji. struct Zwierzak
{
[Z] void jedz();
________________________________________________________________ void spij();
1. Sprawd , czy zamiana struktur na klasy nie zmienia sposobu void oddychaj();
działania programów, ani długo ci kodów wynikowych. };
2. Opracuj program zliczaj cy wyst pienia ci gu znaków - np.
"as" we wprowadzanym tek cie. Je li chcemy zasygnalizowa , e pochodny typ struktur Slon ma
odziedziczy co po typie bazowym Zwierzak, musimy w definicji
klasy pochodnej poda nazw klasy bazowej (je li mamy
LEKCJA 27: O DZIEDZICZENIU. dziedziczy - nale y wskaza po kim):
________________________________________________________________
W trakcie tej lakcji dowiesz si na czym polega dziedziczenie. struct Slon : Zwierzak
{
89
int trabie(); Unie nie mog bra udziału w dziedziczeniu. Unia nie mo e by
int tupie(); ani typem bazowym ani typem pochodnym.
}; _______________________________________________________________

Przed nazw typu struktury (klasy) bazowej (tu: Zwierzak) mo e Program w cało ci b dzie wygl dał tak:
pojawi si słowo okre laj ce zasady dost pu do danych i funkcji
[P099.CPP]
(tu: public).
# include <iostream.h>
[!!!] RÓ NIE MO NA DZIEDZICZY ...
________________________________________________________________ struct Zwierzak
* Je li u yjemy w tym miejscu słowa public (przy strukturach {
domy lne), to atrybuty dost pu zostan odziedziczone wprost. int nogi;
Oznacza to, e to, co było prywatne w strukturze bazowej void jedz();
zostanie przeniesione jako prywatne do struktury pochodnej, a void spij();
to, co było publiczne w strukturze bazowej zostanie przeniesione void oddychaj();
};
jako publiczne do struktury pochodnej. void Zwierzak::jedz(void) { cout << "Jem conieco...\n"; }
* Je li natomiast u yjemy w tym miejscu słowa private, to void Zwierzak::spij(void) { cout << "Cosik mi sie sni...\n"; }
wszystko, co struktura pochodna odziedziczy po strukturze void Zwierzak::oddychaj(void) { cout << "Dysze ciezko...\n"; }
bazowej stanie si w strukturze pochodnej prywatne.
________________________________________________________________ struct Slon : Zwierzak
{
Opracowanie przykładowego programu ilustruj cego mechanizm int flaga_ssak;
dziedziczenia rozpoczniemy od zdefiniowania bazowego typu void trabi();
struktur i struktury pochodnej. void tupie();
};
struct Zwierzak
{ void Slon::trabi(void) { cout << "Tra-ta-ta...\n"; }
int nogi; <-- dane void Slon::tupie(void) { cout << "Kroczem...na wschod\n"; }

void jedz(); <-- funkcje void main()


void spij(); {
void oddychaj(); Slon Choleryk;
}; Choleryk.nogi = 4; Choleryk.flaga_ssak = 1;
cout << "\nNogi odziedziczylem: " << Choleryk.nogi;
struct Slon : Zwierzak cout << "\nA teraz kolejno funkcje: \n";
{ Choleryk.jedz();
int flaga_ssak; Choleryk.spij();
int trabie(); Choleryk.oddychaj();
int tupie(); Choleryk.trabi();
}; Choleryk.tupie();
if(Choleryk.flaga_ssak == 1) cout << "SSak!";
Zdefiniujemy teraz wszystkie funkcje nale ce do powy szych }
struktur. Funkcje b d tylko zgłasza si na ekranie napisem, by

prze ledzi kolejno ich wywołania.


LEKCJA 28: DZIEDZICZENIE ZŁO ONE.
void Zwierzak::jedz(void) { cout << "Jem conieco...\n"; } ________________________________________________________________
void Zwierzak::spij(void) { cout << "Cosik mi sie sni...\n"; } W trakcie tej lekcji dowiesz si , jak mo na odziedziczy wiele
void Zwierzak::oddychaj(void) { cout << "Dysz cie ko...\n"; } cech po wielu ró nych przodkach.
void Slon::trabi(void) { cout << "Tra-ta-ta...\n"; } ________________________________________________________________
void Slon::tupie(void) { cout << "Kroczem...na zachód\n"; }
Je li zechcemy dziedziczy dalej według schematu
Aby przekona si , co struktura typu Slon rzeczywi cie dziadek-ojciec-syn-wnuk...? Nic nie stoi na przeszkodzie. Przy
odziedziczy "po przodku", zredagujemy program główny. okazji zwró uwag , e nast pne pokolenia s coraz bardziej
zło one (tak by nie musi, ale mo e). W przykładzie poni ej
# include <iostream.h> dziedziczymy według schematu Punkt-Okr g-Elipsa.
...
void main() [P100.CPP]
{
Slon Choleryk; //Deklaracja struktury //Przyklad dziedziczenia "wielopokoleniowego"
...
cout << "\nNogi odziedziczylem: " << Choleryk.nogi; #include "stdio.h"
cout << "\nA teraz kolejno funkcje: \n"; #include "conio.h"
Choleryk.jedz();
Choleryk.spij(); struct punkt //BAZOWY typ struktur - punkt(x, y)
Choleryk.oddychaj(); {
Choleryk.trabi(); int x; //wspolrzedne punktu na ekranie
Choleryk.tupie(); int y;
} };

Mimo, e tworz c struktur Sło nie zadeklarowali my w jej struct kolo: punkt //Str. pochodna - kolo(x, y, R)
składzie ani funkcji jedz(), ani spij(), ani danych nogi, mo emy {
int promien; //wspolrzedne srodka x,y dziedziczymy
zastosowa funkcj Choleryk.jedz(), poniewa Choleryk };
odziedziczył t funkcj po strukturze bazowej Zwierzak. Dzi ki
dziedziczeniu mo emy posługiwa si danymi i funkcjami struct elipsa: kolo //dziedziczymy x,y i promien
nale cymi do obu typów struktur - bazowego: Zwierzak i {
pochodnego: Slon. int mniejszy_promien; //Str. pochodna elipsa(x, y, R, r)
};
[???] A CO Z UNIAMI ?
_______________________________________________________________ punkt P; //deklarujemy trzy struktury
90
kolo C;
elipsa E; [P102.CPP]

main() #include <iostream.h>


{
clrscr(); class Zwierzak //Klasa bazowa (base class)
{
P.x = C.x = E.x = 1; //Nadajemy wartosci polom struktur public:
P.y = C.y = E.y = 2; int nogi;

C.promien = E.promien = 4; void jedz();


E.mniejszy_promien = 3; void spij();
//Sprawdzamy zawartosc pol struktur void oddychaj();
printf("%d %d %d %d %d %d \n", };
P.x, C.x, E.x, P.y, C.y, E.y);
printf("%d %d %d", void Zwierzak::jedz(void) { cout << "Jem conieco...\n"; }
C.promien, E.promien, E.mniejszy_promien ); void Zwierzak::spij(void) { cout << "Cosik mi sie sni...\n"; }
getch(); void Zwierzak::oddychaj(void) { cout << "Dysze ciezko...\n"; }
return 0;
} class Slon : public Zwierzak
{
Mo na dziedziczy po wi cej ni jednym przodku tak e w inny public:
sposób. Kwadrat, dla przykładu, dziedziczy cechy po prostok tach int flaga_ssak;

i po rombach jednocze nie (jest jednocze nie szczególnym void trabi();


przypadkiem prostok ta i szczególnym przypadkiem rombu). Typ void tupie();
pochodny w tym wypadku, zamiast "dziadka" i "ojca" powinien mie };

DWU RÓ NYCH OJCÓW (!). W C++ takie dziedziczenie po dwu ró nych void Slon::trabi(void) { cout << "Tra-ta-ta...\n"; }
typach bazowych jednocze nie nazywa si DZIEDZICZENIEM void Slon::tupie(void) { cout << "Kroczem...na wschod\n"; }
WIELOBAZOWYM (ang. multi-base inheritance). A oto przykład
takiego dziedziczenia. void main()
{
[P101.CPP] Slon Obiekt;
/* obiekt Obiekt klasy Slon */
#include <iostream.h> Obiekt.nogi = 4; Obiekt.flaga_ssak = 1;
cout << "\nNogi odziedziczylem: " << Obiekt.nogi;
struct BAZOWA1 cout << "\nA teraz kolejno funkcje: \n";
{ //Struktura bazowa pierwsza Obiekt.jedz();
public: Obiekt.spij();
void Funkcja_a(void); Obiekt.oddychaj();
}; Obiekt.trabi();
Obiekt.tupie();
struct BAZOWA2 if(Obiekt.flaga_ssak) cout << "Jestem ssakiem !";
{ //Struktura bazowa druga }
public:
void Funkcja_b(void); Pami taj c o problemie domy lnego statusu członków
}; struktur/public i klas/private) mo emy przej do klas i
obiektów.
struct POCHODNA : BAZOWA1, BAZOWA2 //Lista "przodkow"
{ O KLASACH SZCZEGÓŁOWO.
public:
void Funkcja_c(void); Aby wykaza mo liwo modularyzacji programu zaprojektujemy
}; moduł w postaci pliku nagłówkowego. Moduł b dzie zawiera
definicj naszej prywatnej klasy obiektów ZNAK.
void BAZOWA1::Funkcja_a(void){cout << "To ja F_a().\n";}
void BAZOWA2::Funkcja_b(void){cout << "To ja F_b().\n";} Zaczynamy od danych, które b d nam potrzebne do tworzenia w
void POCHODNA::Funkcja_c(void){cout << "To ja F_c().\n";} programach (ró nych !) obiektów typu Znak.

void main() class ZNAK


{ {
POCHODNA dziecko; //Dekl. strukt. typu pochodnego char znak_dany; //Kod ASCII znaku
...
dziecko.Funkcja_a();
dziecko.Funkcja_b(); Aby obiekt został zainicjowany (tzn. wiedział jakim znakiem ma
dziecko.Funkcja_c(); by w danym programie) dodamy do definicji klasy
} jednoparametrowy konstruktor

Słowo public jest w strukturach zb dne. Zostało u yte wył cznie class ZNAK
z pobudek "dydaktycznych" - dla zwrócenia uwagi na status {
funkcji - członków struktury. char znak_dany;
public:
Zarówno pokole w schemacie dziadek-ojciec-syn, jak i struktur ZNAK(...);
(klas) bazowych w schemacie baza_1-baza_2-....-baza_n mo e by ...
wi cej ni 2.
Dane mog by prywatne, natomiast konstruktor i funkcje-metody
DZIEDZICZENIE KLAS. powinny by publiczne, by mo na było wywoływa je w programach.
Konstruktor b dziemy wywoływa w programach tak:
Oto "klasowo-obiektowa" wersja poprzedniego programu
przykładowego ze słonikiem Cholerykiem. Typy struktur Zwierzak i ZNAK Obiekt('a');

Slon nazwiemy klasami, (odpowiednio - klas bazow i klas Znaczy to: Utwórz w RAM obiekt klasy ZNAK pod nazw "Obiekt" i
pochodn ) a struktur Slon Choleryk nazwiemy obiektem. wytłumacz mu, e jest znakiem 'a'.
91
i zdefiniujmy te metody.
Konstruktor powinien pobiera od programu jeden argument typu
char i przekazywa go obiektowi klasy ZNAK na jego pole danych void ZNAK::Pokaz_sie(void)
znak_dany. Definicja konstruktora b dzie zatem wygl da tak: {
cout << znak_dany << '\a';
ZNAK::ZNAK(char x) }
{
znak_dany = x; void ZNAK::Znikaj(void)
} {
cout << "\b" << ' '; //'\b' == Back Space
Zakres dopuszczalnych znaków zaw zimy np. do kodów ASCII 65...90 }

(od A do Z). Je li u ytkownik "nie trafi", ustawimy zawsze "*" void ZNAK::Skacz(void)
(asterisk). Dodatkowo, dla "elegancji" zamienimy ewentualne małe {
for(int i = 0; i < 100; i++)
litery na du e. {
gotoxy(rand()%50, rand()%50);
ZNAK::ZNAK(char x) cout << znak_dany;
{ getch();
znak_dany = x; }
if(znak_dany < 65 || znak_dany >122) znak_dany = '*'; }
if(znak_dany > 97) znak_dany -= 32;
} Je li implementacj klasy ZNAK umie cimy w pliku nagłówkowym

A je li u ytkownik nie zechce poda adnego znaku i zda si na A:\ZNAK.H


domy lno obiektu? aden problem, wystarczy do klasy ZNAK doda
//_____________________________________________________________
bezparametrowy konstruktor domy lny. Konstruktory domy lne # include <stdlib.h>
spełniaj w C++ tak wła nie rol : # include <conio.h>
# include <iostream.h>
class ZNAK
{ class ZNAK
char znak_dany; {
public: char znak_dany;
ZNAK(char); //Konstruktor zwykly ("jednoznakowy")
ZNAK(void); //Konstruktor domy lny (bezparametrowy) public:
... ZNAK(char);
ZNAK();
Słowo void (tu opcjonalne) mo e nie wyst pi . Aby "kłuło w void Pokaz_sie();
oczy", który konstruktor jest konstruktorem domy lnym (ang. void Znikaj();
default konstructor), wi kszo programistów zapisuje to tak: void Skacz();
};
class ZNAK
{ ZNAK::ZNAK()
char znak_dany; {
public: znak_dany = 'X';
ZNAK(char); }
ZNAK(); //Z daleka wida , e nic nie ma !
... ZNAK::ZNAK(char x)
{
Definicja konstruktora bezparametrowego b dzie wygl da tak: znak_dany = x;
if(znak_dany < 65 && znak_dany >122) znak_dany = '*';
ZNAK::ZNAK() { znak_dany = 'X'; } if(znak_dany > 97) znak_dany -= 32;
}
W zale no ci od sposobu zadeklarowania obiektu w programie C++
wywoła automatycznie albo konstruktor ZNAK(char), albo void ZNAK::Pokaz_sie(void)
konstruktor domy lny ZNAK(): {
cout << znak_dany << '\a';
ZNAK obiekt; //Nie sprecyzowano jaki, konstruktor domy lny }
ZNAK obiekt('m'); //Wiadomo jaki, konstruktor jednoparametrowy
void ZNAK::Znikaj(void)
{
Dzi ki temu, e C++ "pedantycznie" sprawdza przed wywołaniem cout << "\b" << ' '; //'\b' == Back Space
funkcji zgodno typów argumentów przekazywanych do funkcji }
(konstruktor to te funkcja) i porównuje typ argumentów z
yczeniem programisty wyra onym w prototypie - bezbł dnie void ZNAK::Skacz(void)
rozpozna (mimo identycznej nazwy), któr funkcj nale y {
zastosowa . for(int i = 0; i < 100; i++)
{
Dodajmy do klasy ZNAK deklaracje (prototypy) funkcji-metod: gotoxy(rand()%50, rand()%50);
cout << znak_dany;
class ZNAK getch();
{ }
char znak_dany; }
//_____________ koniec pliku A:\INCLUDE\ZNAK.H _________________
public:
ZNAK(char);
ZNAK(); to nasz program mo e wygl da tak:
void Pokaz_sie();
void Znikaj(); [P103.CPP]
void Skacz();
}; # include <a:\znak.h>

92
void main() }
{
char litera; Ła cuch znaków jest widziany jako jednowymiarowa tablica
zawieraj ca dane typu znakowego, czyli w taki sposób:
clrscr();
cout << '\n' << "Podaj znak: "; char TABLICA[9] ={ "123456789" };
cin >> litera;
Definice powinny mie nast puj c posta :
ZNAK Obiekt(litera);
cout << "\nSTART" << "\n\n\n"; void KLASA::wydrukuj(char znak) {cout << znak;};
void KLASA::wydrukuj(int kodASCII) {cout << (char) kodASCII;};
getch(); void KLASA::wydrukuj(char *string) {cout << string;};
Obiekt.Pokaz_sie();
getch(); Zapis:
Obiekt.Znikaj();
getch(); cout << (char) kodASCII;
Obiekt.Skacz();
oznacza forsowanie typu - zamie typ int na typ char -
ZNAK Obiekt2; //To bedzie domyslny 'X' przyporz dkowanie kodowi ASCII - znaku. Wywołanie tej funkcji w
Obiekt2.Skacz(); programie mo e spowodowa ró ne działanie, w zale no ci od typu
} i ilo ci argumentów, z którym(i) funkcja zostaje wywołana.
Wywołania funkcji mog wygl da np. tak:
I tu ju wida pewne cechy nowoczesnego obiektowego stylu
programowania. Tym razem sprwdzenie, czy słowo class mo na KLASA Obiekt1, Obiekt2;
spokojnie zamieni na słowo struct pozostawim dociekliwym main() {
Czytelnikom. ...
Obiekt1.wydrukuj('A'); //Wydrukuje si litera A
Obiekt1.wydrukuj(99); //Wydrukuje si litera c
LEKCJA 29: FUNKCJE I OVERLOADING. Obiekt2.wydrukuj("napis"); //Wydrukuje si napis.
________________________________________________________________ ...
W trakcie tej lekcji dowiesz si , jak jeszcze w C++ mo na }
wykorzystywa funkcje.
________________________________________________________________ Taki sposób post powania umo liwia funkcjom wi ksz elastyczno

w C++ jedna funkcja mo e by definiowana wielokrotnie a ka da z i pozwala operowa bez konfliktów na ró nych rodzajach danych.
wersji funkcji mo e by przystosowana do obsługi innego typu
argumentów. C++ wybiera t wła ciw wersj funkcji J zyk C posiada funkcje słu ce do kopiowania ła cuchów
automatycznie. znakowych: strcpy() i strncpy(). Funkcja biblioteczna strncpy()
przerywa proces kopiowania po zako czeniu ła cucha ródłowego,
JEDNA NAZWA FUNKCJI - WIELE ZASTOSOWA . b d po skopiowaniu zadanej ilo ci znaków. Dzi ki mechanizmowi
overloadingu mo emy utworzy nasz własn funkcj
Overloading funkcji bywa czasem w podr cznikach dzielony na kopiuj_string(), która zale nie od sytuacji zadziała jak
odr bne zagadnienia: strcpy(), b d tak jak strncpy().

* funkcja mo e tolerowa ró n liczb argumentów (co dało si [P104.CPP]


spokojnie realizowa równie w klasycznym C - vide printf());
* funkcja mo e tolerowa ró ne typy argumentów; # include <iostream.h>
* funkcja mo e realizowa ró ne operacje dla ró nych
/* dwa porototypy - dwie wersje funkcji kopiuj_string() */
Wyobra my sobie, e mamy funkcj wydrukuj(), która potrafi /* source: destination: len: */
wysła na ekran otrzymany znak:
void kopiuj_string(char*, const char*); //Dwa argumenty
void wydrukuj(char znak) void kopiuj_string(char*, const char*, int); //a tu trzy
{
cout << znak; static char Piggie[20], Kermit[32];
}
main()
Tak zdefiniowan funkcj mo emy wywoła w programie w {
nast puj cy sposób: kopiuj_string(Piggie, "Panna Piggie");
kopiuj_string(Kermit, "Kermit - to protokul transmisji", 6);
wydrukuj('Z'); cout << Kermit << " oraz " << Piggie;

Czasem jednak wygodniej byłoby, gdyby nasza funkcja była return 0;


bardziej elastyczna i pozwalała na wykonanie szerszego zakresu }
operacji, np.:
void kopiuj_string(char *destin, const char *source)
wydrukuj('Z'); {
wydrukuj(75); // 75 to kod ASCII znaku, zamiast znaku bezpo r. while((*destin++ = *source++) != '\0') /* instr. pusta */ ;
}
wydrukuj("Wiecej niz znak - tekst");
void kopiuj_string(char *destin, const char *source, int len)
W klasycznym j zyku C wymaga to zdefiniowania nowej funkcji, {
natomiast w C++ to, e funkcja wydrukuj() została ju while (len && (*destin++ = *source++) != '\0') --len;
zdefiniowana w niczym nie przeszkadza. Poni ej definjujemy tak while (len--) *destin++ = '\0';
funkcj . }

... [S] Source- Destination.


class KLASA ________________________________________________________________
{ source - tu: ródłowy ła cuch znaków. Ogólnie - ródło. Typowy
public: skrót src.
void wydrukuj(char znak); destin - tu: ła cuch przeznaczenia. Ogólnie destination -
void wydrukuj(int kod_ASCII); miejsce przeznaczenia. Typowy skrót dest, dst, destin.
void wydrukuj(char *string); //wska nik do lancucha len - tu: długo .
93
________________________________________________________________ typu inline.
________________________________________________________________
O FUNKCJACH WPLECIONYCH - TYPU inline.
Status inline mo emy nada wszystkim trzem wersjom funkcji
Czsami zale y nam na przyspieszeniu działania programu wydrukuj() umieszczaj c definicje funkcji bezpo rednio wewn trz
obiektowego (zwykle kosztem zwi kszenia długo ci pliku). Je li w definicji klasy:

ródłowym tek cie programu nast puje wywołanie funkcji typu class Klasa
inline, to kompilator wstawia w to miejsce całe ciało funkcji {
(funkcje typu inline nie maj bezpo redniego ani wył cznego public:
odniesienia do obiektowego stylu programowania). Dla przykładu, inline void wydrukuj(char* a) { cout << a; }
je li nadaliby my naszej funkcji wydrukuj() status funkcji inline void wydrukuj(char z) { cout << z; }
inline, to fragment programu: inline void wydrukuj(int kod) { cout << (char) kod; }
};

obiekt.wydrukuj(65); //Kod ASCII W wi kszo ci przypadków daje to efekt pozytywny. Je li


definiujemy funkcje wewn trz klasy, s to zwykle funkcje o
zostałby zast piony wstawionym w to miejsce ciałem funkcji krótkim ciele.
wydrukuj():
OVERLOADING KONSTRUKTORÓW.
....
cout << (char) 65; W C++ mo emy podda overloadingowi tak e konstruktory.
....
UWAGA: destruktorów nie mo na podda overloadingowi.
Jest to skuteczna metoda przyspieszenia działania programów.
Je li chcemy zastosowa technik funkcji inline w stosunku do Overloading konstruktorów nie wyró nia si niczym specjalnym.
metod nale cych do danej klasy, powinni my u y słowa Wyobra my sobie, e tworzymy obiekt klasy Klasa o nazwie Obiekt.
kluczowego "inline" w definicjach funkcji. Zwró uwg , e w
samej definicji klasy słowo inline NIE POJAWIA SI : Je li chcemy, by konstruktor przy zakładaniu Obiektu przekazał
mu ła cuch znaków "zzzz", mo emy to zrobi na dwa sposoby. Raz
[P105.CPP] polecimy konstruktorowi przekaza do obiektu ła cuch znaków
"zzzz", a za drugim razem polecimy przekaza do obiektu
# include <iostream.h> czterokrotnie znak 'z':

class Klasa Obiekt("zzzz"); /* albo */ Obiekt('z', 4);


{
public: Je li w programie zadeklarujemy obiekt danej klasy, spowoduje to
void wydrukuj(char* tekst);
void wydrukuj(char Znak); automatyczne wywołanie konstruktora z parametrem podanym w
void wydrukuj(int KodASCII); momencie deklaracji obiektu.
};
class Klasa
inline void Klasa::wydrukuj(char* tekst) {
{ public:
cout << tekst; Klasa(char*);
} Klasa(char, int);
};
inline void Klasa::wydrukuj(char Znak)
{ Wersje konstruktora Klasa::Klasa() powinni my zdefiniowa tak:
cout << Znak;
} Klasa::Klasa(char *tekst) { cout << tekst; }

inline void Klasa::wydrukuj(int KodASCII) Klasa::Klasa(char Znak, ile = 4);


{ {
cout << (char) KodASCII; for(int i = 1; i < ile; i++)
} cout << Znak;
}
void main()
{ Dodajmy jeszcze jeden kontruktor domy lny. Konstruktory domy lne
Klasa Obiekt;
cout << "Obiekt wyprowadza dane: " << '\n'; działaj według zasady, któr w naturalnym j zyku dałoby si
Obiekt.wydrukuj(65); przekaza mniej wi cej tak: "dopóki nie zdecydowano inaczej...".
Obiekt.wydrukuj('B');
Obiekt.wydrukuj("C i juz"); Dopóki nie zdecydowano inaczej - obiekt otrzyma znak 'x'.
}
class Klasa
{
Wszystkie wersje funkcji wydrukuj() otrzymały status inline. public:
Oznacza to, e funkcje te nie b d w programie wywoływane lecz Klasa();
całe ciała funkcji zostan wstawione do programu w miejsca Klasa(char*);
wywoła . Jest to mechanizm podobny do wstawiania do programu Klasa(char, int);
makrorozkazów z t ró nic , e w przypadku funkcji inline C++ };
przeprowadza dodatkowo sprawdzenie zgodno ci typów argumentów ...
(ang. type checking). W naszym przypadku kompilator C++ wstawi Klasa::Klasa(void)
do programu ciało funkcji tyle razy, ile razy funkcja powinna {
zosta wywoływana. Zastosowanie funkcji inline jest opłacalne, cout << 'x';
je eli ciało funkcji jest stosunkowo krótkie. }

[!!!] A CZY NIE MO NA WEWN TRZ KLASY ? Praktyczne zastosowanie w programie b dzie wygl da tak:
________________________________________________________________
Mo na. Je li umie cimy pełn definicj funkcji wewn trz [P106.CPP]
definicji klasy, to taka funkcja staje si AUTOMATYCZNIE funkcj
# include <iostream.h>
94
okre lonego znaku w strumieniu znaków wej ciowych (wczytywanym z
class Klasa
{ klawiatury). Tablica b dzie si składa z MAX == 26 elementów -
public: obiektów - liczników, po jednym dla ka dej du ej litery
Klasa(); alfabetu. Tablica b dzie nazywa si TAB[26]. Po zadeklarowaniu:
Klasa(char*);
Klasa(char, int);
}; nazwa_klasy TAB[MAX];

Klasa::Klasa(void) kolejne obiekty b d si nazywa :


{
cout << 'x'; nazwa_klasy Obiekt1 == TAB[0]; //Licznik 1 - 'A'
} nazwa_klasy Obiekt2 == TAB[1]; //Licznik 2 - 'B'
... ...
Klasa::Klasa(char *tekst) nazwa_klasy ObiektN == TAB[N-1];
{
cout << tekst; Po wprowadzeniu znaku z klawiatury wywołamy wbudowan do ka dego
}
obiektu funkcj Skok_licznika(), która doda jedynk do
Klasa::Klasa(char Znak, int ile = 4) wewn trznego licznika obiektu. Wywołuj c funkcj zastosujemy
{ zamiast typowej składni
for(int i = 0; i < ile; i++) cout << Znak;
} ObiektK.Skok_licznika();

static char *p = "\nJestem Obiekt."; odpowiadaj c jej w tym wypadku notacj

void main() TAB[i].Skok_licznika();


{
Klasa Obiekt1; //Konstr. domy lny Powinni my jeszcze przed wywołaniem funkcji sprawdzi , czy znak
Klasa Obiekt2('A'); // ile - domyslnie == 4 jest du liter alfabetu. W przykładowym programie zrobimy to
Klasa Obiekt3('B', 3); tak:
Klasa Obiekt4(p);
} ...
cin >> znak; //Pobranie znaku z klawiatury
for(int i = 0; i < 26; i++)
{
LEKCJA 30: WYMIANA DANYCH MI DZY OBIEKTAMI. if(i == (znak - 'A')) TAB[i].Skok_licznika();
________________________________________________________________ }
...
W trakcie tej lekcji dowiesz si , jak mo na wymienia dane i
informacje pomi dzy ró nymi obiektami. Dzi ki temu wewn trzny licznik obiektu TAB[2] zostanie
________________________________________________________________ powi kszony tylko wtedy, gdy znak - 'A' == 2 (znak jest liter
C, bo 'C' - 'A' == 2).

Hermetyzacja danych jest cenn zdobycz , ale od czasu do czasu Mo na to zapisa skuteczniej.
obiekty powinny dokonywa pomi dzy sob wymiany informacji, ...
tak e tych wewn trznych - prywatnych. Ten problem mo e sprawia cin >> znak;
programi cie troch kłopotów - nale y zatem po wi ci mu troch TAB[znak - 'A'].Skok_licznika(); //Inkrementacja licznika
uwagi. ...

DOST P DO DANYCH PRZY POMOCY FUNKCJI KATEGORII friend. b d jeszcze krócej:

Aby wyja ni mechanizmy dost pu do danych obiektów b dziemy ...


potrzebowa : TAB[getch() - 'A'].Skok_licznika();
...
* wielu obiektów;
* danych prywatnych obiektów (dost p do publicznych, Istnieje tu wszak e niebezpiecze stwo próby odwołania si do
"niezakapsułkowanych" danych jest prosty i oczywisty); nieistniej cego elementu tablicy, przed czym powinni my si
* funkcji o specjalnych uprawnieniach. wystrzega .

Takie funkcje o specjalnych uprawnieniach - z mo liwo ci W wyniku działania programu otrzymamy zliczon ilo
odwoływania si do prywatnych danych wielu obiektów (a nie tylko wyst powania danej litery w strumieniu znaków wej ciowych.

swojego) musz w C++ posiada status "friend" (ang. friend - [P107.CPP]


przyjaciel).
# include <ctype.h> //prototyp toupper()
Nasz przykładowy program b dzie operował tablic zło on z # include <iostream.h>
obiektów klasy Licznik.
class Licznik
class Licznik {
{ char moja_litera;
char moja_litera; int ile;
int ile; public:
public: void Inicjuj(char);
void Inicjuj_licznik(char); void Skok_licznika();
void Skok_licznika(void); void Pokazuj();
void Pokazuj(); };
};
void Licznik::Inicjuj(char z)
... {
Licznik TAB[MAX]; moja_litera = z;
ile = 0;
Obiekty - liczniki b d zlicza wyst pienie (ka dy swojego) }
95
zsumowa zawarto pól
void Licznik::Skok_licznika(void)
{ TAB[i].ile
ile++;
} dla wszystkich obiektów (od i = 0 a do i = MAX). Zwró uwag ,
e definiuj c funkcj Suma() nie stosujemy powtórnie słowa
void Licznik::Pokazuj(void) kluczowego friend. A oto definicja:
{
cout << "Znak " << moja_litera << " wystapil " int Suma(int ilosc_obiektow)
<< ile << " razy" << '\n'; {
} int i, suma = 0;
main() for(i = 0; i < ilosc_obiektow; i++)
{ suma += TAB[i].ile;
const MAX = 26;
Licznik TAB[MAX]; return (suma);
register int i; }

/* inicjujemy liczniki: -------------------------------*/ Dzi ki zastosowaniu słowa "friend", funkcja Suma() jest
zaprzyja niona ze wszystkimi 26 obiektami, poniewa wszystkie
for(i = 0; i < MAX; i++) obiekty nale do tej klasy, w której zadeklarowali my funkcj :
{
TAB[i].Inicjuj('A' + i); class ...
} {
/* pracujemy - zliczamy: -------------------------------*/ ...
friend int Suma(...);
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n'; ...
for(;;) } ... ;
{ char znak;
cin >> znak; Tablica TAB[MAX] zło ona z obiektów klasy Licznik została
if(znak == '.') break; zadeklarowana nazewn trz funkcji main() ma wi c status tablicy
for(i = 0; i < MAX; i++) GLOBALNEJ. Funkcja Suma() ma dost p do prywatnych danych
{ wszystkich obiektów, mo emy wi c zastosowa j w programie w
if(i == (znak - 'A')) TAB[i].Skok_licznika(); nast puj cy sposób:
}
} [P108.CPP]
/* sprawdzamy: ----------------------------------------*/
# include <ctype.h>
char sprawdzamy; # include <iostream.h>
cout << '\n' << "Podaj znak do sprawdzenia: " << '\n';
cin >> sprawdzamy; class Licznik
cout << "Wyswietlam wyniki zliczania: \n"; {
TAB[toupper(sprawdzamy) - 'A'].Pokazuj(); char moja_litera;
int ile;
return 0; public:
} void Inicjuj(char);
void Skok_licznika();
Je li chcieliby my zliczy ilo wszystkich wprowadzonych void Pokazuj();
znaków, powinni my zsumowa dane pobrane od wielu obiektów. friend int Suma(int);
}
Je li dane przechowywane w obiektach maj status danych const MAX = 26;
prywatnych, to dost p do tych danych mo e by utrudniony. Do Licznik TAB[MAX];
tego momentu dost p do danych prywatnych obiektu mogli my register int i;
uzyska tylko posługuj c si autoryzowan do tego metod -
własn funkcj wewn trzn tego obiektu. Ale wtedy nie mieli my main()
dost pu do danych innych obiektów a tylko do jednego - {
"własnego" obiektu funkcji. Je li zatem chcieliby my zsumowa /* inicjujemy liczniki: -------------------------------*/
zawarto ci wielu obiektów - liczników, to nale y do tego
zastosowa tzw. funkcj "zaprzyja nion " - friend function. for(i = 0; i < MAX; i++)
Je li deklaruj c funkcj zastosujemy słowo kluczowe friend, to {
taka zaprzyja niona z klas funkcja uzyska prawo dost pu do TAB[i].Inicjuj('A' + i);
prywatnych elementów danej klasy. Zadeklarujemy tak przykładow }
/* pracujemy - zliczamy: -------------------------------*/
zaprzyja nion funkcj o nazwie Suma(). Funkcja b dzie pobiera
jako parametr ilo obiektów do zsumowania i sumowa zawarto ci cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';
wewn trznych liczników obiektów. for(;;)
{ char znak;
const MAX = 26; cin >> znak;
if(znak == '.') break;
class Licznik for(i = 0; i < MAX; i++)
{ {
char moja_litera; if(i == (znak - 'A')) TAB[i].Skok_licznika();
int ile; }
public: }
void Inicjuj(char); /* sprawdzamy: ----------------------------------------*/
void Skok_licznika();
void Pokazuj(); char sprawdzamy;
friend int Suma(int); cout << '\n' << "Podaj znak do sprawdzenia: " << '\n';
} TAB[MAX]; cin >> sprawdzamy;
cout << "Wyswietlam wyniki zliczania: \n";
Zadeklarowana w taki sposób zaprzyja niona funkcja ma prawo TAB[toupper(sprawdzamy) - 'A'].Pokazuj();
dost pu do prywatnych elementów wszystkich obiektów klasy
Licznik. Typowe zastosowanie funkcji typu friend polega wła nie cout << "\n Wszystkich liter bylo " << Suma(MAX);
na dost pie do danych wielu ró nych obiektów. Powinni my
96
return 0;
} static int TAB[] = {31,28,31,30,31,30,31,31,30,31,30,31};

void Licznik::Inicjuj(char zn) /* ---- funkcja - metoda konwersji - definicja ----------- */


{
moja_litera = zn; Data1::operator TEZ_DATA(void)
ile = 0; {
} TEZ_DATA DT_Obiekt(0, rok);
for (int i = 0; i < mc-1; i++)
void Licznik::Skok_licznika(void) { ile++; } DT_Obiekt.dz += TAB[i];
DT_Obiekt.dz += dz;
void Licznik::Pokazuj(void) return DT_Obiekt;
{ }
cout << "Znak " << moja_litera << " wystapil "
<< ile << " razy" << '\n'; main()
} {
Data1 dt_Obiekt(11,17,89);
int Suma(int ilosc_obiektow) TEZ_DATA DT_Obiekt;
{ DT_Obiekt = dt_Obiekt;
int i, suma = 0; DT_Obiekt.Pokazuj();
for(i = 0; i < ilosc_obiektow; i++)
suma += TAB[i].ile; return 0;
}
return (suma);
} Zaprzyja nione s klasy Data1 i TEZ_DATA. Dzi ki temu metody
zadeklarowane wewn trz zaprzyja nionej klasy Data1 maj dost p
Tak działa funkcja typu friend. Zwró my tu uwag , e funkcja do prywatnych danych obiektów klasy TEZ_DATA. Poniewa klasa to
taka nie jest traktowana dokładnie tak samo, jak metoda nowy formalny typ danych, a obiekt to dane takiego nowego typu,
wchodz ca w skład klasy i obiektu. Metoda, czyli "własna" nic nie stoi na przeszkodzie, by obiekty przekazywa do funkcji
funkcja obiektu odwołuje si do jego pola (danych) w taki jako argumenty (tak jak wcze niej obiekty typów typowych - int,
sposób: float itp.).

void Licznik::Skok_licznika(void) W C++ mamy jeszcze jedn metod wymiany danych. Mo emy nada
{ elementom klas i obiektów status static (statyczny).
ile++; //Wiadomo o ktory obiekt chodzi
} WYMIANA INFORMACJI PRZY POMOCY DANYCH STATYCZNYCH.

Funkcja klasy friend odwołuje si do pól obiektów tak: Je li element klasy został zadeklarowany jako element statyczny
(przy pomocy słowa kluczowego static), to bez wzgl du na to jak
int Suma(int liczba) wiele obiektów danej klasy utworzymy, w pami ci b dzie istnie
{ TYLKO JEDEN EGZEMPLARZ (kopia) tego elementu. W przykładowym
... programie z obiektami-licznikami mo emy osi gn c taki efekt
suma += TAB[i].ile; nadaj c zmiennej ile (stan licznika) status static int ile:
/* - wymaga dodatkowo wskazania, o który obiekt chodzi - */
} class Licznik
{
Nale y pami ta , e dla funkcji kategorii friend wszystkie char moja_litera;
obiekty nale ce do danej klasy maj status public - s static int ile;
dost pne. ...
};
O ZAPRZYJA NIONYCH KLASACH.
Je li utworzymy wiele obiektów takiej klasy, to wszystkie te
W C++ mog by zaprzyja nione ze sob wzajemnie tak e klasy. obiekty b d posługiwa si t sam (wspóln !) zmienn ile. Dla
Pozwala to metodom zdefiniowanym wewn trz jednej z klas na przykładu, je li zechcemy zlicza ile razy w strumieniu danych
dost p do prywatnych danych obiektów innych klas. W przypadku wej ciowych pojawiły si np. znaki 'a' , 'b' i 'c', mo emy
zaprzyja nionych klas słowem kluczowym friend poprzedzamy nazw utworzy trzy obiekty - liczniki: licznik_a, licznik_b i
klasy (a nie ka dej zaprzyja nionej metody z osobna, cho licznik_c. wszystkie te liczniki b d posługiwa si wspóln
zamierzony skutek wła nie na tym polega). Oto praktyczny zmienn statyczn ile:
przykład zaprzyja nionych klas.
class Licznik
[P109.CPP] {
public:
# include <iostream.h> char moja_litera;
static int ile;
class Data1; //Deklaracja (a nie definicja!) klasy Licznik(char); //Konstruktor
...
class TEZ_DATA };
{
int dz, rok; Do zainicjownia obiektów posłu ymy si konstruktorem. Deklaracja
public:
TEZ_DATA() {} obiektu spowoduje automatyczne wywołanie kostruktora i
TEZ_DATA(int d, int y) { dz = d; rok = y;} zainicjowanie obiektu w pami ci. Przy okazji przekazujemy
void Pokazuj() {cout << '\n' << rok << '-' << dz;} obiektom znaki do zliczania.
friend Data1; //"zaprzyjazniona" klasa
}; Licznik licznik_a('a'), licznik_b('b'), licznik_c('c');

class Data1 //Tu DEFINICJA klasy Je li teraz w strumieniu wej ciowym pojawi si która z
{ interesuj cych nas liter (a, b, b d c), zostanie wywołana
int mc, dz, rok; wła ciwa wersja metody Skok_licznika():
public:
Data1(int m, int d, int y) { mc = m; dz = d; rok = y; } int main(void)
operator TEZ_DATA(); {
}; char litera;
97
... }
cin >> litera;
... void Licznik::Skok_licznika(void)
if(litera == licznik_a.moja_litera) licznik_a.Skok_licznika(); {
ile++;
if(litera == licznik_b.moja_litera) licznik_b.Skok_licznika(); }

... void Licznik::Pokazuj(void)


} {
cout << "Znak " << moja_litera << " wystapil "
Zmienna ile jest zmienn statyczn , wi c wsztstkie trzy funkcje << ile << " razy" << '\n';
dokonaj inkrementacji zmiennej znajduj cej si pod tym samym }
fizycznym adresem pami ci. Je li dla wszystkich obiektów danej
klasy jaka zmienna oznacza zawarto tego samego adresu Tym razem Twój dialog z programem mo e wygl da np. tak:
pami ci, mo emy si odwoła do tej zmiennej równie tak:
C:\>program
nazwa_klasy::nazwa_zmiennej Wpisz ciag zankow zakonczony kropka [.]
aaa bbb cccc qwertyQWERTYPOLIPOLIpijesz? nie ojojojojoj.
Ten sposób mo na jednak e stosowa wył cznie wobec statycznych Wyswietlam wyniki zliczania:
elementów klasy o statusie danych publicznych. Je li s to dane Znak a wystapil 10 razy
prywatne nie mo na jeszcze dodatkowo zapomina o hermetyzacji i Znak b wystapil 10 razy
zasadach dost pu. Je eli pole danej klasy jest polem statycznym, Znak c wystapil 10 razy

mo emy do niego odwoływa si na dwa sposoby. Za po rednictwem Jak wida , program si myli. Wszystkie funkcje wy wietlaj
obiektów w taki sposób: (odwołuj si do) zawarto ci tego samego wspólnego pola.

identyfikator_obiektu.identyfikator_pola Charakter (status) statyczny mo emy nada równie funkcji


(metodzie) nale cej do danej klasy. Je li funkcja otrzyma
A za po rednictwem nazwy klasy (podobnie jak do zmiennych status static, w pami ci b dzie istnie tylko jeden egzemplarz
globalnych), tak metod : danej funkcji i do takiej funkcji mo na b dzie odwoływa si
podobnie jak do zmiennej statycznej posługuj c si nazw obiektu
identyfikator_klasy::identyfikator_pola
lub nazw klasy:
Mo emy zmodyfikowa program przykładowy posługuj c si
(globaln ) zmienn statyczn . Zamiast wszystkich liter b dziemy nazwa_obiektu.Funkcja(...); /* lub */
zlicza tylko wyst pienia 'a', 'b' i 'c'. nazwa_klasy::Funkcja(...);

[P110.CPP] Je eli funkcja jest tylko jedna, jej działanie nie zale y od
tego ile obiektów danej klasy zostało utworzone i jakie nazwy
# include "ctype.h" nadamy tym obiektom. W przykładowym programie powy ej "a si
# include "iostream.h" prosi", by nada status funkcji statycznej metodzie
wy wietlaj cej wyniki zliczania:
class Licznik
{ class Licznik
public: {
char moja_litera; ...
static int ile; static void Pokazuj(void);
Licznik(char); //Konstruktor ...
void Skok_licznika(); }
void Pokazuj();
}; Sprawdzenie, czy wtedy program przestanie "robi bł dy"
pozostawiamy bardziej dociekliwym Czytelnikom jako zadanie
void main() domowe.
{
/* inicjujemy liczniki: -------------------------------*/

Licznik licznik_a('a'), licznik_b('b'), licznik_c('c'); LEKCJA 31: PRZEKAZANIE OBIEKTÓW JAKO ARGUMENTÓW DO
FUNKCJI.
/* pracujemy - zliczamy: -------------------------------*/ ________________________________________________________________
W trakcie tej lekcji poznasz sposoby manipulowania obiektami
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n'; przy pomocy funkcji. Poznasz tak e troch dokładniej referencje.
for(;;) ________________________________________________________________
{ char znak;
cin >> znak; Typowy sposób przekazywania argumentów do funkcji w C++ to
if(znak == '.') break; przekazanie przez warto (ang. by value). W przypadku obiektów
if (znak == licznik_a.moja_litera) licznik_a.Skok_licznika(); oznacza to w praktyce przekazanie do funkcji kopii obiektu. Jako
if (znak == licznik_b.moja_litera) licznik_b.Skok_licznika();
if (znak == licznik_c.moja_litera) licznik_c.Skok_licznika(); przykład zastosujemy program zliczaj cy wyst pienia znaków w
} strumieniu wej ciowym. Zmienimy w tym programie sposób
/* sprawdzamy: ----------------------------------------*/ wyprowadzenia wyników. Funkcji Pokazuj() przeka emy jako
argument obiekt. Obiekt-licznik zawiera w rodku t informacj ,
której potrzebuje funkcja - ilo zliczonych znaków. Zacznijmy
cout << "Wyswietlam wyniki zliczania: \n"; od zdefiniowania klasy.
licznik_a.Pokazuj();
licznik_b.Pokazuj(); class Licznik
licznik_c.Pokazuj(); {
public:
} char moja_litera;
int ile;
Licznik::Licznik(char z) Licznik(char litera);
{ void Skok_licznika();
moja_litera = z; };
ile = 0;
98
W programie głównym mo emy zastosowa konstruktor do /* Prototypy funkcji (dwie wersje): ---------------- */
zainicjowania obiektu np. tak:
void Pokazuj1(Licznik);
main()
{ int Pokazuj2(Licznik);
Licznik licznik_a('a');
...
void main()
Zdefiniujmy funkcj . Obiekt licznik_a b dzie argumentem funkcji {
Pokazuj(). Funkcja powinna wyprowadzi na ekran zawarto pola /* inicjujemy licznik: -------------------------------*/
licznik_a.ile. Deklaracja - prototyp takiej pobieraj cej obiekt
funkcji b dzie wygl da tak: Licznik licznik_a('a');

wart_zwracana Nazwa_funkcji(nazwa_klasy nazwa_obiektu); /* pracujemy - zliczamy: -------------------------------*/

Nazwa klasy spełnia dokładnie tak sam rol jak ka dy inny typ cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';
danych. W naszym przypadku b dzie to wygl da tak: for(;;)
{
void Pokazuj(Licznik obiekt); char znak;
cin >> znak;
Poniewa "obiekt" jest parametrem formalnym i jego nazwa nie if(znak == '.') break;
jest tu istotna, mo emy pomin j w prototypie funkcji (w if (znak == licznik_a.moja_litera) licznik_a.Skok_licznika();
definicji ju nie!) i skróci zapis do postaci: }

void Pokazuj(Licznik); /* sprawdzamy: ----------------------------------------*/

Funkcja Pokazuj() otrzyma w momencie wywołania jako swój cout << "Wyswietlam wyniki zliczania litery a: \n";
argument kopi obiektu, któr jako argument formalny funkcji
nazwali my "obiekt". W naszym programie wywołanie tej funkcji Pokazuj1(licznik_a);
b dzie wygl da tak: cout << '\n' << Pokazuj2(licznik_a);

Pokazuj(licznik_a); }

Obiekt "licznik_a" jest tu BIE CYM ARGUMENTEM FAKTYCZNYM. Licznik::Licznik(char z)


Typ {
(tzn. tu: klasa) argumentu faktycznego musi by oczywi cie moja_litera = z;
zgodny z zadeklarowanym wcze niej typem argumentu formalnego ile = 0;
funkcji. }

Je li funkcja dostała własn kopi obiektu, mo e odwoła si do void Licznik::Skok_licznika(void)


elementów tego obiektu w taki sposób: {
ile++;
void Pokazuj(Licznik obiekt) }
{
cout << obiekt.ile; /* ------------ Definicje funkcji: ---------------- */
}
void Pokazuj1(Licznik Obiekt)
albo np. tak: {
cout << Obiekt.ile;
int Pokazuj(Licznik obiekt) }
{
return (obiekt.ile); int Pokazuj2(Licznik Obiekt)
} {
return (Obiekt.ile);
Nale y podkre li , e funkcja Pokazuj() NIE MA DOST PU do }
oryginalnego obiektu i jego danych. Podobnie jak było to w
przypadku przekazania zmiennej do funkcji i tu funkcja ma do [!!!]UWAGA:
dyspozycji WYŁ CZNIE SWOJ "PRYWATN " KOPI obiektu. Funkcja ________________________________________________________________
nie Programy manipuluj ce obiektami w taki sposób mog wymaga
modelu pami ci wi kszego ni przyjmowany domy lnie model SMALL.
mo e zmieni zawarto ci pól oryginalnego obiektu. Typowy komunikat pojawiaj cy si przy zbyt małym modelu pami ci
to:
Podobnie, jak w przypadku "zwykłych" zmiennych, je li chcemy by
funkcja działała na polach oryginalnego obiektu, musimy funkcji Error 43: Type mismatch in parameter to call to
przekaza nie kopi obiektu a wska nik (pointer) do tego Pokazuj1(Licznik)...
obiektu. Oto program przykładowy w cało ci: ( ły typ argumentu przy wywołaniu funkcji Pokazuj(...)...)

[P110.CPP] Programy obiektowe s z reguły szybke, ale niestety do


"pami ciochłonne". W IDE BORLAND C++ masz do dyspozycji opcj :
//UWAGA: Program moze wymagac modelu wiekszego niz SMALL !
Options | Compiler | Code generation | Model
# include "ctype.h"
# include "iostream.h" Dokładniejsze informacje o modelach pami ci znajdziesz w dalszej

class Licznik cz ci ksi ki.


{ ________________________________________________________________
public:
char moja_litera;
int ile; O PROBLEMIE REFERENCJI.
Licznik(char);
void Skok_licznika(); Typowy (domy lny) sposób przekazywania argumentów do funkcji w
}; C++ polega na tzw. "przekazaniu przez warto " i jest inny ni
Pascalu, czy Basicu. Poniewa w polskich warunkach do C/C++
99
wi kszo adeptów "dojrzewa" po przebrni ciu przez Basic i/lub
Pascal, programi ci ci obci eni s ju pewnymi nawykami i main()
pewnym schematyzmem my lenia, który do C++ niestety nie da si {
zastosowa i jest powodem wielu pomyłek. To, co w Basicu wygl da int zmienna;
int& ksywa;
zrozumiale (uwaga, tu wła nie pojawia si automatyzm my lenia): ...

PRINT X REM Wyprowad bie c warto zmiennej X Aby "ksywa" oznaczała t sam zmienn , referencj nale y
INPUT X REM Pobierz warto zmiennej X zainicjowa :

a w Pascalu: int& ksywa = zmienna;

writeln(X); { Wyprowad bie ac warto zmiennej X } Zainicjujemy nasz zmienn "zmienna" i b dziemy robi z ni
readln(X); { Pobierz warto zmiennej X } cokolwiek (np. inkrementowa ). Równocze nie b dziemy sprawdza ,
czy odwołania do zmiennej przy pomocy nazwy i referencji b d
przyjmuje w C/C++ form zapisu wyra nie dualnego: pozostawa równowa ne.

printf("%d", X); //Wyprowad warto zmiennej X [P111.CPP]


scanf("%d", &X); //Pobierz warto zmiennej X
/* UWAGA: Program moze potrzebowac modelu wiekszego niz
Na czym polega ró nica? Je li odrzucimy na chwil automatyzm i domyslnie ustawiany MODEL SMALL */
zastanowimy si nad t sytuacj , zauwa ymy, e w pierwszym
przypadku (wyprowadzanie istniej cych ju danych - PRINT, # include "iostream.h"
wrilteln, printf()) w celu poprawnego działania funkcji
powinni my przekaza jej BIE C WARTO ARGUMENTU X (adres main()
zmiennej w pami ci nie jest funkcji potrzebny). Dla Basica, {
Pascala i C++ bie ca warto zmiennej kojarzoana jest z jej int zmienna = 6666;
identyfikatorem - tu: "X". W drugim jednak e przypadku (pobranie int& ksywa = zmienna;

danych i umieszczenie ich pod wła ciwym adresem pami ci) jest cout << '\n' << "Zmienna" << " Ksywa";
inaczej. Funkcji zupełnie nie interesuje bie ca wart zmiennej cout << '\n' << zmienna << '\t' << ksywa;

X, jest jej natomiast do poprawnego działania potrzebny adres for (register int i = 0; i < 5; i++, zmienna += 100)
zarezerwowany dla zmiennej X w pami ci. Ale tu okazuje si , e cout << '\n' << zmienna << '\t' << ksywa;
Basic i Pascal post puj dokładnie tak samo, jak poprzednio:
return 0;
INPUT X i read(X); }

Oznacza to, e X nie oznacza dla Pascala i Basica bie cej Dialog (a wła ciwie monolog) powinien wygl da tak:
warto ci zmiennej, lecz oznacza (DOMY LNIE) przekazanie do
funkcji adresu zmiennej X w pami ci. Funkcje oczywi cie C:\>program
"wiedz ", co dostały i dalej ju one same manipuluj danymi we
wła ciwy sposób. Zmienna Ksywa
6666 6666
W C++ jest inaczej. Zapis: 6666 6666
6766 6766
Funkcja(X); 6866 6866
6966 6966
oznacza w praktyce, e zostan wykonane nast puj ce operacje: 7066 7066

* spod adresu pami ci przeznaczonego dla zmiennej X zostanie Referencje i wska niki mo na stosowa a C++ niemal wymiennie
(zgodnie z zadeklarowanym formatem) odczytana bie ca warto (dokładniej - nie jest to wymienno wprost, a uzupełnianie na
zmiennej X; zasadzie odwrotno ci-komplementarno ci).
* warto X zostanie zapisana na stos (PUSH X);
* zostanie wywołana funkcja Funkcja(); [!!!] TO NIE WSZYSTKO JEDNO!.
* Funkcja() pobierze sobie warto argumentu ze stosu (zgodnie z ________________________________________________________________
Mogłoby si wydawa , e operator adresowy & zyskał dwa RÓ NE
formatem zadeklarowanym w prototypie Funkcji()). zastosowania: okre lenie adresu w pam ci oraz tworzenie
* Funkcja() zadziała zgodnie ze swoj definicj i je li ma co wskazania. Aby rozró ni te dwie sytuacje zwró uwag na
do pozostawienia (np. return (wynik); ) pozostawi wynik. "gramatyk " zapisu. Je li identyfikator zminnej jest poprzedzony

Jak wida : okre leniem typu zminnej:

* funkcja "nie wie", gdzie w pami ci umieszczony był przekazany int &zmienna; /* lub */ int &zmienna = ... ;
jej argument;
* funkcja komunikuje si "ze wiatem zewn trznym" (czyli własnym to zmienn nazywamy "zmienn referencyjn ". Je li natomiast
identyfikator nie został poprzedzony okre leniem typu:
programem, b d funkcj wy szego rz du - wywołuj c ) tylko za
po rednictwem stosu; p = &zmienna;
* funkcja dostaje swoj "kopi " argumentu z którym działa;
* funkcja nie ma wpływu na "oryginał" argumentu, który pozostaje to mówimy wtedy o adresie zmiennej.
Przekazanie argumentu do funkcji poprzez referencj jest w
bez zmian. istocie zbli one do przekazania wska nika do argumentu. Zwró
uwag , e przekazanie wska nika do obiektu mo e zwykle odby si
REFERENCJA - CO TO TAKIEGO ?
szybciej ni sporz dzenie kopii obiektu i przekazanie tej kopii
Zastanówmy si , czym wła ciwie jest referencja zmiennej w C++. do funkcji. Zastosowanie w deklaracji funkcji operatora
Pewne jest, e jest to alternatywny sposób odwołania si do adresowego & pozwala nam stosowa syntaktyk zapisu tak "jak
zmiennej. Zacznijmy od trywialnego przykładu odwołania si do zwykle" - przy przekazaniu przez warto . Je li nie chcemy
tej samej zmiennej maj cej swoj wła ciw nazw "zmienna" i ryzykowa zmian wprowadzonych do oryginalnego parametru
referencj "ksywa". przekazanego funkcji poprzez wskazanie, mo emy zadeklarowa
oryginalny parametr jako stał (kompilator "dopilnuje" i
# include "iostream.h" uniemo liwi zmian warto ci):
100
nazwa_funkcji(const &nazwa_obiektu); [P119.CPP]
________________________________________________________________
# include "ctype.h"
Poprosimy C++ by pokazał nam konkretne fizyczne adresy # include "iostream.h"
skojarzone z identyfikatorami "zmienna" i "ksywa". Operator &
oznacza dla C++ class Licznik
{
&X --> adres w pami ci zmiennej X public:
char moja_litera;
[P112.CPP] int ile;
Licznik(char z) { moja_litera = z; ile = 0; }
/* UWAGA: Program moze potrzebowac modelu wiekszego niz void Skok_licznika(void) { ile++; }
domyslnie ustawiany MODEL SMALL */ };

# include "iostream.h" void main()


{
main() char znak;
{ cout << "\nPodaj litere do zliczania: ";
int zmienna = 6666; cin >> znak;
int& ksywa = zmienna;
Licznik Obiekt1(znak), Obiekt2('a'), *p1, *p2;
cout << "Zmienna (ADR-hex) Ksywa (ADR-hex): \n\n"; p1 = &Obiekt1;
cout << hex << &zmienna << "\t\t" << &ksywa; p2 = &Obiekt2;
cout << "\n Wpisz ciag znakow";
return 0; cout << "zakonczony kropka [.] i [Enter] \n";
} for(;;)
{
Monolog programu powinien wygl da tak: cin >> znak;
if(znak == '.') break;
Zmienna (ADR-hex) Ksywa (ADR-hex): if(znak == p1->moja_litera) p1->Skok_licznika();
if(znak == p2->moja_litera) p2->Skok_licznika();
0x287efff4 0x287efff4 }
cout << "\nBylo " << p1->ile;
Fizyczny adres pami ci, który "kojarzy si " C++ ze zmienn i cout << " liter: " << p1->moja_litera;
ksyw jest identyczny. Referencja nie oznacza zatem ani p1 = p2;
sporz dzania dodatkowej kopii zmiennej, ani wskazania do cout << "\nBylo " << p1->ile;
zmiennej w rozumieniu wska nika (pointer). Jest to inna metoda cout << " liter: " << p1->moja_litera;
odwołania si do tej samej pojedynczej zmiennej. }

LEKCJA 33: WSKA NIKI DO OBIEKTÓW.


________________________________________________________________ Mo emy oczywi cie np. stosowa przypisanie, inkrementowa i
W trakcie tej lekcji dowiesz si , jak posługiwa si obiektami dekrementowa pointer oraz realizowa arytmetyk na wska nikach
za po rednictwem wska ników. dokładnie tak samo, jak w przypadku innych zmiennych.
________________________________________________________________
this - WSKA NIK SPECJALNY.
Wska niki do obiektów funkcjonuj podobnie jak wska niki do
struktur. Operator -> pozwala na dost p zarówno do danych jak i Po wi cimy teraz chwil uwagi pewnemu specjalnemu wska nikowi.
do funkcji. Dla przykładu wykorzystamy obiekt naszej prywatnej Specjalnemu (i wa nemu) na tyle, e a "dorobił si " w C++
klasy Licznik. własnego słowa kluczowego "this".

class Licznik Ka dej funkcji - metodzie zadeklarowanej wewn trz klasy zostaje
{ w momencie wywołania w niejawny sposób (ang. implicitly)
public: przekazany wska nik do obiektu (w stosunku do którego funkcja ma
char moja_litera;
int ile; zadziała ). Pointer wskazuje funkcji w pami ci ten obiekt,
Licznik(char znak) { moja_litera = z; ile = 0; } którego członkiem jest dana funkcja. Bez istnienia takiego
void Skok_licznika(void) { ile++; } wła nie wska nika nie mogliby my stosowa spokojnie funkcji, nie
};
mogliby my odwoływa si do pola obiektu, gdyby my nie wiedzieli
Aby w programie mo na było odwoła si do obiektu nie poprzez
nazw a przy pomocy wska nika, zadeklarujemy wska nik do jednoznacznie, o który obiekt chodzi. Program posługuje si
obiektów klasy Licznik: automatycznie niejawnym wska nikiem do obiektu (ang. implicit
pointer). Mo emy wykorzysta ten istniej cy, cho do tej pory
Licznik *p; nie widoczny dla nas pointer posługuj c si słowem kluczowym
this (ten). This pointer wskazuje na obiekt, do którego nale y
Wska nik w programie mo emy zastosowa np. tak: funkcja. Korzystaj c z tego wska nika funkcja mo e bez cienia
w tpliwo ci zidentyfikowa wła nie ten obiekt, z którym pracuje
p->Skok_licznika(); a nie obiekt przypadkowy.

(czytaj: Wywołaj metod "Skok_licznika()" w stosunku do obiektu [!!!] FUNKCJE KATEGORII static NIE OTRZYMUJ POINTERA this.
wskazywanego w danym momencie przez wska nik p) Nale y pami ta , e wska nik this istnieje wył cznie podczas
wykonywania metod (ang. class member function execution), za
Trzeba pami ta , e sama deklaracja w przypadku referencji i wyj tkiem funkcji statycznych.
wska ników nie wystarcza. Przed u yciem nale y jeszcze
zainicjowa wska nik w taki sposób, by wskazywał na nasz Je li w programie zadeklarujemy klas Klasa:
obiekt-licznik. Wska nik do obiektu inicjujemy w taki sam sposób
class Klasa
jak ka dy inny pointer: {
int dane;
p = &Obiekt; ...
}
Mo emy przyst pi do utworzenia programu przykładowego.
101
a wewn trz tej klasy metod Pokazuj():
a inaczej liczb całkowitych rzeczywistych. Dlatego te wykonanie
class Klasa
{ operacji mno enia wymaga od operatora * podj cia ró nych
int dane; działa :
public:
void Pokazuj(); class Liczba_zespolona x, y, z; z = x * y;
...
} int x, y, z; z = x * y;

void Klasa::Pokazuj(void) Czasem mo e si zdarzy , e dla dwu ró nych klas działanie


{ jakiego operatora jest identyczne, cz ciej jednak (i tak
cout << dane; nale y si spodziewa ) działanie operatora dla ka dej klasy
} b dzie odr bne i unikalne.

To zdefiniowanie funkcji Pokazuj() z zastosowaniem pointera this Pójd my w tym rozumowaniu o krok dalej. Skoro rozszerzenie
obszaru zastosowa jakiego operatora na obiekty nowej
i notacji wska nikowej (p->), jak poni ej, b dzie równowa ne: (nieznanej wcze niej klasy) wymaga zdefiniowania nowego
algorytmu działania operatora, C++ b dzie potrzebował do tego
void Klasa::Pokazuj(void) celu specjalnych rodków, które powinny by łatwo rozpoznawalne.
{
cout << this->dane; Do opisu algorytmów słu generalnie w C++ funkcje i tu Autorzy
} nie wprowadzili wyj tku. Zastrzegli jednak dla tych specjalnych
funkcji specjaln nazw : operator ...();
Przypomnijmy, e taka notacja wska nikowa oznacza:
"Wyprowad zawarto pola "dane" obiektu, na który wskazuje I tak funkcja precyzuj ca nowy algorytm dodawania (nowy sposób
wska nik" (poniewa jest to wska nik this, wi c chodzi o własny działania operatora + ) b dzie si nazywa :
obiekt).
operator+();

a np. funkcja okre laj ca nowy algorytm mno enia (nowy sposób
LEKCJA 34 OVERLOADING OPERATORÓW. działania operatora * ) b dzie si nazywa :
________________________________________________________________
Podczas tej lekcji poznasz mo liwo ci dostosowania operatorów operator*();
C++ do własnego "widzimisi " i do potrzeb własnych obiektów.
________________________________________________________________ Spróbujmy zastosowa tak filozofi w praktyce programowania.

Niemal od pocz tku niniejszej ksi ki korzystamy z operatorów [!!!] NIESTETY NIE WSZYSTKIE OPERATORY MO NA
poddanych overloadingowi. S to operatory << i >> , które ROZBUDOWA .
pierwotnie wykonywały bitowe przesuni cie w lewo i w prawo. ________________________________________________________________
Owerloading tych operatorów "załatwił" za nas producent S w C++ operatory, których nie mo emy podda overloadingowi. S
(Borland, Microsoft, czy inny). Jak widzisz, nie powoduje to w
dalszym u ytkowaniu tych operatorów adnych zauwa alnych to:
komplikacji, a cz sto ułatwia tworzenie programów. Zwró uwag ,
e overloading operatorów (jak i definicje klas) mo e znajdowa . :: .* ?:
si w doł czonych plikach nagłówkowych i po jednorazowym
wykonaniu mo e by "niewidoczny" dla programistów tworz cych . operator kropki umo liwia dost p do pól struktur i obiektów;
programy aplikacyjne.
:: operator "widoczno ci-przesłaniania" (ang. scope);
Je li projektujemy (definiujemy) now klas , dodajemy do C++ .* wskazanie członka klasy (ang. pointer-to-member);
nowy, lecz pełnoprawny typ danych. Autorzy C++ nie byli w stanie ?: operator warunkowy.
________________________________________________________________
przewidzie jakie klasy i jakie obiekty mog wymy li kolejne
pokolenia programistów w ramach swojej radosnej twórczo ci. Wszystkie pozostałe operatory mo emy podda overloadingowi i
Wprowadzili zatem do C++ jasne i jednoznaczne algorytmy przypisywa im potrzebne nam działanie.
post powania z typami "typowymi". C++ doskonale wie jak dodawa ,
OVERLOADING OPERATORA [+] (DWUARGUMENTOWEGO).
mno y , czy odejmowa np. liczby int, long, float itp., nie wie
jednak jak doda do siebie obiekty klas CString (CString = Class Zaczniemy od operatora + nale cego do grupy "dwuargumentowych
operatorów arytmetycznych" (ang. binary arithmetic operator).
String = klasa "ła cuch znaków"), TOdcinek (to taki kawałek Zwracamy tu ju na pocz tku rozwa a uwag na przynale no
prostej) itp.. A przecie miło byłoby, gdyby rozbudowa operatora do okre lonej grupy, poniewa overloading ró nych
działanie operatorów tak, by było mo liwe ich typowe opertorów nale cych do tej samej grupy przebiega podobnie.
zastosowanie w stosunku do naszych własnych, "nietypowych" Poniewa znak + mo e by tak e operatorem jednoargumentowym
obiektów: (ang. unary plus, o czym za chwil ), podkre lamy, e tym razem
chodzi o plus jako operator dodawania. Overloading operatora
int x, y; int z = x + y; //To operator + załatwia sam przeprowadzimy w stosunku do obiektów prostej, znanej Ci ju z
float x, y; float z = x + y; poprzednich przykładów klasy Data, któr (w celu upodobnienia
si do maniery stosowanej w Windows i bibliotekach klas)
Zanim jednak stanie si mo liwe post powanie takie: nazwiemy tym razem CData. "Namówimy" operator + do
przeprowadzenia operacji na obiektach (dokładniej na polach
class CString x, y, z; z = x + y; obiektów):

class Nasza_Klasa obiekt1, obiekt2, obiekt3; CData nowadata = staradata + 7; // W tydzien pozniej
obiekt3 = obiekt1 + obiekt2;
Operator + musi oczywi cie "wiedzie ", na którym polu obiekty
itp., itd. ... klasy CData przechowuj liczb dni i jak zwi zane s (logicznie)

musimy "uzupełni " C++ i "wyja ni " operatorom, co wła ciwie ma pola obiektu dz, mc, rok. Jest rzecz zrozumiał , e samo
w praktyce oznacza operacja obiekt1 = obiekt2 + obiekt3; . dodanie dni do pola dz mo e nie wystarczy , poniewa data
Jest wyczuwalne intuicyjnie, e działanie operatorów w stosunku 37.11.93 jest niedopuszczalna.
do ró nych obiektów mo e by ró ne. Dla przykładu - wiesz
zapewne, e inaczej wygl da algorytm mno enia liczb zespolonych, Je li staradata jest obiektem klasy CData z zawartymi wewn trz
102
danymi, to w wyniku działania "nowego" operatora + powinien W prawym polu operatora (operator jest dwuargumentowy, ma wi c
powsta obiekt nowadata klasy CData, którego pola zostan w swoje lewe i prawe pole) mo e pojawi tak e stała. Operacja:
sensowny sposób powi kszone o dodan liczb dni. Rozwa
działanie programu (najlepiej skompiluj i uruchom). nowadata = staradata + 14;

[P120.CPP] zostanie wykonana poprawnie.

/* Overloading operatora dwuargumentowego + */ Ale to nie wszystko. Je li wyst pi układ odwrotny - np.:

# include <iostream.h> nowadata = 14 + staradata;

class CData nasz operator "zgłupieje". Doszedłszy do operatora + C++ "nie


{ b dzie jeszcze wiedział" (analizuje wyra enia arytmetyczne od
int dz, mc, rok; lewej do prawej), KTÓRY obiekt wyst pi za chwil . Jedno jest
public: pewne, nie zawsze musi by to "własny" obiekt funkcji, do
CData() {} //Konstruktor domyslny (pusty) którego mamy pointer this. Aby uzyska jednoznaczno sytuacji,
CData(int d, int m, int y) { mc = m; dz = d; rok = y; } funkcja operatorowa powinna tu w jawny sposób pobiera przed
void Pokazuj() { cout << dz << '.' << mc << '.' << rok; } zadziałaniem dwa argumenty:
CData operator+(int); //TU! overloading operatora +
}; CData operator+(int n, CData obiekt);

static int TAB[] = {31,28,31,30,31,30,31,31,30,31,30,31}; aby działanie:

/* Definicja funkcji operatorowej: ------------------------ */ CData obiekt_wynik; obiekt_wynik = n + obiekt;

CData CData::operator+(int n) stało si wykonalne. Pojawia si tu wszak e pewien problem.


{ Wska nik this wskazuje własny obiekt funkcji-metody, a tym razem
CData kopia_obiektu = *this;
n += kopia_obiektu.dz; funkcja potrzebuje dost pu nie do pola własnego obiektu, lecz do
while (n > TAB[kopia_obiektu.mc-1])
{ pola "obcego" obiektu przekazanego jej jako argument. Ale w C++
n -= TAB[kopia_obiektu.mc-1]; mo emy:
if (++kopia_obiektu.mc == 13)
{ kopia_obiektu.mc = 1; kopia_obiektu.rok++; } * zdefiniowa dwie (i wi cej) funkcji o tej samej nazwie (ka da
} na inn ewentualno );
kopia_obiektu.dz = n; * mo emy nada funkcji status friend (wtedy nie b d c metod te
return (kopia_obiektu);
} uzyska dost p do danych obiektu).

main() Definicja naszej klasy CData zawieraj ca deklaracje dwu funkcji


{ operatorowych operator+() ró ni cych si zastosowaniem i (po
CData staradata(31, 1, 94); //Kostruktor z argumentami czym rozpozna je C++) liczb argumentów, b dzie wygl da tak:
CData nowadata; //Pusty konstruktor
cout << "\n Stara data: "; class CData
staradata.Pokazuj(); {
cout << "\n Podaj ile minelo dni --> "; int dz, mc, rok;
int n; public:
cin >> n; CData() {}
nowadata = staradata + n; CData(int d, int m, int y) { mc = m; dz = d; rok = y; }
cout << "\n Jest zatem --> "; void Pokazuj() { cout << dz << '.' << mc << '.' << rok; }
nowadata.Pokazuj(); /* Dwie funkcje operatorowe: ------------------------------ */
return 0; CData operator+(int);
} friend CData operator+(int, CData&);
};
Do tej pory do danych prywatnych obiektu mogli my si gn
wył cznie przy pomocy zdefiniowanej wewn trz klasy Zastosowali my zamiast kopii obiektu bezpo rednio przekazywanej
funkcji-metody. Metod umo liwiaj c nam dost p do prywatnych funkcji - referencj do obiektu klasy CData - CData&. Klasa
danych obiektu jest tu zadeklarowana wewn trz klasy (a wi c zawiera:
maj ca "status prawny" metody) funkcja operatorowa. Przyjrzyjmy * prywatne dane;
si tej funkcji dokładniej: * dwa konstruktory;
* własn metod - funkcj operatorow operator+();
CData CData::operator+(int n) * deklaracj zaprzyja nionej z klas funkcji kategorii friend
{ (cho jest to funkcja o tej samej nazwie, jej status i
CData kopia_obiektu = *this; uprawnienia s nieco inne).
...
return (kopia_obiektu); [!!!] NIE WSZYSTKO, CO WEWN TRZ JEST METOD .
} ________________________________________________________________
Nawet, je li wewn trz definicji klasy zdefiniujemy w pełni
Funkcja funkcj (nadaj c jej status inline), nie stanie si ona metod !
* została zdefiniowana dla obiektów klasy CData (z innymi Słowo kluczowe friend okre la status funkcji jednoznacznie, bez
post powa nie potrafi); wzgl du na to, w którym miejscu w tek cie programu umie cimy
Je li operator + zostanie umieszczony pomi dzy obiektem klasy definicj ciała funkcji.
CData, a liczb typu int: ________________________________________________________________
.... staradata + n;
* funkcja pobiera liczb n jako argument (jawnie);
* funkcja pobiera obiekt klasy CData jako swój drugi argument W zasadzie ciało funkcji jest na tyle proste (wymagamy od niej
(niejawnie, dzi ki pointerowi this); tylko zwrotu obiektu ze zmodyfikowanym polem danych), e mo emy
* funkcja zwróci obiekt klasy CData (ze zmodyfikowanym polem); skorzysta z rozbudowanego wcze niej operatora + i całe ciało
zdefiniowa tak:
Nowy obiekt zwrócony przez funkcj zostanie przypisany
class CData
nowadata = ... ; // <-- return(kopia_obiektu); {
int dz, mc, rok;
103
public: Podaj ile minelo dni --> -150
... Jest zatem --> -119.1.94
CData operator+(int); Testuje nowy operator: -118.1.94
friend CData operator+(int n, CData& x) { return (x + n); }
}; Funkcja operatorowa została napisana w taki sposób, e po
przekroczeniu warto ci -31 program b dzie wypisywał bzdury. Jako
Je li w operacji dodawania argumenty zastosujemy we
wcze niejszej kolejno ci: zadanie domowe - spróbuj zmodyfikowa algorytm w taki sposób, by

return (obiekt + liczba); rozszerzy zakres poprawnych warto ci.

to zostanie tu wykorzystany operator + rozbudowany poprzednio [!!!] Mo esz dodawa obiekty minusem.
przez metod CData::operator+(int). Program w cało ci mo e ________________________________________________________________
zatem wygl da tak: * Nale y tu zwróci uwag , e dodawanie obiektów mo e wykonywa
nie tylko i nie koniecznie operator + . Je li zechcesz, mo esz
[P121.CPP] do tego celu zastosowa dowolnie wybrany operator (np. -, *
itp.). W celu ułatwienia zrozumienia zapisu (i tylko dlatego)
# include "iostream.h" wi kszo programistów rozbudowuje działanie operatorów zgodnie
z ich pierwotnym zastosowaniem.
class CData * DOWOLNO , ALE NIE PEŁNA!
{ O tyle, o ile działanie operatora mo e by zmienione, to ilo
int dz, mc, rok; argumentów potrzebnych operatorowi pozostaje w C++ "sztywna"
public: (patrz przykład z n!).
CData() {} ________________________________________________________________
CData(int d, int m, int y) { mc = m; dz = d; rok = y; }
void Pokazuj() { cout << dz << '.' << mc << '.' << rok; } W bardzo podobny sposób mo esz rozbudowywa inne arytmetyczne
CData operator+(int); operatory dwuargumentowe (*, /, -, itp.) w stosunku tak e do
friend CData operator+(int n, CData& x) { return (x + n); } innych klas.
};
OVERLOADING OPERATORÓW JEDNOARGUMENTOWYCH ++ I -- .
static int TAB[] = {31,28,31,30,31,30,31,31,30,31,30,31};
Typowe operatory jednoargumentowe to ++ i --. Jako przykładem
CData CData::operator+(int n) posłu ymy si problemem zlicznia znaków pobieranych ze
{ strumienia wej ciowego.
CData kopia_obiektu = *this;
n += kopia_obiektu.dz; Zaczniemy od redefinicji postinkrementacji licznika. Musimy
while (n > TAB[kopia_obiektu.mc-1]) zastosowa funkcj operatorow . Funkcja, chc c operowa na
{ obiektach musi w stosunku do tych obiektów posiada status
n -= TAB[kopia_obiektu.mc-1]; friend, lub by metod . Prototyp funkcji operatorowej potrzebnej
if (++kopia_obiektu.mc == 13)
{ kopia_obiektu.mc = 1; kopia_obiektu.rok++; } do wykonania overloadingu operatora jednoargumentowego ++
} wygl da w postaci ogólnej tak:
kopia_obiektu.dz = n;
return (kopia_obiektu); typ_zwracany nazwa_klasy::operator++(lista argumentów);
}
Funkcje operatorowe zwracaj zwykle warto zgodn co do typu z
main() typem obiektów z którymi współpracuj . Je li identyfikatory b, c
{
CData staradata(31, 1, 94); //Kostruktor z argumentami i d reprezentuj obiekty, nic nie stoi na przeszkodzie, by stał
CData nowadata, jeszczejednadata; si mo liwy zapis:
cout << "\n Stara data: ";
staradata.Pokazuj(); class Klasa
cout << "\n Podaj ile minelo dni --> "; {
int n; ...
cin >> n; } x, y, z;
nowadata = staradata + n; ...
cout << "\n Jest zatem --> "; z = x + y;
nowadata.Pokazuj();
cout << "\n Testuje nowy operator: "; Dodajemy dwa obiekty x i y tego samego typu (tej samej klasy), a
jeszczejednadata = (1+n) + staradata;
jeszczejednadata.Pokazuj(); wynik przypisujemy obiektowi z, który tak e jest obiektem tego
return 0; samego typu. Je li mo naby jeszcze zastosowa operator
} przypisania tak:

Operator + w obu sytuacjach działa poprawnie. By mo e wpadłe z = q = x + y;


na pomysł, e operator - (minus) te mamy ju z głowy. Niby tak,
operator przypisania = zwracałby nam w efekcie obiekt tego
ale tylko w takim zakresie, w jakim nasza funkcja operatorowa samego typu. Funkcje operatorowe musz przestrzega tych samych
poprawnie b dzie obsługiwa ujemne liczby dni. Je li zechcesz zasad, które obowi zuj wyra enia: typ argumentów x, y, z, q,
poda ujemn liczb dni (zmuszaj c funkcj do odejmowania ... powinien by zgodny, rezultat operacji (x + y) powinien by
zamiast dodawania), twój dialog z programem b dzie wygl dał np. obiektem tego samego typu, co obiekty x, y, z, q. Dokonuj c
tak: overloadingu operatorów powinni my precyzyjnie okre li typ
warto ci zwracanej w wyniku działania operatora.
C:\>program
Stara data: 31.1.94 Stosowan poprzednio do inkrementacji liczników metod
Podaj ile minelo dni --> -10 Skok_licznika() zast pimy w definicji klasy funkcj operatorow :
Jest zatem --> 21.1.94
Testuje nowy operator: 22.1.94
class Licznik
lub tak: {
public:
C:\>program char moja_litera;
Stara data: 31.1.94 int ile;
104
Licznik(char); cout << "\n Wpisales " << obiekt.ile << " znakow";
Licznik operator++(); }
};
Podobnie jak wcze niej, preinkrementacja i postinkrementacja
Powinni my teraz zdefiniowa funkcj operatorow . Poniewa pole wymagaj odr bnego overloadingu. Dokładnie rzecz ujmuj c,
obiektu, które zamierzamy inkrementowa nazywa si : zgodnie ze standardem ANSI C, odr bny overloading nie jest ju
niezb dny, wykorzystamy to jednak jako pretekst do wykonania go
obiekt.ile // Licznik::ile; dwiema ró nymi technikami. Poniewa logika jest bardzo podobna,
pomijamy tu (chyba ju zb dny) komemtarz. Dla ułatwienia Ci
funkcja powinna zadziała tak: porównania, zestawili my obok siebie ró ne funkcje operatorowe
napisane ró nymi technikami (notacja wska nikowa i
Licznik Licznik::operator++(void) referencyjna).
{
this->ile++; [P122.CPP]
return (*this);
} /* -------- PRE - inkrementacja ------------------------- */
# include "iostream.h"
Przetłumaczmy t notacj na "ludzki j zyk". Funkcja operatorowa:
class Licznik
{
* nie pobiera adnych jawnych argumentów (void); public:
* jest metod , zatem w momencie wywołania otrzymuje w niejawny int ile;
sposób wska nik *this do "własnego" obiektu; Licznik() { ile = 0;}
* posługuj c si wsak nikiem this inkrementuje zawarto pola Licznik operator+(int n = 1)
int ile własnego obiektu; { this->ile += n; return (*this); }
* zwraca obiekt (zmodyfikowany) klasy Licznik (tj. dokładniej - Licznik friend operator++(Licznik& x)
zwraca wska nik this do własnego-zmodyfikowanego obiektu. { x + 1; return (x); }
} obiekt;
Poniewa funkcja operatorowa jest metod zadeklarowan wewn trz
klasy, bez problemu uzyska dost p do wewn trznych pól obiektów void main()
tej klasy i wykona inkrementacj licznika. Mo emy zatem {
zastosowa wyra enie typu: cout << "\n Wpisz kilka znakow: ";
char znak;
Licznik licznik_a; licznik_a++; for(;;)
{
Funkcja jest metod wraz ze wszystkimi wła ciwymi metodom cin >> znak;
przywilejami. Zapis mo emy zatem upro ci do postaci: if(znak == '.') break;
++obiekt;
Licznik Licznik::operator++(void) }
{ cout << "\n Wpisales " << obiekt.ile << " znakow";
ile++; cout << "\n I dodamy jeszcze sto! --> ";
return (*this); obiekt + 100;
} cout << obiekt.ile;
}
a tak skrócone ciało funkcji umie ci w definicji klasy obok
definicji konstruktora:
Poni ej inny przykład tego samego overloadingu odno nie tej
class Licznik samej klasy Licznik (w troch inny sposób).
{
public: [P123.CPP]
char moja_litera;
int ile; # include "conio.h"
Licznik(char z) { ile = 0; moja_litera = z; } # include "iostream.h"
Licznik operator++() { ile++; return (this); }
}; class Licznik
{
Aby nie zaciemnia obrazu, przy pomocy licznika b dziemy tym public:
razem zlicza wszystkie znaki za wyj tkiem kropki. Poniewa char moja_litera;
licznik nie b dzie miał swojej ulubionej litery, mo emy int ile;
zastosowa pusty konstruktor. Licznik() { ile = 0; } //Pusty konstruktor
Licznik(char);
[P121.CPP] Licznik operator++(); //Funkcja pre/post-inkrementacji
/* --------------------- POST - inkrementacja ----------- */ Licznik operator--(); //Funkcja pre/post-dekrementacji
# include "iostream.h" };

class Licznik Licznik::Licznik(char z) { moja_litera = z; ile = 10; }


{ Licznik Licznik::operator++(void) { ile++; return *this; }
public: Licznik Licznik::operator--(void) { ile--; return *this; }
int ile;
Licznik() { ile = 0;}
Licznik operator++() { ile++; return (*this); } void main()
} obiekt; {
Licznik obiekt1('A'), obiekt2; //obiekt2 - "pusty"
void main()
{ cout << "\n Wpisz napis z max. 10 literami [A]: \n ";
cout << "\n Wpisz kilka znakow: "; for(;;)
char znak; {
for(;;) char litera = getch(); cout << litera;
{
cin >> znak; if(obiekt1.ile == 0) break;
if(znak == '.') break;
obiekt++; if(litera == obiekt1.moja_litera) obiekt1--;
}
105
++obiekt2; //Ten zlicza wszystkie znaki
//metoda PRE - inkrementacji program uda si skompilowa i kod wynikowy b dzie działał
if(obiekt2.ile > 30) cout << "\n NIE PRZESADZAJ \n"; poprawnie, C++ zaprotestuje jedynie przy pomocy ostrze enia
}
Warning: obiekt2 is never used...
cout << "\n Koniec: " << obiekt1.ile;
cout << " liter " << obiekt1.moja_litera; Chc c unikn ostrze e nale y u y argument pozorny w dowolny
cout << "\n Wszystkich znakow bylo: " << obiekt2.ile; sposób. Zwracamy na to uwag , poniewa C++ jest pedantem i:
}
[!!!] DZIAŁANIE OPERATORÓW MO E BY DALECE DOWOLNE, ALE
Overloading "siostrzanych" operatorów ++ i -- jest bli niaczo LICZBA
podobny. ARGUMENTÓW MUSI POZOSTA ZGODNA Z "TRADYCJAMI" C++.

OVERLOADING OPERATORA ! Stosowanie podczas overloadingu operatorów argumentów pozornych


jest technik cz sto stosowan przez programistów.
Z matematyki jeste my przyzwyczajenu do zapisu silni n! i
wydawałoby si , e maj c w C++ do dyspozycji operator ! nie Aby wykaza , e korzystanie z gotowych "fabrycznych" zasobów
powinni my mie z tym zadaniem najmniejszego kłopotu. Operuj c ułatwia ycie programi cie czasami w zaskakuj co skuteczny
znan Ci klas Liczba i wyposa aj c program w funkcj sposób, przytocz przykładowy program, który posługuj c si
operatorow mo emy załatwi ten problem np. tak: "fabryczn " klas ofstream (obiekty - strumie danych do pliku
wyj ciowego - Output File STREAM):
[P124.CPP]
* zakłada w bie cym katalogu plik dyskowy DANE.TST;
# include <iostream.h> * otwiera plik dla zapisu;
* zapisuje do pliku tekst "to jest zawartosc pliku";
class Liczba * zamyka plik;
{
public: [P125.CPP]
long wartosc;
Liczba(int x) { wartosc = (long) x; } # include "fstream.h"
friend void operator!(Liczba&);
}; void main()
{
void operator!(Liczba& obiekt) ofstream plik("dane.tst");
{ plik << "To jest zawartosc pliku";
long wynik = 1; }
for(int i = 1; i <= obiekt.wartosc; i++)
{ I ju . O wszystkie szczegóły techniczne tych (wcale przecie nie
wynik *= i;
} najprostszych) operacji zadbał producent w bibliotekach klas
cout << '\n' << wynik; Wej cia/Wyj cia. Je li zechcemy do pliku dopisa co jeszcze,
} wystarczy doda :

int x; [P126.CPP]

main() # include "fstream.h"


{
for(int k = 0; k < 5; k++) void main()
{ {
cout << "\n Podaj liczbe --> "; ofstream plik("dane.tst");
cin >> x; plik << "To jest zawartosc pliku" << " i jeszcze cosik.";
Liczba a(x); }
cout << "\n Silnia wynosi: ";
!a; Urzekaj ca prostota, nieprawda ? I to wszystko załatwia poddany
} overloadingowi operator << . Niedowiarek mógłby w tym momencie
return 0; zapyta "a je li plik ju istnieje, to chyba nie jest takie
} proste?". Rzeczywi cie, nale ałoby tu rozbudowa program w C++
do postaci:
Program działa, wyniki kolejnych kilku silni s poprawne. Gdy
jednak spróbujemy zastosowa operator ! zgodnie z tradycyjnym # include "fstream.h"
matematycznym zapisem: a!; oka e si , e C++ zacznie mie void main()
w tpliwo ci. Komunikaty o bł dzie spowoduj w tpliwo ci {
kompilatora, czy chodzi nam o operator "!=", w którym ofstream plik("dane.tst", ios::app);
zapomni li my znaku "=". Je li w funkcji operatorowej spróbujemy plik << " Dopiszemy do pliku jeszcze i to...";
}
zmieni operator ! na != , a zapis w programie:
Korzystamy tu dodatkowo z globalnej zmiennej ios::app (ang.
z !a; na a!=a; append - doł cz) okre laj cej inny ni typowy tryb dost pu do
pliku dyskowego i w dalszym ci gu z operatora << . Tworzenie
C++ zarz da dwuargumentowej funkcji operatorowej (bo taki obiektu - pliku dyskowego jest takie proste, dzi ki istnieniu
operator jest tradycyjnie dwuargumentowy). Mo emy oczywi cie konstruktora, który jest tu automatycznie wywoływany po
próbowa oszuka C++ przy pomocy argumentu pozornego. Je li deklaracji: ofstream plik( ... );
podamy w funkcji operatorowej dwa argumenty
[Z]
void operator!=(Liczba& obiekt1, Liczba& obiekt2) ________________________________________________________________
{ 1. Wykonaj samodzielnie overloading dowolnego operatora.
long wynik = 1; ________________________________________________________________
for(int i = 1; i <= obiekt.wartosc; i++)
{
wynik *= i;
} LEKCJA 35: O ZASTOSOWANIU DZIEDZICZENIA.
cout << '\n' << wynik; ________________________________________________________________
} Z tej lekcji dowiesz si , do czego w praktyce programowania
106
szczególnie przydaje si dziedziczenie. Cpochodna(char c1, char c2, char c3);
________________________________________________________________ };

Dzi ki dziedziczeniu programista mo e w pełni wykorzysta gotowe Cpochodna::Cpochodna(char c1,char c2,char c3) : CBazowa1(c2),
CBazowa2(c3)
biblioteki klas, tworz c własne klasy i obiekty, jako klasy {
pochodne wazgl dem "fabrycznych" klas bazowych. Je li bazowy cout << c1;
zestw danych i funkcji nie jest adekwatny do potrzeb, mo na np. }
przesłoni , rozbudowa , b d przebudowa bazow metod dzi ki
elastyczno ci C++. Zdecydowana wi kszo standardowych klas Konstruktor klasy pochodnej pobiera trzy argumenty i dwa z nich:
bazowych wyposa ana jest w konstruktory. Tworz c klas pochodn
powinni my pami ta o istnieniu konstruktorów i rozumie sposoby c2 --> przekazuje do konstruktora klasy CBazowa1
c3 --> przekazuje do konstruktora klasy CBazowa2
przekazywania argumentów obowi zuj ce konstruktory w przypadku Sposób zapisu w C++ wygl da tak:
bardziej zło onej struktury klas bazowych-pochodnych.
Cpochodna::Cpochodna(char c1,char c2,char c3) : CBazowa1(c2),
PRZEKAZANIE PARAMETRÓW DO WIELU KONSTRUKTORÓW. CBazowa2(c3)

Klasy bazowe mog by wyposa one w kilka wersji konstruktora. Mo emy zatem przekaza parametry "w tył" do konstruktorów klas
Dopóki nie przeka emy konstruktorowi klasy bazowej adnych bazowych w taki sposób:
argumentów - zostanie wywołany (domy lny) pusty konstruktor i
klasa bazowa b dzie utworzona z parametrami domy lnymi. Nie kl_pochodna::kl_pochodna(lista):baza1(lista), baza2(lista), ...
zawsze jest to dla nas najwygodniejsza sytuacja.
gdzie:
Je eli wszystkie, b d cho by niektóre z parametrów, które lista - oznacza list parametrów odpowiedniego konstruktora.
przekazujemy konstruktorowi obiektu klasy pochodnej powinny
zosta przekazane tak e konstruktorowi (konstruktorom) klas W takiej sytuacji na li cie argumentów konstruktorów klas
bazowych, powinni my wytłumaczy to C++. Z tego te powodu, bazowych mog znajdowa si tak e wyra enia, przy zało eniu, e
je li konstruktor jakiej klasy ma jeden, b d wi cej elementy tych wyra e s widoczne i dost pne (np. globalne
parametrów, to wszystkie klasy pochodne wzgl dem tej klasy stałe, globalne zmienne, dynamicznie inicjowane zmienne globalne
bazowej musz posiada konstruktory. Dla przykładu dodajmy
konstruktor do naszej klasy pochodnej Cpochodna: itp.). Konstruktory b d wykonywane w kolejno ci:

CBazowa1 --> CBazowa2 --> Cpochodna


class CBazowa1
{ Dzi ki tym mechanizmom mo emy łatwo przekazywa argumenty
public: "wstecz" od konstruktorów klas pochodnych do konstruktorów klas
CBazowa1(...); //Konstruktor bazowych.
};
FUNKCJE WIRTUALNE.
class CBazowa2
{ Działanie funkcji wirtualnych przypomina rozbudow funkcji
public: dzi ki mechanizmowi overloadingu. Je li, zdefiniowali my w
CBazowa2(...); //Konstruktor klasie bazowej funkcj wirtualn , to w klasie pochodnej mo emy
}; definicj tej funkcji zast pi now definicj . Przekonajmy si o

class Cpochodna : public CBazowa1, CBazowa2 //Lista klas tym na przykładzie. Zacznijmy od zadeklarowania funkcji
{ wirtualnej (przy pomocy słowa kluczowego virtual) w klasie
public: bazowej. Zadeklarujemy jako funkcj wirtualn funkcj oddychaj()
Cpochodna(...); //Konstruktor
}; w klasie CZwierzak:

main() class CZwierzak


{ {
Cpochodna Obiekt(...); //Wywolanie konstruktora public:
... void Jedz();
virtual void Oddychaj();
W momencie wywołania kostruktora obiektu klasy pochodnej };
Cpochodna() przekazujemy kostruktorowi argumenty. Mo emy (je li
chcemy, nie koniecznie) przekaza te argumenty konstruktorom Wyobra my sobie, e chcemy zdefiniowa klas pochodn CRybka
"wcze niejszym" - konstruktorom klas bazowych. Ta mo liwo Rybki nie oddychaj w taki sam sposób, jak inne obiekty klasy
okazuje si bardzo przydatna (niezb dna) w rodowisku obiektowym CZwierzak. Funkcj Oddychaj() trzeba zatem b dzie napisa w dwu
ró nych wariantach. Obiekt Ciapek mo e t funkcj odziedziczy
- np. OWL i TVL. Oto prosty przykład definiowania konstruktora w bez zmian i sapa spokojnie, z Sardynk gorzej:

przypadku dziedziczenia. Rola konstruktorów b dzie polega na class CZwierzak


trywialnej operacji przekazania pojedynczego znaku. {
public:
class CBazowa1 void Jedz();
{ virtual void Oddychaj() { cout << "Sapie..."; }
public: };
CBazowa1(char znak) { cout << znak; }
}; class CPiesek : public CZwierzak
{
class CBazowa2 char imie[30];
{ } Ciapek;
public:
CBazowa2(char znak) { cout << znak; } class CRybka
}; char imie[30];
public:
class Cpochodna : public CBazowa1, CBazowa2 void Oddychaj() { cout << "Nie moge sapac..."; }
{ } Sardynka;
public:
107
Zwró uwag , e w klasie pochodnej w deklaracji funkcji słowo p->Oddychaj()(); //która wersja Oddychaj() ???
kluczowe virtual ju nie wyst puje. W klasie pochodnej funkcja
CRybka::Oddychaj() robi wi cej ni w przypadku "zwykłego" Aby mie pewno , co w tym momencie b dzie wskazywał pointer,
overloadingu funkcji. Funkcja CZwierzak::Oddychaj() zostaje kompilator musiałby wiedzie w jaki sposób b dzie przebiega
"przesłoni ta" (ang. overwrite), mimo, e ilo i typ wykonanie programu. Takie wyra enie mo e zosta wykonane "w
argumentów. pozostaje bez zmian. Taki proces - bardziej ruchu programu" dwojako: raz, gdy pointer b dzie wskazywał
drastyczny, ni overloading nazywany jest przesłanianiem lub Ciapka (inaczej), a drugi raz - Sardynk (inaczej):
nadpisywaniem funkcji (ang. function overriding). W programie
przykładowym Ciapek b dzie oddychał a Sardynka nie. CZwierzak *p;
...
[P127.CPP] for(p = &Ciapek, int i = 0; i < 2; i++)
{
# include <iostream.h> p->Oddychaj();
p = &Sardynka;
class CZwierzak }
{
public: lub inaczej:
void Jedz();
virtual void Oddychaj() {cout << "\nSapie...";} if(p == &Ciapek) CZwierzak::Oddychaj();
}; else CRybka::Oddychaj();

class CPiesek : public CZwierzak Taki efekt nazywa si polimorfizmem uruchomieniowym (ang.
{ run-time polymorphism).
char imie[30];
} Ciapek; Overloading funkcji i operatorów daje efekt tzw. polimorfizmu
kompilacji (ang. compile-time), to funkcje wirtualne daj efekt
class CRybka polimorfizmu uruchomieniowego (run-time). Poniewa wszystkie
char imie[30]; wersje funkcji wirtualnej maj taki sam prototyp, nie ma innej
public: metody stwierdzenia, któr wersj funkcji nale y zastosowa .
void Oddychaj() {cout << "\nSardynka: A ja nie oddycham.";} Wybór wła ciwej wersji funkcji mo e by dokonany tylko na
} Sardynka; podstawie typu obiektu, do którego nale y wersja funkcji-metody.

void main() Ró nica pomi dzy polimorfizmem przejawiaj cym si na etapie


{ kompilacji i poliformizmem przejawiaj cym si na etapie
Ciapek.Oddychaj(); uruchomienia programu jest nazywana równie wszesnym albo pó nym
Sardynka.Oddychaj();
} polimorfizmem (ang. early/late binding). W przypadku wyst pienia

Funkcja CZwierzak::Oddychaj() została w obiekcie Sardynka wczesnego polimorfizmu (compile-time, early binding) C++ wybiera
przesłoni ta przez funkcj CRybka::Oddychaj() - nowsz wersj
funkcji-metody pochodz c z klasy pochodnej. wersj funkcji (poddanej overloadingowi) do zastosowania ju
tworz c plik .OBJ. W przypadku pó nego polimorfizmu (run-time,
Overloading funkcji zasadzał si na "typologicznym pedanty mie" late binding) C++ wybiera wersj funkcji (poddanej przesłanianiu
C++ i na dodatkowych informacjach, które C++ doł cza przy
kompilacji do funkcji, a które dotycz licznby i typów - overriding) do zastosowania po sprawdzeniu bie cego kontekstu
argumentów danej wersji funkcji. W przypadku funkcji wirtualnych
i zgodnie z bie cym wskazaniem pointera.
jest inaczej. Aby wykona przesłanianie kolejnych wersji funkcji
Przyjrzyjmy si dokładniej zastosowaniu wska ników do obiektów w
wirtualnej w taki sposób, funkcja we wszystkich "pokoleniach"
musi mie taki sam prototyp, tj. pobiera tak sam liczb przykładowym programie. Utworzymy hierarchi zło on z klasy
parametrów tych samych typów oraz zwraca warto tego samego bazowej i pochodnej w taki sposób, by klasa pochodna zawierała
typu. Je li tak si nie stanie, C++ potraktuje ró ne prototypy jaki unikalny element - np. nie wyst puj c w klasie bazowej
tej samej funkcji w kolejnych pokoleniach zgodnie z zasadami funkcj .
overloadingu funkcji. Zwró my tu uwag , e w przypadku funkcji
wirtualnych o wyborze wersji funkcji decyduje to, wobec którego class CZwierzak
obiektu (której klasy) funkcja została wywołana. Je li wywołamy {
funkcj dla obiektu Ciapek, C++ wybierze wersj public:
CZwierzak::Oddychaj(), natomiast wobec obiektu Sardynka zostanie void Jedz();
virtual void Oddychaj() {cout << "\nSapie...";}
zastosowana wersja CRybka::Oddychaj(). };

W C++ wska nik do klasy bazowej mo e tak e wskazywa na klasy class CPiesek : public CZwierzak
pochodne, wi c zastosowanie funkcji wirtualnych mo e da pewne {
ciekawe efekty "uboczne". Je li zadeklarujemy wska nik *p do char imie[20];
obiektów klasy bazowej CZwierzak *p; a nast pnie zastosujemy ten void Szczekaj() { cout << "Szczekam !!!"; }
} Ciapek;
sam wska nik do wskazania na obiekt klasy pochodnej:
Je li teraz zadeklarujemy wska nik do obiektów klasy bazowej:
p = &Ciapek; p->Oddychaj();
... CZwierzak *p;
p = &Sardynka; p->Oddychaj();
to przy pomocy tego wska nika mo emy odwoła si tak e do
zarz damy w taki sposób od C++ rozpoznania wła ciwej wersji obiektów klasy pochodnej oraz do elementów obiektu klasy
wirtualnej metody Oddychaj() i jej wywołania we wła ciwym pochodnej - np. do funkcji p->Oddychaj(). Ale pojawia si tu
momencie. C++ mo e rozpozna , któr wersj funkcji nale ałoby pewien problem. Je li zechceliby my wskaza przy pomocy pointera
zastosowa tylko na podstawie typu obiektu, wobec którego
funkcja została wywołana. I tu pojawia si pewien problem. taki element klasy pochodnej, który nie został odziedziczony i
Kompilator wykonuj c kompilcj programu nie wie, co b dzie którego nie ma w klasie bazowej? Rozwi zanie jest proste -
wskazywał pointer. Ustawienie pointera na konkretny adres wystarczy zarz da od C++, by chwilowo zmienił typ wska nika z
nast pi dopiero w czasie wykonania programu (run-time). obiektów klasy bazowej na obiekty klasy pochodnej. W przypadku
Kompilator "wie" zatem tylko tyle: funkcji Szczekaj() w naszym programie wygl dałoby to tak:
108
public:
CZwierzak *p; virtual void Oddychaj() = 0;
... ...
p->Oddychaj(); };
p->Szczekaj(); // LE !
(CPiesek*)p->Szczekaj(); //Poprawnie class CPiesek : public CZwierzak
... {
...
Dzi ki funkcjom wirtualnym tworz c klasy bazowe pozwalamy public:
pó niejszym u ytkownikom na rozbudow funkcji-metod w void Oddychaj() { cout << "Oddycham..."; }
najwła ciwszy ich zdaniem sposób. Dzi ki tej "nieokre lono ci" ...
dziedzicz c mo emy przejmowa z klasy bazowej tylko to, co nam };
odpowiada. Funkcje w C++ mog by jeszcze bardziej
"nieokre lone" i rozbudowywalne. Nazywaj si wtedy funkcjami w Przykładem takiej funkcji jest funkcja Mów() z przedstawionego
pełni wirtualnymi. poni ej programu. Zostawiamy j w pełni wirtualn , poniewa
LEKCJA 36: FUNKCJE WIRTUALNE i KLASY ABSTRAKCYJNE. ró ne obiekty klasy CZLOWIEK i klas pochodnych
________________________________________________________________
W trakcie tej lekcji dowiesz si , co mawia ona programisty, gdy class CZLOWIEK
{
nie chce by obiektem klasy abstrakcyjnej. public:
________________________________________________________________ void Jedz(void);
virtual void Mow(void) = 0; //funkcja WIRTUALNA
FUNKCJE W PEŁNI WIRTUALNE (PURE VIRTUAL). };

W skrajnych przypadkach wolno nam umie ci funkcj wirtualn w class NIEMOWLE : public CZLOWIEK
klasie bazowej nie definiuj c jej wcale. W klasie bazowej {
umieszczamy wtedy tylko deklaracj -prototyp funkcji. W public:
nast pnych pokoleniach klas pochodnych mamy wtedy pełn swobod void Mow(void); // Tym razem BEZ slowa virtual
i mo emy zdefiniowa funkcj wirtualn w dowolny sposób - };
adekwatny dla potrzeb danej klasy pochodnej. Mo emy np. do klasy /* Tu definiujemy metod wirtualn : -------------------- */
void NIEMOWLE::Mow(void) { cout << "Nie Umiem Mowic! \n"; };
bazowej (ang. generic class) doda prototyp funkcji wirtualnej
funkcja_eksperymentalna() nie definiuj c jej w (ani wobec)
klasie bazowej. Sens umieszczenia takiej funkcji w klasie mog mówi na ró ne sposoby... Obiekt Niemowle, dla przykładu,
bazowej polege na uzyskaniu pewno ci, i wszystkie klasy nie chce mówi wcale, ale z innymi obiektami mo e by inaczej.
pochodne odziedzicz funkcj funkcja_eksperymentalna(), ale Wyobra sobie np. obiekt klasy ona ( ona to przecie te
ka da z klas pochodnych wyposa y t funkcj we własn definicj . człowiek !).

Takie post powanie mo e okaza si szczególnie uzasadnione przy class Zona : public CZLOWIEK
tworzeniu biblioteki klas (class library) przeznaczonej dla {
innych u ytkowników. C++ w wersji instalacyjnej posiada ju public:
kilka gotowych bibliotek klas. Funkcje wirtuale, które nie void Mow(void);
zostaj zdefiniowane - nie posiadaj zatem ciała funkcji - }
nazywane s funkcjami w pełni wirtualnymi (ang. pure virtual
function). W tym pokoleniu definicja wirtualnej metody Mow() mogłaby
wygl da np. tak:
O KLASACH ABSTRAKCYJNYCH.
void Zona::Mow(void)
Je li zadeklarujemy funkcj CZwierzak::Oddychaj() jako funkcj w {
cout << "JA NIE MAM CO NA SIEBIE WLOZYC !!! ";
pełni wirtualn , oprócz słowa kluczowego virtual, trzeba t cout << "DLACZEGO KOWALSKI ZARABIA ZAWSZE WIECEJ NIZ TY
informacj w jaki sposób przekaza kompilatorowi C++. Aby C++ ?!!!";
wiedział, e nasz intencj jest funkcja w pełni wirtalna, nie
mo emy zadeklarowa jej tak: //... itd., itd., itd...
}
class CZwierzak
{ [P128.CPP]
...
public: #include "iostream.h"
virtual void Oddychaj();
... class CZLOWIEK
}; {
public:
a nast pnie pomin definicj (ciało) funkcji. Takie void Jedz(void);
post powanie C++ uznałby za bł d, a funkcj - za zwykł funkcj virtual void Mow(void) = 0;
wirtualn , tyle, e "niedorobion " przez programist . Nasz };
intencj musimy zaznaczy ju w definicji klasy w taki sposób:
void CZLOWIEK::Jedz(void) { cout << "MNIAM, MNIAM..."; };
class CZwierzak
{ class Zona : public CZLOWIEK
... {
public: public:
virtual void Oddychaj() = 0; void Mow(void); //Zona mowi swoje
... }; //bez wzgledu na argumenty (typ void)
};
void Zona::Mow(void)
Informacj dla kompilatora, e chodzi nam o funkcj w pełni {
wirtualn , jest dodanie po prototypie funkcji "= 0". Definiuj c cout << "JA NIE MAM CO NA SIEBIE WLOZYC !!!";
klas pochodn mo emy rozbudowa funkcj wirtualn np.: cout << "DLACZEGO KOWALSKI ZARABIA ZAWSZE WIECEJ NIZ TY
?!!!";
class CZwierzak
{ }
...
109
class NIEMOWLE : public CZLOWIEK CA obiekt;
{ public:
public: CB() { obiekt = 1; cout << "->Konstruktor CB() "; }
void Mow(void); };
};
Mo emy teraz sprawdzi , co stanie si w programie po
void NIEMOWLE::Mow(void) { cout << "Nie Umiem Mowic! \n"; }; zadeklarowaniu obiektu klasy CB:

main() [P129.CPP]
{
NIEMOWLE Dziecko; # include "iostream.h"
Zona Moja_Zona;
class CA
Dziecko.Jedz(); {
Dziecko.Mow(); int liczba;
Moja_Zona.Mow() public:
CA() { liczba = 0; cout << "-> CA(), CA_O::liczba = 0 "; }
return 0; CA(int x) { liczba = x; cout << "->CA(int) "; }
} void operator=(int n) { liczba = n; cout << "->operator "; }
};
Przykładowa klasa CZŁOWIEK jest klas ABSTRAKCYJN . Je li
spróbujesz doda do powy szego programu np.: class CB
{
CZLOWIEK Facet; CA obiekt;
Facet.Jedz(); public:
CB() { obiekt = 1; cout << "->Konstruktor CB() "; }
uzyskasz komunikat o bł dzie: };

Cannot create a variable for abstract class "CZLOWIEK" main()


(Nie mog utworzy zmiennych dla klasy abstrakcyjnej "CZLOWIEK" {
CB Obiekt;
[???] KLASY ABSTRAKCYJNE. return 0;
________________________________________________________________ }
* Po klasach abstrakcyjnych MO NA dziedziczy !
* Obiektów klas abstrakcyjnych NIE MO NA stosowa bezpo rednio! Po uruchomieniu programu mo esz przekona si , e kolejno
________________________________________________________________ działa b dzie nast puj ca:

Poniewa wyja nili my, dlaczego klasy s nowymi typami danych, C:\>program
wi c logika (i sens) innej rozpowszechnionej nazwy klas -> CA(), CA_O::liczba = 0 ->operator ->Konstruktor CB()
abstrakcyjnych - ADT - Abstract Data Type (Abstrakcyjne Typy
Danych) jest chyba zrozumiała i oczywista. Skoro oprócz zainicjowania obiektu klasy pochodnej nie robimy w
programie dokładnie nic, nie dziwmy si ostrze eniu
ZAGNIE D ANIE KLAS I OBIEKTÓW.
Warning: Obiekt is never used...
Mo e si np. zdarzy , e klasa stanie si wewn trznym elementem
(ang. member) innej klasy i odpowiednio - obiekt - elementem Jest to sytuacja troch podobna do komunikacji pomi dzy
innego obiektu. Nazywa si to fachowo "zagnie d aniem" (ang. konstruktorami klas bazowych i pochodnych. Je li zaprojektujemy
nesting). Je li, dla przykładu klasa CB b dzie zawiera obiekt prost struktur klas:
klasy CA:
class CBazowa
class CA {
{ private:
int liczba; int liczba;
public: public:
CA() { liczba = 0; } //Konstruktor domyslny CBazowa() { liczba = 0}
CA(int x) { liczba = x; } CBazowa(int n) { liczba = n; }
void operator=(int n) { liczba = n } };
};
class CPochodna : public CBazowa
class CB {
{ public:
CA obiekt; CPochodna() { liczba = 0; }
public: CPochodna(int x) { liczba = x; }
CB() { obiekt = 1; } };
};
problem przekazywania parametrów mi dzy konstruktorami klas
Nasze klasy wyposa yli my w konstruktory i od razu poddali my mo emy w C++ rozstrzygn i tak:
overloadingowi operator przypisania = . Aby prze ledzi
kolejno wywoływania funkcji i sposób przekazywania parametrów class CPochodna : public CBazowa
pomi dzy tak powi zanymi obiektami rozbudujemy ka d funkcj o {
zgłoszenie na ekranie. public:
CPochodna() : CBazowa(0) { liczba = 0; }
class CA CPochodna(int x) { liczba = x; }
{ };
int liczba;
public: B dzie to w praktyce oznacza wywołanie konstruktora klasy
CA() { liczba = 0; cout << "-> CA(), CA_O::liczba = 0 "; } bazowej z przekazanym mu argumentem 0. Podobnie mo emy post pi
CA(int x) { liczba = x; cout << "->CA(int) "; } w stosunku do klas zagnie d onych:
void operator=(int n) { liczba = n; cout << "->operator "; }
}; [P130.CPP]

class CB #include "iostream.h"


{
110
class CA delete (temp);
{ }
int liczba; return 0;
public: }
CA() { liczba = 0; cout << "-> CA(), CA_O::liczba = 0 "; }
CA(int x) { liczba = x; cout << "->CA(int) "; } Z reguły to kompilator nadaje warto wska nikowi this i to on
void operator=(int n) { liczba = n; cout << "->operator "; } automatycznie dba o przyporz dkowanie pami ci obiektom. Pointer
}; this jest zwykle inicjowany w trakcie działania konstruktora
obiektu.
class CB
{
CA obiekt;
public:
CB() : CA(1) {}
};
LEKCJA 37: KA DY DYSK JEST ZA MAŁY, A KA DY PROCESOR
main() ZBYT WOLNY...
{ ________________________________________________________________
CB Obiekt; W trakcie tej lekcji dowiesz si , jak komputer dysponuje swoimi
return 0; zasobami w rodowisku tekstowym (DOS).
} ________________________________________________________________

Eksperymentuj c z dwoma powy szymi programami mo esz przekona Truizmy u yte w tytule maj znaczy , e "zasoby najlepszego
si , jak przebiega przekazywanie parametrów pomi dzy nawet komputera s ograniczone" i zwykle okazuj si
konstruktorami i obiektami klas bazowych i pochodnych. wystarczaj ce tylko do pewnego momentu. Najbardziej newralgiczne

JESZCZE RAZ O WSKA NIKU *this. zasoby to:

Szczególnie wa nym wska nikiem przy tworzeniu klas pochodnych i * czas mikroprocesora i
funkcji operatorowych mo e okaza si pointer *this. Oto * miejsce w pami ci operacyjnej.
przykład listy.
Tworzone przez nas programy powinny wystrzega si zatem
[P131.CPP] najci szych grzechów:

# include "string.h" * nie pozwala mikroprocesorowi na słodkie nieróbstwo;


# include "iostream.h"
Rzadko uzmysławiamy sobie, e oczekiwanie na naci ni cie
class CLista klawisza przez u ytkownika (czasem po przeczytaniu napisu na
{ ekranie) trwa sekundy (1, 2, .... czasem 20), a ka da sekunda
private: lenistwa PC to stracone miliony cykli mikroprocesora.
char *poz_listy;
CLista *poprzednia; * oszcz dnie korzysta z pami ci dyskowej, a szczególnie
public: oszcz dnie z pami ci operacyjnej RAM.
CLista(char*);
CLista* Poprzednia() { return (poprzednia); }; MODELE PAMI CI IBM PC.
void Pokazuj() { cout << '\n' << poz_listy; }
void Dodaj(CLista&); Jak zapewne wiesz, Twój PC mo e mie :
~CLista() { delete poz_listy; }
}; * pami ROM (tylko do odczytu),
* konwencjonaln pami RAM (640 KB),
CLista::CLista(char *s) * pami rozszerzon EMS i XMS,
{ * pami karty sterownika graficznego ekranu (np. SVGA-RAM),
poz_listy = new char[strlen(s)+1]; * pami Cache dla buforowania operacji dyskowych.
strcpy(poz_listy, s);
poprzednia = NULL; Najcz ciej stosowane modele pami ci to:
}
* Small - mały,
void CLista::Dodaj(CLista& obiekt) * Medium - redni,
{ * Compact - niewielki (tu mam w tpliwo , mo e "taki sobie" ?),
obiekt.poprzednia = this; * Large - du y,
} * Huge - jeszcze wi kszy, odległy.

main() Dodatkowo mo e wyst pi


{
CLista *ostatni = NULL; * Tiny - najmniejszy.
cout << '\n' << "Wpisanie kropki [.]+[Enter] = Quit \n";
for(;;) Taki podział został spowodowany segmentacj pami ci komputera
{ przez procesory Intel 8086 i podziałem pami ci na bloki o
cout << "\n Wpisz nazwe (bez spacji): "; wielko ci 64 KB. Model Small (Tiny, je li jest) jest najszybszy,
char TAB[70];
cin >> TAB; ale najmniej pojemny. Model Huge - odwrotnie - najpojemniejszy,
if (strncmp(TAB, ".", 1) == 0) break; za to najwolniejszy. Model Tiny powoduje ustawienia wszystkich
CLista *lista = new CLista(TAB); rejestrów segmentowych mikroprocesora na t sam warto
if (ostatni != NULL) (pocz tek tej samej stronicy pami ci) i umieszczenie wszystkich
ostatni->Dodaj(*lista); zasobów programu wewn trz wspólnego obszaru pami ci o wielko ci
ostatni = lista; nie przekraczaj cej 64 KB. Wszystkie skoki s wtedy "krótkie", a
}
wszystkie pointery (adresy) 16-bitowe. Kompilacja z
for(; ostatni != NULL;) zastosowaniem modelu Tiny pozwala uzyska program wykonywalny w
{ wersji *.COM (a nie *.EXE). Ale niestety nie wszystkie programy
ostatni->Pokazuj(); mieszcz si w 64 KB. W modelu Small segment kodu jest jeden
CLista *temp = ostatni; (kod max. 64 K) i segment danych te tylko jeden (dane max. 64
ostatni = ostatni->Poprzednia(); K), ale s to ju dwa ró ne segmenty. Zestawienia
111
najwa niejszych parametrów poszczególnych modeli pami ci void main()
przedstawia tabelka poni ej: {
clrscr();
Modele pami ci komputera IBM PC. printf("Funkcja zwraca : %d", bioskey(1));
________________________________________________________________ printf("\n Nacisnij klawisz ! \n");
while (!bioskey(1));
Model Segment kodu Segment danych *dp *cp printf("Funkcja zwrocila: %c", bioskey(1));
________________________________________________________________ printf("\nKod: %d", (char)bioskey(1));
...
Tiny 1 1 (CS = DS) 16 bit 16 bit
Small 1 1 16 bit 16 bit A to jeszcze inny sposób korzystania z tej bardzo przydatnej
Medium wiele 1 16 bit 32 bit funkcji, tym razem z innymi parametrami:
Compact 1 wiele 32 bit 16 bit
Large wiele wiele 32 bit 32 bit /* Funkcja z parametrem (0) zwraca kod klawisza: ------ */
Huge wiele wiele 32 bit 32 bit
________________________________________________________________ klawisz = bioskey(0);

*dp - data pointer - wska nik do danych (near/far) /* Funkcja sprawdza stan klawiszy specjalnych --------- */
*cp - code pointer - wska nik do kodu.
Large - kod + dane = max. 1 MB. modyfikatory = bioskey(2);
Huge - kod = max. 1 MB, wiele segmentów danych po 64 K ka dy. if (modyfikatory)
{
Wynikaj ce z takich modeli pami ci kwalifikatory near, far, huge printf("\n");
if (modyfikatory & RIGHT) printf("RIGHT");
dotycz ce pointerów w C++ nie s akceptowane przez standard ANSI if (modyfikatory & LEFT) printf("LEFT");
if (modyfikatory & CTRL) printf("CTRL");
C (poniewa odnosz si tylko do IBM PC i nie maj charakteru if (modyfikatory & ALT) printf("ALT");
uniwersalnego). Trzeba tu zaznaczy , e typ wska nika jest przez printf("\n");
}
kompilator przyjmowany domy lnie (automatycznie) zgodnie z /* drukujemy pobrany klawisz */
wybranym do kompilacji modelem pami ci. Je li poruszamy si if (isalnum(klawisz & 0xFF))
wewn trz niewielkiego obszaru pami ci, mo esz "forsowa " bli szy printf("'%c'\n", klawisz);
else
typ pointera, przyspieszaj c tym samym działanie programów: printf("%#02x\n", klawisz);
}
huge *p;
... Nale y tu zwróci uwag , e funkcje kbhit() i bioskey() nie
near *ptr; //Bliski pointer dokonuj czyszczenia bufora klawiatury. Identyfikuj znak
... (znaki) w buforze, ale pozostawiaj bufor w stanie niezmienionym
near int Funkcja(...) //Bliska funkcja
{ do dalszej obróbki. Zwró uwag , e funkcja getch() mo e
... oczekiwa na klawisz w niesko czono . Sprawdzi szybciej, czy
} u ytkownik nacisn ł ju cokolwiek mo esz np. tak:
#define ILE (1024*640)
if (kbhit()) ...; if (!kbhit()) ...;
near unsigned int Funkcja(void)
{ while (!bioskey(1)) ... if (bioskey(1)) ...;
huge char *ptr; // tu długi pointer jest niezb dny
long suma = 0; Inn wielce przydatn "szybk " funkcj jest getch(). Oto
for (p = 0; p < ILE; p++) suma += *p; praktyczny przykład pobierania i testowania naci ni tych
return (suma); klawiszy klawiatury.
}
[P131.CPP]
Zarówno zadeklarowanie funkcji jako bliskiej (near), jak i jako
statycznej (static) powoduje wygenerowanie uproszczonej # include "stdio.h"
sekwencji wywołania funkcji przez kompilator. Daje to w efekcie # include "conio.h"
mniejszy i szybszy kod wynikowy.
char z1, z2;
IDENTYFIKACJA KLAWISZY.
void Odczyt(void)
Znane Ci z pliku <stdio.h> i <conio.h> "klasyczne" funkcje {
obsługi konsoli maj pewne zalety. Korzystanie z klasycznych, z2 = '\0';
nieobiektowych mechanizmów powoduje z reguły wygenerowanie z1 = getch();
znacznie krótszego kodu wynikowego. Funkcje scanf() i gets() if (z1 == '\0') z2 = getch();
wymagaj wci ni cia klawisza [Enter]. Dla szybkiego dialogu z }
komputerem znacznie bardziej nadaj si szybsze getch() i
kbhit(). Poniewa klawiatura zawiera tak e klawisze specjalne main()
(F1 ... F10, [Shift], [Del], itp.), pełn informacj o stanie {
klawiatury mo na uzyska za po rednictwem funkcji bioskey(), clrscr();
korzystaj cej z przerywania BIOS Nr 16. Oto krótki przykład printf("\nKropka [.] = Quit");
zastosowania funkcji bioskey(): printf("\nRozpoznaje klawisze [F1] ... [F3] \n\n");

#include "bios.h" for (;;)


#include "ctype.h" {
#include "stdio.h" while(!kbhit());
#include "conio.h" Odczyt();
if (z1 == '.') break;
# define CTRL 0x04 if (z1 != '\0') printf("\nZnak: %c", z1);
# define ALT 0x08 else
# define RIGHT 0x01 switch (z2)
# define LEFT 0x02 {
case ';' : printf("\n F1"); break;
int klawisz, modyfikatory; case '<' : printf("\n F2"); break;
112
case '=' : printf("\n F3"); break;
default : printf("\n Inny klawisz specjalny!"); for (; y1 < y2; y1++) { gotoxy(x1, y1);
} for (k = x1; k < x2; k++)
} {
return 0; asm MOV AL, znak
} asm INT 29H
}
Klawisze specjalne powoduj wygenerowanie dwubajtowego kodu }
(widzianego w powy szym przykładowym programie jako dwa }
jednobajtowe znaki z1 i z2). Funkcja getch() pobiera te bajty z
bufora klawiatury kolejno jednocze nie czyszcz c bufor. W [Z]
przypadku klawiszy specjalnych pierwszy bajt jest zerowy (NULL, ________________________________________________________________
'\0', 00h), co jest sprawdzane w programie. A oto tabela kodów 1. Opracuj program pozwalaj cy porówna szybko wyprowadzania
poszczególnych klawiszy: danych na ekran monitora ró nymi technikami (cout, puts(),
printf(), asm).
Kody klawiszy klawiatury IBM PC. 2. Porównaj wielko plików wynikowych .EXE powstaj cych w
________________________________________________________________ ró nych wariantach z poprzedniego zadania.
________________________________________________________________
Klawisze Kody ASCII (dec)
________________________________________________________________
LEKCJA 38: O C++, Windows i małym Chi czyku.
Home G 71 (00:47h) '\0', 'G' czyli:
End O 79 (00:4Fh) '\0', 'O' KTO POWIEDZIAŁ, E PROGRAMOWANIE DLA WINDOWS JEST
PgUp I 73 TRUDNE?!!!
PgDn Q 81
Ins R 82 Jak wiat wiatem ludzie przekazuj sobie s dy, opinie,
Del S 83 pogl dy... W ci gu naszej nowo ytnej ery wymy lono ju wiele
F1 ; 59 opinii, które kr yły przez dziesi cio- i stulecia gwarantuj c
F2 ... F10 <, ... D 60, ... 68 jednym komfort psychiczny (- Ja przecie mam swoje zdanie na ten
Shift + F1 T 84
... temat!), innym daj c pozory wiedzy (- Tak, ja co o tym wiem,
Shift + F10 ] 93 słyszałem, e...). ywotno takich wier prawd, uproszcze ,
Ctrl + F1 ^ 94 uogólnie , czy wr cz kompletnie bzdurnych mitów była i jest
... zadziwiaj ca.
Ctrl + F10 f 103
Alt + F1...F10 h, ... q 104, ... 113 Podejm tu prób obalenia funkcjonuj cego powszechnie przes du,
Alt + 1...9 x, ... (?) 120, ... 128 e
Alt + 0 (?) 129
- Programowanie dla Windows jest trudne. (BZDURA!!!)
Strzałki kursora:
LeftArrow K 75 Aby nie zosta całkowicie pos dzonym o herezj , przyznaj na
RightArrow M 77 wst pie dwa bezsporne fakty.
UpArrow H 72 Po pierwsze, wielu powszechnie szanowanych ludzi zrobiło wiele,
DownArrow P 80 by ju pierwszymi przykładami (zwykle na co najmniej dwie
strony) skutecznie odstraszy adeptów programowania dla Windows.
Ctrl + PgDn v 118
Ctrl + PgUp (?) 132 No bo jak tu nie straci zapału, gdy program pisz cy tradycyjne
Ctrl + Home w 119 "Hello World." w okienku ma 2 - 3 stronice i jeszcze zawiera
Ctrl + End u 117 kilkadziesi t zupełnie nieznanych i niezrozumiałych słów
________________________________________________________________ (skrótów? szyfrów?).
Po drugie, wszystko jest trudne, gdy brak odpowiednich narz dzi.

Wyprowadzanie znaków na ekran mo na przeprowadzi szybciej Nawet odkr cenie małej rubki bywa niezwykle trudne, gdy do
posługuj c si przerywaniem DOS INT 29H. Drukowanie na ekranie w dyspozycji mamy tylko młotek... Napisanie aplikacji okienkowej
przy pomocy Turbo Pascal 6, Turbo C, Quick C, czy QBASIC
trybie tekstowym przebiega wtedy szybciej ni robi to rzeczywi cie BYŁO nadwyraz trudne.
standardowe funkcje <stdio.h>, <conio.h>, czy <iostream.h>.
Poni ej prosty przykład praktyczny wykorzystania przerywania I tu wła nie dochodzimy do sedna sprawy:
29H:
(!!!) Programowanie dla Windows BYŁO trudne (!!!)
[P132.CPP]

# include <stdlib.h> UWAGA!


# include <conio.h> Pierwsza typowa aplikacja dla Windows napisana w BORLAND C++ 3/4
# pragma inline
mo e wygl da np. tak:
void SpeedBox(int, int, int, int, char);
#include <iostream.h>
main()
{ void main()
clrscr(); {
for (; !kbhit(); ) cout <<"Pierwsza Aplikacja dla Windows";
{ }
int x = rand() % 40;
int y = rand() % 12; I ju !
SpeedBox(x, y, (80 - x), (24 - y), (' ' + x % 50)); Niedowiarek zapyta: - I TAKIE CO CHODZI POD Windows???
} TAK!.
return 0;
} W BORLAND C++ 3+ ... 4+ wystarczy dobra parametry pracy
kompilatora i zamiast aplikacji DOS-owskiej otrzymamy program
void SpeedBox(int x1, int y1, int x2, int y2, char znak) wyposa ony we własne okienko, paski przewijania w okienku,
{ klawisze, menu, ikonk , itp., itd.!
int k;
113
O MAŁYM CHI CZYKU, czyli - NAJLEPIEJ ZACZ OD POCZ TKU...
z menu Plik) zobaczymy tradycyjny pulpit (desktop)
Istnieje jedyny sprawdzony sposób rozwi zywania zagadnie zintegrowanego rodowiska IDE - podobny do Turbo Pascala, z
takiego typu - tzw. METODA MAŁEGO CHI CZYKA. tradycyjnym układem głównego menu i okien roboczych.
WSZYSCY DOSKONALE WIEDZ , e j zyk chi ski jest szalenie trudny.
Skoro mamy zaj si tworzeniem aplikacji dla Windows- zaczynamy
Dlatego te mimo ogromnego wysiłku prawie NIKOMU nie udaje si
biegle nauczy chi skiego - z jednym wyj tkiem - wyj tkiem od rozwini cia menu Options i wybieramy z menu rozkaz
małego Chi czyka. Dlaczego? To proste. Mały Chi czyk po prostu o Application... . Rozwinie si okienko dialogowe. Przy pomocy
klawiszy mo emy wybra sposób generowania aplikacji - dla DOS,
tym nie wie! I dlatego ju po kilku latach doskonale swobodnie dla Windows lub tworzenie bibliotek statycznych .LIB, czy te
włada tym bodaj najtrudniejszym j zykiem wiata! dynamicznych .DLL. Wybieramy oczywi cie wariant [Windows EXE].

Je li zatem komu udało si przekona Ci , szanowny Czytelniku, [!!!]UWAGA!


e programowanie dla Windows jest trudne, namawiam Ci na ________________________________________________________________
dokonanie pewnego eksperymentu intelektualnego. Spróbuj
zapomnie , e masz ju na ten temat jakie zdanie i wczuj si w Struktura podkatalogów i wewn trzna organizacja pakietów 3.0,
rol małego Chi czyka. Co roku udaje si to wielu milionom 3.1, 4 i 4.5 ZNACZNIE SI RÓ NI.
przyszłych ekspertów od wszystkich mo liwych j zyków wiata (C++ ________________________________________________________________

jest chyba znacznie łatwiejszy do chi skiego).


Skoro ustawili my ju poprawnie najwa niejsze dla nas parametry
BORLAND C++ aby dopomóc programi cie w jego ci kiej pracy konfiguracyjne - mo emy przyst pi do uruchomienia pierwszej
tworzy (cz sto automatycznie) wiele plików pomocniczych. Krótkie aplikacji dla Windows.

zestawienie plików pomocniczych zawiera tabela poni ej. PIERWSZA APLIKACJA "specjalnie dla Windows".

Najwa niejsze pliki pomocnicze w kompilatorach Borland/Turbo Tryb post powania z kompilatorem BORLAND C++ 3.0/3.1 b dzie w
C++. tym przypadku dokładnie taki sam, jak np. z Turbo Pascalem.
________________________________________________________________ Wszystkich niezb dnych zmian w konfiguracji kompilatora ju
dokonali my. Kompilator "wie" ju , e chcemy uzyska w efekcie
Rozszerzenie Przeznaczenie Gdzie/Uwagi aplikacj dla Windows w postaci programu .EXE. Mo emy zatem
________________________________________________________________
* Wyda rozkaz File | New
.C .CPP Teksty ródłowe \EXAMPLES \SOURCE
(ASCII) (przykłady) (kod ródł.) Pojawi si nowe okienko robocze. Zwró uwag , e domy lne
.H .HPP .CAS Pliki nagłówkowe \INCLUDE rozszerzenie jest .CPP, co powoduje domy lne zastosowanie
(ASCII) kompilatora C++ (a nie kompilatora C - jak w przypadku plików z
.PRJ .DPR .IDE Projekty \EXAMPLES \SOURCE rozszerzeniem .C). Mo esz to oczywi cie zmieni , je li zechcesz,

.TAH .TCH .TDH Help posługuj c si menu Options | Compiler | C++ options... (Opcje |
.TFH .HLP .HPJ
.RTF Kompilator | Kompilator C albo C++). W tym okienku dialogowym
masz sekcj :
.DSK .TC .CFG Konfiguracyjne
.DSW .BCW Use C++ Compiler: Zastosuj Kompilator C++
(zamiast kompilatora C)
.DEF .RC .RES Zasoby i definicje (.) CPP extention - tylko dla rozszerzenia .CPP
.RH .ICO .BMP ( ) C++ always - zawsze

.BGI .CHR .RTF Grafika DOS, fonty * Wybierz rozkaz Save as... z menu File

.MAK .NMK .GEN Pliki instrukta owe dla Pojawi si okienko dialogowe "Save File As" (zapis pliku pod
MAKEFILE MAKE.EXE wybran nazw i w wybranym miejscu).

.ASM .INC .ASI Do asemblacji (ASCII) * Do okienka edycyjnego wpisz nazw pliku i pełn cie k
dost pu - np. A:\WIN1.CPP lub C:\C-BELFER\WIN1.CPP
.RSP Instrukta owy dla TLINK
Zmieni si tytuł roboczego okna z NONAME00 na wybran nazw
.LIB .DLL Biblioteki
Mo emy wpisa tekst pierwszego programu:
.TOK Lista słów zastrze onych (reserved words)
(ASCII) [P133.CPP]
.DRV Sterowniki (drivery)
#include <iostream.h>
.OVL Nakładki (overlay)
void main()
.SYM Plik ze skompilowanymi (Pre - compiled) {
plikami nagłówkowymi. cout << " Pierwsza Aplikacja " << " Dla MS Windows ";
________________________________________________________________ }

Po wpisaniu tekstu dokonujemy kompilacji.


wiadome i umiej tne wykorzystanie tych plików mo e znacznie
ułatwi i przyspieszy prac . * Wybierz rozkaz Compile to OBJ z menu Compile.
* Wybierz rozkaz Link lub Make z menu Compile.
Po wprowadzeniu na rynek polskiej wersji Windows 3.1 okienka W okienku komunikatów (Messages) powinien pojawi si w trakcie
zacz ły coraz cz ciej pojawia si w biurach i domach, i konsolidacji komunikat ostrzegawczy:
stanowi coraz cz ciej naturalne (wła nie tak, jak chi ski dla
Chi czyków) rodowisko pracy dla polskich u ytkowników PC. Nie *Linker Warning: No module definition file specified:
pozostaje nam nic innego, jak po prostu zauwa y i uzna ten using defaults
fakt.
Oznacza to: Konsolidator ostrzega, e brak specjalnego
Po uruchomieniu Borland C++ (2 * klik myszk , lub rozkaz Uruchom stowarzyszonego z plikiem .CPP tzw. pliku definicji sposobu
114
wykorzystania zasobów Windows - .DEF. Program linkuj cy - Nasza aplikacja wyposa ona jest w menu systemowe. Mo esz
zastosuje warto ci domy lne. rozwin menu i wybra z menu jeden z kilku rozkazów.

Je li w IDE wersji kompilatora przeznaczonej dla rodowiska DOS Je li nie pisałe jeszcze programów dla Windows - mo esz by
spróbujesz uruchomi program WIN1.EXE w tradycyjny sposób - troch zaskoczony. Gdzie w naszym programie jest napisane np. -
rozkazem Run z menu Run - na ekranie pojawi si okienko z co powinno znale si w menu??? Odpowied jest prosta -
komunikatem o bł dzie (Error message box): nigdzie. Podobnie jak programy tworzone dla DOS korzystaj w
niejawny sposób z zasobów systemu - standardowych funkcji DOS,
Can't run a Windows EXE file standardowych funkcji BIOS, przerywa , itp - tak programy
D:\WIN1.EXE tworzone dla Windows mog w niejawny sposób korzysta z zasobów
rodowiska Windows - standardowego menu, standardowych okien,
[ OK ] standardowych klawiszy, itp.. Takie zasoby udost pniane przez
rodowisko programom aplikacyjnym nazywaj si interfejsem API
czyli: "Nie mog uruchomi pliku EXE dla Windows". (Application Program Interface). Poznałe ju API DOS'a - jego
przerywania i funkcje. Interfejs Windows nazywa si "Windows
Jak ju napisałem wcze niej, kompilatory C++ w pakietach 3.0/3.1 API" i to z jego gotowych funkcji wła nie korzystamy.

maj swoje ulubione specjalno ci: Uruchom program wielokrotnie (min. 4 razy). Wykonaj 4 - 6 razy
czynno ci oznaczone powy ej trzema gwiazdkami *** . Poniewa nie
Borland C++ - jest zorientowany na współprac z DOS
Turbo C++ - jest zorientowany na współprac z Windows za dali my, by okno programu było zawsze "na wierzchu" (on top)

w wersji 3.1: - po ka dym kolejnym uruchomieniu (nie musisz nic robi -


nast pi to automatycznie - zadba o to Mened er Windows)
BCW - dla Windows poprzednie okno programu zniknie. Je li po czwartym (pi tym)
BC - dla DOS uruchomieniu programu zredukujesz okno Mened era Programów do
ikony (np. [-] i "do ikony" z menu systemowego) - oka e si , e
nie oznacza to jednak, e b d kłopoty z prac naszego programu! "pod spodem" stale wida kaskad okien naszej aplikacji WIN1.EXE

Wyjd z IDE BC/BCW. (patrz rys. poni ej). Na rysunkach poni ej przedstawiono kolejne

Z poziomu Mened era Programów mo esz uruchomi swój program stadia pracy z nasz PIERWSZ APLIKACJ .
rozkazem Plik | Uruchom. Do okienka musisz oczywi cie wpisa
poprawn cie k do pliku WIN1.EXE (czyli katalog wyj ciowy Aplikacja WIN1.EXE została wyposa ona w ikonk systemow (znane
kompilatora Borland C++). Ci okienko). Ikonka jest transparentna (półprzezroczysta) i
mo emy j tak e metod drag and drop przenie w dowolne miejsce
*** Wybierz z menu głównego Mened era Programów (pasek w górnej
cz ci ekranu) rozkaz Plik. Rozwinie si menu Plik. - np. do roboczego okna naszej aplikacji. Zwró uwag tak e na
*** Wybierz z menu Plik rozkaz Uruchom. Pojawi si okienko towarzysz cy nazwie programu napis "inactive" (nieaktywna).
dialogowe uruchamiania programów. Wpisz pełn cie k Chodzi o to, e program zrobił ju wszystko, co miał do
dost pu do programu - np.: zrobienia i zako czył si . DOS doło yłby standardowo funkcj
zwolnienia pami ci i zako czył program. W Windows niestety
D:\KATALOG\WIN1.EXE okienko nie zamknie si samo w sposób standardowy. W Windows,
jak wiesz, mo emy mie otwarte jednocze nie wiele okien
i "kliknij" myszk na klawiszu [OK] w okienku. programów a aktywne jest (tylko jedno) zawsze to okno, do
którego przeka emy tzw. focus. Okno to mo na rozpozna po
Na ekranie pojawi si okno naszej aplikacji. Okno jest ciemnym pasku tytułowym. Wła nie z przyj cia takiego sposobu
wyposa one w: podziału zasobów Windows pomi dzy aplikacje wynika skutek
praktyczny - okno nie zamknie si automatycznie po zako czeniu
- Pasek z tytułem (Caption) - np.: A:\WIN1.EXE ; programu - lecz wył cznie na wyra ne yczenie u ytkownika. API
- Klawisz zamykania okna i rozwini cia standardowego menu (tzw. Windows zawiera wiele gotowych funkcji (np. CloseWindow() -
menu systemowego Windows) - [-] ; zamknij okno, DestroyWindow() - skasuj okno i in.), z których
- Paski przewijania poziomego i pionowego; mo e skorzysta programista pisz c aplikacj . Nie jeste my wi c
- Klawisze MINIMIZE i MAXIMIZE (zmniejsz do ikonki | powi ksz na całkiem bezradni.

cały ekran) w prawym górnym naro niku okna; Spróbuj skompilowa w opisany wy ej sposób i uruchomi pierwsz
aplikacj w takiej wersji:
Program znajduje si w wersji .EXE na dyskietce doł czonej do
ksi ki. Mo esz uruchomi go z poziomu Mened era Plików (Windows #include <stdio.h>

File Manager), Mened era Programów (Windows Program Manager) lub void main()
{
z DOS-owskiego wiersza rozkazów (DOS Command Line): printf(" Pierwsza Aplikacja \n Dla MS Windows ");
}
C\>WIN A:\WIN1.EXE[Enter]
Jak łatwo si przekona , całkowicie klasyczny, w pełni
Co mo e nasza pierwsza aplikacja? nieobiektowy program WIN1.C b dzie w Windows działa dokładnie
tak samo. Nasze aplikacje nie musz bynajmniej by całkowicie
- Typow dla Windows technik drag and drop - poci gnij i upu obiektowe, chocia zastosowanie obiektowej techniki
mo esz przy pomocy myszki przesuwa okno naszej pierwszej programowania pozwala zmusi nasz komputer do zdecydowanie
aplikacji po ekranie ("ci gn c" okno za pasek tytułowy). wydajniejszego działania.

- Ci gn c ramki b d naro niki mo esz zmienia wymiary okna w PODSUMUJMY:


sposób dowolny.
* Je li korzystamy wył cznie ze standardowych zasobów rodowiska
- Posługuj c si paskami przewijania mo esz przewija tekst w
oknie w pionie i w poziomie. Windows, tworzenie aplikacji dla Windows nie musi by wcale
trudniejsze od tworzenia aplikacji DOS'owskich.
- Mi esz zredukowa okno do ikonki. * Czy aplikacja ma by przeznaczona dla DOS, czy dla Windows
mo emy zdecydowa "w ostatniej chwili" ustawiaj c odpowiednio
- Mo esz uruchomi nasz aplikacj wielokrotnie i mie na robocze parametry kompilatora C++:
ekranie kilka okien programu WIN1.EXE. Options | Applications... | DOS standard
albo
115
Options | Applications... | Windows EXE ________________________________________________________________
* Aplikacje skompilowane do wersji DOS'owskiej mo emy uruchamia

wewn trz kompilatora DOS'owskiego rozkazem Run | Run. Dla przykładu spróbujmy skompilowa i uruchomi w rodowisku
* Aplikacje skompilowane ( ci lej - skonsolidowane) do wersji Windows jeden z wcze niejszych programów - tabliczk mno enia.
okienkowej mo emy uruchamia wewn trz Windows z poziomu Zwró uwag na doł czony dodatkowy plik WINDOWS.H i nowy typ
Mened era Plików b d Mened era Programów rozkazem Uruchom z wska nika. Zamiast zwykłego
menu Plik.
* Dodatkowe pliki nagłówkowe .H i biblioteki .LIB .DLL znajduj char *p ...
si w katalogach LPSTR p ...
\BORLANDC\INCLUDE
\BORLANDC\OWL\INCLUDE LPSTR - to Long Pointer to STRing - daleki wska nik do ła cucha
\BORLANDC\LIB tekstowego. Jest to jeden z "ulubionych" typów Windows.
\BORLANDC\OWL\LIB
cie ki dost pu do tych katalogów nale y doda do roboczych /* WIN2.CPP: */
katalogów kompilatora w okienku Options | Directories... /* - Tablica dwuwymiarowa
* Aplikacje nie korzystaj ce z funkcji Windows API nie musz - Wskazniki do elementów tablicy */
doł cza okienkowych plików nagłówkowych. Je li jednak
zechcemy zastosowa funkcje i dane (stałe, struktury, #include <windows.h>
obiekty, itp.) wchodz ce w skład: #include <iostream.h>
- Windows API #include <stdio.h>
- Windows Stock Objects - obiekty "ze składu Windows"
- biblioteki klas Object Windows Library int T[10][10], *pT, i, j, k;
nale y doł czy odpowiedni plik nagłówkowy: char spacja = ' ';
#include <windows.h>
#include <windowsx.h> LPSTR p1 = " TABLICZKA MNOZENIA (ineksy)\n";
#include <owl.h> LPSTR p2 = " Inicjujemy i INKREMENTUJEMY wskaznik:\n";
LPSTR p3 = "... nacisnij cokolwiek (koniec)...";
TYPOWE BŁ DY I KŁOPOTLIWE SYTUACJE:
void main()
* Nale y pami ta o ustawieniu wła ciwych katalogów roboczych {
kompilatora Options | Directories... printf(p1);
* Przy bardziej skomplikowanych aplikacjach mo e wyst pi for (i = 0; i < 10; i++)
potrzeba dobrania innego (zwykle wi kszego) modelu pami ci. {
Modelem domy lnym jest model Small. Inne parametry pracy for (j = 0; j < 10; j++)
kompilatora ustawia si podobnie za pomoc menu Options. { T[i][j] = (i + 1)*(j + 1);
if (T[i][j] < 10) cout << T[i][j] << spacja << spacja;
else
cout << T[i][j] << spacja;
LEKCJA 39: KORZYSTAMY ZE STANDARDOWYCH ZASOBÓW }
Windows. cout << '\n';
________________________________________________________________ }
W trakcie tej lekcji dowiesz si , jak korzysta z zasobów printf(p2);
Windows bez potrzeby wnikania w wiele szczególów technicznych pT = &T[0][0];
interfejsu aplikacji - Windows API. for (k = 0; k < 10*10; k++)
________________________________________________________________ {
if (*(pT+k) < 10) cout << *(pT + k) << spacja << spacja;
Poniewa nasze programy mog korzysta ze standardowych zasobów else
Windows, na pocz tku b dziemy posługiwa si okienkami cout << *(pT + k) << spacja;
standardowymi. Pocz wszy od aplikacji WIN3.EXE "rozszerzymy if ((k + 1)%10 == 0) cout << '\n';
ofert " do dwu podstawowych typów: }
printf(p3);
* Standardowe główne okno programu (Default main window). getchar();
To takie wła nie okno, jakie dostały nasze pierwsze aplikacje }
WIN1.EXE.
* Okienkiem dialogowym (Dialog box), Wybrali my dla aplikacji standardowe główne okno (Main Window),
a dokładniej najprostszym rodzajem okienek dialogowych - tzw. poniewa istnieje potrzeba pionowego przewijania okna w celu
okienkami komunikatów - Message Box. przejrzenia pełnego wydruku obu tablic.

Zastosowanie okienka dialogowego pozwoli nam na wprowadzenie do [???] Dlaczego ten tekst jest nierówny???
akcji klawiszy (buttons). ________________________________________________________________
Niestety, znaki w trybie graficznym Windows nie maj stałej
________________________________________________________________ szeroko ci (jak było to w trybie tekstowym DOS). Niektóre
aplikacje przeniesione ze rodowiska DOS b d sprawia kłopoty.
UWAGA: ________________________________________________________________
Niestety nie wszystkie tradycyjne funkcje typu printf(),
scanf(), gets() itp. zostały zaimplementowane dla Windows! APLIKACJE DWUPOZIOMOWE.
Pisz c własne programy mo esz przekona si o tym dzi ki opisowi
Zastosujemy teraz najprostszy typ okienka dialogowego - okienko
funkcji w Help. Funkcj nale y odszuka w Help | Index. Oprócz kamunikatów (Message Box), nasze nast pne aplikacje mog by ju
przykładu zastosowania znajdziesz tam tabelk typu:
nie jedno- a dwupoziomowe. Typowe post powanie okienkowych
DOS Unix Windows ANSI C C++ Only aplikacji bywa takie:
cscanf Yes
fscanf Yes Yes Yes Yes * program wy wietla w głównym oknie to, co ma do powiedzenia;
scanf Yes Yes Yes * aby zadawa pytania stosuje okienka dialogowe, b d okienka
sscanf Yes Yes Yes Yes komunikatów;
* funkcja okienkowa (u nas MessageBox()) zwraca do programu
[Yes] oznacza "zaimplementowana". Dlatego wła nie w dalszych decyzj u ytkownika;
programach przykładowych dla wersji 3.0 nale y np. stosowa np. * program główny analizuje odpowied i podejmuje w głównym oknie
makro getchar() zamiast tradycyjnego getch() zaimplementowane
dla Windows ju w wersji BC++ 3.0. stosowne działania.

116
Prze led my ewolucj powstaj cej w taki sposób aplikacji. - główne okno aplikacji
- dwa okienka komunikatów (Dopisywanie i KONIEC)
STADIUM 1. Tekst w głównym oknie. - jeden klawisz - [OK]

Zaczniemy tworzenie naszej aplikacji tak: Ła cuchy tekstowe przeznaczone do pola tekstowego okienka
pobierane s z tablicy napisy[4][20] (cztery napisy po max. 20
/* WINR1.CPP: */ znaków) przy pomocy wska nika p2. MB_OK to predefiniowana stała
/* Stadium 1: Dwa okienka w jednym programie */ (Message Box OK - key identifier - identyfikator klawisza [OK]
dla okienek komunikatów).
# include <stdio.h>
# include <windows.h> /* WINR3.CPP: */
/* Stadium 3: Dwa okienka steruj p tl */
char *p1 = "Teraz dziala \n funkcja \n MessageBox()";
char *p2 = "START"; # include <windows.h>
int wynik; # include <stdio.h>

void main() char *p2, *p1 = "Dopisywanie:";


{ char napisy[4][20] = { "Borland ", "C++ ", "dla ", "Windows" };
printf(" Start: Piszemy w glownym oknie \n");
printf(" ...nacisnij cosik..."); void main()
getchar(); {
MessageBox(0, p1, p2, 0); printf("\n\n\n Hello World dla WINDOWS!");
printf("\n\n\n Hello World dla WINDOWS!"); printf("\n AUTOR: ...................");
printf("\n\t...dowolny klawisz... ");
getchar(); for( int i = 0; i < 4; i++)
} {
p2 = &napisy[i][0];
Mogliby my zrezygnowa z metod typowych dla aplikacji DOSowskich if( MessageBox(0, p2, p1, MB_ICONSTOP | MB_OKCANCEL) == IDOK)
printf("\n %s", napisy[i]);
i zatrzymania (i zapytania) makrem getchar() (odpowiednik else
getch() dla Windows). To działanie mo emy z powodzeniem printf("\n ...?");
powierzy funkcji okienkowej MessageBox(). Funkcja MessageBox() }
pobiera cztery parametry: MessageBox(0, "I to juz \n wszystko...", "KONIEC", MB_OK);
}
int Message Box(hwndParent, lpszText, lpszTitle, Style)

HWND hwndParent - identyfikator macie ystego okna (głównego okna W tym stadium stosujemy:

aplikacji). Poniewa nie wiemy póki co pod jakim numerem - główne okno aplikacji
(identyfikatorem) Windows zarejestruj nasz aplikacj - - dwa okienka komunikatów (Dopisywanie i KONIEC)
wpisujemy 0 - dwa klawisze - [OK] i [Anuluj] (OK/Cancel)
LPCSTR lpszText - daleki wska nik do ła cucha tekstowego - jedn ikon [STOP]
wewn trz okienka.
LPCSTR lpszTitle - daleki wska nik do ła cucha tekstowego - Zwró uwag , e tym razem sprawdzamy, który klawisz wybrał
tytułu okienka komunikatu. u ytkownik w okienku. Odbywa si to tak:
UINT Style - UINT = unsigned int; numer okre laj cy zawarto
okienka. if( MessageBox(0, p2, p1, MB_ICONSTOP | MB_OKCANCEL) == IDOK)
int Return Value - identyfikator klawisza, który wybrał
u ytkownik w okienku komunikatu. IDOK jest predefiniowan stał - kodem klawisza [OK] (ang.
OK-key IDentifier - identyfikator klawisza OK). Identyfikatory
[!!!] UWAGA ró nych zasobów Windows s liczbami całkowitymi. Je li jeste
________________________________________________________________ dociekliwy Czytelniku, mo esz sprawdzi - jaki numer ma klawisz
Deklaracje wska ników do tekstów powinny wygl da tak: [OK] rozbudowuj c tekst aplikacji np. tak:
LPCSTR p1 = "Napis1", p2 = "Tekst2";
ale C++ mo e samodzielnie dokona forsowania typów i zamieni int Numer;
typ char* na typ LPCSTR (lub LPSTR). ...
________________________________________________________________ Numer = MessageBox(0, p2, p1, MB_ICONSTOP | MB_OKCANCEL);
printf("\nKlawisz [OK] ma numer: %d", Numer);
/* WINR2.CPP: */ if(Numer == IDOK) ...
/* Stadium 2: Dwa okienka ze zmienn zawaro ci */
Zwró uwag na sposób wykorzystania zasobów w funkcji
# include <windows.h> MessageBox(). Identyfikatory zasobów, które chcemy umie ci w
# include <stdio.h> okienku s wpisywane jako ostatni czwarty argument funkcji i
mog by sumowane przy pomocy znaku | (ang. ORing), np.:
char *p2, *p1 = "Dopisywanie:";
char napisy[4][20] = { "Borland ", "C++ ", "dla ", "Windows" }; MessageBox(0,..,.., MB_ICONSTOP | MB_OKCANCEL);

void main() oznacza umieszczenie ikony STOP i klawiszy [OK] i [Anuluj]. Kod
{ zwracany przez funkcj mo e by wykorzystywany we wszelkich
printf("\n\n\n Hello World dla WINDOWS!"); konstrukcjach warunkowych (switch, case, for, while, if-else,
printf("\n AUTOR: ..................."); itp.).

for( int i = 0; i < 4; i++) /* WINR4.CPP: */


{ /* Stadium 4: Okienka steruj 2 p tlami, przybywa zasobów. */
p2 = &napisy[i][0];
MessageBox(0, p2, p1, MB_OK); # include <windows.h>
printf("\n %s", napisy[i]); # include <stdio.h>
}
MessageBox(0, "I to juz \n wszystko...", "KONIEC", MB_OK); char *p2, *p1 = "Dopisywanie:";
} char *p3 = "I to by bylo na tyle...\n Konczymy ???";
char *p4 = "UWAGA: KONIEC ?";
W tym stadium stosujemy: char napisy[5][20] = { "Borland ", "C++ ", "dla ", "Microsoft",
"Windows" };
117
"Windows" };
main()
{ main()
printf("\n\n\n Grafoman dla WINDOWS!"); {
printf("\n AUTOR: (jak wyzej)"); cout << "\n\n\n Grafoman dla WINDOWS!";
puts("_____________________________\n"); cout << "\n AUTOR: (jak wyzej)";
cout << "\n_____________________________\n";
do
{ p0 = &tytul[0];
for( int i = 0; i < 5; i++) do
{ {
p2 = &napisy[i][0]; for( int i = 0; i < 5; i++)
if( MessageBox(0, p2, p1, MB_ICONSTOP | MB_OKCANCEL) == IDOK) {
printf("\n %s", napisy[i]); p2 = &napisy[i][0];
else strcat(p0, p2);
printf("\n ...?"); int decyzja = MessageBox(0, p1, p0, MB_ICONHAND |
} MB_ABORTRETRYIGNORE);
} while if (decyzja == IDABORT) break;
(MessageBox(0,p3,p4,MB_ICONQUESTION | else
MB_OKCANCEL)==IDCANCEL); if (decyzja == IDRETRY)
{
return 0; cout << "\n " << napisy[i];
} i--;
}
W tym stadium stosujemy: else
if (decyzja == IDIGNORE)
- główne okno aplikacji {
- dwa okienka komunikatów (Dopisywanie i KONIEC) cout << "\n ...?";
- dwa klawisze - [OK] i [Anuluj] (OK/Cancel) continue;
- dwie ikonki [STOP] i [PYTAJNIK] }
}
Tekst jest przewijany w głównym oknie programu i po zako czeniu } while
roboczej cz ci programu i przej ciu w stan nieaktywny (MessageBox(0, p3, p4, MB_ICONQUESTION | MB_OKCANCEL) ==
(inactive) mo esz przy pomocy paska przewijania pionowego IDCANCEL);
obejrze napisy - histori Twoich zmaga z programem. Zwró return 0;
uwag , e pojemno głównego okna jest ograniczona. Je li }
napisów b dzie zbyt du o, tekst przewini ty poza okno mo e
ulega obci ciu (ang clip on). Zwró równie uwag na W Stadium 5 zmienia si (ro nie) nagłówek okienka komunikatów.
naprzemienne przekazywanie aktywno ci (focus) pomi dzy oknami
aplikacji: UWAGA: Po wyj ciu za ekran nast pi załamanie programu. Program
nie zawiera handlera obsługuj cego przekroczenia
MainWindow <-----> MessageBox dopuszczalnej długo ci.

Warto w tym momencie zwróci uwag na kilka typowych dla Rysunek poni ej przedstawia ró ne stadia działania opisanych
okienkowych aplikacji mechanizmów. powy ej aplikacji.

* Je li naci niemy klawisz na klawiaturze, b d klawisz myszki, Je li postanowisz napisa praktyczn aplikacj dla Windows, jest
obsługa takiego zdarzenia mo e nast powa na dwa sposoby.
Najpierw Windows pobieraj kod klawisza i dokonuj to zwykle program znacznie dłu szy, w którym trzeba przemy le
"kolejkowania" (podobnie jak DOS-owski bufor klawiatury). sposób organizacji p tli, wyra e warunkowych i sposoby
Nast pnie przekazuj kod klawisza aplikacji do obsługi. Je li wykorzystania zasobów.
aplikacja czeka na klawisz i potrafi obsłu y takie zdarzenie
(np. funkcja MessageBox(), b d makro getchar(), czy operator [!!!]UWAGA
cin >> w programie głównym), obsługa zdarzenia zostaje ________________________________________________________________
zako czona. Je li aplikacja nie potrafi obsłu y zdarzenia - Okienka mog by "modalne" i "nie-modlane". Okienko "modalne" to
obsługa przekazywaba jest stadardowym funkcjom obsługi (Event
Handler) Windows. takie okienko, które do momentu jego zamkni cia uniemo liwia
* Kiedy na ekranie pojawia si okienko dialogowe (tu: u ytkownikowi działania w innych oknach (tej samej aplikacji,
komunikatów) zostaje mu przekazany tzw. focus - czyli aktywno . b d innych aplikacji) znajduj cych si na ekranie. W ramach
parametru Styl mo esz stosowa predefiniowane stałe
Naci ni cie [Entera] spowoduje zadziałanie tego klawisza w MB_APPMODAL
okienku, który wła nie ten focus otrzymał (tu zwykle pierwszego MB_TASKMODAL
z lewej). itp.
* je li naci niemy klawisz specjalny, którego obsług w sposób okre laj ce stopie "modalno ci" okienka (na poziomie zadania -
standardowy powinny załatwia Windows - obsługa takiego TASK, aplikacji - APP, itp.).
zdarzenia zostaje przekazana domy lnej funkcji Windows (ang. ________________________________________________________________
Default Event Handler). Tak jest w przypadku klawiszy ze
strzałkami (przewijanie w oknie), [Tab], [Alt]+[F4], itp.
LEKCJA 40: STRUKTURA PROGRAMU PROCEDURALNO -
/* WINR5.CPP: */ ZDARZENIOWEGO
/* Stadium 5: Zmiana wielko ci i nazwy okienka. */ PRZEZNACZONEGO DLA WINDOWS.
________________________________________________________________
# include <windows.h> W trakcie tej lekcji poznasz ogóln budow interfejsu API
# include <iostream.h> Windows i dowiesz si , co z tego wynika dla nas - autorów
# include <string.h> programów przeznaczonych dla Windows.
________________________________________________________________
char tytul[80] = "Dopisywanie: ";
char *p0, *p2; W przeciwie stwie do długich liniowych programów przeznaczonych
char *p1 = "UWAGA: Ponawianie proby \n oznacza: WYDRUKUJE I dla DOS, w naszych programach dla Windows b dziemy pisa co
ZAPYTAM"; na kształt krótkich odcinków programu i przekazywa sterowanie
char *p3 = "I to by bylo na tyle...\n Konczymy ???"; Windows. Jest to bardzo wa na cecha - kod programu jest zwykle
char *p4 = "UWAGA: KONIEC ?"; silnie zwi zany z Windows w taki sposób, e u ytkownik mo e w
char napisy[5][20] = { "Borland ", "C++ ", "dla ", "Microsoft", du ym stopniu decydowa o sposobie (kolejno ci) wykonywania
118
programu. Praktycznie robi to poprzez wybór opcji-klawiszy w w unsigned int (word) słowo
dowolnej kolejno ci. Przy takiej filozofii w dowolnym momencie x,y short x,y coordinate współrz dne x,y (typ: short)
powinni my mie mo liwo przeł czenia si do innego programu ________________________________________________________________
(innego okna) i nasz program powinien (bez zauwa alnej zwłoki)
przekaza sterowanie, nie zagarniaj c i nie marnuj c czasu CPU. O PROGRAMOWANIU PROCEDURALNO - ZDARZENIOWYM DLA
Z tego powodu kod programu powinien by bardzo WINDOWS.
"zmodularyzowany". Ka da sekcja kodu powinna by odseparowana i
ka da, po wykonaniu powinna przekazywa sterowanie do Windows. W proceduralno-sekwencyjnych programach DOS'owskich sterowanie
jest przekazywane mniej lub bardziej kolejno kolejnym
NOTACJA W GIERSKA I NOWE TYPY DANYCH. instrukcjom w taki sposób, jak yczył sobie tego programista. W
Windows program-aplikacja prezentuje u ytkownikowi wszystkie
Tworzenie zdarzeniowych programów dla Windows wymaga kilku dost pne opcje w formie widocznych na ekranie obiektów (visual
wst pnych uwag na temat nowych typów danych. Okienkowe typy s objects) do wyboru przez u ytkownika. Program funkcjonuje zatem
definiowane w plikach nagłówkowych (WINDOWS.H, WINDOWSX.H, według zupełnie innej koncepcji nazywanej "programowaniem
OWL.H zdarzeniowym" (ang. event-driven programming). Mo na powiedzie ,

itp) i maj posta najcz ciej struktury, b d klasy. Typowe e za przebieg wykonania programu nie jest odpowiedzialny tylko
sposoby deklaracji w programach okienkowych s nast puj ce: programista lecz cz tej odpowiedzialno ci przejmuje
u ytkownik i to on decyduje w jaki sposób przebiega wykonanie
HWND hWnd - WiNDow Handle - identyfikator okna programu. U ytkownik mo e wybra w dowolnym momencie dowoln
HWND hWnd - typ (predefiniowany), hWnd - zmienna spo ród wszystkich oferowanych mu opcji a program powinien
HINSTANCE hInstance - Instance Handle - identyfikator danego zawsze zareagowa poprawnie i równie szybko. Jest oczywiste, e
wyst pienia (uruchomienia) programu pisz c program nie mo emy przewidzie w jakiej kolejno ci
PAINTSTRUCT - struktura graficzna typu PAINTSTRUCT u ytkownik b dzie wybierał opcje/rozkazy z menu. Przeciwnie
ps - nasza robocza struktura (zmienna) powini my napisa program w taki sposób by dla ka dego rozkazu
WNDCLASS - struktura (a nie klasa wbrew myl cej nazwie) istniał oddzielny kod. Jest to ogólna koncepcja, na której
POINT - struktura (współrz dne punktu - piksela na ekranie) opiera si programowanie zdarzeniowe.
RECT - struktura (współrz dne prostok ta)
BOOL - typ signed int wykorzystywany jako flaga (TRUE/FALSE) W przeciwie stwie do programów proceduralno - sekwencyjnych,
WORD - unsigned int które nale y czyta od pocz tku do ko ca, programy dla Windows
DWORD - unsigned long int musz zosta poci te na na mniejsze fragmenty - sekcje - na
LONG - long int zasadzie jedna sekcja - obsługa jednego zdarzenia. Je li
HANDLE, HWND, HINSTANCE - unsigned int (jako nr - identyfikator) zechcesz wy wietli napis "Hello, World", sekcja zdarzeniowego
programu obsługuj ca takie zdarzenie mo e wygl da np. tak:
UINT - j. w. - unsigned int.
Funkcja_Obsługi_Komunikatów_o_Zdarzeniach(komunikat)
W programach okienkowych stosuje si wiele predefiniowanych {
stałych, których znaczenie sugeruje przedrostek i nazwa, np: switch (komunikat_od_Windows)
{
WM_CREATE - Windows Message: Create! - Komunikat Windows: case WM_CREATE:
Utworzy ! (np. okno) ...
WS_VISIBLE - Window Style: Visible - Styl Okna: Widoczne TextOut(0, 0, "Napis: np. Hello world.", dlugosc_tekstu);
ID_... - IDentifier - IDentyfikator break;
MB_... - Message Box - elementy okienka komunikatów
...
W rodowisku Windows stosuje si specjaln notacj nazwan od case WM_CLOSE: // CLOSE - zamkn okno
narodowo ci swojego wynalazcy Karoja Szimoni - notacj .... break;
w giersk . Sens notacji w gierskiej polega na dodaniu do nazwy ..................... itd.
zmiennej okre lonych liter jako przedrostka (prefix). }
Litery-przedrostki stosowane w notacji w gierskiej zebrano w
Tabeli poni ej. Pomi dzy nazewnictwem Microsofta a Borlanda a w przypadku obiektowego stylu programowania - metoda
istniej wprawdzie drobne rozbie no ci, ale ogólne zasady mo na obsługuj ca to zdarzenie (nale ca np. do obiektu
odnie zarówno do BORLAND C++ 3+...4+, jak i Microsoft C++ Obiekt_Główne_Okno - TMainWindow) mo e wygl da np. tak:
6...7, czy Visual C++.
void TMainWindow::RysujOkno()
Notacja w gierska {
________________________________________________________________ TString Obiekt_napis = "Hello, World";
Prefix Skrót ang. Znaczenie int dlugosc_tekstu = sizeof(Obiekt_napis);
________________________________________________________________ TextOut(DC, 10, 10, Obiekt-napis, dlugosc_tekstu);
}
a array tablica
b bool zmienna logiczna (0 lub 1) Taki fragment kodu programu jest specjalnie przeznaczony do
by unsigned char znak (bajt) obsługi jednego zdarzenia (ewent-ualno ci). W okienku wykonuje
c char znak si operacja PAINT (maluj). "Malowanie" okna mo e si odbywa
cb count of bytes liczba bajtów albo po raz pierwszy, albo na skutek przesuni cia. Programy
cr color reference value okre lenie koloru zdarzeniowe tworzone w C++ dla Windows b d zbiorem podobnych
cx, cy short (count x, y len.) x-ilo , y-długo (short) "kawałków" nast puj cych w tek cie programu sekcja za sekcj .
dw unsigned long liczba długa bez znaku Oto jak działa program zdarzeniowy: kod programu, podzielony na
double word podwójne słowo sekcje obsługuj ce poszczególne zdarzenia koncentruje si wokół
fn function funkcja interfejsu.
pfn pointer to function wsk. do funkcji
h handle "uchwyt" - identyfikator FUNKCJE WinMain() i WindowProc().
i integer całkowity
id identifier identyfikator W programach pisanych w standardowym C dla Windows u ywane s
n short or int krótki lub całkowity dwie najwa niejsze funkcje: WinMain() i WindowProc().
np near pointer wska nik bliski
p pointer wska nik ________________________________________________________________
l long długi
lp long pointer wska nik typu long int UWAGA:
lpfn l. p. to function daleki wska n. do funkcji Funkcji WindowProc() mo na nada dowoln nazw , ale WinMain()
s string ła cuch znaków musi si zawsze nazywa WinMain(). Jest to nazwa zastrze ona
sz string terminated '\0' ła cuch ASCIIZ podobnie jak main() dla aplikacji DOSowskich.
tm text metric miara tekstowa ________________________________________________________________
119
Komunikaty Windows mo na tak e podzieli umownie na nast puj ce
kategorie:
Funkcja WinMain() powoduje utworzenie okna programu umo liwiaj c
1. Komunikaty dotycz ce zarz dzania oknami (Windows Managenent
zdefiniowanie i zarejestrowanie struktury "okno" (struct Msg.):
WNDCLASS) a nast pnie powoduje wy wietlenie okna na ekranie. Od WM_ACTIVATE (zaktywizuj lub zdezaktywizuj okno), WM_PAINT,
tego momentu zarz dzanie przejmuje funkcja WindowProc(). W WM_MOVE, WM_SIZE, WM_CLOSE, WM_QUIT.
typowej proceduralno - zdarzeniowej aplikacji dla Windows to
wła nie funkcja WindowProc() obsługuje pobieranie informacji od Bardzo istotnym szczegółem technicznym jest problem
u ytkownika (np. naci ni cie klawisza lub wybór z menu). Funkcja przekazywania aktywno ci pomi dzy oknami. Szczególnie cz sto
wyst puje potrzeba przekazania aktywno ci do elementu
WindowProc() robi to dzi ki otrzymywaniu tzw. komunikatów (ang. steruj cego. Je li hEditWnd b dzie identyfikatorem (window
Windows message). handle) okienka edycyjnego:

W Windows zawsze po wyst pieniu jakiego zdarzenia (event) case WM_SETFOCUS:


nast puje przesłanie komunikatu (message) o tym zdarzeniu do SetFocus(hEditWnd);
bie cego aktywnego w danym momencie programu w celu break;
poinformowania go, co si stało. Je li został naci ni ty
klawisz, komunikat o tym zdarzeniu zostanie przesłany do funkcji funkcja SetFocus() spowoduje, e wszystkie komunikaty dotycz ce
zdarze klawiatury b d kierowane do okna steruj cego, je eli
WindowProc(). Tak funkcjonuje interfejs pomi dzy aplikacj a okno macie yste jest aktywne. Poniewa zmiana rozmiaru okna
Windows. W programach tworzonych w C prototyp funkcji głównego nie poci ga za sob automatycznej zmiany rozmiaru okna
WindowProc() wygl da nast puj co: steruj cego, potrzebna jest dodatkowo obsługa wiadomo ci
WM_SIZE wobec okna elementu steruj cego.
LONG FAR PASCAL WindowProc(HWND hWnd, WORD Message,
WORD wParam, LONG lParam); 2. Komunikaty inicjacyjne dotycz ce konstrukcji np. menu
aplikacji:
Słowa FAR i PASCAL oznaczaj , e: WM_INITMENU - zainicjuj menu (wysyłany przed zainicjowaniem),
WM_INITDIALOG - zainicjuj okienko dialogowe.
FAR - kod funkcji znajduje si w innym segmencie ni kod
programu; 3. Komunikaty generowane przez Windows w odpowiedzi na wybór
PASCAL - kolejno odkładania argumentów na stos - odwrotna (jak rozkazu z menu, zegar, b d naci ni cie klawisza:
WM_COMMAND - wybrano rozkaz z menu,
w Pascalu). WM_KEYDOWN - naci ni to klawisz,
WM_MOUSEMOVE - przesuni to myszk ,
________________________________________________________________ WM_TIMER - czas min ł.

UWAGA: 4. Komunikaty systemowe. Aplikacja nie musi odpowiada na


Prototyp funkcji mo e zosta podany równie tak: rozkazy obsługiwane przez domy ln procedur Windows -
DefWindowProc(). Szczególnie dotyczy to rozkazów nie odnosz cych
LONG FAR PASCAL WndProc(HWND, unsigned, WORD, LONG);
________________________________________________________________ si do roboczego obszaru okna - Non Client Area Messages.

5. Komunikaty schowka (Clipborad Messages).


Pierwszy parametr hWnd jest to tzw. identyfikator okna (ang.
window handle). Ten parametr zawiera informacj , dla którego Sens działania funkcji WindowProc() w C/C++ polega na
okna przeznaczony jest komunikat. Zastosowanie takiego przeprowadzeniu analizy, co si stało i podj ciu stosownej
identyfikatora jest celowe, poniewa funkcje typu WindowProc() akcji. Mo na to realizowa przy pomocy drabinki if-else-if, ale
mog obsługiwa przesyłanie komunikatów do wielu okien. Je li najwygodniejsze jest stosowanie instrukcji switch.
okien jest wiele, okno jest identyfikowane przy pomocy tego
wła nie identyfikatora (numeru). LONG FAR PASCAL WindowProc(HWND hWnd, WORD Message,
WORD wParam, LONG lParam)
Nast pny parametr to sam komunikat o długo ci jednego słowa {
(word). Ten parametr przechowuje warto z zakresu switch (Message)
zdefiniowanego w pliku nagłówkowym WINDOWS.H. W zale no ci od {
tego co si zdarzyło, Windows mog nam przekaza ok. 150 ró nych case WM_CREATE:
.....
komunikatów a w tym np.: break; /* Koniec obsługi komunikatu WM_CREATE */
case WM_MOVE:
WM_CREATE Utworzono okno .... /* Kod obsługi komunikatu WM_MOVE */
WM_KEYDOWN Naci ni to klawisz break; /* Koniec obsługi WM_MOVE. */
WM_SIZE Zostały zmienione wymiary okna case WM_SIZE:
WM_MOVE Okno zostało przesuni te .... /* Kod obsługi sytuacji WM_SIZE */
WM_PAINT Okno nale y narysowa (powtórnie) - (re)draw break; /* Koniec obsługi WM_SIZE */
WM_QUIT Koniec pracy aplikacji
itp. .......... /* Inne, pozostałe mo liwe sytuacje */

Przedrostek WM_ to skrót od Windows Message - komunikat Windows. case WM_CLOSE: /* Zamkni cie okna */
....
Wymiana komunikatów w rodowisku Windows mo e przebiega w ró ny break;
default: /* wariant domy lny: standardowa obsługa
sposób - zale nie od ródła wywołuj cego generacj komunikatu i .... przez standardow funkcj Windows */
od charakteru zdarzenia. Ze wzgl du na ródło mo na komuniakty }
umownie podzieli na nast puj ce grupy: }
________________________________________________________________
1. Działanie u ytkownika (np. naci ni cie klawisza) powoduje UWAGA:
wygenerowanie komunikatu. Poniewa komunikatów "interesuj cych" dan aplikacj mo e by
2. Program - aplikacja wywołuje funkcj Windows i powoduje ponad 100 a sposobów reakcji u ytkownika jeszcze wi cej, w
przesłanie komunikatu do aplikacji. "powa nych" aplikacjach tworzone s cz sto struktury decyzyjne o
3. rodowisko Windows przesyła komunikat do programu.
4. Dwie aplikacje zwi zane mechanizmem dynamicznej wymiany wi kszym stopniu zło ono ci. Je li istnieje potrzeba
danych (Dinamic Data Exchange - DDE) wymieniaj komunikaty. optymalizacji działania programów stosuje si struktury dwu
typów:
120
* hierarchia warto ci (Value Tree) i nale c do Windows API) funkcja GetMessage(). Ta funkcja
* drzewo analizy zdarze (Event Tree). wypełnia struktur komunikatów i zwraca warto . Zwracana przez
Utworzone w taki sposób tzw. "Drzewo decyzyjne" nazywane tak e funkcj warto jest ró na od zera, je eli otrzymany wła nie
"Drzewem analizy zdarze " mo e by wielopoziomowe. Widoczny komunikat był czymkolwiek za wyj tkiem WM_QUIT. Komunikat
powy ej pierwszy poziom drzewa (pierwszy przesiew) realizowany WM_QUIT jest komunikatem ko cz cym prac ka dej aplikacji dla
jest zwykle przy pomocy instrukcji switch a nast pne przy pomocy Windows. Je li otrzymamy komunikat WM_QUIT powinni my przerwa
p tl pobierania komunikatów i zako czy prac funkcji
drabinek typu if-else-if-break. Schemat if-else-if-break cz sto WinMain(). Taka sytuacja oznacza, e wi cej komunikatów nie
bywa zast powany okienkami dialogowymi. b dzie. Po uwzgl dnieniu tych warunków p tla mo e wygl da tak:
________________________________________________________________
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, \
LPSTR lpszCmdLine, int nCmdShow)
Parametry wParam i lParam przechowuj parametry istotne dla ....
danego komunikatu. wParam ma długo pojedynczego słowa (word) a while(GetMessage(&msg,NULL,0,0)) //Poki nie otrzymamy WM_QUIT
{
lParam ma długo podwójnego słowa (long). Je li, dla przykładu, ....
}
okno zostało przesuni te, te parametry zawieraj nowe
współrz dne okna. Po naci ni ciu przez u ytkownika klawisza generowany jest
komunikat WM_KEYDOWN. Jednak e z faktu otrzymania komunikatu
Je eli program ma by programem zdarzeniowym, powinni my przed WM_KEYDOWN nie wynika, który klawisz został przyci ni ty, czy
podj ciem jakiejkolwiek akcji zaczeka a Windows przy l nam była to du a, czy mała litera. Funkcj TranslateMessage()
komunikat o tym, jakie zdarzenie nast piło. Wewn trz Windows (PrzetłumaczKomunikat) stosuje si do przetłumaczenia komunikatu
tworzona jest dla komunikatów kolejka (ang message queue).
Dzi ki istnieniu kolejkowania otrzymujemy komunikaty pobierane z WM_KEYDOWN na komunikat WM_CHAR. Komunikat WM_CHAR
przekazuje
kolejki pojedynczo. Je li u ytkownik przesunie okno a nast pnie przy pomocy parametru wParam kod ASCII naci ni tego klawisza.
przyci nie klawisz, to Windows wywołaj funkcj WindowProc() Funkcj TranslateMessage() stosujemy w p tli pobierania
najpierw z parametrem WM_MOVE a nast pnie z parametrem komunikatów tak:
WM_KEYDOWN.
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, \
Jednym z najwa niejszych zada funkcji WinMain() jest utworzenie LPSTR lpszCmdLine, int nCmdShow)
....
kolejki dla komunikatów i poinformowanie Windows, e komunikaty while(GetMessage(&msg, 0, 0, 0))
do naszego programu nale y kierowa pod adresem funkcji {
WindowProc(). W tym celu stosuje si daleki wska nik do TranslateMessage(&msg);
procedury okienkowej lpfn (Long Pointer to Function). Poza tym ....
funkcja WinMain() tworzy okno (okna) i wy wietla je na ekranie w }

pozycji pocz tkowej. Kiedy program zostaje po raz pierwszy W tym stadium program jest gotów do przesłania komunikatu do
załadowany i uruchomiony - Windows najpierw wywołuj funkcj funkcji - procedury okienkowej WindowProc(). Posłu ymy si w tym
WinMain().
celu funkcj DispatchMessage() (ang. dispatch - odpraw, przeka ,
Windows manipuluj komunikatami posługuj c si struktur MSG (od
DispatchMessage = OtprawKomunikat). Funkcja WinMain()
messages - komunikaty). Struktura MSG jest zdefiniowana w pliku poinformowała wcze niej Windows, e odprawiane komunikaty
WINDOWS.H w nast puj cy sposób: powinny trafi wła nie do WindowProc().

typedef struct tagMSG while(GetMessage(&msg, NULL, NULL, NULL))


{ {
HWND hwnd; TranslateMessage(&msg);
WORD message; DispatchMessage(&msg);
WORD wParam; }
LONG lParam;
DWORD time; Tak funkcjonuje p tla pobieraj ca komunikaty od Windows i
POINT pt; przekazuj ca je funkcji WindowProc(). P tla działa do momentu
} MSG; pobrania komunikatu WM_QUIT (Koniec!). Otrzymanie komunikatu
WM_QUIT powoduje przerwanie p tli i zako czenie pracy programu.
Na pierwszym polu tej struktury znajduje si "identyfikator" Komunikaty systemowe (system messages), które s kierowane do
(kod) okna, dla którego przeznaczony jest komunikat (ka dy Windows tak e trafiaj do tej p tli i s przekazywane do
komunikat mo e by przesłany tylko do jednego okna). Na drugim WindowProc(), ale ich obsług powinna si zaj specjalna
polu struktury przechowywany jest sam komunikat. Komunikat jest funkcja DefWindowProc() - Default Window Procedure, umieszczona
zakodowany przy pomocy predefiniowanych stałych w rodzaju na ko cu (wariant default).
WM_SIZE, WM_PAINT czy WM_MOUSEMOVE. Kolejne dwa pola słu do Jest to standardowa dla aplikacji okienkowych posta p tli
przechowania danych-parametrów towarzysz cych ka demu pobierania komunikatów.
komunikatowi: wParam i lParam. Na nast pnym polu przechowywany
jest w zakodowanej postaci czas - moment, w którym wyst piło Jak wida , wymiana informacji pomi dzy u ytkownikiem,
zdarzenie. Na polu pt przechowywane s współrz dne kursora rodowiskiem a aplikacj przebiega tu troch inaczej ni w DOS.
myszki na ekranie w momencie w którym został wygenerowany Program pracuj cy w rodowisku tekstowym DOS nie musi np.
komunikat o wyst pieniu zdarzenia. Nale y zwróci tu uwag , e rysowa własnego okna.
typ POINT oznacza struktur . Struktura POINT (punkt) w Windows
wygl da tak: [Z]
________________________________________________________________
typedef struct tagPOINT 1. Uruchom Windows i popatrz wiadomym, fachowym okiem, jak
{ przebiega przekazywanie aktywno ci (focus) mi dzy okienkami
int x; aplikacji.
int y; ________________________________________________________________
} POINT;

Aby mie pewno , e otrzymali my wszystkie komunikaty, które


zostały do nas skierowane, w programie wykonywana jest p tla LEKCJA 41: JAK TWORZY SI APLIKACJ DLA Windows?
pobierania komunikatów (message loop) wewn trz funkcji ________________________________________________________________
WinMain(). Na pocz tek wywoływana jest zwykle okienkowa (czyli W trakcie tej lekcji dowiesz si , jak "poskłada " aplikacj dla
121
Windows z podstawowych funkcji interfejsu API i jakie komunikaty ps danymi. Pola struktury typu PAINTSTRUCT wygl daj
s najwa niejsze dla naszych aplikacji. nast puj co:
________________________________________________________________
typedef struct tagPAINTSTRUCT
Przy tworzeniu programu zwró my szczególn uwag na to, co {
dzieje si w programie po otrzymaniu komunikatu WM_PAINT (nale y HDC hdc;
narysowa okno). Jest to danie ze strony Windows, by program BOOL fErase;
narysował obszar roboczy (client area) swojego okna. Program RECT rcPaint;
otrzyma komunikat WM_PAINT zawsze na pocz tku, kiedy powinien BOOL fRestore;
narysowa swoje okno po raz pierwszy i pó niej powtórnie, za BYTE rgbReserved[16];
ka dym razem, gdy trzeba b dzie odtworzy okno na ekranie. Je li } PAINTSTRUCT;
inne okno przesuwane po ekranie przysłoni okno naszego programu,
po odsłoni ciu naszego okna Windows prze l do programu Przy pomocy pola typu RECT (ang. rectangle - prostok t) Windows
komunikat WM_PAINT - odtwórz swoje okno - narysuj go powtórnie przekazuj do programu współrz dne wymiary (ang. dimensions)
(redraw, repaint). Je li zechcemy wyprowadzi na ekran napis "zepsutego" na ekranie prostok ta. Typ RECT oznacza nast puj c
"Hello World" tak e b dziemy musieli narysowa okno od nowa. Nie struktur :
zawsze "od wie enia" wymaga całe okno. W ka dej z sytuacji:
typedef struct tagRECT
- całe okno zostało przysłoni te i odsłoni te {
- cz okna wymaga od wie enia int left; //współrz dna lewa - x
- okno jest rysowane po raz pierwszy int top; //współrz dna górna - y
int right; //współrz dna prawa - x
Windows prze l do programu ten sam komunikat - WM_PAINT. int bottom; //współrz dna dolna - y
Je li odtworzenia wymaga tylko cz okna, taka cz okna } RECT;
nazywa si niewa n -nieaktualn (ang. invalid). W Windows takie
nieaktualne fragmenty okna zawsze maj kształt prostok tów. Górny lewy róg nieaktualnego prostok ta (invalid rectangle) ma
Wyobra my sobie, e jakie inne okno przesłoniło naro nik okna dwie współrz dne (left, top) a dolny prawy róg prostok ta ma
naszego programu. Je li u ytkownik usunie to przesłaniaj ce współrz dne (right, bottom). Te współrz dne ekranowe mierzone s
okno, odsłoni ty obszar b dzie potraktowany przez Windows jako
nieaktualny. Windows prze l do aplikacji komunikat WM_PAINT w pikselach i s to współrz dne wzgl dne - wzgl dem lewego
daj cy odtworzenia okna. daj c odtworzenia okna Windows górnego naro nika okna aplikacji. Lewy górny naro nik okna
powinny nas poinformowa która cz naszego okna została na aplikacji ma wi c współrz dne (0,0).
ekranie "zepsuta". Współrz dne prostok ta na ekranie Windows
przeka przy pomocy specjalnej struktury nazywanej struktur Zwró my uwag na warto zwracan przez funkcj BeginPaint() -
rysunku (ang. paint structure - PAINTSTRUCT). zmienn hDC:

Struktur rysunku mo emy nazwa w programie np.: case WM_PAINT:


memset(&ps, 0x00, sizeof(PAINTSTRUCT));
PAINSTRUCT ps; hDC = BeginPaint(hWnd, &ps);
....
W funkcji WindowProc() obsługa komunikatu WM_PAINT rozpoczyna
si od wyczyszczenia pól struktury rysunku ps. Struktura Wszystnie operacje graficzne b d wymaga nie kodu okna hWnd a
predefiniowanego typu PAINTSTRUCT (w WINDOWS.H) zawiera wła nie kodu-identyfikatora kontekstowego hDC.
informacje o rysunku.
Na pocz tku pracy programu, gdy okno jest rysowane po raz
PAINTSTRUCT ps; pierwszy, Windows generuj komunikat WM_PAINT i cały obszar
{ roboczy okna jest uznawany za nieaktualny. Kiedy program otrzyma
switch (Message)
{ ten pierwszy komunikat, mo emy wykorzysta to do umieszczenia w
case WM_CREATE: oknie np. napisu. Je li tekst ma rozpoczyna si od lewego
..... break; górnego naro nika okna aplikacji, funkcja TextOut() u ywana w
case WM_MOVE: Windows do wykre lania tekstu (w trybie graficznym) powinna
.... break; rozpoczyna wyprowadzanie tekstu od punktu o (pikselowych)
case WM_SIZE: współrz dnych (0,0).
.... break;
case WM_PAINT:
case WM_PAINT: /* Obsługa rysowania okna */ ...
memset(&ps, 0x00, sizeof(PAINTSTRUCT); TextOut(hDC, 0, 0, (LPSTR) "Tekst", strlen("Tekst"));
.... EndPaint(hWnd, &ps);
break; //Koniec obsługi WM_PAINT break;

case WM_CLOSE: Funkcja TextOut() (wyprowad tekst) pobiera pi parametrów:


.... break;
hDC - identyfikator-kod prostok ta, który nale y narysowa
default: ..... x - współrz dna pozioma (w pikselach)
} y - współrz dna pionowa pocz tku naszego napisu
} W tym przypadku współrz dne wynosz (0,0).
LPSTR - wska nik do ła cucha znaków "Hello world."
Nast pnie pola struktury rysunku zostaj wypełnione poprzez LPSTR = long pointer to string (wska nik typu far).
okienkow funkcj BeginPaint() - RozpocznijRysowanie. Zwró
uwag , e do poprawnego działania funkcji potrzebne s Wska nk ten przekazujemy do funkcji poprzez forsowanie typu:
informacje o tym, które okno trzeba od wie y (Windows powinny ... (LPSTR) "Tekst";
wiedzie wobec którego okna damy informacji o "zepsutym" Zgodnie z definicj typu w pliku WINDOWS.H spowoduje to zamian
prostok cie) i adres naszej struktury rysunku. Aby przekaza te wska nika do ła cucha typu near char* (bliski) na wska nik typu
informacje post pujemy tak: far (daleki). Ostatni parametr funkcji to długo wyprowadzanego

case WM_PAINT: tekstu - tu obliczana przez funkcj strlen().


memset(&ps, 0x00, sizeof(PAINTSTRUCT));
hDC = BeginPaint(hWnd, &ps); Prze led my etapy powstawania aplikacji.
....
Funkcja MainWin() rejestruje i tworzy główne okno programu oraz
Teraz funkcja BeginPaint() mo e wypełni nasz struktur rysunku inicjuje globalne zmienne i struktury. Funkcja WinMain() zawiera

122
p tl pobierania komunikatów. Ka dy komunikat przeznaczony dla identyfikator kombinacji klawiszy - "accelerator ID". Procedura
głównego okna (lub ewentualnych nastepnych okien potomnych) jest obsługi komunikatów powinna zawiera

pobierany, ewentualnie poddawany translacji i przekazywany do case (WM_COMMAND): ..... break;


funkcji obsługuj cej dialog z Windows. Przed zako czeniem
programu funkcja WinMain() kasuje utworzone wcze niej obiekty, Wewn trz przy pomocy instrukcji switch{...} nale ałoby
zwalnia pami i pozostałe zasoby. rozpatrywa kolejne warianty, wykorzystuj c identyfikator
wybranego z menu rozkazu - ID. Obsługa komunikatow wiadcz cych
UWAGA: "Obiekty" nie s tu u yte w sensie stosowanym w OOP. o wyborze przez u ytkownika rozkazu z menu stanowi zwykle główn
"Obiekt" oznacza tu np. struktur .
robocz cze programu.
int PASCAL WinMain(HANDLE hInstance, hPrevInstance,
LPSTR lpszCmLine, int nCmdShow) LONG FAR PASCAL WindowProc(HWND hWnd, WORD Message, WORD
{ ... wParam,

HANDLE hInstance - identyfikator bie cego pojawienia si danej LONG lParam)


aplikacji. Poniewa w Windows program mo e by uruchamiany {
wielokrotnie, stosuje sie pojecie tzw. "Instancji" - wyst pienia HMENU hMenu=0; /* Identyfikator menu */
HBITMAP hBitmap=0; /* Identyfikator mapy bitowej */
- uruchomienia programu. HDC hDC; /* Identyfikator kontekstowy */
PAINSTRUCT ps; /* Struktura rysunku */
HANDLE hPrevInstance - identyfikator poprzedniego wyst pienia int nRc=0; /* Zwrot kodu przez funkcje */

danej aplikacji switch (message)


LPSTR lpszCmdLine - daleki wska nik do parametrów wywołania {
programu z linii rozkazu case WM_CREATE:
int nCmdShow - sposób pocz tkowego wy wietlenia okna
Gdy okno jest tworzone Windows przesyłaj jeden raz komunikat
(pełne okno, b d ikona) WM_CREATE do okna. Procedura obsługi nowego okna (new window
procedure) otrzymuje ten komunikat po utworzeniu okna, ale
Deklaracja struktury typu MSG (Message) do przechowywania jeszcze zanim okno pojawi sie na ekranie.
komunikatów.
lParam - Wska nik do struktury CREATESTRUCT o postaci:
MSG msg;
typedef struct {
Nadanie nazwy aplikacji: LPSTR lpCreateParams;
HANDLE hInst;
strcpy(szAppName, "Nazwa Aplikacji"); HANDLE hMenu;
HWND hwndParent;
Rejestrujemy struktury okien je li jest to pierwsze uruchomienie int cy;
int cx;
danej aplikacji i sprawdzamy, czy rejestracja powiodła si : int y;
int x;
if(!PrevInstance) LONG style;
{ LPSTR lpszName;
if((int nRc = RegisterClass() ... LPSTR lpszClass;
DWORD dwExStyle;
Utworzenie głównego okna programu (mo e si nie uda ): } CREATESTRUCT; */

hWndMain = CreateWindow(....);
if(hWndMain == NULL) Kod obsługi powiekszania/zmniejszania case WM_SIZE.
{
MessageBox(0, "Klops", "Koniec", MB_OK); wParam zawiera kod operacji - zmniejsz/powi ksz
return (FALSE); lParam zawiera now wysoko i szeroko okna
}
case WM_PAINT:
Wy wietlenie głównego okna na ekranie:
Pobranie kontekstowego identyfikatora urz dzenia. Funkcja
ShowWindow(hWndMain, nCmdShow); BeginPaint() spowoduje w razie potrzeby wysłanie komunikatu
WM_ERASEBKGND (Erase Background - skasuj tło).
P tla komunikatów wykrywaj ca komunikat WM_QUIT:
memset(&ps, 0x00, sizeof(PAINTSTRUCT));
while(GetMessage(&msg, 0, 0, 0)) hDC = BeginPaint(hWnd, &ps);
{
TranslateMessage(&msg); Set Background Mode - ustaw rodzaj tła (tu: przezroczyste):
DispatchMessage(&msg);
} SetBkMode(hDC, TRANSPARENT);

Główna procedura obsługi okna WindowProc(). Aplikacja powinna wykre li obszar roboczy okna posługuj c sie
grafik GDI i (Graficzny Interfejs Urz dzenia - analogia do
Instrukcja switch przeł cza do odpowiedniego wariantu działania graficznego standardu BGI w rodowisku DOS). Struktura ps typu
- obsługi odpowiedniego komunikatu. Musz tu znajdowa sie PAINSTRUCT zwrócona przez BeginPaint() wskazuje prostok t do
procedury obsługi wszystkich interesujacych nas działa zamalowania.
uzytkownika i ogólnych komunikatow Windows (np. WM_CLOSE). Je li
Wypisanie tekstu w głównym oknie aplikacji:
wyst pi taki komunikat, którego obsługa nie została
przewidziana, obsługa jest przekazywana, do funkcji okienkowej TextOut(hDC, 0, 0, (LPSTR) "Hello, world.", strlen("Hello,
DefWindowProc() - obsług przejmuj Windows. world."));
Komunikaty inicjowane przez u ytkownika s rozpatrywane
zasadniczo jako WM_COMMAND. Rozkaz wybrany z menu lub Funkcja TextOut() pracuje w trybie graficznym, wi c (podobnie
odpowiadaj ca mu kombinacja klawiszy jest przekazywana przy jak inne funkcje graficzne Windows API) otrzymuje jako argument
pomocy pierwszego parametru komunikatu - wParam. Kod tzw. "kontekst urz dzenia" - hDC.
odpowiadaj cy rozkazowi z menu nazywa sie "control menu ID", a
123
Zamykanie okna: korzysta z Debuggera), pojawiło si natomiast nowe menu Browse
(przegl danie). Rozkazy, których tradycyjnie szukali my w menu
case WM_CLOSE: Debug zostały rozrzucone do innych menu. I tak:
DestroyWindow(hWnd);
if (hWnd == hWndMain) Menu Compile zawiera:
PostQuitMessage(0);
Compile (kompilacja do *.OBJ),
Je li zamkni te zostało główne okno aplikacji, funkcja Make (kompilacja i konsolidacja do *.EXE),
PostQuitMessage() wysyła do Windows komunikat, e aplikacja Link (konsolidacja bez powtórnej kompilacji),
zako czyła działanie i okno aplikacji zostało usuni te. W tym Build all (konsolidacja wszystkich modułów),
stadium stosuje si funkcje PostQuitMessage() i Information... (informacja o przebiegu kompilacji),
PostAppMessage(). Pozostale przypadki s obsługiwane przez Remove messages (usuwanie komunikatów z pliku wynikowego)
wariant domy lny - default. Przekazanie komunikatu do obsługi
przez Windows. Menu Run zawiera:

default: Run (uruchomienie i ewentualna rekompilcja),


return (DefWindowProc(hWnd, Message, wParam, lParam)); Arguments... (argumenty uruchomieniowe z wiersza rozkazu),
Debugger (zamiast w Debug - TU!)
Funkcja rejestruj ca wszystkie klasy wszystkich okien zwi zanych Debugger arguments... (argumenty dla Debuggera)

z bie c aplikacja (nazwiemy j roboczo FRegisterClasses()). Menu Project zawiera:


Jesli operacja sie powiodła - funkcja zwraca kod bł du.
Open project - otwórz (nowy lub istniej cy) plik projektu,
int FRegisterClasses(void)
{ Close project - zamknij projekt,
WNDCLASS wndclass; /* Struktura do definiowania klas okien. */ Add item... - dodaj element (plik) do projektu,
memset(&wndclass, 0x00, sizeof(WNDCLASS)); Delete item - usu element (plik) z projektu,
Include ˙˙files... ˙˙- ˙˙podaj ˙katalog ˙zawieraj cy ˙dodatkowe
Ustawienie parametrów okna w strukturze:
doł czane do programu pliki nagłówkowe *.H
wndclass.style = CS_HRDRAW | CS_VRDRAW;
wndclass.lpfnWindowProc = WindowProc; W menu Options (zestaw znany ju z Borland C++) warto zwróci
uwag na pewn dodatkow mo liwo . Jak wiemy z do wiadczenia,
Dodatkowa pami dla klasy Window i obiektów klasy Window. uruchamiaj c program cz sto dokonujemy zmian i korekt w pliku
Doł czanie innych zasobów odbywa si przy pomocy funkcji: ródłowym *.C, czy *.CPP. Znacznie rzadziej jednak zmieniamy
zestaw doł czanych do programu plików nagłówkowych *.H. Wiemy
LoadBitmap() - załaduj map bitow równie , e kompilacja tych wła nie plików nagłówkowych zajmuje
LoadIcon() - załaduj ikonk cz sto lwi cz czasu całej kompilacji i konsolidacji
LoadCurcor(), LoadMenu(), itp. ... programu. Borland zauwa ył to i w okienku dialogowym:

wndclass.cbClsExtra = 0; Options | Compiler | Code generation --> Code Generation Options


wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = LoadIcon(NULL, ID_ICON); umie cił opcj Pre-compiled headers (pliki nagłówkowe wst pnie
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); skompilowane wcze niej - i tylko jeden raz). Szczególnie w
przypadku aplikacji okienkowych mo e to znacznie przyspieszy
Utworzenie p dzla (brush) dla tła: proces uruchamiania i "szlifowania" naszych programów. Nie ma
jednak nic za darmo. Borland/Turbo C++ po skompilowaniu plików
wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); nagłówkowych tworzy na dysku roboczy plik *.SYM nadaj c mu nazw
wndclass.lpszMenuName = szAppName;
wndclass.lpszClassName = szAppName; zgodn z nazw bie cego projektu (jest to zwykle nazwa głównego

if (!RegisterClass(&wndclass)) return -1; modułu *.CPP) i do poprawnego działania wymaga kilkadziesi t lub
}
nawet kilkaset kilobajtów dodatkowej przestrzeni na dysku.
Typowe obiekty ze składu Windows to
[!!!]UWAGA
HBRUSH P dzel; i ________________________________________________________________
HPEN Ołówek;
Je li przenosisz projekt na dyskietk i tam kontynuujesz prac
Nale y tu zwróci uwag jeszcze na dwa szczegóły techniczne. DC nad projektem, pami taj, e mo e zabrakn miejsca na
i GDI - Device Context, Graphics Device Interface - to tzw. prekompilowany plik .SYM.
kontekst urz dzenia i graficzny interfejs urz dzenia. Pozwala to ________________________________________________________________
Windows działa skutecznie w trybie "Device Independent"
(niezale nym od sprz tu).
Czytelnik zechce sam sprawdzi w jakim stopniu przyspieszy to
kompilacj naszego własnego programu proceduralno -
LEKCJA 42: KOMPILATORY "SPECJALNIE DLA Windows". zdarzeniowego WINPZ1.CPP:
________________________________________________________________
Z tej lekcji dowiesz si , czym ró ni si kompilatory WINZ1.CPP. Jednomodułowa aplikacja proceduralno - zdarzeniowa
przeznaczone dla pracy w rodowisku Windows. dla Windows.
________________________________________________________________ ________________________________________________________________
#include <windows.h>
W IDE i w sposobie zachowania zaszły istotne zmiany. Posługuj c #pragma argused
si Turbo C++ z pakietu BORLAND C++ 3.0 lub BCW z pakietu 3.1
mo emy korzysta z uroków i usług Windows szerzej ni do tej long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ;
pory. Mo emy otwiera wiele okien i uruchamia bezpo rednio z
poziomu IDE okienkowe aplikacje. W głównym menu kompilatora int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
zaszły pewne zmiany (sygnalizuj ce obiektowo- i okienkowo - LPSTR lpszCmdLine, int nCmdShow )
zorientowan ewolucj pakietów Borlanda), na które warto zwróci {
uwag . WNDCLASS Okno1;
MSG komunikaty;
Znikn ło menu Debug (co wcale nie oznacza, e nie mo emy HWND NrOkna;
124
LPSTR LongPtr1 = "Okno 1";
LPSTR lp2 = "AM: BC++ 3..4/Reczne sterowanie (1)"; Program demonstruje opisane wy ej mechanizmy, mo e by
uruchamiany wielokrotnie i sprowadzony do ikony. Z uwagi na brak
if (hPrevInstance == 0)
{ zdefiniowanych dodatkowych zasobów (brak w projekcie plików:
Okno1.style= CS_HREDRAW | CS_VREDRAW ; .RC - resources - zasoby
Okno1.lpfnWndProc= WndProc; .ICO - ikona
Okno1.cbClsExtra = 0; .DEF - definicji
Okno1.cbWndExtra= 0; .PRJ lub .IDE - projektu
Okno1.hInstance = hInstance; .DSK - konfiguracyjnego
Okno1.hCursor = LoadCursor(0, IDC_CROSS ); itp.)
Okno1.hbrBackground= GetStockObject(WHITE_BRUSH );
Okno1.lpszMenuName= 0; podczas kompilacji programu wyst pi dwa komunikaty
Okno1.lpszClassName= LongPtr1; ostrzegawcze. Komunikaty te mo na zignorowa .

if (!RegisterClass(&Okno1)) A oto druga przykładowa aplikacja w tym samym stylu. Tym razem
return 0; funkcja okienkowa reaguje na naci ni cie lewego klawisza myszki,
}
co powoduje wygenerowanie komunikatu WM_LEFTBUTTONDOWN.
NrOkna = CreateWindow(LongPtr1, lp2, WS_VISIBLE |
WS_SYSMENU | Program WINZ-2.CPP
WS_MINIMIZEBOX | WS_VSCROLL | WS_MAXIMIZEBOX, ________________________________________________________________
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, #include <windows.h>
0, 0, hInstance, 0); #include <string.h>
#pragma argused
ShowWindow(NrOkna, nCmdShow);
UpdateWindow(NrOkna); char napis[10];
int X, Y;
while (GetMessage(&komunikaty, 0, 0, 0))
{ LONG FAR PASCAL WndProc (HWND, WORD, WORD, LONG);
TranslateMessage(&komunikaty );
DispatchMessage(&komunikaty ); int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
} LPSTR lpszCmdLine, int nCmdShow )
return 0; {
} WNDCLASSwndClass;
MSGmsg;
long FAR PASCAL WndProc (HWND NrOkna, unsigned HWNDhWnd;
KomunikatWindows, LPSTR Lp1 = "Mysza1";
LPSTR lp2 = "WINPZ2: Wykrywanie Lewego Klawisza
WORD wParam, LONG lParam) Myszki";
{
HDC NrKontekstu; if (!hPrevInstance)
PAINTSTRUCT struktura_graficzna; {
RECT prostokat; wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc;
switch(KomunikatWindows) wndClass.cbClsExtra = 0;
{ wndClass.cbWndExtra= 0;
case WM_PAINT: wndClass.hInstance = hInstance;
{ wndClass.hIcon = 0;
NrKontekstu = BeginPaint(NrOkna, &struktura_graficzna); wndClass.hCursor= LoadCursor(0, IDC_ARROW );
GetClientRect(NrOkna, &prostokat); wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
TextOut(NrKontekstu,80,50, ": Reczne sterowanie:", 20 ); wndClass.lpszMenuName= 0;
TextOut(NrKontekstu, 5,70, "Tu -->", 6); wndClass.lpszClassName= Lp1;
TextOut(NrKontekstu, 5, 85, "Blad:", 5);
TextOut(NrKontekstu,75,70, "-----------------------------", if (!RegisterClass(&wndClass))
exit(1);
40); }
TextOut(NrKontekstu,30,110, "Programowanie proceduralno -
zdarzeniowe.", 41 ); hWnd = CreateWindow(Lp1, lp2, WS_OVERLAPPEDWINDOW,
TextOut(NrKontekstu,30,135, "Szablon moze zostac rozbudowany CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
0, 0, hInstance, 0);
o inne funkcje.", 47 );
TextOut(NrKontekstu,30,180, "RECZNIE panujemy np. nad:", 25 ShowWindow(hWnd, nCmdShow);
); UpdateWindow(hWnd);
TextOut(NrKontekstu,20,220, "paskiem tytulowym okna, tytulem
while (GetMessage(&msg, 0, 0, 0))
ikonki...", 41); {
TextOut(NrKontekstu, 100, 250, "!KONIEC - [Alt]+[F4]", 20); TranslateMessage(&msg );
DispatchMessage(&msg );
EndPaint(NrOkna,&struktura_graficzna); }
break; return 0;
} }
case WM_DESTROY:
{ LONG FAR PASCAL WndProc (HWND hWnd, WORD Message,
PostQuitMessage(0); WORD wParam, LONG lParam)
break; {
} HDC hDC;
default: PAINTSTRUCT ps;
return DefWindowProc(NrOkna,KomunikatWindows,wParam,lParam); RECT rect;
switch(Message)
} {
return 0; case WM_SIZE:
} hDC = GetDC( hWnd );
125
TextOut(hDC, 50, 100, "Wykrywanie nacisniecia", 22); Wska nik do parametrów uruchomieniowych programu (Arguments)
TextOut(hDC, 50, 120, "lewego klawisza myszki.", 23); pobieranych z wiersza rozkazu nie został ani raz u yty w
TextOut(hDC, 20, 140, "Komunikat o zdarzeniu: ", 22); programie. Na to nic nie mo emy poradzi . Po prostu argumenty
TextOut(hDC, 20, 156, "Left Button Down - LBUTTONDOWN", 31); uruchomieniowe nie s nam potrzebne. Wykonujemy wi c "klik"
(przekazanie "focusa") w okienku edycyjnym i mo emy przej do
TextOut(hDC, 50, 170, "Po wcisnieciu klawisza,", 23); nast pnej czynno ci:
TextOut(hDC, 50, 190,"w biezacej pozycji kursora, pojawi sie
4. Konsolidacja: Compile | Link.
napis <-- Tu!.", 52);
ReleaseDC(hWnd, hDC); W okienku "Message" znów pojawi si ostrze enie:
break;
Linker Warning: No module definition file specified:
case WM_PAINT: using defaults.
hDC = BeginPaint(hWnd, &ps); (brak wyspecyfikowanego pliku definicji .DEF; stosuj warto ci
TextOut(hDC, X,Y, napis, strlen(napis)); domy lne)
EndPaint(hWnd, &ps);
break; I tu ju mo emy co zaradzi . Mo emy zatem pokusi si o
stworzenie naszego pierwszego pliku definicji (nazwa jest troch
case WM_LBUTTONDOWN:
strcpy(napis,"<-- Tu !"); myl ca - chodzi o zdefiniowanie sposobu wykorzystania zasobów
X = LOWORD(lParam); rodowiska Windows).
Y = HIWORD(lParam);
InvalidateRect(hWnd, 0, TRUE); Aby utworzy plik .DEF (jest to plik ASCII) nale y:
UpdateWindow(hWnd);
break; 1. Otworzy nowe okienko edycyjne (nie wychodz c z IDE):
File | New
case WM_DESTROY: Otworzy si okienko NONAMExx.CPP. Ta nazwa nie jest oczywi cie
PostQuitMessage(0); break; najodpowiedniejsza, wi c umieszczamy plik we wła ciwym katalogu
(tym samym, co główny program *.CPP) przy pomocy rozkazu File |
default: Save as...
return DefWindowProc(hWnd, Message, wParam, lParam); i nadajemy plikowi stosown nazw i rozszerzenie *.DEF. Okieno
} pozostaje puste, ma jednak "focus" i now nazw , np.
return 0; C:\..\PR.DEF.
}
3. Redagujemy nasz pierwszy plik definicji, np. tak:
Plik nagłówkowy STRING.H pojawia si ze wzgl du na obecno
funkcji strlen() wyznaczaj cej długo napisu. Zmienne X i Y to NAME JAKAKOLWIEK // <-- nazwa aplikacji
bie ce (wzgl dne) współrz dne kursora myszki w momencie DESCRIPTION 'Opis: A. MAJCZAK, BC C++ 3...4'
naci ni cia klawisza. Program demonstruje nast puj ce efekty: EXETYPE WINDOWS // <-- EXE dla Windows
CODE PRELOAD MOVEABLE DISCARDABLE
X = LOWORD(lParam); DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 4096 // <-- sterta 4 KB
- przekazanie współrz dnej X przy pomocy parametru lParam STACKSIZE 5120 // <-- stos 5 KB
(LOWORD to LOw WORD of the double word - młodsze słowo podójnego
_______________________________________________________________
słowa). UWAGA:
W przypadku tworzenia bibliotek .DLL dane musz mie status
Y = HIWORD(lParam); SINGLE (pojedyncze) zamiast MULTIPLE (wielokrotne). U ycie tu
słowa MULTIPLE pozwoli nam na wielokrotne uruchamianie
Analogicznie - przekazanie współrz dnej Y (HIgh WORD of the aplikacji.
double word). Funkcja InvalidateRect() powoduje uznanie ________________________________________________________________
prostok nego pola za nieaktualne. Funkcja UpdateWindow()
"od wie a" okno. Dzi ki temu tandemowi napis znika i pojawia si Mo naby tu zapyta - po co to robi , skoro u ywamy standardowych
warto ci i obecno tego pliku nie wnosi nic nowego do sposobu
w nowym miejscu. działania naszego programu?
Odpowied jest prosta. Maj c taki plik b dziemy mogli
PROJEKT. prze ledzi stadia tworzenia tzw. projektu (w BC++ 4 bez tego
ani rusz). Zapisujemy zatem plik na dysk:
Aby skompilowa powy sze programy przykładowe nale y:
4. File | Save. (plik .DEF zostaje zapisany na dysku).
1. Uruchomi kompilator C++. Poniewa pracujemy w rodowisku Windows, okno edycji pliku *.DEF
2. Załadowa do okienka edycyjnego (File | Open) plik z tekstem
ródłowym programu. mo emy traktowa podobnie jak ka de inne okno. Najwygodniej
3. Wybra rozkaz Compile z menu Compile. zatem przej do okna edycji głównego pliku ródłowego *.CPP
Przed kompilacj i konsolidacj (je li był inny) ustawi sposób przy pomocy własnego menu systemowego tego okna.
tworzenia kodu wynikowego [Windows EXE].
5. Menu Systemowe [-] | Zamknij.
Kompilacja przebiegnie poprawnie (pami taj o Opcjach i
Katalogach), mimo to pojawi si jednak dwa komunikaty I mo emy przyst pi do tworzenia projektu składaj cego si z dwu
ostrzegawcze. W okienku "Compile Status" (stan/przebieg
kompilacji) pojawi si zawarto : plików: *.CPP i *.DEF. Je li, dla przykładu, przyjmiemy w tym
miejscu, e nasze dwa moduły nazywaj si : WINZ2.CPP i WINZ2.DEF
Lines 3832 (znakomita wi kszo to WINDOWS.H,
prekompilacja byłaby celowa) i s przechowywane w katalogu głównym dysku C:\ , kolejno
Warnings: 1 czynno ci powinna by nast puj ca:
Errors: 0
1. Rozwijamy menu Project ([Alt]+[P] lub myszk ).
Je li wybierzesz klawisz [OK] w okienku "focus" (aktywno ) 2. Wybieramy z menu rozkaz Open Project... (Utwórz projekt).
zostanie przekazana do okienka komunikatów "Message" a tam Pojawia si okienko dialogowe Open Project File z domy lnym
pojawi si napis: rozszerzeniem *.PRJ (w BC 4+ - *.IDE).
3. Do okienka File Name:
Warning: Parameter 'lspzCmdLine' is never used. wpisujemy nazw pliku z opisem projektu: np. WINZ2.PRJ.
W dolnej cz ci ekranu otwiera si okienko
126
Project: WINZ2
4. Wybieramy z menu Project rozkaz Add item... (dodaj element do COMBOBOX - okienko dialogowe kombinowane. Jest
zło eniem klasy EDIT i LISTBOX;
projektu). Pojawia si okienko dialogowe "Add to Project List"
(dodawanie do listy elementów projektu). LISTBOX - oknienko z list (zwykle element
5. Do okienka File Name: wpisujemy nazw głównego pliku składowy okienka dialogowego typu
projektu: WINZ2.CPP (*.cpp jest domy lnym rozszerzeniem). Combo Box.
Plik mo emy wybra tak e z listy w okienku Files: .
6. Wybieramy w okienku dialogowym klawisz [+Add] (dodaj do STATIC - pole statyczne (bez prawa edycji).
projektu). Niewielkie okno zawieraj ce tekst lub
7. Wpisujemy nazw kolejnego pliku wchodz cego w skład projektu
(w tym przypadku WINZ2.DEF). grafik ; słu y z reguły do oznaczania
8. Wybieramy klawisz [+Add] w okienku.
UWAGA: Czynno ci 7) i 8) w przypadku bardziej zło onych innych okien steruj cych.
projektów b d powtarzane wielokrotnie.
9. Wybieramy klawisz [Done] w okienku (zrobione/gotowe). SCROLLBAR - pasek przewijania (pionowy - Vertical
Konfigurowanie projektu zostało zako czone.
10. Przy pomocy rozkazów Compile, Link, Make, Build all, Run Scroll Bar; poziomy - Horizontal
mo emy teraz skompilowa , skonsolidowa i uruchomi nasz program Scroll Bar).

w postaci projektu. Ostrze enie Linkera zniknie. Style klawiszy steruj cych (Button Styles):

[!!!]UWAGA BS_PUSHBUTTON - Klawisz. Okno steruj ce wysyła, po


________________________________________________________________ ka dym wyborze klawisza
(klikni cie), wiadomo do okna
W dolnej cz ci ekranu w stadium tworzenia projektów ( i pó niej macie ystego (Parent Window).

po załadowaniu pliku projektu [Open Project] pojawi si lista BS_RADIOBUTTON - Okr gły przeł cznik działaj cy
plików. Do trybu edycji pliku mo esz przj poprzez dwukrotne zwykle na zasadzie @tylko jeden
klini cie pliku na tej li cie. z grupy".
Zwró uwag , e pliki projektów .PRJ ( w Borland 4+ .IDE)
przechowuj równie informacje o konfiguracji. Najwa niejsza z BS_CHECKBOX - - prostok tny przeł cznik [X]
nich to informacja o katalogach, z których korzysta kompilator: wł czaj cy (aktywna) lub
wył czaj cy (nieaktywna)
Options | Directories... | Include opcj . Działa niezale nie od
Options | Directories... | Library pozostałych.
Options | Directories... | Output
________________________________________________________________ Inne style okre laj np. sposób edycji tekstu (ES_LEFT,
ES_MULTILINE, itp.) Szczegóły - patrz system Help - Windows API.
Najwygodniej przechowywa wszystkie pliki wchodz ce w skład Oto przykład utworzenia okna elementu steruj cego typu "Klawisz"
jednego projektu w odr bnym katalogu dyskowym. Dla wprawy załó
odr bny katalog i zapisz tam pliki: (BUTTON to nazwa typu):

*.CPP hControlWnd = CreateWindow ("BUTTON", " Napis_na_Klawiszu ",


*.DEF BS_PUSHBUTTON |WS_CHILD | WS_VISIBLE,
*.PRJ (lub *.IDE) 10, 20, 30, 40,
hWnd, ID_Elem, hInstance, 0);
dla swoich pierwszych dwóch projektów, które wła nie powstały.
Identyfikator ID_Elem jest potrzebny, gdy w jednym oknie
[!!!] UWAGA znajduje si kilka elementów steruj cych - pozwala na ich
________________________________________________________________ rozpoznawanie w programie. Sposób przekazywania informacji o
klikni ciu klawisza przypomn na przykładzie okienka
Ten sam plik definicji mo esz wykorzystywa do tworzenia komunikatów:
nast pnych przykładowych aplikacji typu Windows EXE.
________________________________________________________________ if(IDOK==MessageBox(0, "", "", MB_OK)) ...

IDOK to predefiniowany w Windows identyfikator klawisza [OK].


Oto krótkie wyja nienie pozostałych elementów:
LEKCJA 43: Elementy steruj ce i zarz dzanie programem.
________________________________________________________________ 10, 10, 30, 20, - współrz dne. x, y, szeroko , wysoko
Jak sterowa prac aplikacji. Jak umieszcza elementy hWnd, - oznacznik okna macie ystego
graficzne-steruj ce w oknie aplikacji. Najcz ciej stosowane
funkcje API Windows. Przesuwanie i zmiana wielko ci elementu steruj cego.
________________________________________________________________
Funkcja MoveWindow() przesuwa okno we wskazane miejsce:
Elementy steruj ce prac aplikacji w Windows (ang. controls) s
równie swoistymi okienkami (tyle, e potomnymi - Child Window MoveWindow(hKlawisz, 10, 10, 20, 30, TRUE);
wobec głównego okna aplikacji - Parent Window).
Do utworzenia takiego specjalnego okna równie mo na u y Poniewa okno elementu steruj cego ma zadane wzgl dne
funkcji CreateWindow(). Je li okno ma sta si nie głównym oknem współrz dne w oknie macie ystym, gdy okno macierzyste zostanie
aplikacji, lecz oknem steruj cym przebiegiem programu, funkcja przesuni te - element steruj cy b dzie przesuni ty
wymaga podania nast puj cych argumentów: automatycznie. Równie po zmianie rozmiarów okna macie ystego
okno elementu steruj cego zmienia poło enie, zawsze jednakowe
- rodzaj klasy steruj cej (ang. control class) wzgl dem lewego górnego rogu.
- rodzaj elementu steruj cego (ang. control style)
Usuwanie okna steruj cego
Typowe rodzaje elementów (obiektów) staruj cych w rodowisku
Windows: Okienko elementu steruj cego mo emy usun (jak i ka de inne
okna) przy pomocy funkcji:
BUTTON - klawisz rozkazu, prostok tne okno typu
Child, reprezentuj ce przycisk, który DestroyWindow(hKlawisz);
u ytkownik mo e wł czy ; przycisk mo e
by opatrzony etykiet (text label).
127
Przekazywanie informacji do- i z- okna elementu steruj cego CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
0, 0, hInstance, 0);
Zdarzenie w oknie elementu steruj cego - np. klikni cie klawisza
GetClientRect(hWnd, (LPRECT) &rect);
- powoduje wygenerowanie komunikatu WM_COMMAND. Towarzysz ce hEditWnd = CreateWindow ("Edit",NULL, WS_CHILD | WS_VISIBLE |
komunikatowi parametry przenosz istotne informacje: ES_MULTILINE | WS_VSCROLL |
WS_HSCROLL | ES_AUTOHSCROLL |
wParam - identyfikator elementu steruj cego, ES_AUTOVSCROLL, 0, 0,(rect. right -
lParam - dla wci ni tego klawisza b dzie to BN_CLICKED. rect. left),
(rect. bottom - rect.
Niektóre komunikaty Windows mog by kierowane do okna elementu top),hWnd,IDC_EDIT, hIstance,NULL);
steruj cego i wymusza pewne operacje. Dla przykładu komunikat if( ! hEditWnd )
WM_GETTEXTLENGTH przesłany do okienka edycyjnego typu Text Edit {
Box (element steruj cy klasy EDIT) jest daniem podania DestroyWindow(hWnd);
długo ci tekstu wpisanego wła nie do okienka. Aby Windows return 0;
wygenerowały komunikat i przesłały go do naszego elementu }
steruj cego - musimy "poprosi " przy pomocy funkcji ShowWindow(hWnd, nCmdShow);
SendMessage() (Wy lijKomunikat): UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
DlugTekstu = SendMessage(hEditWnd, WM_GETTEXTLENGHT, 0, 0); {
gdzie: TranslateMessage(&msg );
hEditWnd jest identyfikatorem elementu - okienka edycyjnego DispatchMessage(&msg );
}
[???]Robi na "szaro'? return 0;
________________________________________________________________ }
Podobnie jak opcje w menu - klawisze tak e mog zosta
udost pnione (ang. enable), b d zablokowane (ang. disable). long FAR PASCAL WndProc (HWND hWnd, unsigned Message,
Je li hKlawisz b dzie identyfikatorem elementu steruj cego, WORD wParam, LONG lParam)
mo na go udost pni (1), b d zablokowa (0) przy pomocy {
funkcji: switch(Message)
{
EnableWindow(hKlawisz, 0); case ID_EDIT:
EnableWindow(hKlawisz, 1); if(HIWORD(lParam)==EN_ERRSPACE)
________________________________________________________________
/* starsze słowo lParam zawiera wła ciwe dla okna edycyjnego
Typowy projekt dla rodowiska Windows składa si z kilku (czasem wiadomo ci, je eli jest to EN_ERRSPACE - okno steruj ce nie
mo e alokowa dodatkowego obszaru pami ci */
kilkunastu) plików: .H, .MNU, .DLG, .RC, .DEF, .PRJ, .ICO, .BMP,
{
itp. Kompilator zasobów generuje na podstawie tego "składu" MessageBox (GetFocus(), "Brak pamieci", "MEDYT-01",
ko cowy plik aplikacji. MB_ICONSTOP | MB_OK);
}
------------------Plik MEDYT-01.H------------------------------- break;
#define szAppName "MEDYT-01" case WM_SETFOCUS:
#define ID_EDIT 200 SetFocus(hEditWnd);
break;
------------------Plik główny: MEDYT-01.CPP---------------------
/* Pierwsze dwa parametry funkcji MoveWindow s ustawione na
#include <windows.h> zero, dzi ki temu po zastosowaniu tej funkcji nie zmieni si
#include "EDIT.H"
#pragma argused wzajemne poło enie obu okien, a jedynie uaktualnianiu
ulegnie okno steruj ce. */
HWND hEditWnd;
case WM_SIZE:
long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ; MoveWindows(hEditWnd, 0, 0, LOWORD(lParam));
HIWORD(lParam), TRUE);
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, break;
LPSTR lpszCmdLine, int nCmdShow) case WM_DESTROY:
{ PostQuitMessage(0);
WNDCLASS wndClass; break;
MSG msg;
HWND hWnd; default:
RECT rect; return (DefWindowProc(hWnd,Message,wParam,lParam));
}
if ( !hPrevInstance ) return 0;
{ }
wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc; Jak sterowa prac aplikacji. Jak umieszcza elementy
wndClass.cbClsExtra = 0; graficzne-steruj ce w oknie aplikacji. Najcz ciej stosowane
wndClass.cbWndExtra= 0; funkcje API Windows.
wndClass.hInstance = hInstance; ________________________________________________________________
wndClass.hIcon = LoadIcon(NULL, szAppName);
wndClass.hCursor= LoadCursor(NULL, IDC_CROSS); Elementy steruj ce prac aplikacji w Windows (ang. controls) s
wndClass.hbrBackground= GetStockObject(WHITE_BRUSH ); równie swoistymi okienkami (tyle, e potomnymi - Child Window
wndClass.lpszMenuName= NULL; wobec głównego okna aplikacji - Parent Window).
wndClass.lpszClassName= szAppName; Do utworzenia takiego specjalnego okna równie mo na u y
funkcji CreateWindow(). Je li okno ma sta si nie głównym oknem
if (!RegisterClass(&wndClass))
return 0; aplikacji, lecz oknem steruj cym przebiegiem programu, funkcja
} wymaga podania nast puj cych argumentów:

hWnd = CreateWindow(szAppName, - rodzaj klasy steruj cej (ang. control class)


"MEDYT-01", WS_OVERLAPPEDWINDOW, - rodzaj elementu steruj cego (ang. control style)
128
Usuwanie okna steruj cego
Typowe rodzaje elementów (obiektów) staruj cych w rodowisku
Windows: Okienko elementu steruj cego mo emy usun (jak i ka de inne
okna) przy pomocy funkcji:
BUTTON - klawisz rozkazu, prostok tne okno typu
Child, reprezentuj ce przycisk, który DestroyWindow(hKlawisz);
u ytkownik mo e wł czy ; przycisk mo e
by opatrzony etykiet (text label).
Przekazywanie informacji do- i z- okna elementu steruj cego
COMBOBOX - okienko dialogowe kombinowane. Jest
zło eniem klasy EDIT i LISTBOX; Zdarzenie w oknie elementu steruj cego - np. klikni cie klawisza

LISTBOX - oknienko z list (zwykle element - powoduje wygenerowanie komunikatu WM_COMMAND. Towarzysz ce
składowy okienka dialogowego typu komunikatowi parametry przenosz istotne informacje:
Combo Box.
wParam - identyfikator elementu steruj cego,
STATIC - pole statyczne (bez prawa edycji). lParam - dla wci ni tego klawisza b dzie to BN_CLICKED.
Niewielkie okno zawieraj ce tekst lub
Niektóre komunikaty Windows mog by kierowane do okna elementu
grafik ; słu y z reguły do oznaczania steruj cego i wymusza pewne operacje. Dla przykładu komunikat
WM_GETTEXTLENGTH przesłany do okienka edycyjnego typu Text Edit
innych okien steruj cych. Box (element steruj cy klasy EDIT) jest daniem podania
długo ci tekstu wpisanego wła nie do okienka. Aby Windows
SCROLLBAR - pasek przewijania (pionowy - Vertical wygenerowały komunikat i przesłały go do naszego elementu
steruj cego - musimy "poprosi " przy pomocy funkcji
Scroll Bar; poziomy - Horizontal SendMessage() (Wy lijKomunikat):
Scroll Bar).
DlugTekstu = SendMessage(hEditWnd, WM_GETTEXTLENGHT, 0, 0);
Style klawiszy steruj cych (Button Styles): gdzie:
hEditWnd jest identyfikatorem elementu - okienka edycyjnego
BS_PUSHBUTTON - Klawisz. Okno steruj ce wysyła, po
ka dym wyborze klawisza [???]Robi na "szaro'?
(klikni cie), wiadomo do okna ________________________________________________________________
macie ystego (Parent Window). Podobnie jak opcje w menu - klawisze tak e mog zosta
udost pnione (ang. enable), b d zablokowane (ang. disable).
BS_RADIOBUTTON - Okr gły przeł cznik działaj cy Je li hKlawisz b dzie identyfikatorem elementu steruj cego,
zwykle na zasadzie @tylko jeden mo na go udost pni (1), b d zablokowa (0) przy pomocy
z grupy". funkcji:

BS_CHECKBOX - - prostok tny przeł cznik [X] EnableWindow(hKlawisz, 0);


wł czaj cy (aktywna) lub EnableWindow(hKlawisz, 1);
wył czaj cy (nieaktywna) ________________________________________________________________
opcj . Działa niezale nie od
pozostałych. Typowy projekt dla rodowiska Windows składa si z kilku (czasem

Inne style okre laj np. sposób edycji tekstu (ES_LEFT, kilkunastu) plików: .H, .MNU, .DLG, .RC, .DEF, .PRJ, .ICO, .BMP,
ES_MULTILINE, itp.) Szczegóły - patrz system Help - Windows API.
Oto przykład utworzenia okna elementu steruj cego typu "Klawisz" itp. Kompilator zasobów generuje na podstawie tego "składu"
ko cowy plik aplikacji.
(BUTTON to nazwa typu):
------------------Plik MEDYT-01.H-------------------------------
hControlWnd = CreateWindow ("BUTTON", " Napis_na_Klawiszu ", #define szAppName "MEDYT-01"
BS_PUSHBUTTON |WS_CHILD | WS_VISIBLE, #define ID_EDIT 200
10, 20, 30, 40,
hWnd, ID_Elem, hInstance, 0); ------------------Plik główny: MEDYT-01.CPP---------------------

Identyfikator ID_Elem jest potrzebny, gdy w jednym oknie #include <windows.h>


znajduje si kilka elementów steruj cych - pozwala na ich #include "EDIT.H"
rozpoznawanie w programie. Sposób przekazywania informacji o #pragma argused
klikni ciu klawisza przypomn na przykładzie okienka
komunikatów: HWND hEditWnd;

if(IDOK==MessageBox(0, "", "", MB_OK)) ... long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ;

IDOK to predefiniowany w Windows identyfikator klawisza [OK]. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
Oto krótkie wyja nienie pozostałych elementów: LPSTR lpszCmdLine, int nCmdShow)
{
10, 10, 30, 20, - współrz dne. x, y, szeroko , wysoko WNDCLASS wndClass;
hWnd, - oznacznik okna macie ystego MSG msg;
HWND hWnd;
Przesuwanie i zmiana wielko ci elementu steruj cego. RECT rect;

Funkcja MoveWindow() przesuwa okno we wskazane miejsce: if ( !hPrevInstance )


{
MoveWindow(hKlawisz, 10, 10, 20, 30, TRUE); wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc;
Poniewa okno elementu steruj cego ma zadane wzgl dne wndClass.cbClsExtra = 0;
współrz dne w oknie macie ystym, gdy okno macierzyste zostanie wndClass.cbWndExtra= 0;
przesuni te - element steruj cy b dzie przesuni ty wndClass.hInstance = hInstance;
automatycznie. Równie po zmianie rozmiarów okna macie ystego wndClass.hIcon = LoadIcon(NULL, szAppName);
okno elementu steruj cego zmienia poło enie, zawsze jednakowe wndClass.hCursor= LoadCursor(NULL, IDC_CROSS);
wzgl dem lewego górnego rogu. wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
wndClass.lpszMenuName= NULL;
129
wndClass.lpszClassName= szAppName; DialogBox(), a do zako czenia ich " ycia na ekranie" -
EndDialog(). Podobnie jak ka de okno, równie okno dialogowe
if (!RegisterClass(&wndClass)) musi mie swoj funkcj , obsługi komunikatów Windows. Zamiast
return 0; WindowProc() nazywa si j tradycyjnie DlgProc():
}
BOOL FAR PASCAL DlgProc(HWND hDLG, unsigned Message, WORD
hWnd = CreateWindow(szAppName, wParam, LONG lParam);
"MEDYT-01", WS_OVERLAPPEDWINDOW, {
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, switch (message)
0, 0, hInstance, 0); {
...
GetClientRect(hWnd, (LPRECT) &rect); default: return (0);
hEditWnd = CreateWindow ("Edit",NULL, WS_CHILD | WS_VISIBLE | }
ES_MULTILINE | WS_VSCROLL | }
WS_HSCROLL | ES_AUTOHSCROLL |
ES_AUTOVSCROLL, 0, 0,(rect. right - Za wyj tkiem braku domy lnego handlera Windows -
rect. left), DefWindowProc(), który jest zb dny, w zwi zku z wewn trznie
(rect. bottom - rect. przyjmowanymi warto ciami domy lnymi, funkcja podobna jest
top),hWnd,IDC_EDIT, hIstance,NULL); bardzo w swojej konstrukcji do WindowProc(). Funkcja zwraca
if( ! hEditWnd ) warto FALSE (czyli 0), je li przesłany komunikat nie został
{ obsłu ony. Typowymi komunikatami, które rozpatruje wi kszo
DestroyWindow(hWnd); okienek dialogowych, s WM_INITDIALOG oraz WM_COMMAND.
return 0;
} Przykład okienka dialogowego:
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd); ------------------Plik: DLGBOX1.H-------------------------------
while (GetMessage(&msg, NULL, 0, 0))
{ #define szAppName "DLGBOX1"
TranslateMessage(&msg ); #define IDM_DLG1 100
DispatchMessage(&msg );
} ------------------Plik zasobów: DLGBOX1.RC----------------------
return 0;
} #include "DLGBOX1.H"
#include <windows.h>
long FAR PASCAL WndProc (HWND hWnd, unsigned Message,
WORD wParam, LONG lParam) IDI_ICON ICON CONTROL.ICO
{
switch(Message) DLGBOX1 MENU
{ BEGIN
case ID_EDIT: MENUITEM "&O DlgBox" IDM_DLG1
if(HIWORD(lParam)==EN_ERRSPACE) /* to menu pojawi si w oknie macie ystym */
END
/* starsze słowo lParam zawiera wła ciwe dla okna edycyjnego
wiadomo ci, je eli jest to EN_ERRSPACE - okno steruj ce nie DLGBOX1 DIALOG 30,30,200,100
mo e alokowa dodatkowego obszaru pami ci */
/* Pierwsze liczby to współrz dne lewego-górnego rogu okna, dwie
{
MessageBox (GetFocus(), "Brak pamieci", "MEDYT-01", nast pne - to szeroko i długo . Współrz dne s wzgl dne.
MB_ICONSTOP | MB_OK); Punkt (0,0) to naro nik okna macie ystego */
}
break; STYLE WS_POPUP | WS_DLGFRAME
case WM_SETFOCUS:
SetFocus(hEditWnd); BEGIN
break; LTEXT "Przyklad" -1, 0, 12, 160, 8
CTEXT "DLGBOX1 - Przyklad" -1, 0, 36, 160, 8
/* Pierwsze dwa parametry funkcji MoveWindow s ustawione na DEFPUSHBUTTON "OK" IDOK, 64, 60, 32,14, WS_GROUP
zero, dzi ki temu po zastosowaniu tej funkcji nie zmieni si END
----------------------------------------------------------------
wzajemne poło enie obu okien, a jedynie uaktualnianiu
ulegnie okno steruj ce. */ Pomi dzy par słów kluczowych BEGIN-END mo na umieszcza ró ne
instrukcje steruj ce. Definiuj one, jaki rodzaj okna
case WM_SIZE: steruj cego uka e si w okienku dialogowym. Instrukcje te mo na
MoveWindows(hEditWnd, 0, 0, LOWORD(lParam)); stosowa w nast puj cym formacie:
HIWORD(lParam), TRUE);
break; typ_okna "tekst" ID, x, y, szeroko , wysoko [styl]
case WM_DESTROY:
PostQuitMessage(0); Parametr styl jest opcjonalny. Styl okna okre laj
break; identyfikatory predefiniowane w API Windows (WS_...). Parametr
ID jest odpowiednikiem identyfikatora dla okien potomnych typu
default: Child Window; dla okien steruj cych, które nie zwracaj
return (DefWindowProc(hWnd,Message,wParam,lParam)); komunikatów do okna macierzystego, ma warto -1. IDOK
} wykorzystali my jako identyfikator dla okna steruj cego typu
return 0; BUTTON. Zostanie on wysłany do funkcji okienkowej jako warto
} parametru wParam, gdy u ytkownik kliknie klawisz.

------------------Plik główny: DLGBOX1.CPP----------------------

LEKCJA 44: O Okienkach dialogowych.


________________________________________________________________ #include <windows.h>
O tym, jak konstruuje si okienka dialogowe. #include <stdio.h>
________________________________________________________________ #include <string.h>
#include "DLGBOX1.H"
Do wy wietlania okienek dialogowych w Windows API słu y funkcja #pragma argused
130
hDC = BeginPaint(hWnd , &ps);
HANDLE hInst; TextOut(hDC, 30, 50,"Demo okienka dialogowego", 25);
TextOut(hDC, 30, 70,"Zastosuj menu...", 17);
long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ; EndPaint(hWnd, &ps);
BOOL FAR PASCAL ControlProc (HWND, unsigned, WORD, LONG) ; break;
case WM_DESTROY:
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, PostQuitMessage(0);
LPSTR lpszCmdLine, int nCmdShow ) break;
{
WNDCLASS wndClass; default:
MSG msg; return (DefWindowProc(hWnd,Message,wParam,lParam));
HWND hWnd; }
if ( !hPrevInstance ) return 0;
{ }
wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc; Stosuj c okienko edycyjne mo emy u y nast puj cych
wndClass.cbClsExtra = 0; predefiniowanych parametrów:
wndClass.cbWndExtra= 0;
wndClass.hInstance = hInstance; CONTROL - okre la okno elementu steruj cego zdefiniowane
wndClass.hIcon = LoadIcon(NULL, szAppName);
wndClass.hCursor= LoadCursor(NULL, IDC_ARROW ); przez u ytkownika.
wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
wndClass.lpszMenuName= szAppName; CONTROL "tekst", klasa, styl, x, y, szeroko , wysoko
wndClass.lpszClassName= szAppName;
LTEXT - element steruj cy: okienko tekstowe
if (!RegisterClass(&wndClass)) Wyrównywanie tesktu: do lewej.
return 0; RTEXT - j. w. Wyrównywanie tesktu: do prawej
} CTEXT - j. w. Wyrównywanie tesktu: centrowanie w okienku
CHECKBOX - pole tekstowe po prawej stronie przeł cznika typu
hInst = hInstance; Check Box.
hWnd = CreateWindow(szAppName, "DLGBOX1", PUSHBUTTON - Klawisz z napisem.
WS_OVERLAPPEDWINDOW, LISTBOX - okienko z list
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance, 0); GROUPBOX - grupa elementów steruj cych typu BUTTON; zgrupowanie

ShowWindow(hWnd, nCmdShow); kilku elementów steruj cych i otoczenie ramk . Tekst


UpdateWindow(hWnd);
zostanie umieszczony w lewym górnym rogu.
while (GetMessage(&msg, 0, 0, 0)) DEFPUSHBUTTON - Klawisz domy lny w stylu BS_DEFPUSHBUTTON.
{ RADIOBUTTON - analogicznie jak dla stylu BS_RADIOBUTTON.
TranslateMessage(&msg ); EDITTEXT - tworzy okno oparte na klasie EDIT.
DispatchMessage(&msg ); COMBOBOX - tworz okno oparte na klasie COMBOBOX.
} ICON - definiuje ikon opart na klasie STATIC; w
return 0; okienku dialogowym.
} SCROLLBAR - tworzy okno oparte na klasie SCROLLBAR.

BOOL FAR PASCAL ControlProc (HWND hDlg, unsigned Message, [!!!]UWAGA


WORD wParam, LONG lParam) ________________________________________________________________
{ W niektórych przypadkach okienko dialogowe mo e by głównym
switch(msg) oknem aplikacji.
{ ________________________________________________________________
case WM_INITDIALOG:
return TRUE;
break; LEKCJA 45: Doł czanie zasobów - menu i okienka dialogowe.
case WM_COMMAND: ________________________________________________________________
switch(wParam)
{ Jak doda menu i okienka dialogowe do aplikacji.
case IDOK: ________________________________________________________________
case IDCANCEL:
EndDialog(hDlg,0); Aby doda do aplikacji menu nale y utworzy plik (ASCII) zasobów
return TRUE; *.RC, który zostanie u yty w projekcie. Pierwsz instrukcj jest
} MENU, "NazwaMenu",
break; MENU i para słów kluczowych (znanych z Pascala) BEGIN oraz END,
} mi dzy którymi znajdzie si kombinacja instrukcji MENUITEM oraz
return (0); POPUP.
}
MENUITEM definiuje pozycj na głównym pasku menu - okre la - jak
long FAR PASCAL WndProc (HWND hWnd, unsigned msg, b dzie wygl da i jaki identyfikator b dzie j reprezentował.
WORD wParam, LONG lParam) Instrukcja POPUP pozwala, rozwin list pozycji wchodz cych w
{ skład danego menu. Nazwa menu mo e by u yta podczas rejestracji
FARPROC lpControlProc; klasy danego okna jako wpisana w odpowiednie pole struktury na
switch(Message) której oparte jest okno. W ten sposób uzyskamy menu dla
{ wszystkich okien danej klasy.
case WM_COMMAND:
switch(wParam) BEGIN
{ POPUP "Rozkaz"
case IDM_ABOUT: BEGIN
lpControlProc = MakeProcInstance((FARPROC) ControlProc, hInst); MENUITEM "Rozkaz 1", IDM_R1
MENUITEM "Rozkaz 2", IDM_R2
DialogBox(hInst, "DLGBOX1", hWnd, lpControlProc); MENUITEM "Rozkaz 3", IDM_R3
return 0; END
} POPUP "Kolor"
break; BEGIN
case WM_DESTROY: MENUITEM "Czarny", IDM_BLACK
131
MENUITEM "Niebieski", IDM_BLUE sensowne (mo liwe do wykonania). Zaraz przekonasz si , jak to
MENUITEM "Zielony", IDM_GREEN si dzieje, e niektóre pozycje "robi si na szaro". W API
END Windows słu y do tego funkcja:
MENUITEM "Koniec", IDM_EXIT
END EnableMenuItem (hMenu, IDM_R1, MF_DISABLED);
EnableMenuItem (hMenu, IDM_R1, MF_GRAYED);
Ka da pozycja ma własny identyfikator, np. IDM_EXIT, IDM_BLUE, EnableMenuItem (hMenu, IDM_R1, MF_ENABLED);
który Windows przekazuj do aplikacji, gdy zostaje ona wybrana
przez u ytkownika z systemu menu. Poniewa ka dy identyfikator Rozkaz R1 skojarzony z identyfikatorem IDM_R1 i znajduj cy si w
powinien by unikalny, najlepiej jest go zdefiniowa w pliku
zasobów .RC lub własnym pliku nagłówkowym .H: systemie menu o oznaczniku hMenu stanie si kolejno zablokowany,

#define IDM_EXIT 100 widoczny-lecz-niedost pny, dost pny.


#define IDM_BLUE 101
#define IDM_R1 102 Dodawanie i usuwanie pozycji w menu
...
Dodawanie pozycji do menu mo e by wykonane dwoma sposobami:
Mamy ju zdefiniowane menu w pliku zasobów, nale y je teraz przez wstawienie pomi dzy istniej ce pozycje lub na ko cu listy.
doł czy do aplikacji na jeden z dwóch sposobów:
W pierwszym przypadku nale y u y funkcji InsertMenu(). Funkcja
- Mo na okre li menu jako menu danej klasy okien, gdy klasa ta ta pozwala jednocze nie okre li status pozycji, mi dzy innymi
czy b dzie umieszczone nowe pole mo na okre li dwoma sposobami:
jest rejestrowana. W ten sposób doł czymy menu do ka dego
okna opartego na tej klasie. Aby to wykona , wystarczy przez identyfikator pozycji maj cej by przed now lub przez
przypisa odpowiedniemu polu struktury nazw naszego menu. numeracj poszczególnych, licz c id lewej skrajnej pozycji (C++
Je eli obiekt klasy WNDCLASS nazwiemy Window1, to: tradycyjnie liczy od zera). Sposób "odliczania" pozycji w
systemie menu okre la tryb (BYCOMMAND lub BYPOSITION - rozkaz,
Window1.lpszMenuName = "NazwaMenu"; b d pozycja):

Gdy klasa zostanie zarejestrowana, ka de okno tej klasy b dzie InsertMenu(hMenu, IDM_R1, MF_BYCOMMAND |MF_DISABLED,
miało to samo menu, chyba e dostarczymy odpowiedni IDM_R5,
identyfikator menu w momencie tworzenia okna funkcj "Rozkaz 5");
CreateWindow(). InsertMenu(hMenu, 1, MF_ENABLED, IDM_R5, "Rozkaz 5");

- Drugim sposobem jest doł czenie menu w momencie tworzenia Funkcja wstawi za pozycj "Rozkaz 1" now pozycj "Rozkaz 5",
okna, wtedy tylko tworzone okno b dzie miało dane menu. jednocze nie ustawia jej status. Drug funkcj dodaj c pozycj
do utworzonego systemu menu jest:
Nale y najpierw załadowa menu przy u yciu funkcji LoadMenu(),
która zwraca jego identyfikator: AppendMenu(hMenu, MF_ENABLED, IDM_R4, "Rozkaz 4");

HMENU hMenu = LoadMenu(hInstance, "NazwaMenu"); Poni ej przykład zdefiniowania menu aplikacji w taki wła nie
sposób:
hWnd = CreateWindow(szAppName,
"Nazwa Aplikacji", case WM_CREATE:
WS_OVERLAPPEDWINDOW, hMenu = CreateMenu(); //Utworzenie menu
CW_USEDEFAULT, AppendMenu(hMenu, MF_ENABLED, IDM_R1, "Rozkaz 1");
CW_USEDEFAULT, AppendMenu(hMenu, MF_ENABLED, IDM_R2, "Rozkaz 2");
CW_USEDEFAULT, AppendMenu(hMenu, MF_ENABLED, IDM_R3, "Rozkaz 3");
CW_USEDEFAULT, SetMenu(hWnd, hMenu); //Wy wietlenie menu
NULL, ...
hMenu, <-- tu break;
hIstance,
NULL ); Usuwanie pozycji z menu mo na przeprowadzi dwoma sposobami:

Typow praktyk jest doł czenie pozycji menu do instrukcji - poprzez wskazanie numeru pozycji w systemie menu:
switch w funkcji okienkowej. Poniewa Windows wysyła komunikat
WM_COMMAND do odpowiedniej funkcji okienkowej w odpowiedzi na DeleteMenu(hMenu, 1, MF_BYPOSITION); //usuni ta zostanie druga
wybór pozycji przez u ytkownika, a parametr wParam zawiera //pozycja z systemu menu
identyfikator tej e pozycji - mo na napisa tak:
- przez wyszczególnienie identyfikatorem pozycji
case WM_COMMAND:
switch (wParam) DeleteMenu(hMenu, IDM_R3, MF_BYCOMMAND);
{
case IDM_R1: Po usuni ciu pozycji z menu Window usunie równie wszystkie
... obsługa ...; break; zwi zane z ni submenu.
case IDM_R2:
... obsługa ...; break Zaznaczanie pozycji w menu (mark).
case IDM_QUIT:
...DestroyWindow(...); Obok pozycji w menu mo na umie ci znak markuj cy ("ptaszek").
} Znak markuj cy mo na zainicjowa w pliku zasobów .RC. Dzi ki
temu, u ytkownik w momencie otwarcia okna dowie si z wygl du
Jak rozbudowuje si menu. menu o pocz tkowym ustawieniu opcji.

API Windows zawiera funkcje, umo liwiaj ce rozbudow menu nawet MENUITEM "Rozkaz 2", IDM_R2, CHECKED
w ruchu aplikacji (run-time). Rozbudowa menu w konkretnym oknie
nie poci ga za sob zmian w innych, opartych na tej samej klasie W trakcie pracy aplikacji nale y posłu y si funkcj
CheckMenuItem(). Zwykle najpierw kasujemy "ptaszka" przy
oknach. Jest to mo liwe, poniewa w chwili tworzenia okna poprzedniej pozycji:
otrzymuje ono swoj kopi menu (tradycyjne w C/C++ przekazywanie
CheckMenuItem( hMenu, IDM_R2, MF_UNCHECKED);
kopii zmiennej do funkcji). CheckMenuItem(hMenu, IDM_R3, MF_CHECKED);

Nie wszystkie pozycje w menu s w danym stadium pracy aplikacji Zmiany pozycji menu
132
BEGIN
Funkcja ModyfyMenu() pozwala na zmian nazwy pozycji i jej POPUP "&File"
atrybutów. Oto przykłady u ycia tej funkcji: BEGIN
MENUITEM "&Open", IDM_OPEN
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND, IDM_R2, "Polecenie MENUITEM "&New" , IDM_NEW
2"); MENUITEM "&Save", IDM_SAVE
MENUITEM "Save &As", IDM_SAVEAS
Identyfikator pozycji nie ulegnie zmianie, jedynie nazwa pola z MENUITEM "&DOS shell", IDM_DOSSHELL
"Rozkaz 2" na "Polecenie 2". Mo emy zmieni jednocze nie i MENUITEM "E&xit", IDM_EXIT
identyfikator, by nie pomyli si w programie: END
POPUP "&Options"
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND, IDM_P2, "Polecenie BEGIN
2"); MENUITEM "Menu&1", IDM_M1,
MENUITEM "Menu&2" , IDM_M2, CHECKED
Dodatkowo mo na ustawi za jednym zamachem i atrybuty: END
END
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND | MF_CHECKED |
MF_GRAYED, ZASTOSOWANIE Resource Worshop

IDM_R2, "Polecenie 2"); Takie pliki zasobów w Borland C++ mało kto tworzy dzi "na
piechot ". BORLAND C++ oferuje do tego celu dwa
U ycie grafiki w systemie menu. narz dzia:
Edytor zasobów - Resource Workshop
W systemie menu aplikacji mo emy zamiast ła cucha znaków "Rozkaz Automatyczny generator - DialogExpert (wersje 4+)

2" umie ci element graficzny - np. w postaci mapy bitowej. Najwygodniejszym sposobem jest zastosowanie edytora zasobów
Zamiast pola o nazwie "Pole", wprowadza map bitow : Resource Workshop. Jest to tym wygodniejsze, e Resource
Workshop pozwala jednocze nie obserwowa i ródłowy plik *.RC
HMENU hMenu = GetMenu(hWnd); (ASCII) i efekt - menu w ruchu.
HBITMAP hBitmap = LoadBitmap (hIstance, "Pole"); W rodowisku Borland C++ okienka dialogowe tworzy si tak e
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND | MF_BITMAP, zwykle przy pomocy Resource Worshop.
IDM_R2, Tworzenie okienek dialogowych przy pomocy Resource Workshop
(LPSTR) MAKELONG (hBitmap, 0)); przypomina składanie budowli z gotowych klocków.

GetMenu() zwraca oznacznik aktualnego menu, potrzebny jako Kolejne elementy steruj ce mo emy umieszcza w okienku
pierwszy parametr funkcji ModifyMenu(). Drugim parametrem tej dialogowym poprzez wybranie ich z palety narz dzi i
funkcji jest identyfikator pozycji, któr chcemy zmieni . przeniesienie do projektowanego okienka technik "poci gnij i
Trzecia okre la, e zmiana ma by wykonana przez wyszukanie upu " (drag & drop).
pozycji za po rednictwem jej identyfikatora oraz e now pozycj
Po skróconym omówieniu najwa niejszych funkcji z API Windows
ma reprezentowa mapa bitowa. Czwarty parametr okre la przejd my to niemniej krótkiej prezentacji zasad tworzenia
identyfikator nowej pozycji. Poniewa ostatnim parametrem nie aplikacji przy pomocy biblioteki obiektów OWL.
jest ju wska nik do ła cucha znakowego, nale y przesła
oznacznik mapy bitowej jako mniej znacz ce słowo tego parametru. [Z]
________________________________________________________________
W tym celu 16-bitowy oznacznik jest ł czony z 16-bitow stał , a 1. Przeanalizuj program w pełnej wersji (na dyskietce).
2. Zmodyfikuj dowoln aplikacj przykładow tak, by doł czy do
nast pnie poddawany konwersji do typu Long Pointer to STRing. niej inn ikon .
3. Opracuj własne menu i własn ikon przy pomocy Resource
Zmiana menu aplikacji na kolejne. Workshop.
________________________________________________________________
Aplikacja w ró nych stadiach pracy mo e mie na ekranie ró ne
(kilka czasem kilkana cie) menu. Wymiany menu w oknie aplikacji Krótka instrukcja do Resource Workshop.
mo na dokona , załadowuj c nowe menu funkcj LoadMenu() i
ustawiaj c je jako aktualne funkcj SetMenu(): ________________________________________________________________

... 1. Uruchomienie: Ikonka Worshop w oknie grupowym Borland C++.


hMenu2 = LoadMenu (hIstance, "Menu2"); 2. Pocz tek pracy: File | New Project...
SetMenu (hWnd, hMenu2); 3. Rodzaje zasobów do wyboru w okienku dialogowym "New project":
DrawMenuBar(...);
... [ ] RC - plik zasobów
[ ] CUR - kursor
Menu i Menu2 powinny by zdefiniowane w pliku zasobów *.RC. [ ] BMP - mapa bitowa
Po ka dej zmianie menu nale y u y funkcji DrawMenuBar(), aby [ ] RES - plik zasobów w formie skompilowanej
wprowadzone zmiany pojawiły si na ekranie. Oto przykład [ ] ICO - ikonka
stosownego pliku zasobów: [ ] FNT - czcionki (Fonts)
Wybieramy odpowiednio: RC
Menu1 MENU 4. Zmieni si menu w głównym oknie Resource Workshop. Z menu
BEGIN wybieramy Resource | New
POPUP "&File" W okienku dialogowym z listy Resource Type (rodzaj zasobów):
BEGIN ACCELERATORS, BITMAP, CURSOR, DIALOG, FONT, ICON, MENU,
MENUITEM "&New" , IDM_NEW RCDATA,
MENUITEM "&Save", IDM_SAVE STRINGTABLE, VERSINFO
MENUITEM "E&xit", IDM_EXIT wybieramy odpowiednio MENU lub DILOG.
END
POPUP "&Options" Kolejny raz zmieni si menu. W przypadku menu wybieramy:
BEGIN Menu:
MENUITEM "Menu&1", IDM_M1,CHECKED New pop-up - nowa pozycja POPUP
MENUITEM "Menu&2" , IDM_M2 New menu item - nowa pozycja MENUITEM
END Zwró uwag , e typowe menu File, Edit, Help jesy ju gotowe do
END wstawienia (ukryte pod pozycjami New file pop-up, New edit
pop-up...).
Menu2 MENU
133
W przypadku okienka dialogowego najwa niejsze jest menu Control. zdarzeniowych aplikacji.
A oto najwa niejsze elementy implementacji klasy TApplication:
S tam wszyskie rodzaje podstawowych elementów steruj cych (Push
- Konstruktor obiektu "Aplikacja":
button, Radio button, scroll bar, List box, Combo box, Edit box,
TApplication::TApplication(const char far* name,
itd.). Projektuj c okienko mo esz równie wy wietli siatk HINSTANCE Instance,
(Grid). HINSTANCE prevInstance,
const char far* CmdLine,
Przy pomocy Resource Workshop mo esz poddawa edycji i int CmdShow,
modyfikowa pliki zasobów zarówno nale ce do programów TModule*& gModule)
przykładowych zawartoch na dyskietce, jak i zasoby "firmowych" {
przykładów Borlanda. W katalogach \SOURCE (kody ródłowe .CPP) i hPrevInstance = prevInstance;
nCmdShow = CmdShow;
\EXAMPLES (przykłady - projekty) znajdziesz wiele rozmaitych MainWindow = 0;
przykładów. Mo esz tak e poddawa edycji pliki .BMP, .ICO i inne HAccTable = 0; //Accelerator Keys Table Handle
BreakMessageLoop = FALSE;
niekoniecznie nale ce do pakietu Borland C++. AddApplicationObject(this); //this to wska nik do własnego
________________________________________________________________ gModule = this; //obiektu, czyli do bie . aplikacji
}

Funkcja - metoda "Zainicjuj Instancj ":


LEKCJA 46: O PROGRAMACH OBIEKTOWO - ZDARZENIOWYCH.
________________________________________________________________ void TApplication::InitInstance()
Po aplikacjach sekwencyjnych, proceduralno-zdarzeniowych, jedno- {
InitMainWindow();
i dwupoziomowych, pora rozwa y dokładniej stosowanie technik if (MainWindow)
obiektowych. {
________________________________________________________________ MainWindow->SetFlag(wfMainWindow);
MainWindow->Create();
Programy pracuj ce w rodowisku Windows tworzone s w oparciu o MainWindow->Show(nCmdShow);
tzw. model trójwarstwowy. Pierwsza warstwa to warstwa }
wizualizacji, druga - interfejs, a trzecia - to wła ciwa
maszyneria programu. W tej lekcji zajmiemy si "anatomi " Metoda "Zainicjuj główne okno aplikacji":
aplikacji wielowarstwowych a nast pnie sposobami wykorzystania
bogatego instrumentarium oferowanego przez Borlanda wraz z void TApplication::InitMainWindow()
kompilatorami BC++ 3+...4+. {
SetMainWindow(new TFrameWindow(0, GetName()));
Biblioteka OWL w wersjach BORLAND C++ 3, 3.1, 4 i 4.5 zawiera }
definicje klas potrzebnych do tworzenia aplikacji dla Windows.
Fundamentalne znaczenie dla wi kszo ci typowych aplikacji maj Metoda Run() - "Uruchom program":
nast puj ce klasy:
int TApplication::Run()
TModule (moduł - program lub biblioteka DLL) {
TApplication (program - aplikacja) int status;
TWindow (Okno) {
if (!hPrevInstance) InitApplication();
Rozpoczn od krótkiego opisu dwu podstawowych klas. InitInstance();
status = MessageLoop();
KLASA TApplication. }

Tworz c obiekt klasy TNaszProgram b dziemy wykorzystywa A oto p tla pobierania komunikatów w uproszczeniu. "Pump" to po
dziedziczenie od tej wła nie klasy bazowej: prostu "pompowanie" komunikatów (message) oczekuj cych (waiting)

class TNaszProgram : public TApplication w kolejce. PeekMessage() to sprawdzenie, czy w kolejce oczekuje
komunikat. PM_REMOWE to "brak komunikatu".
Podstawowym celem zastosowania tej wła nie klasy bazowej jest
odziedziczenie gotowej funkcji - metody virtual InitMainWindow() BOOL TApplication::PumpWaitingMessages()
{
(zainicjuj główne okno programu). Utworzenie obiektu klasy MSG msg;
TNaszProgram nast puje zwykle w czterech etapach: BOOL foundOne = FALSE;

* Windows uruchamiaj program wywołuj c główn funkcj WinMain() while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
lub OwlMain() wchodz c w skład ka dej aplikacji. foundOne = TRUE;
* Funkcja WinMain() tworzy przy pomocy operatora new nowy obiekt if (msg.message == WM_QUIT)
{
- aplikacj . BreakMessageLoop = TRUE;
* Obiekt - aplikacja zaczyna funkcjonowa . Konstruktor obiektu MessageLoopResult = msg.wParam;
(własny, b d odziedziczony po klasie TApplication) wywołuje ::PostQuitMessage(msg.wParam);
funkcj - wirtualn metod InitMainWindow(). break;
* Funkcja przy pomocy operatora new tworzy obiekt - okno }
aplikacji.
if (!ProcessAppMsg(msg))
Wska nik do utworzonego obiektu zwraca funkcja GetApplication(). {
::TranslateMessage(&msg);
Dla zobrazowania mechanizmów poni ej przedstawiamy uproszczony ::DispatchMessage(&msg);
"wyci g" z dwu opisywanych klas. Nie jest to dokładna kopia kodu }
}
ródłowego Borlanda, lecz skrót tego kodu pozwalaj cy na return foundOne;
zrozumienie metod implementacji okienkowych mechanizmów wewn trz }

klas biblioteki OWL i tym samym wewn trz obiektów obiektowo - int TApplication::MessageLoop()
134
{ Metoda GetWindowClass() bardzo przypomina klasyczne
long idleCount = 0; zainicjowanie zanej ju struktury WNDCLASS:
MessageLoopResult = 0;
while (!BreakMessageLoop) { void TWindow::GetWindowClass(WNDCLASS& wndClass)
TRY { {
if (!IdleAction(idleCount++)) wndClass.cbClsExtra = 0;
::WaitMessage(); wndClass.cbWndExtra = 0;
if (PumpWaitingMessages()) wndClass.hInstance = *GetModule();
idleCount = 0; wndClass.hIcon = 0;
} wndClass.hCursor = ::LoadCursor(0, IDC_ARROW);
if (MessageLoopResult != 0) { wndClass.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
::PostQuitMessage(MessageLoopResult); wndClass.lpszMenuName = 0;
break; wndClass.lpszClassName = GetClassName();
} wndClass.style = CS_DBLCLKS;
}) wndClass.lpfnWndProc = InitWndProc;
} }
BreakMessageLoop = FALSE;
return MessageLoopResult; Skoro te wszystkie "klocki" zostały ju zaimplementowane
} wewn trz definicji klas, nasze programy powinny tylko umiej tnie

else if (::IsWindowEnabled(wnd)) { z nich korzysta a teksty ródłowe programów powinny ulec


*(info->Wnds++) = wnd; skróceniu i uproszczeniu.
::EnableWindow(wnd, FALSE);
} STADIA TWORZENIA OBIEKTOWEJ APLIKACJI.
}
return TRUE; Poniewa znakomita wi kszo dzisiejszych u ytkowników pracuje z
}
Windows 3.1, 3.11, i NT - zaczniemy tworzenie aplikacji od
umieszczenia na pocz tku informacji dla OWL, e nasz docelowy
KLASA TWindow. program ma by przeznaczony wła nie dla tego rodowiska:

Klasa TWindow (Okno) zawiera implementacj wielu przydatnych #define WIN31


przy tworzeniu aplikacji "cegiełek". Poni ej przedstawiono
fragment pliku ródłowego (patrz \SOURCE\OWL\WINDOW.CPP). Łatwo Jak ju wiemy dzi ki krótkiemu przegl dowi struktury bazowych
mo na rozpozna pewne znane ju elementy. klas przeprowadzonemu powy ej - funkcje API Windows s w istocie
...
extern LRESULT FAR PASCAL _export InitWndProc(HWND, UINT, klasycznymi funkcjami posługuj cymi si mechanizmami j zyka C.
WPARAM, LPARAM); C++ jest "pedantem typologicznym" i przeprowadza dodatkowe
... testowanie typów parametrów przekazywanych do funkcji (patrz
struct TCurrentEvent //Struktura Bie ceZdarzenie "Technika programowania w C++"). Aby ułatwi współprac ,
{ zwi kszy poziom bezpiecze stwa i "uregulowa " potencjalne
TWindow* win; //Wska nik do okna konflikty - dodamy do programu:
UINT message; //Komunikat
WPARAM wParam; #define STRICT
LPARAM lParam;
}; Chc c korzysta z biblioteki OWL wypada doł czy wła ciwy plik
... nagłówkowy:
DEFINE_RESPONSE_TABLE(TWindow)
//Makro: Zdefiniuj tablic odpowiedzi na zdarzenia #include <owl.h>
//EV_WM_SIZE - Zdarzenie (EVent)-nadszedł komunikat WM_SIZE
... Plik OWL.H zawiera ju wewn trz doł czony WINDOWS.H, który
EV_WM_SETCURSOR, wyst pował we wcze niejszych aplikacjach proceduralno -
EV_WM_SIZE, zdarzeniowych i jeszcze par innych plików.
EV_WM_MOVE, Poniewa chcemy skorzysta z gotowych zasobów - odziedziczymy
EV_WM_PAINT, pewne cechy po klasie bazowej TApplication. Zgodnie z zasadami
EV_WM_LBUTTONDOWN, programowania obiektowego chc c utworzy obiekt musimy najpierw
EV_WM_KILLFOCUS, zdefiniowa klas :
EV_WM_CREATE,
EV_WM_CLOSE, class TOkno ...
EV_WM_DESTROY,
EV_COMMAND(CM_EXIT, CmExit), i wskaza po której klasie bazowej chcemy dziedziczy :
...
END_RESPONSE_TABLE; class TOkno : public TApplication
{
Funkcje - metody obsługuj ce komunikaty zaimplementowane zostały ...

wewn trz klasy TWindow tak: Konstruktor obiektu klasy TOkno powinien tylko przekaza
parametry konstruktorowi klasy bazowej - i ju .
TWindow::EvCreate(CREATESTRUCT far&)
{ class TOkno : public TApplication
SetupWindow(); {
return (int)DefaultProcessing(); public:
} TOkno(LPSTR name, HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpCmdLine, int nShow) : TApplication(name,
void TWindow::EvSize(UINT sizeType, TSize&) hInstance, hPrevInstance, lpCmdLine, nShow)
{ {
if (Scroller && sizeType != SIZE_MINIMIZED) return;
{ }
Scroller->SetPageSize(); virtual void InitMainWindow();
Scroller->SetSBarRange(); };
}
} Umie cili my w definicji klasy jeszcze jedn funkcj inicjuj c
główne okno aplikacji. Mo emy j zdefiniowa np. tak:
135
void InitMainWindow(){MainWindow = new TWindow(NULL, "Okno
void TOkno::InitMainWindow(void) PW2" );};
{ };
MainWindow = new (TWindow(0, "Napis - Tytul Okna"));
} int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
Działanie funkcji polega na utworzeniu nowego obiektu (operator {
new) klasy bazowej TWindow. Główne okno stanie si zatem TOkno OBIEKT("Okno PW2", hInstance, hPrevInstance,
obiektem klasy TWindow (Niektóre specyficzne aplikacje posługuj lpCmdLine, nCmdShow);
LPSTR p1 = "Jesli wybierzesz [Anuluj]\n- aplikacja nie
si okienkiem dialogowym jako głównym oknem programu. W takiej ruszy!";
sytuacji dziedziczenie powinno nast powa po klasie TDialog). LPSTR p2 = "START";
Konstruktorowi tego obiektu przekazujemy jako parametr napis,
który zostanie umieszczony w nagłówku głównego okna aplikacji. if (MessageBox(NULL, p1, p2, MB_OKCANCEL) == IDCANCEL)
Pierwszy argument (tu ZERO) to wska nik do macie ystego okna, MessageBox(NULL, "I juz..." , "KONIEC" , MB_OK);
poniewa w bardziej zło onych aplikacjach wyst puj okna else
macie yste (parent) i okna potomne (child). Okno macie yste to OBIEKT.Run();
zwykle obiekt klasy "główne okno" a okno potomne to najcz ciej return 0;
okienko dialogowe, b d okienko komunikatów. W tym przypadku }
wpisujemy zero, poniewa program nie posiada w tym stadium ________________________________________________________________
wcze niejszego okna macie ystego. Uwagi techniczne.
Pozostało nam jeszcze doda funkcj WinMain() i pierwszy program cie ki do katalogów:
..\INCLUDE;..\CLASSLIB\INCLUDE;..\OWL\INCLUDE;
obiektowy w wersji "Maszyna do robienia nic" jest gotów. ..\LIB;..\CLASSLIB\LIB;..\OWL\LIB;
Konsolidacja:
Listing . Obiektowa "Maszyna do robienia nic" Options | Linker | Settings: Windows EXE (typ aplikacji)
________________________________________________________________ Options | Linker | Libraries:
#define STRICT - Container class Libraries: Static (bibl. klas CLASSLIB)
#define WIN31 - OWL: Static (bibl. OWL statycze .LIB)
#include <owl.h> - Standard Run-time Lib: Static (bibl. uruchomieniowe .LIB)

class TOkno : public TApplication (.) None - oznacza adne (nie zostan doł czone);
{ (.) Static - oznacza statyczne .LIB
public: (.) Dinamic - oznacza dynamiczne .DLL
TOkno(LPSTR AName, HANDLE hInstance, HANDLE hPrevInstance, ________________________________________________________________
LPSTR lpCmdLine, int nCmdShow)
: TApplication(AName, hInstance, hPrevInstance, lpCmdLine, JAK ROZBUDOWYWA OBIEKTOWE APLIKACJE?
nCmdShow) {};
void InitMainWindow(){MainWindow = new TWindow(NULL, Name);}; Mimo całego uroku obiektowych aplikacji pojawia si tu wszak e
}; drobny problem. Skoro komunikacja klawiatura/myszka -> program
-> ekran nie odbywa si wprost, lecz przy pomocy wymiany danych
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, pomi dzy obiektami ró nych warstw - w jaki sposób (w którym
LPSTR lpCmdLine, int nCmdShow) miejscu programu) umie ci "zwyczajne" funkcje i procedury i jak
{
TOkno OBIEKT("Windows - Program PW1", hInstance, zorganizowa wymian informacji. "Zwyczajne" funkcje b d
hPrevInstance, lpCmdLine, nCmdShow); przecie wchodzi w skład roboczych cz ci naszych programów
OBIEKT.Run(); (Engine). Rozwa my to na przykładzie aplikacji reaguj cej na
return 0; naci ni cie klawisza myszki. Najbardziej istotny -
} "newralgiczny" punkt programu został zaznaczony w tek cie "<--
________________________________________________________________ TU". Od Windows przejmiemy obsług komunikatów
WM_LBUTTONDOWN,
Wykonanie takiej aplikacji przebiega nast puj co. Windows WM_RBUTTONDOWN. Aby wiedzie , w którym miejscu ekranu jest
wywołuj główn funkcj WinMain(), która przekazuje swoje kursor myszki, wykorzystamy informacje przenoszone przez
parametry do konstruktora klasy TOkno::TOkno(). Konstruktor parametr lParam.
przekazuje parametry do konstruktora klasy bazowej
TApplication(). Po skonstruowaniu obiektu w pami ci funkcja Rozpoczniemy tworzenie programu od zdefiniowania klasy.
wywołuje odziedziczon metod Run(). Funkcja Run() wywołuje
metody InitApplication() (zainicjuj aplikacj ) i InitInstance() #define WIN31
(zainicjuj dane wyst pienie programu). Metoda InitInstance() #define STRICT
wywołuje funkcj InitMainWindow(), która buduje główne okno #include <stdio.h>
aplikacji na ekranie. Po pojawieniu si okna rozpoczyna #include <string.h>
działanie p tla pobierania komunikatów (message loop). P tla #include <owl.h>
komunikatów działa a do otrzymania komunikatu WM_QUIT.
class TNAplikacja : public TApplication
Rozbudujmy aplikacj o okienko komunikatów. Zastosujemy do tego {
funkcj MessageBox(). Funkcja zostanie u yta nie jako metoda public:
(składnik obiektu), lecz jako "wolny strzelec" (stand alone TNAplikacja(LPSTR AName, HANDLE hInstance, HANDLE
function). hPrevInstance, LPSTR lpCmdLine, int nCmdShow) :
TApplication(AName, hInstance, hPrevInstance, lpCmdLine,
Listing B. Maszyna rozszerzona o okienka komunikatów. nCmdShow) {};
________________________________________________________________ virtual void InitMainWindow();
};
#define WIN31
#define STRICT Wykorzystamy okienko komunikatu do wiadomego zako czenia pracy
#include <owl.h> aplikacji. Klasa TApplication jest wyposa ona w metod
CanClose() (czy mo na zamkn ?) słu c do zamykania głównego
class TOkno : public TApplication okna aplikacji. Metoda została zaimplementowana tak:
{
public: BOOL TApplication::CanClose()
TOkno(LPSTR Nazwa, HANDLE hInstance, HANDLE hPrevInstance, {
LPSTR lpCmdLine, int nCmdShow) if (MainWindow)
: TApplication(Nazwa, hInstance, hPrevInstance, lpCmdLine, return (MainWindow->CanClose());
nCmdShow) {}; else
136
return (TRUE); ________________________________________________________________
}

B dzie nam wi c potrzebna własna wersja metody CanClose() i Komunikaty Windows mo emy wykorzysta w programie.
wska nik do obiektu MainWindow. Wska nik (typu far utworzony ...
przez składowe makro _FAR) wygenerujemy przy pomocy makra BOOL CanClose();
_CLASSDEF(nazwa_klasy): void WMLButtonDown(RTMessage Msg)= [WM_FIRST +
WM_LBUTTONDOWN];
_CLASSDEF(TGOkno) void WMRButtonDown(RTMessage Msg)= [WM_FIRST +
WM_RBUTTONDOWN];
Implementujemy teraz klas główne okno aplikacji. Jako klas };
bazow stosujemy TWindow.
Nasze Główne_Okno potrafi obsługiwa nast puj ce zdarzenia:
class TGOkno : public TWindow * Funkcja CanClose() zwróciła wynik TRUE/FALSE,
{ * Naci ni to lewy/prawy klawisz myszki.
public: Komunikat Msg zadeklarowany jako zmienna typu RTMessage jest w
TGOkno(PTWindowsObject AParent, LPSTR ATitle) klasie macie ystej TWindow wykorzystywany tak:
: TWindow(AParent, ATitle) {};
_CLASSDEF(TWindow)
Konstruktor tradycyjnie wykorzystujemy do przekazania parametrów
class _EXPORT TWindow : public TWindowsObject
do konstruktora klasy bazowej. PTWindowsObject AParent to {
wska nik (PoinTer) do obiektu "okno" a ATitle to string - tytuł. ...
protected:
Obsługa komunikatów kierowanych do tego okna mo e by virtual LPSTR GetClassName()
realizowana przy pomocy metod zaimplementowanych jako elemeny { return "OWLWindow"; }
składowe klasy Główne Okno - TGOkno. virtual void GetWindowClass(WNDCLASS _FAR & AWndClass);
Program graficzny powinien reagowa raczej na myszk ni na virtual void SetupWindow();
klawiatur . Windows rozpoznaj zdarzenia zwi zane z myszk i
generuj komunikaty o tych zdarzeniach. virtual void WMCreate(RTMessage Msg) = [WM_FIRST +
WM_CREATE];
Zdarzenia myszki (mouse events).
________________________________________________________________ virtual void WMMDIActivate(RTMessage Msg) =
[WM_FIRST + WM_MDIACTIVATE];
Komunikat Zdarzenie ...
________________________________________________________________ virtual void WMSize(RTMessage Msg) = [WM_FIRST + WM_SIZE];
WM_MOUSEMOWE - przesuni to myszk (wewn trz obszaru virtual void WMMove(RTMessage Msg) = [WM_FIRST + WM_MOVE];
roboczego - inside the client area - virtual void WMLButtonDown(RTMessage Msg) = [WM_FIRST +
ICA) WM_LBUTTONDOWN];
WM_LBUTTONDOWN - naci ni to LEWY klawisz myszki (ICA)
WM_LBUTTONDBLCLK - naci ni to dwukrotnie LEWY klaw. (ICA) Zwró uwag na notacj . Zamiast WM_CREATE pojawiło si [WM_FIRST
WM_LBUTTONUP - puszczono LEWY klawisz (ICA)
WM_RBUTTONDOWN - naci ni to PRAWY klawisz myszki (ICA) + WM_CREATE]. Komunikat WM_FIRST jest predefiniowany w
WM_RBUTTONDBLCLK - naci ni to dwukrotnie PRAWY klaw. (ICA) OWLDEF.H
WM_RBUTTONUP - puszczono PRAWY klawisz (ICA) i musi wyst pi w obiektowych aplikacjach w dowolnej klasie
WM_MBUTTONDOWN - naci ni to RODK. klawisz myszki (ICA) okienkowej, b d steruj cej (window class/controll class), która
WM_MBUTTONDBLCLK - naci ni to dwukrotnie ROD. klaw. (ICA)
WM_MBUTTONUP - puszczono RODKOWY klawisz (ICA) winna odpowiada na okre lony komunikat. Oto fragment pliku
WM_NCMOUSEMOVE - ruch myszki poza client area (NCA) OWLDEF.H zawieraj cy definicje stałych tej grupy:
WM_NLBUTTONDOWN - naci ni to LEWY klawisz myszki poza
obszarem roboczym - non-client area #define WM_FIRST 0x0000
(NCA) /* 0x0000- 0x7FFF window messages */
WM_NCLBUTTONDBLCLK - naci ni to dwukrotnie LEWY klaw. (NCA) #define WM_INTERNAL 0x7F00
WM_NCLBUTTONUP - puszczono LEWY klawisz (NCA) /* 0x7F00- 0x7FFF reserved for internal use */
WM_NCRBUTTONDOWN - naci ni to PRAWY klawisz myszki (NCA) #define ID_FIRST 0x8000
WM_NCRBUTTONDBLCLK - naci ni to dwukrotnie PRAWY klaw. /* 0x8000- 0x8FFF child id messages */
(NCA) #define NF_FIRST 0x9000
WM_NCRBUTTONUP - puszczono PRAWY klawisz (NCA) /* 0x9000- 0x9FFF notification messages */
WM_NCMBUTTONDOWN - naci ni to R. klawisz myszki (NCA) #define CM_FIRST 0xA000
WM_NCMBUTTONDBLCLK - naci ni to dwukrotnie RODK. klaw. /* 0xA000- 0xFFFF command messages */
(NCA) #define WM_RESERVED WM_INTERNAL - WM_FIRST
WM_LBUTTONUP - puszczono RODKOWY klawisz (NCA) #define ID_RESERVED ID_INTERNAL - ID_FIRST
________________________________________________________________ #define ID_FIRSTMDICHILD ID_RESERVED + 1
#define ID_MDICLIENT ID_RESERVED + 2
Nast pna tabelka zawiera (znacznie skromniejszy) zestaw #define CM_RESERVED CM_INTERNAL - CM_FIRST
komunikatów generowanych pod wpływem zdarze zwi zanych z
klawiatur . Cho by z wizualnego porównaia wielko ci tych tabel W tym momencie zwró my jeszcze uwag , e funkcje z grupy
wyra nie wida , e Windows znacznie bardziej "lubi " współprac MessageHandlers s typu void i zwykle s metodami wirtualnymi -
z myszk . przeznaczonymi "z definicji" do nadpisywania przez programistów
w klasach potomnych. Wszystkie te metody maj zawsze jedyny
Komunikaty Windows w odpowiedzi na zdarzenia zwi zane z argument - referencj do struktury TMessage zdefiniowanej
klawiatur . nast puj co:
_______________________________________________________________
Komunikat Zdarzenie struct TMessage
_______________________________________________________________ {
WM_KEYDOWN Naci ni to (jaki ) klawisz. HWND Receiver; //Identyfikator okna - odbiorcy
WM_KEYUP Puszczono klawisz. WORD Message; //sam komunikat
WM_SYSKEYDOWN Naci ni to klawisz "systemowy". union
WM_SYSKEYUP Puszczono klawisz "systemowy". {
WM_CHAR Kod ASCII klawisza. WORD WParam; //Parametr WParam stowarzyszony z
________________________________________________________________ //komunikatem; ALBO (dlatego unia!)
struct tagWP
Klawisz systemowy to np. [Alt]+[Esc], [Alt]+[F4] itp. {
137
BYTE Lo;
BYTE Hi; Wy wietlanie współrz dnych jakkolwiek warto ciowe z
} WP; dydaktycznego punktu widzenia jest mało interesuj ce. Pokusimy
union si o obiektow aplikacj umo liwiaj c odr czne rysowanie w
{ oknie (freehand drawing).
DWORD lParam;
struct tagLP
{ [!!!]UWAGA
WORD Lo; ________________________________________________________________
WORD Hi;
} LP; Pakiety Borland C++ 3..4.5 zawieraj wiele gotowych "klocków" do
};
long Result; wykorzystania. Oto przykład wykorzystania w pliku zasobów .RC
}; standardowego okienka wej ciowego (Input Dialog Box) i
standardowego okienka typu Plik (File Dialog Box):
Po tych wyja nieniach mo emy zaimplementowa poszczególne
funkcje. #include <windows.h>
#include <owlrc.h>
void TAplikacja::InitMainWindow()
{ rcinclude INPUTDIA.DLG
MainWindow = new (0, Name); rcinclude FILEDIAL.DLG
}
ROZKAZY MENU LOADONCALL MOVEABLE PURE DISCARDABLE
Je li wybrano klawisz [Yes] funkcja zwróci IDYES. Je li funkcja BEGIN
zwróciła IDYES - operator porównania zwróci TRUE (prawda) i ta POPUP "&File"
te warto zostanie zwrócona przez metod CanClose: BEGIN
MENUITEM "&New" CM_FILENEW
BOOL TMyWindow::CanClose() MENUITEM "&Open" CM_FILEOPEN
{ MENUITEM "&Save" CM_FILESAVE
return (MessageBox(HWindow, "Wychodzimy?", END
"Koniec", MB_YESNO | MB_ICONQUESTION) == IDYES); END
}
Takie menu mo na zastosowa w programie obiektowym umieszcaj c
Stosunkowo najciekawsza kombinacja odbywa si wewn trz handlera je w konstruktorze i dokonuj c nadpisania metody AssignMenu()
komunikatu WM_LBUTTONDOWN. Ze struktury komunikatów pobierana (przypisz menu):
jest zawarto młodszego słowa parametru lParam - Msg.LP.Lo i
starszego słowa Msg.LP.Hi. S to wzgl dne współrz dne graficzne TGOkno::TGOkno(PTWindowsObject AParent, LPSTR ATitle) :
kursora myszki (wzgl dem naro nika okna) w momencie naci ni cia TWindow(AParent, ATitle)
lewego klawisza myszki. Funkcja sprintf() zapisuje je w postaci {
dwu liczb dziesi tnych %d, %d do bufora znakowego char AssignMenu("ROZKAZY");
string[20]. Funkcja GetDC() (Get Device Context) okre la ...
kontekst urz dzenia (warstwa sterownika urz dzenia) i dalej }
obiekt mo e ju stosuj c funkcj kontekstow "czu si "
niezale ny od sprz tu. Dane te w postaci znakowej s pobierane [S]
przez funkcj kontekstow OutText() jako string a równocze nie rcinclude - doł cz zasoby
pobierane s w formie liczbowej: Msg.LP.Hi. Msg.LP.Lo, aby LOADONCALL - załaduj po wywołaniu
wyznaczy współrz dne tekstu na ekranie. Funkcja strlen() owlrc - zasoby biblioteki klas OWL
oblicza długo ła cucha znakowego - i to ju ostatni potrzebny
nam parametr. Gotowe "klocki" mo na wykorzysta nawet wtedy, gdy nie pasuj w
100%. Inne ni typowe odpowiedzi na wybór rozkazu implementujemy
void TMyWindow::WMLButtonDown(RTMessage Msg)
{ w programie głównym poprzez nadpisanie wirtualnej metody
HDC DC;
char string[20]; virtual void CMFileOpen(RTMessage msg) =
sprintf(string, "(%d, %d)", Msg.LP.Lo, Msg.LP.Hi); <-- TU [CM_FIRST + CM_FILEOPEN]
DC = GetDC(HWindow);
TextOut(DC, Msg.LP.Lo, Msg.LP.Hi, string, strlen(string)); TGOkno GOkno;

/* Mo na zwolni kontekst */ void TGOkno::CMFileOpen(RTMessage)


ReleaseDC(HWindow, DC); {
} ... obsługa zdarzenia ...
}
Ewentualna metoda uniewa niaj ca prostok t (invalid rectangle) i ________________________________________________________________

kasuj ca w ten sposób zawarto okna w odpowiedzi na


WM_RBUTTONDOWN mo e zosta zaimplementowana np. tak: [Z]
________________________________________________________________
void TMyWindow::WMRButtonDown(RTMessage) 1. Przeanalizuj gotowe zasoby doł czone do Twojej wersji Borland
{
InvalidateRect(HWindow, 0, 1); C++.
} 2. Uruchom kilka projektów "firmowych" doł czonych w katalogu
\EXAMPLES. Zwró szczególn uwag na projekty STEPS (kolejne
Główny program to ju tylko wywołanie metody Run() wobec kroki w tworzeniu aplikacji obiektowej).
obiektu. ________________________________________________________________

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,


LPSTR lpCmdLine, int nCmdShow) LEKCJA 47: APLIKACJA OBIEKTOWA - RYSOWANIE W OKNIE.
{ ________________________________________________________________
TNAplikacja OBIEKT("Wspolrzedne w oknie", hInstance, W trakcie tej lekcji opracujemy obiektow aplikacj psoługuj c
hPrevInstance, lpCmdLine, nCmdShow); si bibliotek klas Object Windows Library.
OBIEKT.Run(); ________________________________________________________________
return (OBIEKT.Status);
} Zaczniemy oczywi cie od standardowych "klocków". Definicja klasy
138
TGOkno::TGOkno(PTWindowsObject AParent, LPSTR ATitle)
Nasza_Aplikacja i moduł prezentacyjno - uruchomieniowy b d : TWindow(AParent, ATitle)
wygl da standardowo, nie musimy im zatem po wi ca zbytniej {
uwagi. Przytoczymy je jedynie. Pointer do napisu inicjujemy po ButtonDown = FALSE;
to, by okienko komunikatu zawierało jak bardziej konkretn }
informacj dla u ytkownika. Rysunki z wn trza tej aplikacji
mo na przy pomocy Schowka przenie jako pliki .CLP, b d za Funkcja obsługuj ca zdarzenie WM_LBUTTONDOWN jeden raz inicjuje
pomoc PAINTBRUSH - jako .BMP, .PCX i drukowa . obsług myszki i ustawia flag . Funkcje SetCapture() i GetDC()
załatwij problem relacji kontekstowych i okre laj obszar
#include <owl.h> roboczy (client area). Je li umie cimy te funkcje w
konstruktorze za obszar client area uznany zostanie cały ekran.
LPSTR Ptr = "Jesli chcesz zapamietac rysunek, \ Po zadziałaniu tych funkcji komunikaty od myszki b d dotyczy
powinienes przeniesc go do Clipboard'u \ wył cznie obszaru roboczego. Do naci ni cia prawego klawisza nie
klawiszami [Print Screen] \
lub [Alt]+[PrtScr]."; b dzie dost pu do "ramki" okna.

class TNAplikacja : public TApplication void TGOkno::WMLButtonDown(RTMessage Msg)


{ {
public: if (!Flaga_Start)
TNAplikacja(LPSTR AName, HANDLE hInstance, HANDLE {
hPrevInstance, Flaga_Start = TRUE; //UWAGA:
LPSTR lpCmdLine, int nCmdShow) SetCapture(HWindow); //Jesli zainicjujemy SetCapture()
: TApplication(AName, hInstance, hPrevInstance, lpCmdLine, dc = GetDC(HWindow); //w konstruktorze - mamy caly ekran
nCmdShow) {}; }
virtual void InitMainWindow(); MoveTo(dc, Msg.LP.Lo, Msg.LP.Hi);
}; ButtonDown = TRUE;
... }

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, Funkcja MoweTo() powoduje przesuni cie kursora graficznego do
LPSTR lpCmdLine, int nCmdShow) aktualnej pozycji myszki (ju wzgl dnej - z uwzgl dnieniem dc)
{ bez rysowania linii. Flaga ButtnDown została ustawiona.
TNAplikacja OBIEKT("Rysownik. Prawy klawisz umozliwia wyjscie.", Rysowanie scedujemy na metod obsługuj c WM_MOUSEMOVE -
przesuni cie myszki.
hInstance, hPrevInstance, lpCmdLine, nCmdShow);
OBIEKT.Run(); void TGOkno::WMMouseMove(RTMessage Msg)
return (OBIEKT.Status); {
} if (ButtonDown)
LineTo(dc, Msg.LP.Lo, Msg.LP.Hi);
Nic specjalnie ciekawego nie dzieje si w funkcji inicjuj cej }
główne okno, ani w funkcji zamykaj cej aplikacj . Zmieniły si
tylko napisy w okienku komunikatów. Je li lewy klawisz jest naci ni ty - funkcja LineTo() b dzie
kre li lini do kolejnych punktów " ledz c" ruch myszki. Je li
void TNAplikacja::InitMainWindow() u ytkownik pu ci lewy klawisz - zerujemy flag stanu klawisza
{ ButtonDown <== FALSE.
MainWindow = new TGOkno(0, Name);
} void TGOkno::WMLButtonUp(RTMessage)
{
BOOL TGOkno::CanClose() if (ButtonDown) ButtonDown = FALSE;
{ }
return (MessageBox(HWindow, Ptr, "KONIEC",
MB_YESNO | MB_ICONQUESTION) == IDYES); Jak ju nabazgrzemy po ekranie, prawy klawisz umo liwi nam
} skasowanie zawarto ci przy pomocy InvalidateRect().

Zajmiemy si teraz główn "maszyneri " programu. Rozbudujemy void TGOkno::WMRButtonDown(RTMessage)


obsług komunikatów przez handlery zaimplenmentowane w klasie {
Główne_Okno. InvalidateRect(HWindow, 0, 1);
ReleaseCapture();
_CLASSDEF(TGOkno) ReleaseDC(HWindow, dc);
class TGOkno : public TWindow Flaga_Start = FALSE;
{ }
public:
HDC dc; Para funkcji ReleaseDC() i ReleaseCapture() pozwala przekaza
BOOL ButtonDown; komunikaty od myszki do "ramki okna". Dzi ki temu mo na po
BOOL Flaga_Start; skasowaniu ekranu np. rozwin menu systemowe i zako czy
aplikacj . A oto program w cało ci.
TGOkno(PTWindowsObject AParent, LPSTR ATitle);
//Konstruktor Listing. Odr czne rysowanie.
________________________________________________________________
virtual void WMLButtonDown(RTMessage Msg)
= [WM_FIRST + WM_LBUTTONDOWN]; #define STRICT
virtual void WMLButtonUp(RTMessage Msg) #define WIN31
= [WM_FIRST + WM_LBUTTONUP]; #include <owl.h>
virtual void WMMouseMove(RTMessage Msg)
= [WM_FIRST + WM_MOUSEMOVE]; LPSTR Ptr = "Jesli chcesz zapamietac rysunek, \
virtual void WMRButtonDown(RTMessage Msg) powinienes przeniesc go do Clipboard'u \
= [WM_FIRST + WM_RBUTTONDOWN]; klawiszami [Print Screen] \
virtual BOOL CanClose(); lub [Alt]+[PrtScr].";
};
class TNAplikacja : public TApplication
Konstruktor przekazuje parametry do konstruktora klasy bazowej i {
public:
zeruje flag ButtonDown - lewy klawisz myszki przyci ni ty. TNAplikacja(LPSTR AName, HANDLE hInstance, HANDLE
hPrevInstance,
139
LPSTR lpCmdLine, int nCmdShow) return (OBIEKT.Status);
: TApplication(AName, hInstance, hPrevInstance, lpCmdLine, }
nCmdShow) {}; ________________________________________________________________
virtual void InitMainWindow();
};

_CLASSDEF(TMyWindow)
class TMyWindow : public TWindow LEKCJA 48: O PAKIETACH BORLAND C++ 4/4.5.
{ ________________________________________________________________
public: Z tej lekcji dowiesz si , czy warto kupi nowsz wersj Borland
HDC dc; C++ 4/4.5 i jakie niespodzianki czekaj Ci po zamianie
BOOL ButtonDown; kompilatora na nowszy.
BOOL Flaga_Start; ________________________________________________________________

TMyWindow(PTWindowsObject AParent, LPSTR ATitle); Czy warto sprawi sobie BORLAND C++ 4/4.5 ?
//Konstruktor
Kilka słów o tym, co oferuje Borland w pakietach "Borland C++
virtual void WMLButtonDown(RTMessage Msg) 4/4.5" i jakie niespodzianki czekaj nowych u ytkowników przy
= [WM_FIRST + WM_LBUTTONDOWN]; instalacji i uruchamianiu.
virtual void WMLButtonUp(RTMessage Msg)
= [WM_FIRST + WM_LBUTTONUP]; Wymagania sprz towe i instalacja
virtual void WMMouseMove(RTMessage Msg)
= [WM_FIRST + WM_MOUSEMOVE]; Aby instalacja i u ytkowanie pakietu przebiegało poprawnie,
virtual void WMRButtonDown(RTMessage Msg) zaleca si nast puj c konfiguracj sprz tu:
= [WM_FIRST + WM_RBUTTONDOWN];
virtual BOOL CanClose(); Wymagania sprz towe Borland C++ 4.
}; ________________________________________________________________
Parametr minimum zalecane (pełna konfig.)
TMyWindow::TMyWindow(PTWindowsObject AParent, LPSTR ATitle) ________________________________________________________________
: TWindow(AParent, ATitle) * procesor 80386/33 MHZ 486 DX (lub 386 + 387)
{ * miejsce na dysku 8 MB 80 MB (bez kompresji)
ButtonDown = FALSE; * pami RAM 4 MB 8 MB i wi cej
} * system DOS 4.01 DOS 6.0...6.22
* MS Windows 3.1 Windows NT
void TMyWindow::WMLButtonDown(RTMessage Msg) ________________________________________________________________
{
if ( !Flaga_Start )
{
Flaga_Start = TRUE; //UWAGA: Cz ciowa instalacja Borland C++ 4.
SetCapture(HWindow); //Jesli zainicjujemy SetCapture() ________________________________________________________________
dc = GetDC(HWindow); //w konstruktorze - mamy caly ekran
} Konfiguracja Dysk
MoveTo(dc, Msg.LP.Lo, Msg.LP.Hi); ________________________________________________________________
ButtonDown = TRUE; 1. Kompilator BCC 16 bitowy (D+W) 9 MB
} 2. Kompilator BCC 32 bitowy (D+W) 13 MB
3. rodowisko IDE 16 bitowe 26 MB
void TMyWindow::WMMouseMove(RTMessage Msg) 4. rodowisko IDE 32 bitowe 30 MB
{ 5. Tylko dla DOS (minimum) 8 MB
if ( ButtonDown ) ________________________________________________________________
LineTo(dc, Msg.LP.Lo, Msg.LP.Hi); * D+W - dla DOS i Windows
}
Mo na próbowa zainstalowa Borland C++ 4 na małym dysku, mo na
void TMyWindow::WMLButtonUp(RTMessage) tak e ograniczy si do 4 MB RAM, ale generowanie 32-bitowych
{ aplikacji b dzie wtedy znacznie utrudnione a praca kompilatora
if (ButtonDown) ButtonDown = FALSE; wolniejsza. W przypadku stosowania kompresorów (np. SUPERSTOR,
} DOUBLE SPACE) nale y pami ta , e wtórna kompresja plików jest
mało skuteczna i dysk zgłaszany jako 80 MB mo e okaza si
void TMyWindow::WMRButtonDown(RTMessage) "ciasny".
{
InvalidateRect(HWindow, NULL, TRUE); Borland C++ 4 mo na instalowa z dyskietek, b d z CD-ROM.
ReleaseCapture(); Poniewa pakiet BC++ 4 jest "okienkowo - zorientowany", nawet
ReleaseDC(HWindow, dc); program instalacyjny wymaga obecno ci Windows. Uruchomienie
Flaga_Start = FALSE; programu instalacyjnego nast puje zatem z poziomu Mened era
} programów rozkazem File | Run... (w spolszczonej wersji Windows
- Plik | Uruchom...) lub z DOS-owskiego wiersza rozkazu:
void TNAplikacja::InitMainWindow()
{ C:\>WIN X:INSTALL
MainWindow = new TMyWindow(0, Name);
} Opcji jest troch wi cej - o najciekawszych z nich - kilka słów
poni ej.
BOOL TMyWindow::CanClose()
{ Warto zwróci uwag na tzw. "rozszerzenie dla Windows"
return (MessageBox(HWindow, Ptr, "KONIEC", (extention to MS Windows) - Win32s. W programie INSTALL.EXE do
MB_YESNO | MB_ICONQUESTION) == IDYES); zainstalowania tego pakietu (pakiet jest oryginalnym produktem
} Microsofta i wymaga 8 MB przestrzeni dyskowej) słu y opcja
[Install Win32s]. Najwa niejszy plik-driver instaluje si w
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, pliku SYSTEM.INI:
LPSTR lpCmdLine, int nCmdShow)
{ device=X:\WINDOWS\SYSTEM\WIN32S\W32S.386
TNAplikacja OBIEKT("Rysownik. Prawy klawisz umozliwia
wyjscie.", hInstance, hPrevInstance, Pozwala to na uruchamianie 32 - bitowych aplikacji pod Windows
lpCmdLine, nCmdShow); 3.1. Je li masz Windows NT - jest to zb dne - o ten "drobiazg"
OBIEKT.Run(); zadbał ju Microsoft.
140
konfliktów.
W przypadku instalacji w sieci, gdzie Windows zainstalowane s
na serwerze nale y pami ta , e BC++ 4 w trakcie instalacji Je li jest ju Borland Pascal 7...
modyfikuje nie tylko klasyczne parametry systemu:
Je li masz ju zainstalowany Borland Pascal 7 nale y pami ta ,
FILES=40 e poprawna praca obu kompilatorów w jednym systemie wymaga
BUFFERS=40 "uregulowania stosunków":
PATH=...;X:\BC4\BIN;
1. Ka dy kompilator musi mie własn kopi debuggera TDW. Aby
ale tak e pliki konfiguracyjne i inicjacyjne w katalogu WINDOWS: unikn konfliktu pascalowski debugger mo na przemianowa np.:

TDW.EXE --> PASTDW.EXE


WIN.INI, PROGMAN.INI, SYSTEM.INI,
2. Nale y usun stare pliki inicjuj ce TDW.INI. Mo na tu
oraz tworzy nowe własne pliki, które b dzie próbował zapisa w posłu y si narz dziem TDWINI.EXE.
katalogach \WINDOWS i \WINDOWS\SYSTEM, np. BCW.INI, TDW.INI, 3. Nale y sprawdzi poprawno instalacji driverów w pliku
HELP.ICO, OWL.INI, BWCC.DLL, itp. (ł cznie 18 nowych plików). SYSTEM.INI:
Brak prawa zapisu na dysk serwera mo e uniemo liwi poprawn
instalacj i skonfigurowanie BC++ 4/4.5 w sieci. DEVICE=X:\BC4\BIN\WINDPMI.386
DEVICE=X:\BC4\BIN\TDDEBUG.386 <-- tu mo liwy konflikt z BP 7
Borland wraz z wersjami bibliotek dostarcza komplet kodów
ródłowych. Je li chcesz - mo esz sam wygenerowa sobie cał Nale y usun dubluj ce si instalacje pozostawiaj c tylko te z
bibliotek , je li chcesz - mo esz na własne oczy przekona si BC++ 4 oraz usun pascalowskie TDDEBUG.386 (pas) i TDWIN.DLL by
jak to wszystko działa i jak jest zbudowane. Oprócz
teoretycznych mo liwo ci poznawczych daje to praktyczn uniemo liwi omyłkowe zainstalowanie.
mo liwo dostosowania bibliotek do nowej wersji kompilatora, co
Przy poprawnym skonfigurowaniu systemu pozostałe zasoby ( w tym
w przypadku "czwórki" mo e okaza si dla wielu u ytkowników np. Resource Workshop 4) b d poprawnie współpracowa z BP 7.
bardzo przydatne (o czy dokładniej za chwil ).
Stare zasoby C++
Oprócz klasycznego paska głównego menu zintegrowane rodowisko
(IDE) zostało wyposa one w rozbudowan listw narz dziow . Zapewne wi kszo u ytkowników Borland C++ 4 "przesi dzie si " z

W skład pakietu wchodz mi dzy innymi: BC++ 3/3.1 lub Turbo C++. I tu tak e czychaj pewne
niebezpiecze stwa. Stare projekty - tradycyjnie .PRJ w BC++ 4
* BCW - zintegrowane rodowisko (IDE) dla rodowiska Windows zyskuj nowe domy lne rozszerzenie .IDE. W okienku dialogowym
* TDW - Turbo Debugger for Windows zarz dzania projektem: Project | Open... przy pomocy opcji
* BCC - kompilator uruchamiany z DOS'owskiego wiersza rozkazu
* BCC32 - kompilator 32 - bitowy (odpowiednik BCC) [3.1 Project Files (*.prj)]
* BRCC - kompilator zasobów do kompilacji plików *.RC z zasobami
mo na dokona automatycznej konwersji do formatu .IDE, przy czym
do postaci binarnej *.RES
* RLINK - konsolidator słu cy do doł czania plików z zasobami stara wersja pliku *.PRJ pozostanie bez zmian. Niektóre stare
przy tworzeniu plików wykonywalnych *.EXE kody ródłowe b d wymaga drobnych modyfikacji. Szczególnie
* TLINK - "zwykły" konsolidator nale y zwró i uwag na:
* MAKE - program narz dziowy do automatyzacji kompilacji i
konsolidacji, korzystaj cy z tzw. plików instrukta owych - nakładki (overlay support)
(emuluj cy NMAKE Microsofta) - zarz dzanie pami ci (new - delete)
* WINSIGHT - przegl danie informacji o okienkach (dla Windows) i - informacje diagnostyczne w plikach (debug info)
- zmianne pseudorejestrowe (dost pne teraz tylko w niektórych
komunikatach trybach)
* TDUMP - bezpo rednie przegl danie informacji zawartych w
plikach *.EXE i *.OBJ O bibliotece Turbo Vision.
* TDSTRIP - narz dzie do usuwania tablicy symboli z plików
wykonywalnych Biblioteka Turbo Vision Library - TV.LIB współpracuj ca
* IMPLIB - importer bibliotek z DLL poprawnie z BC++ 3.0/3.1 powinna zosta powtórnie skompilowana,
* TDMEM - wy wietlanie informacji o zaj to ci pami ci poniewa BC++ 4 stosuje inny format:
* MAKESWAP - zarz dzanie swapowaniem (tworzenie plików
tymczasowych EDPMI.SWP o zadanej wielko ci) - informacji diagnostycznych (debug info format)
- inn długo identyfikatorów (symbol length)
i jeszcze par narz dzi (np. tradycyjny bibliotekarz TLIB, - inn bibliotek Runtime Library
TOUCH, GREP, itp.), o których tu nie wspominam.
Kod ródłowy biblioteki znajduje si w katalogu:
Czego robi nie nale y?
\BIN\TVISION\SOURCE
Przede wszystkim nie nale y traktowa Borland C++ 4/4.5 jako
"upgrade" do wcze niejszych wersji (3, czy 3.1). W kompilatorze Po (Uwaga!) wprowadzeniu kilku niewielkich zmian
dokonano sporych zmian (np. inaczej działa operator new). Nie
wolno zatem "nadpisa " zawarto ci poprzednich katalogów i plików - do plików ródłowych .CPP
- do pliku instrukta owego MAKEFILE
o tych samych nazwach. Szczególnie dotyczy to plików
konfiguracyjnych BCCONFIG.BCW i TDCONFIG.TDW. Je li stare wersje oraz po skompilowaniu przy pomocy BCC 4 w DWU WERSJACH: TVO.LIB
(z nakładk - Overlay) i TVNO.LIB (bez nakładki - No Overlay)
tych plików nie zostan przemianowane, b d usuni te z pola biblioteka TVL mo e by nadal z powodzeniem stosowana z Borland
widzenia (PATH) - pojawi si konflikty przy uruchamianiu BC++. C++ 4. Podobnie rekompilacji wymaga bibiloteka klas doł czona w
wersji ródłowej w katalogu X:\BC4\SOURCE\CLASSLIB.
Ze wzgl du na wprowadzone zmiany pliki .OBJ tworzone przez
wcze niejsze kompilatory C b d w zasadzie przeno ne, natomiast O AUTOMATYZACJI - CASE.
pliki .OBJ i biblioteki utworzone przez wcze niejsze wersje
kompilatorów C++ (szczególnie Borland C++ 3.1) b d sprawia Prócz znanego ju od do dawna (w komputerologii kilka lat to
kłopoty (nie b d np. poprawnie wywoływane destruktory). Przy cała epoka) tradycyjnego narz dzia Resource Worshop, w wersji
konsolidacji "starych" plików mo na stosowa opcj -K2 BC4 wyst puj jeszcze inne narz dzia CASE kategorii "wizard"
konsolidatora, co pozwoli zmniejszy do minimum ryzyko (kreator aplikacji):
141
oraz nowoczesnych styli programowania:
- ClassExpert obiektowego i zdarzeniowego
- ApplicationExpert pozostał Ci ju tylko wykonanie trzech rzeczy. Powiniene teraz:
- DialogExpert
- TargetExpert
1. Pisa własne aplikacje
Nazwa TargetExpert pochodzi od ang. "Target platform" - docelowa 2. Pisa własne aplikacje
3. Pisa własne aplikacje
platforma pracy aplikacji (DOS, Win16, Win32).
Biblioteka OWL 2.0 została wzbogacona o dodatkowe klasy VBX Tak naprawd - jest to jedyny sposób, by zosta dobrym
umo liwiaj ce współprac z Visual Basic i wykorzystanie programist .
elementów utworzonych przy pomocy VB.
Wspomaganie tworzenie programu przy pomocy tych narz dzi Przez pewien czas oka e Ci si zapewne przydatna dyskietka
(AppExpert podobnie jak inne narz dzie typu Wizard jest doł czona do ksi ki. Znajdziesz tam jeszcze sporo programów
automatycznym generatorem aplikacji) wymaga od u ytkownika przykładowych, które nie zmie ciły si w ksi ce.
wyboru z listy "zagadnienia" a z okienek docelowych cech
programu. Przytocz tu dla przykładu list opcji z pojedynczego Przyjemnej pracy z programem MEDYT.
okienka AppExperta z krótkim wyja nieniem:

________________________________________________________________
Topics: (okienko z list : Zagadnienia)
Application (program docelowy)
-- Basic Opttions (wybór opcji podstawowych)
-- Advanced Options (opcje zaawansowane)
-- Code Gen Control (sposób generacji kodu)
-- Admin Options (opcje "administracyjne")
Main Window (główne okno programu)
-- Basic Options (podstawowe opcje)
-- SDI Client (interf. jednego dokumentu)
-- MDI Client (interf. wielu dokumentów)
MDI Child/View (okna potomne, widok/edycja)
-- Basic Options (opcje podstawowe)

Model: (Szkielet programu)


[X] Multiple document interface - interfejs MDI
[ ] Single document interface - interfejs SDI

Features: (cechy)
[.] SpeedBar (ma pasek narz dzi)
[.] Status line (ma wiersz statusowy)
[.] Drag/drop (obsługuje ci gnij/upu )
[.] Printing (obsługuje drukark )
________________________________________________________________

Po wybraniu w okienku klawisza [Generate] (wygeneruj) AppExpert


generuje szkielet programu aplikacji o podanych własno ciach.
Wygenerowane zostaje od sze ciu do dziewi ciu (zale nie od
ustawienia opcji i Twoich ycze ) plików projektu:

*.IDE - plik projektu (lub .PRJ)


*.APX - plik roboczy AppExpert'a (odpowiednik
.PRJ)
*.RC - plik zasobów
*.RH - plik nagłówkowy zasobów
*.H - plik nagłówkowy, ródłowy
*.CPP - moduł główny ródłowy
*.HPJ - plik pomocy
*.RTF - ródłowy pomocy kontekstowej
*.ICO - ikonka projektu

Przy pomocy rozkazu Generate makefile mo na równie


automatycznie utworzy plik instrukta owy MAKEFILE dla
generatora MAKE.EXE.

Uzyskany plik szkieletowy *.CPP nale y tylko uzupełni o obsług

interesuj cych nas zdarze /komunikatów. Przyspiesza to znacznie


tworzenie typowych aplikacji.

Programi ci wszystkich krajów...

BC++ 4 zawiera bibliotek LOCALE.DLL umo liwiaj c obsług


angielsko- francusko- i niemiecko- j zyczn . Borland zapowiada,
e nast pne wersje b d coraz bogatsze. Doczekali my si
spolszczenia Windows - mo e i Borland C++ po polsku ju tu tu ?

Póki co, najwygodniej podmieni czcionki.


________________________________________________________________

ZAKO CZENIE.

I to ju niestety koniec. Po przeanalizowaniu historii:


programowania sekwencyjnego i strukturalnego
142

You might also like