Podstawy języka C.doc

(164 KB) Pobierz

Podstawy języka C++

Większość kursów C++, jakie widziałem w necie, zaczyna się od omówienia tego, co C++ odziedziczył w spadku po języku C. Uważam, że takie podejście jest szkodliwe. Przede wszystkim dlatego, że nie każdy, kto chce nauczyć się C++, znał wcześniej C lub jakiś inny podobny język programowania. Niektórzy zaczynają od łysego zera i wcale nie jest im łatwo, gdy autor kursu co chwilę fąfra coś o języku C, którego przecież nie znają! :-P

Poza tym kursy zaczynające od C uczą Cię tak naprawdę języka C i skazują na jego ograniczenia :-P Ucząc się z takiego kursu nabierzesz złych nawyków: będziesz próbować w C++ pisać programy w taki sam sposób, jak się to robiło w C. A przecież C++ to jednak nie jest C, lecz zupełnie nowy język z nowymi możliwościami, których w C nie było [te dwa plusy nie są tam dla picu ;-P]. Wiele rzeczy w C++ robi się inaczej, niektóre nawet dużo prościej niż w C. Warto więc skorzystać z tych udogodnień - do tego przecież został stworzony! :-)

Jest jeszcze jedna wada zaczynania nauki od C. Język ten był raczej "niskopoziomowy" i nawet najprostsze rzeczy wymagały od programisty sporej wiedzy o szczegółach działania komputera. C++ jest tak pomyślany, że na początku nauki nie musisz wcale wiedzieć zbyt wiele, by móc skorzystać z jego nowych możliwości i wcale nie musisz posiadać dużej wiedzy, by zrobić proste rzeczy. Doświadczenie możesz więc zdobywać stopniowo, w czasie nauki języka, a techniczne szczegóły poznajesz dopiero wtedy, gdy są Ci one potrzebne by zrobić coś bardziej nietypowego. Nie trzeba przecież być elektronikiem, by używać komputera ;-)

Dlatego właśnie w moim kursie postanowiłem przyjąć od początku, że C++ jest pierwszym językiem, którego się uczysz. Będę Cię zaznajamiał z nowoczesnym stylem pisania programów i od początku będziemy korzystać z nowych możliwości, jakie daje Biblioteka Standardowa C++. Dzięki temu będziesz w stanie od razu pisać użyteczne programy i na bieżąco widzieć efekty ich działania. Nauka będzie przebiegać stopniowo i przyjemnie ;-)

Jeśli należysz do tych, którzy wcześniej znali C, takie podejście może Cię trochę niepokoić. Możesz czuć się trochę niepewnie widząc, że odbiegam trochę od tego, co znasz dobrze z C. Możesz też mieć wątpliwości, czy nowe mechanizmy obiektowe dostępne w C++ są tak samo wydajne, jak te używane w C. Proszę jednak, powstrzymaj się narazie z oceną. W trakcie kursu zobaczysz, że jednak ten nowy styl ma swoje zalety i warto programować w taki sposób ;-) Przekonasz się, że dzięki temu programowanie staje się prostsze, mniej podatne na błędy, a wydajność jest przeważnie taka sama [będę niekiedy wyjaśniał, dlaczego tak jest ;-)].

Najbardziej wkurzały mnie zawsze w innych kursach teksty w stylu: "Narazie nie mogę Ci tego wyjaśnić, bo jesteś za głupi, dowiesz się jak wyrośniesz z pieluch [czyli za X lekcji] a narazie rób tak, jak Ci mówię, i nie zadawaj durnych pytań" :-P Dlatego w moim kursie będę się starał unikać takiego podejścia i wyjaśniać wszystko od razu na tyle, na ile się da, by działanie programu było dla Ciebie zrozumiałe. Bardziej szczegółowe wyjaśnienia czasami będę odkładał do czasu, aż okażą się konieczne by coś zrozumieć. Jednak będę tak robił tylko po to, by nie przeciążać Ci mózgownicy informacjami, które na początku nauki i tak nie będą Ci jeszcze potrzebne ;-)

No, to by było tyle ględzenia na wjazd ;-P Zapraszam do czytania i życzę przyjemnej nauki :-)

Obiekty i typy danych

