Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00128 011224 16963615 na godz. na dobę w sumie
C. Rusz głową! - książka
C. Rusz głową! - książka
Autor: , Liczba stron: 578
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-5232-7 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c - programowanie
Porównaj ceny (książka, ebook, audiobook).

W obecnych czasach triumfy święcą platforma .NET, Java oraz HTML5 i JavaScript. Mogłoby się wydawać, że język C i inne podobne języki odeszły w niepamięć. Nic bardziej mylnego! W dalszym ciągu są one niezastąpione w wielu dziedzinach. Znajdują zastosowanie wszędzie tam, gdzie wymagana jest pełna kontrola nad sprzętem oraz gwarancja czasu wykonania powierzonych zadań. Dlatego specjaliści znający ten język wciąż są poszukiwani na rynku pracy.

Dzięki tej książce możesz dołączyć do ich grona! Kolejne wydanie z serii 'Rusz głową' to gwarancja sukcesu. Zastosowanie nowatorskich technik nauki pozwala na błyskawiczne przyswojenie wiedzy. W trakcie lektury poznasz składnię języka C, dostępne typy zmiennych, sposoby zarządzania pamięcią oraz zasady tworzenia przejrzystego kodu. Ponadto nauczysz się biegle obsługiwać kompilator, korzystać z plików nagłówkowych oraz przesyłać komunikaty między procesami. Dzięki licznym ćwiczeniom bez problemu utrwalisz zdobytą wiedzę. Książka ta jest wprost genialną pozycją dla wszystkich osób chcących wkroczyć w świat języka C. Przyda się również studentom na zajęciach z programowania. Warto ją mieć!

Zainwestuj czas w naukę C i poznaj:

