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. ________________________________________________________________ Możemy teraz po¶więcić chwilę na zagadnienie kolorów, które pojawiaj± się na monitorze. Po uruchomieniu program przykładowy poniżej wygeneruje krótki dĽwięk i zapyta o imię. Po wpisaniu imienia program zapiszczy jeszcze raz i zapyta o nazwisko. Po wpisaniu nazwiska program zmieni kolor na ekranie monitora i wypisze komunikat kolorowymi literami. Różne kolory zobaczysz oczywi¶cie tylko wtedy, gdy masz kolorowy monitor. Dla popularnego zestawu VGA mono będ± to różne odcienie szaro¶ci. Tekst powinien zmieniać kolor i "migać" (ang. - blinking text). [P012.CPP] #include #include 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; } Wyja¶nijmy kilka szczegółów technicznych: cout << "\aPodaj nazwisko? "; /* \a to kod pisku gło¶niczka (beep) */ cin >> nazwisko; textcolor(4+128); <---- funkcja zmienia kolor tekstu cprintf("\nPan(i), %s %s? Bardzo mi milo!", imie, nazwisko);   ___ tu funkcja wstawi "string" nazwisko | |________ a tu wstawi "string" imie |_________ funkcja wyprowadza tekst na ekran w kolorach (cprintf = Color PRINTing Function) Operator >> pobiera ze strumienia danych wej¶ciowych cin wpisane przez Ciebie imię i zapisuje ten tekst do tablicy znakowej imie[20]. Po wypisaniu na ekranie następnego pytania następuje pobranie drugiego łańcucha znaków (ang. string) wpisanego przez Ciebie jako odpowiedĽ na pytanie o nazwisko i umieszczenie tego łańcucha w tablicy znakowej nazwisko[]. Wywołana następnie funkcja textcolor() powoduje zmianę roboczego koloru wyprowadzanego tekstu. Tekst nie tylko zmieni kolor, lecz także będzie "migać" (blink). Funkcja cprintf() wyprowadza na ekran końcowy napis. Funkcja cprintf() to Color PRINTing Function - funkcja drukowania w kolorze. Funkcja textcolor() pozwala na zmianę koloru tekstu wyprowadzanego na monitor. Można przy pomocy tej funkcji także "zmusić" tekst do migotania. Aby funkcja zadziałała - musimy przekazać jej ARGUMENT. Argument funkcji to numer koloru. Zwróć jednak uwagę, że zamiast prostego, zrozumiałego zapisu: textcolor(4); /* 4 oznacza kolor czerwony */ mamy w programie podany argument w postaci wyrażenia (sumy dwu liczb): textcolor(4+128); // to samo, co: textcolor(132); Wbrew pierwszemu mylnemu wrażeniu te dwie liczby stanowi± jeden argument funkcji. C++ najpierw dokona dodawania 4+128 a dopiero uzyskany wynik 132 przekaże funkcji textcolor jako jej argument (parametr). Liczba 4 to kod koloru czerwonego, a zwiększenie kodu koloru o 128 powoduje, że tekst będzie migał. Numery (kody) kolorów, które możesz przekazać jako argumenty funkcji textcolor() podano w tabeli poniżej. Je¶li tekst ma migać - należy dodać 128 do numeru odpowiedniego koloru. Kod koloru przekazywany do funkcji textcolor(). ________________________________________________________________ Kod Kolor (ang) Kolor (pol) Stała n (przykład) ________________________________________________________________ 0 Black Czarny BLACK 1 Blue Niebieski BLUE 2 Green Zielony GREEN 3 Cyan Morski CYAN 4 Red Czerwony 5 Magenta Fioletowy 6 Brown Br±zowy 7 White Biały 8 Gray Szary 9 Light blue Jasno niebieski 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 - przykłady), które możesz stosować jako argumenty funkcji. Kolor tła możesz ustawić np. przy pomocy funkcji textbackground() - np. textbacground(RED); * Manipuluj±c kolorem tekstu musisz pamiętać, że je¶li kolor napisu: - foreground color, text color i kolor tła: - background color okaż± się identyczne - tekst zrobi się NIEWIDOCZNY. Je¶li każesz komputerowi pisać czerwonymi literami na czerwonym tle - komputer wykona rozkaz. Jednakże większo¶ć ludzi ma kłopoty z odczytywaniem czarnego tekstu na czarnym tle. Jest to jednak metoda stosowana czasem w praktyce programowania do kasowania tekstów i elementów graficznych na ekranie. ________________________________________________________________ Powołuj±c się na nasze wcze¶niejsze porównanie (NIE TRAKTUJ GO ZBYT DOSŁOWNIE!),zajmiemy się teraz czym¶, co trochę przypomina rzeczowniki w normalnym języku. O IDENTYFIKATORACH - DOKŁADNIEJ. Identyfikatorami (nazwami) mog± być słowa, a dokładniej ci±gi liter, cyfr i znaków podkre¶lenia rozpoczynaj±ce się od litery lub znaku podkre¶lenia (_). Za wyj±tkiem słów kluczowych, (które to słowa kluczowe - MUSZˇ ZAWSZE BYĆ PISANE MAŁYMI LITERAMI) można stosować i małe i duże litery. Litery duże i małe s± rozróżniane. Przykład: [P013.CPP] #include #include float PI = 3.14159; <-- stała PI float r; <-- zmienna r int main(void) { clrscr(); printf("Podaj promien ?\n"); scanf("%f", &r); printf("\nPole wynosi P = %f", PI*r*r ); getch(); return 0; } * Użyte w programie słowa kluczowe: int, float, void, return. * Identyfikatory - nazwy funkcji (zastrzeżone): main, printf, scanf, getch, clrscr. - nazwy zmiennych (dowolne): PI, r. * Dyrektywy preprocesora: # include Zwróć uwagę, że w wierszu: float PI = 3.14159; nie tylko DEKLARUJEMY, zmienn± PI jako zmiennoprzecinkow±, ale także od razu nadajemy liczbie PI jej warto¶ć. Jest to tzw. ZAINICJOWANIE zmiennej. [Z] ________________________________________________________________ 1. Uruchom program przykładowy. Spróbuj zamienić identyfikator zmiennej PI na pisane małymi literami pi. Powinien wyst±pić bł±d. ________________________________________________________________ Dla porównania ten sam program w wersji obiektowo-strumieniowej: [P013-1.CPP] #include #include const float PI = 3.14159; <-- stała PI float r; <-- zmienna r int main(void) { clrscr(); cout << "Podaj promien ?\n"; cin >> r; cout << "\nPole wynosi P = " << PI*r*r; getch(); return 0; } LITERAŁY. Literałem nazywamy reprezentuj±cy dan± NAPIS, na podstawie którego można jednoznacznie zidentyfikować dan±, jej typ, warto¶ć i inne atrybuty. W języku C++ literałami mog± być: * łańcuchy znaków - np. "Napis"; * pojedyncze znaki - np. 'X', '?'; * liczby - np. 255, 3.14 [!!!] Uwaga: BARDZO WAŻNE !!! ________________________________________________________________ * Rolę przecinka dziesiętnego spełnia kropka. Zapis Pi=3,14 jest nieprawidłowy. * Próba zastosowania przecinka w tej roli SPOWODUJE BŁĘDY ! ________________________________________________________________ Liczby całkowite mog± być: * Dziesiętne (przyjmowane domy¶lnie - default); * Ósemkowe - zapisywane z zerem na pocz±tku: 017 = 1*8 + 7 = 15 (dziesiętnie); * Szesnastkowe - zapisywane z 0x na pocz±tku: 0x17 = 1*16 + 7 = 23 (dziesiętnie); 0x100 = 16^2 + 0 + 0 = 256 . Liczby rzeczywiste mog± zawierać czę¶ć ułamkow± lub być zapisane w postaci wykładniczej (ang. scientific format) z liter± "e" poprzedzaj±c± wykładnik potęgi. Przykład: Zapis liczby€€€€€€€€Warto¶ć dziesiętna .0123€€€€€€€€€€€€€€€0.0123 123e4€€€€€€€€€€€€€€€123 * 10^4 = 1 230 000 1.23e3€€€€€€€€€€€€€€€1.23 * 10^3 = 1230 123e-4€€€€€€€€€€€€€€0.0123 Literały składaj±ce się z pojedynczych znaków maj± jedn± z trzech postaci: * 'z' - gdzie z oznacza znak "we własnej osobie"; * '\n' - symboliczne oznaczenie znaku specjalnego - np. steruj±cego - tu: znak nowej linii; * '\13' - nr znaku w kodzie ASCII. UWAGA: '\24' - kod Ósemkowy ! (dziesiętnie 20) '\x24' - kod SZESNASTKOWY ! (dziesiętnie 36) [S]€€SLASH, BACKSLASH. €€€€€Kreska "/" nazywa się SLASH (czyt. "slasz") - łamane, uko¶nik zwykły. Kreska "\" nazywa się BACKSLASH (czyt. "bekslasz") - uko¶nik odwrotny. Uzupełnimy teraz listę symboli znaków z poprzedniej lekcji. Znak €€€€ÓSEMKOWO€€ASCII (10)€€€€€ZNACZENIE \a€€€€€€€'\7'€€€€€€7€€€€€€€€€€€€€€- sygn. dĽwiękowy BEL \n€€€€€€€'\12'€€€€€10€€€€€€€€€€€€€- nowy wiersz LF \t€€€€€€€'\11'€€€€€9€€€€€€€€€€€€€€- tabulacja pozioma HT \v€€€€€€ '\13'€€€€€11€€€€€€€€€€€€€- tabulacja pionowa VT \b€€€€€€€'\10'€€€€€8€€€€€€€€€€€€€€- cofnięcie kursora o 1 znak \r€€€€€€€'\15'€€€€€13€€€€€€€€€€€€€- powrót do pocz±tku linii CR \f€€€€€€€'\14'€€€€€12€€€€€€€€€€€€€- nowa strona (form feed) FF \\€€€€€€€'\134'€€€€92€€€€€€€€€€€€€- poprostu znak backslash "\" \'€€€€€€€'\47'€€€€€39€€€€€€€€€€€€€- apostrof "'" \"€€€€€€€'\42'€€€€€34€€€€€€€€€€€€€- cudzysłów (") \0€€€€€€€'\0'€€€€€€0€€€€€€€€€€€€€€- NULL (znak pusty) Komputer przechowuje znak w swojej pamięci jako "krótk±", bo zajmuj±c± tylko jeden bajt liczbę całkowit± (kod ASCII znaku). Na tych liczbach wolno Ci wykonywać operacje arytmetyczne ! (Od czego mamy komputer?) Przekonaj się o tym uruchamiaj±c następuj±cy program. [P014.CPP] # include //prototypy printf() i scanf() # include //prototypy clrscr() i getch() int liczba; //deklaracja zmiennej "liczba" 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; } Uruchom program kilkakrotnie podaj±c różne liczby całkowite z zakresu od 1 do 100. Przyjrzyj się sposobowi formatowania wyj¶cia: %c, %d, \t, \n Je¶li pamiętasz, że kody ASCII kolejnych liter A,B,C... i kolejnych cyfr 1, 2, 3 s± kolejnymi liczbami, to zauważ, że wyrażenia: '5' + 1 = '6' oraz 'A' + 2 = 'C' (czytaj: kod ASCII "5" + 1 = kod ASCII "6") s± poprawne. [!!!]Jak sprawdzić kod ASCII znaku? ________________________________________________________________ Można oczyw¶cie nauczyć się tabeli kodów ASCII na pamięć (dla pocz±tkowych i najważniejszych stronic kodowych - przede wszystkom od 0 do 852). Dla hobbystów - stronica kodowa 1250 i 1252 też czasem się przydaje. (to oczywi¶cie żart - autor nie zna ani jednego faceta o tak genialnej pamięci) Można skorzystać z edytora programu Norton Commander. W trybie Edit [F4] po wskazaniu kursorem znaku w górnym wierszu po prawej stronie zostanie wy¶wietlony jego kod ASCII. ________________________________________________________________ CZY PROGRAM NIE MÓGŁBY CHODZIĆ W KÓŁKO? Twoja intuicja programisty z pewno¶ci± podpowiada Ci, że gdyby zmusić komputer do pracy w pętli, to nie musiałby¶ przykładowych programów uruchamiać wielokrotnie. Spróbujmy nakazać programowi przykładowemu chodzić "w kółko". To proste - dodamy do programu: * na końcu rozkaz skoku bezwarunkowego goto (idĽ do...), * a żeby wiedział dok±d ma sobie i¶ć - na pocz±tku programu zaznaczymy miejsce przy pomocy umownego znaku - ETYKIETY. Zwróć uwagę, że pisz±c pliki wsadowe typu *.BAT w języku BPL (Batch Programming Language - język programowania wsadowego) stawiasz dwukropek zawsze na pocz±tku etykiety: :ETYKIETA (BPL) a w języku C++ zawsze na końcu etykiety: ETYKIETA: (C/C++) Przystępujemy do opracowania programu. [P015.CPP] # include short int liczba; int main(void) { clrscr(); 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; } Skompiluj program do wersji *.EXE: Compile | Make (rozkazem Make EXE file z menu Compile). Musisz nacisn±ć następuj±ce klawisze: [Alt]-[C], [M]. (lub [F9]) * Je¶li wyst±piły błędy, popraw i powtórz próbę kompilacji. * Uruchom program [Alt]-[R], [R] (lub [Ctrl]-[F9]). * Podaj kilka liczb: np. 1,2,5,7,8 itp. * Przerwij działanie programu naciskaj±c kombinację klawiszy [Ctrl]+[Break] lub [Ctrl]+[C]. * SprawdĽ, jaki jest katalog wyj¶ciowy kompilatora. - Rozwiń menu Options [Alt]-[O], - Otwórz okienko Directories... [D], - SprawdĽ zawarto¶ć okienka tekstowego Output Directory. Teraz wiesz już gdzie szukać swojego programu w wersji *.EXE. - Uruchom program poza ¶rodowiskiem IDE. - SprawdĽ reakcję programu na klawisze: [Esc], [Ctrl]-[C], [Ctrl]-[Break]. Uruchom powtórnie kompilator C++ i załaduj program rozkazem: BC A:\GOTOTEST.CPP Wykonaj od nowa kompilację programu [F9]. [???] ... is up to date... ________________________________________________________________ Je¶li C++ nie zechce powtórzyć kompilacji i odpowie Ci: €€€€€€€€€€€€€€€€€€€€Making A:\GOTOTEST.CPP €€€€€€€€€€€€€€€is up to date (Program w takiej wersji już skompilowałem, więcej nie będę!) nie przejmuj się. Dokonaj jakiejkolwiek pozornej zmiany w programie (np. dodaj spację lub pusty wiersz w dowolnym miejscu). Takich pozornych zmian wystarczy by oszukać C++. C++ nie jest na tyle inteligentny, by rozróżniać zmiany rzeczywiste w pliku Ľródłowym od pozornych. ________________________________________________________________ Powtórz kompilację programu. Nie musisz uruchamiać programu. Zwróć uwagę tym razem na pojawiaj±ce się w okienku komunikatów ostrzeżenie: Warning: A:\GOTOTEST.CPP 14: Unreachable code in function main. (Uwaga: Kod programu zawiera takie rozkazy, które nigdy nie zostan± wykonane inaczej - "s± nieosi±galne"). O co chodzi? Przyjrzyj się tekstowi programu. Nawet je¶li po rozkazie skoku bezwarunkowego: goto etykieta; dopiszesz jakikolwiek inny rozkaz, to program nigdy tego rozkazu nie wykona. Wła¶nie o to chodzi. Program nie może nawet nigdy wykonać rozkazu "return 0", który dodali¶my "z przyzwyczajenia". Pętla programowa powinna być wykonywana w nieskończono¶ć. Taka pętla nazywa się pętl± nieskończon± (ang. infinite loop). Mimo to i w ¶rodowisku IDE (typowy komunikat: User break) i w ¶rodowisku DOS tę pętlę uda Ci się przerwać. Kto wobec tego przerwał działanie Twojego programu? Nieskończon± pętlę programow± przerwał DOS. Program zwrócił się do systemu DOS, a konkretnie do której¶ z DOS'owskich funkcji obsługi WEJ¦CIA/WYJ¦CIA i to DOS wykrył, że przycisn±łe¶ klawisze [Ctrl]-[C] i przerwał obsługę Twojego programu. Następnie DOS "wyrzucił" twój program z pamięci operacyjnej komputera i zgłosił gotowo¶ć do wykonania dalszych Twoich poleceń - swoim znakiem zachęty C:\>_ lub A:\>_. Spróbujmy wykonać taki sam "face lifting" i innych programów przykładowych, dodaj±c do nich najprostsz± pętlę. Zanim jednak omówimy szczegóły techniczne pętli programowych w C++ rozważmy prosty przykład. WyobraĽmy sobie, że chcemy wydrukować na ekranie kolejne liczby całkowite od 2 do np. 10. Program powinien zatem liczyć ilo¶ć wykonanych pętli, b±dĽ sprawdzać, czy liczba przeznaczona do drukowania nie stała się zbyt duża. W C++ do takich konstrukcji używa się kilku bardzo ważnych słów kluczowych: [S] some important keywords - kilka ważnych słów kluczowych ________________________________________________________________ for - dla (znaczenie jak w Pascalu i BASICu) while - dopóki do - wykonuj if - jeżeli break - przerwij wykonywanie pętli continue - kontynuuj pętelkowanie goto - skocz do wskazanej etykiety ________________________________________________________________ Nasz program mógłby przy zastosowaniu tych słów zostać napisany np. tak: [LOOP-1] #include void main() { int x = 2; petla: cout << x << '\n'; x = x + 1; if (x < 11) goto petla; } Możemy zastosować rozkaz goto w postaci skoku bezwarunkowego, a pętelkowanie przerwać rozkazem break: [LOOP-2] #include void main() { int x = 2; petla: cout << x << '\n'; x = x + 1; if(x > 10) break; goto petla; } Możemy zastosować pętlę typu for: [LOOP-3] #include int main(void) { for(int x = 2; x < 11; x = x + 1) { cout << x << '\n'; } return 0; } Możemy zastosować pętlę typu while: [LOOP-4] #include int main(void) { int x = 2; while (x < 11) { cout << x << '\n'; x = x + 1; } return 0; } Możemy także zastosować pętlę typu do-while: [LOOP-5] #include int main(void) { int x = 2; do { cout << x << '\n'; x = x + 1; }while (x < 11); return 0; } Możemy wreszcie nie precyzować warunków pętelkowania w nagłówku pętki for, lecz przerwać pętlę w jej wnętrzu (po osi±gnięciu okre¶lonego stanu) przy pomocy rozkazu break: [LOOP-6] #include int main(void) { for(;;) { cout << x << '\n'; x++; if( x > 10) break; } return 0; } Wszytkie te pętle (sprawdĽ!) będ± działać tak samo. Spróbuj przy ich pomocy, zanim przejdziesz dalej, wydrukować np. liczby od 10 do 100 i wykonaj jeszcze kilka innych eksperymentów. Dokładniejszy opis znajdziesz w dalszej czę¶ci ksi±żki, ale przykład - to przykład. Wróćmy teraz do "face-liftingu" naszych poprzednich programów. Ponieważ nie możemy sprecyzować żadnych warunków, każemy programowi przykładowemu wykonywać pętlę bezwarunkowo. Wpisz tekst programu: [P016.CPP] // Przyklad FACELIFT.CPP // Program przykladowy 10na16.CPP / 16na10.CPP FACE LIFTING. # include 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; } - Uruchom program Run, Run. - Dla przetestowania działania programu: * podaj kolejno liczby o różnej długo¶ci 1, 2, 3, 4, 5, 6 cyfrowe; * zwróć uwagę, czy program przetwarza poprawnie liczby dowolnej długo¶ci? - Przerwij program naciskaj±c klawisz z kropk± [.] - Zapisz program na dysk [F2]. - WyjdĽ z IDE naciskaj±c klawisze [Alt]-[X]. Zwróć uwagę na dziwny wiersz: if(getch() == '.') break; C++ wykona go w następuj±cej kolejno¶ci: 1) - wywoła funkcję getch(), poczeka na naci¶nięcie klawisza i wczyta znak z klawiatury: getch() 2) - sprawdzi, czy znak był kropk±: (getch() == '.') ? 3) - je¶li TAK - wykona rozkaz break i przerwie pętlę, if(getch() == '.') break; - je¶li NIE - nie zrobi nic i pętla "potoczy się" dalej. if(getch() != '.') ...--> printf("Podaj liczbe dziesietna... [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. _______________________________________________________________