23 Trzy ważne słowa w C Zacznijmy od prostych analogii do przykładów znanych już z części poświęconej Pascalowi. W C, posługując się funkcjami bibliotecznymi, możemy łatwo napisać podobne programy. Oto przykłady, które demonstrują sposób ustawienia koloru tekstu na ekranie: textcolor(red); //<-- pisz na czerwono (ustaw kolor tekstu) oraz koloru tła pod wyprowadzanym tekstem: textbackground(white); Listing L2301.C // <-- tlo tekstu na bialo gotoxy(5, 3); puts( X <-- Tu: X=5, Y=3 ); gotoxy(12, 8); puts( X <-- a tu: X=12, Y=8 ); gotoxy(32, 18); puts( X <-- a tu: X=32, Y=18 ); Listing L2302.C
Trzy ważne słowa w C textbackground(white); textcolor(red); gotoxy(5, 3); cprintf( X <-- Tu: X=5, Y=3 ); // <-- cprintf() textbackground(yellow); textcolor(blue); gotoxy(7, 4); cprintf( X <-- a tu: X=7, Y=4 ); Popatrzmy uważnie na dwa powyższe przykłady i porównajmy je z programami pisanymi uprzednio w Pascalu. Chociaż nazwy funkcji bibliotecznych są bardzo często takie same lub podobne, istnieje kilka różnic w zapisie: qq Nazwy funkcji bibliotecznych C pisze się zawsze małymi literami. qq Nazwy stałych w C pisze się wielkimi literami. Paleta kolorów i nazwy są dokładnie takie same. Nawet instrukcja skoku goto jest identyczna. Istnieje jednakże pewna różnica. W przeciwieństwie do Pascala, w C/C++ nie musimy deklarować etykiety przed użyciem. Kompilator C rozpoznaje etykietę po dwukropku na końcu, na przykład: etykieta: Instrukcja skoku do miejsca zaznaczonego za pomocą etykiety jest taka sama jak w Pascalu (z tym że pisana jest małymi literami): goto nazwa_etykiety; Choć stosowanie instrukcji goto nie jest w dobrym tonie i jej wyeliminowanie było jednym z najważniejszych celów towarzyszących wprowadzaniu, popularyzacji i lansowaniu programowania strukturalnego jako obowiązującego standardu, nie pomijam jej w niniejszym podręczniku. Ma to pewne uzasadnienie. Istotne argumenty są dwa: 1. Kompilatory Pascala, C i C++ mogą generować kod asemblera i pokazywać go w oknie diagnostycznym debugera. Na poziomie asemblera kompilatory same stosują etykiety i instrukcje skoków warunkowych i bezwarunkowych. Programista musi rozumieć, na czym one polegają. 2. Przy programowaniu sterowników mikroprocesorowych, w asemblerze i w C często nadal stosuje się instrukcje skoków warunkowych i bezwarunkowych. To niezbędny element rzemiosła inżynierskiego. 187
Rozdział 23 t Trzy ważne słowa w C UWAGA Należy pamiętać, że metodyka programowania strukturalnego i obiektowego nie zezwala na stosowanie skoków goto. Żaden z bardziej zaawansowanych przykładów w podręczniku nie zawiera tej instrukcji. Pamiętajmy: nie ma pętli programowej, w której użycie instrukcji skoku goto byłoby niezbędne. Każdą pętlę programową można zapisać w sposób strukturalny. Listing L2303.C /* UWAGA: ta petla, jak poprzednio w Pascalu, nie chce sie zakonczyc! */ int kolor1 = BLACK; int kolor2 = BLUE; // BLACK to czarny // BLUE to niebieski gotoxy(30, 1); puts( STOP - [Ctrl]+[Break]!\n ); start: // <-- etykieta (poczatek petli) textbackground(kolor1++); textcolor(kolor2++); cprintf( X ); goto start; // <-- instrukcja skoku (koniec petli) Nietrudno się domyślić, że funkcja cprintf() to odpowiednik printf(), tylko w wersji na konsolę (ang. Console PRINT Formatted output). W notacji C jest jednak kilka różnic: 1. Deklaracje zmiennych znajdują się wewnątrz funkcji main(). To ważne spostrzeżenie. Zmienne w C można zadeklarować przed początkiem programu. Stają się wtedy, jak w Pascalu, zmiennymi globalnymi. Warto zwrócić uwagę, że metodyka programowania strukturalnego zaleca stosowanie możliwie jak najmniejszej liczby zmiennych globalnych. Zastępowanie zmiennych globalnych przez zmienne lokalne jest pożądane i korzystne z powodu bardziej racjonalnego wykorzystania pamięci. Zmienna lokalna zajmuje pamięć tylko na chwilę, a zmienna globalna na stałe. 188
Trzy ważne słowa w C 2. Brak słowa kluczowego Var. 3. Wiele funkcji bibliotecznych nazywa się tak samo (choć nazwy pisane są małymi literami). 4. Nawet w tak prostych programach pojawiają się elementy składni charakterystyczne dla C i C++. Kolejny przykład będzie dotyczył inkrementacji zmiennej w pętli programowej. Skrócony zapis: kolor1++; oznacza w C++: kolor1 = kolor1 + 1; Program rzeczywiście wykonuje pętlę, ale ta pętla nie chce się zakończyć! Jeśli znajdujemy się w środowisku uruchomieniowym IDE, uda nam się ją przerwać, wystarczy nacisnąć Ctrl+Break. Skoro przed chwilą napisano, że każdą pętlę można zapisać w sposób strukturalny, przekształcimy ten program, posługując się słowami do-while. Listing L2304.C int kolor1 = BLACK; int kolor2 = BLUE; gotoxy(30, 1); puts( STOP - [F3]!\n ); do textbackground(kolor1++); textcolor(kolor2); cprintf( X ); while (!kbhit()); Wyjaśnienie rozpocznijmy od konstrukcji pętli: do... while (!kbhit() ); 189
Rozdział 23 t Trzy ważne słowa w C W tłumaczeniu na język polski znaczyłoby to mniej więcej: Powtarzaj Początek...Koniec Dopóki NIE naciśnięto_klawisza Słowo kluczowe do jest tu odpowiednikiem pascalowskiego Repeat i służy w C/C++ właśnie do tego, by wytłumaczyć, że jakiś fragment kodu powinien być powtarzany. Początek tego fragmentu zaznacza się tym razem nie etykietą, lecz nawiasem klamrowym. Koniec tegoż fragmentu zaznacza się nawiasem klamrowym. Pomiędzy oba nawiasy można wstawiać więcej niż jedną instrukcję. To, co znajduje się pomiędzy nawiasami..., fachowcy nazywają ciałem pętli (ang. loop body), blokiem instrukcji albo instrukcją złożoną. Choć to takie samo słowo kluczowe jak w Pascalu, jego znaczenie i rola są inne. Do konstrukcji pętli programowych Pascal potrzebuje słów: For, To, DownTo, Do, While, Repeat, Until. Natomiast C i C++ stosują tylko trzy słowa: for, do, while i już. Trudno uwierzyć, że C lub C++ może być prostszy od Pascala, jednakże w niektórych sytuacjach naprawdę jest. W kodzie z tego przykładu znajduje się jeszcze wywołanie funkcji bibliotecznej: kbhit() // <-- czy nacisnieto cos na klawiaturze? Zapis!kbhit() oznacza nie naciśnięto klawisza. Znak wykrzyknika spełnia w C/ C++ funkcję przeczenia, czyli jak mawiają fachowcy realizuje logiczną funkcję negacji/inwersji NOT (NIE). Samo kbhit() to nazwa gotowej funkcji bibliotecznej, która sprawdza, czy użytkownik nacisnął jakiś klawisz. Z funkcjonalnego punktu widzenia jest to dokładny odpowiednik pascalowskiego KeyPressed(). Aby spokojnie prześledzić wszystkie kolory na ekranie, potrzebny nam jeszcze jeden element łamigłówki, mianowicie sposób posługiwania się liczbami. Prościej: potrzebne nam są zmienne. Jeśli chcemy posługiwać się zmieniającymi się w trakcie pracy programu liczbami (zmieniać się powinny ich wartości, a nie nazwa czy miejsce w pamięci), powinniśmy użyć deklaracji. UWAGA Deklaracja zmiennej, jak w Pascalu, powoduje zarezerwowanie dla niej miejsca w pamięci, ale nie jest równoznaczna z definicją zmiennej. Zmienne globalne są zerowane przez kompilatory C automatycznie, natomiast początkowa wartość zmiennej lokalnej jest w C nieokreślona. Przed pierwszym użyciem należy zadeklarować i zainicjować zmienną. Listing L2305.C int main( void ) 190
Trzy ważne słowa w C int X; // <- deklaracja zmiennej calkowitej X = 0; do textbackground(x); textcolor(white); cprintf( X= ); cprintf( %d, X); X++; while (X <= 10); W przykładzie zmienna X jest licznikiem pętli. Zwróćmy uwagę na sposób wyprowadzania danych charakterystyczny dla wszystkich funkcji z grupy printf() (jest ich w bibliotekach C/C++ kilka, różnią się pierwszą literą nazwy, np. cprintf(), sprintf()): cprintf( X= ); cprintf( %d, X); Podkreślmy jeszcze raz różnicę w notacji C. Jeśli wyprowadzamy zwyczajny tekst, możemy postąpić tak: printf( %s, tekst do wyprowadzenia ); lub tak: printf( tekst do wyprowadzenia ); Znak specjalny formatujący %s oznacza string, czyli łańcuch tekstowy. Jeśli natomiast chcemy wyprowadzać inne dane, na przykład liczby, powinniśmy o tym kompilator C++ poinformować. Dlaczego? To proste. Komputery wszystkie informacje w pamięci przechowują w postaci zer i jedynek. Dla przykładu litera A zajmuje jeden bajt pamięci i jest tam zapisana w postaci swojego kodu ASCII, czyli: 0100 0001 (dziesiętnie 65, szesnastkowo 41, po prostu A ) Skąd komputer ma wiedzieć, co programista życzy sobie zobaczyć na ekranie: 65, 41 czy A? Możemy mu to wytłumaczyć w programie, na przykład tak: char BAJT = A ; // <- deklaracja i zainicjowanie zmiennej //... printf( %c, BAJT); // <-- A (c - character - znak ASCII) 191
Rozdział 23 t Trzy ważne słowa w C printf( %d, BAJT); // <-- 65 (d - decimal - dziesietnie) printf( %x, BAJT); // <-- 41 (x - hexadecimal - szesnastkowo) Możemy zapisać to samo, posługując się pętlą typu for, co pokazane zostanie w kolejnym listingu. Listing L2306.C int X; for(x=0; X<=10; X++) // naglowek sterujacy petli textbackground(x); textcolor(x+1); cprintf( Kolor tekstu = ); cprintf( %d, X); Taki zapis w języku C można przetłumaczyć tak: Dla (X = 0 Dopóki X <= 10 po każdej pętli inkrementując X = X + 1) Początek kolor tła(nr X); kolor tekstu(nr X + 1); drukuj na konsoli napis( Kolor tekstu = ); drukuj na konsoli liczbę dziesiętną. (X); Koniec Konstrukcja języka C: for ( licznik = wart_początkowa ; warunek_powtarzania ; skok_licznika )... 192
Trzy ważne słowa w C jest typowym nagłówkiem sterującym pętli programowej (ang. loop control header). Zmienna licznik (w przykładzie nazywa się X) jest tzw. zmienną sterującą pętli (ang. loop control variable). Powyższy program przykładowy wyprowadza na ekran tekst dokładnie jedenaście razy. ĆWICZENIA 1. 2. Narysuj schematy blokowe programów przykładowych z tego rozdziału. Zapisz programy przykładowe z tego rozdziału w Pascalu lub w Delphi. 3. Pobierz z systemu pomocy przykłady użycia pętli for, while, do-while. Skopiuj je, uruchom i spolszcz napisy na ekranie. 193