Poznaj język C - ta wiedza zaprocentuje!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Head First C Tłumaczenie: Piotr Rajca ISBN: 978-83-246-5232-7 © 2013 Helion S.A. Authorized Polish translation of the English edition of Head First C, 1st edition, ISBN 9781449399917 © David Griffiths and Dawn Griffiths. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Wydawnictwo HELION dołożyło wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/cruszg.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/cruszg Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treści (skrócony) Spis treści Wprowadzenie Zaczynamy poznawać C. Dajmy nurka Pamięć i wskaźniki. Na co wskazujesz? Tworzenie małych programów narzędziowych. Rób jedną rzecz, ale rób ją dobrze Stosowanie wielu plików źródłowych. Podziel go, rozbuduj go 1. laboratorium C. Arduino Struktury, unie i pola bitowe. Wytocz swoje własne struktury Struktury danych i pamięć dynamiczna. Budowanie mostów Zaawansowane funkcje. Odpicuj swoje funkcje na maksa! Biblioteki statyczne i dynamiczne. Wymienialny kod 2. laboratorium C. OpenCV Procesy i wywołania systemowe. Przekraczanie granic 1 2 2,5 Łańcuchy znaków. Teoria łańcuchów 3 4 5 6 7 8 9 10 Komunikacja pomiędzy procesami. Dobrze jest porozmawiać 11 Gniazda i komunikacja sieciowa. Nie ma drugiego takiego miejsca jak 127.0.0.1 12 Wątki. To równoległy świat A Pozostałości. Dziesięć najważniejszych rzeczy (których nie opisaliśmy) B 3. laboratorium C. Blasteroidy Zagadnienia programowania w C. Powtórka z całego materiału xxvii 1 41 83 101 155 205 215 265 309 349 387 395 427 465 499 521 537 551 Spis treści (z prawdziwego zdarzenia) W Wprowadzenie Twój mózg jest skoncentrowany na C. Kiedy Ty starasz się czegoś nauczyć, Twój mózg robi Ci przysługę i stara się, by ta wiedza nie została utrwalona. Twój mózg myśli sobie: „Lepiej zostawić miejsce na naprawdę ważne rzeczy, takie jak dzikie zwierzęta, których należy unikać, albo rozważania, czy jeżdżenie na snowboardzie w stroju Adama to dobry pomysł”. Jak zatem możesz oszukać swój mózg i przekonać go, że Twoje życie zależy od znajomości C? Dla kogo jest przeznaczona ta książka? Wiemy, co sobie myślisz Metapoznanie Zmuś swój mózg do posłuszeństwa Przeczytaj to Zespół recenzentów technicznych Podziękowania xxviii xxix xxxi xxxiii xxxiv xxxvi xxxvii ix Spis treści 1 1 Zaczynamy poznawać C Dajmy nurka Czy chcesz zajrzeć do głowy komputera? Musisz napisać kod działający naprawdę szybko, na przykład na potrzeby nowej gry? A może program na Arduino? Albo we własnej aplikacji na iPhone’a użyć biblioteki napisanej przez kogoś innego? Jeśli tak, to skorzystaj z pomocy bohaterskiego C. C działa na znacznie niższym poziomie niż większość innych języków programowania, a zatem zrozumienie go daje nam znacznie większe pojęcie o tym, co się naprawdę dzieje w programie. C pozwala także lepiej zrozumieć inne języki programowania. A zatem bierz się do pracy, przygotuj kompilator, a już niedługo zaczniesz poznawać C. C to język do pisania małych, szybkich programów Ale jak wygląda skompilowany program napisany w C? A jak można uruchomić program? Dwa rodzaje poleceń Oto kod, jakim aktualnie dysponujemy Liczenie kart? W języku C? Wartości logiczne to nie tylko sprawdzanie równości Jak aktualnie wygląda nasz kod? Pociąg do Switcherado Czasami jeden raz nie wystarcza… Pętle często mają taką samą strukturę… Instrukcji break używamy, by wydostać się z pętli… Twój niezbędnik C 2 5 9 14 15 17 18 25 26 29 30 31 40 x x Spis treści 2 Pamięć i wskaźniki Na co wskazujesz? Jeśli naprawdę chcesz zrobić coś odlotowego w języku C, musisz się dowiedzieć, w jaki sposób zarządza on pamięcią. Język C daje nam bardzo dużą kontrolę nad tym, jak programy korzystają z pamięci komputera. W tym rozdziale zajrzysz za kulisy i zobaczysz, co dokładnie dzieje się podczas zapisywania i odczytywania zmiennych. Dowiesz się, jak działają tablice, jak unikać paskudnych błędów w trakcie wykonywania operacji na pamięci, a przede wszystkim przekonasz się, że opanowanie operacji na wskaźnikach i adresowania pozwoli Ci stać się rewelacyjnym programistą C. Kod C zawiera wskaźniki Grzebiemy w pamięci Stawiamy żagle ze wskaźnikami Spróbujmy przekazać wskaźnik do zmiennej Stosowanie wskaźników Jak przekazać łańcuch znaków do funkcji? Zmienne tablicowe są jak wskaźniki… Co myśli komputer, wykonując nasz kod? Jednak zmienne tablicowe nie są tak do końca wskaźnikami Dlaczego tablice naprawdę zaczynają się od 0? Dlaczego wskaźniki mają typ? Stosowanie wskaźników do wprowadzania danych Używając funkcji scanf(), uważaj! Alternatywą dla scanf() jest fgets() Literały łańcuchowe nie mogą być nigdy modyfikowane Jeśli chcesz zmienić łańcuch — skopiuj go Ściąga z pamięci Twój niezbędnik C 42 43 44 47 48 53 54 55 59 61 62 65 66 67 72 74 80 81 Złapaliśmy wiatr w żagle, kapitanie! Kurs na Cancún! Arr! Wiosenne wakacje! latitude 32 31 4 100 000 xi Spis treści 2,5 Łańcuchy znaków Teoria łańcuchów Korzystanie z łańcuchów nie ogranicza się do ich odczytywania. Przekonałeś się już, że w języku C łańcuchy znaków są w rzeczywistości tablicami danych typu char. Pozostaje jednak pytanie, co język C pozwala nam z nimi robić. W tym właśnie momencie na scenę wkracza string.h. To część standardowej biblioteki języka C, przeznaczona do wykonywania operacji na łańcuchach znaków. Jeśli chcemy połączyć ze sobą dwa łańcuchy, skopiować jeden łańcuch do drugiego bądź też porównać dwa łańcuchy znaków, to wszystkie te operacje można wykonać przy użyciu funkcji zadeklarowanych w pliku nagłówkowym string.h. W tym rozdziale dowiesz się, jak można stworzyć tablicę łańcuchów, a następnie przyjrzysz się nieco bliżej przeszukiwaniu zawartości łańcuchów przy użyciu funkcji strstr(). Desperacko poszukuję Franka Utwórz tablicę tablic Odnajdywanie łańcucha zawierającego określony tekst Stosowanie funkcji strstr() Czas na przegląd kodu Tablica tablic czy tablica wskaźników? Twój niezbędnik C 84 85 86 89 94 98 99 Porównaj ze sobą dwa łańcuchy znaków Utwórz kopię łańcucha string.h Szukaj łańcucha znaków Podziel łańcuch na małe fragmenty xii Spis treści 3 Tworzenie małych programów narzędziowych Rób jedną rzecz, ale rób ją dobrze Każdy system operacyjny udostępnia niewielkie programy narzędziowe. Niewielkie programy narzędziowe pisane w języku C wykonują wyspecjalizowane zadania, takie jak odczytywanie i zapisywanie plików czy też filtrowanie danych. Jeśli chcemy wykonać bardziej złożone zadanie, można nawet połączyć ze sobą kilka takich programów. W jaki jednak sposób tworzy się takie małe programy narzędziowe? W tym rozdziale przyjrzymy się elementom używanym podczas ich tworzenia. Dowiesz się, jak korzystać z opcji wiersza poleceń, jak zarządzać strumieniami informacji, czym są przekierowania, i błyskawicznie zdobędziesz nowe narzędzia. Małe programy narzędziowe mogą rozwiązywać wielkie problemy Oto sposób wykorzystania programu Ale my nie używamy plików… Możesz skorzystać z przekierowania Przedstawiamy standardowy strumień błędów Domyślnie strumień błędów jest wyświetlany na ekranie fprintf() zapisuje dane w strumieniu Zaktualizujmy kod, by korzystał z funkcji fprintf() Niewielkie programy narzędziowe są elastyczne Nie zmieniaj programu geo2json Różne zadania wymagają różnych narzędzi Połącz wejście i wyjście przy użyciu potoku Program narzędziowy bermuda A jeśli chcemy przekazywać wyniki do więcej niż jednego pliku? Stwórz swoje własne strumienie danych Nieco więcej o funkcji main() Niech biblioteka wykona pracę za nas Twój niezbędnik C 102 106 107 108 118 119 120 121 126 127 128 129 130 135 136 139 147 154 Standardowy strumień błędów jest podłączony do ekranu. Standardowy strumień wyjściowy jest podłączony do ekranu. xiii Standardowy strumień wejściowy jest podłączony do klawiatury. Spis treści 4 Stosowanie wielu plików źródłowych Podziel go, rozbuduj go Jeśli piszesz duże programy, nie chcesz mieć równie dużych plików źródłowych. Czy jesteś sobie w stanie wyobrazić, jak trudna i czasochłonna byłaby pielęgnacja dużego programu korporacyjnego napisanego w formie jednego pliku źródłowego? W tym rozdziale dowiesz się, jak C pozwala na dzielenie kodu źródłowego na małe, poręczne fragmenty oraz jak potem utworzyć z nich jeden duży program. W międzyczasie dowiesz się także nieco o niuansach związanych z typami danych i poznasz swojego nowego najlepszego przyjaciela — program make. Krótki przewodnik po typach danych Nie umieszczaj czegoś dużego w czymś małym Użyj rzutowania, by zapisać wartość zmiennoprzecinkową w zmiennej całkowitej O nie… to bezrobotni aktorzy… Zobaczmy, co się stało z kodem Kompilatory nie lubią niespodzianek Oddziel deklaracje od definicji Tworzenie pierwszego pliku nagłówkowego Jeśli oprogramowałeś często używane operacje… Możesz rozdzielić kod, umieszczając go w osobnych plikach Za kulisami kompilacji Współdzielony kod trzeba umieścić w osobnym pliku źródłowym To nie jest kosmiczna technologia… a może jest? Nie rekompiluj każdego pliku Najpierw skompiluj źródła do plików obiektowych Ciągłe śledzenie zmian w plikach jest trudne Zautomatyzuj kompilacje, używając narzędzia make Jak działa make Przekaż informacje o kodzie, używając pliku makefile Startujemy! Twój niezbędnik C 160 161 162 166 167 169 171 172 180 181 182 184 187 188 189 194 196 197 198 203 204 gcc -c gcc -o xiv 1. laboratorium C Arduino Czy kiedykolwiek marzyłeś o tym, by rośliny mogły Ci powiedzieć, kiedy potrzebują podlania? No i proszę: dzięki Arduino stało się to możliwe! W tym laboratorium stworzysz działający w oparciu o Arduino monitor roślin, napisany w całości w języku C. napisany w całości w języku C. Spis treści Spis treści Spis treści xv Spis treści 5 Struktury, unie i pola bitowe Wytocz swoje własne struktury Większość rzeczy w realnym życiu jest nieco bardziej złożona niż proste liczby. Do tej pory poznałeś jedynie podstawowe typy danych dostępne w języku C, ale co można zrobić, by wykroczyć poza to, co dają nam liczby i łańcuchy znaków — gdybyśmy chcieli odwzorować przedmioty z realnego świata? W języku C złożoności realnego świata można odwzorowywać przy użyciu struktur — typu struct. W tym rozdziale dowiesz się, jak łączyć podstawowe typy danych przy użyciu struktur, a nawet jak radzić sobie z niewiadomymi życia przy użyciu unii. Jeśli z kolei wolisz proste odpowiedzi typu „tak” lub „nie”, to mogą Ci się przydać pola bitowe. Czasami musisz rozdawać wiele danych Rozmowa trójstronna Twórz swoje własne strukturalne typy danych przy użyciu struct Po prostu daj im rybkę Odczytuj pola struktur, używając operatora . Czy można umieścić jedną strukturę wewnątrz drugiej? Jak zaktualizować zawartość struktury? Ten kod klonuje żółwie Potrzebny będzie wskaźnik na strukturę (*t).age kontra *t.age Czasami rzeczy podobnego typu wymagają danych różnych typów Unie pozwalają używać bloku pamięci na różne sposoby Jak stosować unie? Zmienna typu enum przechowuje symbol Czasami potrzebujemy kontroli na poziomie bitów Pola bitowe zawierają dowolną liczbę bitów Twój niezbędnik C 216 217 218 219 220 225 234 236 237 238 244 245 246 253 259 260 264 To jest Marceli… …ale do funkcji zostaje przekazany jego klon. xvi Oto żółw „t”. Spis treści 6 Struktury danych i pamięć dynamiczna Budowanie mostów Czasami prosta struktura nie wystarcza. Aby zamodelować bardzo złożone dane, często będziemy musieli łączyć ze sobą struktury. W tym rozdziale zobaczysz, jak korzystać ze wskaźników na dane typu struct, by łączyć niestandardowe typy danych w duże i złożone struktury danych. Poznasz kluczowe zasady, ucząc się tworzyć listy połączone. Dowiesz się także, jak sprawić, by Twoje struktury danych radziły sobie ze zmienną liczbą informacji, wykorzystując do tego celu dynamiczne przydzielanie pamięci na stercie i zwalniając używaną pamięć, kiedy nie będzie już potrzebna. A gdy porządkowanie pamięci stanie się zbyt trudne, dowiesz się, jak może nam pomóc program valgrind. Czy potrzebujesz elastycznego sposobu przechowywania danych? Listy połączone przypominają łańcuchy danych Listy połączone pozwalają na dodawanie elementów Tworzenie struktur rekurencyjnych Tworzenie wysp w języku C… Wstawianie elementów pośrodku listy Pamięć dynamiczną rezerwuj na stercie Zwróć pamięć, kiedy nie będzie już potrzebna Proś o pamięć, wywołując malloc()… Popraw kod, używając funkcji strdup() Zwalniaj pamięć, gdy jej nie potrzebujesz Przegląd systemu SPIES Detektywi oprogramowania: stosowanie valgrind Skorzystaj z programu valgrind kilkakrotnie, by zebrać więcej dowodów Przeanalizuj dowody Sprawdzenie poprawek Twój niezbędnik C 266 267 268 269 270 271 276 277 278 284 288 298 300 301 302 305 307 Wyspa Skalista 32 bajty danych na stercie w miejscu o adresie 4204853 Wyspa Zjaw Wyspa Chmur xvii Spis treści 7 Zaawansowane funkcje Odpicuj swoje funkcje na maksa! Proste funkcje są w porządku, jednak czasami możemy potrzebować czegoś więcej. Do tej pory koncentrowaliśmy się na sprawach podstawowych, ale co zrobić, kiedy do osiągnięcia celu będziemy potrzebowali większych możliwości i większej elastyczności? W tym rozdziale zobaczysz, jak podnieść IQ swojego kodu, przekazując funkcje jako parametry. Dowiesz się, jak można sortować, wykorzystując funkcje — komparatory. A na samym końcu nauczysz się, jak dzięki zastosowaniu zmiennej liczby argumentów tworzyć superelastyczne funkcje. Szukając Pana Doskonałego… Przekaż kod do funkcji Musisz przekazać funkcji find() nazwę funkcji testującej Każda nazwa funkcji jest wskaźnikiem do tej funkcji… …ale nie ma żadnego typu danych reprezentującego funkcję Jak utworzyć wskaźnik do funkcji Posortuj to, używając standardowej biblioteki C Użyj wskaźnika do funkcji, by określić porządek sortowania Automatyzacja generowania listów do Jana Stwórz tablicę wskaźników do funkcji Zapewnij swoim funkcjom elastyyyyyczność Twój niezbędnik C 310 314 315 316 317 318 323 324 332 336 341 348 Maszyna testująca xviii Spis treści 8 Biblioteki statyczne i dynamiczne Wymienialny kod Poznałeś już ogromne możliwości bibliotek standardowych. Nadszedł czas, byś użył mocy swojego własnego kodu. W tym rozdziale dowiesz się, jak tworzyć swoje własne biblioteki oraz jak wielokrotnie używać tego samego kodu w różnych programach. Co więcej, nauczysz się współużytkowania kodu w trakcie działania programu, co jest możliwe dzięki bibliotekom łączonym dynamicznie. Poznasz sekrety mistrzów kodowania. A pod koniec tego rozdziału będziesz już potrafił pisać kod, który w łatwy i efektywny sposób będzie można skalować oraz którym będzie można równie łatwo zarządzać. Kod, który możesz zabrać do banku Nawiasy kątowe dołączają standardowe pliki nagłówkowe A co zrobić, jeśli będziesz chciał współużytkować jakiś kod? Współużytkowanie plików nagłówkowych Współużytkowanie plików .o poprzez określanie pełnej ścieżki dostępu Archiwum zawiera pliki .o Utwórz archiwum, używając polecenia ar… I w końcu kompiluj inne programy Siłownia Rusz Głową wchodzi na scenę globalną Obliczanie spalonych kalorii Ale zagadnienie jest nieco bardziej skomplikowane… Programy składają się z wielu fragmentów… Łączenie dynamiczne następuje podczas działania programu Czy pliki .a można łączyć podczas działania programu? Najpierw utwórz plik obiektowy Nazewnictwo bibliotek dynamicznych zależy od platformy systemowej Twój niezbędnik C 350 352 353 354 355 356 357 358 363 364 367 368 370 371 372 373 385 Rodzynki, mąka, masło, anchois… Czy to ptak? Czy samolot? Nie, to przenaszalny plik obiektowy z metadanymi. xix 2. laboratorium C OpenCV Wyobraź sobie, że komputer mógłby pilnować Twojego domu, kiedy Cię nie ma, i informować Cię, kto się po nim kręcił. W tym laboratorium napiszesz w C system wykrywania włamywaczy, korzystając przy tym z możliwości biblioteki OpenCV. z możliwości biblioteki OpenCV. Spis treści xx Spis treści 9 Procesy i wywołania systemowe Przekraczanie granic Czas, by zacząć myśleć kreatywnie. Dowiedziałeś się już, że można tworzyć złożone aplikacje, łącząc niewielkie programy narzędziowe wywoływane z poziomu wiersza poleceń. Ale co zrobić, gdy będziemy chcieli korzystać z innych programów we własnym kodzie? W tym rozdziale dowiesz się, jak korzystać z usług systemowych, by tworzyć i kontrolować działanie procesów. Dzięki temu Twoje programy uzyskają dostęp do poczty elektronicznej, WWW oraz wszelkich innych narzędzi zainstalowanych na komputerze. Po przeczytaniu tego rozdziału zyskasz moc pozwalającą wykraczać poza język C. Wywołania systemowe są Twoją gorącą linią z systemem operacyjnym Wtem ktoś włamał się do systemu… Bezpieczeństwo nie jest jedynym problemem Funkcja exec() zapewnia większą kontrolę Istnieje wiele funkcji exec() Funkcje z tablicą argumentów: execv(), execvp() oraz execve() Przekazywanie zmiennych środowiskowych Większość wywołań systemowych zawodzi w taki sam sposób Czytaj doniesienia, używając RSS exec() jest końcem rodu naszego programu Uruchamianie procesu potomnego przy użyciu funkcji fork() i exec() Twój niezbędnik C 396 400 401 402 403 404 405 406 414 418 419 425 To jest Twój proces newshound. Uruchamia on odrębny proces dla każdego z trzech kanałów RSS. newshound Wszystkie procesy potomne działają jednocześnie. xxi Spis treści 10 Komunikacja pomiędzy procesami Dobrze jest porozmawiać Tworzenie procesów to tylko połowa sukcesu. Co zrobić, gdy chcemy kontrolować proces po jego uruchomieniu? Albo przesłać do niego jakieś dane? Albo odczytać generowane przez niego wyniki? Komunikacja pomiędzy procesami zapewnia procesom możliwość podejmowania wspólnych działań w celu wykonania zadania. W tym rozdziale pokażemy Ci, jak możesz zwiększyć możliwości swojego kodu, pozwalając mu na komunikowanie się z innymi programami w systemie. Przekierowania strumieni wejściowych Zajrzyjmy do wnętrza standardowego procesu Przekierowanie zastępuje deskryptor Funkcja fileno() zwraca deskryptor Czasami trzeba poczekać… Bądź w kontakcie ze swymi potomkami Połącz swoje procesy potokami Studium przypadku: otwieranie doniesień w przeglądarce W procesie potomnym W procesie rodzicielskim Otwieranie strony w przeglądarce Śmierć procesu Przechwytywanie sygnałów i wykonywanie własnego kodu Struktury sigaction są rejestrowane przy użyciu funkcji sigaction() Modyfikacja kodu i wykorzystanie procedury obsługi sygnałów Używaj polecenia kill, by wysyłać sygnały Wysyłanie do procesu sygnału pobudki Twój niezbędnik C 428 429 430 431 436 440 441 442 443 443 444 449 450 451 452 455 456 464 #include stdio.h int main() { char name[30]; printf(“Wpisz, jak masz na imię: “); fgets(name, 30, stdin); printf(“Witaj, s ”, name); return 0; } Plik Edycja Okno Pomoc ./greetings Wpisz, jak masz na imię: ^C Kiedy naciśniesz kombinację klawiszy Ctrl+C, program przestaje działać. Ale dlaczego? xxii Spis treści 11 Gniazda i komunikacja sieciowa Nie ma drugiego takiego miejsca jak 127.0.0.1 Programy działające na różnych komputerach muszą się ze sobą komunikować. Dowiedziałeś się już, jak można używać operacji wejścia-wyjścia, by korzystać z plików, oraz w jaki sposób mogą się ze sobą porozumiewać programy działające na tym samym komputerze. Teraz jednak masz zamiar sięgnąć po resztę świata i nauczyć się pisać w języku C programy, które będą mogły komunikować się z innymi programami działającymi w tej samej sieci oraz na całym świecie. Po przeczytaniu tego rozdziału będziesz potrafił pisać programy działające jako serwery oraz programy pracujące jako klienty. Internetowy serwer puk-puk Prezentacja serwera puk-puk PNAR — jak serwery komunikują się z internetem Gniazdo nie jest typowym strumieniem danych Czasami serwer nie uruchamia się prawidłowo Dlaczego mama zawsze powtarzała Ci, byś sprawdzał błędy Odczyt danych przesyłanych przez klienta Serwer może rozmawiać tylko z jednym klientem naraz Możesz użyć fork(), by obsłużyć oba klienty jednocześnie Pisanie klienta WWW To zadanie klienta Utwórz gniazdo dla adresu IP Funkcja getaddrinfo() pobiera adresy domen Twój niezbędnik C Klient telnet Serwer będzie rozmawiał z kilkoma klientami jednocześnie. Klient telnet Klient telnet Serwer Klient oraz serwer prowadzą konwersację o ściśle określonej strukturze, nazywanej protokołem. 466 467 468 470 474 475 476 483 484 488 489 490 491 498 xxiii Spis treści 12 Wątki To równoległy świat Programy często muszą robić kilka rzeczy naraz. Wątki POSIX mogą sprawić, że nasz kod będzie sprawniej reagował na poczynania użytkownika, a to dzięki wydzieleniu kilku fragmentów, które będą działać jednocześnie. Ale uważaj! Wątki są potężnym narzędziem, jednak na pewno byś nie chciał, żeby sobie wzajemnie przeszkadzały. W tym rozdziale dowiesz się, jak zainstalować sygnalizację świetlną i wytyczyć linie, które zapobiegną programistycznym karambolom w Twoim kodzie. Po przeczytaniu tego rozdziału będziesz wiedział, jak tworzyć wątki POSIX oraz jak używać mechanizmów synchronizacji, by chronić integralność ważnych danych. Zadania są sekwencyjne… lub nie… …a procesy nie zawsze są właściwą odpowiedzią Proste procesy robią po jednej rzeczy naraz Zatrudnij dodatkowych pracowników: skorzystaj z wątków Jak się tworzy wątki? Utwórz wątki, używając funkcji pthread_create() Ten kod nie jest wielobieżny Potrzeba Ci sygnalizacji świetlnej Użyj muteksu jako sygnalizacji świetlnej Twój niezbędnik C 500 501 502 503 504 505 510 511 512 519 Zmienna współdzielona Sygnalizacja świetlna uniemożliwia wątkom dostęp do tej samej współdzielonej zmiennej w tym samym czasie. A Te dwa auta reprezentują dwa wątki. Oba chcą skorzystać z tej samej współdzielonej zmiennej. B xxiv 3. laboratorium C Blasteroidy W tym laboratorium oddasz hołd jednej z najbardziej popularnych i długowiecznych gier wideo wszech czasów. Pora, byś napisał własną wersję gry Blasteroids! Spis treści Spis treści Spis treści xxv Spis treści A Pozostałości Dziesięć najważniejszych rzeczy (których nie opisaliśmy) Nawet po tym wszystkim, co już napisaliśmy, wciąż jeszcze pozostaje coś, czego nie wyjaśniliśmy. Jest jeszcze parę zagadnień, o których według nas powinieneś się dowiedzieć. Nie czulibyśmy się dobrze, gdybyśmy zupełnie je zignorowali. Wymagają one choć krótkiego wyjaśnienia, a my naprawdę nie chcemy oddawać Ci do rąk książki, której nie byłbyś w stanie podnieść bez solidnego treningu na lokalnej siłowni. A zatem zanim odłożysz tę książkę na półkę, przeczytaj zamieszczone tu informacje. 1. Operatory 2. Dyrektywy preprocesora 3. Słowo kluczowe static 4. Jak duże to jest? 5. Automatyczne testowanie 6. Więcej o gcc 7. Więcej o programie make 8. Narzędzia programistyczne 9. Tworzenie graficznego interfejsu użytkownika 10. Materiały 538 540 541 542 543 544 546 548 549 550 Zagadnienia programowania w C Powtórka z całego materiału Czy kiedykolwiek pomyślałeś, że fajnie by było, gdyby te wszystkie wspaniałe fakty dotyczące C zostały zebrane w jednym miejscu? W tym dodatku zostały zebrane wszystkie zagadnienia oraz zasady związane z pisaniem w języku C, które przedstawiliśmy w całej książce. Przejrzyj je wszystkie i przekonaj się, czy je zapamiętałeś. Przy każdym fakcie został podany numer rozdziału, z którego on pochodzi, a zatem nie będziesz miał problemów z odnalezieniem dodatkowych informacji, gdybyś ich potrzebował. Możesz nawet wyciąć te strony z książki i przykleić je sobie na ścianie. gcc B Procesy i komunikacja Procesy i komunikacja . 9 ł a i z d z o R Funkcja system() wykona polecenie zapisane w łańcuchu znaków, tak jakby zostało ono wpisane w wierszu poleceń. . 9 ł a i z d z o R Funkcja fork() tworzy kopię bieżącego procesu. . 9 ł a i z d z o potomny.R Wywołania funkcji fork() oraz exec() tworzą proces . 9 ł a i z d z o R execl() = lista argumentów. execle() = lista argumentów oraz zmienne środowiskowe. execlp() = lista argumentów oraz przeszukanie ścieżki. execv() = tablica argumentów. execve() = tablica argumentów oraz zmienne środowiskowe. execvp() = tablica argumentów oraz przeszukanie ścieżki. . 0 1 ł a i z d z o R Procesy mogą wymieniać ze sobą dane przy użyciu potoków. . 0 1 ł a i z d z o R Funkcja exit() powoduje natychmiastowe zakończenie programu. 568 Dodatek B . 0 1 ł a i z d z o R . 0 1 ł a i z d z o R Funkcja pipe() tworzy potok komunikacyjny. Funkcja waitpid() pozwala poczekać na zakończenie procesu. xxvi 1. Zaczynamy poznawać C Dajmy nurka Czy nie ubóstwiasz niebieskiego oCeanu? Wskakuj — woda jest cudowna! Czy chcesz zajrzeć do głowy komputera? Musisz napisać kod działający naprawdę szybko, na przykład na potrzeby nowej gry? A może program na Arduino? Albo we własnej aplikacji na iPhone’a użyć biblioteki napisanej przez kogoś innego? Jeśli tak, to skorzystaj z pomocy bohaterskiego C. C działa na znacznie niższym poziomie niż większość innych języków programowania, a zatem zrozumienie go daje nam znacznie większe pojęcie o tym, co się naprawdę dzieje w programie. C pozwala także lepiej zrozumieć inne języki programowania. A zatem bierz się do pracy, przygotuj kompilator, a już niedługo zaczniesz poznawać C. to jest nowy rozdział  1 Jak działa C C to język do pisania małych, szybkich programów Język C został stworzony do pisania małych i szybkich programów. Działa na znacznie niższym poziomie niż większość innych języków programowania, a to oznacza, że tworzy kod znacznie bliższy temu, co komputery naprawdę są w stanie zrozumieć. Sposób działania C Tak naprawdę komputery rozumieją tylko jeden język: kod maszynowy — binarny strumień składający się jedynie z zer i jedynek. Kod napisany w języku C konwertujemy na kod maszynowy za pomocą kompilatora. #include stdio.h int main() { puts(“C jest czaderskie!”); return 0; } rocks.c 1 Kod źródłowy Zaczynasz od utworzenia pliku źródłowego. Plik źródłowy zawiera kod napisany w języku C, który jest zrozumiały dla człowieka. Plik Edycja Okno Pomoc Kompilacja gcc rocks.c -o rocks 2 Kompilacja Plik źródłowy jest następnie przetwarzany przy użyciu kompilatora. Kompilator sprawdza kod w poszukiwaniu błędów, a kiedy uzna, że wszystko jest w porządku, kompiluje go. W systemie Windows ten plik będzie nosił nazwę rocks.exe, a nie rocks. rocks 3 Kod wynikowy Kompilator tworzy nowy plik, nazywany plikiem wykonywalnym. Zawiera on kod maszynowy — strumień jedynek i zer, które jest w stanie zrozumieć komputer. I to właśnie jest program, który możesz wykonać. Język C jest używany, w przypadku gdy duże znaczenie mają szybkość działania, niewielkie rozmiary oraz możliwość przenoszenia. Większość systemów operacyjnych została napisana w języku C. Także większość innych języków programowania została napisana w C. Dodatkowo przeważająca większość gier jest pisana w C. Istnieją trzy standardy języka C, z którymi można się zetknąć. ANSI C pochodzi z późnych lat 80. i jest używany w najstarszym kodzie. W nowym standardzie — C99, istniejącym od 1999 roku, poprawiono sporo różnych rzeczy. Natomiast w najnowszym standardzie — C11, opracowanym w 2011 roku, dodano kilka nowych, świetnych możliwości. Różnice pomiędzy tymi trzema standardami nie są wielkie, jednak będziemy o nich wspominać. 2 Rozdział 1. Zaczynamy poznawać C Zaostrz ołówek Zaostrz ołówek Zaostrz ołówek Spróbuj odgadnąć, co robi każdy z tych fragmentów kodu. int card_count = 11; if (card_count 10) puts(“Nowe rozdanie. Licytujemy.”); int c = 10; while (c 0) { puts(“Nie mogę pisać kodu w klasie.”); c = c - 1; } Opisz, co według Ciebie robi ten fragment kodu. ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... /* Załóż, że imię ma mniej niż 20 znaków. */ char ex[20]; puts(“Podaj imię chłopaka: “); scanf(“ 19s”, ex); printf(“ s. Z nami już koniec. ”, ex); ....................................... ....................................... ....................................... ....................................... ....................................... char suit = ‘K’; switch(suit) { case ‘T’: puts(“Trefle”); break; case ‘K’: puts(“Kara”); break; case ‘P’: puts(“Piki”); break; default: puts(“Serca”); } ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... ....................................... jesteś tutaj  3 Fragmenty bez tajemnic Zaostrz ołówek Zaostrz ołówek Zaostrz ołówek Rozwiązanie Nie przejmuj się, jeśli jeszcze nie rozumiesz wszystkiego. Zostanie to szczegółowo wyjaśnione w dalszej części książki. int oznacza liczbę całkowitą. int card_count = 11; if (card_count 10) puts(“Nowe rozdanie. Licytujemy.”); To wyświetla łańcuch znaków w wierszu poleceń lub na terminalu. Nawiasy klamrowe definiują instrukcję blokową. int c = 10; while (c 0) { puts(“Nie mogę pisać kodu w klasie.”); c = c - 1; } Tworzy zmienną całkowitą i przypisuje jej wartość 11. ........................................................... Czy wartość zmiennej jest większa od 10? ........................................................... Jeśli jest, to wyświetlamy komunikat. ........................................................... Tworzy zmienną całkowitą i przypisuje jej wartość 10. ........................................................... Jak długo wartość jest większa od zera… ........................................................... …wyświetlamy komunikat… ........................................................... …i dekrementujemy wartość zmiennej. ........................................................... To koniec powtarzanego bloku kodu. ........................................................... /* Załóż, że imię ma mniej niż 20 znaków. */ To oznacza: char ex[20]; „Wszystko, puts(“Podaj imię chłopaka: “); co użytkownik wpisze, zapisz scanf(“ 19s”, ex); w tablicy ex”. printf(“ s. Z nami już koniec. ”, ex); To jest komentarz. ........................................................... Tworzymy tablicę 20 znaków. ........................................................... Wyświetlamy komunikat na ekranie. ........................................................... Zapisujemy w tablicy to, co wpisze użytkownik. ........................................................... Wyświetlamy komunikat zawierający wpisany tekst. ........................................................... To wstawi łańcuch znaków w miejsce s Instrukcja switch sprawdza zmienną, porównując ją do różnych wartości. char suit = ‘K’; switch(suit) { case ‘T’: puts(“Trefle”); break; case ‘K’: puts(“Kara”); break; case ‘P’: puts(“Piki”); break; default: puts(“Serca”); } Tworzymy zmienną znakową i zapisujemy w niej K. ........................................................... Sprawdzamy wartość zmiennej. ........................................................... Czy jest nią „T”? ........................................................... Jeśli tak, to wyświetlamy słowo „Trefle”. ........................................................... Następnie pomijamy pozostałe testy. ........................................................... Czy jest nią „K”? ........................................................... Jeśli tak, to wyświetlamy słowo „Kara”. ........................................................... Następnie pomijamy pozostałe testy. ........................................................... Czy jest nią „P”? ........................................................... Jeśli tak, to wyświetlamy słowo „Piki”. ........................................................... Następnie pomijamy pozostałe testy. ........................................................... W przeciwnym razie… ........................................................... ...wyświetlamy słowo „Serca”. ........................................................... To już koniec sprawdzania. ........................................................... 4 Rozdział 1. Zaczynamy poznawać C Ale jak wygląda skompilowany program napisany w C? Aby stworzyć pełny program, musisz zapisać jego kod w pliku źródłowym. Pliki źródłowe programów pisanych w języku C można utworzyć w dowolnym edytorze tekstów, a ich nazwy zazwyczaj mają rozszerzenie .c. Przyjrzyjmy się typowemu plikowi źródłowemu programu w języku C. To jest tylko konwencja, jednak powinieneś się do niej zastosować. 1 Programy pisane w języku C zazwyczaj zaczynają się od komentarza. Komentarz opisuje przeznaczenie kodu umieszczonego w tym pliku, a dodatkowo może także zawierać informacje o licencji oraz prawach autorskich. Nie ma potrzeby umieszczania komentarza — ani tu, ani w żadnym innym miejscu pliku — jednak jest to dobrym zwyczajem i większość programistów używających języka C będzie takiego komentarza oczekiwać. Komentarz zaczyna się od znaków /*. Te znaki * są opcjonalne. Poprawiają tylko wygląd komentarza. Komentarz kończy się znakami */. /* * Ten program służy do liczenia kart. * Kod jest udostępniany na warunkach Vegas Public License. * (c)2014, Studencki Klub Graczy w Oczko. */ 2 Teraz kolej na sekcję dyrektyw include. C jest językiem o bardzo, bardzo małych możliwościach… bez zastosowania bibliotek zewnętrznych nie da się w nim zrobić praktycznie niczego. Będziesz musiał poinformować kompilator o tym, jakiego kodu zewnętrznego chcesz używać, podając pliki nagłówkowe odpowiednich bibliotek. Plikiem nagłówkowym, którego będziemy używać zdecydowanie najczęściej, jest stdio.h. Biblioteka stdio zawiera kod pozwalający odczytywać dane z terminala i wyświetlać je w nim. 3 #include stdio.h int main() { int decks; puts(“Podaj liczbę talii”); scanf(“ i”, decks); if (decks 1) { puts(“To nie jest prawidłowa liczba talii”); return 1; } printf(“Łącznie jest w nich i kart ”, (decks * 52)); return 0; } Ostatnią rzeczą, jaką można znaleźć w plikach źródłowych, są funkcje. Cały kod pisany w języku C jest umieszczany wewnątrz funkcji. Najważniejsza funkcja, którą znajdziemy w każdym programie pisanym w tym języku, nosi nazwę main(). Stanowi ona punkt początkowy, od którego zaczyna się wykonywanie całego kodu programu. A zatem przyjrzyjmy się funkcji main() nieco bardziej szczegółowo. jesteś tutaj  5 Funkcja main() Zbliżenie na semantyczne znaczniki Komputer zacznie wykonywać nasz program od funkcji main(). Jej nazwa ma znaczenie: jeśli w kodzie programu nie będzie funkcji main(), nie będzie go można wykonać. Funkcja main() zwraca wartość typu int. Co to oznacza? Cóż, kiedy komputer wykonuje program, musi dysponować jakimś sposobem określenia, czy został on wykonany prawidłowo, czy też nie. Robi to, sprawdzając wartość wynikową zwracaną przez funkcję main(). Jeśli każemy jej zwrócić wartość 0, będzie to oznaczało, że program został wykonany prawidłowo. Jeśli natomiast zwrócimy inną wartość, będzie to oznaczało, że pojawiły się jakieś problemy. To typ wyniku. W przypadku funkcji main() zawsze powinien to być typ int. Zawartość funkcji jest zawsze umieszczana pomiędzy nawiasami klamrowymi. Ponieważ funkcja nosi nazwę „main”, to właśnie od niej rozpocznie się wykonywanie programu. Gdyby funkcja miała jakieś parametry, zostałyby one tu wymienione. int main() { int decks; puts(“Podaj liczbę talii”); scanf(“ i”, decks); if (decks 1) { puts(“To nie jest prawidłowa liczba talii”); return 1; } printf(“Łącznie jest w nich i kart ”, (decks * 52)); return 0; } Nazwa funkcji jest podawana za typem wyniku. Za nazwą mogą natomiast zostać podane parametry funkcji, oczywiście jeśli w ogóle takie są. Ostatnim elementem funkcji jest jej zawartość. Zawartość funkcji musi być zapisana wewnątrz pary nawiasów klamrowych. Dla maniaków Funkcja printf() służy do wyświetlania sformatowanych danych wynikowych. Zastępuje ona znaki formatujące wartościami zmiennych. Oto przykład: Pierwszy parametr zostanie wstawiony jako łańcuch znaków. Pierwszy parametr printf(“ s mówi, że poszukiwaną liczbą jest i”,”Janek”, 21); Drugi parametr zostanie wstawiony jako liczba całkowita. Drugi parametr Wywołując funkcję printf(), można w niej podać dowolnie wiele parametrów, musimy się jednak przy tym upewnić, że użyliśmy tyle samo znaków formatujących . Jeśli chcesz sprawdzić status wykonania programu, to w systemie Windows wpisz: echo ErrorLevel natomiast w systemach Linux lub Mac OS wpisz: echo $? 6 Rozdział 1. Zaczynamy poznawać C Magnesiki z kodem Członkowie Studenckiego Klubu Gry w Oczko pracowali nad pewnym kodem, układając go z magnesików na lodówce w swoim akademiku, ale jakiś dowcipniś im je pomieszał! Czy byłbyś w stanie odtworzyć ich prawidłowe ułożenie? /* * Ten program służy do liczenia kart. * Kod jest udostępniany na warunkach Vegas Public License. * (c)2014, Studencki Klub Graczy w Oczko. */ ...................................................... ...................................................... .......... main() { char card_name[3]; puts(“Wpisz symbol karty (card_name): “); scanf(“ 2s”, card_name); int val = 0; if (card_name[0] == ’K’) { val = 10; } else if (card_name[0] == ’Q’) { ............................................ } else if (card_name[0] == ............) { val = 10; } .............(card_name[0] == ...........) { ............................................ } else { val = atoi(card_name); } printf(“Wartość karty to: i ”, val); ............. 0; } Ta funkcja konwertuje tekst na liczbę. Wpisz dwuliterowy symbol określający nazwę karty. stdlib.h ; ; val = 11 int J #include A return else #include val = 10 if stdio.h jesteś tutaj  7 Magnesiki ponownie poukładane Magnesiki z kodem. Rozwiązanie Członkowie Studenckiego Klubu Gry w Oczko pracowali nad pewnym kodem, układając go z magnesików na lodówce w swoim akademiku, ale jakiś dowcipniś im je pomieszał! Twoim zadaniem było ponowne poukładanie magnesików. /* * Ten program służy do liczenia kart. * Kod jest udostępniany na warunkach Vegas Public License. * (c)2014, Studencki Klub Graczy w Oczko. */ #include stdio.h ............................................ ............................................ ............................................ ............................................ ............................................ ............................................ ............................................ ............................................ stdlib.h #include int ................... main() ................... main() ................... main() { char card_name[3]; puts(“Wpisz symbol karty (card_name): “); scanf(“ 2s”, card_name); int val = 0; if (card_name[0] == ’K’) { val = 10; } else if (card_name[0] == ’Q’) { ............................................ ............................................ ............................................ ............................................ val = 10 ; } else if (card_name[0] == ........... ) { } else if (card_name[0] == ........... ) { val = 10; } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { } ........... (card_name[0] == ........... ) { else A if J val = 11 ; ............................................ ............................................ ............................................ ............................................ } else { val = atoi(card_name); } printf(“Wartość karty to: i ”, val); ........... 0; ........... 0; } return 8 Rozdział 1. Nie istnieją głupie pytania P: Co oznacza card_name[0]? O: To pierwszy znak wpisany przez użytkownika. Jeśli zatem użytkownik wpisał 10, to wartością wyrażenia card_ name[0] będzie 1. P: Czy zawsze zapisujecie komentarze, używając sekwencji znaków /* oraz */? O: Jeśli używany kompilator obsługuje standard C99, to komentarze można także zapisywać za sekwencją znaków //. W takim przypadku kompilator uzna za komentarz całą zawartość wiersza umieszczoną za tymi znakami. P: Skąd mam wiedzieć, jaki standard obsługuje mój kompilator? O: Sprawdź dokumentację kompilatora. Kompilator gcc obsługuje wszystkie trzy standardy: ANSI C, C99 oraz C11. Zaczynamy poznawać C A jak można uruchomić program? C jest językiem kompilowanym. Oznacza to, że komputer nie zinterpretuje kodu bezpośrednio. Zamiast tego musimy przekonwertować — czy też skompilować — zrozumiały dla nas, ludzi, kod źródłowy na kod maszynowy, który z kolei jest w stanie zrozumieć komputer. Aby skompilować kod źródłowy, będzie nam potrzebny program nazywany kompilatorem. Jednym z najbardziej popularnych kompilatorów jest GNU Compiler Collection, nazywany też skrótowo gcc. Jest on dostępny w wielu systemach operacyjnych i pozwala na kompilowanie kodu napisanego nie tylko w C, lecz także w wielu innych językach programowania. A co najważniejsze, można go używać za darmo. Oto, w jaki sposób można skompilować i uruchomić program przy użyciu gcc: 1 2 Zapisz kod z ćwiczenia Magnesiki z kodem, umieszczonego na poprzedniej stronie, w pliku cards.c. Pliki źródłowe zazwyczaj mają rozszerzenie .c. Skompiluj plik, wykonując następujące polecenie w wierszu poleceń lub w oknie terminala: gcc cards.c -o cards. cards.c Kompilujemy plik cards.c na plik o nazwie cards. Plik Edycja Okno Pomoc Kompilacja gcc cards.c -o cards 3 Uruchom program, wydając polecenie cards w systemie Windows lub ./cards w systemie Linux bądź na komputerach Mac. Plik Edycja Okno Pomoc Kompilacja ./cards Wpisz symbol karty (card_name): Dla maniaków Na większości komputerów program można jednocześnie skompilować i uruchomić, posługując się następującą sztuczką: gcc zork.c –o zork ./zork Umieszczone w tym poleceniu dwa znaki oznaczają: „a następnie, jeśli wszystko się uda, zrób…”. Na komputerach z zainstalowanym systemem Windows należy użyć „zork” zamiast „./zork”. To polecenie spowoduje uruchomienie nowego programu wyłącznie wtedy, gdy uda się go poprawnie skompilować. Jeśli podczas kompilacji wystąpią jakieś problemy, program nie zostanie wykonany, a na ekranie pojawią się informacje o błędach. cards.c cards Jeśli używamy systemu Windows, to ten plik będzie nosił nazwę cards.exe. Zrób to sam! Teraz powinieneś samemu utworzyć i skompilować plik cards.c. W dalszej części rozdziału będziemy go jeszcze wielokrotnie modyfikować. jesteś tutaj  9 Jazda próbna Jazda próbna Sprawdźmy, czy uda się skompilować i uruchomić program. Otwórz okno wiersza poleceń lub terminala na swoim komputerze i przekonaj się sam. To polecenie kompiluje kod i tworzy program cards. To polecenie wykonuje program. Jeśli używasz systemu Windows, pomiń znaki ./. Uruchamiamy program jeszcze raz. Użytkownik wpisuje nazwę karty… …a program wyświetla odpowiednią wartość. Plik Edycja Okno Pomoc 21 gcc cards.c -o cards ./cards Wpisz symbol karty (card_name): Q Wartość karty to: 10 ./cards Wpisz symbol karty (card_name): A Wartość karty to: 11 ./cards Wpisz symbol karty (card_name): 7 Wartość karty to: 7 Pamiętaj: kompilację i uruchomienie programu można połączyć i wykonać w jednym kroku (zerknij na poprzednią stronę, by zobaczyć, jak to zrobić). Program działa! Gratulujemy! Właśnie skompilowałeś i uruchomiłeś program napisany w C. Kompilator gcc przekonwertował kod źródłowy programu zapisany w pliku cards.c i zrozumiały dla ludzi na kod maszynowy programu cards, który z kolei może zrozumieć komputer. Jeśli korzystasz z komputera Mac lub systemu Linux, kompilator wygeneruje kod maszynowy programu, zapisując go w pliku cards. Z kolei w systemie Windows, w którym wszystkie programy muszą mieć rozszerzenie .exe, program ten będzie nosił nazwę cards.exe. Nie istnieją głupie pytania P: Dlaczego na komputerach Mac oraz w systemie Linux muszę poprzedzać nazwę programu znakami ./? O: W systemach operacyjnych wzorowanych na systemie UNIX programy są uruchamiane wyłącznie wtedy, gdy zostanie określony katalog, w którym się znajdują, bądź też gdy katalog ten zostanie podany w zmiennej środowiskowej PATH. 10 Rozdział 1. Zaczynamy poznawać C Chwila, nie rozumiem. Kiedy prosimy użytkownika o podanie nazwy karty, używamy tablicy znaków. Tablicy znaków???? Czemu? Nie możemy użyć łańcucha znaków albo czegoś takiego? Istnieje jednak kilka bibliotek języka C, które udostępniają łańcuchy znaków. Sam język C nie udostępnia łańcuchów znaków. C działa na niższym poziomie niż większość pozostałych języków programowania, dlatego też zamiast łańcuchów znaków używa zazwyczaj czegoś zbliżonego: tablicy pojedynczych znaków. Jeśli pisałeś już programy w innych językach, to zapewne wiesz, czym są tablice. Tablica jest po prostu listą zawierającą jakieś elementy i posiadającą jedną nazwę. A zatem card_name jest nazwą zmiennej umożliwiającą odwoływanie się do listy znaków wpisanych przez użytkownika w wierszu poleceń. Zmienną card_name zdefiniowałeś jako tablicę składającą się z dwóch znaków, a zatem do pierwszego oraz drugiego z nich możesz się odwołać, używając następujących wyrażeń: card_name[0] oraz card_name[1]. Aby się przekonać, jak one działają, zajrzyjmy nieco głębiej do pamięci komputera i zobaczmy, w jaki sposób język C obsługuje teksty… jesteś tutaj  11 Teoria łańcuchów Łańcuchy pod mikroskopem Łańcuchy znaków są jedynie tablicami znaków. Kiedy kompilator C zobaczy następujący łańcuch: s = “Szpadel” odczytuje go tak, jak gdyby stanowił on tablicę niezależnych znaków: s = { ’S’, ’z’, ’p’, ’a’, ’d’, ’e’, ’l’} Każdy ze znaków w łańcuchu jest elementem tablicy; to właśnie dlatego można się do nich odwoływać przy użyciu indeksów, na przykład: s[0] oraz s[1]. Właśnie w taki sposób definiuje się łańcuchy znaków w języku C. S z p ... s[0] s[2] s[1] Nie wypadnijmy poza koniec łańcucha Ale co się dzieje, kiedy program chce odczytać zawartość łańcucha? Na przykład kiedy będzie chciał go wyświetlić. W wielu językach programowania komputer bardzo dokładnie śledzi i pamięta długość tablicy, jednak w porównaniu z wieloma innymi językami C jest językiem niższego poziomu i dlatego nie zawsze jest w stanie określić, jak długa jest tablica. Skoro zatem C ma wyświetlić łańcuch znaków na ekranie, musi wiedzieć, kiedy dotrze do końca tablicy znaków. I właśnie do tego służy specjalny znak nazywany wartownikiem. Wartownik to dodatkowy znak umieszczany na końcu łańcucha; ma on wartość . Kiedy komputer musi odczytać zawartość łańcucha, pobiera kolejne znaki z tablicy, aż dotrze do znaku . To oznacza, że gdy komputer zobaczy następujący łańcuch znaków: s = “Szpadel” to w rzeczywistości w pamięci będzie on zapisany w poniższy sposób: C wie, że po dotarciu do znaku musi się zatrzymać. S z p a s[3] s[0] s[2] s[1] d e l s[6] s[4] s[5] s[7] to znak kodu ASCII o wartości 0. Programiści piszący w języku C często nazywają go znakiem NULL. To właśnie z tego względu zmienną card_name musieliśmy zdefiniować w następujący sposób: char card_name[3]; W zmiennej card_name będziemy zapisywać wyłącznie łańcuchy składające się z jednego lub dwóch znaków, jednak ze względu na to, że łańcuchy muszą się kończyć wartownikiem, w tablicy musi się znaleźć miejsce dla dodatkowego znaku. 12 Rozdział 1. P: Dlaczego znaki są numerowane od 0, a nie od 1? O: Indeks określa przesunięcie; stanowi on miarę odległości od pierwszego znaku. P: Dlaczego? O: Komputer będzie przechowywać znaki w sąsiadujących ze sobą bajtach pamięci. Może zatem użyć indeksu do określenia położenia znaku. Jeśli komputer wie, że c[0] znajduje się w komórce o numerze 1000000, może bardzo szybko wyliczyć, iż znak c[96] będzie się znajdował w komórce 1000000 + 96. P: A dlaczego potrzebny jest znak wartownika? Czy C nie wie, jak długie są tablice? O: Zazwyczaj nie wie. Język C nie jest zbyt dobry w zapamiętywaniu długości tablic, a łańcuchy znaków są zwyczajnymi tablicami. Nie istnieją głupie pytania P: C nie wie, jak długie są tablice? O: Nie. Czasami kompilator może określić ich długość na podstawie analizy kodu, jednak zazwyczaj w języku C za kontrolę długości tablic odpowiada programista. P: Czy zapisywanie znaków w cudzysłowach lub apostrofach ma jakieś znaczenie? O: Tak. Apostrofy są używane do zapisywania pojedynczych znaków, natomiast cudzysłowy służą wyłącznie do zapisu łańcuchów znaków. P: Czy definiując łańcuchy, powinienem zatem zapisywać je w cudzysłowach (“), czy jawnie podawać jako tablicę znaków? O: Zazwyczaj definiujemy łańcuchy znaków, zapisując je w cudzysłowach. Nazywamy je wtedy literałami łańcuchowymi. Zapisywanie łańcuchów w takiej postaci jest znacznie prostsze. Bezbolesne operacje Nie wszystkie znaki równości są sobie równe. W języku C znak równości (=) jest używany do przypisywania. Natomiast dwa znaki równości (==) służą do testowania równości. Jeśli chcemy zwiększyć lub zmniejszyć wartość zmiennej, to używając skróconych operatorów przypisania += oraz -=, możemy zaoszczędzić trochę miejsca: Dodajemy 2 do zmiennej teeth. teeth = 4; teeth += 2; teeth == 4; teeth -= 2; Odejmujemy 2 od wartości zmiennej teeth. Przypisujemy zmiennej teeth wartość 4. Sprawdzamy, czy wartość zmiennej teeth jest równa 4. Zaczynamy poznawać C P: Czy istnieje jakakolwiek różnica pomiędzy literałami łańcuchowymi a tablicami znaków? O: Tylko jedna: literały łańcuchowe są stałymi. P: A co to znaczy? O: Oznacza to, że po utworzeniu literału jego znaków nie można zmieniać. P: A co się stanie, kiedy spróbuję to zrobić? O: To zależy od kompilatora. W przypadku gcc zostanie zgłoszony błąd magistrali. P: Błąd magistrali? A co to niby znaczy? O: Język C przechowuje literały łańcuchowe w pamięci w inny sposób. Błąd magistrali oznacza, że program nie może zmodyfikować fragmentu pamięci. I w końcu, jeśli chcemy zwiększyć lub zmniejszyć wartość zmiennej o 1, możemy się posłużyć operatorami ++ lub --. teeth++; teeth--; Powiększamy o 1. Zmniejszamy o 1. jesteś tutaj  13 Zróbmy coś! Dwa rodzaje poleceń Wszystkie polecenia, z jakimi do tej pory się spotkałeś, można było zaliczyć do jednej z dwóch następujących kategorii. Zrób coś Większość poleceń w języku C to instrukcje. Proste instrukcje są akcjami; coś robią lub coś zwracają. Spotkałeś już instrukcje definiujące zmienne, pobierające dane wejściowe z klawiatury lub wyświetlające informacje na ekranie. split_hand(); To jest prosta instrukcja. Czasami grupujemy instrukcje, tworząc tak zwane instrukcje blokowe. Instrukcje blokowe to grupy instrukcji zapisane wewnątrz nawiasów klamrowych. Te polecenia tworzą instrukcję blokową, gdyż są zapisane wewnątrz pary nawiasów klamrowych. { deal_first_card(); deal_second_card(); cards_in_hand = 2; } Zrób coś, wyłącznie jeśli warunek jest prawdziwy Instrukcje sterujące, takie jak if, przed wykonaniem kodu sprawdzają warunek: if (value_of_hand = 16) hit(); else stand(); To jest warunek. Wykonaj tę instrukcję, jeśli warunek zostanie spełniony. Wykonaj tę instrukcję, jeśli warunek nie zostanie spełniony. Zazwyczaj, jeśli warunek w instrukcji if zostanie spełniony, będziemy chcieli wykonać więcej niż jedną instrukcję; dlatego też w instrukcjach warunkowych często umieszcza się instrukcje blokowe: if (dealer_card == 6) { double_down(); hit(); } Jeśli warunek będzie spełniony, zostaną wykonane OBIE instrukcje. Zostały one umieszczone wewnątrz jednej instrukcji blokowej. 14 Rozdział 1. Czy nawiasy są potrzebne? Dzięki instrukcjom blokowym całe grupy instrukcji można traktować jako jedną. W języku C instrukcja if działa w następujący sposób: if (countdown == 0) do_this_thing(); Po sprawdzeniu warunku jest wykonywana jedna instrukcja. Co zatem zrobić, jeśli po sprawdzeniu warunku chcielibyśmy wykonać kilka instrukcji? Jeśli serię instrukcji zapiszemy w nawiasach klamrowych, to C potraktuje je tak, jak gdyby stanowiły jedną instrukcję: if (x == 2) { call_whitehouse(); sell_oil(); x = 0; } Programiści używający języka C starają się, by ich kod był krótki i zwięzły, dlatego też większość z nich będzie pomijać niepotrzebne nawiasy klamrowe w instrukcjach warunkowych (np. if) i pętlach (np. while). Dlatego zamiast: if (x == 2) { puts(“Zrób coś!”); } większość programistów C napisze: if (x == 2) puts(“Zrób coś!”); Oto kod, jakim aktualnie dysponujemy /* * Ten program służy do liczenia kart. * Kod jest udostępniany na warunkach Vegas Public License. * (c)2014, Studencki Klub Graczy w Oczko. */ #include stdio.h #include stdlib.h int main() { char card_name[3]; puts(“Wpisz symbol karty (card_name): “); scanf(“ 2s”, card_name); int val = 0; if (card_name[0] == ‘K’) { val = 10; } else if (card_name[0] == ‘Q’) { val = 10; } else if (card_name[0] == ‘J’) { val = 10; } else if (card_name[0] == ‘A’) { val = 11; } else { val = atoi(card_name); } printf(“Wartość karty to: i ”, val); return 0; } Zaczynamy poznawać C Mam pomysł. Czy ten program mógłby sprawdzać, czy wartość karty mieści się w określonym zakresie? To mogłoby być przydatne… jesteś tutaj  jesteś tutaj  15 ???????????????????? ???????????????????? Siema! Jak leci? Wyglądasz mi na sprytnego gościa. Kto jak kto, ale ja to wiem, bo sam jestem sprytnym gościem! Słuchaj, mam tu świetny interes, a ponieważ jestem też miłym gościem, pozwolę Ci w niego wejść. Bo wiesz, jestem ekspertem w liczeniu kart. Capo di tutti capi. A co to jest liczenie kart, spytasz? Cóż, z mojego punktu widzenia to jest kariera! Mówiąc poważnie, liczenie kart jest zwiększeniem twoich szans podczas gry w oczko. Grając w oczko, gdy na stole pozostaje sporo kart o wysokiej wartości, szanse gracza są nieco większe. I to jest twoja okazja! Liczenie kart pomaga ci śledzić, ile wysokich kart pozostaje jeszcze w grze. Załóżmy, że zaczynasz liczyć od wartości 0. Najpierw krupier wydaje królową — to wysoka karta. A zatem w talii jest już o jedną wysoką kartę mniej, czyli ich liczba jest pomniejszana o jeden: To królowa - liczba – 1 Jeśli jednak krupier wyda niską kartę, na przykład 4, to liczba jest powiększana: To czwórka - liczba + 1 Za wysokie karty uznajemy dziesiątkę oraz waleta, damę i króla. Kartami niskimi są: trójki, czwórki, piątki i szóstki. W taki sposób postępujemy w przypadku wszystkich kart wysokich i niskich, aż liczba stanie się naprawdę wysoka, a wtedy w następnym zakładzie możesz położyć dużo kasy i ta-dam! Niebawem będziesz miał więcej kasy niż moja trzecia żona! Jeśli chcesz nauczyć się jeszcze więcej, to już dziś zapisz się na mój Korespondencyjny Kurs Gry w Oczko i dowiedz się znacznie więcej nie tylko o liczeniu kart, lecz także o tym: ∗ Jak skorzystać z kryterium Kelly’ego, by zmaksymalizować wartość zakładów. ∗ Jak uniknąć kompletnej porażki w grze w wojnę. ∗ Jak się pozbyć tłustych plam z jedwabnego garnituru. ∗ Co pasuje do ubrania w kratkę. Więcej informacji można uzyskać od Kuzyna Józka, wicedyrektora Korespondencyjnego Kursu Gry w Oczko. 16 16 Rozdział 1. Rozdział 1. Zaczynamy poznawać C Liczenie kart? W języku C? Liczenie kart to sposób na powiększenie swoich szans w grze w oczko. Zliczając zagrane karty, gracz może określić najodpowiedniejszy moment do zrobienia dużego zakładu lub określić, kiedy lepiej grać o małe stawki. Mimo, że jest to metoda dająca duże możliwości, to jest ona jednocześnie całkiem prosta. Już dysponujemy kodem, który to robi. Do tego celu wystarczy użyć zmiennej. W tym przypadku wystarczy sprawdzić kilka wartości… prawda? Określić wartość karty. Czy mieści się ona w granicach od 3 do 6 (włącznie)? Powiększyć liczbę o 1. W przeciwnym razie… Czy karta to dziesiątka, J, Q lub K? Pomniejszyć liczbę o 1. A jak sprawdzić, czy coś jest = 3 i = 6? Czy to są dwa warunki do sprawdzenia? Jak trudno byłoby napisać taki program w języku C? Dowiedziałeś się już, jak sprawdzić jeden warunek, jednak nasz algorytm liczenia kart wymaga sprawdzenia dwóch warunków: musimy sprawdzić, czy wartość karty jest = 3 oraz czy jest = 6. Musimy zatem poznać operacje, które pozwolą nam łączyć ze sobą warunki. jesteś tutaj  17 Zaczynamy poznawać C Wartości logiczne to nie tylko sprawdzanie równości Jak na razie zetknąłeś się wyłącznie z instrukcją if, która kontrolowała, czy został sprawdzony pojedynczy warunek. A co zrobić, jeśli trzeba sprawdzić kilka warunków? Albo zrobić coś, gdy warunek nie zostanie sprawdzony? Operator sprawdza, czy dwa warunki są prawdziwe Operator logicznej koniunkcji ( ) zwraca prawdę wyłącznie wtedy, gdy oba łączone warunki są spełnione. if ((dealer_up_card == 6) (hand == 11)) double_down(); Aby funkcja została wywołana, muszą być spełnione oba warunki. Operator działa wydajnie — jeśli pierwszy warunek nie zostanie spełniony, komputer nie będzie sobie zaprzątał głowy przetwarzaniem drugiego. Doskonale bowiem wie, że jeśli pierwszy warunek nie został spełniony, to całe wyrażenie też nie będzie. Operator || sprawdza, czy jest spełniony jeden z dwóch warunków Operator logicznej alternatywy (||) zwraca prawdę, jeśli którykolwiek z warunków jest spełniony. if (cupcakes_in_fridge || chips_on_table) eat_food(); Którykolwiek z tych warunków powinien być spełniony. Jeśli pierwszy warunek będzie spełniony, komputer nie będzie sobie zawracał głowy sprawdzaniem drugiego. Doskonale bowiem wie, że jeśli pierwszy warunek został spełniony, to także całe wyrażenie musi być prawdziwe. Operator ! odwraca wartość warunku ! to logiczny operator przeczenia. Zmienia on wartość warunku na przeciwną. if (!brad_on_phone) answer_phone(); ! oznacza „nie” 18 Rozdział 1. Dla maniaków W języku C wartości logiczne są reprezentowane przy użyciu liczb. W C wartość 0 reprezentuje logiczny fałsz — nieprawdę. A jaka wartość reprezentuje logiczną prawdę? Logiczną prawdą jest każda wartość różna od zera. A zatem w języku C poniższy fragment kodu jest całkowicie poprawny: int people_moshing = 34; if (people_moshing) take_off_glasses(); W rzeczywistości w kodzie pisanym w języku
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

C. Rusz głową!
Autor:
,

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: