Podstawy programowania 1

Dlaczego C++, a nie język X

Język C++ powstał w latach 80-tych ubiegłego wieku jako obiektowe rozszerzenie języka C i jest starszy niż większość popularnych języków programowania (Java, C#, Python, Ruby, Perl). Nie znaczy to, że język się nie zmienia – nowe elementy są cały czas dodawane, w szczególności standard C++11 (przedtem znany jako C++0x) jest cały czas w trakcie wprowadzania, a tworzony jest nowy standard o roboczej nazwie C++1y.

Przeznaczeniem C++ jest pisanie systemów operacyjnych i dużych aplikacji (niekompletna lista tutaj), więc wyróżniają go wysoka wydajność i duża wszechstronność. Często znajduje też zastosowanie w przypadku poważnych obliczeń na superkomputerach.

Niestety, język C++ nie należy do najprostszych do opanowania, jednak jego znajomość pozwala lepiej rozumieć działanie komputera. Poza tym elementy składni C++ są obecne w innych językach (C#, Java), co znaczy, że nauka C++ nie jest stratą czasu nawet dla wielbicieli innych języków.

Narzędzia

Aby napisać nasz pierwszy program potrzebujemy trzech rzeczy:

Edytor tekstu

Wybór edytora tekstu nie jest najprostszy, a na forach łatwo znaleźć kłótnie miłośników różnych edytorów. Zasadniczo, potrzebujemy programu, który pozwala tworzyć proste pliki testowe bez formatowania (więc MS Word odpada). Najprostszym jest oczywiście Notatnik, choć jego używanie do programowania na dłuższą (a nawet krótszą) metę doprowadza do przeklinania i rwania włosów z głowy. Absolutne minimum, którego należy wymagać to kolorowanie składni pisanego programu, które powoduje, że zamiast:

#include <iostream>

using namespace std;

int main() {
   cout << "Hello World" << endl;
   return 0;
}

zobaczymy

#include <iostream>

using namespace std;

int main() {
   cout << "Hello World" << endl;
   return 0;
}

Pozwala to szybciej znajdować błędy i poruszać się w pisanym (lub czytanym) programie. Potrzebujemy więc edytora tekstu dla programistów. Najważniejsze to:

  • Notepad++ (Windows);
  • PSPAd (Windows);
  • ConTEXT (Windows);
  • vim (Linux, Windows);
  • emacs (Linux, Windows);
  • Kate (Linux (Qt), Windows);
  • Geany (Linux (GTK), Windows).

Zwykły edytor tekstu (w szczególności jeżeli pozwala na szybką kompilację kodu) jest wystarczający do pisania małych programów, jednak często znacznie wygodniejsze są jeszcze bardziej rozbudowane systemy, tzw. zintegrowane środowiska programistyczne (ang. IDE – Integrated Develepment Environment). IDE poza rozbudowanym edytorem oferują często wychwytywanie błędów już na etapie pisania programu, szybką kompilację i uruchamianie programu, wygodne debugowanie, podpowiedzi przy pisaniu kodu i wyszukiwanie obiektów w plikach źródłowych. Ponieważ są to spore wymagania, dobrych IDE jest znacznie mniej niż dobrych edytorów. Do C++ warto wymienić:

  • Dev-C++ – nieduże możliwości, chociaż z tego powodu bywa używany przez początkujących, do tego tylko pod Windows, na dłuższą metę stanie się obciążeniem, nie polecam;
  • Eclipse – napisane w Javie wszechstronne IDE, w szczególności można także pisać w C++; niezłe, choć pożera sporo zasobów; bardzo popularne, do tego obsługa wielu języków/platform/technologii powoduje, że umiejętność pracy w Eclipse można wykorzystywać w wielu miejscach;
  • NetBeans – j.w.;
  • Visual Studio – produkt Microsoftu, jedyny płatny na tej liście. Jako jedyne IDE na tej liście zawiera też dedykowany kompilator, dzięki temu, przynajmniej początkowo, jest najwygodniejsze do używania. Uwaga: darmowa wersja Express dla hobbystów nie zawiera kilku bardziej zaawansowanych funkcjonalności, pełne Visual Studio można pobrać w ramach programu Dream Spark;
  • Qt Creator – wieloplatformowe, nie za duże IDE przeznaczone do pisania programów używających bibliotek Qt, nadaje się jednak także do pisania programów w C++ nie korzystających z Qt, polecam;
  • KDevelop – bardzo dobre IDE dla systemu Linux (KDE), również polecam.

Pozostaje problem obecności i działania powyższych IDE na komputerach uczelnianych. Do pracy w domu dla posiadających szybsze komputery (głównie dużo RAM-u) polecam Eclipse, dla tych z nieco mniejszą ilością pamięci – QtCreator. Na uczelnianych komputerach, zarówno pod Windows jak i pod Linuksem dobrze sprawuje się Eclipse (dla dzialającego debuggera trzeba wybierać narzędzia MinGW).

Kompilator

Wybór kompilatorów dla nas ogranicza się głównie do:

  • GCC-C++ – otwartoźródłowy kompilator C++ z projektu GNU Compiler Collection. Domyślny kompilator na wielu platformach (Linux, różne Uniksy). Kompilatory GCC wspierają także kompilowanie kodu na wiele mniej lub bardziej egzotycznych docelowych architektur mikroprocesorów i mikrokontrolerów (x86, ARM, AVR, PowerPC, SPARC). Większość IDE (poza Visual Studio) pozwala na używanie GCC, często jest to wręcz domyślne rozwiązanie. Nie zawsze jest dołączany do IDE, czasem trzeba zainstalować oddzielnie. W systemach Linux wywoływany poleceniem g++. Pod Windows dostępny w ramach projektu MinGW. Dynamicznie rozwijany, z reguły warto używać najnowszej wersji stabilnej (nowe funkcjonalności, często szybsze programy).
  • MS Visual C++ – zintegrowany z Visual Studio. Nowsze wersje z reguły tylko z nowszym Visual Studio (a więc rzadko).
  • Clang – nowy, obiecujący kompilator projektu LLVM. Dynamicznie rozwijany i uważany za stabilny. Jest podstawą najnowszych rozwiązań dla programistów firmy Apple.
  • ICC – komercyjny kompilator firmy Intel, wspierający najnowsze rozwiązania w procesorach Intela. Czasem oskarżany o generowanie kodu nie wykorzystującego optymalnie możliwości procesorów innych producentów. Do celów niekomercyjnych dostępna wersja pod systemy Linux.

Konsolidator

Na tym przedmiocie używać będziemy jedynie konsolidatora domyślnie dostarczanego wraz z kompilatorem.

Pierwszy program w języku C++

Zadanie 1. Skompilować i uruchomić następujący program w języku C++:

#include <iostream>

using namespace std;

int main() {
   cout << "Hello World" << endl;
   return 0;
}

Błędy kompilacji

Zadanie 2. Spróbować skompilować następujący program, znaleźć błąd kompilacji i poprawić go:

#include <iostream>
using namespace std;

// Funkcja main może mieć (z większością kompilatorów)
// jeden z trzech możliwych prototypów:
// int main();
// int main(int, char**);
// int main(int, char**, char**);
void main(int argc, char** argv) {
    cout << argc << endl;
    cout << argv[0] << endl;
    return 0;
}

Błędy konsolidacji

Zadanie 3. Spróbować skompilować następujący program, spróbować poprawić błąd konsolidacji przez znalezienie odpowiedniej funkcji w bibliotece standardowej:

#include <iostream>

double sin(double); //deklaracja funkcji bez definicji
                    //Prawdziwa funkcja sinus
                    //jest zadeklarowana jest
                    //w pliku nagłówkowym cmath

int main() {
   std::cout << sin(1) << std::endl;
   return 0;
}

Czasem znalezienie źródła błędów kompilacji czy konsolidacji może być bardzo trudne (zwłaszcza tych drugich). Z reguły jednak błędy kompilacji oznaczają błędny kod, błędy konsolidacji zaś – złe ustawienia kompilatora (brak dołączenia używanych bibliotek itp.).

Błędy wykonania

Zadanie 4. Skompilować i uruchomić następujący program:

#include <iostream>

int main() {
   std::cout << 1/0 << std::endl;
   return 0;
}

Dobry kompilator zgłosi przy kompilacji powyższego programu ostrzeżenie – mimo, że jest to poprawny program w C++, to zawiera (potencjalnie) błąd logiczny, o czym informuje kompilator. Ostrzeżeń nie należy ignorować, lecz modyfikować kod, aby kompilator ich nie zgłaszał (często potrzebne będą jawne rzutowania typów itp.).

Do znajdowania błędów czasu wykonania i błędów logicznych najlepiej używać debuggera.

Wejście i wyjście

Do obsługi wejścia/wyjścia mamy do dyspozycji dwa mechanizmy. Jeden z nich sięga jeszcze języka C – to rodziny funkcji bibliotecznych printf i scanf. Funkcje z tej biblioteki dostępne są po dołączeniu nagłówka cstdio.

Obsługę wejścia/wyjścia w C++ zaimplementowano od nowa w bibliotece strumieni. Na początek do obsługi standardowych wejścia i wyjścia służą obiekty std::cin i std::cout. Implementacja tych obiektów używa silnie szablonów i dlatego może być na pierwszy rzut oka dużo trudniejsza i mniej wygodna w użyciu niż biblioteka funkcji C. Jednak jest to rozwiązanie bardziej elastyczne, nowocześniejsze, szybsze i bezpieczniejsze pod względem typów. Używamy ich następująco:

#include <iostream>

using namespace std;

int main() {
  int a;
  cout << "Podaj jakąś liczbę: ";
  cin >> a;
  cout << "Podwojenie twojej liczby to: " << 2*a << endl;
  return 0;
}

Sprawdzarka

Zadanie 5. Zalogować się na sprawdzarkę i rozwiązać zadanie Suma.

W domu

Zadanie 6. Korzystając z dokumentacji do używanego narzędzia nauczyć się obsługi debuggera, w szczególności: jak ustawić pułapkę (ang. breakpoint), pułapkę warunkową (ang. conditional breakpoint), jak obserwować zawartość zmiennej (ang. watch), jak wykonywać program linijka po linijce (ang. step over, step in, step out).