Professional Documents
Culture Documents
w C i C++
BORLAND C++
- 1-
Spis Treści
- 2-
Lekcja 1. Co o C i C++ każdy wiedzieć powinien.
________________________________________________________________
Grzech Pierwszy:
* Kompilator języka C/C++ jest standardowym wyposażeniem systemu
operacyjnego UNIX.
Skutki praktyczne:
Grzech drugi:
* Język C/C++ powstał jeszcze zanim wymyślono PC, DOS, GUI
(Graficzny Interfejs Użytkownika), Windows i inne tym podobne.
i:=i+1; (Pascal)
10 I=I+1 lub inaczej NEXT I (Basic)
- 3-
to w języku C++ wygląda dziwacznie:
Inny przykład:
Skutki praktyczne:
- 4-
Nauczywszy się języka C/C++ możesz nie bać się ani systemu
UNIX/XENIX a ich środowiska okienkowego - X Windows, ani OS2,
ani Windows 95 (dotychczasowe testy starych 16-bitowych
aplikacji wykazały b. wysoki stopień kompatibilności), ani
stacji roboczych, ani dużych komputerów klasy mainframe. Język
C/C++ dosłużył się bowiem ogromnej ilości tzw. implementacji
czyli swoich odmian, przeznaczonych dla różnych komputerów i dla
różnych systemów operacyjnych. Windows NT i Windows 95 również
zostały napisane w C++.
Czytając prasę (np. Computer World, PC-Kurier i in.) zwróć
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
lat, póki nie wymyślą czegoś lepszego - np. jakiegoś C+++).
Z Grzechu Trzeciego (choć nie tylko) wynika także pośrednio
Grzech Czwarty.
Języka C++ Grzech Czwarty - ANSI C, C++, czy Turbo C++, Visual
C++, czyli mała wieża BABEL.
- 5-
Program (1)
main()
{
printf("Hello World\n");
}
Program (2)
#include <windows.h>
#include <iostream.h>
main(void)
{
cout << "Hello World" << endl;
MessageBox(0, p, "Aplikacja dla Windows", MB_OK);
return (0);
}
* słowa kluczowe
(tu pomiędzy wersjami C++ rozbieżności są niewielkie),
* dyrektywy
(polecenia dla kompilatora JAK tworzyć program wynikowy;
tu już jest gorzej, szczególnie dyrektywa #pragma w każdej
wersji kompilatora C++ jest inna)
* nazwy funkcji
(z tym gorzej, bo każdy producent ma własne funkcje i własne
- 6-
upodobania)
* nazwy stałych
(gdyby chodziło tylko o PI i e - wszystko byłoby proste)
* nazwa() - funkcja
* słowa kluczowe i nazwy zmiennych - małymi literami
* STAŁE - nazwy stałych najczęściej dużymi literami
* long/LONG - typy danych podstawowe/predefiniowane dla Windows
_NAZWA - nazwy stałych predefiniowanych przez producenta
__nazwa lub __nazwa__ - identyfikatory charakterystyczne dla
danej wersji kompilatora
- 7-
Professional, CA-Visual Objects, Clipper, itp.
[!!!]UWAGA!
________________________________________________________________
[???] C.A.S.E.
________________________________________________________________
- 8-
Zaczynamy zatem od rzeczy najprostszych, mając jedynie tę
krzepiącą świadomość, że gdy już przystąpimy do pisania
aplikacji konkurencyjnej wobec Worda, QR-Tekst'a, czy Power
Point'a - może nas wspomagać system wspomaganina CASE dołączony
szybciej).
_______________________________________________________________
- 9-
LEKCJA 2. Jak korzystać z kompilatora BORLAND C++?
________________________________________________________________
W trakcie tej lekcji poznasz sposoby rozwiązania typowych
problemów występujących przy uruchomieniu kompilatora Borland
C++.
________________________________________________________________
UWAGA:
Z A N I M rozpoczniesz pracę z dyskietką dołączoną do niniejszej
książki radzimy Ci SPORZĄDZIĆ ZAPASOWĄ KOPIĘ DYSKIETKI przy
pomocy rozkazu DISKCOPY, np.
INSTALACJA DYSKIETKI.
INSTALUJ.BAT
UWAGI:
* Jeśli korzystasz z napędu dyskietek B:, lub chcesz
zainstalować programy z dyskietki na innym dysku niż C: -
wystarczy napisać rozkaz - np. B:\INSTALUJ AMC48 D: i nacisnąć
[Enter].
* Program instalacyjny zadziała poprawnie tylko wtedy, gdy masz
system operacyjny DOS 6+ (6.0 lub nowszy) na dysku C: w katalogu
C:\DOS.
* Możesz zainstalować programy z dyskietki z poziomu środowiska
Windows. W oknie Menedżera Programów:
- rozwiń menu Plik
- wybierz rozkaz Uruchom...
- do okienka wpisz <-- patrz tekst książki
- 10-
Program instalacyjny utworzy na wskazanym dysku katalog
\C-BELFER
i tam skopiuje całą zawartość dyskietki oraz dokona dekompresji
(rozpakowania) plików. Jeśli chcesz skopiwać zawartość dyskietki
do własnego katalogu roboczego, wystarczy "wskazać" programowi
instalacyjnemu właściwy adres:
UWAGA:
Prócz przykładów opisanych w książce dyskietka zawiera dodatkowo
kilka przykładowych aplikacji, na które zabrakło miejsca, między
innymi:
I. URUCHOMIENIE KOMPILATORA.
BC
i nacisnąć [Enter].
(UWAGA: w różnych wersjach kompilatorów może to być np.:
BC, TC, a dla Windows np. BCW - sprawdź swoją wersję)
ROZWIĄZANIE:
- 11-
komputerze; najlepiej zasięgnij rady lokalnego eksperta).
Albo
FILES = 20
BC[Enter]
- 12-
________________________________________________________________
Co robić, jeśli przy próbie uruchomienia kompilator C++
odpowiedział Ci:
DIR TC.EXE
uzyskasz odpowiedź, jak poniżej:
C:>DIR TC.EXE
Directory of D:\TC\BIN
C:>DIR BC.EXE
Directory of C:\BORLANDC\BIN
€[!!!] UWAGA:
- 13-
we własnych katalogach - do innych możecie nie mieć praw zapisu.
- 14-
LEKCJA 3. Główne menu i inne elementy IDE.
________________________________________________________________
W trakcie tej lekcji dowiesz się jak poruszać się w
zintegrowanym środowisku (IDE) Turbo C++.
________________________________________________________________
UWAGA:
__________________________________________________________
W niektórych wersjach kompilatora na pasku głównego menu pojawi
się jeszcze Browse - przeglądanie (funkcji, struktury klas i
obiektów). Zwróć uwagę, że w okienkowych wersjach niektóre
rozkazy "zmieniają" menu i trafiają do
Browse, Debug, Project.
W BC++ 4 menu Run brak (!). Tworzenie aplikacji sprowadza się
tam do następujących kroków:
ROZWIJAMY MENU.
- 15-
Wskaż w menu głównym nazwę "File" i naciśnij [Enter].
Rozwinęło się menu File zawierające listę rozkazów dotyczących
operacji na plikach. Po tym menu też możesz się poruszać przy
pomocy klawiszy kursora ze strzałkami górę lub w dół. Masz do
wyboru dwie grupy rozkazów rozdzielone poziomą linią:
€[S!]
______________________________________________________________
Open - Otwórz istniejący już plik z programem (np. w celu
dopisania czegoś nowego).
New - Utwórz nowy plik (zaczynamy tworzyć nowy program).
Save - Zapisz bieżący program na dysk. Pamiętaj: Pliki z
dysku nie znikają po wyłączeniu komputera. Zawsze
lepiej mieć o jedną kopię za dużo niż o jedną za mało.
oraz
Print - Wydrukuj program.
Get Info€€ - Wyświetl informacje o stanie IDE.
Dos Shell - Wyjście "na chwilę" do systemu DOS z możliwością
powrotu do IDE przez rozkaz EXIT.
Quit - Wyjście z IDE Turbo C++ i powrót do DOSa. Inaczej -
KONIEC PRACY.
_______________________________________________________________
OKIENKO TEKSTOWE - (ang. Text Box lub Input Box) w którym możesz
- 16-
[Shift]-[Tab] (spróbuj!).
UWAGA!
_________________________________________________________________
Dopóki manipulujesz okienkiem tekstowym i okienkiem z listą
klawisz polecenia [Open] jest wyróżniony (podświetlony) i
traktowany jako tzw. OPCJA DOMYŚLNA (ang. default). W tym
stadium aby wybrać [Open] WYSTARCZY NACISNĄĆ [Enter].
__________________________________________________________________
- 17-
#include <stdio.h>
main()
{
printf("Autor: ..........."); /*tu wpisz imie Twoje!*/
printf(" TO JA, TWOJ PROGRAM - PIERWSZY.CPP");
printf("...achoj !!!");
}
I już. Jak widzisz nie jest to aż takie straszne. Gdyby nie to,
że zamiast znajomego PRINT"TO JA...", albo writeln(".."); jest
printf("...");, byłoby prawie całkiem zrozumiałe. Podobny
program w Pascalu mógłby wyglądać np. tak:
a w BASICU:
€[!!!]UWAGA
______________________________________________________________
Zwróć uwagę, że działanie funkcji:
PRINT (Basic),
printf() (C++),
Write i Writeln (Pascal)
nie jest identyczne, a TYLKO PODOBNE.
________________________________________________________________
- 18-
[Alt]+[R] menu Run (Uruchamianie)
[Alt]+[W] menu Window (Okna)
itd., itd..
[S!]
________________________________________________________________
Run - Uruchomienie programu (Utwórz plik .EXE i Wykonaj).
Program Reset - "Wyzerowanie" zmiennych programu.
Go to Cursor - Wykonanie programu do miejsca wskazanego kursorem
w tekście.
Trace Into - Uruchom śledzenie programu.
Step Over - Śledzenie programu z możliwością pominięcia funkcji.
klawiszy [Alt]-[F5].
3. Po przejrzeniu wydruku naciśnij [Enter]. Wrócisz do okna
edytora.
Błędów zwykle bywa nie więcej niż dwa. Najczęściej jest to brak
lub przekłamanie którejś litery (w słowie main lub printf) i
brak średnika na końcu linii. W okienku komunikatów (Message)
mogą pojawić się napisy - np.:
- 19-
Error - błąd
Warning - ostrzeżenie
Syntax - składnia (składniowy)
Expression - wyrażenie
never used - nie użyte (nie zastosowane)
assign - przypisywać, nadawać wartość/znaczenie
value - wartość
statement - operator, operacja, wyrażenie
________________________________________________________________
________________________________________________________________
Zwróć uwagę, że po pdświetleniu komunikatu o błędzie (pasek
wyróżnienia podświetlenia możesz przesuwać po liście przy pomocy
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
jest coś nie w porządku. Brak średnika zauważa zwykle dopiero po
przejściu do następnego wiersza (i tenże wiersz pokaże), co bywa
na początku trochę mylące.
________________________________________________________________
Errors: 0 (Błędy: 0)
Warnings: 1 (Ostrzeżenia: 1)
- 20-
JAK STĄD WYJŚĆ ?
[Alt]-[X] - Quit/Exit
[F2] - Save
[F3] - Open
[Alt]-[F5] - User screen (Podglądanie działania programu) itp.
________________________________________________________________
€[Z]
________________________________________________________________
1. Spróbuj napisać i uruchomić kilka własnych programów
wypisujących różne napisy. W swoich programach zastosuj funkcję
printf() według następującego wzoru:
printf("...napis...\n");
porównaj działanie.
- 21-
Swoim programom staraj się nadawać łatwe do rozpoznania nazwy
typu PIERWSZY, DRUGI, ADAM1, PRZYKLAD itp.
€ PAMIĘTAJ:
________________________________________________________________
Jeśli masz oryginalny tekst programu, nazywany WERSJĄ ŹRÓDŁOWĄ
PROGRAMU, zawsze możesz uzyskać ten program w wersji "roboczej",
tzn. skompilować go na plik wykonywalny typu *.EXE (ang.
EXEcutable - wykonywalny).
________________________________________________________________
- 22-
2. Przejść do odpowiedniego katalogu - np. głównego:
CD \
3. Wydać polecenie:
PIERWSZY[Enter]
________________________________________________________________
€[!!!]UWAGA:
________________________________________________________________
Jeśli nie jesteś jedynym użytkownikiem kompilatora C++ i na tym
samym komputerze pracuje jeszcze ktoś inny, sprawdź, czy inny
użytkownik nie ustawił inaczej katalogu wyjściowego (Options |
Directories | Output Directory). Katalog wyjściowy (ang. output
directory) to ten katalog, w którym C++ zapisuje pliki *.EXE po
wykonaniu kompilacji. Jeśli jesteś skazany na własne siły -
patrz - następne lekcje.
________________________________________________________________
- 23-
Shift+[-->] Zaznaczanie bloku tekstu w prawo
Shift+[<--] Zaznaczanie bloku tekstu w lewo
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ę)
Alt+Backspace Anuluj ostatnią operację (Undo)
Ctrl+L Powtórz przeszukiwanie (Repeat search)
________________________________________________________________
________________________________________________________________
EOF
- 24-
LEKCJA 4. Jeszcze o IDE C++ .
_______________________________________________________________
W trakcie tej lekcji:
1. Dowiesz się więcej o menu i okienkach w środowisku IDE.
2. Poznasz trochę technik "myszologicznych".
3. Napiszesz i uruchomisz swój drugi program.
________________________________________________________________
System Message
Disk is not ready in drive A
[Retry] [Cancel]
znaczy to:
[F1] - Pomoc
[F2] - Zapamiętanie bieżącego pliku na dysku pod bieżącą nazwą
(nawet jeśli tą nazwą jest NONAME01.CPP, tzn. została nadana
automatycznie i znaczy - o ironio - "BEZNAZWY01.CPP") i w
bieżącym katalogu.
[F3] - Załadowanie do okienka edycyjnego nowego pliku tekstowego
(np. nowego programu).
[Alt]-[F9] - Kompilacja w trybie "Compile".
[F9] - Kompilacja w trybie "Make" (jednoczesnej kompilacji i
- 25-
konsolidacji).
[F10] - Uaktywnienie głównego menu.
- 26-
[Alt]-[F3].
________________________________________________________________
[!!!]UWAGA
________________________________________________________________
Bądź ostrożny podejmując decyzję o zapisie wersji programu na
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
dysk.
________________________________________________________________
- 27-
Rozwiń menu Options (opcje).
Możesz to zrobić na wiele sposobów. Najszybciej chyba naciskając:
[Alt]+[O]
Full Menus [Off/On]- Use or don't use full set of menu commands.
Save - Save all the settings you've made in the Options menu.
- 28-
Ten rozkaz pozwala Ci ustawić konfigurację IDE "raz na zawsze".
UWAGA:
________________________________________________________________
* Jeśli zainstalowałeś zawartość dyskietki na dysku i wolisz
posługiwać się własnym katalogiem roboczym - wpisz tam
odpowiednią ścieżkę dostępu - np. C:\C-BELFER. Jeśli Twój
katalog zagnieżdżony jest głębiej (np. w przypadku użytkowników
sieci Novell) - podaj pełną ścieżkę dostępu - np.:
F:\USERS\ADAM\C-BELFER
* Wszędzie, gdzie w treści książki odwołuję się do dyskietki A:
możesz konsekwentnie po zainstalowaniu stosować odpowiedni
- 29-
katalog na dysku stałym, bądź na dysku sieciowym.
________________________________________________________________
4. Naciśnij [Enter].
*.C
A:\???.C
D:\BORLANDC\SOURCE\P*.*
BC A:\PIERWSZY.CPP
- 30-
Jeśli korzystasz z programu Norton Commander, to możesz dodać do
C: TC !.!
cpp: bc !.!
C: D:\BORLANDC\BIN\BC !.!
CPP: WIN C:\BORLANDC\BIN\BCW !.!
[!!!]UWAGA
________________________________________________________________
Rozkazy uruchamiające kompilator mogą być złożone nawet z 4
parametrów - np.:
spowoduje:
* uruchomienie Windows w trybie rozszerzonym 386
* uruchomienie kompilatora w wersji dla Windows - BCW.EXE
* załadowanie pliku z programem - P27.CPP z wskazanego katalogu
________________________________________________________________
[P002.CPP]
main()
{
printf("\n");
printf("Autor: np. Antoni Kowalski\n");
printf("program: PIERWSZY.CPP \n - wersja II \n");
getch();
}
________________________________________________________________
- 31-
poprzez schowek Windows (Clipboard).
W oknie kompilatora należy:
1. Otworzyć nowe okno edytora tekstowego:
File | New
2. Wstawić plik ze schowka:
Edit | Paste
--- To okno (AM-Edit) i całego BELFRA możesz w tym czasie zredukować
--- Do ikonki.------------------------------------------------------
********************************************************************
10 IF INKEY$="" GOTO 10
[Alt]-[R], [R]
lub
[Alt]-[R], [Enter]
- 32-
W ten sposób C++ ZNOWU chce Cię uchronić przed utratą programu,
ale uważaj! Jeśli odpowiesz Tak ([Y] lub [Enter]), to nowa
wersja programu zostanie nadpisana na starą! Jeśli odpowiesz Nie
[N]
A:\PIERWSZY.EXE
lub krócej
A:\PIERWSZY
a jeśli chcesz się przekonać, czy Twój program jest tam, gdzie
powinien być, możesz go zobaczyć. Napisz rozkaz
DIR A:\
lub
DIR A:\*.EXE
- 33-
doskonale spisują się przy obróbce plików tekstowych, nie nadają
się do analizy i obróbki programów w wersji *.EXE. Narzędziami,
które będziemy musieli stosować, mogą być programy typu
DEBUGGER, PROFILER, LINKER (konsolidator), kompilator i in..
- 34-
LEKCJA 5. DZIAŁANIA PRZY POMOCY MYSZKI I BŁĘDY W PROGRAMIE.
________________________________________________________________
Z tej lekcji dowiesz się,
* Jak posługiwać się myszką w środowisku IDE (DOS)
* O czy należy pamiętać, przy tworzeniu i uruchamianiu
programów.
* Jak poprawiać błędy w programie.
________________________________________________________________
Name:
F:\USERS\ADAM\PROBY\PROGRAM.CPP
- 35-
Możesz również (jeśli odpowiedni katalog już istnieje), wskazać
właściwy katalog w okienku z listą "Files" i dwukrotnie
"kliknąć" lewym klawiszem myszki.
[!!!]UWAGA.
________________________________________________________________
Wszystkie pliki zawierające teksty programów w języku C++
powinny ˙mieć charakterystyczne rozszerzenie *.CPP (CPP to skrót
od C Plus Plus), lub .C. Po tym rozszerzeniu rozpoznaje te
programy kompilator. Nadanie rozszerzenia .C lub .CPP może
dodatkowo wpływać na sposób kompilacji programu. Zanim wyjaśnimy
te szczegóły, będziemy zawsze stosować rozszerzenie .CPP.
Wszelkie inne rozszerzenia (.BAK, .TXT, .DEF, itp.) nie
przeszkadzają w edycji i kompilacji programu, ale mogą w
niejawny sposób wpłynąć na sposób kompilacji.
________________________________________________________________
void main(void)
- 36-
[S] Entry Point
___________________________________________________________________
Punkt wejścia do programu nazywa się:
Program Entry Point
Taki właśnie punkt wejścia wskazuje słowo main().
Punk wejścia mogą mieć nie tylko programy .EXE ale także biblioteki
(.DLL - dynamicznie dołączanie biblioteki).
____________________________________________________________________
main()
{
<-- tu rozbudowuje się tekst programu
}
- 37-
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
ekran użytkownika. Na nieszczęście program nic nie robi, więc
nic się tam nie wydarzy.
vod main(void)
{
}
Co to jest deklaracja?
- 38-
to specjalne słowo wchodzące w skład języka programowania. Słowa
clrscr();
clrscr();
[S]
Function - Funkcja
Fuction call - Wywołanie funkcji
________________________________________________________________
- 39-
Włącz kompilację i próbę uruchomienia programu.
Kompilator stwierdzi, że program zawiera błędy.
Naciśnij dowolny klawisz, by zniknęło okienko kompilacji.
Kompilator napisał:
[???] O co mu chodzi?
________________________________________________________________
Tzw. PROTOTYP funkcji to coś bardzo podobnego do deklaracji
funkcji. Prototyp służy do przekazania kompilatorowi pewnych
informacji o funkcji jeszcze przed użyciem tej funkcji w
programie. Dla przykładu, gdy pisałeś pierwszą linię programu:
void main(void)
tekstu programu
* na samym początku programu wpisz:
- 40-
#include <conio.h>
#include ....
CONIO.H,
(plik CONIO.H
nazywany ˙także "plikiem nagłówkowym" znajduje się w podkatalogu
\INCLUDE). Kompilator dołącza zawartość pliku CONIO.H jeszcze
przed rozpoczęciem procesu kompilacji programu.
- 41-
- litera w nazwie funkcji
- średnik na końcu wiersza
- cudzysłów obejmujący tekst do wydrukowania
- nawias ( lub ) w funkcji printf()
- nawias klamrowy { lub }
- znak dyrektywy #
- całą dyrektywę #include <stdio.h>
______________________________________________________________________
EOF
- 42-
LEKCJA 6. NASTĘPNY PROGRAM - KOMPUTEROWA ARYTMETYKA.
________________________________________________________________
W trakcie tej lekcji napiszesz i uruchomisz następny program
wykonujący proste operacje matematyczne.
________________________________________________________________
[P003.CPP ]
/* Program przykladowy: _DRUGI.CPP */
clrscr();
printf("Zamieniam ulamki zwykle na dziesietne\n");
printf("\nPodaj licznik ulamka: ");
scanf("%f", &x); /* pobiera liczbę z klawiatury */
printf("\nPodaj mianownik ulamka: ");
scanf( "%f", &y);
UWAGA:
_________________________________________________________________
* Komentarze ujęte w [/*.....*/] możesz pominąć. Komentarz jest
przeznaczony dla człowieka. Kompilator ignoruje całkowicie
komentarze i traktuje komentarz jak puste miejsce, a dokładniej
- tak samo jak pojedynczą spację. Komentarz w C++ może mieć dwie
formy:
- 43-
/* Tekst komentarza */
// Tekst komentarza
* #include - Włącz.
Dyrektywa włączająca cały zewnętrzny plik tekstowy. W tym
przypadku włączone zostały dwa tzw. pliki nagłówkowe:
CONIO.H i STDIO.H.
- 44-
return - słowo kluczowe: Powrót, zwrot.
5+7 12
12 - 7 5
3*8 24
10 / 3 3.333333
10 % 3 1
________________________________________________________________
14%4
- 45-
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ć
przykłady po raz wtóry.
Przykład 1:
randomize();
int X=ramdom();
X = X % 10;
Przykład 2:
---------------------
#include <stdlib.h> /* Zwróc uwagę na dołączony plik */
#include <stdio.h>
main()
{
int i;
Przykad3
--------------------
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void main()
{
randomize();
printf("Liczby pseudolosowe z zakresu: 0-99 --> %d\n", random (100));
}
Przykład 4
-----------------
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
int i;
randomize();
printf("Liczby pseudolosowe: 0 to 99\n\n");
for(i=0; i<10; i++)
printf("%d\n", rand() % 100);
return 0;
}
- 46-
Zwróć uwagę, że to randomize() uruchamia generator liczb pseudolosowych,
czyli jakgdyby "włącza bęben maszyny losującej".
________________________________________________________________
[Z]
________________________________________________________________
1. Zamień operator dzielenia na operator mnożenia [*]:
__________________________________________________________________
EOF
- 47-
LEKCJA 7. Z czego składa się program.
_______________________________________________________________
W trakcie tej lekcji:
* Dowiesz się co robić, jeśli tęsknisz za Pascalem.
* Zapoznasz się wstępnie z preprocesorem C++.
* Poznasz dokładniej niektóre elementy języka C++.
_______________________________________________________________
A:\PASCAL.H
A:\POLTEKST.H
[P004.CPP]
#include <a:\pascal.h>
Program
Begin
Write("Ten program jest podobny");
Write(" do Turbo Pascala ");
Write(" tak tez mozna pisac w BORLAND C++ !");
Readln;
End
- 48-
UWAGA: MUSI ZOSTAĆ ZACHOWANA IDEALNA ZGODNOŚĆ z tekstem
oryginału!
A:\POKUS.CPP
3. Naciśnij [Enter].
4. Wpisz tekst programu:
[P005.CPP]
# include <a:\poltekst.h>
program
poczatek
czysty_ekran
drukuj ("Ten program - POKUS.CPP ");
drukuj ("Jest napisany po polsku ");
drukuj ("a mimo to Turbo C++ go rozumie!");
czekaj;
koniec
- 49-
Najczęściej stosowanymi dyrektywami preprocesora są:
# include - włącz
i
# define - zdefiniuj
#include
# include
PASCAL.H:
_______________________________________________________________
# include <stdio.h>
# define Program main()
# define Begin {
# define Writeln printf
# define Readln getch()
# define End }
________________________________________________________________
POLTEKST.H:
________________________________________________________________
# include <stdio.h>
# define program main()
# define poczatek {
# define koniec }
# define czysty_ekran clrscr();
# define drukuj printf
# define czekaj getch()
________________________________________________________________
"drukuj"
"printf"
- 50-
zauważysz łańcuchy znaków pisane w dość specjalny sposób:
napisy_w_których_unika_się_spacji.
#include <D:\KATALOG\nazwa.roz>
2. Komentarzy. Przykład:
3. Deklaracji. Przykład:
KAŻDY PROGRAM musi zawierać deklarację funkcji main (ang. main -
główna). Funkcja ta często jest bezparametrowa, co można
zaakcentować wpisując w nawiasy słowo kluczowe void:
main(void)
main()
4. Instrukcji.
i++;
- 51-
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
usunąć z pamięci (bywają także programy rezydujące w pamięci -
tzw. TSR, o czym system operacyjny powinien "wiedzieć").
WinMain(.....)
a w środowisku obiektowym w
OwlMain(....)
NAZWA.DLG
* wreszcie plik instruktażowy - jak z tego wszystkiego zrobić
końcową aplikację. W zależności od wersji kompilatora pliki
instruktażowe mogą mieć nazwy: NAZWA.PRJ (Project - BORLAND),
NAZWA.IDE, a dla programu MAKE - MAKEFILE, NAZWA.MAK, NAZWA.NMK,
itp.
W środowisku Windows występuje jeszcze zwykle w składzie
projektów aplikacji tzw. plik definicji sposobu wykorzystania
zasobów - NAZWA.DEF.
________________________________________________________________
- 52-
exit() - wyjście.
________________________________________________________________
FORMAT A:
main(void)
{
printf("wydrukuj cokolwiek");
return 0;
}
printf("pisz!");
nazwa_funkcji();
- 53-
Język C++ operuje wyłącznie pojęciem FUNKCJI. W C ani w C++ nie
ma podziału na FUNKCJE i PROCEDURY.
oznacza:
1. Funkcja main jest bezparametrowa (nie przyjmuje żadnych
argumentów z zewnątrz).
2. Funkcja main zwraca jako wynik swojego działania liczbę
całkowitą typu int (ang. INTeger - całkowita). Zwróć uwagę, że
jest to domyślny sposób działania funkcji main(). Jeśli nie
napiszemy przed funkcją main() słowa "int" - kompilator C++ doda
FUNKCJA printf().
#include <stdio.h>
- 54-
domyślnych ustawieniach kompilatora wywołanie kompilatora C
zamiast C++. C jest bardziej tolerancyjny i dokona kompilacji
(wyświetli jedynie komunikat ostrzegawczy - Warning). Kompilator
[S!]
EOF - End Of File - znak końca pliku.
EOL - End Of Line - znak końca linii.
Indicator - znak, wskaźnik (nie mylić z pointerem !)
- 55-
[???] SKĄD TO WIADOMO ?
________________________________________________________________
Kody EOF, EOL są tzw. predefiniowanymi stałymi. Ich szyfrowanie
(przypisywanie tym identyfikatorom określonej stałej wartości
liczbowej) dokonuje się z zastosowaniem preprocesora C++.
To, że nie musisz się zastanawiać ile to właściwie jest EOF
(zero ? czy -1 ?) zawdzięczamy też dołączanym plikom typu *.H, w
printf("%s","jakis napis");
ale także
printf("Jakis napis");
- 56-
ponieważ format "%s" jest formatem domyślnym dla funkcji
printf().
Przykład:
printf("%39s","jakis napis");
printf("%c",'X');
printf("%d", 1994);
Przykład:
printf("%f", 3.1416);
printf("%f3.2", 3.14159);
printf("%o", 255);
- 57-
Po przytoczeniu przykładów uogólnijmy sposób zastosowania wzorca
formatu:
%[przełączniki][szerokość_pola][.precyzja][rozmiar]Typ
[P006.CPP]
#include <stdio.h>
#include <conio.h>
int liczba;
int main()
{
clrscr();
printf("Podaj liczbe dziesietna calkowita ? \n");
scanf("%d", &liczba);
printf("\nSzesnastkowo to wynosi: ");
printf("%x",liczba);
getch();
return 0;
}
[P007.CPP]
int liczba;
int main()
{
clrscr();
printf("Podaj liczbe SZESNASTKOWA-np. AF - DUZE LITERY: \n");
scanf("%X", &liczba);
printf("%s","\nDziesietnie to wynosi: ");
printf("%d",liczba);
getch();
return 0;
}
- 58-
komentarza. Zwróć uwagę, że funkcja scanf() "formatuje" dane
wejściowe bardzo podobnie do funkcji printf(). Pewnie dziwi Cię
trochę "dualny" zapis:
liczba i &liczba.
Przykład:
Działanie:
"Iloczyn_3_ - wyprowadź jako łańcuch znaków.
%c - tu wyprowadź pojedynczy znak - '*'.
_5_ - wyprowadź jako łańcuch znaków.
%8s - wyprowadź łańcuch "wynosi_" uzupełniając go z przodu
spacjami do długości 8 znaków.
%d - wyprowadź 15 jako liczbę dziesiętną.
Przykład:
[P008.CPP]
int main()
{
clrscr();
printf("Skomplikowany napis:\n");
printf("Iloczyn 3 %c 5 %8s %d", '*', "wyniosi ", 15);
getch();
printf("\nWyrazenie jako argument:\n");
printf("Iloczyn 3 %c 5 %9s %d", 'x', "wynosi ", 3*5);
printf("\n\n\n");
printf("Przyjrzyj sie i nacisnij klawisz...");
getch();
return 0;
- 59-
}
________________________________________________________________
[Z]
Spróbuj samodzielnie:
- 60-
6. Powtórzyć kompilację programu, przy której nastąpiło
przepełnienie dyskietki.
7. Usunąć z dyskietki A: zbędne pliki *.EXE (TYLKO *.EXE !!!).
programu.
Podobnie jak większość edytorów tekstu zintegrowany edytor
środowiska IDE pozwala manipulować fragmentami blokami tekstu i
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:
- 61-
LEKCJA 8. Jakich słów kluczowych używa C++.
* Słów kluczowych
* Identyfikatorów
* Stałych liczbowych i znakowych
* Stałych tekstowych (łańcuchów znaków - napisów)
* Operatorów (umownych znaków operacji)
* Znaków interpunkcyjnych
* Odstępów
- 62-
angielskiego (swoją drogą, może to i lepiej, że C++ nie
wymyślili Japończycy...). Najważniejszą częścią słownika są tzw.
asm
Pozwala wstawić kod w ASEMBLERZE bezpośrednio do programu
break - przerwij.
case - w przypadku.
class - klasa.
continue - kontynuuj.
do - wykonaj.
extern - zewnętrzna.
- 63-
far - dalekie. Wskaźnik - podwójne słowo (w zakresie do 1 MB).
interrupt - przerwanie.
long - długi.
_seg - segment.
- 64-
sizeof - podaj wielkość.
static - statyczna.
struct - struktura.
switch - przełącz.
void - nieokreślona.
volatile - ulotna.
while - dopóki.
_AX€€€€€€€_AL€€€€€€€_AH€€€€€€€_SI€€€€€€€_CS
_BX€€€€€€€_BL€€€€€€€_BH€€€€€€€_SP€€€€€€€_DS
_CX€€€€€€€_CL€€€€€€€_CH€€€€€€€_BP€€€€€€€_ES
_DX€€€€€€€_DL€€€€€€€_DH€€€€€€€_DI€€€€€€€_SS
_FLAGS
- 65-
Próba użycia słowa o zastrzeżonym znaczeniu w jakiejkolwiek
innej roli (np. jako nazwa Twojej zmiennej) może spowodować
wadliwe działanie programu lub uniemożliwić kompilację. Unikaj
przypadkowego zastosowania słów o zastrzeżonym znaczeniu!
- 66-
pliku nagłówkowym IOSTREAM.H) pozwala programiście
przesłać dane tekstowe i/lub numeryczne do strumienia wyjściwego
i umieścić tekst na ekranie monitora.
[P009.CPP]
void main(void)
{
clrscr();
cout << "Stosujemy obiekt cout:\n";
cout << "Tekst pierwszy\n";
cout << "Tekst drugi...\n";
getch();
}
- 67-
Bajt Nr X 0100 0001 - kod ASCII litery A
Bajt Nr X+1 0000 0000 - kod ASCII 0 - znak końca
- 68-
stdout jest skrótem od Standard Output - standardowe wyjście.
Oznacza to w skrócie typowe urządzenie wyjściowe podłączone do
komputera ˙i umożliwiające wyprowadzenie informacji z komputera.
[P010.CPP]
#include <stdio.h>
#include <conio.h>
int main(void)
{
clrscr();
fprintf(stdout, "Drukuje...\n");
fprintf(stdprn, "Pierwsza proba drukowania\n");
fprintf(stdprn, "Autor: ....................");
fprintf(stdout, "Koniec drukowania.");
fprintf(stdout, "Skonczylem, nacisnij cosik...");
getch();
return 0;
}
fprintf(stdout, "Drukuje...\n");
- 69-
wątpliwości. Często próbuje wtedy wykonać reset komputera i
wypowiada mnóstwo słów, których nie wypada mi tu zacytować.
ZMIENNE.
3+[]=5
- 70-
klasy, zadania skomplikowały się:
3+[]=5
147.968 + [ ] = 123876.99875
3+x=5
147.968 + y = 123876.99875
- 71-
parami. Przy obiekcie cin musisz zawsze podać operator
pobierania ze strumienia wejściowego >> i nazwę zmiennej. Zapis
[P011.CPP]
#include <iostream.h>
#include <conio.h>
void main(void)
{
int x;
cout << "Podaj liczbe calkowita 0 - 1000 do zapamietania: ";
cin >> x;
cout << "Pamietam! ";
cout << "Wielokrotnosci liczby: \n":
cout << "x, 2x, 3x: " << x << " " << 2*x << " " << 3*x;
cout << "\n ...Nacisnij dowolny klawisz...";
getch();
}
- 72-
itp...(szczegóły - patrz niżej).
int x;
- 73-
RÓŻNYCH TYPÓW - mogą być liczbami, mogą także być tekstami.
[P012.CPP]
#include <conio.h>
#include <iostream.h>
void main(void)
{
char x[20]; //<---- deklaracja tablicy znakowej.
clrscr();
cout << "Podaj mi swoje imie: : ";
- 74-
cin >> x;
cout << "\nNazywasz sie " << x << ", ladne imie!\n";
cout << "...Nacisnij dowolny klawisz...";
getch();
}
[Z]
- 75-
LEKCJA 9. O SPOSOBACH ODWOŁYWANIA SIĘ DO DANYCH.
________________________________________________________________
W trakcie tej lekcji poznasz:
* sposoby wyprowadzania napisów w różnych kolorach
* sposoby zapamiętywania tekstów
* sposoby odwoływania się do danyc i zmiennych przy pomocy ich
nazw - identyfikatorów.
________________________________________________________________
[P012.CPP]
#include <conio.h>
#include <iostream.h>
main()
{
char imie[20];
char nazwisko[20];
clrscr();
cout << "\aPodaj imie: ";
cin >> imie;
cout << "\aPodaj nazwisko: ";
cin >> nazwisko;
cout << '\n' << imie << ' ' << nazwisko << '\n';
textcolor(4+128);
cprintf("\nPan(i), %s %s? Bardzo mi milo!", imie, nazwisko);
getch();
cout << '\a';
return 0;
}
- 76-
Operator >> pobiera ze strumienia danych wejściowych cin wpisane
- 77-
10 Light green Jasno zielony
11 Light cyan Morski - jasny
12 Light red Jasno czerwony
13 Light magenta Jasno fio;etowy (fiol-różowy)
14 Yellow Żółty
15 Bright white Biały rozjaśniony
128 + n Blinking Migający BLINK
________________________________________________________________
[!!!]UWAGA:
________________________________________________________________
* W pliku CONIO.H są predefiniowane stałe (skrajna prawa kolumna
O IDENTYFIKATORACH - DOKŁADNIEJ.
[P013.CPP]
#include <stdio.h>
#include <conio.h>
- 78-
int main(void)
{
clrscr();
printf("Podaj promien ?\n");
scanf("%f", &r);
printf("\nPole wynosi P = %f", PI*r*r );
getch();
return 0;
}
* Identyfikatory
- nazwy funkcji (zastrzeżone):
main, printf, scanf, getch, clrscr.
- nazwy zmiennych (dowolne):
PI, r.
* Dyrektywy preprocesora:
# include
[Z]
________________________________________________________________
1. Uruchom program przykładowy. Spróbuj zamienić identyfikator
zmiennej PI na pisane małymi literami pi. Powinien wystąpić
błąd.
________________________________________________________________
[P013-1.CPP]
#include <stdio.h>
#include <conio.h>
int main(void)
{
clrscr();
cout << "Podaj promien ?\n";
cin >> r;
cout << "\nPole wynosi P = " << PI*r*r;
getch();
return 0;
- 79-
}
LITERAŁY.
nieprawidłowy.
* Próba zastosowania przecinka w tej roli SPOWODUJE BŁĘDY !
________________________________________________________________
Przykład:
.0123€€€€€€€€€€€€€€€0.0123
123e4€€€€€€€€€€€€€€€123 * 10^4 = 1 230 000
1.23e3€€€€€€€€€€€€€€€1.23 * 10^3 = 1230
123e-4€€€€€€€€€€€€€€0.0123
UWAGA:
'\24' - kod Ósemkowy ! (dziesiętnie 20)
'\x24' - kod SZESNASTKOWY ! (dziesiętnie 36)
[S]€€SLASH, BACKSLASH.
- 80-
€€€€€Kreska "/" nazywa się SLASH (czyt. "slasz") - łamane,
[P014.CPP]
int main(void)
{
clrscr();
printf("Wydrukuje A jako \nLiteral znakowy:\tKod ASCII:\n");
printf("%c", 'A');
printf("\t\t\t\t%d", 'A');
printf("\nPodaj mi liczbe ? ");
scanf("%d", &liczba);
printf("\n%c\t\t\t\t%d\n", 'A'+liczba, 'A'+liczba);
scanf("%d", &liczba);
printf("\n%c\t\t\t\t%d", 'A'+liczba, 'A'+liczba);
getch();
return 0;
}
- 81-
kolejnych cyfr 1, 2, 3 są kolejnymi liczbami, to zauważ, że
wyrażenia:
:ETYKIETA (BPL)
ETYKIETA: (C/C++)
[P015.CPP]
# include <stdio.h>
int main(void)
{
clrscr();
- 82-
printf("Wydrukuje A jako \nLiteral znakowy:\tKod ASCII:\n");
printf("%c", 'A');
printf("\t\t\t\t%d", 'A');
etykieta:
printf("\npodaj mi liczbe ? ");
scanf("%d", &liczba);
printf("\n%c\t\t\t\t%d\n", 'A'+liczba, 'A'+liczba);
goto etykieta;
return 0;
}
€€€€€€€€€€€€€€€€€€€€Making
A:\GOTOTEST.CPP
€€€€€€€€€€€€€€€is up to date
- 83-
Powtórz kompilację programu. Nie musisz uruchamiać programu.
Zwróć uwagę tym razem na pojawiające się w okienku komunikatów
ostrzeżenie:
goto etykieta;
- 84-
Nasz program mógłby przy zastosowaniu tych słów zostać napisany
np. tak:
[LOOP-1]
#include <iostream.h>
void main()
{
int x = 2;
petla:
cout << x << '\n';
x = x + 1;
if (x < 11) goto petla;
}
[LOOP-2]
#include <iostream.h>
void main()
{
int x = 2;
petla:
cout << x << '\n';
x = x + 1;
if(x > 10) break;
goto petla;
}
[LOOP-3]
#include <iostream.h>
int main(void)
{
for(int x = 2; x < 11; x = x + 1)
{
cout << x << '\n';
}
return 0;
}
[LOOP-4]
#include <iostream.h>
int main(void)
{
int x = 2;
while (x < 11)
- 85-
{
cout << x << '\n';
x = x + 1;
}
return 0;
}
[LOOP-5]
#include <iostream.h>
int main(void)
{
int x = 2;
do
{
cout << x << '\n';
x = x + 1;
}while (x < 11);
return 0;
}
[LOOP-6]
#include <iostream.h>
int main(void)
{
for(;;)
{
cout << x << '\n';
x++;
if( x > 10) break;
}
return 0;
}
- 86-
[P016.CPP]
// Przyklad FACELIFT.CPP
// Program przykladowy 10na16.CPP / 16na10.CPP FACE LIFTING.
# include <stdio.h>
int liczba;
int main()
{
clrscr();
printf("Kropka = KONIEC \n");
for(;;)
{
printf("Podaj liczbe dziesietna calkowita ? \n");
scanf("%d", &liczba);
printf("Szesnastkowo to wynosi:\n");
printf("%X",liczba);
getch();
printf("Podaj liczbe SZESNASTKOWA-np.DF- DUZE LITERY: \n");
scanf("%X", &liczba);
printf("%s","Dziesietnie to wynosi: ");
printf("%d",liczba);
if(getch() == '.') break;
}
return 0;
}
- 87-
[Z]
________________________________________________________________
2. Opracuj program pobierający znak z klawiatury i podający w
odpowiedzi kod ASCII pobranego znaku dziesiętnie.
3. Opracuj program pobierający liczbę dziesiętną i podający w
odpowiedzi:
* kod ósemkowy,
* kod szesnastkowy,
* znak o zadanym
** dziesiętnie
** szesnastkowo
kodzie ASCII.
_______________________________________________________________
- 88-
LEKCJA 10. Jakie operatory stosuje C++.
_______________________________________________________________
Podczas tej lekcji:
* Poznasz operatory języka C++.
* Przetestujesz działanie niektórych operatorów.
* Dowiesz się więcej o deklarowaniu i inicjowaniu zmiennych.
_______________________________________________________________
* priorytetem
** najwyższy priorytet ma grupa 1 a najniższy grupa 16 -
przecinek, np. mnożenie ma wyższy priorytet niż dodawanie;
** wewnątrz każdej z 16 grup priorytet operatorów jest równy;
* łącznością (wiązaniem).
Przykład:
a+b+c+d = (a+d)+(c+b)
[S]
________________________________________________________________
ASSIGN(ment) - Przypisanie.
EQAL(ity) - Równy, odpowiadający.
BITWISE - bit po bicie (bitowo).
REFERENCE - odwołanie do..., powołanie się na..., wskazanie
na... .
Funkcje logiczne:
OR - LUB - suma logiczna (alternatywa).
AND - I - iloczyn logiczny.
XOR (eXclusive OR) - ALBO - alternatywa wyłączająca.
NOT - NIE - negacja logiczna.
________________________________________________________________
- 89-
Lista operatorów języka C++.
________________________________________________________________
Kategoria€| Operator€€€€€| €€€Co robi / jak działa
----------|--------------|--------------------------------------
- 90-
----------|--------------|--------------------------------------
4. Dostępu| .* | Operatory specyficzne dla C++.
(Member |(dereference) | Skasowanie bezpośredniego wskazania
access) | | na członka klasy (Class Member).
{L->R} |--------------|--------------------------------------
| ->* | Skasowanie pośredniego wskazania typu
objektowe | | "wskaźnik do wskaźnika"
----------|--------------|--------------------------------------
5. Addy - | + | Dodawanie dwuargumentowe.
tywne |--------------|--------------------------------------
{L->R} | - | Odejmowanie dwuargumentowe.
----------|--------------|--------------------------------------
6. Przesu-| << | Binarne przesunięcie w lewo.
nięcia |--------------|--------------------------------------
(Shift) | >> | Binarne przesunięcie w prawo.
{L->R} | | (bit po bicie)
----------|--------------|--------------------------------------
7. Relacji| < | Mniejsze niż...
{L->R} |--------------|--------------------------------------
|> | Większe niż....
|--------------|--------------------------------------
| <= | Mniejsze lub równe.
|--------------|--------------------------------------
| >= | Większe lub równe.
----------|--------------|--------------------------------------
8.Równości| == | Równe (równa się).
{L->R} | != | Nie równe.
----------|--------------|--------------------------------------
9. |& | AND binarnie (Bitwise AND)
{L->R} | | UWAGA: Druga rola "&".
----------|--------------|--------------------------------------
10. |^ | XOR binarnie (Alternatywa wyłączna).
{L->R} | | UWAGA: To nie potęga !
----------|--------------|-------------------------------------
11.{L->R} | | | OR binarnie (bit po bicie)
----------|--------------|-------------------------------------
12.{L->R} | && | Iloczyn logiczny (Logical AND).
----------|--------------|-------------------------------------
13.{L->R} | || | Suma logiczna (Logical OR).
----------|--------------|--------------------------------------
14. Oper. | ?: | Zapis a ? x : y oznacza:
Warunkowy | | "if a==TRUE then x else y"
Conditional | gdzie TRUE to logiczna PRAWDA "1".
{L<<-R} | |
----------|--------------|--------------------------------------
15. Przy- | = | Przypisz wartość (jak := w Pascalu)
pisania |--------------|--------------------------------------
{L<<-R} | *= | Przypisz iloczyn. Zapis X*=7
| | oznacza: X=X*7 (o 1 bajt krócej!).
|--------------|--------------------------------------
| /= | Przypisz iloraz.
|--------------|--------------------------------------
| %= | Przypisz resztę z dzielenia.
|--------------|--------------------------------------
| += | Przypisz sumę X+=2 oznacza "X:=X+2"
- 91-
|--------------|--------------------------------------
| -= | Przypisz różnicę X-=5 ozn. "X:=X-5"
|--------------|--------------------------------------
| &= | Przypisz iloczyn binarny ( Bitwise
| | AND)
| | bit po bicie.
|--------------|--------------------------------------
| ^= | Przypisz XOR bit po bicie.
|--------------|--------------------------------------
| |= | Przypisz sumę log. bit po bicie.
|--------------|--------------------------------------
| <<= | Przypisz wynik przesunięcia o jeden
| | bit w lewo.
|--------------|--------------------------------------
| >>= | j. w. o jeden bit w prawo.
----------|--------------|--------------------------------------
16. Prze- | , | Oddziela elementy na liście argu -
cinek | | mentów funkcji,
(Comma) | | Stosowany w specjalnych wyrażeniach
{L->R} | | tzw. "Comma Expression".
----------|--------------|-------------------------------------
UWAGI:
* Operatory # i ## stosuje się tylko w PREPROCESORZE.
* Operatory << i >> mogą w C++ przesyłać tekst do obiektów cin i
A:\UNARY.CPP
- 92-
[P017.CPP ]
# include <stdio.h>
# include <conio.h>
float x;
void main(void)
{
clrscr();
for(;;)
{
printf("\n Podaj liczbe...\n");
scanf("%f", &x);
printf("\n%f\t%f\t%f\n", x, +x, -x );
printf("\n%f", --x );
printf("\t%f", x );
printf("\t%f", ++x);
if(getch() = '.') break;
};
}
- 93-
Zajmijmy się teraz dokładniej INKREMENTACJĄ, DEKREMENTACJĄ i
OPERATORAMI PRZYPISANIA.
[P018.CPP]
# include <stdio.h>
# include <conio.h>
long int x;
short int krok;
char klawisz;
int main()
{
clrscr();
printf("Test operatora przypisania += \n");
x=0;
printf("Podaj KROK ? \n");
scanf("%d",&krok);
for(;;)
{
printf("\n%d\n", x+=krok);
printf("[Enter] - dalej [K] - Koniec\n");
klawisz = getch();
if (klawisz=='k'|| klawisz=='K') goto koniec;
}
koniec:
printf("\n Nacisnij dowolny klawisz...");
getch();
return 0;
}
w programie:
* DEKLARACJE ZMIENNYCH:
long int x; (długa, całkowita)
short int krok; €€€€(krótka, całkowita)
char klawisz;€€€€€(zmienna znakowa)
- 94-
* INSTRUKCJĘ WARUNKOWĄ:
if (KLAWISZ=='k'|| KLAWISZ=='K') goto koniec;
(JEŻELI zmienna KLAWISZ równa się "k" LUB równa się "K"
idź do etykiety "koniec:")
* Warunek sprawdzany po słowie if jest ujęty w nawiasy.
* Nadanie wartości zmiennej znakowej char klawisz przez funkcję:
klawisz = getch();
[Z]
________________________________________________________________
1. Do programu przykładowego wstaw kolejno różne operatory
przypisania:
[P019.CPP]
# include <stdio.h>
# include <conio.h>
int b,c,d,e;
int i;
int STO = 100;
void main(void)
{
clrscr();
- 95-
printf("Demonstruje dzialanie \n");
printf(" PREinkrementacji POSTinkrementacji");
printf("\nNr€€€€--X€€€€€€++X€€€€€€€€€€€€X--€€€€€€€X++ \n");
b = c = d = e = STO;
for(i=1; i<6; i++)
{
printf("%d\t%d\t%d\t\t%d\t%d\t\n", i,--b,++c,d--,e++);
}
getch();
}
Demonstruje dzialanie
PREinkrementacji POSTinkrementacji
Nr€€€€--X€€€€€€++X€€€€€€€€€€€€X--€€€€€€€X++
1 99 101 100 100
2 98 102 99 101
3 97 103 98 102
4 96 104 97 103
5 95 105 96 104
[F7] - printf("Demonstruję...");
- 96-
Zapraszamy teraz debugger do pracy wydając mu polecenie "Wykonaj
Inspekcję" [Alt]-[D] | Inspect. Pojawia się okienko dialogowe
"Inspect".
* Wpisz do okienka tekstowego nazwę zmiennej b i naciśnij
[Enter].
Demonstruje dzialanie
PREinkrementacji POSTinkrementacji
Nr€€€€--X€€€€€€++X€€€€€€€€€€€€X--€€€€€€€X++
1 99 101 1000 100
2 98 102 999 101
3 97 103 998 102
4 96 104 997 103
5 95 105 996 104
- 97-
...
i<6 (warunek kontynuacji)
[Z]
________________________________________________________________
4. Zmień w programie przykładowym wartość początkową STO na
dowolną inną - np. zero. Przetestuj działanie programu.
5. Sprawdź, czy można wszystkie zmienne używane w programie
przykładowym zadeklarować wspólnie (jeden wiersz zamiast
trzech).
- 98-
LEKCJA 11. Jak deklarować zmienne. Co to jest wskaźnik.
________________________________________________________________
Więcej o deklaracjach.
późniejszych lekcji.
* deklarowane,
* definiowane i
* inicjowane.
Przykład :
- 99-
float x,y,z;€€€€€€€€€€€€€€€€€€€€€€€(DEKLARACJA)
Skutek praktyczny:
* Ma sens i jest poprawna deklaracja:
const float PI = 3.1416;
* Niepoprawna natomiast jest deklaracja:
var float x;
Jeśli nie zadeklarowano stałej słowem const, to "zmienna" (var)
przyjmowana jest domyślnie.
Przykład:
Przykład
int DrukujAutora(void)
{
printf("\nAdam MAJCZAK AD 1993/95 - C++ w 48 godzin!\n");
printf("\n Wydanie II Poprawione i uzupełnione.")
return 0;
}
Przykład
void Drukuj_Pytanie(void)
{
printf("Podaj liczbe z zakresu od 0 do 255");
printf("\nUstawie Ci ERRORLEVEL\t");
}
- 100-
W powyższych przykładach zwróć uwagę na:
* sposób deklarowania zmiennej, przekazywanej jako parametr do
funkcji - n i err;
* definicje funkcji i ich wywołanie w programie (podobnie jak w
Pascalu).
# include "stdio.h"
# include "A:\funkcje1.h"
int err;
void main(void)
{
DrukujAutora();
Drukuj_Pytanie();
scanf("%d", &err);
UstawDosErrorlevel(err);
}
[Z]
________________________________________________________________
1. Sprawdź, w jakim pliku nagłówkowym znajduje się prototyp
funkcji exit(). Opracuj najprostszy program PYTAJ.EXE
ustawiający zmienną systemową ERRORLEVEL według schematu:
main()
{
printf("....Pytanie do użytkownika \n...");
scanf("%d", &n);
exit(n);
}
@echo off
:LOOP
cls
echo 1. Wariant 1
echo 2. Wariant 2
echo 3. Wariant 3
echo Wybierz wariant działania programu...1,2,3 ?
- 101-
PYTAJ
IF ERRORLEVEL 3 GOTO START3
IF ERRORLEVEL 2 GOTO START2
IF ERRORLEVEL 1 GOTO START1
echo Chyba zartujesz...?
goto LOOP
:START1
'AKCJA WARIANT 1
GOTO KONIEC
:START2
'AKCJA WARIANT 2
GOTO KONIEC
:START3
'AKCJA WARIANT 3
:KONIEC
- 102-
sam efekt, jak zastosowanie kompilatora bcc/tcc w następujący
sposób:
Dla IBM PC typy int i short int są reprezentowane przez taki sam
- 103-
char signed 1 -128...+127 DB
int signed 2 -32768...+32767 DB
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
long int signed 4 -2 147 483 648... DW
+2 147 483 647
unsigned char unsigned 1 0...+255 DB
unsigned unsigned 2 0...+65 535 DW
unsigned int unsigned 2 0...+65 535 DW
unsigned short unsigned 2 0...+65 535 DW
signed int signed 2 -32 768...+32 767 DW
signed signed 2 -32 768...+32 767 DW
signed long signed 4 -2 147 483 648... DD
+2 147 483 647
enum unsigned 2 0...+65 535 DW
float signed 4 3.4E+-38 (7 cyfr) DD
double signed 8 1.7E+-308 (15 cyfr) DQ
long double signed 10 3.4E-4932...1.1E+4932 DT
far * (far pointer, 386) 6 unsigned 2^48 - 1 DF, DP
________________________________________________________________
UWAGI:
* DB - define byte - zdefiniuj bajt;
DW - define word - zdefiniuj słowo (16 bitów);
DD - double word - podwójne słowo (32 bity);
DF, DP - define far pointer - daleki wskaźnik w 386;
DQ - quad word - poczwórne słowo (4 * 16 = 64 bity);
DT - ten bytes - dziesięć bajtów.
* zwróć uwagę, że typ wyliczeniowy enum występuje jako odrębny
typ danych (szczegóły w dalszej części książki).
________________________________________________________________
Ponieważ nie ma liczb ani short float, ani unsigned short float,
deklaracje:
short a;
unsigned short b;
- 104-
stosowaliśmy - funkcji wejścia - scanf().
FUNKCJA scanf().
dla przykładu
int X;
...
scanf("%d", &X);
- 105-
STDIO.H i CONIO.H.
[P021.CPP]
//UWAGA: Dołącz właściwe pliki nagłówkowe !
void main()
{
float A, B;
clrscr();
scanf("%f %f", &A, &B);
printf("\n%f\t%d", A,B);
getch();
}
[Z]
________________________________________________________________
3 Zmień w programie przykładowym, w funkcji printf() wzorce
formatu na %s, %c, itp. Porównaj wyniki.
________________________________________________________________
px = &x;
- 106-
przypisuje wskaźnikowi px adres zmiennej x. Mówimy, że:
y = x;
oraz
px = &x;
y = *px;
int x,y;
int *px;
main()
......
int X,Y;
int *pX;
...
pX = &X;
.......
Y = *pX + 1; €€€€€€/* to samo, co Y = X + 1 */
printf("%d", *pX);€€€€€€€/* to samo, co printf("%d", X); */
Y = sqrt(*pX);€€€€€€€€€€€/* pierwiastek kwadrat. z X */
......
- 107-
* potem następuje wykonanie operacji arytmetycznej;
(operacja nie jest więc wykonywana na wskaźniku, a na
wskazywanej zmiennej!).
Y = *(pX + 1);
*pX = 0;€€€€€€€€€€€€i€€€€€€€€€X = 0;
*pX += 1;€€€€€€€€€€€i€€€€€€€€€X += 1;
(*pX)++;€€€€€€€€€€€€i€€€€€€€€€X++; /*3*/
*pX++;
najpierw nastąpiłoby
- zwiększenie wskaźnika o 1 i wskazanie "sąsiedniej" zmiennej,
potem
- wyłuskanie, czyli pobranie z pamięci zmiennej wskazanej przez
nowy, zwiększony wskaźnik, zawartość pamięci natomiast, tj.
wszystkie zmienne rozmieszczone w pamięci pozostałyby bez zmian.
najpierw ++
potem *
- 108-
Zwróć uwagę, że kolejność {L<<-R} dotyczy WSZYSTKICH operatorów
jednoargumentowych.
________________________________________________________________
zadeklarowaniu:
i zainicjowaniu:
pX = &X; pY = &Y;
pY = pX;
[P022-1.CPP wersja 1]
# include "stdio.h"
# include "conio.h"
int a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,x=9,y=10,i;
int *ptr1;
long int *ptr2;
void main()
{
- 109-
clrscr();
ptr1=&a;
ptr2=&a;
printf("Skok o 2Bajty Skok o 4Bajty");
[P022-2.CPP wersja 2]
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;
void main()
{
clrscr();
ptr1=&a;
ptr2=&a;
for (i=0; i<=9; i++)
{
printf("\n%d", *(ptr1+i));
printf("\t%d", *(ptr2+i));
getch();
}
}
Skok o 2B Skok o 4B
11€€€€€€€€€€€€€11
22€€€€€€€€€€€€€33
33€€€€€€€€€€€€€55
44€€€€€€€€€€€€€77
55€€€€€€€€€€€€€99
66€€€€€€€€€€€€€27475
- 110-
77€€€€€€€€€€€€€28448
88€€€€€€€€€€€€€8258
99€€€€€€€€€€€€€27475
10€€€€€€€€€€€€€2844
wskazania:
[Z]
________________________________________________________________
4 Wybierz dowolne dwa przykładowe programy omawiane wcześniej i
przeredaguj je posługując się zamiast zmiennych - wskaźnikami do
- 111-
LEKCJA 12. Wskaźniki i tablice w C i C++.
________________________________________________________________
Deklaracja:
int A[12];
oznacza:
należy zarezerwować 12 KOLEJNYCH komórek pamięci dla 12 liczb
całkowitych typu int (po 2 bajty każda). Jednowymiarowa tablica
(wektor) będzie się nazywać "A", a jej kolejne elementy zostaną
ponumerowane przy pomocy indeksu:
- zwróć uwagę, że w C zaczynamy liczyć OD ZERA A NIE OD JEDYNKI;
- 112-
element) tablicy;
- samą tablicę;
to takie deklaracje powinny wyglądać następująco:
int i;
int *pA;
int A[12];
pA = &A[0];
*pA[0]
oznacza:
"wyłuskaj zawartość komórki pamięci wskazanej przez wskaźnik",
czyli inaczej - pobierz z pamięci pierwszy (zerowy!) element
tablicy A[]. Jeśli deklaracja typów elementów tablicy i
deklaracja typu wskaźnika są zgodne i poprawne, nie musimy się
dalej martwić ile bajtów zajmuje dany obiekt - element tablicy.
Zapisy:
*pA[0];€€€€€€€€*pA;€€€€€€€€€€€A[0]
*(pA[0]+1)€€€€€*(pA+1)€€€€€€€€A[1]
*(pA[0]+2)€€€€€*(pA+2)€€€€€€€€A[2]€€€€€€itd.
A[0][0];
A[0][0][0];
itd.
*pA == *pA[0]
*A
*(A+1)€€€€€€€€€€€€*(pA+1)€€€€€€€€A[1]
*(A+8)€€€€€€€€€€€€*(pA+8)€€€€€€€€A[8] itd.
- 113-
x = &A[i]€€€€€€€€x=A+i
*pA[i]€€€€€€€€€*(A+i)
pA = A;
pA++;
A = pA;€€€€€€€€€€€€€ŹLE !
A++;€€€€€€€€€€€€€€€€ŹLE !
Przykład
int WEKTOR[5];
Tablica WEKTOR jest jednowymiarowa i składa się z 5 elementów
typu int: WEKTOR[0]....WEKTOR[4].
Przykład
float Array[10][5];
Tablica Array jest dwuwymiarowa i składa się z 50 elementów typu
Przykład
Przykład
- 114-
char hej[5]="Ahoj";
char hej[5]={'A', 'h', 'o', 'j'};
€€€€€hej[0]='A'€€€€€hej[1]='h'€€€€€hej[2]='o' itp.
€€€€€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 A[];
[P023.CPP]
# include "stdio.h"
# include <conio.h>
int a[][2]={ {1,2},{3,4},{5,6},{7,8},{9,10},{11,12} };
char b[]={ "Poniedzialek" };
int i;
int *pa;
char *pb;
void main()
{
pa = &a[0][0];
pb = b; // lub pb = b[0];
clrscr();
for (i=0; i<12; i++)
printf("%d\t%c\n", *(pa+i), *(pb+i));
getch();
}
Zwróć uwagę, że w C++ każdy wymiar tablicy musi mieć swoją parę
nawiasów kwadratowych. Dla przykładu, tablicę trójwymiarową
należy deklarować nie tak TAB3D[i, j, k] lecz tak:
int i, j, k;
- 115-
...
TAB3D[i][j][k];
[P024.CPP]
# include <stdio.h>
# include <conio.h>
void main()
{
char bufor[20];
clrscr();
printf("podaj liczby - ja oblicze SREDNIA i SUMA\n");
printf("ZERO = KONIEC\n");
- 116-
}
printf("Suma wynosi: %d\n", suma);
printf("Srednia wynosi: %d\n", (suma / ile));
getch();
}
[P025.CPP]
# include <stdio.h>
# include <conio.h>
void main()
{
char bufor[20];
clrscr();
printf("podaj liczby - ja oblicze SREDNIA i SUMA\n");
printf("ZERO = KONIEC\n");
gets(bufor);
sscanf(bufor, "%d", &liczba);
while (liczba != 0)
{
suma += liczba;
gets(bufor);
sscanf(bufor, "%d", &liczba);
if(liczba == 0)
printf("I to by bylo na tyle...\n");
else
ile++;
}
printf("Suma wynosi: %d\n", suma);
printf("Srednia wynosi: %d\n", suma / ile);
getch();
}
€€€€€€€€€€a11€€a12€€a13€€a14€€a15€€a16
€€€€€€€€€€a21€€a22€€a23€€a24€€a25€€a26
€€€€€€€€€€a31€€a32€€a33€€a34€€a35€€a36
€€€€€€€€€€a41€€a42€€a43€€a44€€a45€€a46
- 117-
gdzie a i,j /** indeks**/ oznacza element tablicy zlokalizowany
w:
- wierszu i
- kolumnie j
Przypiszmy kolejnym elementom tablicy następujące wartości:
€€€€€€€€€€11€€€12€€€13€€€14€€€15€€€16
€€€€€€€€€€21€€€22€€€23€€€24€€€25€€€26
€€€€€€€€€€31€€€32€€€33€€€34€€€35€€€36
€€€€€€€€€€41€€€42€€€43€€€44€€€45€€€46
int TABLICA[4][6];
int TABLICA[4][6]={{11,12,13,14,15,16},{21,22,23,24,25,26}
{31,32,33,34,35,36},{41,42,43,44,45,46}};
Przykładowo:
int i, j;
for (i=0; i<=3; i++)
€€€€€{ for (j=0; j<=5; j++)
€€€€€€€€€€{ TABLICA[i][j] = (i+1)*10 + (j+1);}
€€€€€}
[P026.CPP]
int TABLICA[4][6]={{11,12,13,14,15,16},{21,22,23,24,25,26},
- 118-
{31,32,33,34,35,36},{41,42,43,44,45,46}};
# include <stdio.h>
# include <conio.h>
int *pT;
int i, j;
void main()
{
clrscr();
printf("OTO NASZA TABLICA \n");
for (i=0; i<=3; i++)
{
for (j=0; j<=5; j++)
printf("%d\t", TABLICA[i][j]);
printf("\n");
}
printf("\n\Inicjujemy wskaźnik na poczatek tablicy\n");
printf("i INKREMENTUJEMY wskaźnik *pT++ \n");
pT=&TABLICA[0][0];
for (i=0; i<4*6; i++)
printf("%d ", *(pT+i));
getch();
}
[P027.CPP]
# include <stdio.h>
# include <conio.h>
int TABLICA[4][6];
int *pT;
int i, j;
void main()
{
clrscr();
printf("Inicjujemy tablice\n");
for (i=0; i<4; i++)
€€€€€for (j=0; j<6; j++)
€€€€€{ TABLICA[i][j] = (i+1)*10 + (j+1); } // INDEKS!
printf("OTO NASZA TABLICA \n");
for (i=0; i<=3; i++)
{
for (j=0; j<=5; j++)
printf("%d\t", TABLICA[i][j]);
printf("\n");
}
printf("\n\Inicjujemy wskaźnik na poczatek tablicy\n");
- 119-
printf("i INKREMENTUJEMY wskaźnik *pT++ \n");
pT=&TABLICA[0][0];
for (i=0; i<4*6; i++)
printf("%d ", *(pT+i));
getch();
}
int T[10][10];
T[i][j] = (i+1)*(j+1);
int *pT;
i jego zainicjowania
pT = &T[0][0];
[P028.CPP]
# include <stdio.h>
# include <conio.h>
int T[10][10];
int *pT;
int i, j, k;
char spacja = ' ';
void main()
{
clrscr();
printf("\t TABLICZKA MNOZENIA (ineksy)\n");
for (i=0; i<10; i++)
{
for (j=0; j<10; j++)
{ T[i][j] = (i+1)*(j+1);
if (T[i][j]<10)
printf("%d%c ", T[i][j], spacja);
else
printf("%d ", T[i][j]);
- 120-
}
printf("\n");
}
printf("\n Inicjujemy i INKREMENTUJEMY wskaźnik *pT++ \n\n");
pT=&T[0][0];
for (k=0; k<10*10; k++)
{
if (*(pT+k) < 10)
printf("%d%c ", *(pT+k) , spacja);
else
printf("%d ", *(pT+k));
if ((k+1)%10 == 0) printf("\n");
}
getch();
}
[P029.CPP]
# include <stdio.h>
# include <conio.h>
char T[7][12]={"Poniedzialek",
"Wtorek",
"Sroda",
"Czwartek",
"Piatek",
"Sobota",
"Niedziela"};
char *pT;
int i, j, k;
char spacja=' ';
void main()
{
clrscr();
- 121-
pT =&T[0][0];
printf("\t TABLICA znakowa (ineksy)\n\n");
zmienisz format z
Poniedzialek
Wtorek
Sroda
Czwartek
Piatek
Sobota
Niedziela
80 111 110 105 101 100 122 105 97 108 101 107
87 116 111 114 101 107 0 0 0 0 0 0
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
83 111 98 111 116 97 0 0 0 0 0 0
78 105 101 100 122 105 101 108 97 0 0 0
[Z]
________________________________________________________________
- 122-
1. Posługując się wskaźnikiem i inkrementując wskaźnik z różnym
krokiem - np. pT += 2; pT += 3 itp., zmodyfikuj programy
przykładowe tak, by uzyskać wydruk tylko części tablicy.
2. Spróbuj zastąpić inkrementację wskaźnika pT++ dekrementacją,
odwracając tablicę "do góry nogami". Jak należałoby poprawnie
zainicjować wskaźnik?
3. Napisz program drukujący tabliczkę mnożenia w układzie
szesnastkowym - od 1 * 1 do F * F.
4. Wydrukuj nazwy dni tygodnia pionowo i wspak.
5. Zinterpretuj następujące zapisy:
int *pt_int;
float *pt_float;
int p = 7, d = 27;
float x = 1.2345, Y = 32.14;
void *general;
pt_int = &p;
*pt_int += d;
general = pt_int;
pt_float = &x;
Y += 5 * (*pt_float);
general = pt_float;
- 123-
LEKCJA 13. Jak tworzyć w programie pętle i rozgałęzienia.
_______________________________________________________________
W trakcie tej lekcji:
1. Dowiesz się znacznie więcej o pętlach.
2. Przeanalizujemy instrukcje warunkowe i formułowanie warunków.
_______________________________________________________________
- 124-
Instrukcja może być INSTRUKCJĄ GRUPUJĄCĄ, składającą się z
instrukcji prostych, deklaracji i definicji zmiennych lokalnych:
Przykład:
#include <math.h>
#include <stdio.h>
void main()
{
int n;
for (n=0; n<=100; n++) printf("%f\t", sqrt(n));
getch();
}
Przykład:
void main()
{
float y=0, n=0;
for (; (sqrt(n)-y)<=3.0; n++)
€€€€€{ y=sqrt(n);
€€€€€ printf("%f2.3\t", y);
- 125-
€€€€€}
getch();
}
UWAGA:
Sprawdź, czy nawias (sqrt(n)-y)<=3 można pominąć? Jaki jest
priorytet operatorów w wyrażeniach:
(sqrt(n)-y)<=3.0 i sqrt(n)-y<=3.0
Jaki będzie wynik? Dlaczego?
Przykład:
void main()
{
float SUMA=0, n=0;
for (; SUMA < 1000; SUMA+=(++n));
printf("%f", n);
getch();
}
flat a, b, c;
- 126-
const float d=1.2345;
void main()
{
for (a=5,b=3.14,c=10; c; ++a,b*=d,c--)
printf("\n%f\t%f\t%f", a,b,c);
getch();
}
if (c)...; i if (c != 0)...;
są w C++ równoważne.
Przykład:
void main()
{
for (; !kbhit(); printf("."));
}
Przykład:
[P030.CPP]
- 127-
# include "conio.h"
# include "dos.h"
# include "math.h"
# include "stdio.h"
char TABL[27]={"zsxdcvgbhnjm,ZSXDCVGBHNJM<"};
char k;
float D[26];
int i;
void main()
{
clrscr();
printf("[A]- KONIEC, dostepne klawisze: \n");
printf(" ZSXDCVGBHNJM,i [Shift]");
D[0]=200.0;
for(i=1; i<26; i++) D[i]=D[i-1]*1.0577;
for (;;) //patrz przyklad {*}
{
k = getch();
for(i=0; i<27; i++)
{ if (k==TABL[i])
{ sound(D[i]); delay(100); nosound(); }
};
if (k=='a'|| k=='A') break; //Wyjście z pętli.
k = '0';
};
}
[P031.CPP]
/* Inicjowanie tablicy przy pomocy stałej */
# include <iostream.h>
main()
{
const int wymiar = 7; //Deklaracja stałej
char TAB[wymiar]; //Deklaracja tablicy
- 128-
cout << "\n Wielkosc tablicy TAB[] wynosi: " << sizeof TAB;
cout << " bajtow.";
return 0;
}
DANE PREDEFINIOWANE.
Pętlę typu while stosuje się na ogół "do skutku", tj. do momentu
Przykład
void main()
{
while (!kbhit()) printf(".");
}
Przykład
- 129-
void main(){
float SUMA=0, n=0;
clrscr();
while (SUMA<1000) SUMA+=(++n);
printf("SUMA: %4.0f ostatnia liczba: %3.0f",
SUMA, n);
getch();
}
[P032.CPP]
void main(){
clrscr();
while (*Pointer1)
printf("%c", *Pointer1++);
printf("\nZobacz ten NUL na koncu lancucha znakow\n");
while (*Pointer2)
printf("%c", *Pointer2++);
printf("%d", *Pointer2);
getch();
}
PĘTLA do...while.
Przykład:
void main()
{
do
{printf(".");}
while (!kbhit());
printf("Koniec petli....");
}
- 130-
if (Wyrażenie) Instrukcja;
if (Wyrażenie) Instrukcja1 else Instrukcja2;
Przykład:
void main()
{
float a;
scanf("%f", &a);
if (a<0) printf("Ujemna!");
€€€€€else if (a==0) printf("Zero!");
€€€€€€€€€€else printf("Dodatnia!");
}
Przykład:
inaczej:
Przykład:
inaczej:
- 131-
Przykład:
float a, sigma=0;
void main(){
for (;;)
{
printf("\n Podaj liczbe do sumowania\n");
scanf("%f", &a);
if (a==0) break;
sigma+=a;
printf("\n SUMA: %f",sigma);
}
printf("Nastapil BREAK");
getch();
}
Instrukcja continue.
Przykład:
float a, sigma=0;
void main()
{
for (;;)
{
printf("\n Sumuje tylko liczby dodatnie\n");
scanf("%f", &a);
if (a<0) continue;
if (a==0) break;
sigma+=a;
printf("\n SUMA: %f",sigma);
}
printf("Nastapil BREAK");
getch();
}
- 132-
przypadków - wariantów (case). Każdy wariant jest oznaczony przy
switch (selector)
{
case STAŁA1: Ciąg_instrukcji-wariant 1;
case STAŁA2: Ciąg_instrukcji-wariant 2;
...............................
case STAŁAn: Ciąg_instrukcji-wariant n;
default : Ostatni_ciąg_instrukcji;
}
[P033.CPP]
[P034.CPP]
void main()
{
int Numer_Dnia;
pisz("\nPodaj numer dnia tygodnia\n");
scanf("%d", &Numer_Dnia);
switch(Numer_Dnia)
- 133-
{
case 1: pisz("PON."); break;
case 2: pisz("WTOR"); break;
case 3: pisz("SRO."); break;
case 4: pisz("CZW."); break;
case 5: pisz("PIO."); break;
case 6: pisz("SOB."); break;
case 7: pisz("NIEDZ."); break;
default: pisz("\n ?????");
}
}
return;
return stała;
return Wyrażenie;
return (wyrażenie);
Przykład:
float _dodaj(float x)
{
x+=5;
return x;
}
[P035.CPP]
float funkcja_dodaj(float x)
{
x += 5;
return x;
}
float dana = 1, wynik = 0;
void main()
{
clrscr();
wynik = funkcja_dodaj(dana);
- 134-
printf("%f", wynik);
}
goto Identyfikator_etykiety;
Przykład:
[P036.CPP]
#include <dos.h>
#include <stdio.h>
void main()
{
int czestotliwosc=5000, n=10, milisekundy=990;
printf("\n");
start:
{
sound(czestotliwosc);
delay(milisekundy);
nosound();
czestotliwosc/=1.2;
printf("%d\b", --n);
if (n) goto start; //petle strukturalne zrob sam(a)
}
koniec: ;
} // Tu jest instrukcja pusta.
[Z]
________________________________________________________________
1. Biorąc pod uwagę, że iloraz częstotliwości kolejnych dźwięków
- 135-
podwojenie częstotliwości, opracuj program i oblicz
częstotliwości poszczególnych dźwięków.
2. Spróbuj zastosować w programie przykładowym kolejno pętle
for, while, do...while.
3. Zastosuj we własnym programie doświadczalnym instrukcję
switch.
- 136-
LEKCJA 14. Jak tworzyć i stosować struktury.
________________________________________________________________
- 137-
programie więcej zmiennych jako zmienne rejestrowe - zostaną one
Przykład:
register int i;
.....
for (i=1; i<1000; i++) {.....}
programu.
STRUKTURY.
struct Ludzie
{
char Imiona[30];
char Nazwisko[20];
- 138-
int wiek;
char pokrewienstwo[10]
};
struct Ludzie
{ char pokrewienstwo[10];
char Imiona[30];
int wiek;
} Moi, Twoi, Szwagra;
Struktury statyczne
struct Ludzie
{ char pokrewienstwo[10];
char Imiona[30];
int wiek;
};
Zapis
oznacza:
statyczna struktura typu "Ludzie" pod nazwą "Szwagra".
- 139-
C4.Wiek=Czlowiek2.Wiek; - przekazanie zawartości pojedynczego
pola numerycznego;
C4=Czlowiek3; - przekazanie zawartości całej struktury Czlowiek3
do C4.
[P037.CPP]
int main()
{
struct Ludzie
{
char Imie[20];
int Wiek;
char Status[30];
char Tel_Nr[10];
};
C4=Czlowiek3;
C4.Wiek=Czlowiek2.Wiek;
C5=Czlowiek1;
clrscr();
return 0;
}
int TABLICA[10];
struct TABLICA[50];
- 140-
* deklarację jednowymiarowej tablicy LISTA[50],
* elementami tablicy są struktury typu SCzlowiek,
* jednym z elementów każdej struktury SCzlowiek jest struktura
"niższego rzędu" typu Adres;
[P038.CPP]
int main()
{
struct Adres
{
char Ulica[30];
int Nr_Domu;
int Nr_Mieszk;
};
struct SCzlowiek
{
char Imie[20];
int Wiek;
struct Adres Mieszkanie;
};
LISTA[1].Wiek=34;
LISTA[1].Mieszkanie.Nr_Domu=29;
printf("%d", LISTA[1].Mieszkanie.Nr_Domu);
return 0;
}
Zapis
printf("%d", LISTA[1].Mieszkanie.Nr_Domu
oznacza:
* wybierz element nr 1 z tablicy LISTA;
(jak wynika z deklaracji tablicy, każdy jej element będzie miał
wewnętrzną strukturę zorganizowaną tak, jak opisano w deklaracji
struktury SCzlowiek);
* wybierz ze struktury typu SCzlowiek pole Mieszkanie;
(jak wynika z deklaracji, pole Mieszkanie będzie miało
wewnętrzną organizację zgodną ze strukturą Adres);
* ze struktury typu Adres wybierz pole Nr_Domu;
* Wydrukuj zawartość pola pamięci interpretując ją jako liczbę
typu int - w formacie %d.
- 141-
[???] A CO Z ŁAŃCUCHAMI ZNAKOWYMI ?
________________________________________________________________
Język C++ oferuje do kopiowania łańcuchów znakowych specjalną
funkcję strcpy(). Nazwa funkcji to skrót STRing CoPY (kopiuj
łańcuch). Sposób wykorzystania tej funkcji:
STRUKTURY I WSKAŹNIKI.
[P039.CPP]
int main()
{
struct
{
char Tekst[20];
int Liczba1;
float Liczba2;
} STA, STB, STC, *Pointer;
STA.Liczba1 = 1;
STA.Liczba2 = 2.2;
strcpy(STA.Tekst, "To jest tekst");
STB=STA;
Pointer = &STC;
Pointer->Liczba1 = 1;
Pointer->Liczba2 = 2.2;
strcpy(Pointer->Tekst, STA.Tekst);
return 0;
}
- 142-
Rozszyfrujmy zapis:
strcpy(Pointer->Tekst, STA.Tekst);
Ciekawostka:
________________________________________________________________
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
POLA BITOWE.
- 143-
(czyli takie jak w przykładzie poniżej). Jeśli jakieś dane
chcemy przechowywać w postaci pola bitowego, w deklaracji
struktury sygnalizujemy to dwukropkiem. Stwarza to dwie istotne
możliwości:
* bardziej ekonomicznego wykorzystania pamięci;
* łatwego dodatkowego zaszyfrowania danych.
[P040.CPP]
int main()
{
struct USC {
int Sex : 1;
unsigned Wiek : 8;
unsigned Dzieci : 4;
unsigned Ktora : 3; } Facet;
int bufor;
clrscr();
Facet.Sex = 0;
printf("\n Ile ma lat ? : ");
scanf("%d", &bufor); Facet.Wiek = bufor;
printf("\n Ktore malzenstwo ? : ");
scanf("%d", &bufor); Facet.Ktora = bufor;
printf("\n Ile dzieci ? : ");
scanf("%d", &bufor); Facet.Dzieci = bufor;
printf("\n\n");
if (Facet.Ktora) printf("Facet ma %d zone", Facet.Ktora);
printf("\nPlec: Dzieci: Wiek (lat): \n\n");
printf("%d\t%d\t%d", Facet.Sex, Facet.Dzieci, Facet.Wiek);
getch();
return 0;
}
- 144-
struct
{
unsigned pole_I:4;
unsigned pole_II:10;
unsigned pole_III:4;
unsigned :0; /* to jest pole puste */
unsigned pole_IV:5;
} pole_przykladowe;
[P041.CPP]
#include "string.h"
#include "stdio.h"
int BUFOR, i;
int main()
{
union
{
int Cyfra;
char Napis[20];
} Unia;
- 145-
printf(" %d\t\t\t%s", Unia.Cyfra, Unia.Napis);
}
return 0;
}
[Z]
________________________________________________________________
1. W programie przykładowym zamień unię na strukturę. Porównaj
działanie.
2 Przydziel na Wiek w strukturze Facet o jeden bit mniej. Ile
lat może teraz mieć Facet ?
3. Zmodyfikuj program przykładowy tak, by napis o liczbie
mężów/żon zależał od płci - pola Sex.
4. Zamieniwszy unię na strukturę w programie, sprawdź, czy
wpływa to na wielkość pliku *.EXE.
________________________________________________________________
OPERACJE LOGICZNE.
- 146-
LEKCJA 15. Jak posługiwać się funkcjami.
________________________________________________________________
[P042.CPP]
# include <stdio.h>
int Demo(int Liczba)
{
int MaxNr=15;
for (; MaxNr>=0; MaxNr--)
if ((Liczba>>MaxNr)&1) printf("1");
else printf("0");
return 0;
}
char odp;
int main()
{
int X, Y;
clrscr();
printf("\nPodaj dwie liczby calkowite od -32768 do +32767\n");
printf("\nLiczby X i Y rozdziel spacja");
printf("\nPo podaniu drugiej liczby nacisnij [Enter]");
printf("\nLiczby ujemne sa w kodzie dopelniajacym");
printf("\nskrajny lewy bit oznacza znak 0-Plus, 1-Minus");
- 147-
for(;;)
{
printf("\n");
scanf("%d %d", &X, &Y);
printf("\nX:\t"); Demo(X);
printf("\nY:\t"); Demo(Y);
printf("\n~Y:\t"); Demo(~Y);
printf("\nX&Y:\t"); Demo(X&Y);
printf("\nX|Y:\t"); Demo(X|Y);
printf("\nX^Y:\t"); Demo(X^Y);
printf("\nY:\t"); Demo(Y);
printf("\nY>>1:\t"); Demo(Y>>1);
printf("\nY<<2:\t"); Demo(Y<<2);
printf("\n\n Jeszcze raz? T/N");
odp=getch();
if (odp!='T'&& odp!='t') break;
}
return 0;
}
Przykłady:
Porównaj:
if (a<=0) ...
if (a) ...
if (a+b) ...
Konwersja - przykłady.
- 148-
np:
p1 - liczby do przekształcenia;
p2 - bufora, w którym będą przechowywać wynik - łańcuch ASCII;
p3 - podstawy (szesnastkowa, dziesiętna itp.).
[P043.CPP]
# include "stdio.h"
# include "stdlib.h"
main()
{
int i;
char B10[10], B2[20], B16[10]; //BUFORY
for (i=1; i<17; i++)
printf("%s %s %s\n",
itoa(i, B10[i], 10),
itoa(i, B2[i], 2),
itoa(i, B16[i], 16));
return 0;
}
[Z]
________________________________________________________________
1. Opracuj program testujący działanie funkcji atoi().
________________________________________________________________
Po pierwsze:
- 149-
rodzaju typu zmiennej "bardziej pojemnego" rodzaju przed
wykonaniem operacji;
Po drugie:
[P044.CPP]
# include "stdio.h"
void main()
{
int a=7;
printf("%f", (float) a);
}
int a = 2;
float x = 17.1, y = 8.95, z;
char c;
c = (char)a + (char)x;
c = (char)(a + (int)x);
c = (char)(a + x);
c = a + x;
z = (float)((int)x * (int)y);
z = (float)((int)x * (int)y);
z = (float)((int)(x * y));
z = x * y;
c = char(a) + char(x);
c = char(a + int(x));
c = char(a + x);
c = a + x;
z = float(int(x) * int(y));
z = float(int(x) * int(y));
z = float(int(x * y));
z = x * y;
- 150-
cos() - cosinus, sin() - sinus, tan() - tangens,
asin(), atan(), acos(), - funkcje odwrotne ARCUS SINUS...
funkcje hiperboliczne: sinh(), cosh(), tanh(),
wykładnicze i logarytmiczne:
exp() - e^x
log() - logarytm naturalny,
log10() - logarytm dziesiętny.
int F_Trzynascie()
{
return 13;
}
int main()
{
......
int X;
........ // Funkcja typu int nie musi byc deklarowana.
X = F_Trzynascie();
......
}
Przykład:
int main()
- 151-
{
int Podstawa, Wynik, a, b;
... /* Funkcja nie jest deklarowana przed uzyciem */
Wynik = F_XdoPiatej(Podstawa);
.....
a = F_XdoPiatej(b);
.....
return 0;
}
[P045.CPP]
main()
{
double a, b;
double sqrt(); // tu skasuj deklaracje funkcji sqrt()
// a otrzymasz bledny wynik !
clrscr();
printf("Podaj liczbe\n");
scanf("%lf", &a);
b = sqrt(a);
printf("\n %Lf", (long double) b);
getch();
return 0;
}
main()
{
double A=0, B=3.14;
printf("Wynik działania funkcji: \n");
printf("%lf", FUNKCJA(A,B));
- 152-
return 0; }
void main()
[P046.CPP]
#include <stdio.h>
#include <conio.h>
void main()
{
clrscr();
RYSUJPROSTOKAT(5, 20, '€'); // klocek ASCII 176 - [Alt]-[176]
getch();
RYSUJPROSTOKAT(15, 15, '€'); //[Alt]-[177]
getch();
}
- 153-
int i, j; // automatyczne zmienne wewnętrzne funkcji
for(i=1; i<=Wys; i++)
{
for(j=1; j<=Szer; j++) printf("%c",Wzorek);
printf("\n");
}
}
Skutek praktyczny:
JEŚLI DOŁĄCZYSZ DO PROGRAMU STOSOWNE PLIKI NAGŁÓWKOWE *.h,możesz
#include <math.h>
#include <stdio.h>
#include <math.h>
main()
{
double a, b;
clrscr();
printf("Podaj liczbe\n");
scanf("%lf", &a);
b = sqrt(a);
printf("\n %Lf", (long double) b);
getch();
return 0;
}
void main()
- 154-
{
int Zmienna; //Zmienna funkcji main, rzeczywisty argument
clrscr();
Zmienna = 7;
[P047.CPP]
int Zmienna;
void main()
{
clrscr();
printf("Stadium: \tZmienna Argument");
printf("\nStadium 1\t%d\tnie istnieje\n", Zmienna);
Zmienna = 7;
printf("Stadium 2\t%d\tnie istnieje\n", Zmienna );
FUNKCJA( Zmienna);
printf("Stadium 3\t%d", Zmienna);
// printf("%d", Argument);
// taka proba sie NIE UDA !
getch();
}
- 155-
to, że POZA FUNKCJĄ zmienna Argument NIE ISTNIEJE. Jest tworzona
[P048.CPP]
- 156-
W linii /* DZIALANIE */ mnożymy i dodajemy to, co wskazuje
wskaźnik, czyli Zmienną. Funkcja działa zatem nie na własnej
kopii zmiennej a bezpośrednio na zmiennej zewnętrznej. Zwróć
uwagę na analogię w sposobie wywołania funkcji:
FUNKCJA( &Zmienna );
scanf( "%d", &Zmienna );
[P049.CPP]
# include <conio.h>
# include <stdio.h>
main()
{
clrscr();
do
{
printf("\n Ile wyrazow tablicy dodac ??? \n");
scanf("%d", &N);
if (N>10)
{ printf("TO ZA DUZO ! - max. 10");
continue;
}
suma = SUMA( N,TAB );
printf("\nTO JEST suma z progr. glownego %d", suma);
printf("\n Jeszcze raz ? T/N");
Odp = getch();
}
while (Odp!='N' && Odp!='n');
return 0;
}
- 157-
definicja funkcji może być zarówno na początku jak i na końcu.
[P050.CPP]
main()
{
clrscr();
Wypelniacz( TAB_1D, 'X', 41); //Wypelnia X-ami
printf("%s\n\n", TAB_1D);
for (k=0; k<5; k++) Wypelniacz( TAB2D[k], 65+k, 9);
//ASCII 65 to 'A'; 66 to 'B' itd.
{
int i;
for ( i=0; i<=(Dlugosc-1); i++) *(BUFOR+i) = Znak;
*(BUFOR+Dlugosc) = '\0';
}
- 158-
[P051.CPP]
int BALAGAN[10];
int PORZADEK[10]; // Tablica koncowa - uporzadkowana
int k, *pointer , MAX=10000 ;
main()
{
clrscr();
printf("Podaj 10 liczb calkowitych od -10000 do 10000\n");
for (k=0; k<=9; k++) scanf("%d", &BALAGAN[k]);
printf("Po kolei: \n\n");
for ( k=0; k<=9; k++ )
{
€€€€€pointer=Minimum(10, BALAGAN);
€€€€€PORZADEK[k]=*pointer;
€€€€€*pointer=MAX;
}
for(k=0; k<=9; k++) printf("%d ", PORZADEK[k]);
getch();
return 0;
}
WSKAŹNIKI DO FUNKCJI.
należy rozumieć:
"Przy pomocy wskaźnika do funkcji *FUNKCJA wolno nam wskazać
- 159-
takie funkcje, które
* pobierają jeden argument typu double float;
* zwracają do programu wartość typu double float. "
Dostępne są dla nas zatem wszystkie standardowe funkcje
arytmetyczne z pliku MATH.H (MATH pochodzi od MATHematics -
matematyka.)
[P052.CPP]
# include <conio.h>
# include <math.h>
double NASZA( double ); //Deklaracja zwyklej funkcji
main()
{
clrscr();
printf("Podaj Liczbe \n");
scanf("%lf", &Liczba);
printf("CO MAM ZROBIC ?\n");
printf("1 - Sinus \n");
printf("2 - Pierwiastek\n");
printf("3 - Odwrotnosc 1/x\n");
scanf("%d", &WYBOR);
switch(WYBOR)
{
case 1: Funkcja=sin; break;
case 2: Funkcja=sqrt; break;
case 3: Funkcja=NASZA; break;
}
Wynik=Funkcja(Liczba); // Wywolanie wybranej funkcji
printf("\n\nWYNIK = %lf", Wynik);
getch();
return 0;
}
double NASZA(double a)
{
printf("\n A TO NASZA PRYWATNA FUNKCJA\n");
if (a!=0) a=1/a; else printf("???\n");
return a;
}
- 160-
choćby, opisu pomijanego dyskretnie do tej pory problemu
PRZEKAZANIA PARAMETRÓW DO PROGRAMU.
lub tak:
- 161-
[P053.CPP]
# include "stdio.h"
# include "stdlib.h"
main(char *env[])
[Z]
________________________________________________________________
1. Spróbuj tak zmodyfikować funkcję Demo(), by liczba w formie
dwójkowej była pisana "od tyłu". Do cofania kursora w funkcji
printf użyj sekwencji \b\b.
2. Zinterpretuj zapis:
if (MIANOWNIK) printf("%f", 1/MIANOWNIK); else exit(1);
- 162-
3 Spróbuj przeprowadzić rzutowanie typu we własnym programie.
- 163-
LEKCJA 16. ASEMBLER TASM i BASM.
________________________________________________________________
W trakcie tej lekcji:
* dowiesz się , jak łączyć C++ z assemblerem
* poznasz wewnętrzne formaty danych
________________________________________________________________
# pragma inline
void main()
{
asm mov dl, 81
asm mov ah, 2
asm int 33
}
void main()
{
char *NAPIS = "tekst - test$"; /* $ - ozn. koniec */
- 164-
Umieściliśmy w pamięci łańcuch, będący w istocie tablicą
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
[P054.CPP]
# pragma inline
void main()
{
char *NAPIS = "\n tekst - test $";
asm {
MOV DX, NAPIS
MOV AH, 9
INT 33
}
}
[P055.ASM]
- 165-
napisana w C++, aby inne fragmenty programu mogły się do tych
danych odwoływać. Możemy we wstawce asemblerowskiej odwoływać
się do tych danych w taki sposób, jakgdyby zostały zadeklarowane
[P056.CPP]
#pragma inline
void main()
{
char *napis = "\nRazem warzyw: $";
int marchewki = 2, pietruszki = 5;
asm {
MOV DX, napis
MOV AH, 9
INT 33
MOV DX, marchewki
ADD DX, pietruszki
ADD DX, '0'
MOV AH, 2
INT 33
}
}
Razem warzyw: 7
- 166-
ADD DX, '0' ;Dodaj kod ASCII "zera" do rejestru
ADD DX, 48
[P057.CPP]
#pragma inline
void main()
{
const char *napis = "\nRazem warzyw: $";
char marchewki = 2, pietruszki = 5;
asm {
MOV DX, napis
MOV AH, 9
INT 33
MOV DL, marchewki
ADD DL, pietruszki
ADD DL, '0'
MOV AH, 2
INT 33
}
}
long int x = 2;
- 167-
słowo zawiera interesującą nas informację, możemy wczytać to
słowo do rejestru rozkazem
MOV DX, X
[P058.CPP]
# pragma inline
void main()
{
unsigned long marchewki = 2, pietruszki = 5;
const char *napis = "\nRazem warzyw: $";
asm
{
MOV DX, napis
MOV AH, 9
INT 33
MOV DX, marchewki
ADD DX, pietruszki
ADD DX, '0'
MOV AH, 2
INT 33
}
}
czy też bez decyduje wyłącznie to, czy zwracamy uwagę na ten
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
traktowaliśmy go, jako najstarszy bit nie przydając mu poza tym
żadnego szczególnego znaczenia. Aby liczba stała się liczbą ze
znakiem - to my musimy zacząć ją traktować jako liczbę ze
znakiem, czyli zacząć zwracać uwagę na ten pierwszy bit.
Pierwszy, najstarszy bit liczby ustawiony do stanu 1 będzie
oznaczać, że liczba jest ujemna - jeśli zechcemy ją potraktować
jako liczbę ze znakiem.
(-1) + 1 = 0
- 168-
stanie się 0. Czy można jednakże wyobrazić sobie np.
jednobajtową liczbę dwójkową, która po dodaniu 1 da nam w
rezultacie 0 ? Wydawałoby się, że w dowolnym przypadku wynik
powinien być conajmniej równy 1.
asemblera z C++:
[P059.CPP]
#pragma inline
void main()
{
const char *napis = "\nRazem warzyw: $";
int marchewki = -2, pietruszki = 5;
asm {
MOV DX, napis
MOV AH, 9
- 169-
INT 33
MOV DX, marchewki
NEG DX
ADD DX, pietruszki
ADD DX, '0'
MOV AH, 2
INT 33
}
}
[P060.CPP]
# include "iostream.h"
# pragma inline
char odp;
char *p = "\nLiczby rozdziel spacja $";
int main()
{
int x, y;
asm {
mov dx, p
mov ah, 9
int 33
}
cout << "\nPo podaniu drugiej liczby nacisnij [Enter]";
cout << "\nLiczby ujemne sa w kodzie dopelniajacym";
cout << "\nSkrajny lewy bit oznacza znak 0-Plus, 1-Minus";
for(;;)
{
cout << "\n";
- 170-
cin >> x >> y;
cout << "\nX: "; demo(x);
cout << "\t\tY: "; demo(y);
cout << "\n~X: "; demo(~x);
cout << "\t\t~Y: "; demo(~y);
cout << "\nX & Y: "; demo(x & y);
cout << "\nX | Y: "; demo(x | y);
cout << "\nX ^ Y: "; demo(x ^ y);
cout << "\n Y: "; demo(y);
cout << "\nY >> 1: "; demo(y >> 1);
cout << "\nY << 2: "; demo(y << 2);
[P061.CPP]
#pragma inline
void main()
{
drukuj(); //Wywołanie funkcji drukuj()
}
- 171-
void drukuj(void) //Definicja funkcji
{
asm MOV DX, TEKST
asm MOV AH, 9
asm INT 33
}
Funkcja może oczywiście nie tylko zgłosić się napisem, ale także
[P062.CPP]
# pragma inline
void main()
{
czysc_bufor(); //Czyszczenie bufora klawiatury
}
- 172-
"pozostawia" argumenty przeznaczone dla funkcji przed jej
wywołaniem? W Tabeli poniżej przedstawiono w skrócie "konwencję
wywoływania funkcji" (ang. Function Calling Convention) języka
C++.
# pragma inline
void wyswietl(char, char); //Prototyp funkcji
void main()
{
wyswietl('A', 'B'); //Wywolanie funkcji
}
PUSH 'B'
PUSH 'A'
- 173-
Funkcja wyswietl() musi uzyskać dostęp do przekazanych jej
argumentówów. Odwołamy się do zmiennych C++ w taki sposób, jak
robiłaby to każda inna funkcja w C++:
[P063.CPP]
# pragma inline
void wyswietl(char, char); //Prototyp funkcji
void main()
{
_AH = 2; //BEEEEE !
wyswietl('A', 'B'); //Wywolanie funkcji
}
- 174-
LEKCJA 17. TROCHĘ SZCZEGÓLÓW TECHNICZNYCH.
________________________________________________________________
W trakcie tej lekcji dowiesz się więcej o szczegółach działania
komputera widzianych z poziomu assemblera.
________________________________________________________________
# include <....
....
# pragma inline
void main()
{
float liczba = 3.5;
....
- 175-
dziesiętnych. Przesunięcie przecinka powoduje, że 12345.67 =
1.234567 * 10^4. Aby wróciła do swojej starej "zwykłej" postaci
(jest to tzw. "rozwinięcie" liczby - ang. expand) należy
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
zmiennoprzecinkowej liczbie dwójkowej pierwszą cyfrą jest zawsze
Dla liczb typu float offset wykładnika wynosi +127 a dla liczb
double float +1023. Wrócmy do naszej przykładowej liczby. Jeśli
nasza liczba 3.5 = 11.1(B) ma być zapisana w postaci
zmiennoprzecinkowej - float, zapisany w pamięci wykładnik potęgi
wyniesie:
znak liczby -0
wykładnik potęgi - 1000 0000
cyfry znaczące liczby - 110000000....
do 32 bity zerami:
- 176-
postaci 00 00 60 40.
tak:
# include <.....
# pragma inline
void funkcja(long int) //Prototyp funkcji
main()
{
long liczba = 0xABCDCDEF; //Deklaracja argumentu
.....
funkcja(liczba); //Wywołanie w programie
....
}
funkcja(long int x)
{
int x1starsze, x2mlodsze; //Wewnętrzne zmienne pomocnicze
x2mlodsze = (int) x;
x >> 16;
x1starsze = (int) x;
_DX = x1starsze;
_BX = x2mlodsze;
asm {
...... //Tu funkcja już może działać
- 177-
zwrócić jakąś wartość do programu.
zwróci wynik typu int (return (_AX)). Dla modelu pamięci small
będzie to wyglądać tak:
[P064.CPP]
# include <iostream.h>
# pragma inline
int funkcja(int, int); //Prototyp funkcji
void main()
{
cout << "\nWynik 7 - 8 = " << funkcja(7, 8);
}
- 178-
}
return (_AX); //Zwróć zawartość rejestru AX
}
[P065.CPP]
[MODUL.ASM]
.MODEL SMALL
.DATA
EXTRN _Flaga:WORD
.CODE
PUBLIC _UstawFlage
_UstawFlage PROC
CMP [_Flaga], 0
JNZ SKASUJ_Flage
MOV [_Flaga], 1
JMP SHORT KONIEC
SKASUJ_Flage: MOV [_Flaga], 0
KONIEC:
RET
_UstawFlage ENDP
END
- 179-
PROGRAM.CPP --> PROGRAM.OBJ
MODUL.ASM --> MODUL.OBJ
TLINK PROGRAM.OBJ MODUL.OBJ --> PROGRAM.EXE
asm {
POP AX; POP DX; POP DS
IRET
}
asm {
MOV DX, 1 ;TAK NIE MOŻNA W BASM !
...
asm {
ADD AX, BX; /* Taki komentarz może być */
- 180-
hex) wykorzystuje DOS i Basic.
UWAGA:
Wektor zapisywany jest w pamięci w odwrotnej kolejności:
C:\DOS\DEBUG
-D 0:0
-d 0:0
0000:0000 FB 91 32 00 F4 06 70 00-78 F8 00 F0 F4 06 70 00
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
0000:0030 23 FF 00 F0 CE 02 00 C8-57 EF 00 F0 F4 06 70 00
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
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
jest obsługiwane.
- 181-
-u 32:91FB
0032:9211 07 POP ES
0032:9212 ˙˙˙˙˙˙˙˙˙˙˙16 ˙˙˙˙˙˙˙˙˙˙˙PUSH ˙˙˙˙˙˙˙˙˙˙˙SS
0032:9213 1F POP DS
0032:9214 C606940308 MOV BYTE PTR [0394],08
0032:9219 C606920316 MOV BYTE PTR [0392],16
zadeklarować ją tak:
# define us unsigned
# include <iostram.h>
- 182-
# include <dos.h>
void main()
{
.....
}
....
stare_bity = inportb(0x61);
- 183-
cout << "\nInstaluje wektor" << numer_wektora << "\n";
setvect(numer_wektora, adres);
}
# include <...
...
void main()
{
Instaluj(Piszczek, 10);
Start(5, 10);
}
- 184-
SI -> 0...31 ESI w tym (SI = 0..15)
DI -> 0...31 EDI w tym (DI = 0..15)
BP -> 0...31 EBP w tym (BP = 0..15)
SP -> 0...31 ESP w tym (SP = 0..15)
IP -> 0...31 EIP w tym (IP = 0..15)
FLAGS -> 0...31 EFLAGS w tym (FLAGS = 0..15)
.386
...
MOV EAX, 1 ;zapisz 1 do rejestru EAX
SUB EBX, EBX ;wyzeruj rejestr EBX
ADD EBX, EAX ;dodaj (EAX)+(EBX) --> EBX
.386
...
MOV AX, Liczba_16_bitowa
ROR EDX, 16
MOV AX, DX
ROR EDX, 16
... itp.
- 185-
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
stałoprzecinkowe).
- 186-
LEKCJA 18. O ŁAŃCUCHACH TEKSTOWYCH
________________________________________________________________
W trakcie tej lekcji dowiesz się,
* jak manipulować łańcuchami tekstowymi i poznasz kilka
specjalnych funkcji, które służą w C++ właśnie do takich celów;
* jak wykonują się operacje plikowo-dyskowe.
________________________________________________________________
char tekst1[40];
char napis[1];
char znak;
- 187-
________________________________________________________________
ŁĄCZENIE TEKSTÓW.
- 188-
funkcję:
strcat(napis1, napis2);
[P066.CPP]
#include <conio.h>
#include <iostream.h>
#include <string.h> //W tym pliku jest prototyp strcat()
int main(void)
{
char imie[50], nazwisko[30];
clrscr();
cout << "Podaj imie: ";
cin >> imie;
- 189-
strcat(imie, nazwisko); <-- po dołączonej spacji dodaj
drugi tekst - nazwisko
"Nie ważne, czy Polska będzie bogata, czy biedna - ważne, żeby
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
(oczywiście za ich pieniądze, z ich podatków), niż zarabiać na
chleb własną pracą."
char napis[0] = 0;
char *p = "";
char napis[50] = "";
________________________________________________________________
- 190-
łańcucha pozwala mieć pewność, że tablica nie zawiera jakichś
starych, zbędnych danych.
[P067.CPP]
#include <conio.h>
#include <iostream.h>
#include <string.h>
- 191-
main()
{
char imie[50], nazwisko[20];
int dlugosc;
clrscr();
cout << "Podaj imie: ";
cin >> imie;
cout << "Podaj nazwisko: ";
cin >> nazwisko;
strcat(imie, " ");
strcat(imie, nazwisko);
cout << "\nNazywasz sie: " << imie << '\n';
dlugosc = strlen(imie);
cout<<"Imie i nazwisko sklada sie z: "<<dlugosc<<"znakow\n";
cout << "Nacisnij dowolny klawisz";
getch();
return 0;
}
cout << "Wszystkich znakow bylo: " << strlen(imie) << '\n';
- 192-
W tym przykładzie wywołujemy funkcję strncpy() przekazując jej
przy wywołaniu trzy argumenty:
strcpy(string1, string2);
string2 = "BABCIA";
[P068.CPP]
#include <conio.h>
#include <iostream.h>
#include <string.h>
#include <stdio.h>
main()
{
- 193-
char napis1[80] = "";
char napis2[80] = "";
char napis3[80] = "";
clrscr();
cout << "Wpisz jakis tekst: ";
gets(napis1);
strcpy(napis2, napis1);
strncpy(napis3, napis1, 3);
niemniej, nawet jeśli program się nie zawiesza, nie oznacza to,
że wyniki działania przy bezsensownych danych wejściowych będą
mieć jakikolwiek sens. Jako programista powinieneś wystrzegać
się takich błędów (dane z poza zakresu, dane bez sensu
merytorycznego) nie licząc na to, że C++ jakoś z tego wybrnie.
________________________________________________________________
- 194-
wprowadzać napisów zawierających spacje. Jeśli zastosowalibyśmy
w programie
WYSZUKIWANIE TEKSTÓW.
dysponuje funkcją:
- 195-
wskazujący nam - gdzie w pamięci kmputera znajduje się
interesujący nas tekst "Alfons\0".
char *wskaznik;
[P069.CPP]
#include <conio.h>
#include <iostream.h>
#include <string.h>
main()
{
char string1[] = "Ala, Magda, Adam, Alfons, Jasiek, Alfons, As";
char *pointer;
clrscr();
cout << "Lista:\n" << string1;
getch();
return 0;
}
- 196-
wyszukanego pierwszego wystąpienia zadanego łańcucha znaków.
[P070.CPP]
#include <conio.h>
#include <iostream.h>
#include <string.h>
#include <stdio.h>
main()
{
char str1[80], str2[80];
char *ptr;
clrscr();
cout << "Wpisz tekst do przeszukania:\n ";
gets(str1);
[P071.CPP]
#include <conio.h>
#include <iostream.h>
#include <string.h>
#include <stdio.h>
main()
- 197-
{
char string1[80];
clrscr();
cout << "Wpisz tekst do zamiany:\n";
gets(string1);
- 198-
LEKCJA 19: KILKA INNYCH PRZYDATNYCH FUNKCJI.
________________________________________________________________
[P072.CPP]
#include <conio.h>
int main(void)
{
int i, x = 0, y = 0;
clrscr();
for (i = 1; i < 10; i++)
{
y = i;
x = 5*i;
textbackground(16-i);
textcolor(i);
gotoxy(x, y);
cprintf("Wspolrzedne: x=%d y=%d", x, y);
getch();
}
return 0;
}
[Z]
________________________________________________________________
1. Rozmieść na ekranie napisy i znaki semigraficzne tworzące
rysunek tabelki.
2. Opracuj program, w którym pojedyncze znaki, bądź napisy będą
poruszać się po ekranie.
3. Spróbuj przyspieszyć działanie swojego programu z
poprzedniego zadania poprzez wstawkę w assemblerze.
________________________________________________________________
- 199-
operacjami na plikach są:
FUNKCJE:
int open(p1, p2, p3) - trójparametrowa funkcja otwierająca plik;
[S] STD...
STandarD INput - standardowe wejście.
- 200-
STD OUTput - standardowe wyjście.
STD ERRors - plik diagnostyczny.
//[P072-2.CPP]
# include <stdio.h>
# include <conio.h>
# include <SYS\STAT.H> //Duze litery tylko dla podkreslenia
# include <FCNTL.H>
# include <IO.H>
char *POINTER;
int IL_znakow, DLUG_pliku, TRYB_dostepu, Wynik, i;
int Plik_1, Plik_2;
char BUFOR[20] = {"TEKST DO PLIKU"};
char STOS[3], ZNAK='X';
main()
{
POINTER = &BUFOR[0];
if (Plik_1 == -1)
printf("\n Nie udalo sie zalozyc plik1.dat...");
close( Plik_1 );
POINTER = &STOS[0];
- 201-
read( Plik_1, &ZNAK, 1);
}
close(Plik_1); close(Plik_2);
getch();
return 0;
}
początku pliku:
Funkcja lseek():
WSK_PLK = long int lseek( plik, o_ile, kierunek);
służy do pozycjonowania w pliku.
Liczba typu long int określająca pozycję w pliku nazywana jest
WSKAŹNIKIEM PLIKOWYM ( w programie przykładowym została
oznaczona long int WSK_PLK).
- 202-
* zamknięcie pliku;
* otwarcie pliku do odczytu;
* ustawienie wskaźnika na końcu pliku;
* odczyt z pliku od końca;
* wyprowadzenie odczytanych z pliku danych na ekran.
[P073.CPP]
# include "sys\stat.h"
# include "conio.h"
# include "stdio.h"
# include "io.h"
# include "fcntl.h"
# define Cofnij_o_Zero 0
# define dwa_bajty 2
int Numer = 0;
int Plik, L, M, i;
long int Dlug_Pliku;
main()
{
clrscr();
creat("A:\PROBA.DAT", S_IWRITE);
printf("\nPodaj liczbe rozna od zera, zero - KONIEC");
_fmode=O_BINARY;
Plik=open("A:\PROBA.DAT", O_WRONLY);
do
{
printf("\n Nr liczby \t%d\t\t", Numer++);
scanf("%d", &L);
if (L) write(Plik, &L, 2);
}
while (L != 0);
close(Plik);
getch();
return 0;
}
[Z]
________________________________________________________________
- 203-
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
tekstowych.
________________________________________________________________
- 204-
LEKCJA 20. JEŚLI PROGRAM POWINIEN URUCHOMIĆ INNY PROGRAM...
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak w C++ można programować
* procesy potomne
* pisać programy rezydujące w pamięci (TSR)
________________________________________________________________
O bloku PSP.
# include <stdio.h>
# include <dos.h>
main()
{
static char TAB[128];
char far *ptr;
- 205-
int dlugosc, i;
# include <process.h>
# include <stdio.h>
# include <errno.h>
printf("Parametry uruchomieniowe:");
for (i=0; i<argc; i++)
printf("\n%d) %s", i, argv[i]);
[P074.CPP]
# include <stdlib.h>
# include <stdio.h>
- 206-
void main()
{
printf("Wyjscie do DOS i wykonanie jednego rozkazu:\n");
system("dir > c:\plik.dir");
}
# include <process.h>
# include <stdio.h>
# include <conio.h>
void main()
{
int rezultat;
rezultat = spawnl(P_WAIT, "program.exe", NULL);
if (rezultat == -1)
{
perror(" Fiasko !");
exit(1);
}
}
/* Funkcja spawnle() */
# include <process.h>
# include <stdio.h>
# include <conio.h>
void main()
{
int rezultat;
- 207-
zakończyć program posługując się przerywaniem INT 39 (27 hex).
Jeśli natomiast zamierzamy posługiwać się dłuższymi programami,
mamy do dyspozycji funkcję systemową nr 49 (31 hex). Należy tu
zwrócić uwagę, że zakończenie programu w taki sposób (z
pozostawieniem w pamięci) nie spowoduje automatycznego
zamknięcia plików, a jedynie opróżnienie buforów. Programy
rezydentne dzieli się umownie na trzy kategorie:
# include "stdio.h"
# include "dos.h"
# include "conio.h"
void main()
{
/* Zapamiętaj poprzedni wektor przerywania 28 */
oldhandler = getvect(28);
- 208-
/* Inkrementuj licznik */
for (; licznik < 10; ) printf("licznik: %d\n",licznik);
setvect(28, oldhandler);
}
# include <stdio.h>
# include <dos.h>
int warunek = 1;
main()
{
printf("\n [Shift]+[Print Screen] = Quit \n");
printf("Zapamietaj, i nacisnij cosik....");
while(!kbhit());
01 - PRINT.EXE
06 - ASSIGN.COM
- 209-
16 - SHARE.EXE (10 hex)
26 - ANSI.SYS
67 - HIMEM.SYS
72 - DOSKEY.COM
75 - TASK SWITCHER
173 - KEYB.COM
174 - APPEND.EXE
176 - GRAFTABL.COM
183 - APPEND.EXE
# include <dos.h>
ekran = MK_FP(0xB800,0);
- 210-
licznik++;
licznik %= 10;
void main()
{
oldhandler = getvect(INTR);
struct BYTEREGS
{
unsigned int al, ah, bl, bh, cl, ch, dl, dh;
};
struct WORDREGS
{
unsigned int ax, bx, cx, dx, si, di, cflag, flags;
};
- 211-
struct SREGS
{
unsigned int es, cs, ss, ds;
};
union REGS
{
struct WORDREGS x;
struct BYTEREGS h;
};
# include <stdio.h>
# include <conio.h>
# include <dos.h>
void main()
{
clrscr();
UstawKursor(30, 12);
printf("Tekst - Test");
while(!kbhit());
}
# include <dos.h>
# include <process.h>
# include <stdio.h>
- 212-
void main()
{
char nazwapliku[40];
union REGS inregs, outregs;
struct SREGS segregs;
# include <stdio.h>
# include <dos.h>
int SkasujPlik(char far*) // Prototyp
void main()
{
int error;
err = SkasujPlik("PLIK.DAT");
if (!error) printf("\nSkasowalem plik PLIK.DAT");
else
printf("\nNie moge skasowac pliku PLIK.DAT");
}
1. Wywołanie funkcji:
AL = kod powrotu (ang. return code);
AH = 0031 (hex) - nr funkcji;
DX = długość programu TSR w paragrafach - Size/16 [Bajtów];
2. Działanie:
- 213-
* funkcja odtwarza wektory przerywań nr 34, 35, 36 (hex 21, 22,
23);
* proces macieżysty może uzyskać kod powrotu przy pomocy funkcji
nr 77 (4D hex).
- 214-
LEKCJA 21: KILKA PROCESÓW JEDNOCZEŚNIE.
________________________________________________________________
Procesy współbieżne.
Porozmawiajmy o narzędziach.
- 215-
wielu procesów (więcej niż dwa) stosuje się tablicę złożoną ze
struktur typu
typedef struct
{
unsigned j_sp, j_ss, j_flag, j_cs;
unsigned j_ip, j_bp, j_di, j_es;
unsigned j_si, j_ds;
} jmb_buf[1];
Prototypy funkcji:
...
void proces1(void);
void proces2(void);
int main(void)
{
clrscr();
- 216-
proces1();
proces2();
return 0;
}
#include <setjmp.h>
void proces1(void);
void proces2(void);
jmp_buf bufor1;
int main(void)
{
clrscr();
if(setjmp(bufor1) != 0) proces1(); //Powrót z procesu2 był?
proces2();
return 0;
}
if(setjmp(bufor1) != 0) ...
void proces2(void)
{
for(;;)
{
gotoxy(10,20);
printf("PROCES 2: ");
for(int i = 1; i<40; i++)
{
printf(".2\b");
delay(5); //UWAGA: delay() tylko dla DOS!
}
longjmp(bufor1, 1); <--- wróć
} ____________ tę jedynkę zwróci setjmp()
}
int main(void)
{
- 217-
clrscr();
if(setjmp(bufor1)) proces1(); <--- tu powrót
proces2();
return 0;
}
void proces1(void)
{
while(kbhit())
{
gotoxy(1,1);
printf("PROCES1, Pisz tekst: [Kropka - Koniec]");
gotoxy(pozycja,2);
znak = getch();
printf("%c", znak);
pozycja++;
}
if(znak == '.') exit (0);
}
[P075.CPP]
#include <stdio.h>
#include <process.h>
#include <setjmp.h>
#include <conio.h>
#include <dos.h>
void proces1(void);
void proces2(void);
char znak;
int pozycja = 1;
int main(void)
{
clrscr();
if(setjmp(bufor1)) proces1();
proces2();
return 0;
}
void proces1(void)
{
- 218-
while(kbhit())
{
gotoxy(1,1);
printf("PROCES1, Pisz tekst: [Kropka - Koniec]");
gotoxy(pozycja,2);
znak = getch();
printf("%c", znak);
pozycja++;
}
if(znak == '.') exit (0);
}
void proces2(void)
{
for(;;)
{
gotoxy(10,20);
printf("PROCES 2: ");
for(int i = 1; i<40; i++)
{
printf(".1\b");
delay(5);
}
longjmp(bufor1,1);
}
}
[!!!] UWAGA
________________________________________________________________
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ę
funkcję poprzedzić znakiem komentzrza // .
________________________________________________________________
[P076.CPP]
#include <stdio.h>
#include <process.h>
#include <setjmp.h>
#include <conio.h>
#include <dos.h>
void proces1(void);
void proces2(void);
void proces3(void);
- 219-
char znak;
int pozycja = 1;
int main(void)
{
clrscr();
if(setjmp(bufor1)) proces1();
if(setjmp(bufor2)) proces2();
proces3();
return 0;
}
void proces1(void)
{
while(kbhit())
{
gotoxy(1,1);
printf("PROCES1, Pisz tekst: [Kropka - Koniec]");
gotoxy(pozycja,2);
znak = getch();
printf("%c", znak);
pozycja++;
}
if(znak == '.') exit (0);
}
void proces2(void)
{
for(;;)
{
gotoxy(10,20);
printf("PROCES 2: ");
for(int i = 1; i<40; i++)
{
printf(".2\b");
delay(5);
}
longjmp(bufor1, 1);
}
}
void proces3(void)
{
for(;;)
{
gotoxy(10,23);
printf("PROCES 3: ");
for(int i = 1; i<40; i++)
{
printf(".3\b");
delay(2);
}
- 220-
longjmp(bufor2,2);
}
}
- proces3()
- proces2()
- proces1()
[P077.CPP]
#include <stdio.h>
#include <process.h>
#include <setjmp.h>
#include <conio.h>
#include <dos.h>
void proces1(void);
void proces2(void);
void proces3(void);
char znak;
int pozycja = 1;
int main(void)
{
clrscr();
if(setjmp(BuforStanu_1)) proces1();
if(setjmp(BuforStanu_2)) proces2();
proces3();
return 0;
}
void proces1(void)
{
while(kbhit())
{
gotoxy(1,1);
printf("PROCES1, Pisz tekst: [Kropka - Koniec]");
gotoxy(pozycja,2);
znak = getch();
- 221-
printf("%c", znak);
pozycja++;
}
if(znak == '.') exit (0);
void proces2(void)
{
for(;;)
{
gotoxy(10,20);
printf("PROCES 2: ");
for(int i = 1; i<40; i++)
{
if(kbhit()) break;
printf(".2\b");
delay(5);
}
longjmp(BuforStanu_1, 1);
}
}
void proces3(void)
{
for(;;)
{
gotoxy(10,23);
printf("PROCES 3: ");
for(int i = 1; i<40; i++)
{
if(kbhit()) break;
printf(".3\b");
delay(2);
}
longjmp(BuforStanu_2,2);
}
}
[!!!]UWAGA
________________________________________________________________
W pierwszych dwu przykładach trzymanie stale wciśniętego
klawisza spowoduje tylko automatyczną repetycję wprowadzanego
znaku. W przykładzie trzecim spowoduje to przerwanie procesów 2
i 3, co będzie wyraźnie widoczne na monitorze (DOS).
Zwróć uwagę, że kbhit() nie zmienia stanu bufora klawiatury.
________________________________________________________________
- 222-
powrocie z procesu identyfikować - z którego procesu nastąpił
powrót i podejmować stosowną decyzję np. przy pomocy instrukcji
switch:
switch(setjmp(bufor))
{
case 1 : proces2();
case 2 : proces3();
.....
default : proces0();
}
[!!!]UWAGA
________________________________________________________________
* Zmienne sterujące przełączaniem procesów powinny być zmiennymi
class PozycjaListy
{
public:
jmp_buf Bufor[n]; <-- n - Nr procesu
PozycjaListy *nastepna;
}
#include <setjmp.h>
jmp_buf BuforStanu;
int Nr_Bledu;
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) */
....
- 223-
Proces(); <-- Wywołanie procesu
}
else
{
/* PO powrocie z procesu (ów) */
ErrorHandler(); <-- obsługa błędów
}
....
return 0;
}
void Proces()
{
int Flaga_Error = 0;
...
/* Jeśli nastąpiły błędy, flaga w trakcie pracy procesu jest
ustawiana na wartość różną do zera */
if(Error) Flaga_Error++;
...
if(Fllaga_Error != 0) longjmp(BuforStanu, Flaga_Error);
...
}
[Z]
________________________________________________________________
1. Napisz samodzielnie program realizujący 2, 3, 4 procesy
współbieżne. Jeśli chcesz, by jednym z procesów stał się
całkowivie odrębny program - skorzystaj z funkcji grupy
spawn...() umożliwiających w C++ uruchamianie procesów
potomnych.
________________________________________________________________
- 224-
LEKCJA 22. NA ZDROWY CHŁOPSKI ROZUM PROGRAMISTY.
________________________________________________________________
W trakcie tej lekcji dowiesz się:
* jak przyspieszać działanie programów w C++
* jakie dodatkowe narzędzia zyskujesz "przesiadając się" na
nowoczesny kompilator C++
________________________________________________________________
i = 0;
0 < 3 ? == TRUE --> T[0] = 0 // Tu nastepuje i++; //
T[1] = 1 itd...
[P078.CPP]
# include <iostream.h>
# include <stdio.h>
# include <conio.h>
main()
- 225-
{
cout << "\nPodaj ilosc elem. tablicy T[] - 2...99 \n";
cin >> max;
return 0;
}
- 226-
zadziała szybciej niż
TAB_2[0] = 0;
for(i = 1; i < 5; i++)
TAB_1[i] = i;
TAB_2[i] = i;
main() {
char gotowe = 0;
...
while (!gotowe)
{
znak = wybrano_z_menu();
if (znak == 'q' || znak == 'Q') gotowe = 1;
else
.......
gotowe = 1;
}
char gotowe;
main() {
...
while (!gotowe)
{
- 227-
znak = wybrano_z_menu();
if (znak == 'q' || znak == 'Q') break; //Quit !
else
.......
gotowe = 1;
}
if (x >= 2) { ... }
else if (x == 1) { ... }
else { ... }
if (x == 0) { ... }
else if (x == 1) { ... }
else { ... }
- 228-
MAX || W1 || W2 || W3 ...
MIN && W1 && W2 && W3 ...
C++:
2 * a == a + a == a << 1
16 * a == a << 4
a * b + a * c == a * (b + c)
~a + ~b == ~(a + b)
!x && !y == !(x || y)
!x || !y == !(x && y)
wynik = (x * x) + (x * x);
zm_pomocn = x * x;
wynik = zm_pomocn << 1;
- 229-
zoptymalizować. Jako przykład zastosujmy funkcję biblioteczną
strcmp() (string compare - porównaj łańcuchy znaków). Porównanie
łańcuchów
[???] UWAGA:
________________________________________________________________
Takich skrótów nie można stosować w stosunku do operandów typu
double, ani float.
________________________________________________________________
x % 16 == x & 0xF;
x = (x + 1) % (MAXIMUM + 1);
if (x == MAXIMUM) x = 0;
else x++;
- 230-
stosując zamiast if-else operator ? : możemy to zapisać tak:
(x == MAXIMUM) ? (x = 0) : (x++);
a = b / 10;
a = b * .1;
stosujemy jako flagi zmienne typu int lub char a w Windows BOOL.
if (a > b)
Flaga = 1;
else
Flaga = 0;
zastąpimy krótszym
- 231-
wyznaczyć na etapie kompilacji.
Zapis
wynik = 2 * x * 3.14;
wynik = 2 * 3.14 * x;
wynik = 6.28 * x;
- 232-
LEKCJA 23. Co nowego w C++?
________________________________________________________________
Z tej lekcji dowiesz się, jakie mechanizmy C++ pozwalają na
stosowanie nowoczesnego obiektowego i zdarzeniowego stylu
programowania i co programy robią z pamięcią.
________________________________________________________________
class - klasa,
delete - skasuj (dynamicznie utworzony obiekt),
friend - "zaprzyjaźnione" funkcje z dostępem do danych,
inline - wpleciony (funkcje przeniesione w formie rozwiniętej
do programu wynikowego),
new - utwórz nowy obiekt,
operator - przyporządkuj operatorowi nowe działanie,
private - dane i funkcje prywatne klasy (obiektu), do których
zewnętrzne funkcje nie mają prawa dostępu,
protected - dane i funkcje "chronione", dostępne z
ograniczeniami,
public - dane i funklcje publiczne, dostępne bez ograniczeń,
template - szablon,
this - ten, pointer wskazujący bieżący obiekt,
virtual - funkcja wirtualna, abstrakcyjna, o zmiennym
działaniu.
ROZSZERZENIE C - FUNKCJE.
- 233-
w programie jeden (lub więcej) argument (ów) zostanie pominięte,
Funkcja(5.127); //ŹLE
Funkcja(99); //DOBRZE
[P079.CPP]
#include <iostream.h>
main()
{
fun_show(); // Trzy arg. domyslne
fun_show(1); // Pierwszy parametr
fun_show(11, 2.2); // Dwa parametry
fun_show(111, 2.22, 3L); // Trzy parametry
return 0;
}
- 234-
C++ pozwala deklarować zmienne w dowolnym miejscu, z
zastrzeżeniem, że deklaracja zmiennej musi nastąpić przed jej
użyciem. Umieszczanie deklaracji zmiennych możliwie blisko
miejsca ich użycia znacznie poprawia czytelność (szczególnie
dużych "wieloekranowych") programów. Klasyczny sposób deklaracji
zmiennych:
int x, y, z;
...
main()
{
...
z = x + y + 1;
...
}
main()
{
...
for ( int i = 1; i <= 10; i++)
cout << "Biezace i wynosi: " << i;
...
}
[P080.CPP]
//Program demonstruje przesłanianie zmiennych
#include <iostream.h>
main()
{
int x = 22; //Zmienna lokalna funkcji main
cout << ::x << " <-- To jest globalny ::x \n";
cout << x << " <-- A to lokalny x \n";
daj_x();
- 235-
return 0;
}
void daj_x(void)
{
cout << "To ja funkcja daj_x(): \n";
cout << ::x << " <-- To jest globalny ::x \n";
cout << x << " <-- A to lokalny x \n";
int x = 333;
cout << "A to moja zmienna lokalna - automatyczna ! \n";
cout << x << " <-- tez x ";
}
globalnymi a lokalnymi.
[P081.CPP]
# include <iostream.h>
enum ciuchy
{
niewymowne = 1, skarpetka, trampek, koszula, marynarka,
czapa, peruka, koniec
};
main()
{
ciuchy n;
do
{
cout << "\nNumer ciucha ? --> (1-7, 8 = quit): ";
cin >> (int) n;
- 236-
switch (n)
{
case niewymowne: cout << "niewymowne";
break;
case skarpetka: cout << "skarpetka";
break;
case trampek: cout << "trampek";
break;
case koszula: cout << "koszula";
break;
case marynarka: cout << "marynarka";
break;
case czapa: cout << "czapa";
break;
case peruka: cout << "peruka";
break;
case koniec: break;
default:
cout << "??? Tego chyba nie nosze...";
}
} while (n != koniec);
return 0;
}
- 237-
suffix) pozwalające na określenie typu parametrów,
* pozwala na tworzenie tzw. funkcji polimorficznych (kilka
różnych funkcji o tej samej nazwie), itp.
[P081.CPP]
#include <iostream.h>
extern "C"
{
# include <stdlib.h> //Prototyp rand() w STDLIB.H
}
main()
{
cout << rand();
return 0;
}
randomize();
...
int n = rand() % 100;
...
________________________________________________________________
- 238-
W programie przykładowym funkcje z STDLIB.H zostaną skompilowane
[P082.CPP]
# include <iostream.h>
# include <stdlib.h>
# include <string.h>
main()
{
int max;
for(;;)
{
cout << "\n Ilu krewnych chcesz posortowac? (1...6): ";
cin >> max;
if( max > 0 && max < 7) break;
cout << "\n Nic z tego...";
}
static char* krewni[] =
{
"Balbina - ciotka",
"Zenobiusz - kuzyn",
"Kleofas - stryjek",
"Ola - kuzynka (ach)",
"Waleria - tez niby ciotka",
"Halina - stryjenka"
};
return 0;
}
extern "C"
{
int comp(const void *x, const void *y)
{
return strcmp(*(char **)x, *(char **)y);
}
}
- 239-
Program wykonuje następujące czynności:
* sortuje wskaźniki,
* wyświetla posortowane łańcuchy znakowe,
* definiuje funkcję comp() - porównaj,
* wykorzystuje funkcję biblioteczną C - strcmp() - String
Compare do porównania łańcuchów znaków.
O PAMIĘCI.
___________________
niskie adresy --> Ngłówek programu I.
Adres startowy
KOD: Kod programu
___________________
Zmienne statyczne II.
DANE: 1. Zainicjowane Zmienne globalne
___________________
Zmienne statyczne III.
DANE: 2. Niezainicjowane Zmienne globalne
___________________
STERTA: (heap) W miarę potrzeby IV.
rośnie w dół.
Tu operują funkcje
malloc(), free().
___________________
POLE NICZYJE: V.
___________________
W miarę potrzeby VI.
STOS: (stack) rośnie w górę.
wysokie adresy --> ___________________
- 240-
W obszarze kodu (I.) znajdują się instrukcje. Na stosie
przechowywane są:
* zmienne lokalne,
* argumenty przekazywane funkcji w momencie jej wywołania,
* adresy powrotne dla funkcji (RET == CS:IP).
# include <alloc.h>
int a; // III.
int b = 6; // II.
main()
{
char *Dane;
...
float lokalna; // VI.
...
Dane = malloc(16); // IV.
...
}
[P083.CPP]
- 241-
# include "iostream.h"
struct Data
{
int dzien;
int miesiac;
int rok;
};
void main()
{
Data *pointer = new Data;
/* Dekl. wskaznik do struct typu Data */
/* Przydziel pamiec dla struktury */
int TAB[3];
[P084.CPP]
# include "iostream.h"
main()
{
- 242-
int *pointer = new int[3]; // Przydziel pamiec
delete pointer;
}
[P085.CPP]
# include <conio.h>
# include <stdlib.h>
# include <iostream.h>
void main()
{
for(;;)
{
cout << "\nPodaj wielkosc tablicy (1...100) --> ";
int i, size;
cin >> size;
/* Na stercie tworzymy dynamiczna tablica: */
int *pointer = new int[size];
char k = getch();
if(k == 'a') break;
delete pointer;
}
}
- 243-
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
18 19
Podaj wielkosc tablicy (1...100) --> 100
TABLICA:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
67 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
[P086.CPP]
# include <stdlib.h>
# include <string.h>
# include <iostream.h>
extern "C"
{
int Fporownaj(const void* x, const void* y)
{
return (strcmp(*(char **)x, *(char **)y));
}
}
main()
{
cout << "Wpisz maksymalna ilosc imion --> ";
int ilosc, i;
cin >> ilosc;
- 244-
for (i = 0; i < ilosc; i++)
cout << pointer[i] << '\n';
for (i = 0; i < ilosc; i++)
delete pointer[i];
delete pointer;
return 0;
}
[P087.CPP]
# include <stdlib.h>
# include <string.h>
# include <iostream.h>
extern "C"
{
int Fporownaj(const void* x, const void* y)
{
return (Fporown_string(*(char **)x, *(char **)y));
}
}
main()
{
cout << "Wpisz maksymalna ilosc imion --> ";
int ilosc, i;
cin >> ilosc;
- 245-
pointer[i] = new char[strlen(imie)+1];
Fkopiuj_string(pointer[i], imie);
delete imie;
}
/* w tym momencie i == ilosc */
Fsortuj(pointer, i, sizeof(char *), Fporownaj);
delete pointer;
return 0;
}
jej szukać.
[P088.CPP]
#include <conio.h>
#include <math.h>
#include <iostream.h>
int main(void)
{
clrscr();
- 246-
cout << "\nPodaj Liczbe \n";
cin >> Liczba;
cout << "CO OBLICZYC ?\n________________\n";
cout<<"1 - Sin \n2 - Cos \n3 - Odwrotnosc 1/X\n";
double Nasza_F(double x)
{
if (x != 0)
x = 1/x;
else
cout << "???\n";
return x;
}
_new_handler != NULL
[P089.CPP]
- 247-
# include <stdlib.h>
# include <iostream.h>
void main()
{
_new_handler = Funkcja; //Inicjujemy wskaznik
for(;;)
{
char *pointer = new char[8192];
suma += 8192;
cout << "\nMam juz " << suma << " znakow w RAM\n";
if (pointer != 0)
cout << "Pointer != NULL";
}
}
- 248-
LEKCJA 24. SKĄD WZIĘŁY SIĘ KLASY I OBIEKTY W C++.
________________________________________________________________
W trakcie tej lekcji dowiesz się, skąd w C++ biorą się obiekty i
jak z nich korzystać.
________________________________________________________________
[P90.CPP]
#include <iostream.h>
struct Data
{
int dzien;
int miesiac;
int rok;
};
int main()
{
for (; i < 16; i++)
{
*(p + i) = NaszaStruktura;
daty[i].rok += i;
cout << "\nDnia ";
Fdrukuj(daty[i]);
- 249-
cout << " Patrycja ";
if ( !i ) cout << "urodzila sie, wiek - ";
if (i > 0 && i < 14) cout << "miala ";
if (i > 13) cout << "bedzie miec ";
cout << i;
if (i == 1) cout << " roczek";
else cout << " lat";
if (i > 1 && i < 5) cout << "ka";
cout << '.';
}
return 0;
}
[P091.CPP]
#include <iostream.h>
- 250-
Data::Data(void) //Poczatkowa data - Konstruktor
{
dzien = 3;
miesiac = 11;
rok = 1979;
}
int main()
{
Data NStruktura; //Inicjujemy strukture
Zwróć uwagę, że
* odkąd dane stały się elementem struktury, zaczęliśmy odwoływać
- 251-
Data::Data(void) //Poczatkowa data - Konstruktor
automatycznie.
* definiujemy strukturę;
* definiujemy funkcje;
* przekazujemy i pobieramy dane do/od struktury typu Zwierzak.
[STRUCT.CPP]
# include "iostream.h"
struct Zwierzak
{
private:
int schowek; //DANE PRYWATNE - niedostepne
public:
void SCHOWAJ(int Xwe); //Funkcje dostepne zzewnatrz
- 252-
int ODDAJ(void);
};
int Zwierzak::ODDAJ(void)
{
return (schowek);
}
main()
{
Zwierzak Ciapek, Azor, Kotek; // Struktury "Zwierzak"
int Piggy; // zwykla zmienna
Ciapek.SCHOWAJ(1);
Azor.SCHOWAJ(22);
Kotek.SCHOWAJ(-333);
Piggy = -4444;
return 0;
}
- 253-
za chwilę - struktura Ciapek jest już właściwie obiektem, a typ
danych Zwierzak jest już właściwie klasą obiektów. Wystarczy
zamienić słowo "struct" na słowo "class".
[CLASS.CPP]
# include "iostream.h"
class Zwierzak
{
int schowek;
public:
void SCHOWAJ(int Xwe); //Funkcje dostepne zzewnatrz
int ODDAJ(void);
};
int Zwierzak::ODDAJ(void)
{
return (schowek);
}
main()
{
Zwierzak Ciapek, Azor, Kotek; // obiekty klasy "Zwierzak"
int Piggy; // zwykla zmienna
Ciapek.SCHOWAJ(1);
Azor.SCHOWAJ(22);
Kotek.SCHOWAJ(-333);
Piggy = -4444;
return 0;
}
O KLASACH I OBIEKTACH.
- 254-
Klasy służą do tworzenia formalnego typu danych. W przypadku
klas wiadomo jednak "z definicji", że będzie to bardziej złożony
class Klasa
{
int prywatna_tab[80]
public:
int dane;
void Inicjuj(void);
int Funkcja(int arg);
};
struct Klasa
{
private:
int prywatna_tab[80]
public:
int dane;
void Inicjuj(void);
int Funkcja(int arg);
};
- 255-
struktury takiego typu, deklaracja tych struktur musiałaby
wyglądać tak:
struct rodzaj_struktur
{
private:
int prywatna_tab[80]
public:
int dane;
void Inicjuj(void);
int Funkcja(int arg);
} str1, str2, .... , nasza_struktura;
bądź tak:
struct rodzaj_struktur
{
private:
int prywatna_tab[80]
public:
int dane;
void Inicjuj(void);
int Funkcja(int arg);
};
...
(struct) rodzaj_struktur str1, str2, .... , nasza_struktura;
struct rodzaj_struktur
{
private:
int prywatna_tab[80]
public:
int dane;
void Inicjuj(void);
int Funkcja(int arg);
};
main()
{
...
struct rodzaj_struktur nasza_struktura;
//lub równoważnie:
rodzaj_struktur nasza_struktura;
class Klasa
{
int prywatna_tab[80]
- 256-
public:
int dane;
void Inicjuj(void)
int Funkcja(int our_param);
} Obiekt;
class Klasa
{
int prywatna_tab[80]
public:
int dane;
void Inicjuj(void)
int Funkcja(int argument);
};
main()
{
...
Klasa Obiekt;
...
main()
{
...
Klasa Obiekt;
Obiekt.dane = 13;
...
main()
{
...
Klasa Obiekt;
Obiekt.dane = 13; Obiekt.Funkcja(44);
...
class Klasa
{
...
public:
...
void Inicjuj(void) /* Prototypy funkcji */
int Funkcja(int argument);
};
- 257-
[!!!] UWAGA!
________________________________________________________________
W C++ nie możemy zainicjować danych wewnątrz deklaracji klasy:
class Klasa
{
private:
int prywatna_tab[80] = { 1, 2, ... }; //ŹLE !
public:
int dane = 123; //ŹŁE !
...
________________________________________________________________
elementów struktury:
main()
- 258-
{
...
Obiekt.dane = 5; //Przypisanie wartości zmiennej.
Obiekt.Inicjuj(); //Wywołanie funkcji Inicjuj()
...
Obiekt.Funkcja(3); //Wywołanie funkcji z argumentem
- 259-
LEKCJA 25. PRZYKŁAD OBIEKTU.
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak praktycznie projektuje się
klasy i obiekty. Twój pierwszy obiekt zacznie działać.
________________________________________________________________
main()
{
....
Inicjuj('A');
....
//UWAGA: Nie tak:
//licznik.Inicjuj() - funkcja jest zewnętrzna !
- 260-
Aby funkcja inicjująca pole struktury zadziałała prawidłowo, jej
void main()
{
char znak_we;
Inicjuj('A');
- 261-
Po przerwaniu pętli przez użytkownika wystarczy sprawdzić jaka
wartość jest wpisana w polu licznik.ile i możemy wydrukować
wynik zliczania wystąpień litery 'A' we wprowadzonym tekście.
[P092.CPP]
# include <iostream.h>
# include <ctype.h> //Prototyp f. toupper()
struct Licznik
{
char znak;
int ile;
} licznik;
void Inicjuj(char x)
{
licznik.znak = x;
licznik.ile = 0;
}
void PlusJeden(void)
{
licznik.ile++;
}
void main()
{
char znak_we;
Inicjuj('A');
for(;;)
{
cin >> znak_we;
if (znak_we == 'k' || znak_we == 'K') break;
if(licznik.znak == toupper(znak_we)) PlusJeden();
}
- 262-
obiekt. Zawartość naszego obiektu powinna wyglądać tak:
Dane:
char znak;
int ile;
Funkcje:
void Inicjuj(char);
void PlusJeden(void);
class Licznik
{
char znak;
int ile;
public:
void Inicjuj(char);
void PlusJeden(void);
};
własnej klasy:
void Licznik::Inicjuj(char x)
{
znak = x;
ile = 0;
}
void Licznik::PlusJeden(void)
{
ile++;
}
- 263-
operator :: (oper. widoczności/przesłaniania - ang. scope
resolution operator). Taki sposób zapisu definicji funkcji
oznacza dla C++, że funkcja jest członkiem klasy (ang. member
function). Logika C++ w tym przypadku wygląda tak:
main()
{
char znak_we; //Dekl. zwyklej zmiennej
Licznik licznik; //Deklarujemy obiekt klasy Licznik
licznik.Inicjuj('A'); //Inicjujemy licznik
...
char Licznik::Pokaz(void);
char Licznik::Pokaz(void)
- 264-
{
return znak;
}
int Licznik::Efekt(void)
{
return ile;
}
[P093.CPP]
# include <ctype.h>
# include <iostream.h>
class Licznik
{
char znak;
int ile;
public:
void Inicjuj(char);
void PlusJeden(void);
char Pokaz(void);
int Efekt(void);
};
void main()
{
char znak_we;
Licznik licznik;
licznik.Inicjuj('A');
for(;;)
{
cin >> znak_we;
if (znak_we == 'k' || znak_we == 'K') break;
if(licznik.Pokaz() == toupper(znak_we))
licznik.PlusJeden();
}
- 265-
void Licznik::Inicjuj(char x)
{
znak = x;
ile = 0;
}
void Licznik::PlusJeden(void)
{
ile++;
}
char Licznik::Pokaz(void)
{
return znak;
}
int Licznik::Efekt(void)
{
return ile;
}
- 266-
LEKCJA 26. CO TO JEST KONSTRUKTOR.
________________________________________________________________
W trakcie tej lekcji dowiesz się, w jaki sposób w pamięci
komputera są tworzone obiekty.
________________________________________________________________
PRZYKŁADOWY KONSTRUKTOR.
struct Licznik
{
private:
char znak;
int ile;
public:
void Inicjuj(char);
void PlusJeden(void);
};
- 267-
struct Licznik
{
private:
char znak;
int ile;
public:
Licznik(void); //Konstruktor nie pobiera argumentu
void PlusJeden(void);
};
Licznik::Licznik(void)
struct Licznik
{
private:
char znak;
int ile;
public:
Licznik(char); //Konstruktor z argumentem typu char
void PlusJeden(void);
};
- 268-
{
...
}
main()
{
Licznik licznik('A'); //Deklaracja struktury typu Licznik
// oznacza to automatyczne wywołanie konstruktora z argumentem
....
main()
{
Sasiedzi chopy("Helmut", "Ulrich", "Adolf", "Walter");
....
# include <ctype.h>
# include <iostream.h>
- 269-
struct Licznik
{
private:
char znak;
int ile;
public:
Licznik(char); //Konstruktor
void PlusJeden(void);
char Pokaz(void);
int Efekt(void);
};
void main()
{
Licznik licznik('A'); //Zainicjowanie przez konstruktor
- 270-
[P095.CPP] /* Wersja z klasą i obiektem */
# include <ctype.h>
# include <iostream.h>
class Licznik
{
char znak;
int ile;
public:
Licznik(char); //Konstruktor
void PlusJeden(void);
char Pokaz(void);
int Efekt(void);
};
void main()
{
Licznik licznik('A'); //Zainicjowanie obiektu licznik
- 271-
do skasowania obiektu możemy zastosować tzw. desruktor (ang.
destructor). Nazwy konstruktora i destruktora są identyczne z
nazwą macieżystego typu struktur (macieżystej klasy), z tym, że
nazwa destruktora poprzedzona jest znakiem "~" (tylda).
CO TO JEST DESTRUKTOR.
struct Stos
{
private:
int *bufor_danych;
int licznik;
public:
Stos(int ile_RAM); /* Konstruktor
int Pop(int *ze_stosu);
int Push(int na_stos);
};
gdzie:
*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
(lub obiekt klasy Stos),
ile_RAM - ilość pamięci potrzebna do poprawnego działanie stosu,
*ze_stosu - wskaźnik do zmiennej, której należy przypisać
wartość zdjętą właśnie ze stosu,
na_stos - liczba przeznaczona do zapisu na stos.
- 272-
rozmieszczenie 50 liczb typu int (po 2 bajty każda). Liczbę
potrzebnych bajtów pamięci - 100 przekazujemy jako argument
konstruktorowi w momencie deklaracji struktury typu Stos. Nasza
struktura w programie będzie się nazywać nasz_stos.
main()
{
...
Stos nasz_stos(100);
...
struct Stos
{
...
public:
...
~Stos(void);
...
}
- 273-
{
free(bufor_danych);
cout << "\n Destruktor: Struktury juz nie ma...";
}
Stos nazwa_struktury;
nazwa_struktury.Push()
nazwa_struktury.Pop()
[P096.CPP]
# include <iostream.h>
# include <alloc.h>
# define OK 1
struct Stos
{
private:
int *bufor_danych;
int licznik;
public:
Stos(int); /* Konstruktor */
~Stos(void); /* Destruktor */
int Pop(int*);
int Push(int);
};
- 274-
cout << "Konstruktor: Inicjuje strukture. ";
}
void main()
{
Stos nasz_stos(100); //Dekl. struktury typu Stos
int i, Liczba;
# include <iostram.h>
# include <alloc.h>
# include <A:\STOS.HPP>
- 275-
void main()
{
...
}
[P097.CPP]
# include <iostream.h>
# include <alloc.h>
# define OK 1
class Stos
{
int *bufor_danych;
int licznik;
public:
Stos(int); /* Konstruktor */
~Stos(void); /* Destruktor */
int Pop(int*);
int Push(int);
};
- 276-
{
if(licznik >= 49) return 0;
else bufor_danych[++licznik] = na_stos;
return OK;
}
/* ------------------------koniec pliku STOSCL.HPP----------- */
void main()
{
Stos nasz_stos(100); //OBIEKT Klasy Stos
int i, Liczba;
[!!!] A CO Z UNIAMI ?
________________________________________________________________
Unie są w C++ traktowane podobnie jak struktury, z tym, że pola
unii mogą się nakładać (ang. overlap) i wobec tego nie wolno
stosować słowa kluczowego private w uniach. Wszystkie elementy
unii muszą mieć status public. Unie mogą także posiadać
konstruktory.
________________________________________________________________
[P098.CPP]
- 277-
#include <iostream.h>
#include <stdio.h>
#include <time.h>
struct Data
{
int miesiac, dzien, rok;
void Display(void); //Metoda "wyswietl"
};
void Data::Display(void)
{
char *mon[] =
{
"Stycznia","Lutego","Marca","Kwietnia","Maja","Czerwca",
"Lipca","Sierpnia","Wrzesnia","Pazdziernika","Listopada",
"Grudnia"
};
cout << dzien << ". "
<< mon[miesiac] << ". "
<< rok;
}
struct Czas
{
int godz, minuty, sekundy;
void Display(void); // znow metoda "wyswietl"
};
void Czas::Display(void)
{
char napis[20];
main()
{
Czas teraz;
Data dzis;
teraz.godz = tim.tm_hour;
teraz.minuty = tim.tm_min;
teraz.sekundy = tim.tm_sec;
dzis.miesiac = tim.tm_mon;
dzis.dzien = tim.tm_mday;
- 278-
dzis.rok = 1900 + tim.tm_year;
return 0;
}
[Z]
________________________________________________________________
1. Sprawdź, czy zamiana struktur na klasy nie zmienia sposobu
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.
________________________________________________________________
- 279-
LEKCJA 27. O DZIEDZICZENIU.
________________________________________________________________
W trakcie tej lakcji dowiesz się na czym polega dziedziczenie.
________________________________________________________________
LOGIKA DZIEDZICZENIA.
jedz()
śpij()
oddychaj()
Slon.flaga_ssak
Slon.trabie()
Slon.tupie()
- 280-
{
private:
Lista danych i funkcji prywatnych
public:
Lista danych i funkcji publicznych
} Lista struktur danego typu;
struct Zwierzak
{
void jedz();
void spij();
void oddychaj();
};
(tu: public).
- 281-
Opracowanie przykładowego programu ilustrującego mechanizm
dziedziczenia rozpoczniemy od zdefiniowania bazowego typu
struktur i struktury pochodnej.
struct Zwierzak
{
int nogi; <-- dane
# include <iostream.h>
...
void main()
{
Slon Choleryk; //Deklaracja struktury
...
cout << "\nNogi odziedziczylem: " << Choleryk.nogi;
cout << "\nA teraz kolejno funkcje: \n";
Choleryk.jedz();
Choleryk.spij();
Choleryk.oddychaj();
Choleryk.trabi();
Choleryk.tupie();
}
- 282-
należącymi do obu typów struktur - bazowego: Zwierzak i
pochodnego: Slon.
[???] A CO Z UNIAMI ?
_______________________________________________________________
Unie nie mogą brać udziału w dziedziczeniu. Unia nie może być
ani typem bazowym ani typem pochodnym.
_______________________________________________________________
[P099.CPP]
# include <iostream.h>
struct Zwierzak
{
int nogi;
void jedz();
void spij();
void oddychaj();
};
void Zwierzak::jedz(void) { cout << "Jem conieco...\n"; }
void Zwierzak::spij(void) { cout << "Cosik mi sie sni...\n"; }
void Zwierzak::oddychaj(void) { cout << "Dysze ciezko...\n"; }
void main()
{
Slon Choleryk;
Choleryk.nogi = 4; Choleryk.flaga_ssak = 1;
cout << "\nNogi odziedziczylem: " << Choleryk.nogi;
cout << "\nA teraz kolejno funkcje: \n";
Choleryk.jedz();
Choleryk.spij();
Choleryk.oddychaj();
Choleryk.trabi();
Choleryk.tupie();
if(Choleryk.flaga_ssak == 1) cout << "SSak!";
}
- 283-
LEKCJA 28. DZIEDZICZENIE ZŁOŻONE.
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak można odziedziczyć wiele
cech po wielu różnych przodkach.
________________________________________________________________
[P100.CPP]
#include "stdio.h"
#include "conio.h"
main()
{
clrscr();
C.promien = E.promien = 4;
E.mniejszy_promien = 3;
//Sprawdzamy zawartosc pol struktur
printf("%d %d %d %d %d %d \n",
P.x, C.x, E.x, P.y, C.y, E.y);
printf("%d %d %d",
C.promien, E.promien, E.mniejszy_promien );
getch();
return 0;
- 284-
}
[P101.CPP]
#include <iostream.h>
struct BAZOWA1
{ //Struktura bazowa pierwsza
public:
void Funkcja_a(void);
};
struct BAZOWA2
{ //Struktura bazowa druga
public:
void Funkcja_b(void);
};
void main()
{
POCHODNA dziecko; //Dekl. strukt. typu pochodnego
dziecko.Funkcja_a();
dziecko.Funkcja_b();
dziecko.Funkcja_c();
}
- 285-
(klas) bazowych w schemacie baza_1-baza_2-....-baza_n może być
więcej niż 2.
DZIEDZICZENIE KLAS.
[P102.CPP]
#include <iostream.h>
void jedz();
void spij();
void oddychaj();
};
void trabi();
void tupie();
};
void main()
{
Slon Obiekt;
/* obiekt Obiekt klasy Slon */
Obiekt.nogi = 4; Obiekt.flaga_ssak = 1;
cout << "\nNogi odziedziczylem: " << Obiekt.nogi;
cout << "\nA teraz kolejno funkcje: \n";
Obiekt.jedz();
Obiekt.spij();
Obiekt.oddychaj();
Obiekt.trabi();
Obiekt.tupie();
if(Obiekt.flaga_ssak) cout << "Jestem ssakiem !";
}
- 286-
Pamiętając o problemie domyślnego statusu członków
struktur/public i klas/private) możemy przejść do klas i
obiektów.
O KLASACH SZCZEGÓŁOWO.
class ZNAK
{
char znak_dany; //Kod ASCII znaku
...
class ZNAK
{
char znak_dany;
public:
ZNAK(...);
...
ZNAK Obiekt('a');
Znaczy to: Utwórz w RAM obiekt klasy ZNAK pod nazwą "Obiekt" i
wytłumacz mu, że jest znakiem 'a'.
ZNAK::ZNAK(char x)
{
znak_dany = x;
}
litery na duże.
- 287-
ZNAK::ZNAK(char x)
{
znak_dany = x;
if(znak_dany < 65 || znak_dany >122) znak_dany = '*';
if(znak_dany > 97) znak_dany -= 32;
}
class ZNAK
{
char znak_dany;
public:
ZNAK(char); //Konstruktor zwykly ("jednoznakowy")
ZNAK(void); //Konstruktor domyślny (bezparametrowy)
...
class ZNAK
{
char znak_dany;
public:
ZNAK(char);
ZNAK(); //Z daleka widać, że nic nie ma !
...
- 288-
class ZNAK
{
char znak_dany;
public:
ZNAK(char);
ZNAK();
void Pokaz_sie();
void Znikaj();
void Skacz();
};
i zdefiniujmy te metody.
void ZNAK::Pokaz_sie(void)
{
cout << znak_dany << '\a';
}
void ZNAK::Znikaj(void)
{
cout << "\b" << ' '; //'\b' == Back Space
}
void ZNAK::Skacz(void)
{
for(int i = 0; i < 100; i++)
{
gotoxy(rand()%50, rand()%50);
cout << znak_dany;
getch();
}
}
A:\ZNAK.H
//_____________________________________________________________
# include <stdlib.h>
# include <conio.h>
# include <iostream.h>
class ZNAK
{
char znak_dany;
public:
ZNAK(char);
ZNAK();
void Pokaz_sie();
void Znikaj();
void Skacz();
};
- 289-
ZNAK::ZNAK()
{
znak_dany = 'X';
}
ZNAK::ZNAK(char x)
{
znak_dany = x;
if(znak_dany < 65 && znak_dany >122) znak_dany = '*';
if(znak_dany > 97) znak_dany -= 32;
}
void ZNAK::Pokaz_sie(void)
{
cout << znak_dany << '\a';
}
void ZNAK::Znikaj(void)
{
cout << "\b" << ' '; //'\b' == Back Space
}
void ZNAK::Skacz(void)
{
for(int i = 0; i < 100; i++)
{
gotoxy(rand()%50, rand()%50);
cout << znak_dany;
getch();
}
}
//_____________ koniec pliku A:\INCLUDE\ZNAK.H _________________
[P103.CPP]
# include <a:\znak.h>
void main()
{
char litera;
clrscr();
cout << '\n' << "Podaj znak: ";
cin >> litera;
ZNAK Obiekt(litera);
cout << "\nSTART" << "\n\n\n";
getch();
Obiekt.Pokaz_sie();
getch();
- 290-
Obiekt.Znikaj();
getch();
Obiekt.Skacz();
- 291-
LEKCJA 29. FUNKCJE I OVERLOADING.
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak jeszcze w C++ można
wykorzystywać funkcje.
________________________________________________________________
wydrukuj('Z');
wydrukuj('Z');
wydrukuj(75); // 75 to kod ASCII znaku, zamiast znaku bezpośr.
...
class KLASA
{
public:
void wydrukuj(char znak);
void wydrukuj(int kod_ASCII);
void wydrukuj(char *string); //wskaźnik do lancucha
- 292-
}
Zapis:
[P104.CPP]
# include <iostream.h>
- 293-
main()
{
kopiuj_string(Piggie, "Panna Piggie");
kopiuj_string(Kermit, "Kermit - to protokul transmisji", 6);
cout << Kermit << " oraz " << Piggie;
return 0;
}
....
cout << (char) 65;
....
- 294-
kluczowego "inline" w definicjach funkcji. Zwróć uwgę, że w
samej definicji klasy słowo inline NIE POJAWIA SIĘ:
[P105.CPP]
# include <iostream.h>
class Klasa
{
public:
void wydrukuj(char* tekst);
void wydrukuj(char Znak);
void wydrukuj(int KodASCII);
};
void main()
{
Klasa Obiekt;
cout << "Obiekt wyprowadza dane: " << '\n';
Obiekt.wydrukuj(65);
Obiekt.wydrukuj('B');
Obiekt.wydrukuj("C i juz");
}
- 295-
typu inline.
________________________________________________________________
class Klasa
{
public:
inline void wydrukuj(char* a) { cout << a; }
inline void wydrukuj(char z) { cout << z; }
inline void wydrukuj(int kod) { cout << (char) kod; }
};
OVERLOADING KONSTRUKTORÓW.
class Klasa
{
public:
Klasa(char*);
Klasa(char, int);
};
- 296-
for(int i = 1; i < ile; i++)
cout << Znak;
}
class Klasa
{
public:
Klasa();
Klasa(char*);
Klasa(char, int);
};
...
Klasa::Klasa(void)
{
cout << 'x';
}
[P106.CPP]
# include <iostream.h>
class Klasa
{
public:
Klasa();
Klasa(char*);
Klasa(char, int);
};
Klasa::Klasa(void)
{
cout << 'x';
}
Klasa::Klasa(char *tekst)
{
cout << tekst;
}
- 297-
void main()
{
Klasa Obiekt1; //Konstr. domyślny
Klasa Obiekt2('A'); // ile - domyslnie == 4
Klasa Obiekt3('B', 3);
Klasa Obiekt4(p);
}
- 298-
LEKCJA 30. WYMIANA DANYCH MIĘDZY OBIEKTAMI.
________________________________________________________________
* wielu obiektów;
* danych prywatnych obiektów (dostęp do publicznych,
"niezakapsułkowanych" danych jest prosty i oczywisty);
* funkcji o specjalnych uprawnieniach.
class Licznik
{
char moja_litera;
int ile;
public:
void Inicjuj_licznik(char);
void Skok_licznika(void);
void Pokazuj();
};
...
Licznik TAB[MAX];
- 299-
nazwa_klasy TAB[MAX];
ObiektK.Skok_licznika();
TAB[i].Skok_licznika();
...
cin >> znak; //Pobranie znaku z klawiatury
for(int i = 0; i < 26; i++)
{
if(i == (znak - 'A')) TAB[i].Skok_licznika();
}
...
...
TAB[getch() - 'A'].Skok_licznika();
...
- 300-
[P107.CPP]
class Licznik
{
char moja_litera;
int ile;
public:
void Inicjuj(char);
void Skok_licznika();
void Pokazuj();
};
void Licznik::Inicjuj(char z)
{
moja_litera = z;
ile = 0;
}
void Licznik::Skok_licznika(void)
{
ile++;
}
void Licznik::Pokazuj(void)
{
cout << "Znak " << moja_litera << " wystapil "
<< ile << " razy" << '\n';
}
main()
{
const MAX = 26;
Licznik TAB[MAX];
register int i;
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';
for(;;)
{ char znak;
cin >> znak;
if(znak == '.') break;
for(i = 0; i < MAX; i++)
{
if(i == (znak - 'A')) TAB[i].Skok_licznika();
}
- 301-
}
/* sprawdzamy: ----------------------------------------*/
char sprawdzamy;
cout << '\n' << "Podaj znak do sprawdzenia: " << '\n';
cin >> sprawdzamy;
cout << "Wyswietlam wyniki zliczania: \n";
TAB[toupper(sprawdzamy) - 'A'].Pokazuj();
return 0;
}
class Licznik
{
char moja_litera;
int ile;
public:
void Inicjuj(char);
void Skok_licznika();
void Pokazuj();
friend int Suma(int);
} TAB[MAX];
TAB[i].ile
- 302-
kluczowego friend. A oto definicja:
return (suma);
}
class ...
{
...
friend int Suma(...);
...
} ... ;
[P108.CPP]
# include <ctype.h>
# include <iostream.h>
class Licznik
{
char moja_litera;
int ile;
public:
void Inicjuj(char);
void Skok_licznika();
void Pokazuj();
friend int Suma(int);
}
const MAX = 26;
Licznik TAB[MAX];
register int i;
main()
{
/* inicjujemy liczniki: -------------------------------*/
- 303-
/* pracujemy - zliczamy: -------------------------------*/
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';
for(;;)
{ char znak;
cin >> znak;
if(znak == '.') break;
for(i = 0; i < MAX; i++)
{
if(i == (znak - 'A')) TAB[i].Skok_licznika();
}
}
/* sprawdzamy: ----------------------------------------*/
char sprawdzamy;
cout << '\n' << "Podaj znak do sprawdzenia: " << '\n';
cin >> sprawdzamy;
cout << "Wyswietlam wyniki zliczania: \n";
TAB[toupper(sprawdzamy) - 'A'].Pokazuj();
return 0;
}
void Licznik::Pokazuj(void)
{
cout << "Znak " << moja_litera << " wystapil "
<< ile << " razy" << '\n';
}
return (suma);
}
void Licznik::Skok_licznika(void)
- 304-
{
ile++; //Wiadomo o ktory obiekt chodzi
}
O ZAPRZYJAŹNIONYCH KLASACH.
[P109.CPP]
# include <iostream.h>
class TEZ_DATA
{
int dz, rok;
public:
TEZ_DATA() {}
TEZ_DATA(int d, int y) { dz = d; rok = y;}
void Pokazuj() {cout << '\n' << rok << '-' << dz;}
friend Data1; //"zaprzyjazniona" klasa
};
- 305-
Data1::operator TEZ_DATA(void)
{
TEZ_DATA DT_Obiekt(0, rok);
for (int i = 0; i < mc-1; i++)
DT_Obiekt.dz += TAB[i];
DT_Obiekt.dz += dz;
return DT_Obiekt;
}
main()
{
Data1 dt_Obiekt(11,17,89);
TEZ_DATA DT_Obiekt;
DT_Obiekt = dt_Obiekt;
DT_Obiekt.Pokazuj();
return 0;
}
class Licznik
{
char moja_litera;
static int ile;
...
};
class Licznik
- 306-
{
public:
char moja_litera;
static int ile;
Licznik(char); //Konstruktor
...
};
int main(void)
{
char litera;
...
cin >> litera;
...
if(litera == licznik_a.moja_litera) licznik_a.Skok_licznika();
...
}
nazwa_klasy::nazwa_zmiennej
identyfikator_obiektu.identyfikator_pola
identyfikator_klasy::identyfikator_pola
- 307-
Możemy zmodyfikować program przykładowy posługując się
(globalną) zmienną statyczną. Zamiast wszystkich liter będziemy
zliczać tylko wystąpienia 'a', 'b' i 'c'.
[P110.CPP]
# include "ctype.h"
# include "iostream.h"
class Licznik
{
public:
char moja_litera;
static int ile;
Licznik(char); //Konstruktor
void Skok_licznika();
void Pokazuj();
};
void main()
{
/* inicjujemy liczniki: -------------------------------*/
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';
for(;;)
{ char znak;
cin >> znak;
if(znak == '.') break;
if (znak == licznik_a.moja_litera) licznik_a.Skok_licznika();
if (znak == licznik_b.moja_litera) licznik_b.Skok_licznika();
if (znak == licznik_c.moja_litera) licznik_c.Skok_licznika();
}
/* sprawdzamy: ----------------------------------------*/
Licznik::Licznik(char z)
{
moja_litera = z;
ile = 0;
}
void Licznik::Skok_licznika(void)
{
- 308-
ile++;
}
void Licznik::Pokazuj(void)
{
cout << "Znak " << moja_litera << " wystapil "
<< ile << " razy" << '\n';
}
C:\>program
Wpisz ciag zankow zakonczony kropka [.]
aaa bbb cccc qwertyQWERTYPOLIPOLIpijesz? nie ojojojojoj.
Wyswietlam wyniki zliczania:
Znak a wystapil 10 razy
Znak b wystapil 10 razy
Znak c wystapil 10 razy
nazwa_obiektu.Funkcja(...); /* lub */
nazwa_klasy::Funkcja(...);
class Licznik
{
...
static void Pokazuj(void);
...
}
- 309-
LEKCJA 31. PRZEKAZANIE OBIEKTÓW JAKO ARGUMENTÓW DO FUNKCJI.
________________________________________________________________
W trakcie tej lekcji poznasz sposoby manipulowania obiektami
przy pomocy funkcji. Poznasz także trochę dokładniej referencje.
________________________________________________________________
class Licznik
{
public:
char moja_litera;
int ile;
Licznik(char litera);
void Skok_licznika();
};
main()
{
Licznik licznik_a('a');
...
Nazwa klasy spełnia dokładnie taką samą rolę jak każdy inny typ
danych. W naszym przypadku będzie to wyglądać tak:
void Pokazuj(Licznik);
- 310-
będzie wyglądać tak:
Pokazuj(licznik_a);
[P110.CPP]
# include "ctype.h"
# include "iostream.h"
class Licznik
{
public:
char moja_litera;
int ile;
Licznik(char);
void Skok_licznika();
};
void Pokazuj1(Licznik);
- 311-
int Pokazuj2(Licznik);
void main()
{
/* inicjujemy licznik: -------------------------------*/
Licznik licznik_a('a');
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';
for(;;)
{
char znak;
cin >> znak;
if(znak == '.') break;
if (znak == licznik_a.moja_litera) licznik_a.Skok_licznika();
}
/* sprawdzamy: ----------------------------------------*/
Pokazuj1(licznik_a);
cout << '\n' << Pokazuj2(licznik_a);
Licznik::Licznik(char z)
{
moja_litera = z;
ile = 0;
}
void Licznik::Skok_licznika(void)
{
ile++;
}
[!!!]UWAGA:
________________________________________________________________
- 312-
Programy manipulujące obiektami w taki sposób mogą wymagać
modelu pamięci większego niż przyjmowany domyślnie model SMALL.
Typowy komunikat pojawiający się przy zbyt małym modelu pamięci
to:
części książki.
________________________________________________________________
O PROBLEMIE REFERENCJI.
a w Pascalu:
- 313-
inaczej. Funkcji zupełnie nie interesuje bieżąca wartść zmiennej
INPUT X i read(X);
Funkcja(X);
Jak widać:
bez zmian.
REFERENCJA - CO TO TAKIEGO ?
# include "iostream.h"
main()
- 314-
{
int zmienna;
int& ksywa;
...
[P111.CPP]
# include "iostream.h"
main()
{
int zmienna = 6666;
int& ksywa = zmienna;
return 0;
}
C:\>program
Zmienna Ksywa
6666 6666
6666 6666
6766 6766
6866 6866
6966 6966
7066 7066
- 315-
zastosowania: określenie adresu w pamęci oraz tworzenie
wskazania. Aby rozróżnić te dwie sytuacje zwróć uwagę na
"gramatykę" zapisu. Jeśli identyfikator zminnej jest poprzedzony
p = &zmienna;
nazwa_funkcji(const &nazwa_obiektu);
________________________________________________________________
[P112.CPP]
# include "iostream.h"
main()
{
int zmienna = 6666;
int& ksywa = zmienna;
return 0;
}
- 316-
Zmienna (ADR-hex) Ksywa (ADR-hex):
0x287efff4 0x287efff4
- 317-
LEKCJA 32. WSKAŹNIKI DO OBIEKTÓW.
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak posługiwać się obiektami
za pośrednictwem wskaźników.
________________________________________________________________
class Licznik
{
public:
char moja_litera;
int ile;
Licznik(char znak) { moja_litera = z; ile = 0; }
void Skok_licznika(void) { ile++; }
};
Licznik *p;
p->Skok_licznika();
p = &Obiekt;
[P119.CPP]
# include "ctype.h"
# include "iostream.h"
class Licznik
{
public:
char moja_litera;
int ile;
Licznik(char z) { moja_litera = z; ile = 0; }
- 318-
void Skok_licznika(void) { ile++; }
};
void main()
{
char znak;
cout << "\nPodaj litere do zliczania: ";
cin >> znak;
- 319-
wątpliwości zidentyfikować właśnie ten obiekt, z którym pracuje
a nie obiekt przypadkowy.
class Klasa
{
int dane;
...
}
class Klasa
{
int dane;
public:
void Pokazuj();
...
}
void Klasa::Pokazuj(void)
{
cout << dane;
}
void Klasa::Pokazuj(void)
{
cout << this->dane;
}
- 320-
LEKCJA 33. OVERLOADING OPERATORÓW.
________________________________________________________________
Podczas tej lekcji poznasz możliwości dostosowania operatorów
C++ do własnego "widzimisię" i do potrzeb własnych obiektów.
________________________________________________________________
nowy, lecz pełnoprawny typ danych. Autorzy C++ nie byli w stanie
mnożyć, czy odejmować np. liczby int, long, float itp., nie wie
jednak jak dodać do siebie obiekty klas CString (CString = Class
class CString x, y, z; z = x + y;
- 321-
operacji mnożenia wymaga od operatora * podjęcia różnych
działań:
class Liczba_zespolona x, y, z; z = x * y;
int x, y, z; z = x * y;
operator+();
operator*();
to:
. :: .* ?:
- 322-
Zaczniemy od operatora + należącego do grupy "dwuargumentowych
operatorów arytmetycznych" (ang. binary arithmetic operator).
Zwracamy tu już na początku rozważań uwagę na przynależność
operatora do określonej grupy, ponieważ overloading różnych
opertorów należących do tej samej grupy przebiega podobnie.
Ponieważ znak + może być także operatorem jednoargumentowym
(ang. unary plus, o czym za chwilę), podkreślamy, że tym razem
chodzi o plus jako operator dodawania. Overloading operatora
przeprowadzimy w stosunku do obiektów prostej, znanej Ci już z
poprzednich przykładów klasy Data, którą (w celu upodobnienia
się do maniery stosowanej w Windows i bibliotekach klas)
nazwiemy tym razem CData. "Namówimy" operator + do
przeprowadzenia operacji na obiektach (dokładniej na polach
obiektów):
[P120.CPP]
# include <iostream.h>
class CData
{
int dz, mc, rok;
public:
CData() {} //Konstruktor domyslny (pusty)
CData(int d, int m, int y) { mc = m; dz = d; rok = y; }
void Pokazuj() { cout << dz << '.' << mc << '.' << rok; }
CData operator+(int); //TU! overloading operatora +
};
CData CData::operator+(int n)
{
CData kopia_obiektu = *this;
n += kopia_obiektu.dz;
while (n > TAB[kopia_obiektu.mc-1])
- 323-
{
n -= TAB[kopia_obiektu.mc-1];
if (++kopia_obiektu.mc == 13)
{ kopia_obiektu.mc = 1; kopia_obiektu.rok++; }
}
kopia_obiektu.dz = n;
return (kopia_obiektu);
}
main()
{
CData staradata(31, 1, 94); //Kostruktor z argumentami
CData nowadata; //Pusty konstruktor
cout << "\n Stara data: ";
staradata.Pokazuj();
cout << "\n Podaj ile minelo dni --> ";
int n;
cin >> n;
nowadata = staradata + n;
cout << "\n Jest zatem --> ";
nowadata.Pokazuj();
return 0;
}
CData CData::operator+(int n)
{
CData kopia_obiektu = *this;
...
return (kopia_obiektu);
}
Funkcja
* została zdefiniowana dla obiektów klasy CData (z innymi
postępować nie potrafi);
Jeśli operator + zostanie umieszczony pomiędzy obiektem klasy
CData, a liczbą typu int:
.... staradata + n;
* funkcja pobiera liczbę n jako argument (jawnie);
* funkcja pobiera obiekt klasy CData jako swój drugi argument
(niejawnie, dzięki pointerowi this);
* funkcja zwróci obiekt klasy CData (ze zmodyfikowanym polem);
- 324-
nowadata = staradata + 14;
nowadata = 14 + staradata;
aby działanie:
class CData
{
int dz, mc, rok;
public:
CData() {}
CData(int d, int m, int y) { mc = m; dz = d; rok = y; }
void Pokazuj() { cout << dz << '.' << mc << '.' << rok; }
/* Dwie funkcje operatorowe: ------------------------------ */
CData operator+(int);
friend CData operator+(int, CData&);
};
- 325-
zawiera:
* prywatne dane;
* dwa konstruktory;
* własną metodę - funkcję operatorową operator+();
* deklarację zaprzyjaźnionej z klasą funkcji kategorii friend
(choć jest to funkcja o tej samej nazwie, jej status i
uprawnienia są nieco inne).
class CData
{
int dz, mc, rok;
public:
...
CData operator+(int);
friend CData operator+(int n, CData& x) { return (x + n); }
};
[P121.CPP]
# include "iostream.h"
class CData
{
int dz, mc, rok;
public:
CData() {}
CData(int d, int m, int y) { mc = m; dz = d; rok = y; }
void Pokazuj() { cout << dz << '.' << mc << '.' << rok; }
CData operator+(int);
friend CData operator+(int n, CData& x) { return (x + n); }
};
- 326-
static int TAB[] = {31,28,31,30,31,30,31,31,30,31,30,31};
CData CData::operator+(int n)
{
CData kopia_obiektu = *this;
n += kopia_obiektu.dz;
while (n > TAB[kopia_obiektu.mc-1])
{
n -= TAB[kopia_obiektu.mc-1];
if (++kopia_obiektu.mc == 13)
{ kopia_obiektu.mc = 1; kopia_obiektu.rok++; }
}
kopia_obiektu.dz = n;
return (kopia_obiektu);
}
main()
{
CData staradata(31, 1, 94); //Kostruktor z argumentami
CData nowadata, jeszczejednadata;
cout << "\n Stara data: ";
staradata.Pokazuj();
cout << "\n Podaj ile minelo dni --> ";
int n;
cin >> n;
nowadata = staradata + n;
cout << "\n Jest zatem --> ";
nowadata.Pokazuj();
cout << "\n Testuje nowy operator: ";
jeszczejednadata = (1+n) + staradata;
jeszczejednadata.Pokazuj();
return 0;
}
C:\>program
Stara data: 31.1.94
Podaj ile minelo dni --> -10
Jest zatem --> 21.1.94
Testuje nowy operator: 22.1.94
lub tak:
C:\>program
Stara data: 31.1.94
Podaj ile minelo dni --> -150
- 327-
Jest zatem --> -119.1.94
Testuje nowy operator: -118.1.94
class Klasa
{
...
} x, y, z;
...
- 328-
z = x + y;
z = q = x + y;
class Licznik
{
public:
char moja_litera;
int ile;
Licznik(char);
Licznik operator++();
};
obiekt.ile // Licznik::ile;
Licznik Licznik::operator++(void)
{
this->ile++;
return (*this);
}
- 329-
Ponieważ funkcja operatorowa jest metodą zadeklarowaną wewnątrz
klasy, bez problemu uzyska dostęp do wewnętrznych pól obiektów
tej klasy i wykona inkrementację licznika. Możemy zatem
zastosować wyrażenie typu:
Licznik Licznik::operator++(void)
{
ile++;
return (*this);
}
class Licznik
{
public:
char moja_litera;
int ile;
Licznik(char z) { ile = 0; moja_litera = z; }
Licznik operator++() { ile++; return (this); }
};
[P121.CPP]
/* --------------------- POST - inkrementacja ----------- */
# include "iostream.h"
class Licznik
{
public:
int ile;
Licznik() { ile = 0;}
Licznik operator++() { ile++; return (*this); }
} obiekt;
void main()
{
cout << "\n Wpisz kilka znakow: ";
char znak;
for(;;)
{
cin >> znak;
if(znak == '.') break;
obiekt++;
}
- 330-
cout << "\n Wpisales " << obiekt.ile << " znakow";
}
[P122.CPP]
class Licznik
{
public:
int ile;
Licznik() { ile = 0;}
Licznik operator+(int n = 1)
{ this->ile += n; return (*this); }
Licznik friend operator++(Licznik& x)
{ x + 1; return (x); }
} obiekt;
void main()
{
cout << "\n Wpisz kilka znakow: ";
char znak;
for(;;)
{
cin >> znak;
if(znak == '.') break;
++obiekt;
}
cout << "\n Wpisales " << obiekt.ile << " znakow";
cout << "\n I dodamy jeszcze sto! --> ";
obiekt + 100;
cout << obiekt.ile;
}
[P123.CPP]
# include "conio.h"
# include "iostream.h"
- 331-
class Licznik
{
public:
char moja_litera;
int ile;
Licznik() { ile = 0; } //Pusty konstruktor
Licznik(char);
Licznik operator++(); //Funkcja pre/post-inkrementacji
Licznik operator--(); //Funkcja pre/post-dekrementacji
};
void main()
{
Licznik obiekt1('A'), obiekt2; //obiekt2 - "pusty"
if(obiekt1.ile == 0) break;
OVERLOADING OPERATORA !
[P124.CPP]
# include <iostream.h>
class Liczba
- 332-
{
public:
long wartosc;
Liczba(int x) { wartosc = (long) x; }
friend void operator!(Liczba&);
};
int x;
main()
{
for(int k = 0; k < 5; k++)
{
cout << "\n Podaj liczbe --> ";
cin >> x;
Liczba a(x);
cout << "\n Silnia wynosi: ";
!a;
}
return 0;
}
z !a; na a!=a;
- 333-
cout << '\n' << wynik;
}
[P125.CPP]
# include "fstream.h"
void main()
{
ofstream plik("dane.tst");
plik << "To jest zawartosc pliku";
}
[P126.CPP]
# include "fstream.h"
void main()
{
ofstream plik("dane.tst");
plik << "To jest zawartosc pliku" << " i jeszcze cosik.";
}
- 334-
overloadingowi operator << . Niedowiarek mógłby w tym momencie
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:
# include "fstream.h"
void main()
{
ofstream plik("dane.tst", ios::app);
plik << " Dopiszemy do pliku jeszcze i to...";
}
[Z]
________________________________________________________________
1. Wykonaj samodzielnie overloading dowolnego operatora.
________________________________________________________________
- 335-
LEKCJA 34. O ZASTOSOWANIU DZIEDZICZENIA.
________________________________________________________________
Z tej lekcji dowiesz się, do czego w praktyce programowania
szczególnie przydaje się dziedziczenie.
________________________________________________________________
class CBazowa1
{
public:
CBazowa1(...); //Konstruktor
};
class CBazowa2
{
public:
CBazowa2(...); //Konstruktor
};
- 336-
main()
{
Cpochodna Obiekt(...); //Wywolanie konstruktora
...
class CBazowa1
{
public:
CBazowa1(char znak) { cout << znak; }
};
class CBazowa2
{
public:
CBazowa2(char znak) { cout << znak; }
};
- 337-
gdzie:
lista - oznacza listę parametrów odpowiedniego konstruktora.
FUNKCJE WIRTUALNE.
w klasie CZwierzak:
class CZwierzak
{
public:
void Jedz();
virtual void Oddychaj();
};
class CZwierzak
{
public:
void Jedz();
virtual void Oddychaj() { cout << "Sapie..."; }
};
class CRybka
- 338-
char imie[30];
public:
void Oddychaj() { cout << "Nie moge sapac..."; }
} Sardynka;
[P127.CPP]
# include <iostream.h>
class CZwierzak
{
public:
void Jedz();
virtual void Oddychaj() {cout << "\nSapie...";}
};
class CRybka
char imie[30];
public:
void Oddychaj() {cout << "\nSardynka: A ja nie oddycham.";}
} Sardynka;
void main()
{
Ciapek.Oddychaj();
Sardynka.Oddychaj();
}
- 339-
wirtualnej w taki sposób, funkcja we wszystkich "pokoleniach"
musi mieć taki sam prototyp, tj. pobierać taką samą liczbę
parametrów tych samych typów oraz zwracać wartość tego samego
typu. Jeśli tak się nie stanie, C++ potraktuje różne prototypy
tej samej funkcji w kolejnych pokoleniach zgodnie z zasadami
overloadingu funkcji. Zwróćmy tu uwagę, że w przypadku funkcji
wirtualnych o wyborze wersji funkcji decyduje to, wobec którego
obiektu (której klasy) funkcja została wywołana. Jeśli wywołamy
funkcję dla obiektu Ciapek, C++ wybierze wersję
CZwierzak::Oddychaj(), natomiast wobec obiektu Sardynka zostanie
p = &Ciapek; p->Oddychaj();
...
p = &Sardynka; p->Oddychaj();
CZwierzak *p;
...
for(p = &Ciapek, int i = 0; i < 2; i++)
{
p->Oddychaj();
p = &Sardynka;
}
lub inaczej:
- 340-
Taki efekt nazywa się polimorfizmem uruchomieniowym (ang.
run-time polymorphism).
class CZwierzak
{
public:
void Jedz();
virtual void Oddychaj() {cout << "\nSapie...";}
};
CZwierzak *p;
- 341-
taki element klasy pochodnej, który nie został odziedziczony i
którego nie ma w klasie bazowej? Rozwiązanie jest proste -
wystarczy zarządać od C++, by chwilowo zmienił typ wskaźnika z
obiektów klasy bazowej na obiekty klasy pochodnej. W przypadku
funkcji Szczekaj() w naszym programie wyglądałoby to tak:
CZwierzak *p;
...
p->Oddychaj();
p->Szczekaj(); //ŹLE !
(CPiesek*)p->Szczekaj(); //Poprawnie
...
- 342-
LEKCJA 35. FUNKCJE WIRTUALNE i KLASY ABSTRAKCYJNE.
________________________________________________________________
W trakcie tej lekcji dowiesz się, co mawia żona programisty, gdy
O KLASACH ABSTRAKCYJNYCH.
class CZwierzak
{
...
public:
virtual void Oddychaj();
...
};
class CZwierzak
{
- 343-
...
public:
virtual void Oddychaj() = 0;
...
};
class CZwierzak
{
...
public:
virtual void Oddychaj() = 0;
...
};
class CZLOWIEK
{
public:
void Jedz(void);
virtual void Mow(void) = 0; //funkcja WIRTUALNA
};
- 344-
}
void Zona::Mow(void)
{
cout << "JA NIE MAM CO NA SIEBIE WLOZYC !!! ";
cout << "DLACZEGO KOWALSKI ZARABIA ZAWSZE WIECEJ NIZ TY ?!!!";
[P128.CPP]
#include "iostream.h"
class CZLOWIEK
{
public:
void Jedz(void);
virtual void Mow(void) = 0;
};
void Zona::Mow(void)
{
cout << "JA NIE MAM CO NA SIEBIE WLOZYC !!!";
cout << "DLACZEGO KOWALSKI ZARABIA ZAWSZE WIECEJ NIZ TY ?!!!";
main()
{
NIEMOWLE Dziecko;
Zona Moja_Zona;
Dziecko.Jedz();
Dziecko.Mow();
Moja_Zona.Mow()
- 345-
return 0;
}
CZLOWIEK Facet;
Facet.Jedz();
class CA
{
int liczba;
public:
CA() { liczba = 0; } //Konstruktor domyslny
CA(int x) { liczba = x; }
class CB
{
CA obiekt;
public:
CB() { obiekt = 1; }
};
- 346-
zgłoszenie na ekranie.
class CA
{
int liczba;
public:
CA() { liczba = 0; cout << "-> CA(), CA_O::liczba = 0 "; }
CA(int x) { liczba = x; cout << "->CA(int) "; }
void operator=(int n) { liczba = n; cout << "->operator "; }
};
class CB
{
CA obiekt;
public:
CB() { obiekt = 1; cout << "->Konstruktor CB() "; }
};
[P129.CPP]
# include "iostream.h"
class CA
{
int liczba;
public:
CA() { liczba = 0; cout << "-> CA(), CA_O::liczba = 0 "; }
CA(int x) { liczba = x; cout << "->CA(int) "; }
void operator=(int n) { liczba = n; cout << "->operator "; }
};
class CB
{
CA obiekt;
public:
CB() { obiekt = 1; cout << "->Konstruktor CB() "; }
};
main()
{
CB Obiekt;
return 0;
}
C:\>program
-> CA(), CA_O::liczba = 0 ->operator ->Konstruktor CB()
- 347-
Warning: Obiekt is never used...
class CBazowa
{
private:
int liczba;
public:
CBazowa() { liczba = 0}
CBazowa(int n) { liczba = n; }
};
[P130.CPP]
#include "iostream.h"
class CA
{
int liczba;
public:
CA() { liczba = 0; cout << "-> CA(), CA_O::liczba = 0 "; }
CA(int x) { liczba = x; cout << "->CA(int) "; }
void operator=(int n) { liczba = n; cout << "->operator "; }
};
class CB
{
CA obiekt;
public:
CB() : CA(1) {}
- 348-
};
main()
{
CB Obiekt;
return 0;
}
[P131.CPP]
# include "string.h"
# include "iostream.h"
class CLista
{
private:
char *poz_listy;
CLista *poprzednia;
public:
CLista(char*);
CLista* Poprzednia() { return (poprzednia); };
void Pokazuj() { cout << '\n' << poz_listy; }
void Dodaj(CLista&);
~CLista() { delete poz_listy; }
};
CLista::CLista(char *s)
{
poz_listy = new char[strlen(s)+1];
strcpy(poz_listy, s);
poprzednia = NULL;
}
main()
{
CLista *ostatni = NULL;
cout << '\n' << "Wpisanie kropki [.]+[Enter] = Quit \n";
for(;;)
{
cout << "\n Wpisz nazwe (bez spacji): ";
- 349-
char TAB[70];
cin >> TAB;
if (strncmp(TAB, ".", 1) == 0) break;
CLista *lista = new CLista(TAB);
if (ostatni != NULL)
ostatni->Dodaj(*lista);
ostatni = lista;
}
- 350-
LEKCJA 36. KAŹDY DYSK JEST ZA MAŁY, A KAŹDY PROCESOR ZBYT
WOLNY...
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak komputer dysponuje swoimi
zasobami w środowisku tekstowym (DOS).
________________________________________________________________
zasoby to:
* czas mikroprocesora i
* miejsce w pamięci operacyjnej.
* Small - mały,
* Medium - średni,
* Compact - niewielki (tu mam wątpliwość, może "taki sobie" ?),
* Large - duży,
* Huge - jeszcze większy, odległy.
* Tiny - najmniejszy.
- 351-
ale najmniej pojemny. Model Huge - odwrotnie - najpojemniejszy,
za to najwolniejszy. Model Tiny powoduje ustawienia wszystkich
rejestrów segmentowych mikroprocesora na tę samą wartość
(początek tej samej stronicy pamięci) i umieszczenie wszystkich
zasobów programu wewnątrz wspólnego obszaru pamięci o wielkości
nie przekraczającej 64 KB. Wszystkie skoki są wtedy "krótkie", a
huge *p;
...
near *ptr; //Bliski pointer
...
near int Funkcja(...) //Bliska funkcja
{
...
- 352-
}
#define ILE (1024*640)
IDENTYFIKACJA KLAWISZY.
#include "bios.h"
#include "ctype.h"
#include "stdio.h"
#include "conio.h"
- 353-
klawisz = bioskey(0);
modyfikatory = bioskey(2);
if (modyfikatory)
{
printf("\n");
if (modyfikatory & RIGHT) printf("RIGHT");
if (modyfikatory & LEFT) printf("LEFT");
if (modyfikatory & CTRL) printf("CTRL");
if (modyfikatory & ALT) printf("ALT");
printf("\n");
}
/* drukujemy pobrany klawisz */
if (isalnum(klawisz & 0xFF))
printf("'%c'\n", klawisz);
else
printf("%#02x\n", klawisz);
}
[P131.CPP]
# include "stdio.h"
# include "conio.h"
void Odczyt(void)
{
z2 = '\0';
z1 = getch();
if (z1 == '\0') z2 = getch();
}
main()
{
clrscr();
- 354-
printf("\nKropka [.] = Quit");
printf("\nRozpoznaje klawisze [F1] ... [F3] \n\n");
for (;;)
{
while(!kbhit());
Odczyt();
if (z1 == '.') break;
if (z1 != '\0') printf("\nZnak: %c", z1);
else
switch (z2)
{
case ';' : printf("\n F1"); break;
case '<' : printf("\n F2"); break;
case '=' : printf("\n F3"); break;
default : printf("\n Inny klawisz specjalny!");
}
}
return 0;
}
Strzałki kursora:
LeftArrow K 75
- 355-
RightArrow M 77
UpArrow H 72
DownArrow P 80
[P132.CPP]
# include <stdlib.h>
# include <conio.h>
# pragma inline
main()
{
clrscr();
for (; !kbhit(); )
{
int x = rand() % 40;
int y = rand() % 12;
SpeedBox(x, y, (80 - x), (24 - y), ('€' + x % 50));
}
return 0;
}
void SpeedBox(int x1, int y1, int x2, int y2, char znak)
{
int k;
[Z]
________________________________________________________________
1. Opracuj program pozwalający porównać szybkość wyprowadzania
- 356-
danych na ekran monitora różnymi technikami (cout, puts(),
printf(), asm).
2. Porównaj wielkość plików wynikowych .EXE powstających w
różnych wariantach z poprzedniego zadania.
________________________________________________________________
- 357-
LEKCJA 37. O C++, Windows i małym Chińczyku.
czyli:
KTO POWIEDZIAŁ, ŻE PROGRAMOWANIE DLA WINDOWS JEST TRUDNE?!!!
UWAGA!
Pierwsza typowa aplikacja dla Windows napisana w BORLAND C++ 3/4
#include <iostream.h>
void main()
{
cout <<"Pierwsza Aplikacja dla Windows";
}
I już!
Niedowiarek zapyta: - I TAKIE COŚ CHODZI POD Windows???
- 358-
TAK!.
Dlatego też mimo ogromnego wysiłku prawie NIKOMU nie udaje się
biegle nauczyć chińskiego - z jednym wyjątkiem - wyjątkiem
małego Chińczyka. Dlaczego? To proste. Mały Chińczyk po prostu o
- 359-
.RH .ICO .BMP
[!!!]UWAGA!
________________________________________________________________
- 360-
Skoro ustawiliśmy już poprawnie najważniejsze dla nas parametry
konfiguracyjne - możemy przystąpić do uruchomienia pierwszej
aplikacji dla Windows.
Pojawi się okienko dialogowe "Save File As" (zapis pliku pod
wybraną nazwą i w wybranym miejscu).
[P133.CPP]
#include <iostream.h>
void main()
{
cout << " Pierwsza Aplikacja " << " Dla MS Windows ";
}
- 361-
W okienku komunikatów (Messages) powinien pojawić się w trakcie
konsolidacji komunikat ostrzegawczy:
[ OK ]
w wersji 3.1:
D:\KATALOG\WIN1.EXE
- 362-
wyposażone w:
C\>WIN A:\WIN1.EXE[Enter]
- 363-
zażądaliśmy, by okno programu było zawsze "na wierzchu" (on top)
#include <stdio.h>
void main()
{
printf(" Pierwsza Aplikacja \n Dla MS Windows ");
}
PODSUMUJMY:
- 364-
* Jeśli korzystamy wyłącznie ze standardowych zasobów środowiska
- 365-
LEKCJA 38. KORZYSTAMY ZE STANDARDOWYCH ZASOBÓW Windows.
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak korzystać z zasobów
Windows bez potrzeby wnikania w wiele szczególów technicznych
interfejsu aplikacji - Windows API.
________________________________________________________________
________________________________________________________________
UWAGA:
Niestety nie wszystkie tradycyjne funkcje typu printf(),
scanf(), gets() itp. zostały zaimplementowane dla Windows!
Pisząc własne programy możesz przekonać się o tym dzięki opisowi
char *p ...
LPSTR p ...
- 366-
/* WIN2.CPP: */
/* - Tablica dwuwymiarowa
- Wskazniki do elementów tablicy */
#include <windows.h>
#include <iostream.h>
#include <stdio.h>
void main()
{
printf(p1);
for (i = 0; i < 10; i++)
{
for (j = 0; j < 10; j++)
{ T[i][j] = (i + 1)*(j + 1);
if (T[i][j] < 10) cout << T[i][j] << spacja << spacja;
else
cout << T[i][j] << spacja;
}
cout << '\n';
}
printf(p2);
pT = &T[0][0];
for (k = 0; k < 10*10; k++)
{
if (*(pT+k) < 10) cout << *(pT + k) << spacja << spacja;
else
cout << *(pT + k) << spacja;
if ((k + 1)%10 == 0) cout << '\n';
}
printf(p3);
getchar();
}
APLIKACJE DWUPOZIOMOWE.
- 367-
Zastosujemy teraz najprostszy typ okienka dialogowego - okienko
kamunikatów (Message Box), nasze następne aplikacje mogą być już
stosowne działania.
/* WINR1.CPP: */
/* Stadium 1: Dwa okienka w jednym programie */
# include <stdio.h>
# include <windows.h>
void main()
{
printf(" Start: Piszemy w glownym oknie \n");
printf(" ...nacisnij cosik...");
getchar();
MessageBox(0, p1, p2, 0);
printf("\n\n\n Hello World dla WINDOWS!");
printf("\n\t...dowolny klawisz... ");
getchar();
}
- 368-
wpisujemy 0
LPCSTR lpszText - daleki wskaźnik do łańcucha tekstowego
wewnątrz okienka.
LPCSTR lpszTitle - daleki wskażnik do łańcucha tekstowego -
tytułu okienka komunikatu.
UINT Style - UINT = unsigned int; numer określający zawartość
okienka.
int Return Value - identyfikator klawisza, który wybrał
użytkownik w okienku komunikatu.
[!!!] UWAGA
________________________________________________________________
Deklaracje wskaźników do tekstów powinny wyglądać tak:
LPCSTR p1 = "Napis1", p2 = "Tekst2";
ale C++ może samodzielnie dokonać forsowania typów i zamienić
typ char* na typ LPCSTR (lub LPSTR).
________________________________________________________________
/* WINR2.CPP: */
/* Stadium 2: Dwa okienka ze zmienną zawarością */
# include <windows.h>
# include <stdio.h>
void main()
{
printf("\n\n\n Hello World dla WINDOWS!");
printf("\n AUTOR: ...................");
/* WINR3.CPP: */
/* Stadium 3: Dwa okienka sterują pętlą */
- 369-
# include <windows.h>
# include <stdio.h>
void main()
{
printf("\n\n\n Hello World dla WINDOWS!");
printf("\n AUTOR: ...................");
int Numer;
...
Numer = MessageBox(0, p2, p1, MB_ICONSTOP | MB_OKCANCEL);
printf("\nKlawisz [OK] ma numer: %d", Numer);
if(Numer == IDOK) ...
- 370-
oznacza umieszczenie ikony STOP i klawiszy [OK] i [Anuluj]. Kod
zwracany przez funkcję może być wykorzystywany we wszelkich
konstrukcjach warunkowych (switch, case, for, while, if-else,
itp.).
/* WINR4.CPP: */
/* Stadium 4: Okienka sterują 2 pętlami, przybywa zasobów. */
# include <windows.h>
# include <stdio.h>
main()
{
printf("\n\n\n Grafoman dla WINDOWS!");
printf("\n AUTOR: (jak wyzej)");
puts("_____________________________\n");
do
{
for( int i = 0; i < 5; i++)
{
p2 = &napisy[i][0];
if( MessageBox(0, p2, p1, MB_ICONSTOP | MB_OKCANCEL) == IDOK)
printf("\n %s", napisy[i]);
else
printf("\n ...?");
}
} while
(MessageBox(0,p3,p4,MB_ICONQUESTION | MB_OKCANCEL)==IDCANCEL);
return 0;
}
- 371-
MainWindow <-----> MessageBox
/* WINR5.CPP: */
/* Stadium 5: Zmiana wielkości i nazwy okienka. */
# include <windows.h>
# include <iostream.h>
# include <string.h>
main()
{
cout << "\n\n\n Grafoman dla WINDOWS!";
cout << "\n AUTOR: (jak wyzej)";
cout << "\n_____________________________\n";
p0 = &tytul[0];
do
{
for( int i = 0; i < 5; i++)
- 372-
{
p2 = &napisy[i][0];
strcat(p0, p2);
int decyzja = MessageBox(0, p1, p0, MB_ICONHAND |
MB_ABORTRETRYIGNORE);
if (decyzja == IDABORT) break;
else
if (decyzja == IDRETRY)
{
cout << "\n " << napisy[i];
i--;
}
else
if (decyzja == IDIGNORE)
{
cout << "\n ...?";
continue;
}
}
} while
(MessageBox(0, p3, p4, MB_ICONQUESTION | MB_OKCANCEL) ==
IDCANCEL);
return 0;
}
[!!!]UWAGA
________________________________________________________________
Okienka mogą być "modalne" i "nie-modlane". Okienko "modalne" to
- 373-
LEKCJA 39. STRUKTURA PROGRAMU PROCEDURALNO - ZDARZENIOWEGO
PRZEZNACZONEGO DLA WINDOWS.
________________________________________________________________
W trakcie tej lekcji poznasz ogólną budowę interfejsu API
Windows i dowiesz się, co z tego wynika dla nas - autorów
programów przeznaczonych dla Windows.
________________________________________________________________
- 374-
ID_... - IDentifier - IDentyfikator
MB_... - Message Box - elementy okienka komunikatów
Notacja węgierska
________________________________________________________________
Prefix Skrót ang. Znaczenie
________________________________________________________________
a array tablica
b bool zmienna logiczna (0 lub 1)
by unsigned char znak (bajt)
c char znak
cb count of bytes liczba bajtów
cr color reference value określenie koloru
cx, cy short (count x, y len.) x-ilość, y-długość (short)
dw unsigned long liczba długa bez znaku
double word podwójne słowo
fn function funkcja
pfn pointer to function wsk. do funkcji
h handle "uchwyt" - identyfikator
i integer całkowity
id identifier identyfikator
n short or int krótki lub całkowity
np near pointer wskaźnik bliski
p pointer wskaźnik
l long długi
lp long pointer wskaźnik typu long int
lpfn l. p. to function daleki wskaźn. do funkcji
s string łańcuch znaków
sz string terminated '\0' łańcuch ASCIIZ
tm text metric miara tekstowa
w unsigned int (word) słowo
x,y short x,y coordinate współrzędne x,y (typ: short)
________________________________________________________________
- 375-
że za przebieg wykonania programu nie jest odpowiedzialny tylko
programista lecz część tej odpowiedzialności przejmuje
użytkownik i to on decyduje w jaki sposób przebiega wykonanie
programu. Użytkownik może wybrać w dowolnym momencie dowolną
spośród wszystkich oferowanych mu opcji a program powinien
zawsze zareagować poprawnie i równie szybko. Jest oczywiste, że
pisząc program nie możemy przewidzieć w jakiej kolejności
użytkownik będzie wybierał opcje/rozkazy z menu. Przeciwnie
powiniśmy napisać program w taki sposób by dla każdego rozkazu
istniał oddzielny kod. Jest to ogólna koncepcja, na której
opiera się programowanie zdarzeniowe.
Funkcja_Obsługi_Komunikatów_o_Zdarzeniach(komunikat)
{
switch (komunikat_od_Windows)
{
case WM_CREATE:
...
TextOut(0, 0, "Napis: np. Hello world.", dlugosc_tekstu);
break;
...
case WM_CLOSE: // CLOSE - zamknąć okno
.... break;
..................... itd.
}
void TMainWindow::RysujOkno()
{
TString Obiekt_napis = "Hello, World";
int dlugosc_tekstu = sizeof(Obiekt_napis);
TextOut(DC, 10, 10, Obiekt-napis, dlugosc_tekstu);
}
- 376-
FUNKCJE WinMain() i WindowProc().
________________________________________________________________
UWAGA:
Funkcji WindowProc() można nadać dowolną nazwę, ale WinMain()
musi się zawsze nazywać WinMain(). Jest to nazwa zastrzeżona
podobnie jak main() dla aplikacji DOSowskich.
________________________________________________________________
w Pascalu).
________________________________________________________________
UWAGA:
Prototyp funkcji może zostać podany również tak:
- 377-
Pierwszy parametr hWnd jest to tzw. identyfikator okna (ang.
window handle). Ten parametr zawiera informację, dla którego
okna przeznaczony jest komunikat. Zastosowanie takiego
identyfikatora jest celowe, ponieważ funkcje typu WindowProc()
mogą obsługiwać przesyłanie komunikatów do wielu okien. Jeśli
okien jest wiele, okno jest identyfikowane przy pomocy tego
właśnie identyfikatora (numeru).
- 378-
case WM_SETFOCUS:
SetFocus(hEditWnd);
break;
- 379-
break;
default: /* wariant domyślny: standardowa obsługa
.... przez standardową funkcję Windows */
}
}
________________________________________________________________
UWAGA:
Ponieważ komunikatów "interesujących" daną aplikację może być
ponad 100 a sposobów reakcji użytkownika jeszcze więcej, w
"poważnych" aplikacjach tworzone są często struktury decyzyjne o
- 380-
WinMain().
- 381-
while(GetMessage(&msg,NULL,0,0)) //Poki nie otrzymamy WM_QUIT
{
....
}
- 382-
rysować własnego okna.
[Z]
________________________________________________________________
1. Uruchom Windows i popatrz świadomym, fachowym okiem, jak
przebiega przekazywanie aktywności (focus) między okienkami
aplikacji.
________________________________________________________________
- 383-
LEKCJA 40. JAK TWORZY SIĘ APLIKACJĘ DLA Windows?
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak "poskładać" aplikację dla
Windows z podstawowych funkcji interfejsu API i jakie komunikaty
są najważniejsze dla naszych aplikacji.
________________________________________________________________
PAINSTRUCT ps;
PAINTSTRUCT ps;
{
switch (Message)
{
case WM_CREATE:
..... break;
case WM_MOVE:
- 384-
.... break;
case WM_SIZE:
.... break;
case WM_CLOSE:
.... break;
default: .....
}
}
case WM_PAINT:
memset(&ps, 0x00, sizeof(PAINTSTRUCT));
hDC = BeginPaint(hWnd, &ps);
....
- 385-
Górny lewy róg nieaktualnego prostokąta (invalid rectangle) ma
dwie współrzędne (left, top) a dolny prawy róg prostokąta ma
współrzędne (right, bottom). Te współrzędne ekranowe mierzone są
case WM_PAINT:
memset(&ps, 0x00, sizeof(PAINTSTRUCT));
hDC = BeginPaint(hWnd, &ps);
....
case WM_PAINT:
...
TextOut(hDC, 0, 0, (LPSTR) "Tekst", strlen("Tekst"));
EndPaint(hWnd, &ps);
break;
- 386-
Funkcja MainWin() rejestruje i tworzy główne okno programu oraz
inicjuje globalne zmienne i struktury. Funkcja WinMain() zawiera
- uruchomienia programu.
danej aplikacji
LPSTR lpszCmdLine - daleki wskaźnik do parametrów wywołania
programu z linii rozkazu
int nCmdShow - sposób początkowego wyświetlenia okna
MSG msg;
if(!PrevInstance)
{
if((int nRc = RegisterClass() ...
hWndMain = CreateWindow(....);
if(hWndMain == NULL)
- 387-
{
MessageBox(0, "Klops", "Koniec", MB_OK);
return (FALSE);
}
ShowWindow(hWndMain, nCmdShow);
while(GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
LONG lParam)
{
HMENU hMenu=0; /* Identyfikator menu */
HBITMAP hBitmap=0; /* Identyfikator mapy bitowej */
HDC hDC; /* Identyfikator kontekstowy */
PAINSTRUCT ps; /* Struktura rysunku */
int nRc=0; /* Zwrot kodu przez funkcje */
switch (message)
- 388-
{
case WM_CREATE:
typedef struct {
LPSTR lpCreateParams;
HANDLE hInst;
HANDLE hMenu;
HWND hwndParent;
int cy;
int cx;
int y;
int x;
LONG style;
LPSTR lpszName;
LPSTR lpszClass;
DWORD dwExStyle;
} CREATESTRUCT; */
case WM_PAINT:
SetBkMode(hDC, TRANSPARENT);
- 389-
Funkcja TextOut() pracuje w trybie graficznym, więc (podobnie
jak inne funkcje graficzne Windows API) otrzymuje jako argument
tzw. "kontekst urządzenia" - hDC.
Zamykanie okna:
case WM_CLOSE:
DestroyWindow(hWnd);
if (hWnd == hWndMain)
PostQuitMessage(0);
default:
return (DefWindowProc(hWnd, Message, wParam, lParam));
int FRegisterClasses(void)
{
WNDCLASS wndclass; /* Struktura do definiowania klas okien. */
memset(&wndclass, 0x00, sizeof(WNDCLASS));
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = LoadIcon(NULL, ID_ICON);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
- 390-
if (!RegisterClass(&wndclass)) return -1;
}
HBRUSH Pędzel; i
HPEN Ołówek;
- 391-
LEKCJA 41. KOMPILATORY "SPECJALNIE DLA Windows".
________________________________________________________________
Z tej lekcji dowiesz się, czym różnią się kompilatory
przeznaczone dla pracy w środowisku Windows.
________________________________________________________________
- 392-
Options | Compiler | Code generation --> Code Generation Options
[!!!]UWAGA
________________________________________________________________
if (hPrevInstance == 0)
{
Okno1.style= CS_HREDRAW | CS_VREDRAW ;
Okno1.lpfnWndProc= WndProc;
Okno1.cbClsExtra = 0;
Okno1.cbWndExtra= 0;
Okno1.hInstance = hInstance;
Okno1.hCursor = LoadCursor(0, IDC_CROSS );
- 393-
Okno1.hbrBackground= GetStockObject(WHITE_BRUSH );
Okno1.lpszMenuName= 0;
Okno1.lpszClassName= LongPtr1;
if (!RegisterClass(&Okno1))
return 0;
}
ShowWindow(NrOkna, nCmdShow);
UpdateWindow(NrOkna);
switch(KomunikatWindows)
{
case WM_PAINT:
{
NrKontekstu = BeginPaint(NrOkna, &struktura_graficzna);
GetClientRect(NrOkna, &prostokat);
TextOut(NrKontekstu,80,50, ": Reczne sterowanie:", 20 );
TextOut(NrKontekstu, 5,70, "Tu -->", 6);
TextOut(NrKontekstu, 5, 85, "Blad:", 5);
TextOut(NrKontekstu,75,70, "-----------------------------",
40);
TextOut(NrKontekstu,30,110, "Programowanie proceduralno -
zdarzeniowe.", 41 );
TextOut(NrKontekstu,30,135, "Szablon moze zostac rozbudowany
o inne funkcje.", 47 );
TextOut(NrKontekstu,30,180, "RECZNIE panujemy np. nad:", 25
);
TextOut(NrKontekstu,20,220, "paskiem tytulowym okna, tytulem
ikonki...", 41);
- 394-
TextOut(NrKontekstu, 100, 250, "!KONIEC - [Alt]+[F4]", 20);
EndPaint(NrOkna,&struktura_graficzna);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(NrOkna,KomunikatWindows,wParam,lParam);
}
return 0;
}
Program WINZ-2.CPP
________________________________________________________________
#include <windows.h>
#include <string.h>
#pragma argused
char napis[10];
int X, Y;
- 395-
Myszki";
if (!hPrevInstance)
{
wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra= 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = 0;
wndClass.hCursor= LoadCursor(0, IDC_ARROW );
wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
wndClass.lpszMenuName= 0;
wndClass.lpszClassName= Lp1;
if (!RegisterClass(&wndClass))
exit(1);
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
- 396-
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
TextOut(hDC, X,Y, napis, strlen(napis));
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
strcpy(napis,"<-- Tu !");
X = LOWORD(lParam);
Y = HIWORD(lParam);
InvalidateRect(hWnd, 0, TRUE);
UpdateWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0); break;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
}
return 0;
}
X = LOWORD(lParam);
słowa).
Y = HIWORD(lParam);
w nowym miejscu.
PROJEKT.
- 397-
Kompilacja przebiegnie poprawnie (pamiętaj o Opcjach i
Katalogach), mimo to pojawią się jednak dwa komunikaty
ostrzegawcze. W okienku "Compile Status" (stan/przebieg
kompilacji) pojawi się zawartość:
- 398-
EXETYPE WINDOWS // <-- EXE dla Windows
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 4096 // <-- sterta 4 KB
STACKSIZE 5120 // <-- stos 5 KB
_______________________________________________________________
UWAGA:
W przypadku tworzenia bibliotek .DLL dane muszą mieć status
SINGLE (pojedyncze) zamiast MULTIPLE (wielokrotne). Użycie tu
słowa MULTIPLE pozwoli nam na wielokrotne uruchamianie
aplikacji.
________________________________________________________________
- 399-
7. Wpisujemy nazwę kolejnego pliku wchodzącego w skład projektu
(w tym przypadku WINZ2.DEF).
8. Wybieramy klawisz [+Add] w okienku.
UWAGA: Czynności 7) i 8) w przypadku bardziej złożonych
projektów będą powtarzane wielokrotnie.
9. Wybieramy klawisz [Done] w okienku (zrobione/gotowe).
Konfigurowanie projektu zostało zakończone.
10. Przy pomocy rozkazów Compile, Link, Make, Build all, Run
możemy teraz skompilować, skonsolidować i uruchomić nasz program
[!!!]UWAGA
________________________________________________________________
*.CPP
*.DEF
*.PRJ (lub *.IDE)
[!!!] UWAGA
________________________________________________________________
- 400-
LEKCJA 42. Elementy sterujące i zarządzanie programem.
________________________________________________________________
Jak sterować pracą aplikacji. Jak umieszczać elementy
graficzne-sterujące w oknie aplikacji. Najczęściej stosowane
funkcje API Windows.
________________________________________________________________
- 401-
BS_CHECKBOX - - prostokątny przełącznik [X]
włączający (aktywna) lub
wyłączający (nieaktywna)
opcję. Działa niezależnie od
pozostałych.
DestroyWindow(hKlawisz);
- 402-
Zdarzenie w oknie elementu sterującego - np. kliknięcie klawisza
[???]Robi na "szaro'?
________________________________________________________________
Podobnie jak opcje w menu - klawisze także mogą zostać
udostępnione (ang. enable), bądź zablokowane (ang. disable).
Jeśli hKlawisz będzie identyfikatorem elementu sterującego,
można go udostępnić (1), bądź zablokować (0) przy pomocy
funkcji:
EnableWindow(hKlawisz, 0);
EnableWindow(hKlawisz, 1);
________________________________________________________________
kilkunastu) plików: .H, .MNU, .DLG, .RC, .DEF, .PRJ, .ICO, .BMP,
------------------Plik MEDYT-01.H-------------------------------
#define szAppName "MEDYT-01"
#define ID_EDIT 200
#include <windows.h>
#include "EDIT.H"
#pragma argused
HWND hEditWnd;
- 403-
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
WNDCLASS wndClass;
MSG msg;
HWND hWnd;
RECT rect;
if ( !hPrevInstance )
{
wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra= 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, szAppName);
wndClass.hCursor= LoadCursor(NULL, IDC_CROSS);
wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
wndClass.lpszMenuName= NULL;
wndClass.lpszClassName= szAppName;
if (!RegisterClass(&wndClass))
return 0;
}
hWnd = CreateWindow(szAppName,
"MEDYT-01", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
0, 0, hInstance, 0);
- 404-
{
switch(Message)
{
case ID_EDIT:
if(HIWORD(lParam)==EN_ERRSPACE)
{
MessageBox (GetFocus(), "Brak pamieci", "MEDYT-01",
MB_ICONSTOP | MB_OK);
}
break;
case WM_SETFOCUS:
SetFocus(hEditWnd);
break;
case WM_SIZE:
MoveWindows(hEditWnd, 0, 0, LOWORD(lParam));
HIWORD(lParam), TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd,Message,wParam,lParam));
}
return 0;
}
- 405-
Typowe rodzaje elementów (obiektów) starujących w środowisku
Windows:
- 406-
hWnd, ID_Elem, hInstance, 0);
DestroyWindow(hKlawisz);
- 407-
DlugTekstu = SendMessage(hEditWnd, WM_GETTEXTLENGHT, 0, 0);
gdzie:
hEditWnd jest identyfikatorem elementu - okienka edycyjnego
[???]Robi na "szaro'?
________________________________________________________________
Podobnie jak opcje w menu - klawisze także mogą zostać
udostępnione (ang. enable), bądź zablokowane (ang. disable).
EnableWindow(hKlawisz, 0);
EnableWindow(hKlawisz, 1);
________________________________________________________________
kilkunastu) plików: .H, .MNU, .DLG, .RC, .DEF, .PRJ, .ICO, .BMP,
------------------Plik MEDYT-01.H-------------------------------
#define szAppName "MEDYT-01"
#define ID_EDIT 200
#include <windows.h>
#include "EDIT.H"
#pragma argused
HWND hEditWnd;
if ( !hPrevInstance )
{
wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra= 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, szAppName);
- 408-
wndClass.hCursor= LoadCursor(NULL, IDC_CROSS);
wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
wndClass.lpszMenuName= NULL;
wndClass.lpszClassName= szAppName;
if (!RegisterClass(&wndClass))
return 0;
}
hWnd = CreateWindow(szAppName,
"MEDYT-01", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
0, 0, hInstance, 0);
{
MessageBox (GetFocus(), "Brak pamieci", "MEDYT-01",
MB_ICONSTOP | MB_OK);
}
break;
case WM_SETFOCUS:
- 409-
SetFocus(hEditWnd);
break;
case WM_SIZE:
MoveWindows(hEditWnd, 0, 0, LOWORD(lParam));
HIWORD(lParam), TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd,Message,wParam,lParam));
}
return 0;
}
- 410-
LEKCJA 43. O Okienkach dialogowych.
________________________________________________________________
O tym, jak konstruuje się okienka dialogowe.
________________________________________________________________
------------------Plik: DLGBOX1.H-------------------------------
#include "DLGBOX1.H"
#include <windows.h>
DLGBOX1 MENU
BEGIN
MENUITEM "&O DlgBox" IDM_DLG1
/* to menu pojawi się w oknie macieżystym */
END
- 411-
STYLE WS_POPUP | WS_DLGFRAME
BEGIN
LTEXT "Przyklad" -1, 0, 12, 160, 8
CTEXT "DLGBOX1 - Przyklad" -1, 0, 36, 160, 8
DEFPUSHBUTTON "OK" IDOK, 64, 60, 32,14, WS_GROUP
END
----------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "DLGBOX1.H"
#pragma argused
HANDLE hInst;
- 412-
wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
wndClass.lpszMenuName= szAppName;
wndClass.lpszClassName= szAppName;
if (!RegisterClass(&wndClass))
return 0;
}
hInst = hInstance;
hWnd = CreateWindow(szAppName, "DLGBOX1", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance, 0);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
- 413-
DialogBox(hInst, "DLGBOX1", hWnd, lpControlProc);
return 0;
}
break;
case WM_DESTROY:
hDC = BeginPaint(hWnd , &ps);
TextOut(hDC, 30, 50,"Demo okienka dialogowego", 25);
TextOut(hDC, 30, 70,"Zastosuj menu...", 17);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd,Message,wParam,lParam));
}
return 0;
}
przez użytkownika.
[!!!]UWAGA
________________________________________________________________
W niektórych przypadkach okienko dialogowe może być głównym
oknem aplikacji.
- 414-
________________________________________________________________
- 415-
LEKCJA 44. Dołączanie zasobów - menu i okienka dialogowe.
________________________________________________________________
BEGIN
POPUP "Rozkaz"
BEGIN
MENUITEM "Rozkaz 1", IDM_R1
MENUITEM "Rozkaz 2", IDM_R2
MENUITEM "Rozkaz 3", IDM_R3
END
POPUP "Kolor"
BEGIN
MENUITEM "Czarny", IDM_BLACK
MENUITEM "Niebieski", IDM_BLUE
MENUITEM "Zielony", IDM_GREEN
END
MENUITEM "Koniec", IDM_EXIT
END
- Można określić menu jako menu danej klasy okien, gdy klasa ta
- 416-
przypisać odpowiedniemu polu struktury nazwę naszego menu.
Jeżeli obiekt klasy WNDCLASS nazwiemy Window1, to:
Window1.lpszMenuName = "NazwaMenu";
hWnd = CreateWindow(szAppName,
"Nazwa Aplikacji",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
hMenu, <-- tu
hIstance,
NULL );
case WM_COMMAND:
switch (wParam)
{
case IDM_R1:
... obsługa ...; break;
case IDM_R2:
... obsługa ...; break
case IDM_QUIT:
...DestroyWindow(...);
}
- 417-
kopii zmiennej do funkcji).
widoczny-lecz-niedostępny, dostępny.
case WM_CREATE:
hMenu = CreateMenu(); //Utworzenie menu
AppendMenu(hMenu, MF_ENABLED, IDM_R1, "Rozkaz 1");
AppendMenu(hMenu, MF_ENABLED, IDM_R2, "Rozkaz 2");
AppendMenu(hMenu, MF_ENABLED, IDM_R3, "Rozkaz 3");
SetMenu(hWnd, hMenu); //Wyświetlenie menu
...
break;
- 418-
Usuwanie pozycji z menu można przeprowadzić dwoma sposobami:
- 419-
HMENU hMenu = GetMenu(hWnd);
HBITMAP hBitmap = LoadBitmap (hIstance, "Pole");
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND | MF_BITMAP, IDM_R2,
(LPSTR) MAKELONG (hBitmap, 0));
...
hMenu2 = LoadMenu (hIstance, "Menu2");
SetMenu (hWnd, hMenu2);
DrawMenuBar(...);
...
Menu1 MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New" , IDM_NEW
MENUITEM "&Save", IDM_SAVE
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Options"
BEGIN
MENUITEM "Menu&1", IDM_M1,CHECKED
MENUITEM "Menu&2" , IDM_M2
END
END
Menu2 MENU
- 420-
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open", IDM_OPEN
MENUITEM "&New" , IDM_NEW
MENUITEM "&Save", IDM_SAVE
MENUITEM "Save &As", IDM_SAVEAS
MENUITEM "&DOS shell", IDM_DOSSHELL
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Options"
BEGIN
MENUITEM "Menu&1", IDM_M1,
MENUITEM "Menu&2" , IDM_M2, CHECKED
END
END
Takie pliki zasobów w Borland C++ mało kto tworzy dziś "na
piechotę". BORLAND C++ oferuje do tego celu dwa
narzędzia:
Edytor zasobów - Resource Workshop
Automatyczny generator - DialogExpert (wersje 4+)
[Z]
________________________________________________________________
1. Przeanalizuj program w pełnej wersji (na dyskietce).
2. Zmodyfikuj dowolną aplikację przykładową tak, by dołączyć do
niej inną ikonę.
3. Opracuj własne menu i własną ikonę przy pomocy Resource
Workshop.
________________________________________________________________
________________________________________________________________
- 421-
1. Uruchomienie: Ikonka Worshop w oknie grupowym Borland C++.
2. Początek pracy: File | New Project...
3. Rodzaje zasobów do wyboru w okienku dialogowym "New project":
[ ] RC - plik zasobów
[ ] CUR - kursor
[ ] BMP - mapa bitowa
[ ] RES - plik zasobów w formie skompilowanej
[ ] ICO - ikonka
[ ] FNT - czcionki (Fonts)
Wybieramy odpowiednio: RC
4. Zmieni się menu w głównym oknie Resource Workshop. Z menu
wybieramy Resource | New
W okienku dialogowym z listy Resource Type (rodzaj zasobów):
ACCELERATORS, BITMAP, CURSOR, DIALOG, FONT, ICON, MENU, RCDATA,
STRINGTABLE, VERSINFO
wybieramy odpowiednio MENU lub DILOG.
button, Radio button, scroll bar, List box, Combo box, Edit box,
- 422-
LEKCJA 45. O PROGRAMACH OBIEKTOWO - ZDARZENIOWYCH.
________________________________________________________________
Po aplikacjach sekwencyjnych, proceduralno-zdarzeniowych, jedno-
KLASA TApplication.
- aplikację.
* Obiekt - aplikacja zaczyna funkcjonować. Konstruktor obiektu
(własny, bądź odziedziczony po klasie TApplication) wywołuje
funkcję - wirtualną metodę InitMainWindow().
* Funkcja przy pomocy operatora new tworzy obiekt - okno
aplikacji.
- 423-
"wyciąg" z dwu opisywanych klas. Nie jest to dokładna kopia kodu
void TApplication::InitInstance()
{
InitMainWindow();
if (MainWindow)
{
MainWindow->SetFlag(wfMainWindow);
MainWindow->Create();
MainWindow->Show(nCmdShow);
}
void TApplication::InitMainWindow()
{
SetMainWindow(new TFrameWindow(0, GetName()));
}
int TApplication::Run()
{
int status;
{
if (!hPrevInstance) InitApplication();
InitInstance();
status = MessageLoop();
- 424-
}
BOOL TApplication::PumpWaitingMessages()
{
MSG msg;
BOOL foundOne = FALSE;
if (!ProcessAppMsg(msg))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
return foundOne;
}
int TApplication::MessageLoop()
{
long idleCount = 0;
MessageLoopResult = 0;
while (!BreakMessageLoop) {
TRY {
if (!IdleAction(idleCount++))
::WaitMessage();
if (PumpWaitingMessages())
idleCount = 0;
}
if (MessageLoopResult != 0) {
::PostQuitMessage(MessageLoopResult);
break;
}
})
}
BreakMessageLoop = FALSE;
return MessageLoopResult;
}
else if (::IsWindowEnabled(wnd)) {
- 425-
*(info->Wnds++) = wnd;
::EnableWindow(wnd, FALSE);
}
}
return TRUE;
}
KLASA TWindow.
TWindow::EvCreate(CREATESTRUCT far&)
{
SetupWindow();
return (int)DefaultProcessing();
}
- 426-
if (Scroller && sizeType != SIZE_MINIMIZED)
{
Scroller->SetPageSize();
Scroller->SetSBarRange();
}
}
#define WIN31
#define STRICT
- 427-
#include <owl.h>
void TOkno::InitMainWindow(void)
{
MainWindow = new (TWindow(0, "Napis - Tytul Okna"));
}
- 428-
wpisujemy zero, ponieważ program nie posiada w tym stadium
wcześniejszego okna macieżystego.
Pozostało nam jeszcze dodać funkcję WinMain() i pierwszy program
#define WIN31
#define STRICT
- 429-
#include <owl.h>
- 430-
(Engine). Rozważmy to na przykładzie aplikacji reagującej na
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,
WM_RBUTTONDOWN. Aby wiedzieć, w którym miejscu ekranu jest
kursor myszki, wykorzystamy informacje przenoszone przez
parametr lParam.
#define WIN31
#define STRICT
#include <stdio.h>
#include <string.h>
#include <owl.h>
BOOL TApplication::CanClose()
{
if (MainWindow)
return (MainWindow->CanClose());
else
return (TRUE);
}
_CLASSDEF(TGOkno)
- 431-
Konstruktor tradycyjnie wykorzystujemy do przekazania parametrów
Komunikat Zdarzenie
________________________________________________________________
WM_MOUSEMOWE - przesunięto myszkę (wewnątrz obszaru
roboczego - inside the client area -
ICA)
WM_LBUTTONDOWN - naciśnięto LEWY klawisz myszki (ICA)
WM_LBUTTONDBLCLK - naciśnięto dwukrotnie LEWY klaw. (ICA)
WM_LBUTTONUP - puszczono LEWY klawisz (ICA)
WM_RBUTTONDOWN - naciśnięto PRAWY klawisz myszki (ICA)
WM_RBUTTONDBLCLK - naciśnięto dwukrotnie PRAWY klaw. (ICA)
WM_RBUTTONUP - puszczono PRAWY klawisz (ICA)
WM_MBUTTONDOWN - naciśnięto ŚRODK. klawisz myszki (ICA)
WM_MBUTTONDBLCLK - naciśnięto dwukrotnie ŚROD. klaw. (ICA)
WM_MBUTTONUP - puszczono ŚRODKOWY klawisz (ICA)
WM_NCMOUSEMOVE - ruch myszki poza client area (NCA)
WM_NLBUTTONDOWN - naciśnięto LEWY klawisz myszki poza
obszarem roboczym - non-client area
(NCA)
WM_NCLBUTTONDBLCLK - naciśnięto dwukrotnie LEWY klaw. (NCA)
WM_NCLBUTTONUP - puszczono LEWY klawisz (NCA)
WM_NCRBUTTONDOWN - naciśnięto PRAWY klawisz myszki (NCA)
WM_NCRBUTTONDBLCLK - naciśnięto dwukrotnie PRAWY klaw. (NCA)
WM_NCRBUTTONUP - puszczono PRAWY klawisz (NCA)
WM_NCMBUTTONDOWN - naciśnięto ŚR. klawisz myszki (NCA)
WM_NCMBUTTONDBLCLK - naciśnięto dwukrotnie ŚRODK. klaw. (NCA)
WM_LBUTTONUP - puszczono ŚRODKOWY klawisz (NCA)
________________________________________________________________
- 432-
_______________________________________________________________
WM_KEYDOWN Naciśnięto (jakiś) klawisz.
WM_KEYUP Puszczono klawisz.
WM_SYSKEYDOWN Naciśnięto klawisz "systemowy".
WM_SYSKEYUP Puszczono klawisz "systemowy".
WM_CHAR Kod ASCII klawisza.
________________________________________________________________
_CLASSDEF(TWindow)
- 433-
#define WM_FIRST 0x0000
/* 0x0000- 0x7FFF window messages */
#define WM_INTERNAL 0x7F00
/* 0x7F00- 0x7FFF reserved for internal use */
#define ID_FIRST 0x8000
/* 0x8000- 0x8FFF child id messages */
#define NF_FIRST 0x9000
/* 0x9000- 0x9FFF notification messages */
#define CM_FIRST 0xA000
/* 0xA000- 0xFFFF command messages */
#define WM_RESERVED WM_INTERNAL - WM_FIRST
#define ID_RESERVED ID_INTERNAL - ID_FIRST
#define ID_FIRSTMDICHILD ID_RESERVED + 1
#define ID_MDICLIENT ID_RESERVED + 2
#define CM_RESERVED CM_INTERNAL - CM_FIRST
struct TMessage
{
HWND Receiver; //Identyfikator okna - odbiorcy
WORD Message; //sam komunikat
union
{
WORD WParam; //Parametr WParam stowarzyszony z
//komunikatem; ALBO (dlatego unia!)
struct tagWP
{
BYTE Lo;
BYTE Hi;
} WP;
union
{
DWORD lParam;
struct tagLP
{
WORD Lo;
WORD Hi;
} LP;
};
long Result;
};
void TAplikacja::InitMainWindow()
{
MainWindow = new (0, Name);
- 434-
}
BOOL TMyWindow::CanClose()
{
return (MessageBox(HWindow, "Wychodzimy?",
"Koniec", MB_YESNO | MB_ICONQUESTION) == IDYES);
}
void TMyWindow::WMRButtonDown(RTMessage)
{
InvalidateRect(HWindow, 0, 1);
}
- 435-
LPSTR lpCmdLine, int nCmdShow)
{
TNAplikacja OBIEKT("Wspolrzedne w oknie", hInstance,
hPrevInstance, lpCmdLine, nCmdShow);
OBIEKT.Run();
return (OBIEKT.Status);
}
[!!!]UWAGA
________________________________________________________________
#include <windows.h>
#include <owlrc.h>
rcinclude INPUTDIA.DLG
rcinclude FILEDIAL.DLG
[S]
rcinclude - dołącz zasoby
LOADONCALL - załaduj po wywołaniu
owlrc - zasoby biblioteki klas OWL
- 436-
Gotowe "klocki" można wykorzystać nawet wtedy, gdy nie pasują w
100%. Inne niż typowe odpowiedzi na wybór rozkazu implementujemy
TGOkno GOkno;
void TGOkno::CMFileOpen(RTMessage)
{
... obsługa zdarzenia ...
}
________________________________________________________________
[Z]
________________________________________________________________
1. Przeanalizuj gotowe zasoby dołączone do Twojej wersji Borland
C++.
2. Uruchom kilka projektów "firmowych" dołączonych w katalogu
\EXAMPLES. Zwróć szczególną uwagę na projekty STEPS (kolejne
kroki w tworzeniu aplikacji obiektowej).
________________________________________________________________
- 437-
LEKCJA 46. APLIKACJA OBIEKTOWA - RYSOWANIE W OKNIE.
________________________________________________________________
W trakcie tej lekcji opracujemy obiektową aplikację psoługując
się biblioteką klas Object Windows Library.
________________________________________________________________
#include <owl.h>
void TNAplikacja::InitMainWindow()
{
MainWindow = new TGOkno(0, Name);
}
BOOL TGOkno::CanClose()
- 438-
{
return (MessageBox(HWindow, Ptr, "KONIEC",
MB_YESNO | MB_ICONQUESTION) == IDYES);
}
_CLASSDEF(TGOkno)
class TGOkno : public TWindow
{
public:
HDC dc;
BOOL ButtonDown;
BOOL Flaga_Start;
- 439-
Flaga_Start = TRUE; //UWAGA:
SetCapture(HWindow); //Jesli zainicjujemy SetCapture()
dc = GetDC(HWindow); //w konstruktorze - mamy caly ekran
}
MoveTo(dc, Msg.LP.Lo, Msg.LP.Hi);
ButtonDown = TRUE;
}
void TGOkno::WMLButtonUp(RTMessage)
{
if (ButtonDown) ButtonDown = FALSE;
}
void TGOkno::WMRButtonDown(RTMessage)
{
InvalidateRect(HWindow, 0, 1);
ReleaseCapture();
ReleaseDC(HWindow, dc);
Flaga_Start = FALSE;
}
#define STRICT
#define WIN31
#include <owl.h>
- 440-
klawiszami [Print Screen] \
lub [Alt]+[PrtScr].";
_CLASSDEF(TMyWindow)
class TMyWindow : public TWindow
{
public:
HDC dc;
BOOL ButtonDown;
BOOL Flaga_Start;
- 441-
{
if ( ButtonDown )
LineTo(dc, Msg.LP.Lo, Msg.LP.Hi);
}
void TMyWindow::WMLButtonUp(RTMessage)
{
if (ButtonDown) ButtonDown = FALSE;
}
void TMyWindow::WMRButtonDown(RTMessage)
{
InvalidateRect(HWindow, NULL, TRUE);
ReleaseCapture();
ReleaseDC(HWindow, dc);
Flaga_Start = FALSE;
}
void TNAplikacja::InitMainWindow()
{
MainWindow = new TMyWindow(0, Name);
}
BOOL TMyWindow::CanClose()
{
return (MessageBox(HWindow, Ptr, "KONIEC",
MB_YESNO | MB_ICONQUESTION) == IDYES);
}
- 442-
LEKCJA 47. O PAKIETACH BORLAND C++ 4/4.5.
________________________________________________________________
Z tej lekcji dowiesz się, czy warto kupić nowszą wersję Borland
C++ 4/4.5 i jakie niespodzianki czekają Cię po zamianie
kompilatora na nowszy.
________________________________________________________________
Konfiguracja Dysk
________________________________________________________________
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
4. Środowisko IDE 32 bitowe 30 MB
5. Tylko dla DOS (minimum) 8 MB
________________________________________________________________
* D+W - dla DOS i Windows
- 443-
program instalacyjny wymaga obecności Windows. Uruchomienie
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:
C:\>WIN X:INSTALL
device=X:\WINDOWS\SYSTEM\WIN32S\W32S.386
FILES=40
BUFFERS=40
PATH=...;X:\BC4\BIN;
- 444-
W skład pakietu wchodzą między innymi:
komunikatach
* TDUMP - bezpośrednie przeglądanie informacji zawartych w
plikach *.EXE i *.OBJ
* TDSTRIP - narzędzie do usuwania tablicy symboli z plików
wykonywalnych
* IMPLIB - importer bibliotek z DLL
* TDMEM - wyświetlanie informacji o zajętości pamięci
* MAKESWAP - zarządzanie swapowaniem (tworzenie plików
tymczasowych EDPMI.SWP o zadanej wielkości)
- 445-
że poprawna praca obu kompilatorów w jednym systemie wymaga
"uregulowania stosunków":
DEVICE=X:\BC4\BIN\WINDPMI.386
DEVICE=X:\BC4\BIN\TDDEBUG.386 <-- tu możliwy konflikt z BP 7
- 446-
- inną bibliotekę Runtime Library
\BIN\TVISION\SOURCE
O AUTOMATYZACJI - CASE.
- ClassExpert
- ApplicationExpert
- DialogExpert
- TargetExpert
________________________________________________________________
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)
- 447-
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ę)
________________________________________________________________
ZAKOŃCZENIE.
- 448-
pozostał Ci już tylko wykonanie trzech rzeczy. Powinieneś teraz:
- 449-