Witaj w pierwszej lekcji kursu programowania w języku C++ :-) Tak właściwie to powinna być lekcja zerowa, bo Twój pierwszy w życiu program napiszemy wspólnie dopiero w następnej lekcji [a poza tym programiści liczą od zera ;-D]. Natomiast z lekcji, którą teraz czytasz, dowiesz się czym są obiekty i o co tyle szumu ;-J Dowiesz się także jakie typy danych są dostępne w języku C++ i poznasz pierwsze słowa kluczowe języka, będące nazwami tych typów. Tak więc dość gadania, bierzemy się za konkrety...

Co to jest obiekt?

Jak już pewnie wiesz z artykułu Dlaczego wybrać C++, język C++ wspomaga programowanie obiektowe, czyli pozwala Ci posługiwać się w Twoich programach tak zwanymi obiektami. Obiekt reprezentuje w Twoim programie pewien element ze świata rzeczywistego [modeluje go].

Pewnie coniektórzy old-schoolowcy mnie teraz zlinczują, że wprowadzam pojęcie obiektu już na tym etapie ;-P Jednak zrobiłem to celowo, żeby już od początku uczyć właściwego sposobu myślenia i programowania w języku C++. Z początku może się to wydawać dziwne, jednak szybko się okaże, że w tym szaleństwie jest logika i takie podejście bardzo ułatwia pisanie i rozumienie programów ;-)

W języku C++ obiekt to jest takie coś, co znajduje się gdzieś w pamięci komputera i zajmuje w niej pewien ciągły, jednolity obszar. Wiadomo dokładnie gdzie on się zaczyna i gdzie się kończy. Potrafimy go więc odróżnić od pozostałych połaci pamięci ;-J oraz ocenić, jak dużo tej pamięci zajmuje.

W tej pamięci obiekt może przechowywać jakieś dane. Bieżącą wartość przechowywaną w obiekcie nazywamy jego stanem. Obiekty mogą być zmienne lub stałe. Obiekty zmienne [zwane potocznie zmiennymi] mogą zmieniać swój stan w czasie działania programu, natomiast obiekty stałe [zwane potocznie stałymi] przez cały czas działania programu mają ten sam stan [przechowują tę samą wartość] i nie mogą go zmieniać.

Ale to oczywiście nie koniec. Na obiektach można też wykonywać pewne operacje. Jeśli jako przykład weźmiemy obiekty przechowujące liczby, to operacjami, jakie możemy na nich wykonywać, mogłyby być dodawanie, odejmowanie, mnożenie, dzielenie itp.

Typy danych

Oczywiście trzeba wiedzieć, co oznacza wartość przechowywana w obiekcie. Inaczej nie byłoby wiadomo, czy dany obiekt pamięta ładowność statku, ilość wody w zbiorniku czy temperaturę rdzenia reaktora atomowego :-P Nie muszę chyba mówić co by się stało, gdyby taki program naprawdę sterował reaktorem atomowym i przez przypadek pomyliłbyś sobie obiekty ;-P Dlatego każdy obiekt ma też swój typ, który określa rodzaj danych przechowywanych w obiekcie, zakres ich wartości, oraz jakie operacje można na tym obiekcie wykonywać.

Niektóre języki nie rozróżniają typów i całą odpowiedzialność za ich przestrzeganie zrzucają na programistę. W takich językach łatwiej jest popełnić błąd. Na szczęście kompilator języka C++ rozróżnia typy i pamięta je za Ciebie, dzięki czemu może kontrolować, czy używasz obiektów we właściwy sposób i zgodnie z ich przeznaczeniem ;-)

Typy wbudowane

Język C++ posiada kilka podstawowych typów, których możesz używać dla swoich obiektów. Są one nazywane typami wbudowanymi, w odróżnieniu od typów stworzonych przez programistę [Tak, w języku C++ możesz tworzyć własne, całkiem nowe typy danych :-) Cała druga część kursu będzie poświęcona temu zagadnieniu]. Istnieją nawet specjalne słowa kluczowe, służące jako nazwy typów wbudowanych.

Typy wbudowane odpowiadają podstawowym sposobom przechowywania danych w pamięci komputera. Dlatego ich rozmiary w pamięci są zależne od budowy komputera, dla którego kompilujesz swój program, oraz od używanego kompilatora. Postaram się omówić je w kolejności od najmniejszego do największego. Zaczniemy od typów do przechowywania liczb całkowitych.

