Intensivkurs C++ Formalien - Institut für Neuroinformatik

 
WEITER LESEN
Intensivkurs C++ Formalien - Institut für Neuroinformatik
Rahmen Grundlagen Aufgaben

Formalien
  Intensivkurs C++
  Tag 1: Grundlagen
                   Der Kurs besteht aus 10 Einheiten von je (maximal) 8 Stunden.
  Sebastian      Houben
         Jeder Tag wird von einer Vorlesung eingeleitet, an die sich betreute
  InstitutProgrammier
            für Neuroinformatik
                     übungen anschließen. In beiden Wochen stehen die
  www.ini.rub.de/research/groups/rtcv/
      Freitage zur Wiederholung von Stoff zur Verfügung.
                   Die Aufgaben können in Gruppen von bis zu drei Studierenden
  18.02.2019
                   gelöst werden. Die Bearbeitung aller Aufgaben ist Voraussetzung für
                   die erfolgreiche Teilnahme. Es gibt eine Liste, in der jeden Tag die
                   erfolgreich bearbeiteten Aufgaben abgezeichnet werden.
                   Alle Aufgaben sollten um 16:30 fertig bearbeitet sein, da der Raum
                   pünktlich um 17:00 Uhr verlassen werden muss.
                   Die Aufgaben werden benotet. Die Gesamtnote ergibt sich aus dem
                   Durchschnitt der Tagesnoten.

Intensivkurs C++                                      18.02.2019 — Sebastian Houben        3
Rahmen Grundlagen Aufgaben

Formalien

                   Nicht vollständig bearbeitete Aufgaben können am Freitag derselben
                   Woche nachgereicht werden.
                   Es ist möglich, bis zu 3 Tage entschuldigt zu fehlen. Dies betrifft
                   sowohl Krankheit wie auch anderweitige Termine wie z.B. Klausuren.
                   Bitte melden Sie sich dazu entweder persönlich am Tag vorher beim
                   Dozenten oder per Mail über cplusplus@ini.rub.de ab. Die
                   Aufgaben können nachgereicht werden (siehe oben).
                   Es gibt eine Kurs-Homepage mit aktuellem Material auf
                   http://ini.rub.de/courses/teaching
                   /courses/intensive course c winter term 2018/

                                     Viel Spaß mit C++!

Intensivkurs C++                                     18.02.2019 — Sebastian Houben        4
Rahmen Grundlagen Aufgaben

Warum C++?

        Stärken:
                   C++ ist schnell!
                   C++ ist unglaublich flexibel.
                   C++ ist typsicher.
                   C++ ist gut organisiert; für sehr große Projekte geeignet.
                   C++ ist ein weit verbreiteter Industriestandard.
                   C++ ist extrem portabel.
        Schwächen:
                   C++ erscheint (dem Anfänger) oft unnötig komplex.
                   Relativ viel “boilerplate” code
                   Teilweise kryptische Syntax (bei fortgeschrittenen Konzepten, z.B.
                   Funktionszeiger)
                   Teils schwer lesbare Fehlermeldungen

Intensivkurs C++                                       18.02.2019 — Sebastian Houben    5
Rahmen Grundlagen Aufgaben

Ziel dieses Kurses

                   Einführung der Grundkonzepte der Programmiersprache C++
                   Es ist leicht, mit einer Darstellung von C++ ganze Regalwände zu
                   füllen. C++ ist sehr umfangreich. Deshalb kann dieser Kurs keinen
                   Anspruch auf Vollständigkeit haben.
                   Ganz wichtig: Hands on! Dies ist ein Praktikum, keine Vorlesung!
                   Learning by doing, sonst bleibt nur die Hälfte hängen.

Intensivkurs C++                                     18.02.2019 — Sebastian Houben      6
Rahmen Grundlagen Aufgaben

Voraussetzungen

                   Jeder Teilnehmer sollte Erfahrung mit einer halbwegs modernen
                   (imperativen) Programmiersprache haben: Java, Javascript, Python,
                   Lua, Pearl, PHP, C, Objective-C, C#, ...
                   Erfahrung mit einer objektorientierten Sprache (z.B. Java oder Python)
                   ist von Vorteil.

