Intensivkurs C++ Formalien - Institut für Neuroinformatik
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
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