Typy znakowe: char i wchar_t

Nie, to nie jest żadna pomyłka ;-) W komputerach znaki tekstu [litery, cyfry itp.] także są przechowywane jako liczby. Każdemu znakowi odpowiada jakiś liczbowy kod. Typ char został stworzony właśnie do przechowywania kodów znaków [char to skrót od ang. character, czyli znak tekstu]. Obiekt typu char musi mieć taki rozmiar, aby mógł przechować kod dowolnego znaku z podstawowego zestawu znaków danego komputera.

Standard C++ mówi, że obiekt typu char ma rozmiar równy 1 bajtowi. Jest tak z prostej przyczyny: bajt to najmniejsza "cegiełka", jaką da się zaadresować - rozmiar pojedynczej komórki pamięci. Standard nie precyzuje, z ilu bitów ma się składać taki bajt, ale wymaga, by miał ich conajmniej 8 [choć na niektórych maszynach może mieć więcej ;-)], więc spokojnie możesz zakładać, że obiekty typu char mogą przyjąć jedną z conajmniej 256 różnych wartości ;-) Rozmiary obiektów wszystkich pozostałych typów są wielokrotnością rozmiaru obiektu typu char, czyli bajtu.

Typ wchar_t służy do przechowywania kodów znaków z rozszerzonego zestawu znaków [zazwyczaj jest nim Unicode]. Obiekty tego typu zajmują zwykle więcej pamięci, niż obiekty typu char. Ta dziwna nazwa jest spadkiem po języku C i oznacza z angielskiego wide-character type, czyli typ dla znaków rozszerzonych.

Typ int i jego odmiany

Obiekty typu int służą do przechowywania liczb całkowitych [int to skrót od ang. integer, czyli liczba całkowita]. Mają taki rozmiar, jaki jest najwygodniejszy do obliczeń na liczbach całkowitych na danej maszynie. Zazwyczaj odpowiada on rozmiarowi słowa maszynowego, czyli zależy od wielkości wewnętrznych rejestrów mikroprocesora, dla którego kompilujesz.

Typ int ma dodatkowo dwie odmiany, różniące się rozmiarem i zakresem wartości. Pozwala to programiście [czyli Tobie ;-)] lepiej dostosować zajętość pamięci do swoich potrzeb ;-)

Pierwsza z nich to short int, lub w skrócie short [w ang. short znaczy krótki]. Standard C++ mówi, że obiekty tego typu mogą zajmować mniej pamięci, niż zwykły typ int, jednak nie mniej niż 16 bitów. Możesz więc mieć pewność, że pomieści jedną z conajmniej 65536 różnych wartości. Tego typu możesz użyć, jeśli chcesz zyskać trochę miejsca kosztem mniejszego zakresu wartości.

Druga odmiana to typ long int, lub w skrócie long [w ang. long znaczy długi]. Obiekt tego typu może zajmować w pamięci więcej miejsca, niż zwykły typ int. Dodatkowo Standard gwarantuje, że zajmie on conajmniej 32 bity, więc tego typu możesz użyć, gdy chcesz przechować jedną z conajmniej 4294967296 różnych wartości. [Oczywiście nie musisz tego wkuwać na pamięć! ;-D Wystarczy jeśli wiesz, że to około 4 miliardów ;-) A jeśli będziesz potrzebować dokładnej informacji, zawsze możesz zajrzeć na tą stronę :->]

Ze znakiem czy bez?

Do typów char i int można dodać przedrostek signed lub unsigned, który określa, czy chcesz używać liczb ujemnych. Przedrostek signed sprawia, że jeden z bitów jest poświęcany na znak liczby [ujemna/dodatnia]. Połowa zakresu liczb dodatnich zmieni się więc na liczby ujemne. Jeśli nie potrzebujesz liczb ujemnych, a chcesz za to zyskać dwa razy większy zakres na plusie, użyj przedrostka unsigned.

Jeśli nie podasz żadnego z tych przedrostków dla typu int, kompilator domyślnie zrozumie to jako typ signed int. Natomiast jeśli nie podasz żadnego przedrostka dla typu char, kompilator sam wybierze sposób przechowywania kodów znaków, który jest dla niego najwygodniejszy. Najlepiej więc zrobisz jeśli zostawisz tą decyzję właśnie jemu ;-) Pamiętaj tylko, że typy char, signed char i unsigned char to trzy różne typy, więc do przechowywania kodów znaków powinno się używać czystego typu char.

