Artur Poznański
PROGRAMOWANIE
W JZYKU C
DLA CHTNYCH
Kraków 1998
Część 1
1. WSTP
Programowanie w ka\dym języku przypomina budowanie domku z cegieł. Czasem zamiast domku powstaje olbrzymi
gmach, a budowniczych jest cała masa. Mogą oni pracować nawet całymi latami nad jakąś budową. Zwykle nie tworzy
się programów od zera tylko korzysta z tego co się zrobiło wcześniej i jedynie to ulepsza, poprawia oraz dodaje nowe
elementy. Aby zacząć budować my równie\ będziemy musieli poznać cegiełki jakie dany język posiada. Bez wątpienia
najpopularniejszym obecnie jest język C i to nim właśnie się zajmiemy. Moim zdaniem aby umieć programować, wcale
nie jest potrzebna znajomość fachowego słownictwa jakie z pewnością odstrasza wielu chętnych tej zabawy. Dlatego w
mojej ksią\ce nie będzie takich mądrych określeń jak identyfikatory, operatory czy dyrektywy preprocesora. Mnie na
początku skutecznie zniechęcały do czegokolwiek. Nie wymagam od czytelników znajomości programowania ani
języka angielskiego czy te\ wy\szej matematyki Jedyne czego wymagam to chęci, cierpliwości i prób zrozumienia tego
o czym piszę. Zakładam, \e Ty czytelniku masz program umo\liwiający tworzenie innych programów czyli tzw.
kompilator. Ja korzystałem z kompilatora o nazwie "Borland C++" wersja 3.1 ale mo\e być oczywiście inny byleby był
języka C. To chyba na tyle uwag wstępnych. Myślę, \e niektórzy mogą mi zarzucić brak fachowości w moich opisach
ale ten tekst kierowany jest do ludzi, którzy nigdy nie programowali w \adnym języku, a marzy im się pisanie
świetnych gier lub tylko lepsze poznanie komputera. Nie chcą oni studiować opasłych tomów, gdzie zaczyna się od
rzeczy bardzo trudnych i przechodzi do jeszcze trudniejszych. Opis języka nie jest kompletny i nie zamierza wcale taki
być. Po prostu to jest ksią\ka o programowaniu nie zaś o samym języku C. Na koniec mała uwaga: Programowanie jest
przyjemne pod warunkiem, \e nie siedzi się nad nim całymi godzinami, dzień w dzień. Pamiętaj, \e świat jest piękny, a
komputer nie zastąpi jazdy na rowerze czy wycieczki w góry lub nad morze.
Miłej lektury \yczy wszystkim autor.
2. POZNAJMY NARZDZIA
Programowanie polega na pisaniu programu. Wspomniałem ju\, \e potrzebny nam jest oprócz samego komputera
jeszcze pewien program zwany kompilatorem. Kompilator jak to ktoś poetycko napisał, tłumaczy nasze bazgroły i
wypociny na język zrozumiały dla komputera. Tą czynność zwie się kompilowaniem i trwa naprawdę bardzo krótko.
Metoda jest taka: wpierw piszemy program, potem go kompilujemy, a jak nam wyskoczą błędy to je poprawiamy i
znowu kompilujemy, a\ do skutku. Obecnie kompilatory są na tyle mądre, \e mają własny edytor. Program przed
kompilacją to tak zwany kod zródłowy a po kompilacji kod wynikowy.
W kompilatorach "Borland C++" i "Turbo C++" robi się to tak. Tworzymy plik (F3), najlepiej niech ma rozszerzenie .c
. Następnie piszemy instrukcje w tym pliku. Potem naciskamy Alt-F9 co powoduje kompilację. Jeśli wszystko jest OK,
to powstaje nam plik o rozszerzeniu .exe będący programem. Uruchamianie programu w kompilatorze to Ctrl-F9. śeby
zobaczyć efekt działania zwykle wciskamy Alt-F5 który chowa okna i pokazuje to co jest pod spodem. Wa\ne aby
często zapisywać sobie naszą pracę (F2) najlepiej do kilku plików pod ró\nymi nazwami (opcja Save as..). Uchroni to
nas przed pisaniem wszystkiego od nowa np. w razie braku prądu. Z kompilatora wychodzimy kombinacją Alt-X. Są to
jedynie najwa\niejsze opcje, lecz na początek powinny wystarczyć. Jeśli masz inny kompilator, to musisz dowiedzieć
się jak się kompiluje (z ksią\ek lub lepiej spytać kogoś). System UNIX ma równie\ wbudowany kompilator C. Jednak
nie ma on edytora z okienkami i w ogóle jest zupełnie inny. Opisy kompilatorów jednak wykraczają poza ramy tej
ksią\ki. Mamy ju\ narzędzia, mo\emy tworzyć arcydzieła. Zrób mo\e wpierw tak. Utwórz plik o nazwie proba.c (z
polskimi literkami są zawsze problemy). Napisz w nim linijkę
void main(){}
i spróbuj ją skompilować. Na razie nie musisz wiedzieć co to znaczy i co to robi. Wyjaśnię tylko, \e jest to najmniejszy
program napisany w języku C. Nie robi on zupełnie nic z wyjątkiem tego, \e da się go skompilować a potem
uruchomić. W tym samym katalogu powinien Ci powstać plik o nazwie proba.exe. U mnie plik proba.c ma 14 bajtów
a proba.exe ma 6 165 bajtów (zauwa\, \e to 400 razy więcej). Jednak có\ to jest w dzisiejszych czasach 6 kb. To
naprawdę bardzo mało. Wniosek jest taki, kod wynikowy jest zwykle większy od zródłowego (przynajmniej gdy
piszemy małe programy). Powstanie tam tak\e plik proba.obj, który nie jest do niczego potrzebny i mo\na go
spokojnie skasować. Mo\na powiedzieć, \e przed chwilą napisałeś pierwszy program. Moje gratulacje !!! Proponuję
abyś przećwiczył na nim kompilowanie, uruchamianie, zapisywanie pod inną nazwą. Zrób te\ kilka błędów i zobacz co
się stanie. Nie bój się, gdy\ tylko poka\ą się komunikaty, gdzie kompilator wykrył błąd. Zwróć uwagę na to, \e
mógłbyś ten program napisać tak
void
main (
)
{ }
Jednak byłby on bardzo nieczytelny. My będziemy pisać tak aby ka\dy nawias { i } były w osobnym wierszu.
3. NIC NIE ROBI
Jeszcze nic nie robi, ale wiele się mo\na na nim nauczyć. Ostatecznie powinien wyglądać tak:
Przykład 1 ap1.c
void main()
{
}
Jest to nasza pierwsza cegiełka. Chyba najwa\niejsza, więc teraz kilka słów wyjaśnienia. Jeśli za wyrazem są nawiasy
okrągłe ( i ) znaczy to, \e jest to funkcja. Funkcja to mówiąc ogólnie wyraz będący jakąś czynnością komputera. Ka\dy
program zaczyna się od funkcji main. Jest to obowiązkowy element, jakby fundament, na którym stoi reszta. Instrukcje
dla komputera wykonywane są z góry na dół, zatem { oznacza początek zaś } oznacza koniec. Na razie nie musisz
wiedzieć co to void. Dowiesz się w swoim czasie.
4. KOMENTARZE
Komentarz to cegiełka nieobowiązkowa lecz niezmiernie u\yteczna. Kompilator nie widzi komentarzy. Zupełnie je
pomija. Jednak dla nas są nieocenione, zwłaszcza jak chcemy wrócić do jakiegoś programu po pewnym czasie.
Przykład 2 ap2.c
void main()
{ /* początek programu */
/* tu będą instrukcje dla komputera */
} /* koniec programu */
Komentarze piszemy pomiędzy znakami /* i */ . W komentarzu nie mo\e być drugiego komentarza. Będę je co jakiś
czas stosował, bo są bardzo pomocne.
5. WITAJ MISTRZU
Przydało by się by następny program ju\ coś robił. Będzie wypisywał na ekranie tekst. (Przypominam, \e Alt-F5 chowa
okna i pokazuje efekt działania programu)
Przykład 3 ap3.c
#include
void main()
{
puts("Witaj mistrzu");
}
Wyjaśniam nowe elementy. Funkcja puts wyświetla to co podamy jej w nawiasie. Jest to jedna cegiełka będąca
pojedynczą instrukcją dla komputera. Pamiętaj, \e ka\da instrukcja kończy średnikiem. Zastanawiasz się pewnie co jest
w pierwszej linii. Tak jak cegły gromadzone są w magazynach, tak wszystkie funkcje gromadzone są w plikach
zwanych bibliotekami. Funkcja puts jest w bibliotece o nazwie stdio.h. Musieliśmy kazać kompilatorowi ją dołączyć.
Inaczej nie rozpoznał by tej funkcji i podałby błąd. Spróbuj zrobić z pierwszej linii komentarz /* #include
*/ a sam się przekonasz, \e czegoś mu będzie brakować.
6. WYMAZUJE EKRAN I CZEKA NA KLAWISZ
W poprzednim programie mieliśmy jedną instrukcję wewnątrz funkcji. Takich instrukcji mo\e być wiele (nawet setki i
tysiące).
Przykład 4 ap4.c
#include
void main()
{
puts("Witaj");
puts("mistrzu");
}
Tu mamy przykład dwóch takich samych instrukcji. Zauwa\, \e funkcja puts przenosi kursor do następnej linii.
Przydałoby się gdyby to co napiszemy nie chowało się od razu. Ponadto niech napis ekran zostanie ładnie
wyczyszczony ze śmieci jakie tam zostały.
Przykład 5 ap5.c
#include
#include
void main()
{
clrscr(); /* czyszczenie ekranu */
puts("Witaj mistrzu");
getch(); /* czekanie na dowolny klawisz */
}
Dodałem trzy nowe elementy: funkcje clrscr i getch i jeszcze jeden plik z biblioteką. Funkcja clrscr czyści ekran i
ustawia kursor w lewym górnym rogu ekranu. Funkcja getch czeka na naciśnięcie jakiegoś klawisza. Obie funkcje
znajdują się w bibliotece conio.h .
7. USTAW MI KURSOR
Powiem teraz o kolejnej rzeczy. Powiedzmy, \e chcemy nasz napis umieścić na środku ekranu.
przykład 6 ap6.c
#include
#include
void main()
{
clrscr(); /* czyszczenie ekranu */
puts("\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\tWitaj mistrzu");
getch(); /* czekanie na dowolny klawisz */
}
Pewnie widać ró\nicę. Dodałem dwanaście razy \n i cztery razy \t. Symbol \n powoduje przejście do następnej linii, zaś
\t działa jak tabulator. Spróbuj pozmieniać ilość tych symboli np. dodaj jeden między dwa wyrazy i obejrzyj efekt. Jest
jednak prostszy i lepszy sposób na wyświetlenie napisu na środku.
Przykład 7 ap7.c
#include
#include
void main()
{
clrscr();
gotoxy(33,13); /* ustawienie kursora */
puts("Witaj mistrzu");
getch();
}
Zamiast tych dziwnych znaczków u\yliśmy funkcji gotoxy, która ustawia kursor na wybranej wysokości i szerokości.
W naszym przypadku kursor zostanie przeniesiony 33 pozycje w prawo i 13 w dół. Ta funkcja te\ znajduje się w
bibliotece conio.h.
8. WAASNA FUNKCJA
Powiedzmy, \e mamy takie zadanie. Niech jedno słowo będzie w lewym górnym rogu ekranu, a drugie w prawym
dolnym.
Przykład 8 ap8.c
#include
#include
void main()
{
clrscr();
gotoxy(5,2);
puts("Witaj");
gotoxy(65,24);
puts("mistrzu");
getch();
}
Nie ma tu nic nowego. Wszystko działa, jednak mo\na by połączyć dwie powtarzające się funkcje w jedną własną o
nazwie pisz. Poni\szy program działa identycznie, jednak zbudowany jest nieco inaczej.
Przykład 9 ap9.c
#include
#include
/* poni\ej jest nasza funkcja o nazwie pisz */
void pisz(int x, int y, char napis[])
{
gotoxy(x,y);
puts(napis);
}
void main()
{
clrscr();
pisz(5,2,"Witaj");
pisz(65,24,"mistrzu");
getch();
}
Pojawiło się tu sporo nowych elementów. Nie będę ich wszystkich wyjaśniał. Po pierwsze popatrz, \e teraz jest nowa
funkcja pisz, której podać trzeba trzy rzeczy: dwie liczby i tekst. Te rzeczy to tak zwane argumenty. Funkcja gotoxy
wymaga dwóch argumentów, zaś funkcja puts jednego argumentu. Wa\ne byś jedynie wiedział, \e mo\na łączyć
funkcje w inne własne funkcje. To tak jakbyś skleił dwie małe cegły i powstała ci jedna większa. W środku funkcji
pisz są trzy wyrazy: x, y i napis, które coś przechowują. Jak się nazywają dowiesz się pózniej. Zauwa\ jeszcze, \e
nasza funkcja znajduje się przed main i zaczyna się od tajemniczego void.
9. DWA PLUS DWA
Umiesz ju\ wypisać jakiś tekst w dowolnym miejscu ekranu. Teraz trzeba nauczyć się korzystać z tego, \e komputer to
wielki kalkulator. Na początek niech nam mądrala policzy ile jest 2+2.
przykład 10 ap10.c
#include
void main()
{
printf("2+2 = %d",2+2);
}
W tym celu musieliśmy skorzystać z nowej funkcji printf. Działa ona podobnie do puts ale mo\e mieć wiele
argumentów. Pierwszy argument to jakiś tekst, pozostałe muszą mieć jakąś wartość. Symbol %d oznacza, \e
kompilator ma podstawić tam liczbę, której wartość jest kolejnym argumentem. Funkcja printf ró\ni się jeszcze tym, \e
po wyświetleniu tekstu kursor nie przechodzi do nowej linii. Początkowe 2+2 to tylko napis i jeśli go zmienimy to
kompilator nie wykryje błędu. Wtedy program mo\e nam np. wyświetlić, \e 2+1 = 4 co jest oczywiście nieprawdą.
Wniosek: jak widać to co po lewej musi być równie\ po prawej.
10. DWIE ZMIENNE
Teraz czeka nas kolejne zadanie. Zmieńmy program aby obie liczby wystarczało napisać tylko w jednym miejscu.
przykład 11 ap11.c
#include
int liczba1=2, liczba2=2;
void main()
{
printf("%d+%d = %d",liczba1,liczba2,liczba1+liczba2);
}
Teraz jeśli chcemy wiedzieć ile to jest 3+4 to wystarczy poprawić jedynie dwie liczby. Co zmieniliśmy?
Wprowadziliśmy dwa wyrazy które przechowują pewną wartość. Są to tak zwane zmienne. Zmienna to w pewnym
sensie pudełko na liczby. Ka\da zmienna ma swoją nazwę. Mamy tutaj zmienne o nazwach liczba1 i liczba2, choć
równie dobrze mogłyby się nazywać a i b albo kot i pies. Jednak ja zalecam na sam początek stosowanie długich nazw,
które mówią co dana zmienna przechowuje. Trzeba zawsze na początku określić zawartość zmiennej, gdy\ jeśli jej nie
określimy to kompilator nie wykryje \adnego błędu i wsadzi tam coś przypadkowego. Pudełka mogą być ró\nych
rozmiarów. Podobnie zmienne mogą być ró\nych typów. Typ zmiennej to tak jakby rozmiar pudełka. Nasze dwie
zmienne są typu int, czyli ka\da przechowuje liczbę całkowitą.
11. PODAJ DWIE LICZBY
Nasz program jest jednak daleki od doskonałości. śeby w nim coś policzyć, trzeba zmieniać początkowe wartości w
kodzie zródłowym. Mo\e dla programisty byłby przydatny, ale nie dla zwykłego u\ytkownika. Trzeba program tak
zmienić, aby samemu mo\na było wprowadzać dane.
Przykład 12 ap12.c
#include
int liczba1=2, liczba2=2;
void main()
{
puts("Podaj dwie liczby, oddzielając je spacją:");
scanf("%d %d",&liczba1,&liczba2);
printf("%d+%d = %d",liczba1,liczba2,liczba1+liczba2);
}
Dodaliśmy dwie instrukcje. Pierwsza informuje u\ytkownika co ma robić, za pomocą znanej nam ju\ funkcji puts .
Druga to funkcja o nazwie scanf. Tu pobiera od u\ytkownika dwie liczby i wpisuje ich wartość do zmiennych liczba1 i
liczba2. Zwróć uwagę, \e przy nazwach zmiennych jest symbol &. Nie zapomnij go napisać.
12. PASKUDNE UAAMKI
Kiedy program ju\ działa, mo\na zacząć go testować. Mo\e liczby całkowite to on dodaje, ale zupełnie nie radzi sobie z
ułamkami. Na przykład podając 2 i 0.5 wypisuje wynik 2 zamiast 2.5. Trzeba będzie zmienić typ zmiennych z liczb
całkowitych na rzeczywiste.
Przykład 13 ap13.c
#include
float liczba1=2, liczba2=2;
void main()
{
puts("Podaj dwie liczby, oddzielając je spacją:");
scanf("%f %f",&liczba1,&liczba2);
printf("%.3f+%.3f = %.3f",liczba1,liczba2,liczba1+liczba2);
}
Są tu w sumie trzy zmiany. Zamiast int mamy typ float. Trzeba było tak\e zmienić symbol %d na %f. Symbol %d był
dla typu int, zaś %f jest dla typu float. Po tych przeróbkach wynik wyświetlany był z dokładnością 6 miejsc po
przecinku. Dodając .3 w funkcji printf zmniejszyliśmy dokładność do trzech miejsc po przecinku.
13. JESZCZE RAZ ?
Nasz program ju\ działa poprawnie, ale programista nigdy nie jest zadowolony. Po policzeniu czegokolwiek program
od razu wychodzi, to znaczy kończy swoje działanie. Najlepiej \eby się pytał u\ytkownika o zgodę, czy mo\e go
opuścić.
Przykład 14 ap14.c
#include
float liczba1=2, liczba2=2;
int cyferka=1;
void main()
{
do { /* powtarzaj poni\sze instrukcje... */
puts("Podaj dwie liczby, oddzielając je spacją:");
scanf("%f %f",&liczba1,&liczba2);
printf("%.3f+%.3f = %.3f",liczba1,liczba2,liczba1+liczba2);
printf("\nCzy liczymy jeszcze raz ? (0=tak):");
scanf("%d",&cyferka);
} while (cyferka == 0); /*... a\ do spełnienia warunku */
}
Zacznę wyjaśnianie od rzeczy, które są najprostsze. Pierwsze co dodaliśmy to instrukcję printf z pytaniem do
u\ytkownika. Dlaczego ją, a nie puts ? Bo chcę aby kursor pozostał w tej samej linii, a puts go przenosi do następnej.
Na początku jest symbol \n ,po to \eby cały ten tekst był w nowej linii. Funkcja scanf czeka na podanie liczby i pakuje
ją do zmiennej cyferka. Zmienna ta jest typu int i określiliśmy jej wartość jako 1 (w trzeciej linijce od góry).Teraz
nowa cegiełka instrukcja do ... while. Nazywana jest fachowo pętlą, bo instrukcje będące w środku chodzą w kółko.
Ogólnie mo\na by ją zapisać tak.
do {
instrukcja1
instrukcja2
...
} while (warunek)
Pomiędzy { } wykonywane są instrukcje tak długo, a\ zostanie spełniony warunek po while. Nasz warunek brzmi:
zmienna cyferka musi równać się 0. Symbol == oznacza znak równości. Warunek nie jest spełniony, bo wpisaliśmy
inną liczbę ? Wtedy program kończy swoje działanie. Dzięki tej pętli mo\emy opuścić program wtedy, kiedy my
chcemy i liczyć sobie nawet milion razy :)
14. T ZAMIAST ZERA
Jednak wpisywanie zera i potwierdzanie go klawiszem [Enter] jest trochę niewygodne i mało intuicyjne. Spróbujmy
zmienić to na literę t i pomińmy ten [Enter].
Przykład 15 ap15.c
#include
#include
float liczba1=2, liczba2=2;
char literka='n';
void main()
{
do {
puts("\nPodaj dwie liczby, oddzielając je spacją:");
scanf("%f %f",&liczba1,&liczba2);
printf("%.3f+%.3f = %.3f",liczba1,liczba2,liczba1+liczba2);
printf("\nCzy liczymy jeszcze raz ? (t=tak):");
literka=getch();
} while (literka == 't');
}
Zamiast zmiennej cyferka jest teraz literka. Ta zmienna ma nieco inny typ. Stanowi takie pudełko na litery, a nie na
liczby jak przy typach int i float. Typ ten ma nazwę char. Ka\da litera zaznaczana jest apostrofami (znaki ' ) . Ponadto
mamy tu nową funkcję getch, która zastąpiła scanf. Funkcja getch pobiera od nas jeden znak i wpisuje go do zmiennej
literka. Co ciekawe nie wyświetla go na ekranie komputera i nie wymaga naciskania klawisza [Enter]..Popatrz teraz na
linijkę z tą funkcją. Znak = wcale nie oznacza równości tylko przypisanie. Przypisanie znaczy danie tego co po prawej,
temu co po lewej. Tak jak na początku zmiennym liczba1 i liczba2 przypisaliśmy wartość 2, tak samo na końcu
zmiennej literka przypisaliśmy znak zwracany przez funkcję getch. Jeśli w tym miejscu nadal nie rozumiesz co to
przypisanie to zobacz następny przykład.
Przkład 16 ap16.c
#include
int a=1,b=2;
void main()
{
printf("\n%d %d",a,b);
a=b;
printf("\n%d %d",a,b);
}
Taki króciutki programik, z którego mo\emy czerpać wnioski. Mamy dwie zmienne a i b typu int. To co w sobie
zawierają poka\e nam funkcja printf. Najpierw zawierają liczby 1 i 2, potem 2 i 2. Dlaczego? Wartość zmiennej b
(czyli tego co stoi na prawo od znaku = ) została przypisana do zmiennej a (czyli tego co na lewo). Poprzednia
zawartość pudełka a została bezpowrotnie stracona. Mo\na to sobie wyobrazić jakby = działało jak strzałka w lewo.
( <= ). Koniecznie spróbuj zamienić sobie miejscami a i b, czyli napisać b=a; i obejrzeć efekt.
15. DUśA LITERA T
Wróćmy jednak do naszego programu. Kontynuuje pracę po naciśnięciu litery t. Jednak co będzie jeśli u\ytkownik ma
wciśnięty klawisz [CapsLock] ? Du\e T ju\ programowi nie pasuje, a przecie\ powinno.
Przykład 17 ap17.c
#include
#include
float liczba1=2, liczba2=2;
char literka='n';
void main()
{
do {
puts("\nPodaj dwie liczby, oddzielając je spacją:");
scanf("%f %f",&liczba1,&liczba2);
printf("%.3f+%.3f = %.3f",liczba1,liczba2,liczba1+liczba2);
printf("\nCzy liczymy jeszcze raz ? (t=tak):");
literka=getch();
} while ((literka=='t') || (literka=='T'));
}
Troszkę rozbudowaliśmy warunek w pętli do...while. Dodana jest mo\liwość, \e mo\e być te\ du\e T. Dwie kreski
pionowe oznaczają LUB. Czyli literka mo\e być równa 't' lub 'T'. Dzięki nawiasom program jest bardziej czytelny i
mamy określoną kolejność sprawdzania warunku.
16. WIZYTÓWKA
Jeszcze poinformujmy u\ytkownika co ten program robi, jak się nazywa i kto go stworzył (ach ta duma programisty :)
Przykład 18 ap18.c
#include
#include
float liczba1=2, liczba2=2;
char literka='n';
void main()
{
clrscr();
puts("*********************************");
puts("* Program DODAWANIE wersja 1.0 *");
puts("* autor: Artur Poznański *");
puts("* Program dodaje dwie liczby. *");
puts("*********************************");
do {
puts("\nPodaj dwie liczby, oddzielając je spacją:");
scanf("%f %f",&liczba1,&liczba2);
printf("%.3f+%.3f = %.3f",liczba1,liczba2,liczba1+liczba2);
printf("\nCzy liczymy jeszcze raz ? (t=tak):");
literka=getch();
} while ((literka=='t') || (literka=='T'));
}
Zrobiliśmy małą, ładną wizytówkę, która krótko opisuje nasz program. Nowe instrukcje są poza pętlą, gdy\ chcemy aby
nasza wizytówka pojawiła się tylko raz, zaraz po uruchomieniu programu. Najlepiej jeszcze, \eby taka sama wizytówka
była w naszym kodzie zródłowym jako komentarz (na samym początku jako informacja dla nas). To ju\ jednak
napiszesz sobie sam jeśli chcesz.
17. CHC MIEĆ WYBÓR
Powiedzmy, \e chwilowo jesteśmy ju\ zadowoleni, chocia\ nasz program nie jest jeszcze głupoto-odporny ( ktoś mo\e
wpisać tekst zamiast liczb; trzy liczby itp..) Zakładam, \e piszemy program dla siebie i na razie nie musi sobie z tym
radzić. Teraz nasz nowy cel to rozbudowa programu DODAWANIE o nowe działania: odejmowanie, mno\enie i
dzielenie. Najprostsze rozwiązanie to napisanie jeszcze trzech podobnych programów zamieniając jedynie kilka
drobiazgów (mo\esz to zrobić jako ćwiczenie, oczywiście zmieniając te\ komunikaty i wizytówkę). Jednak korzystanie
z czterech programów zamiast jednego staje się super niewygodne. Dodamy te działania do istniejącego programu,
jednak pora poznać najpierw potrzebne nam, nowe instrukcje.
Przykład 19. ap19.c
#include
int liczba;
void main()
{
puts("Podaj liczbę 1, 2 lub 3");
scanf("%d",&liczba);
switch(liczba)
{
case 1: puts("Podałeś 1");
break;
case 2: puts("Podałeś 2");
break;
case 3: puts("Podałeś 3");
break;
default: puts("Podałeś złą liczbę");
break;
}
}
Wpierw powiem o działaniu programu. Prosi o podanie liczby 1, 2 lub 3 i wyświetla odpowiedni napis. Tłumaczę co
nowego. Program nam się wykonuje od wyświetlenia tekstu funkcją puts i pobrania liczby funkcją scanf. W tym
przykładzie chciałem pokazać, \e nie musimy zawsze określać zawartości zmiennej zaraz przy jej nazwie (2 linijka od
góry). W tym przypadku gdybyśmy nawet napisali int liczba=0; to i tak wartość ta zostanie zmazana przez
funkcję scanf i dzięki niej określona na nowo przez u\ytkownika. Krótko mówiąc to czy określimy zawartość pudełka
liczba w tym przykładzie nie ma znaczenia i mo\emy to pominąć. Ja jednak wolę znać zawartość wszystkich moich
pudełek w ka\dej chwili. Czas omówić nową instrukcję. Nazywa się switch jest to instrukcja wyboru bo mo\emy sobie
coś wybrać, np. jedną opcję z menu. Jej ogólna budowa wygląda tak.
switch(zmienna)
{
case wartość1: instrukcja1
...
case wartość2: instrukcja2
...
default: instrukcja3
...
}
Je\eli zmienna będąca w nawiasach switch ma wartość1 to zostanie wykonana instrukcja1 i te co są po niej(czyli tak\e
instrukcja2, instrukcja3...).Je\eli zmienna ma wartość2 to wykona się instrukcja2 i te co są po niej (instrukcja3,...).Je\eli
zmienna ma jakąś jeszcze inną wartość, której nie ma po napisie case, to zostanie wykonana instrukcja3 i te pod nią.
Część default nie jest obowiązkowa i gdy jej brak, to w ostatnim omawianym przypadku nic się nie wykona. śeby nam
komputer nie wykonywał instrukcji od pozostałych case, u\ywamy instrukcji break. Wychodzi ona całkiem ze switch.
Pewnie się domyślasz, \e trzy kropki oznaczają dalsze instrukcje w ramach danej wartości. Spróbuj z tego ostatniego
przykładu skasować wszystkie break (np. zrobić z nich komentarze) i po uruchomieniu wpisać 1, 2 a potem 3.
Przekonasz się wtedy jak bardzo są potrzebne.
18. BUDUJEMY KALKULATOR
Poni\ej masz obiecany program KALKULATOR. Jeszcze bez wizytówki i paru rzeczy, które wyjdą na wierzch przy
testowaniu.
Przykład 20 ap20.c
#include
#include
float liczba1=0, liczba2=0, wynik=0;
char literka='n', znak='+';
void main()
{
do {
puts("\nPodaj liczbę, znak [+,-,*,/] i drugą liczbę.");
puts("Na końcu naciśnij [ENTER].");
scanf("%f %c %f",&liczba1,&znak,&liczba2);
switch(znak)
{
case '+' : wynik=liczba1+liczba2;
break;
case '-' : wynik=liczba1-liczba2;
break;
case '*' : wynik=liczba1*liczba2;
break;
case '/' : wynik=liczba1/liczba2;
break;
}
printf("%.3f%c%.3f = %.3f",liczba1,znak,liczba2,wynik);
printf("\nCzy liczymy jeszcze raz ? (t=tak):");
literka=getch();
} while ((literka=='t') || (literka=='T'));
}
Przykład ten jest dość podobny do przykładu 17. Jednak są tu dwie nowe zmienne: znak i wynik. Mamy inny
komunikat dla u\ytkownika (co ma robić). Potem scanf pobiera trzy dane. Zobacz, \e znak jest typu char, więc w
funkcji scanf mamy jako drugi, symbol %c. Następnie instrukcja switch bada sobie tą zmienną i kieruje program do
odpowiedniej części. Tam wykonywane jest odpowiednie działanie i jego wynik przesyłany jest (przypisany) zmiennej
o nazwie wynik. W funkcji printf zamiast liczba1+liczba2 wsadziliśmy wynik. Chcemy tak\e, aby wyświetlił nam się
odpowiedni znak działania, więc pomiędzy %f stoi %c, zaś jeden z argumentów to zmienna znak.
19. PAMITAJ CHOLERO...
Testując program stwierdzamy, \e mo\na na nim wykonać działanie 2/0. Jednak nasz kalkulator nie powinien
dopuszczać do takich obliczeń.(tylko nie pytaj dlaczego). Nieco więc go zmodyfikujemy.
Przykład 21 ap21.c
#include
#include
#include
float liczba1=0, liczba2=0, wynik=0;
char literka='n', znak='+';
void main()
{
do {
puts("\nPodaj liczbę, znak [+,-,*,/] i drugą liczbę.");
puts("Na końcu naciśnij [ENTER].");
scanf("%f %c %f",&liczba1,&znak,&liczba2);
switch(znak)
{
case '+' : wynik=liczba1+liczba2;
break;
case '-' : wynik=liczba1-liczba2;
break;
case '*' : wynik=liczba1*liczba2;
break;
case '/' : if (liczba2==0)
{
puts("Błąd: Dzielenie przez zero!");
exit(1);
}
wynik=liczba1/liczba2;
break;
}
printf("%.3f%c%.3f = %.3f",liczba1,znak,liczba2,wynik);
printf("\nCzy liczymy jeszcze raz ? (t=tak):");
literka=getch();
} while ((literka=='t') || (literka=='T'));
}
Funkcja exit powoduje zakończenie działania. Podajemy jej w nawiasie powód zakończenia (0 normalne, 1- w
wyniku błędu). Skorzystałem tu z nowej instrukcji if. Jej budowa to:
if (warunek)
instrukcja
lub
if (warunek)
instrukcja1
else
instrukcja2
Jak warunek jest spełniony to wykonuje się instrukcja (lub w drugim przypadku instrukcja1), jak nie jest spełniony to
nic się nie stanie (lub w drugim przypadku wykona się instrukcja2). Wszystko jasne? Jeśli nie to spójrz na króciutki
programik z instrukcją if.
Przykład 22 ap22.c
#include
int a=2, b=1;
void main()
{
if (a > b)
puts("a jest większe ni\ b");
else
puts("a jest mniejsze ni\ b");
}
Zmienne a i b wynoszą 2 i 1. Warunek, \e a > b jest zatem spełniony i wyświetli się napis , \e a jest większe ni\ b. Jak
zmienisz początkowe wartości a i b na odwrotne.(a=1, b=2), to wyświetli się komunikat po słowie else.
Wracając do programu Kalkulator, warunkiem dla if było to, \e zmienna liczba2 będzie się równała zero. Gdy tylko
zostanie on spełniony to wyświetla się komunikat i program przerywa działanie przez funkcję exit. Funkcja ta znajduje
się w bibliotece stdlib.h.
20. NIEWAAŚCIWY ZNAK !
Teraz mo\emy się jeszcze zabezpieczyć, \eby nie dało się wpisać jako znaku działania np. wykrzyknika albo znaku
zapytania albo innej litery oprócz tych przez nas ustalonych ( widziałeś mo\e działanie 2!2 albo 2a2 ?).
Przykład 23 ap23.c
#include
#include
#include
float liczba1=0, liczba2=0, wynik=0;
char literka='n', znak='+';
void main()
{
do {
puts("\nPodaj liczbę, znak [+,-,*,/] i drugą liczbę.");
puts("Na końcu naciśnij [ENTER].");
scanf("%f %c %f",&liczba1,&znak,&liczba2);
switch(znak)
{
case '+' : wynik=liczba1+liczba2;
break;
case '-' : wynik=liczba1-liczba2;
break;
case '*' : wynik=liczba1*liczba2;
break;
case '/' : if (liczba2==0)
{
puts("Błąd: Dzielenie przez zero!");
exit(1);
}
wynik=liczba1/liczba2;
break;
default: puts("Błąd: Niewłaściwy znak działania!");
exit(1);
break;
}
printf("%.3f%c%.3f = %.3f",liczba1,znak,liczba2,wynik);
printf("\nCzy liczymy jeszcze raz ? (t=tak):");
literka=getch();
} while ((literka=='t') || (literka=='T'));
}
Dodałem nowe trzy linijki. Jest to nieobowiązkowa część instrukcji switch. Wróć do programu 19 i popatrz jeszcze raz
na jego budowę. Po słowie default znajdują się te instrukcje, które mają się wykonać gdy wartość w nawiasie switch
nie pasuje do \adnej z wartości podanych po słowach case.
21. NARESZCIE GOTÓW
Pewnie zauwa\yłeś, \e program nam się strasznie rozbudował. Mo\e teraz wydaje ci się du\y, ale prawdziwe programy
mają dziesiątki tysięcy linijek. Nasz ma ich ledwie 35. Dodamy do niego wizytówkę i zajmiemy się budowaniem
czegoś innego.
Przykład 24 ap24.c
#include
#include
#include
float liczba1=0, liczba2=0, wynik=0;
char literka='n', znak='+';
void main()
{
clrscr();
puts(" *********************************");
puts(" * Program KALKULATOR wersja 1.0 *");
puts(" * autor: Artur Poznański *");
puts(" * Program dodaje, odejmuje, *");
puts(" * mno\y lub dzieli dwie liczby. *");
puts(" *********************************");
do {
puts("\nPodaj liczbę, znak [+,-,*,/] i drugą liczbę.");
puts("Na końcu naciśnij [ENTER].");
scanf("%f %c %f",&liczba1,&znak,&liczba2);
switch(znak)
{
case '+' : wynik=liczba1+liczba2;
break;
case '-' : wynik=liczba1-liczba2;
break;
case '*' : wynik=liczba1*liczba2;
break;
case '/' : if (liczba2==0)
{
puts("Błąd: Dzielenie przez zero!");
exit(1);
}
wynik=liczba1/liczba2;
break;
default: puts("Błąd: Niewłaściwy znak działania!");
exit(1);
break;
}
printf("%.3f%c%.3f = %.3f",liczba1,znak,liczba2,wynik);
printf("\nCzy liczymy jeszcze raz ? (t=tak):");
literka=getch();
} while ((literka=='t') || (literka=='T'));
}
W tym momencie mam jeszcze kilkadziesiąt pomysłów jak usprawnić program Kalkulator. Mo\na by dać wizytówkę
na środek ekranu, dodać potęgowanie i pierwiastki, zrobić kolorowe napisy, działania w nawiasach, obsługę myszy i
du\e przyciski, dzwięk, 100 megabajtowe intro... Ops, chyba się trochę zagalopowałem. To przecie\ ma być u\yteczny
kalkulator i taki właśnie jest, dlatego zostawimy go ju\ w spokoju (pewnie i tobie znudziło się jego ciągłe testowanie).
22. PODSUMOWANIE
W tym miejscu będzie małe podsumowanie dotychczasowych wiadomości. Wiesz ju\, \e program buduje się trochę jak
dom. Zamiast cegieł są funkcje (np. printf, scanf, puts) i instrukcje (np. if, switch, do...while). Program zaczyna się
wykonywać od funkcji main. Przed nią umieszczamy jakieś biblioteki (odpowiednik magazynów dla cegieł), oraz
określamy nazwy i typy zmiennych (jakby rozmiary pudełek).Tymi typami mogą być int (pudełko na liczby całkowite),
float (na ułamki), char (najmniejsze pudełko na pojedynczy znak). Jak kilka zmiennych jest tego samego typu, to
wymieniamy je w tej samej linii oddzielając przecinkami i kończąc średnikiem. Mo\emy te\ przypisać zmiennym jakąś
wartość znakiem = (wsadzić coś do pudełka). Przypominam, \e w funkcji scanf przed nazwą zmiennej piszemy znak &,
a warunek równości zaznaczamy symbolem ==. Zapominanie o tych dwóch ostatnich rzeczach to jedne z najczęstszych
błędów, gdy\ nie wykrywa ich kompilator.
23. KILKA RAD PRAKTYCZNYCH
Spróbuj koniecznie napisać kilka własnych programów, które coś wypiszą i coś policzą. Przez same przepisywanie
gotowych niewiele się nauczysz. Twórz, podpatruj, przerabiaj czyjeś, jednym słowem eksperymentuj. Pamiętaj, \e
najpierw trzeba wymyślić co program ma robić. Potem staramy się, \eby w ogóle działał. Ozdoby w postaci wizytówki
zostawiaj zawsze na koniec. Jeszcze jedna uwaga, nie nazywaj programów tak samo jak nazwy funkcji czy instrukcji.
Ja raz zrobiłem taki błąd. Nazwałem program if.c i skompilowałem na if.exe. Nie wiedziałem dlaczego nie chce chodzić
mimo, \e kompilator nie wykrył \adnego błędu. Teraz ju\ wiem, \e w DOS'ie jest polecenie o takiej samej nazwie... :)
Część 2
24. WYŚWIETL MI 5 LICZB
Przechodzimy ju\ do pisania nowych programów. Cel jest taki: wyświetlić 5 liczb (od 1 do 5) , jedna pod drugą.
Przykład 25 ap25.c
#include
void main()
{
printf("1\n");
printf("2\n");
printf("3\n");
printf("4\n");
printf("5\n");
}
Program robi to co chcieliśmy, ale trzeba było napisać 5 razy funkcję printf. Zmienimy to ale jeszcze nie od razu. Teraz
zastąpimy tylko te 5 liczb zmiennymi. Przypominam, \e symbol \n powoduje przejście kursora do następnej linii. Oto
kolejna wersja, obserwuj zmiany.
Przykład 26 ap26.c
#include
void main()
{
printf("%d\n",1);
printf("%d\n",2);
printf("%d\n",3);
printf("%d\n",4);
printf("%d\n",5);
}
Program robi oczywiście to samo, ale teraz mo\na będzie zastąpić liczby 1...5, zmienną powiedzmy k.
Przykład 27 ap27.c
#include
int k;
void main()
{
k=1;
printf("%d\n",k);
k=2;
printf("%d\n",k);
k=3;
printf("%d\n",k);
k=4;
printf("%d\n",k);
k=5;
printf("%d\n",k);
}
Zapytasz pewnie po co to wszystko. Ano po to, byś zrozumiał jak działa nowa instrukcja. Zobacz do czego ju\
doszliśmy. Mamy wreszcie pięć razy taką samą funkcję printf. Zmienia się tylko wartość zmiennej k.
Pamiętasz instrukcję do...while ? Spróbujemy trochę to przekształcić u\ywając właśnie jej.
Przykład 28 ap28.c
#include
int k=1;
void main()
{
do {
printf("%d\n",k);
k=k+1;
} while (k < 6);
}
Teraz jest wa\ne abyś zrozumiał jak działa ten program, który oczywiście wypisuje 5 liczb. Jest on o wiele krótszy od
poprzedniego i funkcja printf napisana jest tylko raz. Prześledzmy jak zmienia się wartość k. Wpierw wynosi ona jeden
(2 linijka od góry). Potem wykonuje się działanie k+1 (czyli 1+1) i wynik przypisany jest k (czyli 2). Zatem instrukcja
k=k+1; zwiększa wartość k o jeden. Potem wyświetla się jedynka i sprawdzany jest warunek czy k jest mniejsze od 5
(czyli 2 < 5). Warunek jest spełniony więc jedziemy na początek. Znowu k+1 (czyli 2+1) i wynik wysyłamy do k (3 <=
2+1). Wyświetla się dwójka i sprawdzany jest warunek czy k < 5 (czyli 3 < 5) . Dalej jest spełniony więc....itd. a\
warunek nie będzie spełniony czyli a\ zmienna k osiągnie wartość 6.
25. MAAE JEST PIKNE
Na koniec ostateczna wersja jeszcze bardziej skrócona dzięki nowej instrukcji.
Przykład 29 ap29.c
#include
int k;
void main()
{
for (k=1; k<6; k++)
printf("%d\n",k);
}
Cztery poprzednie programy były po to abyś mógł zrozumieć jak działa ten program. Wypisuje on 5 liczb, jednak
zajmuje jeszcze mniej ni\ poprzedni. Mamy tu instrukcję for, która jest pętlą, podobnie jak do...while. Składa się z
trzech części oddzielonych średnikami. Pierwsza z nich to instrukcja wykonywana tylko raz (tutaj k=1). Druga część
jest sprawdzanym warunkiem (k<6), zaś trzecia to instrukcja wykonywana za ka\dym razem (k++). Instrukcja k++ robi
dokładnie to samo co k=k+1, czyli zwiększa wartość k o 1. Wewnątrz pętli for znajduje się printf. Mo\na te\
umieścić wewnątrz więcej instrukcji, wtedy ogólna postać będzie wyglądać tak:
for (instrukcja1; warunek; instrukcja2)
{
instrukcja3;
instrukcja4;
...
}
Instrukcja2, instrukcja3, instrukcja4 i dalsze (wewnątrz nawiasów { }) wykonywać się będą a\ do spełnienia warunku
znajdującego się w nawiasie. Teraz ju\ nie będzie dla nas stanowić problemu np. wypisanie 20 liczb, zamiast pięciu
( wystarczy zmienić 6 na 21). A tak musiałbyś dwadzieścia razy pisać printf :( Pewnie wydaje ci się to wszystko
strasznie zagmatwane. Nie przejmuj się, wa\ne byś wiedział, \e jest taka cegiełka jak for i u\ywamy jej wtedy, gdy
wiemy ile razy ma się wykonać dana instrukcja.
26. ZNAK TO LICZBA
Teraz zrobimy coś po\ytecznego. Czy wiesz, \e ka\dy znak zapisany jest w komputerze jako liczba?
Przykład 30 ap30.c
#include
void main()
{
printf("Znak %c to liczba %d\n",'a','a');
}
Program ten wyświetli nam jaki jest kod znaku a. Funkcja printf wyświetla znak 'a' raz jako literę (symbol %c), a drugi
raz jako liczbę (symbol %d). Kod znaku a to liczba 97. A jakim liczbom odpowiadają inne znaki?
Przykład 31 ap31.c
#include
#include
char znak='a';
void main()
{
znak=getch();
printf("Znak %c to liczba %d\n",znak,znak);
}
Program czeka na naciśnięcie klawisza i podaje kod znaku. Wprowadziłem tu zmienną znak, której wartość jest
ustalana przez funkcję getch. Zauwa\, \e kody innych znaków są liczbami pomiędzy 0 a 255.
Ale jak tu sprawdzać sobie kody znaków kiedy program od razy kończy działanie?
Przykład 32 ap32.c
#include
#include
char znak='a';
void main()
{
puts("Naciskaj klawisze (q=wyjscie)");
while (znak!='q')
{
znak=getch();
printf("Znak %c to liczba %d\n",znak,znak);
}
}
Teraz zastosowałem nową pętlę, której do tej pory nie było. Nazywa się while i jej budowa to:
while (warunek)
{
instrukcja1;
instrukcja2;
...
}
Działa podobnie do pętli do...while, ale ró\ni się tym, \e warunek sprawdzany jest na początku, a nie na końcu. Jeśli
jest spełniony to wykonują się instrukcje wewnątrz nawiasów (czyli instrukcja1, instrukcja2 itd...).Natomiast jeśli nie
jest spełniony, to nie wykona się nic. W naszym przykładzie warunek wyglądał tak znak!='q' i oznacza, \e znak musi
być ró\ny od litery q. Symbol != oznacza nierówność. Na samym początku zmienna znak miała wartość a (patrz na 2
linijkę od góry) a zatem warunek został spełniony i program wskoczył do instrukcji wewnątrz pętli. Pobrany jest znak,
(np. b) wyświetlony jego kod (dla b jest to 98) i z powrotem sprawdzany jest warunek w nawiasach (znak!='q' czyli b
ró\ne od 'q'). Jak chcemy skończyć działanie programu to naciskamy 'q' gdy\ wtedy warunek ró\ności nie zostanie
spełniony i program pominie instrukcje znajdujące się wewnątrz pętli. Co się stanie jak na początku zmienna znak
będzie miała wartość 'q' zamiast 'a' ? Nie wykona się \adna instrukcja będąca wewnątrz pętli while.
27. NIE WYŚWIETLAJ KODU Q
Testujemy i ju\ nam się znudziło. Naciskamy 'q' a program zamiast od razu wyjść, wypisuje nam jeszcze kod tej litery.
Jak temu zaradzić?
Przykład 33 ap33.c
#include
#include
char znak='a';
void main()
{
puts("Naciskaj klawisze (q=wyjscie)");
while (1)
{
znak=getch();
if (znak=='q')
break;
printf("Znak %c to liczba %d\n",znak,znak);
}
}
Mo\na by w ten sposób. Jedynka w nawiasie oznacza warunek zawsze spełniony (1 to prawda, 0 to nieprawda). Potem
pobierany jest znak. Zanim zostanie wypisany na ekran, instrukcja if sprawdza czy nie jest to klawisz 'q'. Jak jest to
wykonuje się instrukcja break powodująca wyjście z pętli while. Czyli jak naciśniemy q to nie poka\e nam się jego
kod a przecie\ o to nam chodziło.
28. NIECH WYCHODZI ESKEJP
Zauwa\, \e kod klawisza ENTER to 13, kod ESC to 27 zaś SPACJA ma 32. Mo\emy to wykorzystać zmieniając
program aby wychodziło się z niego inaczej.
Przykład 34 ap34.c
#include
#include
char znak='a';
void main()
{
puts("Naciskaj klawisze (ESC=wyjscie)");
while (1)
{
znak=getch();
if (znak==27) /* 27 to kod klawisza ESC */
break;
printf("Znak %c to liczba %d\n",znak,znak);
}
}
29. LICZBY Z MINUSAMI
Ja mam Windows 95 i jak nacisnę ALT-A to dla litery ą wyskakuje kod 91. Podobnie jest z innymi polskimi znakami.
Dlaczego? Odpowiedz jest taka. Kody liczb są od 0 do 255. Tylko, \e typ char potrafi przechowywać liczby pomiędzy
-127 a 128 i dla tych polskich następuje jakby przekręcenie licznika. Następny program ju\ sobie z tym radzi.
Przykład 35 ap35.c
#include
#include
unsigned char znak='a';
void main()
{
puts("Naciskaj klawisze (ESC=wyjscie)");
while (1)
{
znak=getch();
if (znak==27)
break;
printf("Znak %c to liczba %d\n",znak,znak);
}
}
Zmieniłem jedynie typ z char na unsigned char. Dodanie tego słówka spowodowało, \e zmienna znak mo\e pomieścić
liczby tylko dodatnie, więc przesunął się zakres z 127...128 do 0...255. Teraz ju\ ą ma 165 zaś ń to 228 (zamiast 28).
30. ROBIMY TABLIC
Spróbujemy sobie zrobić taką tablicę wszystkich kodów. ( Jako ciekawostkę dodam, \e te kody są to tzw. kody ASCII)
Przykład 36 ap36.c
#include
#include
unsigned char znak='a';
void main()
{
clrscr();
for (znak=32; znak<255; znak++)
printf("%d=%c",znak,znak);
}
Dzięki instrukcji for zmienna znak przyjmuje wartości od 32 do 254. Zastanawia cię pewnie dlaczego wyświetlamy
dopiero od 32 znaku a nie od zerowego ? Te znaki do 32 są sterujące i wyświetlanie ich mo\e być kłopotliwe( np. znak
o kodzie 7 wywołuje dzwięk głośniczka).
31. PORZDKI NA EKRANIE
Jednak po uruchomieniu programu na ekranie widać straszny bałagan. Trzeba zrobić naszą tablicę bardziej czytelną.
Przykład 37- ap37.c
#include
#include
unsigned char znak='a';
void main()
{
clrscr();
for (znak=32; znak<255; znak++)
printf("%6d=%c",znak,znak);
}
Dopisaliśmy tylko jedną cyferkę w funkcji printf, ale za to jaka ró\nica ! Teraz mamy wszystkie kody ładnie
poukładane w dziesięciu kolumnach. Cyfra 6 przed literką d powoduje, \e na liczbę zarezerwowane jest 6 miejsc.
Ekran mo\e pomieścić 80 znaków w poziomie i 25 w pionie. Sześć znaków na liczbę plus znak = i znak wyświetlany
daje w sumie osiem. 80/8 równa się 10 i stąd mamy dziesięć kolumn.
32. NA KONIEC KOSMETYKA
Powiedzmy, \e program się nam ju\ podoba i poprawimy jedynie by nie kończył od razu działania oraz dodamy
wizytówkę.
Przykład 38- ap38.c
#include
#include
unsigned char znak='a';
void main()
{
clrscr();
puts("***************************************");
puts("* Program TABLICA ZNAKÓW wersja 1.0 *");
puts("* autor: Artur Poznański *");
puts("* Opis: program wyświetla wszystkie *");
puts("* kody znaków ASCII *");
puts("***************************************");
puts("\nNaciśnij dowolny klawisz...");
getch();
clrscr();
for (znak=32; znak<255; znak++)
printf("%6d=%c",znak,znak);
puts("\nNaciśnij dowolny klawisz...");
getch();
}
Nie ma tu \adnych nowych instrukcji i chyba nie musze mówić co ten program robi. Zauwa\, \e w dwóch miejscach
mamy po dwie takie same instrukcje. Chodzi mi o funkcje puts i getch. Zastąpimy je jedną własną o nazwie dowolny.
Lecz wpierw troszkę teorii.
Przykład 39 ap39.c
void jakas_funkcja(void)
{ /* początek naszej funkcji */
/* tu będą instrukcje */
} /* koniec naszej funkcji */
void main()
{
jakas_funkcja();
}
Ten program nic nie robi. To jest demonstracja jak się tworzy własne funkcje. Wiesz, \e program wykonuje się od
funkcji main. Potem przechodzi do funkcji o nazwie jakas_funkcja i wykonuje wszystkie instrukcje wewnątrz jej. (Na
razie ich nie ma, ale zaraz je dodamy). Teraz jeszcze zauwa\, \e nasza funkcja ma z przodu słówko void i wewnątrz
nawiasu równie\. Teraz ci powiem co to oznacza. Słowo void oznacza dosłownie nic. Nic tej funkcji nie przekazujemy
(void w nawiasie) i nic ona nie zwraca (void przed nazwą). Tutaj pewnie się załamiesz. Jak funkcji mo\na coś
przekazać ? Co funkcja mo\e zwracać ? A pamiętasz poprzednie funkcje ? Funkcjom puts, prinf, scanf i gotoxy
mo\na było przekazać argumenty ( jakiś tekst, jakieś liczby). Funkcja getch zwracała nam naciśnięty znak.
33. NACIŚNIJ COŚ
Zrobimy teraz funkcję, która czeka na klawisz.
Przykład 40 ap40a.c
#include
#include
void dowolny(void)
{
puts("\tNaciśnij dowolny klawisz...");
getch();
}
void main()
{
dowolny();
}
Tutaj w funkcji main wywoływana jest jedynie nasza funkcja dowolny, która z kolei wykonuje dwie instrukcje
(wypisanie tekstu i czekanie na klawisz). Własną funkcję mo\na te\ umieścić pod main, ale nad nią musi zostać sam
nagłówek funkcji (pierwsza linijka funkcji).
Przykład 40 ap40b.c
#include
#include
void dowolny(void); /* to jest ta pierwsza linijka */
void main()
{
dowolny();
}
void dowolny(void)
{
puts("\tNaciśnij dowolny klawisz...");
getch();
}
W podręczniku do C widziałem stosowanie drugiej metody. Jednak moim zdaniem ta pierwsza jest lepsza, bo mamy
mniej pisania (gdy\ nie wsadzamy przed main nagłówków). Ja ją będę stosował, ale Ty oczywiście mo\esz robić
inaczej.
34. POWRÓT DO TABLICY
Wróćmy do programu TABLICA ZNAKÓW i zmieńmy to co zamierzaliśmy zmienić.
Przykład 41- ap41.c
#include
#include
unsigned char znak='a';
void dowolny(void)
{
puts("\tNaciśnij dowolny klawisz...");
getch();
}
void main()
{
clrscr();
puts("***************************************");
puts("* Program TABLICA ZNAKÓW wersja 1.0 *");
puts("* autor: Artur Poznański *");
puts("* Opis: program wyświetla wszystkie *");
puts("* kody znaków ASCII *");
puts("***************************************");
dowolny();
clrscr();
for (znak=32; znak<255; znak++)
printf("%6d=%c",znak,znak);
dowolny();
}
Program ten robi dokładnie to samo, co program z przykładu 38. Co prawda poprzez zastąpienie dwóch instrukcji jedną
zysk wydaje się niewielki, ale program zyskał na czytelności. Zasada w programowaniu jest taka, \eby mieć jak
najmniej instrukcji w funkcji main.
35. WIZYTÓWKA NA ŚRODEK
A\ \al ściska jak widzę ile miejsca się marnuje, gdy nasza śliczna wizytówka wyświetla się w lewym górnym rogu
ekranu. Spróbujemy wyświetlić ją na środku ekranu. W tym celu skorzystamy z funkcji pisz będącej w przykładzie 9.
Przykład 42-ap42.c
#include
#include
unsigned char znak='a';
void pisz(int x, int y, char napis[])
{
gotoxy(x,y);
puts(napis);
}
void dowolny(void)
{
pisz(1,24,"Naciśnij dowolny klawisz...");
getch();
}
void main()
{
clrscr();
pisz(20,10,"***************************************");
pisz(20,11,"* Program TABLICA ZNAKÓW wersja 1.0 *");
pisz(20,12,"* autor: Artur Poznański *");
pisz(20,13,"* Opis: program wyświetla wszystkie *");
pisz(20,14,"* kody znaków ASCII *");
pisz(20,15,"***************************************");
dowolny();
clrscr();
for (znak=32; znak<255; znak++)
printf("%6d=%c",znak,znak);
dowolny();
}
Teraz ju\ wizytówka jest mniej więcej na środku. Przyjrzyj się zmianom. Zacznę od funkcji main. Wizytówkę
wyświetla obecnie funkcja pisz. Pierwsze dwie liczby wewnątrz niej to pozycja kursora dla wyświetlanego tekstu.
Zmieniłem te\ funkcję dowolny. Równie\ w niej znajduje się wywołanie funkcji pisz, którą umieściłem na samej
górze. Dlaczego pisz jest przed dowolny (znajduje się wy\ej) ? Poniewa\ funkcje będące pózniej mogą wykonywać
jedynie instrukcje zawarte w funkcjach będących wcześniej. Mówiąc po ludzku, gdy zamienimy miejscami funkcje
pisz i dowolny (oczywiście nie w main :) to kompilator dojdzie do pisz i nie będzie wiedział co to jest, gdy\ nie została
WCZEŚNIEJ zdefiniowana (określona jej zawartość). Od tej pory zajmiemy się czymś zupełnie innym.
36. ZRÓBMY BIP
Ka\dy komputer ma wbudowany głośniczek. Spróbujemy poznać nowe funkcje, wydobywające dzwięki z naszego
peceta.
Przykład 43 ap43.c
#include
void main()
{
sound(200);
delay(500);
nosound();
}
Ten program wyda nam krótki półsekundowy dzwięk. Są tutaj trzy nowe funkcje (wszystkie w bibliotece dos.h).
Funkcja sound powoduje wydobycie z głośnika dzwięku o podanej częstotliwości. Funkcja delay wstrzymuje działanie
programu na pewien czas podany w milisekundach (1 sekunda = 1000 milisekund). Ostatnia z przedstawionych funkcji
to nosound. Wyłącza ona głośniczek włączony wcześniej funkcją sound.
37. DAJ GAOS
Od razu przerobimy ten wcześniejszy programik na własną funkcję, powiedzmy dzwiek (w nazwach funkcji nie mo\na
stosować polskich liter :( ) .
Przykład 44 ap44.c
#include
void dzwiek(int nuta, int czas)
{
sound(nuta);
delay(czas);
nosound();
}
void main()
{
dzwiek(200,500);
}
Program robi to samo co poprzedni. Jedyna zmiana to własna funkcja dzwiek, której przekazujemy dwa argumenty,
pierwszy to wysokość dzwięku (częstotliwość), drugi to jego długość (czas trwania).
38. STAAE A ZMIENNE
W kolejnym przykładzie zademonstruję nowy element języka C. Będą nim stałe (tu wysokosc i czas).
Przykład 45 ap45.c
#include
const wysokosc=200, czas=500;
void dzwiek(int nuta, int czas)
{
sound(nuta);
delay(czas);
nosound();
}
void main()
{
dzwiek(wysokosc,czas);
}
W programie wystąpiło słówko const, które powoduje, \e wyrazy wymienione za nim to stałe. Stała to taka zmienna,
która nie mo\e się zmieniać i dlatego tak się nazywa. Mówiąc prościej jest to (podobnie jak zmienna ) pewne pudełko
na liczby. Lecz jak coś do niego wsadzimy (przypiszemy znakiem =) to ju\ nie mo\emy tego zmienić. Ma to swoje
plusy jak i minusy. Na przykład jak tworzymy pudełko pi na liczbę 3.14 to powinna to być stała. Od tego momentu
wszystkie stałe będę pisał WIELKIMI LITERAMI. Obowiązku oczywiście nie ma, ale wszyscy tak robią, bo dzięki
temu łatwiej w programie je odró\nić od zmiennych.
39. WLAZA KOTEK NA PAOTEK
Zrobimy teraz takie małe pianino, \e po naciśnięciu przycisku zagra odpowiedni dzwięk.
Przykład 46 ap46.c
#include
#include
const C2=131,
D2=147,
E2=165,
F2=175,
G2=196,
A2=220,
B2=248,
C3=262,
CZAS=200;
char znak;
void dzwiek(int nuta, int czas)
{
sound(nuta);
delay(czas);
nosound();
}
void main()
{
while(1)
{
znak=getch();
if (znak==27) /* 27 to kod klawisza ESC */
break;
switch(znak)
{
case 'a' : dzwiek(C2,CZAS);
break;
case 's' : dzwiek(D2,CZAS);
break;
case 'd' : dzwiek(E2,CZAS);
break;
case 'f' : dzwiek(F2,CZAS);
break;
case 'g' : dzwiek(G2,CZAS);
break;
case 'h' : dzwiek(A2,CZAS);
break;
case 'j' : dzwiek(B2,CZAS);
break;
case 'k' : dzwiek(C3,CZAS);
break;
} /* koniec switch */
} /* koniec while */
} /* koniec main */
Co programik robi ? Klawisze od a do k wydają dzwięki, ESC wychodzi. Na tym pianinie mo\na zagrać słynną melodię
"Wlazł kotek na płotek"( klawisze g d d f s s a d g, g d d f s s a d a). Dwa słowa o budowie programu. wszystkie
elementy omawiałem ju\ wcześniej więc jeśli rozumiesz poprzednie przykłady, zrozumiesz i działanie tego (mam taką
nadzieję). Ka\da nuta ma swój dwuliterowy symbol, który ma stałą częstotliwość. Z tych symboli zrobiliśmy stałe
(przecie\ nie chcemy aby zmieniała nam się wysokość danej nuty). Nie trzeba określać typu stałej, wystarczy na
początku słówko const. Wszystkie stałe pisałem jedna pod drugą, \eby program był czytelniejszy. Stałą CZAS
ustawiłem na 200 bo 500 to jak dla mnie trochę za długo. Mo\e pokusisz się o napisanie programu, który sam zagra
jakąś melodię (np. tą podaną przeze mnie).
39. WIZYTÓWKA I STARY NIEDyWIEDy
Oto ostatnie kosmetyczne przeróbki ( u\ytkownik powinien wiedzieć co ma wciskać :).
Przykład 47 ap47.c
#include
#include
#include
const C2=131,
D2=147,
E2=165,
F2=175,
G2=196,
A2=220,
B2=248,
C3=262,
CZAS=200;
char znak;
void dzwiek(int nuta, int czas)
{
sound(nuta);
delay(czas);
nosound();
}
void main()
{
clrscr();
puts(" *********************************");
puts(" * Program PIANINO wersja 1.0 *");
puts(" * autor: Artur Poznański *");
puts(" * opis: Program wydaje przez *");
puts(" * wbudowany głośniczek dzwięki. *");
puts(" *********************************");
puts("\nKlawisze od [a] do [k] wydają odpowiedni dzwięk.");
puts("Klawisz [ESC] powoduje opuszczenie programu.");
while(1)
{
znak=getch();
if (znak==27) /* 27 to kod klawisza ESC */
break;
switch(znak)
{
case 'a' : dzwiek(C2,CZAS);
break;
case 's' : dzwiek(D2,CZAS);
break;
case 'd' : dzwiek(E2,CZAS);
break;
case 'f' : dzwiek(F2,CZAS);
break;
case 'g' : dzwiek(G2,CZAS);
break;
case 'h' : dzwiek(A2,CZAS);
break;
case 'j' : dzwiek(B2,CZAS);
break;
case 'k' : dzwiek(C3,CZAS);
break;
} /* koniec switch */
} /* koniec while */
} /* koniec main */
Có\ mogę więcej dodać do tego co ju\ wiesz. Częstotliwości dzwięków wziąłem z ksią\ki Janusza Malika pt. "Norton
Utilites 6.0" (str.158). Jak znam \ycie pewnie jej nie masz, a mo\e ci być za mało te osiem dzwięków (np. próbując
zagrać "Stary niedzwiedz mocno śpi"). Mam nadzieję, \e autor ksią\ki się nie obrazi jeśli przytoczę wartości dla trzech
pierwszych oktaw.
C 65 131 262 F#/Gb 93 185 370
C#/DB 69 139 277 G 98 196 392
D 73 147 294 G#/Ab 104 208 415
D#/Eb 78 156 311 A 110 220 440
E 82 165 330 A#/Bb 117 233 466
F 87 175 349 B 123 248 494
Mo\na by program zmodyfikować, \eby klawisze plus i minus wydłu\ały bądz skracały czas dzwięku ale twoja w tym
głowa jak to zrobić ( dam ci podpowiedz: trzeba pewną stałą przerobić na zmienną).
40. TROCH NAMIESZAM
Dzisiaj poznasz rzecz, która mo\e bardzo ułatwić programiście \ycie. Pamiętasz wizytówkę z poprzedniego programu ?
Nie umieszczałem jej na środku ekranu bo na początku musiałbym umieścić funkcję pisz, znaną choćby z przykładu 9.
Takie wstawianie tych samych funkcji do plików jest dość ucią\liwe. Lecz znaleziono na to radę. Mo\emy wszystkie
nasze funkcje umieścić w jednym pliku, a potem się do niego odwoływać. Niejako przy okazji poznasz jeszcze jedną
nową rzecz od której teraz zacznę.
Przykład 48 ap48.c
#include
int wynik=0;
int suma(int a, int b)
{
return(a+b);
}
void main()
{
wynik=suma(2,2);
printf("Wynik wynosi %d",wynik);
}
Jest to chyba najprostszy program jaki udało mi się wymyślić by pokazać jeszcze jedną własność funkcji. Oprócz tego,
\e funkcji mo\na coś przekazać, to funkcja mo\e nam coś zwracać. Poprzednie nasze funkcje nic nie zwracały bo miały
na początku słowo void. Tutaj występuje funkcja suma, która zwraca liczbę całkowitą (ma przed nazwą słowo int).
Zwracaną wartością jest zawsze to co znajduje się w nawiasie instrukcji return. Liczba zwracana przez funkcję suma
przypisana jest zmiennej wynik, której wartość na koniec wyświetla printf. Czy domyślasz się jaką liczbę wyświetli
program ?
49. WAASNA BIBLIOTEKA, HURA !!!
Jeśli chcielibyśmy korzystać z funkcji suma w innych programach, to zrobimy sobie własną bibliotekę ( taki plik z
funkcjami). Po przeróbkach program, który robi to co poprzedni lecz korzysta z funkcji, które są poza nim, wygląda
tak:
Przykład 49 ap49.c
#include
#include "moja.h"
void main()
{
wynik=suma(2,2);
printf("Wynik wynosi %d",wynik);
}
Plik moja.h
int suma(int a, int b);
Plik moja.c
int suma(int a, int b)
{
return(a+b);
}
Program z przykładu 49 składa się z trzech plików, które muszą podczas kompilacji znajdować się w tym samym
katalogu. Stworzyliśmy bibliotekę o nazwie moja, która jest dołączana do programu (słowo #include). Biblioteka
składa się z dwóch części: pliku z rozszerzeniami .c i .h . W pliku moja.c jest cała funkcja, zaś w pliku moja.h tylko jej
nagłówek ( przypominam, \e nagłówek to pierwsza linijka funkcji). Pewnie zdziwi cię dlaczego nazwa moja.h jest po
podana w cudzysłowie a nie w nawiasach < >. Cudzysłów oznacza tu, \e biblioteka ma być szukana w bie\ącym
katalogu, zaś nawiasy < > oznaczają, \e kompilator szuka w standardowym (jakimś swoim) katalogu . Jak to udało mi
się skompilować? Szczerze powiedziawszy na początku miałem z tym drobne problemy. śeby w moim kompilatorze
skompilować więcej ni\ jeden plik, trzeba otworzyć tzw. projekt (opcja Open project...), tam podać nazwę (np. suma).
Otworzy się okienko, gdzie mo\emy dodać pliki do kompilacji (tu wystarczy moja.c i ap49.c). Naje\d\amy na plik
moja.c i naciskamy F9 (kompilacja). Jak nie ma błędu powstanie plik taki jak nazwa projektu z rozszerzeniem .exe (tu
suma.exe). To tyle wyjaśnień.
50. STAAA NA GAÓWKACH
Zróbmy sobie bibliotekę o nazwie apbibl1.c (bibl to skrót od słowa biblioteka, zaś co znaczy ap ju\ się pewnie
domyśliłeś :). Umieścimy w niej wszystkie funkcje, do tej pory przez nas stworzone (oprócz tej ostatniej bo jest mało
przydatna).
Przykład 50 ap50.c
#include
#include "apbibl1.h"
void main()
{
clrscr();
pisz(20,10,"W tym programie wykorzystałem własne funkcje");
dzwiek(C2,CZAS);
dowolny();
pisz(25,15,"znajdujące się w innych plikach.");
dzwiek(C3,CZAS);
dowolny();
}
Plik apbibl1.h
const C2=131,
D2=147,
E2=165,
F2=175,
G2=196,
A2=220,
B2=248,
C3=262,
CZAS=200;
void pisz(int x, int y, char napis[]);
void dowolny(void);
void dzwiek(int nuta, int czas);
Plik apbibl1.c
#include
#include
#include
void pisz(int x, int y, char napis[])
{
gotoxy(x,y);
puts(napis);
}
void dowolny(void)
{
pisz(1,24,"Naciśnij dowolny klawisz...");
getch();
}
void dzwiek(int nuta, int czas)
{
sound(nuta);
delay(czas);
nosound();
}
Plik zawierający nagłówki funkcji zwany jest plikiem nagłówkowym. Wszystkie pliki z rozszerzeniem .h są plikami
nagłówkowymi. W naszym pliku nagłówkowym apbibl1.h umieściliśmy oprócz trzech nagłówków jeszcze stałe. Mogą
być u\ywane we wszystkich programach do których dołączymy tą bibliotekę. Świetnym pomysłem jest zrobienie sobie
stałych z kodów wa\niejszych klawiszy np. ESC=27, ENTER=13, SPACJA=32 itp.
51. PODSUMOWANIE 2
Najwy\sza pora na kolejne podsumowanie, które być mo\e poukłada nieco w głowie. Poznałeś nowe instrukcje (for,
while, break, return), a tak\e nowe funkcje (sound, delay, nosound). Wiesz ju\ co oznacza słówko void oraz to, \e
litery w komputerze są przechowywane jako liczby. Własne funkcje (np. pisz, dowolny, dzwiek) mo\na umieszczać we
własnych bibliotekach (np apbibl1). Funkcji mo\na coś przekazać (np. dwie liczby) i mo\e coś zwracać (np. ich sumę).
Oprócz zmiennych istnieją jeszcze podobne pudełka zwane stałymi (pisaliśmy je WIELKIMI LITERAMI). Ich wartość
(zawartość) i nazwę określamy po słówku const. Pierwsza linijka funkcji to jej nagłówek, zaś pliki z rozszerzeniem .h
to pliki nagłówkowe (np. stdio.h, conio.h czy moja.h).
52. KILKA UWAG PRAKTYCZNYCH 2
Mo\e cię to zmartwi, a mo\e ucieszy, ale to wszystko co poznaliśmy do tej pory, to jedynie maleńki fragment
mo\liwości języka C. Jednak pozwala pisać proste programiki i poznać lepiej mo\liwości swego komputera.
Programowanie to zabawa dla cierpliwych. Mo\na parę godzin szukać jakiegoś błahego błędu, lecz jaka jest potem
olbrzymia satysfakcja ! Nie zatrzymuj się w miejscu ! Jeśli jeden program nie chodzi, a ty nie wiesz czemu, zaznacz to
w komentarzu i próbuj z drugim programem. Gdy ju\ więcej się nauczysz (zostaniesz świetnym programistą), wtedy
wróć do tego pierwszego i będziesz miał zupełnie nowe spojrzenie. Co prawda kompilator wykrywa więcej ni\ jeden
błąd, ale ty nie staraj się poprawiać ich wszystkich lecz pierwszy napotkany. Nie ma ludzi omylnych. Ja te\ mogłem się
gdzieś pomylić. Najwa\niejsze by się nie poddawać i by stale zdobywać wiedzę. Tylko ta wiedza jest warta, z której
umiesz skorzystać. Praktyka czyni mistrza !
KONIEC
Wyszukiwarka
Podobne podstrony:
PROGRAMOWANIE w c dla chetnych
01 Wprowadzenie do programowania w jezyku C
Wykrywacz Religijnej Manipulacji – program antywirusowy dla umysłu
Programowanie w jezyku C Szybki start procss
Efektywne Programowanie W Języku Java
Lab Programowanie w jezyku powloki
Oracle?tabaseg Programowanie w jezyku PL SQL or10ps
Zadanie dla chetnych
Wprowadzenie do programowania w języku C
Ćwiczenie 16 dla chętnych
więcej podobnych podstron