Physik auf dem Computer Johannes Roth Institut für Theoretische und Angewandte Physik, Universität Stuttgart Sommersemester 2011 Grundlagen von C++ Hauptprogramm Notwendige Elemente: #include <iostream> using std::cout; int main() { cout << "Hello World\n" ; return 0; } // Zeichenkette auf Bildschirm // ausdrucken Grundlagen von C++ Präprozessoranweisungen werden vor Programmübersetzung vorverarbeitet #ifndef HEADER_H #define HEADER_H // Deklarationen #endif Variable extern setzen: g++ -DHEADER_H myprog.cc Grundlagen von C++ 1. Sprachkonstrukte Kommentare: // Kommentar Daten: Variablen und Konstanten, Felder (Vereinbarungen mittels Deklarationen) Operatoren und Funktionen I/O-Sprachelemente (Ein-, Ausgabe) 2. Kommentare C++: Kommentare werden durch // eingeleitet. C: /* Kommentar */ Kommentare lassen sich nicht schachteln! Grundlagen von C++ Datentypen 3. Datentypen, Variablen, Konstanten Grundlegende Datentypen in C++: int, float, double, bool, char (i) Datentyp int: ganzzahlige (integer) Variablen Deklaration von Variablen: int i, j=5; Im weiteren Verlauf des Programms werden die Variablen über den in der Deklaration vereinbarten Variablennamen angesprochen. Interne Darstellung von int-Variablen im Speicher: Folge von {0, 1}-bits, 8bit = ˆ 1 byte (= ˆ 1 character) int i // 32-bit Variable (Zahlenbereich von −231 bis 231 − 1 = 2 147 483 647) Größere oder kleinere Zahlen führen zu overflow. Beispiel: i = 1 000 000 ∗ 1 000 000: overflow Grundlagen von C++ Datentypen Weitere Datentypen für ganzzahlige Variablen: short s; // 16-bit Variable long l; // 64-bit Variable Datentyp beeinflußt Speicherbedarf und Rechenzeit! (ii) Datentyp float und double: Typen für Gleitkommazahlen float f = 1./3.; // f=0.3333333 (einfache Genauigkeit) float f; // 32-bit Variable (ca. 7 Dezimalstellen + Exponent) double d; // 64-bit Variable (ca. 15 Dezimalstellen + Exponent) Empfehlung: Verwende double! Ein- und Ausgabe als Gleitkommazahlen oder in Exponentialdarstellung: Mantisse, Exponent 1.2345e+6 = 1.2345 × 106 Interne Zahlendarstellung: Compiler- und Maschinenabhängig! Datentypen int, float, double: wichtig zum Rechnen Grundlagen von C++ Datentypen (iii) Datentyp char: Variablen für einzelne Textzeichen char c=’x’; // ein Zeichen: x (1 byte ^= 8 bit) Aneinanderreihung von characters liefert string (Text). (iv) Datentyp bool: Boolsche Variable, kann nur den Wert true oder false annehmen. bool test; // Deklaration einer Boolschen Variable test = (0 < 5) // test hat den Wert true if test {Anweisung 1} else {Anweisung 2} // Anweisung 1 wird // ausgefuehrt (Logische Verknüpfungen: && (and), || (or), ! (not)) (Vergleichsoperatoren: ==, !=, <, <=, >, >=) Grundlagen von C++ Datentypen Bemerkungen zu den Datentypen: Deklarationen können an fast beliebiger Stelle im Programm stehen. Soll der Wert nach einer Initialisierung nicht mehr geändert werden, so empfiehlt sich die Deklaration von Konstanten. Beispiel: const double pi = 3.14159265; Die Variablen existieren innerhalb des Blocks {. . . } in welchem sie deklariert sind. sizeof(variable) liefert die aktuelle Größe der Variablen variable (in bytes). Grundlagen von C++ Datentypen Felder: Zusammenfassung mehrerer Variablen gleichen Typs in einem zusammenhängenden Speicherbereich. Beispiele: const int size = 20; int a[size]; // array von 20 int Variablen Zugriff auf einzelne Elemente erfolgt durch Indizes: a[0] = 3; a[1] = 5; a[19] = a[0] + a[1]; // a[19] = 8 Wichtig: Index läuft von 0 bis size−1 !!! double matrix [20] [30]; // // char text[] = "hello"; // // Deklaration einer Matrix mit 20*30=600 Elementen Text array mit 5 Zeichen (Achtung: sizeof(string) = 6) Grundlagen von C++ Datentypen Beispiel: Matrix-Vektor-Multiplikation ~v2 = M · ~v1 double matrix [20] [30]; double vector1[30]; double vector2[20]; ... Initialisierung von matrix und vector1 ... for (int i=0; i<20; i++){ double tmp = 0; for (int j=0; j<30; j++) tmp = tmp + matrix[i][j] * vector1[j]; vector2[i] = tmp; } Grundlagen von C++ Kontrollstrukturen 4. Kontrollstrukturen Bedingte und wiederholte Ausführung von Programmteilen: if, switch-Anweisung und do, while, for-Schleifen If-Anweisung: if (Boolscher Ausdruck/Variable) {Anweisungsblock 1} else if (...) // optional {Anweisungsblock 2} else // optional {Anweisungsblock 3}; Grundlagen von C++ Kontrollstrukturen Switch-Anweisung: switch( c) { // Anfang des case blocks case ’a’: cout << "hello world!"; break; case ’b’: cout << "HELLO "; // Weitergehen beabsichtigt, // break fehlt case ’c’: cout << "WORLD!"; break; default: cout << "unknown input"; break; // Nicht noetig, aber guter Stil } // Ende des case blocks Grundlagen von C++ Kontrollstrukturen While-Schleifen: while (Boolscher Ausdruck/Variable) {Anweisungsblock}; Do-Schleifen: do {Anweisungsblock} while (Boolscher Ausdruck/Variable); For-Schleifen: for (int i=0; i<20; i++) {Anweisungsblock}; // Zaehlschleife fuer i=0,...,19 Grundlagen von C++ Kontrollstrukturen Goto-Anweisung, Labels Vorzeitiges Verlassen tiefer verschachtelter Schleifen Beispiel: Durchsuchen einer Liste int a[20][30],i,j; for (i=0; i<20; i++) for (j=0; j<20; j++) if (a[i][j] == 42) goto element_gefunden; .. . element_gefunden: // label ... // Ausgabe von i,j ... Grundlagen von C++ Funktionen und Operatoren 5. Funktionen und Operatoren Sinn und Zweck von Funktionen: Einmaliges Schreiben von Programmteilen, die sich im Programm mehrfach wiederholen Bessere Strukturierung und Lesbarkeit von Programmen Beispiel: Berechnung von Potenzen y = xn = power(x, n) mit x reell, n ganze Zahl. Vereinbarung (Deklaration) der Funktion (vor dem Hauptprogramm): double power (double base, int exponent) Aufruf der Funktion im Programm: .. . y = power(x,n); .. . Grundlagen von C++ Funktionen und Operatoren Definition der Funktion in separatem Programmtext: double power (double base, int exponent); { double result; // weitere Deklarationen, Rechenoperationen return result // Datentyp double } Grundlagen von C++ Funktionen und Operatoren Viele Standardfunktionen brauchen nicht selbst geschrieben zu werden, sondern sind in Bibliotheken vorhanden. Beispiel: Benutzung von Funktionen aus der Mathematik-Bibliothek #include <cmath> double x, y; ... y = sqrt(x); Übersetzen des Programms und “Linken” der Programmbibliothek (“library”) libm.a: g++ programm.cc power.cc -lm Programmteile in anderen Dateien müssen angegeben werden! Grundlagen von C++ Funktionen und Operatoren Häufig einfacher zu lesen als Funktionen sind: Operatoren Beispiel: Statt z = plus(x,y) (Funktion mit 2 Argumenten) schreibt man einfacher z = x + y Arithmetische binäre Operatoren: + - * / % (Beachte: Division ist abhängig vom Datentyp!) Kurzschreibweisen durch Kombination mit Gleichheitszeichen: i i i i += -= *= /= j; j; j; j; // // // // i i i i = = = = i i i i + * / j; j; j; j; Grundlagen von C++ Funktionen und Operatoren Unäre Operatoren: x = feld[i++]; x = feld[++i]; // // // // x = feld[i]; i = i + 1; (postfix-Form) i = i + 1; x = feld[i]; (prefix-Form) Analog: i-- und --i Vergleichsoperatoren: == != > >= < <= // // // // // // gleich ungleich groesser groesser oder gleich kleiner kleiner oder gleich Grundlagen von C++ Funktionen und Operatoren Logische Operatoren (zwischen Boolschen Variablen oder Ausdrücken): && || ! // and // or // not Der Wert eines logischen Ausdrucks und das Resultat eines Vergleichsoperators sind vom Typ bool, also entweder true oder false. Beispiel: (1 < 2) && (2 < 3) k (3 < 4) && (5 < 5) | {z } | {z } | {z } | {z } true true true false | {z } | {z } true false | {z } true Grundlagen von C++ Funktionen und Operatoren Bindungsstärke (Priorität) von Operatoren: * + < == && || = / <= != % > >= *= /= %= += -= Grundlagen von C++ Funktionen und Operatoren Ternärer Operator: (Boolscher Ausdruck/Variable) ? (Ausdruck 1) : (Ausdruck 2) Beispiel: int i; cout << (i>0) ? i : 0; ist Alternative zu int i; if (i>0) cout << i else cout << 0; Grundlagen von C++ Funktionen und Operatoren Übergabe von Argumenten an eine Funktion: by value Vor dem Aufruf der Funktion erfolgt eine Kopie der Argumente (auf dem Stack). Die Funktion arbeitet mit den Kopien. (Ausnahme: Felder.) Dies eröffnet die Möglichkeit, Funktionen rekursiv aufzurufen. 1, n=0 Rekursive Funktionen, Beispiel Fakultät: n! ≡ n · (n − 1)!, n > 0 int fak(int n){ if (n==0) return 1; else return n*fak(n-1); } ist Alternative zu int fak(int n){ int result=1; for (int i=2; i<=n; i++) result *= i; return result; } Grundlagen von C++ Funktionen und Operatoren Beispiel quicksort: void quicksort(int left, int right){ int i; if (left < right){ i = partition(left,right); quicksort(left,i-1); quicksort(i+1,right) } } Parameterübergabe per Referenz (Adresse): Voranstellen von & vor den Variablennamen Beispiel: void swap(int &a, int &b){ int tmp = a; a = b; b = tmp } #include <iostream> #include <fstream> using namespace std; void quicksort(int l, int r, double x[]); int main(){ int n = 0; double x[1000]; ifstream ins("data", ios::in); while (ins >> x[n]) n++; quicksort(0,n-1,x); ofstream outs("sort", ios::out); for (int i=0; i<n; i++) outs << x[i] << ’\n’; return 0; } // Oeffnen der Eingabedatei // Lesen der Daten // Oeffnen der Ausgabedatei // Schreiben der Daten void quicksort(int l, int r, double x[]){ if (r > l){ int i = l; double xpivot = x[l]; for (int j=l+1; j<=r; j++) if (x[j] < xpivot){ x[i++] = x[j]; // Kurzform fuer: x[i] = x[j]; i = i+1; x[j] = x[i]; } x[i] = xpivot; quicksort(l, i-1, x); quicksort(i+1, r, x); } } Grundlagen von C++ Zeiger 6. Zeiger Zu jeder Variablen gehört eine Adresse im Speicher. Zeiger = Speicheradresse C++ bietet (fortgeschrittenen Programmierern) die Möglichkeit, diese Adressen der Speicherstellen für Programmierzwecke nutzbar zu machen. & vor Variable: liefert Adresse (“pointer”) einer Variable * vor pointer: “value of” Operator liefer den Wert der Variable Beispiel: int i = 5; int *p_i = &i; cout << *p_i; // // // // // Variable i hat den Wert i=5 p_i ist Zeiger (pointer) auf die Variable i liefert 5 (den Wert von i) als Ausgabe Grundlagen von C++ Ein- und Ausgabe 7. Ein- und Ausgabe (i/o) Kanaltypen: istream und ostream Dekalaration im header durch #include <iostream> Zugriff auf z.B. cin >> ... >> ...; cout << ... << ...; // Standardeingabe // Standardausgabe Die Auswertung erfolgt von links nach rechts. Alternative Schreibweise mit Funktionsaufrufen (put, get): char c1=’x’; cout << c1 << ’\n’; cout.put(c1); cout.put(’\n’); Entsprechend für die Eingabe mit cin.get. Grundlagen von C++ Ein- und Ausgabe Formatierung der Datenausgabe Ausgabe von Text gemäß ASCII-Tabelle (’\n’ = “newline”). Ausgabe von int, float, double erfordert Konversion, d.h. Umwandlung der internen (binären) Zahlendarstellung in Text. Die Konversion läßt sich durch Formatierungsanweisungen steuern, z.B. zur Rundung von Daten oder für die gleichmäßige Ausgabe von Tabellen. Beispiel: #include <iomanip> double x=1234.5; cout << setfill(’*’) << setw(10) << setprecision(5); cout << x << ’\n’; // Ausgabe: ****1234.5 setfill(’*’): Angabe eines Füllzeichens setw(10): Minimale Größe der direkt folgenden Ausgabe setprecision(5): Zahl der Stellen für Festkomma, bzw. Zahl der Stellen hinter dem Komma bei Gleitkommadarstellung Grundlagen von C++ Ein- und Ausgabe Dateien (Files) Beim Arbeiten mit Dateien gibt es viele Parallelen zur Standard Ein- und Ausgabe, aber einige spezifische Besonderheiten: Bekanntmachung bereits existierender Dateien im Programm (zum Lesen) Einrichten neuer Dateien über das Betriebssystem (zum Schreiben) Erkennen von z.B. Größe und Ende von Dateien beim Lesen Kanaltypen ifstream und ofstream. Beispiel: #include <fstream> int variable; ifstream ins("Eingabedatei", ios::in); // Oeffnen zum Lesen ins >> variable; // Einlesen von Daten aus der Eingabedatei ofstream outs("Ausgabedatei", ios::out); // Oeffnen zum Schreiben outs << variable; // Ausgabe von variable in die Ausgabedatei Grundlagen von C++ Ein- und Ausgabe Schließen der Dateien: ins.close(); outs.close(); Statusinformationen (beim Lesen): Typ bool ins.good(); ins.eof(); ins.bad(); ins.fail(); ins.clear(); // // // // // true, falls kein Fehler true bei "end of file" true bei hardware error true bei logical error setzt ins.good auf ’true’ Lesen einer Datei bis Dateiende (eof): int n; while (ins >> n){ ... } Grundlagen von C++ Verschiedenes Macros vs. inline Macros in C und C++ (keine Typprüfung!): #define SQR(a) ((a)*(a)) int b=2,c; c = SQR(b++); // c = ((a++) * (a++)); // c ist nun 2*3 = 6, b ist 4 nach 2(!)-maligem // Inkrement besser in C++: inline-Funktionen verwenden: inline int sqr (int a){ return a*a; } int b=2, c; c = sqr(b++); // b++ wird einmal ausgewertet, deshalb ist c // nun 4, b ist 3 Grundlagen von C++ Verschiedenes Definition neuer Datentypen typedef int Int32; // neuer Name für alte Typen typedef struct { int lower, upper } TwoInt; // komplexer // neuer Type TwoInt interval; // Variable definieren interval.lower=-1; interval.upper=2; // Teile initialisieren Grundlagen von C++ Verschiedenes Dynamischer Speicher Belegen int int int *p_i = new int; n = 40; *pa_i = new int[n]; Freigeben delete p_p; delete[] pa_i; // eine Variable // ein Feld Grundlagen von C++ Verschiedenes Namespaces enthalten Klassen von Befehlen, bspw. für Ein-/Ausgabe: #include <iostream> using namespace std; cout << " Gehalt: " << Personal.mGehalt; kollektiv statt einzeln: #include <iostream> using std::cout; using std::cin; cin >> Personal.mGehalt; cout << " Gehalt: " << Personal.mGehalt; Grundlagen von C++ Verschiedenes Makefile enthält Anweisungen zum Kompilieren Übersetzen der einzelnen Dateien Zusammenbau der .o-Dateien und Bibliotheken Verwendung: make oder make programm Grundlagen von C++ Verschiedenes Objektorientierte Programmierung Klassen: Unterprogramme mit Datenstrukturen Templates: selber Name für verschiedene Fälle, bspw. power(int(base),int(exponent)) und power(double(base),double(exponent)) Bibliotheken: enthalten fertige Programmpakete, benutzen mit #include <math> C++-Standardbibliothek enthält bspw. vector list set