Typy dla liczb rzeczywistych

Liczby rzeczywiste są przechowywane w komputerach w specjalny sposób. Również obliczenia na nich są wykonywane inaczej, niż na liczbach całkowitych. Dlatego wymagają osobnych typów.

Najmniejszym z nich jest typ float [skrót od ang. floating point czyli płynny/zmienny przecinek. Nazwa wzięła się stąd, że podczas obliczeń rzecinek dziesiętny zmienia swoje położenie]. Obiekty tego typu zajmują 32 bity w pamięci i mają zakres od 3.4•10-38 do 3.4•1038. Dokładność tego typu powinna Ci wystarczyć w większości programów.

Jeśli jednak jesteś jakimś naukowcem i piszesz program do obliczeń matematycznych, precyzja typu float może Ci nie wystarczyć. Dlatego jest jeszcze typ double [od ang. double precision = podwójna dokładność]. Zajmuje 64 bity i służy do przechowywania liczb zmiennoprzecinkowych podwójnej precyzji, czyli od 1.7•10-308 do 1.7•10308. A dla megamózgów jest jeszcze typ long double. Zajmuje aż 80 bitów i ma zakres 3.4•10-4932 do 1.1•104932. Wątpię jednak, żeby kiedykolwiek były Ci potrzebne aż tak precyzyjne liczby, chyba że jesteś jakimś astrofizykiem :-P

Typ logiczny

W języku C++ istnieje też typ do przechowywania wartości logicznej. Nazywa się bool [jest to skrót od ang. boolean i nazwa ta pochodzi od George'a Boole'a - wynalazcy logiki matematycznej ;-)]. Obiekty typu bool mogą przyjmować tylko jedną z dwóch wartości: prawdę lub fałsz, oznaczanych odpowiednio słowami: true i false.

No, po tym krótkim wstępie wiesz już co to są obiekty i znasz nazwy podstawowych typów danych. Możemy więc przejść do lekcji drugiej, w której napiszemy wspólnie Twój pierwszy w życiu program w języku C++ :-)

Pierwszy program

Przed Tobą druga lekcja kursu C++, z której dowiesz się wreszcie, jak wygląda pisanie programów w języku C++ :-) Odpal teraz swoje ulubione środowisko i utwórz nowy projekt programu tekstowego. Jeśli w edytorze znajduje się już jakiś kod, skasuj go. Zaczniemy z pustym plikiem, który stopniowo będzie zapełniać się kodem. Będziemy tworzyć nasz program od podstaw, niczym doktor Frankenstein swojego potwora ;-D Początkowo program nie będzie jeszcze robił nic efektownego, jednak dzięki tym przykładom, które dokładnie omówię, będzie Ci łatwiej obczaić o co w tym całym progamowaniu chodzi :-)

Na początek wpisz [albo wklej] poniższy kod:

int main()

{

//To jest komentarz

}

Komentarze

Na pewno od razu rzuciło Ci się w oczy, że pewien fragment wygląda tu zrozumiale. W języku C++ możesz umieszczać w kodzie programu fragmenty tekstu w "ludzkim" języku. Takie fragmenty to komentarze. Kompilator do nich nie zagląda, więc możesz w nich pisać co tylko chcesz ;-) Musisz tylko oznaczyć kompilatorowi gdzie komentarz się zaczyna, a gdzie kończy.

Komentarz liniowy, taki jak ten powyżej, zaczyna się znakami // i ciągnie się do końca linii. Istnieją także komentarze blokowe, które mogą obejmować dowolny fragment tekstu [nawet ciągnący się przez wiele linii]. Zaczynają się od /* i ciągną się aż do */. Przykład komentarza blokowego:

/* To jest komentarz, który

  ciągnie się przez wiele linii */

Komentarzy takich nie możesz zagnieżdżać, czyli umieszczać jeden w drugim. Dlaczego? Bo gdy kompilator napotka zakończenie tego wewnętrznego komentarza, to uzna, że komentarz właśnie się skończył. Znów zacznie pilnować czy nie robisz błędów i będzie bardzo zdziwiony, że nie piszesz w jego języku ;-P

Możesz się zastanawiać, po co Ci komentarze w twoim programie? Przecież jak piszesz program, to chyba wiesz o co w nim chodzi? :-P No tak, w tej chwili wiesz. Jednak wyobraź sobie, że za jakiś czas wracasz do swojego kodu chcąc coś poprawić. Patrzysz na te hieroglify i myślisz sobie: Co za kretyn to pisał?! :-D

Dobra, może nie każdy koduje po flaszce ;-D ale wystarczy już tydzień czy dwa żeby zapomnieć jak dokładnie działał Twój program. Wtedy masz jeszcze komentarz i nie musisz rozgryzać działania własnego kodu ;-) Możesz też zostawiać sobie notatki w kodzie, np. że coś musisz jeszcze poprawić lub dodać. Staraj się tylko nie przesadzać z dokładnością komentarzy. Nie pisz tego, co można wyczytać z samego kodu. Dobry kod jest zrozumiały sam w sobie ;-)

Komentarze przydają się też do innej rzeczy. Wiesz już, że kompilator nie zagląda do komentarzy. Co się stanie jak zamkniesz w znaki komentarzy jakiś fragment Twojego kodu? Zgadza się! Kod przestanie być kodem, a stanie się komentarzem. Ukryjesz go w ten sposób przed kompilatorem ;-) Tej sztuczki możesz używać, by wyłączać sobie wybrane fragmenty programu gdy testujesz jego działanie.

Ok, ale ludzki język już znasz, tego nie muszę Cię uczyć ;-) Wróćmy więc do poznawania języka C++. Zobaczmy co nam jeszcze zostało do omówienia w poprzenim przykładzie.

Najprostszy program

Oprócz komentarza, w naszym pierwszym programie jest jeszcze coś takiego:

int main()

{

 

}

Ten fragment to absolutne minimum. Każdy program w C++ musi zawierać conajmniej to.

Długo myślałem jak wytłumaczyć Ci ten pierwszy fragment kodu, gdyż łączy on w sobie wiele składników języka C++, które chciałoby się dokładniej omówić już teraz. W końcu postanowiłem, że zamiast na wjazd zawalać Cię informacjami, omówię wszystko po kolei, stopniowo odkrywając przed Tobą coraz więcej. Niektóre rzeczy omówię tylko w skrócie, dokładniejsze wyjaśnienia zostawiając na później.

Wszystko ma swój początek. Zacznijmy więc od niego! :-)

Bloki instrukcji

Każdy program to po prostu ciąg instrukcji. Instrukcje są jak zdania, a każde opisuje jedną prostą czynność, którą program ma wykonać. W starożytnych językach programowania pisało się program w postaci jednego długiego ciągu instrukcji, ciągnącego się jak spaghetti ;-P Szybko się okazało, że w takim kodzie łatwo się pogubić. Programiści zaczęli więc dzielić program na części.

W języku C++ taki wydzielony ciąg instrukcji, który stanowi jednolitą całość, nazywany jest blokiem. Blok zamyka się w nawiasy klamrowe, by wyraźnie określić jego początek i koniec. Wygląda to tak:

{

//Tu jakieś instrukcje...

}

W programie może być oczywiście więcej bloków. Niektóre fragmenty kodu są na tyle przydatne, że programista chciałby ich używać wielokrotnie. Żeby jakoś rozróżniać bloki i ułatwić odwoływanie się do nich, programiści zaczęli nadawać im nazwy. Taki blok instrukcji, który ma swoją nazwę, nazywamy procedurą lub funkcją.

W niektórych językach programowania funkcja i procedura to dwie różne rzeczy: procedura to nazwany blok kodu, który można wielokrotnie wywoływać, natomiast funkcja dodatkowo może zwracać pewną wartość, tak jak funkcja matematyczna. W języku C++ nie ma takiego rozróżnienia. Jeśli jakiś blok kodu ma nazwę, to jest funkcją i już, nawet jeśli nic nie zwraca.

Gdy zamienisz jakiś blok kodu w funkcję, nadając mu nazwę, blok przestaje już być "anonimowy" i możesz odwoływać się do niego wielokrotnie, czyli wywoływać funkcję, posługując się jej nazwą ["Azor! Do nogi!" ;-D].

Funkcja główna

