Sztuka dobrego programowania - ebook
Sztuka dobrego programowania - ebook
Książka przeznaczona jest dla programistów, którzy chcą, aby ich programy działały dobrze, czyli szybko zwracały wyniki, zużywały mało pamięci i obejmowały szeroki zakres danych wejściowych. Programista początkujący znajdzie tutaj wyjaśnienia podstawowych elementów języka C, a czytelnik zaawansowany dowie się, jak może udoskonalić swój warsztat.
Czytelnik tej książki nauczy się pisać funkcje działające oszczędnie i wydajnie, np. funkcję, która znajduje liczby pierwsze 56 razy większe niż przykłady podawane w standardowych kursach programowania, a przy tym czyni to 7 razy szybciej.
Dowie się, jak poprawnie tworzyć programy sterowane argumentami wywołania. Nauczy się, jak zautomatyzować proces budowania programów złożonych. Będzie potrafił przetwarzać wyrażenia regularne, czy też stworzyć interpreter poleceń podanych w języku naturalnym.
Stanie się dobrym programistą.
Kategoria: | Programowanie |
Zabezpieczenie: |
Watermark
|
ISBN: | 978-83-01-19047-7 |
Rozmiar pliku: | 2,4 MB |
FRAGMENT KSIĄŻKI
Pierwsze prawo „programisty” brzmi: „U mnie działa”. Niezły programista nieco je przeformułuje: „Mój program działa wszędzie”. Dobry programista doda: „Mój program działa wszędzie i dobrze”.
Dobremu programiście nie wystarczy fakt, że program „chodzi”. Dobrze napisany program jest jak dzieło sztuki: piękny i elegancki. Podświadomość programisty zapala czerwone światełko, gdy widzi rozwiązanie nieeleganckie. Zazwyczaj później okazuje się, że w programie jest jakaś „rysa na szkle” – mały defekt, który ujawni się kiedyś zupełnie niespodziewanie.
Dobry program można łatwo odróżnić od „działającego”:
1. 1) szybciej zwraca wyniki;
2. 2) zużywa mniej pamięci;
3. 3) działa dla szerszego zakresu danych.
W tej książce chcemy nauczyć tworzenia dobrych programów. Na kilkunastu przykładach pokażemy krok po kroku, jak optymalizować programy – czynić je bardziej efektywnymi.
Język C, wynaleziony w roku 1972, do dziś nie znalazł sobie równych – wraz z językami pochodnymi, takimi jak C++, C# lub Objective-C, tworzy najbardziej popularną rodzinę języków programowania na świecie. Przykłady zawarte w tej książce są przedstawione w „czystym” języku C, ponieważ wszystko, co można w nim zapisać, bez trudu można wyrazić w językach pochodnych, co nie musi zachodzić w przeciwnym kierunku.
Programować można w językach różnego poziomu. Najniższy poziom to język „asemblerowy”, w którym kodujemy bezpośrednio rozkazy maszynowe (a nie instrukcje będące złożeniami rozkazów). C jest językiem średniego poziomu. Zawiera niektóre konstrukcje wysokiego poziomu (unie, tablice, struktury), ale jest jeszcze na tyle „blisko maszyny”, że można w nim np. zdefiniować fragmenty będące wstawkami w assemblerze. Ponadto, język C umożliwia działania na strukturach dynamicznych, których nie można definiować w tych językach wyższego poziomu, które nie zawierają zmiennych wskaźnikowych.
Z niniejszej książki dowiesz się, jak napisać funkcję, za pomocą której można wyznaczyć liczby pierwsze 56 razy większe niż przykłady podawane w standardowych kursach programowania, i to 7 razy szybciej. Nauczysz się, jak tworzyć programy, którego działanie zależy od argumentów wywołania. Dowiesz się, jak efektywnie napisać interpreter poleceń podanych w języku naturalnym oraz zrozumiesz, jak działa analizator wyrażeń regularnych.
Treść książki ułożono w ciąg lekcji, podzielonych na cztery części. Część I (lekcje 1–3) to nauka pisania funkcji, które oszczędnie i efektywnie gospodarują pamięcią operacyjną. Część II (lekcje 4–6) jest poświęcona strukturze programu głównego. W części III (lekcje 7–9) omówiono proces tworzenia programów złożonych, składających się z kilku modułów, np. napisanych przez różnych autorów. Ostatnia część (lekcje 10–12) zawiera przykłady zastosowania pozyskanych umiejętności. Pokazujemy w niej, jak w sposób przejrzysty i krótki można napisać programy wykonujące niebanalne zadania.
Każda lekcja ma na celu wyrobienie określonej umiejętności programistycznej. Cel ten realizowany jest poprzez rozwiązywanie, krok po kroku, zadania podanego na początku lekcji. Lekcję kończy podsumowanie – lista porad przydatnych każdemu programiście.
Jeśli dopiero zaczynasz przygodę z programowaniem, to ten podręcznik jest dla Ciebie – znajdziesz w nim wyjaśnienia poszczególnych elementów języka C, a już od początku swojej programistycznej edukacji nauczysz się dążyć do perfekcji.
Jeśli programujesz od wielu lat, to zajrzyj do tej książki – zapewne utwierdzisz się w przekonaniu, że potrafisz programować całkiem nieźle, ale być może przekonamy cię, że możesz jeszcze coś udoskonalić w swoim warsztacie.
Przygotowanie środowiska pracy
Aby móc wypróbować, jak działają funkcje i programy opisane w tej książce, musisz, drogi Czytelniku, przygotować odpowiednie środowisko pracy. W tym celu trzeba zainstalować jedną z wersji systemu Linux.
Istnieją dziesiątki tzw. dystrybucji (odmian) systemu Linux, a jej wybór jest sprawą w dużej mierze osobistą. Największą popularnością cieszy się obecnie dystrybucja Ubuntu oraz oparta na niej wersja Linux Mint. Dla osób rozpoczynających swoją przygodę z Linuksem rekomendujemy stosowanie dystrybucji OpenSuse. Jest ona rozwijana przez SUSE – najstarszą, wciąż działającą, organizację linuksową. Jest to według nas wersja najłatwiejsza do przyjęcia dla użytkowników systemu Windows.
Instalacja systemu Linux
Podamy tutaj kilka wskazówek, jak zainstalować dystrybucję OpenSUSE.
Pobranie OpenSUSE
Pakiet można pobrać pod adresem: //software.opensuse.org/421/en. Przed pobraniem warto przeczytać instrukcje podane na tej stronie internetowej.
Przygotowanie instalacji
Najlepszym rozwiązaniem jest nagranie („wypalenie”) płyty DVD z pobranym pakietem instalacyjnym. Alternatywnie, pakiet ten można umieścić na dysku USB (wtedy do poprawnej instalacji potrzebny jest program pomocniczy, np. ImageWriter). Użytkownikom systemu Windows polecamy dokonanie defragmentacji dysku bezpośrednio przed instalacją (w nowszych wersjach Windows defragmentacja odbywa się samoczynnie co pewien czas). Chodzi o to, aby wszystkie pliki windowsowe zgromadzić na początku dysku, zostawiając jego resztę wolną do użytku przez Linux.
Instalacja
Należy uruchomić komputer z nośnika, na którym nagrany jest program instalacyjny i wybrać opcję Install. Procedura instalacyjna zadaje szereg pytań (np. o strefę czasową i język, w jakim ma być zainstalowany system). Na ogół nietrudno na nie odpowiedzieć.
Następnie procedura instalacyjna przystępuje do partycjonowania dysku. Polega to na tym, że w wolnej przestrzeni na dysku system wydziela nowe części (partycje) dla systemu Linux. Cała procedura instalacji w niczym nie zagraża danym przechowywanym w partycji Windows.
Ostatnią czynnością wykonywaną przez procedurę instalacyjną jest instalacja nowego programu rozruchowego. Działa on w trybie dualnym, co oznacza, że po uruchomieniu komputera możemy wybrać system Windows lub Linux.
W ramach instalacji utworzone zostają konta dwóch użytkowników: konto administratora o nazwie root oraz konto (zwykłego) użytkownika. Szczególnie istotne jest zapamiętanie hasła administratora.
Uruchamianie programów
W pierwszej części książki omawiamy funkcję, a dopiero w drugiej uczymy, jak napisać działający program. Niecierpliwy czytelnik może jednak chcieć sprawdzić, jak działają funkcje już od pierwszej lekcji. Podajemy teraz krótką instrukcję, jak to zrobić.
Edycja kodu źródłowego
Kod źródłowy programu można utworzyć jest w dowolnym edytorze tekstowym. Polecamy korzystanie z edytorów: Vim, Gvim lub Emacs. Aby sprawdzić działanie funkcji, trzeba napisać choćby najprostszy program z wykorzystaniem tej funkcji. W przypadku funkcji opisanej w lekcji 1 kod źródłowy całego programu może mieć następującą postać:
uint
wykladnik(uint n, uint k)
{
uint w = 0;
while (n/=k) w += n;
return (w);
}
void
main()
{
printf("Liczba 5 występuje w rozkładzie liczby 2000!
z wykładnikiem %u\n", wykladnik(2000,5));
}
Tak utworzony kod źródłowy zapisz pod wybraną przed siebie nazwą (np. wykladnik.c) w wybranym przed siebie katalogu.
Przejście do trybu tekstowego
Jeśli system OpenSUSE uruchomił się w trybie graficznym, to należy otworzyć okno, w którym polecenia wydaje się w trybie tekstowym (tzw. emulator konsoli). W tym celu wystarczy uruchomić program o nazwie Konsole. Inną metodą jest zastosowanie skrótu klawiaturowego Ctrl+Alt+Fn, gdzie n jest liczbą od 1 do 6, ale powoduje to opuszczenie trybu graficznego, więc ta metoda powinna być stosowana tylko jako środek ratunkowy, gdy w trybie graficznym coś się zepsuje.
Skompilowanie programu
Przejdź do katalogu (służy do tego polecenie cd), w którym został zapisany kod źródłowy programu i skompiluj go za pomocą programu gcc. W tym celu wydaj polecenie:
$ gcc -o wykladnik wykladnik.c
wykladnik to wybrana przez ciebie docelowa nazwa programu. Jeśli w kodzie programu są błędy, zostaniesz o nich poinformowany.
Uruchomienie programu
Jeśli kompilacja przebiegnie bez zakłóceń, to w tym samym katalogu powstanie nowy plik o nazwie wykladnik, który możesz uruchomić poprzez podanie polecenia:
$ ./wykladnik
Polecane źródła w Internecie
The Top 11 Best Linux Distros for 2015
https://www.linux.com/news/top-11-best-linux-distros-2015
The Best Linux Distros of 2016
https://www.linux.com/news/best-linux-distros-2016
openSUSE
https://pl.opensuse.org/
Compiling C and C++ Programs
http://pages.cs.wisc.edu/~beechung/ref/gcc-intro.htmlLekcja 1
Optymalizowanie funkcji
Zadanie: napisać funkcję, która, dla danego czynnika pierwszego k i liczby naturalnej n, obliczy potęgę, w jakiej czynnik k występuje w rozkładzie liczby n! na czynniki pierwsze.
Elementy matematyki
Rozkład liczby na czynniki pierwsze oznacza zapisanie jej jako iloczynu liczb pierwszych.
Przykładowo, rozkład liczby 60 na czynniki pierwsze zapisujemy w następujący sposób:
60 = 2 · 2 · 3 · 5
Kolejność czynników w rozkładzie można zmienić, np.:
60 = 2 · 3 · 2 · 5
Powyższe dwa rozkłady liczby 60 będziemy uważać za równoznaczne. Przy założeniu, że kolejność czynników rozkładu jest nieistotna, prawdziwe jest twierdzenie:
Każdą liczbę naturalną można rozłożyć na czynniki pierwsze tylko w jeden sposób.
W dalszym ciągu stosować będziemy tylko taki zapis, w którym czynniki pierwsze podane są w kolejności od najmniejszego do największego. Możemy wtedy rozkład liczby zapisać za pomocą potęg czynników pierwszych, np.
60 = 2² · 3¹ · 5¹
Powiemy wtedy, że w rozkładzie liczby 60 czynnik pierwszy 2 występuję w potędze drugiej (ma wykładnik 2), a czynniki pierwsze 3 oraz 5 występują w potędze pierwszej (mają wykładnik 1).
Silnia liczby naturalnej n, oznaczana jako n!, to iloczyn wszystkich liczb naturalnych nie większych niż n.
Przykładowo:
6! = 1 · 2 · 3 · 4 · 5 · 6 = 720
Silnię liczby naturalnej n można zdefiniować również rekurencyjnie, czyli za pomocą definicji, która odwołuje się do samej siebie:
n! = {
1 dla n = 1
n · (n – 1)! dla n > 1
Aby obliczyć wartość 6! korzystając z definicji rekurencyjnej, dokonujemy następujących wyliczeń cząstkowych:
6! =
= 6 · 5! =
= 6 · 5 · 4! =
= 6 · 5 · 4 · 3! =
= 6 · 5 · 4 · 3 · 2! =
= 6 · 5 · 4 · 3 · 2 · 1! =
= 6 · 5 · 4 · 3 · 2 · 1 = 720
Podstawy języka C
W tej części przybliżymy podstawowe elementy języka programowania C.
Program, instrukcja
Program to ciąg instrukcji wykonywanych zgodnie z kolejnością ich zapisania. W języku C każdą instrukcję kończy znak średnika. Instrukcja w języku C ma zatem postać:
nazwa_instrukcji (lista parametrów);
Przykładem instrukcji w języku C jest instrukcja printf, która wypisuje komunikat na urządzenie domyślne (np. monitor komputera). Komunikat kończony jest zwykle komendą przejścia do nowego wiersza \n, np.
printf("Witaj\n"); // wypisanie na ekran napisu 'Witaj'
Składnia języka C dopuszcza zastąpienie jednej instrukcji blokiem instrukcji. Instrukcje łączymy w bloki za pomocą nawiasów klamrowych { }, np.:
{
printf("Witaj\n");
printf("Jak się nazywasz?");
}
Komentarze
Komentarze to teksty pomocnicze, które nie są wykonywane przez program. Zaczynają się znakami /* i kończą znakami */.
Komentarz mieszczący się w jednym wierszu można również zapisać za znakami //.
/* To moj pierwszy program */
printf("Witaj"); // Wypisanie komunikatu powitalnego
Identyfikatory
Identyfikator to nazwa stworzona przez programistę. Identyfikator musi zaczynać się od małej lub dużej litery alfabetu łacińskiego albo znaku podkreślenia; może zawierać ponadto litery, znaki podkreślenia lub cyfry.
Przykładowe identyfikatory: wykladnik, _silnia, n, k1.
Słowa kluczowe
Słowa kluczowe to wyrazy zarezerwowane, których nie można stosować jako identyfikatorów, np. char, switch, return.
Białe znaki
Białe znaki oznaczają spacje, tabulatory, znaki przejścia do następnego wiersza, a także komentarze. Służą one do oddzielania poszczególnych elementów języka, np.
m = n/*ujemna*/ - k/*ujemnik*/;
W powyższym przykładzie spacje oraz komentarze oddzielają identyfikatory oraz operatory (przypisania i odejmowania).