Intensivkurs C++                                     18.02.2019 — Sebastian Houben          7
Rahmen Grundlagen Aufgaben

Verwandschaft zu C, Java und anderen Sprachen

                   C++ ist (fast) eine Obermenge von C. Das heißt, dass fast aller
                   C-Code in C++ gültig ist. Allerdings bietet C++ wesentlich bessere
                   Möglichkeiten zur Strukturierung eines Programms und ermutigt
                   deshalb zu einem besseren Stil (modularer, gut wartbarer Code).
                   Java verfolgt ähnliche Ziele wie C++. Viele aus Java bekannte
                   Konzepte übertragen sich auf die Programmierung in C++, aber C++
                   bietet generell mehr Möglichkeiten, mehr Kontrolle, und als Preis
                   dafür leider oft weniger Komfort.
                   Viele moderne Sprachen orientieren sich an C++, insbesondere an
                   seiner Syntax. Wer eine andere Programmiersprache kennt, wird
                   deshalb vieles wiedererkennen, aber mit Sicherheit auch neue
                   Konzepte lernen, die er dann möglicherweise in anderen Sprachen
                   vermisst.

Intensivkurs C++                                     18.02.2019 — Sebastian Houben       8
Rahmen Grundlagen Aufgaben

Hello World

        Für die ganz Ungeduldigen - “Hello World” sieht in C++ so aus:

             helloworld.cpp

            #include 
            using namespace std;

            int main()
            {
                cout
Rahmen Grundlagen Aufgaben

Hello World

                   Starten Sie Visual Studio
                   Legen Sie ein neues Projekt an: Neues Projekt → Leeres Projekt;
                   Name=“HelloWorld”
                   Fügen Sie eine Datei hinzu: Projekt → Neues Element hinzufügen →
                   Code → C++-Datei; Name=”main.cpp”
                   (Menü Projekt Eigenschaften) → Konfigurationseigenschaften →
                   Linker → System; Setzen Sie “Subsystem” auf “Konsole”.
                   Tippen Sie das “Hallo-Welt”-Programm ein:
                     #include 
                     using namespace std;

                     int main()
                     {
                         cout
Rahmen Grundlagen Aufgaben

Dateistruktur, Compiler und Linker, Präprozessor
        Dateistruktur eines C++-Programms
                   Ein typisches C++-Programm ist über mehrere Dateien (oft mit
                   Endung .cpp) verteilt.
                   Jede Datei kann einzeln vom Compiler in eine sogenannte
                   Objektdatei übersetzt werden.
                   In einem letzten Schritt bündelt der Linker die Objektdateien zu einem
                   ausführbaren Programm.
        Beispiel: Ein Programm besteht aus den Dateien main.cpp, algo.cpp
        und tools.cpp. Daraus soll ein ausführbares Programm erstellt werden.
        Folgende Schritte sind notwendig:
            1      Der Compiler übersetzt main.cpp in main.obj.
            2      Der Compiler übersetzt algo.cpp in algo.obj.
            3      Der Compiler übersetzt tools.cpp in tools.obj.
            4      Der Linker setzt main.obj, algo.obj und tools.obj zum
                   ausführbaren Programm (beispiel.exe) zusammen.
Intensivkurs C++                                      18.02.2019 — Sebastian Houben          11
Rahmen Grundlagen Aufgaben

Dateistruktur, Compiler und Linker, Präprozessor

          Q: Wie können Programmteile (Funktionen, Klassen) in verschiedenen
             Dateien von einander wissen, so dass sie sich gegenseitig aufrufen
             können?
           A: Meist gibt es zu jeder .cpp-Datei eine Header-Datei (.h oder .hpp).
              Die Header-Datei enthält ausschließlich Deklarationen, während die
              .cpp-Datei die zugehörige Implementierung enthält. Einer
              .cpp-Datei wird Wissen über andere Programmteile durch Einbinden
              der entsprechenden Header-Dateien mitgeteilt.

Intensivkurs C++                               18.02.2019 — Sebastian Houben         12
Rahmen Grundlagen Aufgaben

Dateistruktur, Compiler und Linker, Präprozessor

          Q: Wo wird definiert, welche Dateien zusammengehören, um ein
             ausführbares Programm zu bilden?
           A: Das ist nicht Teil der Programmiersprache! Dies wird von jeder
              Programmierumgebung unterschiedlich gelöst. Visual Studio
              speichert diese Information in sogenannten Projektdateien (Solutions),
              die wiederum in Arbeitsbereiche organisiert sind. Jedes Projekt
              entspricht einer Bibliothek oder einem ausführbaren Programm. Ein
              Projekt definiert Quellen (.cpp) und Header (.h), sowie welche
              Bibliotheken verwendet werden sollen und wo diese zu finden sind.

Intensivkurs C++                                18.02.2019 — Sebastian Houben          13
Rahmen Grundlagen Aufgaben

Dateistruktur, Compiler und Linker, Präprozessor

             main.cpp

            #include "square.h"

            int main()
            {
                int s = square(7);
            }

             square.h

            #ifndef SQUARE_H
            #define SQUARE_H

            int square(int value);   // Deklaration

            #endif

             square.cpp

            int square(int value)           // Implementierung
            {
                return value * value;
            }

Intensivkurs C++                                                 18.02.2019 — Sebastian Houben   14
Rahmen Grundlagen Aufgaben

Dateistruktur, Compiler und Linker, Präprozessor

        Bibliotheken
                   Niemand sollte das Rad neu erfinden. Für viele Standardaufgaben gibt
                   es sehr gute Bibliotheken (z. B. die boost-Bibliotheken, Qt, usw.).
                   Eine Bibliothek besteht aus zwei Teilen:
                       Die eigentliche Bibliothek (Windows: .lib oder .dll; Linux: .a oder .so;
                       Mac: .a oder .dylib) enthält die Implementierung, also das, was den
                       .cpp-Dateien entspricht).
                       Die Deklarationen zu einer Bibliothek stehen in den entsprechenden
                       Header-Dateien. Diese gehören fest zur Bibliothek.

Intensivkurs C++                                          18.02.2019 — Sebastian Houben           15
Rahmen Grundlagen Aufgaben

Dateistruktur, Compiler und Linker, Präprozessor

        Beispiel: Unser Programm (main.cpp, algo.cpp, tools.cpp)
        verwendet die Bibliothek matrix, bestehend aus matrix.lib und
        matrix.h. Nehmen wir an, dass die Routinen aus matrix nur innerhalb
        von algo.cpp verwendet werden.
            1      Der Compiler übersetzt algo.cpp in algo.obj. Er liest die
                   Definitionen aus matrix.h ein, wobei ihm völlig egal ist, ob sich die
                   Implementierungen zu den Definitionen in einer anderen .cpp-Datei
                   oder in einer Bibliothek befinden.
            2      Der Linker setzt main.obj, algo.obj, tools.obj und
                   matrix.lib zum ausführbaren Programm (beispiel.exe)
                   zusammen.

Intensivkurs C++                                      18.02.2019 — Sebastian Houben         16
Rahmen Grundlagen Aufgaben

Dateistruktur, Compiler und Linker, Präprozessor
        Präprozessor-Macros
                   Alle Präprozessor-Macros beginnen mit dem Symbol #.
                   #include "dateiname" wird durch den Inhalt der Datei ersetzt.
                   Die Datei wird zuerst im aktuellen Projekt gesucht. So werden Dateien
                   aus dem eigenen Projekt eingebunden.
                   #include  wird durch den Inhalt der Datei ersetzt.
                   Die Datei wird im Include-Suchpfad gesucht. Diese Syntax wird für
                   Header aus Bibliotheken verwendet.
                   #define NAME oder #define NAME Wert, z.B. #define
                   WIDTH 80. Definition einer Konstanten.
                   #ifdef, #ifndef, #else und #endif werden zur bedingten
                   Kompilierung verwendet. Beispiel:
                     #ifdef DEBUG
                         cout
Rahmen Grundlagen Aufgaben

Dateistruktur, Compiler und Linker, Präprozessor

                   Oft binden Header-Dateien weitere Header ein.
                   Dies geschieht rekursiv, so dass ein einziges #include Statement
                   eine große Menge an Headern einbinden kann.
                   Deshalb ist oft unklar, ob ein Header bereits (implizit) eingebunden
                   wurde oder nicht.
                   Damit jeder Header nur maximal einmal in eine .cpp-Datei
                   eingebunden wird, verwendet man sogenannte Include-Guards:
                     #ifndef MEIN_HEADER_H
                     #define MEIN_HEADER_H
                     ...Inhalt...
                     #endif

                   Dabei ist MEIN HEADER H irgendein eindeutiger String, meist einfach
                   der Dateiname.

Intensivkurs C++                                      18.02.2019 — Sebastian Houben       18
Rahmen Grundlagen Aufgaben

Kommentare

        Zeilen-Kommentar:
            // Diese ganze Zeile ist ein Kommentar.
            int magic = 42;   // siehe "Per Anhalter durch die Galaxis" ...

        Block-Kommentar:
            int magic = /*42*/ 1001;
            /* Als magische Zahl ist 1001 viel schoener als 42.
                Das liegt an ihrer Primfaktorzerlegung:
                7 * 11 * 13 = 1001.                             */

Intensivkurs C++                                              18.02.2019 — Sebastian Houben   19
Rahmen Grundlagen Aufgaben

Variablen und Funktionen

        Variablen: Typ Name;
            int a;
            int b = 7;
            int c, d = 3, e = f(b);

        Funktionen: Typ Name(Parameterliste)
            int f(int x);                  // Deklaration von f

            int f(int x)                   // Implementierung von f
            {
                return x * (1 - x);
            }

            int foo(int a, int b, float c, bool flag = true);

        Funktionsaufrufe
            int ergebnis = foo(f(7), d, 3.14159);

            foo(-42, 3, 3.14159, true);

Intensivkurs C++                                                18.02.2019 — Sebastian Houben   20
Rahmen Grundlagen Aufgaben

Vorwärtsdeklaration
        Beispiel: Rekursion über zwei Funktionen.
            void foo()
            {
                if (...) bar();
            }

            void bar()
            {
                if (...) foo();
            }

        Problem: Der Compiler arbeitet von vorn nach hinten und weiß deshalb
        nicht, was nach der aktuellen Stelle im Programm noch kommt. Innerhalb
        der Funktion foo ist bar noch nicht deklariert, wird aber aufgerufen.
        Fehler! Da hilft: die Vorwärtsdeklaration
            void bar();           // Vorwaertsdeklaration von bar

            void foo()
            {
                if (...) bar();
            }

            void bar()
            {
                if (...) foo();
            }

Intensivkurs C++                                        18.02.2019 — Sebastian Houben   21
Rahmen Grundlagen Aufgaben

Datentypen

        void: “kein Wert”, tritt oft als Rückgabetyp von Funktionen auf

        Logik: bool, mit Werten true, false, belegt 1 Byte

        Ganzzahl: char (8 Bit), int (meist 32 Bit).
        Konstanten: 42, -5, ’a’, ’\n’, ’\\’, ’\’’
        Modifikatoren: unsigned, short, long, long long
        → unsigned long long int (= unsigned long long)

        Fließkomma: float (meist 32 Bit IEEE), double (meist 64 Bit IEEE)
        Konstanten: -1.0, 3.14159, .01, +5.77e-18

        C-Strings: char s[256] = "Hallo, Welt"; (char-Array)
        C++-Strings: string s = "Hallo, Welt"; (String-Objekt)

Intensivkurs C++                                18.02.2019 — Sebastian Houben   22
Rahmen Grundlagen Aufgaben

Datentypen

        Zeiger: int*         Zeiger = Speicheradresse
        Referenz: int&        Referenz = anderer Name für eine Variable

        void*: Zeiger auf untypisierten Speicher
        Konstante nullptr: ungültiger Zeiger

        Aufzählungen: enum FileFormat { wav, mp3, ogg };

Intensivkurs C++                                18.02.2019 — Sebastian Houben   23
Rahmen Grundlagen Aufgaben

Datentypen

        Zusammengesetzte Typen: class, struct, union

        C-Arrays: int a[20], bool b[64][64]
        STL-Container: vector, list, deque, set, multiset, map,
        multimap

        Alias-Namen für Typen: typedef Typ Name;

        Genauer: typedef [Variablendefinition mit neuem Namen
        als Variablennamen];

        Es gibt viele weitere Typen, z.B. Funktionszeiger, STL-Iteratoren,
        Templates, ...

Intensivkurs C++                                18.02.2019 — Sebastian Houben   24
Rahmen Grundlagen Aufgaben

Operatoren
                        ::
                        () [] . -> ++ -- dynamic cast static cast
                        reinterpret cast const cast typeid
                        ++ -- ∼ ! sizeof new delete
                        * & + - (unary)
                        (type)
                        .* ->*
                        * / %
                        + - (binary)
                        >
                        < > =
                        == !=
                        &
                        ˆ
                        |
                        &&
                        ||
                        a ? b : c
                        = *= /= %= += -= >>=
Rahmen Grundlagen Aufgaben

Kontrollstrukturen

             Block

            {
                   Kommando1;
                   Kommando2;
                   ...
            }

             Bedingte Ausführung 1

            if (Bedingung) Kommando1; [else Kommando2];

             Bedingte Ausführung 2

            switch (Ausdruck)
            {
            case Konstante1:
                Kommandos1;
                break;
            case Konstante2:
                Kommandos2;
                break;
            ...
            default:
                KommandosN;
            }

Intensivkurs C++                                          18.02.2019 — Sebastian Houben   26
Rahmen Grundlagen Aufgaben

Kontrollstrukturen

             For-Schleife

            for (Kommando1; Bedingung; Kommando2) Kommando3;

             For-Schleife (range-based)

            for (Typ Variable : Container/Range) Kommando;

             While-Schleife

            while (Bedingung) Kommando;

             Do-While-Schleife

            do Kommando; while (Bedingung);

        Die Schlüsselwörter break und continue sind in allen Schleifen
        verfügbar.
        goto existiert (considered harmful, of course).
Intensivkurs C++                                               18.02.2019 — Sebastian Houben   27
Rahmen Grundlagen Aufgaben

Programm-Parameter
        Ein Konsolenprogramm kann mit Parametern aufgerufen werden:
        beispiel.exe -f 17 message=Hallo

        Diese Parameter stehen der main-Funktion zur Verfügung:
            int main(int argc, char** argv)
            {
                ...
                return 0;
            }

                   argc: argument count - Anzahl der Parameter (+ 1)
                   argv: argument values oder argument vector
                   Der Typ von argv ist char**: Ein Zeiger auf einen Zeiger von
                   Zeichen (Characters).
                   Für heute reicht es aus zu wissen, dass argv[1] das erste
                   Argument des Programms ist.
                   Es ist gültig, falls argc > 1 erfüllt ist.

Intensivkurs C++                                          18.02.2019 — Sebastian Houben   28
Rahmen Grundlagen Aufgaben

Konsolen-Ausgabe

                   Das Objekt cout im Namensraum std ist ein sogenannter Stream
                   (Datenstrom).
                   Jedes Konsolenprogramm hat drei Standard-Streams:
                   (Tastatur-)Eingabe (cin), Ausgabe (cout), und Fehler (cerr). Wir
                   benutzen hier nur cout.
                   Beispiel:
                      #include 
                      using namespace std;
                      cout
Rahmen Grundlagen Aufgaben

Typumwandlung

        Beispiele statischer Typumwandlung:
            int a = 3;
            double b = a;            // impliziter cast int -> double
            double c = 2.7;
            int d = c;               //   impliziter cast double -> int: Warnung oder Fehler!
            int e = (int)c;          //   expliziter cast (okay), setzt e = 2.
            int f = int(c);          //   expliziter cast, neue Syntax.
            int g = int(round(c));   //   setzt g = 3.
            bool b1 = 17;            //   0 -> false, Rest -> true
            bool b2 = nullptr;       //   nullptr -> false, alle anderen Zeiger -> true

                   Typecasts elementarer Typen sind meist unkritisch
                   Das Thema wird im Zusammenhang mit Klassen und Vererbung
                   komplizierter.
                   In altem C-Code werden oft Zeiger in Integers und zurück
                   umgewandelt. Das ist sehr gefährlich, denn Zeiger auf 64bit-Systemen
                   passen nicht in einen int!

Intensivkurs C++                                               18.02.2019 — Sebastian Houben    30
Rahmen Grundlagen Aufgaben

Typumwandlung

        Zahlen in Strings wandeln und zurück

        Umwandlung auf C-Art
            int wert = 42;
            char str[50];
            sprintf(str, "%d", wert);               // str = "42";
            int wert2 = strtol(str, nullptr, 10);   // wert2 = 42;

        Umwandlung auf C++-Art
            int wert = 42;
            stringstream ss;
            ss > wert2;            // wert2 = 42;

Intensivkurs C++                                               18.02.2019 — Sebastian Houben   31
Rahmen Grundlagen Aufgaben

Debugging!

        HowTo Debug...

Intensivkurs C++             18.02.2019 — Sebastian Houben   32
Rahmen Grundlagen Aufgaben

Hilfe, Referenz, Dokumentation

        gutes Tutorial:
        http://www.cplusplus.com/doc/tutorial/

        Referenz-Dokumentation:
        http://www.cplusplus.com/doc/
        http://www.cplusplus.com/reference/

        Linux/Mac:
        man-pages!

        Windows:
        MSDN

        Weitere Quellen:
        Programmierfragen, Fehlermeldungen: Google, Stack Overflow.
        Algorithmen: Wikipedia.

Intensivkurs C++                            18.02.2019 — Sebastian Houben   33
Rahmen Grundlagen Aufgaben

Anwesenheitsaufgabe (10 Punkte)

        Schreiben Sie ein Programm mit Namen inkrement, das eine ganze
        Zahl als Argument erwartet, eins addiert, und das Ergebnis ausgibt. Falls
        kein Argument übergeben wurde soll das Programm eine Fehlermeldung
        ausgeben.

        Beispiel:
            $ inkrement 1234
            1234 + 1 = 1235

            $ inkrement -1234
            -1234 + 1 = -1233

            $ inkrement
            Fehler: Es wurde keine Zahl uebergeben.

Intensivkurs C++                               18.02.2019 — Sebastian Houben        34
Rahmen Grundlagen Aufgaben

Anwesenheitsaufgabe (40 Punkte)

        Schreiben Sie ein Programm mit Namen primzahltest, das als
        Argument eine positive ganze Zahl erwartet. Prüfen Sie, ob ein Argument
        vorhanden ist und ob die übergebene Zahl positiv ist. Das Programm
        bestimmt, ob diese Zahl prim ist oder nicht. Verwenden Sie den folgenden
        (ineffizienten aber korrekten) Algorithmus (hier als Pseudo-Code):
            bool ist_prim(unsigned int n)
            {
              if (n == 1) return false;
              schleife: fuer jedes i >= 2, i*i
Rahmen Grundlagen Aufgaben

Anwesenheitsaufgabe (30 Punkte)

        Schreiben Sie ein Programm, dass die Primfaktorzerlegung einer Zahl
        ausgibt. Beispiel:
            $ primfaktorzerlegung 24
            24 = 2 * 2 * 2 * 3
            $ primfaktorzerlegung 1
            1 = 1

Intensivkurs C++                             18.02.2019 — Sebastian Houben    36
Rahmen Grundlagen Aufgaben

Anwesenheitsaufgabe (20 Punkte)

        Modifizieren Sie das Programm so, dass gleiche Primfaktoren zu Potenzen
        gruppiert werden. Beispiel:
            $ primfaktorzerlegung 24
            24 = 2 ˆ 3 * 3

Intensivkurs C++                             18.02.2019 — Sebastian Houben        37
Sie können auch lesen