Jeśli jest kilka nazwanych bloków kodu [czyli funkcji], to od którego z nich program ma się zacząć wykonywać? Żeby rozwiązać ten problem, twórcy języka C++ umówili się, że każdy program będzie się zaczynał w funkcji o nazwie main [ang. main = główna. Czytaj mejn]. Jest to więc pierwsza funkcja, która wykona się w Twoim programie, i zarazem ostatnia. Można by rzec, że funkcja main jest Twoim programem ;-)

A oto jak wygląda owa funkcja main w całości:

int main()

{

//Tu będą instrukcje

}

Jak widzisz, jest tutaj blok, a przed nim widać nazwę funkcji, czyli main. Po nazwie stoi dodatkowo para nawiasów okrągłych. W przyszłości w tych nawiasach znajdą się parametry dla Twojego programu. Narazie Twój program nie pobiera żadnych parametrów, bo żadnych nie potrzebuje, więc nawiasy są puste. Mimo to te nawiasy muszą tam być, bo właśnie po nich kompilator rozpoznaje, że chodzi Ci o nazwę funkcji.

W innych językach trzeba to było dodatkowo sygnalizować różnymi słowami kluczowymi, takimi jak function czy procedure. W C++ wystarczy para nawiasów po nazwie.

Tajemnicze int

Pewnie zastanawiasz się jeszcze, co robi to słówko int przed nazwą funkcji? ;-J

Otóż, gdy funkcja main się kończy, kończy się też program i oddaje sterowanie temu, kto go uruchomił [tym kimś może być system operacyjny lub inny program]. W tym momencie Twój program może dodatkowo zwócić informację o wyniku swojego działania [coś jak "testament" ;-D]. Może to być np. wynik obliczeń, informacja czy program się powiódł czy nie... możliwości jest wiele. Zbyt wiele! Dlatego ustalono, że wynikiem programu ma być zawsze jakaś pojedyncza liczba. Jeśli tą liczbą jest 0, oznacza to umownie, że program przebiegł prawidłowo. Każdy inny wynik oznacza, że program zakończył się z powodu błędu. Wtedy różne wartości oznaczają różne kody błędów.

Słowo kluczowe int oznacza właśnie, że wynikiem funkcji main [a więc zarazem Twojego programu] ma być liczba całkowita. A teraz zastanów się: jaką liczbę zwraca ten Twój pierwszy program? :->

Pytanie trochę podchwytliwe, bo nie ma tu żadnej liczby :-D Jednak nie ma też narazie żadnych instrukcji, jedynie pusty blok funkcji main, więc program po prostu zakończy się od razu po uruchomieniu. Skoro nic nie może pójść źle, to wynikiem programu powinno być 0 i postara się o to sam kompilator.

Sprawdź teraz, czy tak jest naprawdę. Skompiluj ten pierwszy program i uruchom go. Jeśli Twoje środowisko programistyczne pozwala Ci zobaczyć wynik działania programu, to świetnie :-) [takim środowiskiem jest na przykład Code::Blocks]. Jeśli nie - no cóż, musisz uwierzyć mi na słowo ;-P

No dobrze, a co zrobić, by program zwrócił jakąś inną wartość?

Zwracamy wartość, czyli pierwsza instrukcja

Odpowiedź brzmi: musisz napisać w programie, by to zrobił. On sam się tego nie domyśli :-D Komputer jest jak Dżin z lampy - potrafi jedynie spełniać życzenia programisty ;-) Jednak nie kiwnie palcem, dopóki mu nie każesz. Usiądź teraz wygodnie, bo właśnie napiszesz swoją pierwszą instrukcję :-) Wywal z poprzedniego kodu ten komentarz i w jego miejsce wstaw coś takiego:

return 7;

Cały program powinien teraz wyglądać tak:

int main()

{

  return 7;

}

W języku C++ każda instrukcja kończy się średnikiem. Jest tak dlatego, że C++ nie zmusza Cię do umieszczania jednej instrukcji w jednej linijce. Możesz rozpisać jedną instrukcję nawet w kilku linijkach, jeśli tak jest bardziej przejrzyście. Jest tak dzięki temu, że to średnik [a nie koniec linijki] mówi kompilatorowi, w którym dokładnie miejscu instrukcja się kończy. Możesz nawet zapis...

Zgłoś jeśli naruszono regulamin