Prof. Dr.-Ing. Alfred Busse Hochschulübergreifender Studiengang Wirtschaftsingenieurwesen (HWI) HAW Hamburg C++-Programmieranleitung mit Musteraufgaben Studiengang: Wirtschaftsingenieurwesen (3. Sem.) Umfang: 1 SWS (1 Ü) Stand: SS 02 Letzte Änderung: 05.07.2002 Copyright: Busse (dr.b.) nur für persönliche Studienzwecke im HWI keine Lagerung auf fremden Servern Inhaltsverzeichnis 1 Einführung in die Programmierung ................................................................ 4 2 Programmentwicklung in C++ ......................................................................... 6 3 Vorhandene Bedienoberfläche.......................................................................... 7 3.1 Hard- und Software-Umgebung ................................................................................... 7 3.2 Erste Hilfe ................................................................................................................... 7 4 Elementare C++-Programmierung .................................................................. 8 4.1 Der C++-Programmaufbau .......................................................................................... 8 4.1.1 Grundaufbau.................................................................................................... 8 4.1.2 Kommentare .................................................................................................... 8 4.1.3 Zuweisungsoperator......................................................................................... 9 4.2 Zahlenformate, Operatoren und mathem. Funktionen................................................. 10 4.2.1 Bestimmung der Speichergröße ..................................................................... 10 4.2.2 Wertebereich für den Typ int ......................................................................... 10 4.2.3 Wertebereich für den Typ short int................................................................. 11 4.2.4 Wertebereich für den Typ unsigned short int.................................................. 11 4.2.5 Übersicht der Wertebereiche.......................................................................... 12 4.2.6 Bit-Operatoren............................................................................................... 12 4.2.7 Logische Operatoren...................................................................................... 13 4.2.8 Relationale Operatoren .................................................................................. 14 4.2.9 Einige mathematische Funktionen ................................................................. 15 4.3 Ein- und Ausgabe ...................................................................................................... 16 4.3.1 Elementare Ein-/Ausgabe .............................................................................. 16 4.3.2 Stream-Technik ............................................................................................. 16 4.3.3 Einfache Manipulatoren................................................................................. 18 4.3.4 Escape-Sequenzen ......................................................................................... 19 4.3.5 Eingabe ......................................................................................................... 19 4.4 Einfache Rechenoperationen...................................................................................... 21 4.4.1 Addition, Multiplikation, Division, Modulo-Operator .................................... 21 4.4.2 Division mit Gleitkommazahlen .................................................................... 22 4.4.3 Inkrement-Operator ....................................................................................... 23 4.5 Schleifen und Bedingungen ....................................................................................... 24 4.5.1 Struktogrammelemente für C++..................................................................... 24 4.5.2 While-Schleife............................................................................................... 26 4.5.3 Do...while-Schleife ........................................................................................ 27 4.5.4 Switch-Anweisung......................................................................................... 28 4.5.5 Musteraufgabe „Fahrenheit“ .......................................................................... 30 4.5.6 For-Scheife .................................................................................................... 32 4.5.7 If-Anweisung................................................................................................. 34 4.5.8 Boolsche Variablen........................................................................................ 35 3D26E882-2673-8602.doc/05.07.02/dr.b. 2 4.5.9 Zeichen- und Zeichenketten........................................................................... 36 4.5.10 Einlesen von Tastaturzeichen....................................................................... 37 4.5.11 Kleine Musteraufgabe „Pole Position“ ......................................................... 38 4.5.12 Goto-Anweisung.......................................................................................... 39 4.5.13 Chaotische Programmierung ........................................................................ 40 4.5.14 Switch-Anweisung....................................................................................... 41 4.5.15 Musteraufgabe „PIN“ .................................................................................. 42 4.6 Unterprogramme........................................................................................................ 43 4.7 Datenfelder (Arrays) .................................................................................................. 44 4.7.1 Eindimensionale Arrays................................................................................. 44 4.7.2 Mehrdimensionale Arrays.............................................................................. 45 4.7.3 Musteraufgabe „Schachbrett“ ........................................................................ 46 5 Objektorientierte Programmierung ............................................................... 48 5.1 Methodischer Ansatz ................................................................................................. 48 5.1.1 Typen ............................................................................................................ 48 5.1.2 Klassen und Elemente.................................................................................... 48 5.1.3 Klassen deklarieren........................................................................................ 48 5.1.4 Objekte definieren ......................................................................................... 49 5.1.5 Auf Klassenelemente zugreifen...................................................................... 49 5.1.6 Definition einer Elementfunktion................................................................... 49 5.2 Musteraufgabe „Katzendatei“ .................................................................................... 50 6 Assembler-Programmierung .......................................................................... 52 7 Mathematische Methoden............................................................................... 53 7.1 Musteraufgabe „Sortieren“ ........................................................................................ 53 8 Weitere Beispielaufgaben................................................................................ 54 8.1 Musteraufgabe „Bruchkürzen“................................................................................... 54 8.2 Musteraufgabe „Geldautomat“................................................................................... 56 3D26E882-2673-8602.doc/05.07.02/dr.b. 3 1 Einführung in die Programmierung Programmieren ist Teil des Software-Engineering und dient der Kommunikation • • • Mensch Maschine Mensch => => => Maschine Mensch Maschine => Mensch Übliche Ansprüche sind • Benutzerakzeptanz • Ausbaufähigkeit Software entwickeln = Programm schreiben Die Standard-Entwicklungsphasen sind • Problemanalsyse + Anforderungsdefinition => Lastenheft / Pflichtenheft (Was ist zu entwickeln?) • Entwurf (wie ist es zu entwickeln?) • Implementierung (Umsetzung in eine bestimmte Sprache) • Testen (werden die Anforderungen erfüllt?) • Installation (beim Kunden) • Nutzen (Wartung + Pflege) 3D26E882-2673-8602.doc/05.07.02/dr.b. 4 Zeitwaufwand / Kosten 40 – 20 – 40 - Regel Test + Installation Implemetierung Analyse + Entwurf Das eigentliche „Programmschreiben“ nimmt nur ca. 20 % des gesamten Arbeitsumfangs einer Software-Lösung ein! 3D26E882-2673-8602.doc/05.07.02/dr.b. 5 2 Programmentwicklung in C++ Problemstellung Programmentwurf Editor Quelltext Fehlerkorrektur header-files Präprozessor weitere Quelltextmodule „interner Quelltext“ Compiler Objektmodul weitere Objektmodule Linker Lader Programmtest lauffähiges Programm 3D26E882-2673-8602.doc/05.07.02/dr.b. 6 3 Vorhandene Bedienoberfläche 3.1 Hard- und Software-Umgebung WindowsNT Workstations im FH-Bergedorfer Intranet. Entwicklungsplattform: Borland C++ V5.0 IDE = = 3.2 integrated develpment environement integrierte Enwicklungsumgebung Erste Hilfe /* 0. Zum Einloggen nach 16 Uhr ist ab sofort eine eigene Nutzerkennung erforderlich. Diese kann über die Homepage des Bergedorfer RZ beantragt werden. 1. Neue Quelldateien auf N: => in Ihr heutiges Arbeitsverzeichnis laden 2. Dateinamen auf 8.3-Format ändern!!! 3. Für jede Arbeitssitzung ein Verzeichnis auf C: anlegen z.B. alfred oder hilde, heinz wichtig: nicht länger als 8 Zeichen! Reihenfoge a Quelltext schreiben und speichern b Projekt anlegen: Datei => neu => Projekt zu empfehlen: Projektname = Dateiname z.B 21dwhile.ide aus 21dwhile.cpp dann: easywin => return 4. Bei Fehlschlag: * Einzelne Fenster schließen * Borland schließen * alle beim Compilieren entstandenen Datein löschen außer Quelldateien (Explorer: C++ Source File)!!! * ggf. Quelldatei umbenennen 5. Nach Abschluß bitte Ihre Arbeit von Festplatte löschen. 3D26E882-2673-8602.doc/05.07.02/dr.b. 7 4 Elementare C++-Programmierung 4.1 Der C++-Programmaufbau 4.1.1 Grundaufbau Der Rumpf eines typischen C++_Programms // Beschreibung #include <iostream.h> int main() { // hier steht der eigentliche Programmkern return(0); } Das erste C++-Programm // Hello-World #include <iostream.h> int main() { cout << "Hello World!\n"; return (0); } 4.1.2 Kommentare // Programm Kommentar #include <iostream.h> int main() { /* Das ist ein Kommentar, der bis zum schließenden Kommentarzeichen aus Sternchen und Schrägstrich geht */ cout << "Hello World!\n"; // Dieser Kommentar geht nur bis zum Zeilenende cout << "Dieser Kommentar ist beendet!"; // Diese Kommentare können allein auf einer Zeile stehen /* genau wie diese Kommentare */ return (0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 8 4.1.3 Zuweisungsoperator // Programm Addition #include <iostream.h> int main () { int sum1, sum2, sum3=10, a=16, b=20; sum1 = 21+4; /* Addition von Zahlenwerten = ist der Zuweisungsoperator ( kein Gleichheitszeichen im mathem. Sinne Die Addition wird durch das + Zeichen in der CPU durchgeführt und das Ergebnis wird in die Speicherzelle namens sum1 eingespeichert */ sum2 = a+b; /* Addition von Variablen genauer: es werden die Inhalte der Zellen a und b addiert und das Ergebnis wird in sum2 abgespeichert */ cout << "sum3= " << sum3 << "\n"; sum3 = sum3 + 6; /* Es wird von der CPU der Inhalt der Zelle sum3 eingelesen, dann wird 6 hinzuaddiert und dann wird das Ergebnis nach sum3 eingespeichert */ cout << "sum1 = " << sum1 << "\n" << "sum2 = " << sum2 << "\n" << "sum3 = " << sum3 << "\n" ; return (0); } // {} Verbundoperator 3D26E882-2673-8602.doc/05.07.02/dr.b. 9 4.2 Zahlenformate, Operatoren und mathem. Funktionen 4.2.1 Bestimmung der Speichergröße #include <iostream.h> int main() { cout << cout << cout << cout << cout << cout << "Groesse "Groesse "Groesse "Groesse "Groesse "Groesse eines eines eines eines eines eines int:\t\t" short int:\t" long int:\t\t" char:\t\t" float:\t\t" double:\t\t" << << << << << << sizeof(int) sizeof(short) sizeof(long) sizeof(char) sizeof(float) sizeof(double) << << << << << << " " " " " " Bytes.\n"; Bytes.\n"; Bytes.\n"; Bytes.\n"; Bytes.\n"; Bytes.\n"; return 0; } 4.2.2 Wertebereich für den Typ int #include <iostream.h> int main() { int Number; Number = 32767; cout << "Zahl: " << Number << endl; Number++; cout << "Zahl: " << Number << endl; Number++; cout << "Zahl: " << Number << endl; return 0; } 3D26E882-2673-8602.doc/05.07.02/dr.b. 10 4.2.3 Wertebereich für den Typ short int #include <iostream.h> int main() { short int smallNumber; smallNumber = 32767; cout << "Kleine Zahl: " << smallNumber << endl; smallNumber++; cout << "Kleine Zahl: " << smallNumber << endl; smallNumber++; cout << "Kleine Zahl: " << smallNumber << endl; return 0; } 4.2.4 Wertebereich für den Typ unsigned short int #include <iostream.h> int main() { unsigned short int smallNumber; smallNumber = 65535; cout << "Kleine Zahl: " << smallNumber << endl; smallNumber++; cout << "Kleine Zahl: " << smallNumber << endl; smallNumber++; cout << "Kleine Zahl: " << smallNumber << endl; return 0; } 3D26E882-2673-8602.doc/05.07.02/dr.b. 11 4.2.5 Übersicht der Wertebereiche Wertebereich (signed) Wertebereich (unsigned) Anzahl der Stellen Typ Byte [un]signed char 1 -128..127 0..255 (entfällt) [un]signed 2 -32768..32767 0..65535 (entfällt) [un]signed int 4 2147483648..214748 0..4294967295 3647 (entfällt) [un]signed long 8 -2^63..2^63-1 0..2^64-1 (entfällt) float 4 (entfällt) +/- 3.4E +/- 38 7 double 8 (entfällt) +/- 1.7E +/- 308 15 10 (entfällt) +/- 1.7E +/- 4932 19 short (int) (int) long double 4.2.6 Bit-Operatoren Eine spezielle Variante der Operationen sind die Bit-Operationen, die eine Zahl bitweise in ihrer Binärdarstellung verändern: Operator Int << X >> Float Operation Beispiel Ergebnis Linksschieben (Multiplikation mit Potenzen von 2) 3<<2 12 X Rechtsschieben (Division durch Potenzen von 2) 16>>1 8 & X Bitweises UND 6&3 2 | X Bitweises ODER 9|3 11 ^ X Bitweises XOR (entweder-oder / exklusives ODER) 7^5 2 ~ X Bitweises NOT (Negation) ~43 Je nach Typ 3D26E882-2673-8602.doc/05.07.02/dr.b. 12 4.2.7 Logische Operatoren Die nächste Klasse an Operatoren sind die logischen Operatoren. Dabei werden Integerzahlen als wahrer Wert interpretiert, wenn sie ungleich Null sind, als falscher Wert sonst. Das Ergebnis ist 1 falls wahr, 0 falls falsch. Auch hier ist eine Anwendung auf Fließkommazahlen möglich, aber nicht sinnvoll. Operator Int Float Operation Beispiel Ergebnis && X Logisches UND i&&j 1, wenn i und j ungleich 0, 0 sonst || X Logisches ODER a||b 0 wenn a und b gleich 0, 1 sonst ! X Logisches NOT (Negation) !q 1 wenn q gleich 0, 0 sonst Da logische Werte in C++ nichts anderes sind als Integerzahlen, kann man mit ihnen auch rechnen. Dabei kann man z.B. folgenden Trick nutzen: a = 5 + !!b * 7; Dieser Ausdruck weist a den Wert 5 oder 12 zu, je nachdem ob b Null ist oder nicht (falls b nicht Null, ist !b Null und !0 ist 1). Man sollte sich allerdings im klaren darüber sein, daß solche Tricks der Lesbarkeit des Programms schaden. Auch ist es wichtig, immer zwischen den bitweisen und den logischen Operatoren zu unterscheiden. Besonders die beiden UND und ODER werden sehr leicht verwechselt, was besonders schlimm sein kann, wenn es eine Zeitlang richtig funktioniert. Das kann nämlich dann passieren, wenn Wahrheitswerte wirklich nur durch 0 und 1 dargestellt werden. Dann unterscheiden sich die bitweisen und die logischen Operationen nicht. Doch sobald andere Werte genutzt werden, treten Fehler auf, die im Nachhinein sehr schwer zu finden sein können. 3D26E882-2673-8602.doc/05.07.02/dr.b. 13 4.2.8 Relationale Operatoren Die relationalen Operatoren führen Vergleiche durch und ergeben wie die logischen Operatoren Wahrheitswerte, d.h. 0 oder 1. Operator Int Float Operation Beispiel Ergebnis < X X Vergleich auf kleiner x<y 1, wenn x kleiner y, 0 sonst > X X Vergleich auf größer y>x 1, wenn x größer y, 0 sonst <= X X Vergleich auf kleiner oder gleich x<=y 1, wenn x kleiner oder gleich y, 0 sonst >= X X Vergleich auf größer oder gleich y>=x Wie bei x<=y == X X Prüfung auf Gleichheit x==y 1, wenn x und y gleich, 0 sonst != X X Prüfung auf Ungleichheit X!=43 0 wenn x gleich 43, 1 sonst ACHTUNG: Auch hier ist Vorsicht geboten, da der Vergleichsoperator (==) leicht mit dem Zuweisungsoperator (=) verwechselt wird. Letzterer ist fast immer „wahr“, da eine Zuweisung den zugewiesenen Wert zurückgibt (d.h. eine Zuweisung ist dann „falsch“, wenn Null zugewiesen wurde). Falls man also nur ein statt zweier Gleichheitszeichen verwendet, so wird zum einen der Ausdruck nicht richtig ausgewertet, zum anderen können unerwünschte Nebenwirkungen auftreten. Manchmal ist es aber durchaus sinnvoll, das Ergebnis einer Zuweisung abzufragen, nämlich dann, wenn eine erfolglose Zuweisung Null zurückgibt. 3D26E882-2673-8602.doc/05.07.02/dr.b. 14 4.2.9 Einige mathematische Funktionen Eigentlich nicht zu C++ selbst gehören die folgenden mathematischen Funktionen. Um sie zu nutzen muß man folgende Zeile in ein Programm aufnehmen: #include <math.h> Danach stehen u.a. folgende Funktionen zur Verfügung (x steht dabei, falls nichts anderes erwähnt für eine beliebige Integer- oder Gleitkommazahl): sqrt(x) Berechnet die Quadratwurzel Berechnet den Sinus exp(x) Berechnet die Exponentialfunktion bzgl. e log(x) Berechnet den natürlichen Logarithmus abs(x) Berechnet den Betrag (nur für Integerzahlen) fabs(x) Berechnet den Betrag (als double) sin(x) 3D26E882-2673-8602.doc/05.07.02/dr.b. 15 4.3 Ein- und Ausgabe 4.3.1 Elementare Ein-/Ausgabe Klassische Befehle aus der C+Programmierung sind • • • • getchar() - zum Einlesen eines Zeichens putchar() - zum Ausgaben eines Zeichens scanf() - zum formatierten Einlesen eines Zeichens printf() - zum formatierten Ausgaben eines Zeichens Diese Funktionen befinden sich in der header-Datei <stdio.h>, die dementsprechend mit dem Befehl #include <stdio.h> eingebunden werden müßten. 4.3.2 Stream-Technik Die Stream-Technik ist die konsequente Anwendung der objektorientierten Programmierung auf die Ein- und Ausgabe (siehe unten). Die Ein- und Ausgabe wird in C++ mit Hilfe sogenannter Streams durchgeführt, wobei man sich zur anfänglichen Erleichterung ruhig vorstellen darf, daß es sich wirklich um einen "Datenstrom" handelt, in dem die zu bearbeitenden Zeichenfolgen "entlangfließen". Dieses Bild unterstützen auch die beiden Operatoren, die man zum Ein- bzw. Ausgeben von Zeichenfolgen benötigt: Für die Ausgabe benötigt man den "schreibe in"-Operator <<, der wie folgt benutzt werden kann: cout << "Dies ist eine erste Ausgabe"; cout stellt dabei den Standard-Ausgabekanal dar, d.h. die Zeile Dies ist eine erste Ausgabe wird üblicherweise zu einer Ausgabe auf dem Bildschirm führen. 3D26E882-2673-8602.doc/05.07.02/dr.b. 16 Der Operator << suggeriert hierbei, daß etwas in Richtung der Pfeile geschrieben bzw. geshiftet wird, d.h. der Stream wird nach cout geschoben und damit ausgegeben. Um auf die im Folgenden angegebenen I/O-Elemente zugreifen zu können, ist es nötig, die Standard-StreamI/O-Bibliothek <iostream.h> in das Programm einzubinden: #include <iostream.h> // I/O-Bibliothek wird eingebunden Ein großer Vorteil der Stream-Technologie liegt darin, daß man die gleiche Form der Ausgabe für verschiedene Datentypen nutzen kann, ohne explizit den Datentyp angeben zu müssen: #include <iostream.h> void main() { int k = 5 ; char c = 'a'; double d = 3.1241; cout << k; cout << c; cout << d; } // // // // // // Deklaration (und Definition) einer Integer-Variable Deklaration einer Char-Variablen Deklaration einer Double-Variablen Integer-Ausgabe Char-Ausgabe Double-Ausgabe Zudem ist es möglich, mehrere Ausgaben - auch Ausgabe verschiedener Typen aneinanderzureihen.: int k = 5; double d = 3.5; cout << "Das Ergebnis von " << k << " plus " << d << " lautet " << k + d; Das Ergebnis von 5 plus 3.5 lautet 8.5 Man beachte, daß der Operator << eine so niedrige Priorität besitzt, daß auf eine Klammerung des Ausdrucks (k+d) verzichtet werden kann. 3D26E882-2673-8602.doc/05.07.02/dr.b. 17 4.3.3 Einfache Manipulatoren In den vorhergehenden Beispielen wurden die entsprechenden Werte stets hintereinander in einer Zeile ausgegeben, d.h. Formatierungsanweisungen wie etwa "neue Zeile" haben wir bisher noch nicht kennengelernt. Dies soll nun nachgeholt werden. Hierfür wird ein neuer Begriff benötigt, der des Manipulators. Am Ende der meisten Ausgabe-Anweisungen wird etwa der Operator endl ausgegeben: cout << "Erste Ausgabe mit eine Manipulator am Ende" << endl; Der Name Manipulator kommt daher, daß derartige Objekte (auch Manipulatoren passen in die objektorientierte Philosophie) Manipulationen am Stream durchführen. Der eben kennengelernte Manipulator endl steht für "endline" und bewirkt zweierlei: 1. Er gibt ein Newline (Zeichen '\n') aus und 2. leert anschließend den Ausgabepuffer (d.h. schickt die Ausgabe auch wirklich ab!) Für die Ausgabe stehen drei einfache Manipulatoren zur Verfügung: Manipulator flush endl ends Bedeutung Ausgabepuffer leeren '\n' ausgeben und Ausgabepuffer leeren '\O' ausgeben und Ausgabepuffer leeren Mit diesen Operatoren ist man in der Lage, zumindest einfache Formatierungen in Form von Zeilenumbrüchen vorzunehmen. Da man bei der Ausgabe von Strings den jeweiligen String in Anführungszeichen anzugeben hat, steht man vor dem Problem, daß man z.B. nicht in der Lage ist, das Anführungszeichen an sich auszugeben: cout << " Hier soll ein Anführungszeichen " stehen " << endl; // FEHLER !!! Der übergebene String endet nämlich mit den zweiten Anführungszeichen, der Rest ist dann für den Compiler nicht mehr korrekt zu interpretieren. Eine Lösung findet sich in den im folgenden aufgelisteten Escape-Sequenzen, die es zudem erlauben, weitere Formatierungen bei der Ausgabe vorzunehmen. 3D26E882-2673-8602.doc/05.07.02/dr.b. 18 4.3.4 Escape-Sequenzen Anweisung Abkürzung für \a alert \b backspace \n new line \t horizontal tab \v vertical tab \' single quotation mark \" double quotation mark \\ backslash \O NUL \ddd character in octal notation \xhh character in hex notation 4.3.5 Bedeutung Piepton Löscht Zeichen links vom Cursor Neue Zeile Horizontaler Tabulatorensprung Vertikaler Tabulatorensprung Hochkomma Anführungszeichen Rückstrich Beendet die Ausgabe von Zeichenfolgen Zeichen in Oktalzahl ddd Zeichen mit dem Wert in Hexadezimalzahl Eingabe Für die Eingabe steht der zum Ausgabeoperator genau entgegengerichtete Operator >> zur Verfügung, der ein ähnlich einfaches und elegantes Einlesen ermöglicht: #include <iostream.h> main() { int int_wert; double double_wert; cout << " Bitte geben Sie einen Integer und einen Double-Wert ein: " << endl; cin >> int_wert >> double_wert; // Einlesen der Werte cout << "Es wurden die Werte ( " << int_wert << ", " << double_wert << ") eingegeben." << endl; return 0; } In dem Beispiel wird man zur Eingabe zweier Werte aufgefordert, wobei die Werte verschiedenen Typs sein sollen. Die Eingabe an sich erfolgt über die Zeile cin >> int_wert >> double_wert; cin stellt dabei das Objekt dar, aus dem heraus etwas gelesen werden soll. Im Standardfall wird dies die Tastatur sein. 3D26E882-2673-8602.doc/05.07.02/dr.b. 19 Bei der Eingabe der beiden Werte ist darauf zu achten, daß diese durch ein Whitespaces-Zeichen voneinander getrennt sind; dies kann ein Leerzeichen, aber auch ein <Return> sein. Die gesamte Eingabe ist jedoch auf jeden Fall mit <Return> abzuschließen. Die Veranschaulichung durch den Operator kann analog zur Ausgabe erfolgen: Wieder wird in Richtung der Pfeile geschrieben. Auch hier muß der Typ des Objektes, in das etwas geschrieben werden soll, nicht explizit angegeben werden; er wird implizit aus der angegebenen Variable ermittelt. Allerdings sollte man folgendes beachten: Entspricht der eingebene Typ nicht dem Typ, der erwartet wird, so wird die Eingabe nicht korrekt abgeschlossen. Da dies nicht unbedingt zu einer Fehlermeldung führt (z.B. werden u.U. bei einem erwarteten Integer und eingegebenem Double einfach die Nachkommastellen abgeschnitten und das Programm wird ohne Meldung fortgeführt), können sich überraschende Ergebnisse des Programms einstellen! Ein Programmierer sollte daher immer die Eingabe auf ihre Korrektheit hin überprüfen. Zur Beachtung: Ein allgemeines Vorgehen ist z.B. die Abfrage einer Bedingung in einer while-Schleife. Im folgenden Beispiel wird die Eingabe zeichenweise verarbeitet: char C; while (cin >> C) // ... Dabei ist zu bemerken, daß bei der Eingabe wirklich Zeichen für Zeichen eingelesen wird, Strings, d.h. zu einer Worteinheit zusammengefaßte Zeichen, werden nicht als solche behandelt, sondern in die einzelnen Zeichen "zerlegt". Zudem werden Whitespace-Zeichen vom Eingabestrom nicht als eigenständige Zeichen behandelt, sondern dienen nur zur Abgrenzung der eingelesenen Werte. Die Zeichenfolge nix t oll e s wird also als eine Folge von neun Zeichen verarbeitet: 'n','i','x','t','o','l','l','e','s'. Will man Whitespaces-Zeichen als solche berücksichtigen, so sind die Elementfunktionen get(), getline() bzw. read() zu verwenden. 3D26E882-2673-8602.doc/05.07.02/dr.b. 20 4.4 Einfache Rechenoperationen 4.4.1 Addition, Multiplikation, Division, Modulo-Operator // Grundrechenarten # include <iostream.h> int main () { int summe, differenz,nur_rest, produkt, quotient, a=21, b=4; summe = 21+4; differenz = a-b; produkt = a*b; quotient = a/b; nur_rest = a%b; cout << << << << << // Ganzzahlige Division der Rest geht verloren /* Modulo-Operator liefert den Rest einer ganzzahligen Division */ "summe = "differenz = "produkt = "quotient = "nur_rest = " " " " " << << << << << summe << "\n" differenz << "\n" produkt << "\n" quotient << "\n" nur_rest << "\n" ; /* Tastaturkürzel: strg+c = kopieren strg+v = einfügen strg+x = ausschneiden */ return (0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 21 4.4.2 Division mit Gleitkommazahlen // Division und Fließ- Gleitkommazahlen # include <iostream.h> int main () { int div_1, a=21, b=4 ; float div_2, div_3, div_4, div_5, c=21, d=4 ; div_1 = a/b; div_2 = 7.26; div_3 = a/b; div_4 =21.0/4; div_5 =c/d; cout << "div_1 << "div_2 << "div_3 << "div_4 << "div_5 ; // // // // // = = = = = " " " " " // Zelle die Fließkommazahlen // speichern kann ganzzahlige Division, Abspeicherung in int-Zelle OK. Ergebnis der ganzzahligen Division (5) wird in der float- Zelle abgespeichert Bei gemischten Zahlen nimmt der PC die genauere << << << << << div_1 div_2 div_3 div_4 div_5 << << << << << "\n" "\n" "\n" "\n" "\n" return (0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 22 4.4.3 Inkrement-Operator // Inkrement # include <iostream.h> int main () { int a, b, c=5, d, e, f, i=1, j=1, k=1, x=100, y=200 ; i= i+1; a= ++j; // Erhöhung einer Variablen um 1 /* ++(j)=präfix-Inkrement Operator, zuerst wird j inkrementiert und danach wird der neue Wert nach a übergeben Inkrement Operator=Erhöhungsoperator */ /* (k)++=postfix-Inkrement Operator, zuerst wird k in b abgespeichert und danach erst wird k inkrementiert */ /* nur c wird inkrementiert => Ursprung des Namens C++ */ //Präfix-Dekrement //Postfix-Dekrement b= k++; c++; --x; y--; cout << "i= << "a= << "b= << "k= << "c= << "x= << "y= ; return (0); } " " " " " " " << << << << << << << i a b k c x y <<"\n" <<"\n" <<"\n" <<"\n" <<"\n" <<"\n" <<"\n" // z.B. zum Hochzählen bei Schleifenrückläufen 3D26E882-2673-8602.doc/05.07.02/dr.b. 23 4.5 Schleifen und Bedingungen 4.5.1 Struktogrammelemente für C++ Die if-Anweisung true if (Ausdruck) Anweisung(en) 1 false Anweisung(en) 2 Die switch-Anweisung switch (Ausdruck) case 1 case 2 Anweisung(en) 1 Anweisung(en) 2 case n Anweisung(en) n default Anweisung(en) Die for-Anweisung for (Initialisierung; Bedingung; Inkrement) Anweisung(en) 3D26E882-2673-8602.doc/05.07.02/dr.b. 24 Die while-Anweisung while (Ausdruck) Anweisung(en) Die do-while-Anweisung Anweisung(en) do ... while (Ausdruck) 3D26E882-2673-8602.doc/05.07.02/dr.b. 25 4.5.2 While-Schleife // while-Schleife /* Schleifenanweisungen Zur wiederholten Ausführung von Programmteilen stehen 3 Schleifenanweisungen zur Verfügung: - while-Schleife - do...while-schleife - for-Schleife Die Zahl der Schleifendurchläufe ist abhängig von einem Parameter (Laufvariable), deren Wert bei jedem Durchlauf der Schleife überprüft wird (Bedingung erfüllt ja/nein). */ // hier: 5malige Textausgabe #include <iostream.h> int main() { int i=1; // i = Laufvariable while(i<=1) // while(Bedingung erfüllt) { cout << i << ". Moin, moin!\n"; i++; } return(0); } /* 1. Darauf achten, daß die Bedingung mindestens 1mal erfüllt wird, ansonsten wird dieser Programteil übersprungen. 2. Auf jeden Fall das Inkrement so wählen, daß die Bedingung irgend wann mal nicht erfüllt ist, sonst Endlosschleife!!!! 3. Bei der while-Schleife ist die Bedingungsüberprüfung am Anfang der Schleife. */ 3D26E882-2673-8602.doc/05.07.02/dr.b. 26 4.5.3 Do...while-Schleife // do...while-Schleife // hier: Runterzählen von 10 auf 4 #include <iostream.h> int main() { int i=10; do { } // i = Laufvariable // Eintauchen in die Schleife cout << i << "\n"; i--; while(i>=4); return(0); } /* Die Bedingungsüberprüfung ist am Ende der Schleife und daher wird die Schleife mindestens 1mal durchlaufen. */ 3D26E882-2673-8602.doc/05.07.02/dr.b. 27 4.5.4 Switch-Anweisung // Zahlenreihe #include <iostream.h> #include <iomanip.h> int main() { int fall; float xnminus1, xnminus2, xn; cout.setf(ios::right | ios::fixed); cout.precision(1); cout << "Bitte eingeben:\n" << "1 = for-Schleife\n" << "2 = do...while-Schleife\n" << "3 = while-Schleife\n"; cin >> fall; cout << "\n"; switch (fall) { case 1: //***** for-Schleife ***** xnminus1=2.5; xnminus2=1.5; cout << setw(5) << xnminus2 << "\n"; for (xn=2.5; xn<1000; ) { cout << setw(5) << xn << "\n"; xn = xnminus1 + 2*xnminus2; xnminus2=xnminus1; xnminus1= xn; } break; case 2: //***** do...while-Schleife ***** xnminus1=2.5; xnminus2=1.5; cout << setw(5) << xnminus2 << "\n"; xn=2.5; do { cout << setw(5) << xn << "\n"; xn = xnminus1 + 2*xnminus2; xnminus2=xnminus1; xnminus1= xn; } while (xn<1000); break; case 3: //***** while-Schleife xnminus1=2.5; xnminus2=1.5; 3D26E882-2673-8602.doc/05.07.02/dr.b. ***** 28 cout << setw(5) << xnminus2 << "\n"; xn=2.5; while (xn<1000) { cout << setw(5) << xn << "\n"; xn = xnminus1 + 2*xnminus2; xnminus2=xnminus1; xnminus1= xn; } break; default: cout << "Falscher Eingabewert!"; } return (0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 29 4.5.5 Musteraufgabe „Fahrenheit“ Schreiben Sie ein C++-Programm zur Umrechnung der Temperaturen von Celsius in Fahrenheit. Verwenden Sie die Umrechnungsformel FAHREN = 1.8*CELSIUS+32.0. Es soll folgende Tabelle auf dem Bildschirm ausgegeben werden: ZEILE CELSIUS FAHRENHEIT -------------------------------1 2 3 . . . 11 20 22 24 68.0 71.6 75.2 40 104.0 Lösung mit einfacher Ausgabeformatierung // Temperaturumwandlung ohne Ausgabeformatierung #include <iostream.h> int main() { int zeile=1, celsius; float fahrenheit; cout << "ZEILE CELSIUS FAHRENHEIT\n"; cout << "-----------------------------------\n"; do { celsius = 18 + 2*zeile; fahrenheit = 1.8*celsius + 32; cout << zeile << " << celsius << " << fahrenheit << "\n"; zeile++; } while (zeile<=11); " " return(0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 30 Lösung mit objektorientierten Formatierungselementen // Temperaturumwandlung mit Ausgabeformatierung #include <iostream.h> #include <iomanip.h> int main() { int zeile=1, celsius; float fahrenheit; cout << "ZEILE CELSIUS FAHRENHEIT\n"; cout << "12345678901234567890123456789012345\n"; do { celsius = 18 + 2*zeile; fahrenheit = 1.8*celsius + 32; cout.setf(ios::fixed | ios::right); cout.precision(2); /* . und :: sind Operatoren der objektorientierten Programmierung */ cout << setw(5) << zeile << setw(14) << celsius << setw(16) << fahrenheit << "\n"; zeile++; } while (zeile<=11); return(0); } /* iomanip.h ermöglicht Ausgabeformatierungen: setw(zahl) = Vorschub des Cursors um zahl Stellen right = rechtsbündig fixed = feste Nachkommastellenzahl precision(zahl) = Anzahl der Nachkommastellen */ 3D26E882-2673-8602.doc/05.07.02/dr.b. 31 4.5.6 For-Scheife Vollständige Syntax // for-Schleife /* Vollständige Syntax: for(Initialisierung; Bedingung; Inkrement) Anweisung; */ #include <iostream.h> int main() { int zahl; for(zahl=1; zahl<=5; zahl++) cout << zahl << "\n"; return(0); } /* 1. Bei nur 1 Anweisung in der Schleife kann der Verbundoperator {} entfallen. 2. Das Inkrement wird erst nach Abarbeitung der Schleifnbefehle durchgeführt. */ Verkürzte Syntax // for-Schleife mit Leeranweisungen #include <iostream.h> int main() { int zahl=4; for( ; zahl<=5; ) { cout << zahl << "\n"; zahl++; } return(0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. // Initialwert hier bereits // Inkrement jetzt innerhalb der Schleife 32 Verschachtelte Schleifen // Verschachtelte Schleifen #include <iostream.h> #include <iomanip.h> int main() { int zahl=1, otto; for(; zahl<=3;) { cout << zahl << ". Run\n"; for(otto=1; otto<=4; otto++) { cout << setw(4+2*otto) << otto << ". OTTO\n"; } zahl++; } return(0); } /* Anstelle von festen Werten können an den gleichen Stellen auch die Berechngsformeln für die Werte stehen */ 3D26E882-2673-8602.doc/05.07.02/dr.b. 33 4.5.7 If-Anweisung // IF-Anweisung #include <iostream.h> int main() { int zahl; cout << "Bitte Zahl eingeben: "; cin >> zahl; if(zahl==5) // Abfrage auf logisch TRUE { cout << "Die Zahl lautet fünf!\n"; // ggf. weitere Anweisungen } else { cout << "Die Zahl ist NICHT fünf!\n"; } cout << "Ende des Programms."; return(0); } /* IF reicht aus, wenn bei Bedingung nur 1 Sache abzuarbeiten ist. IF .. ElSE, wenn zwischen 2 Alternativen auszuwählen ist. */ 3D26E882-2673-8602.doc/05.07.02/dr.b. 34 4.5.8 Boolsche Variablen // Boolsche Variablen /* Operator C++-Symbol AND && OR || NOT ! Beispiel A&&B A||B !A Eine NOT-Anweisung liefert TRUE, wenn der zu testende Ausdruck FALSE ist Beispiel: if(!(x==5)) ist nur TRUE, wenn x ungleich 5 ist. alt.: if(x!=5) ad-hoc-Aufgabe: Programmieren Sie eine der NORVerknüpfungszeilen Für Zuhause: Formatierte Tabelle für die Äquivalenz-Verknüpfung mittels Schleifenoder if-Anweisung programmieren */ #include <iostream.h> int main() { bool A, B, X, Z=1; do { cout << "A = "; cin >> A; cout << "B = "; cin >> B; X = !(A||B); // Verknüpfung wird berechnet cout << "X = " << X << "\n"; cout << "Neuer Run? 0=nein, 1=ja: "; cin >> Z; } while (Z==1); cout << "Programmende.\n"; return(0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 35 4.5.9 Zeichen- und Zeichenketten // Zeichen und Zeichenketten (String) #include <iostream.h> int main() { char einzeichen = 'X'; char z1 = 65, z2 = 90; // 1 Byte lang char MeinName[6] = "BUSSE"; // Zeichen im ASCII-Code // 65 ... 90 => Großbuchstaben des Alphabets // String /* Min. Feldlänge gleich Textlänge zzgl. 1Byte */ cout << einzeichen << z1 << z2 << MeinName ; return(0); } // hier keine eckigen Klammern << << << << "\n" "\n" "\n" "\n" 3D26E882-2673-8602.doc/05.07.02/dr.b. 36 4.5.10 Einlesen von Tastaturzeichen #include <iostream.h> #include <conio.h> int main() { char zeichen1; cout << "Der PC wartet auf eine Tastatureingabe!\n"; zeichen1 = getch(); cout << " Danke! ... und nochmals!\n"; getch(); cout << "Danke, das war`s."; cout << "Die erste Eingabe war das Zeichen " << zeichen1 << "\nDas zweite Zeichen verrate ich nicht!\n"; return 0; } 3D26E882-2673-8602.doc/05.07.02/dr.b. 37 4.5.11 Kleine Musteraufgabe „Pole Position“ Vier HWI-Professoren sollen auf dem Bildschirm leicht versetzt namentlich eine Startaufstellung wie beim Formel-1-Rennen bilden. Lösung: // Programm Pole Position #include <iostream.h> #include <iomanip.h> int main() { char formel_1_pilot[4][10] = { "EWE", "BUSSE", "ROEBEN", "ORLOWSKI"}; int i; cout << "Die Startreichenfolge ist:\n\n"; for (i=0; i<4; i++) { cout << "\t" << formel_1_pilot[i] << "\n"; i++; cout << "\t\t" << formel_1_pilot[i] << "\n"; } return(0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 38 4.5.12 Goto-Anweisung // goto-Anweisung #include <iostream.h> int main() { int i; anfang: // Sprungmarke setzen (Label) cout << "Bitte die Zahl 1 oder 2 eingeben: "; cin >> i; if (i==1) goto anfang; // Bedingter Sprung nach "anfang" goto ende; cout << "Hey, ich werde dauernd übersprungen!"; ende: cout << "Ich bin jetzt am Ende.\n"; return(0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 39 4.5.13 Chaotische Programmierung // goto-Anweisung #include <iostream.h> int main() { int i; anfang: // Sprungmarke setzen (Label) cout << "Bitte die Zahl 1 oder 2 eingeben: "; cin >> i; if (i==1) goto anfang; // Bedingter Sprung nach "anfang" goto ende; mitte: cout << "Hey, ich bin jetzt auch mal dran!\n"; goto GanzZumSchluss; ende: cout << "Ich bin jetzt am Ende.\n"; goto mitte; GanzZumSchluss: cout << "Tschüss... "; return(0); } /* Diesen Programmierstiel möglichst vermeiden!!! besser: * Schleifenbefehle verwenden * Unterprogramme (Funktionen) schreiben */ 3D26E882-2673-8602.doc/05.07.02/dr.b. 40 4.5.14 Switch-Anweisung // switch-Anweisung zur Fallunterscheidung #include <iostream.h> int main() { int zahl; cout << "Bitte 1, 2 oder 3 eingeben: "; cin >> zahl; switch (zahl) { case 1: cout << break; case 2: cout << break; case 3: cout << break; default: cout << } "Ich habe eine EINS eingegeben.\n"; "Ich habe eine ZWEI eingegeben.\n"; "Ich habe eine DREI eingegeben.\n"; "Die Zahl war nicht 1, 2 oder 3!\n"; cout << "Programmende."; return(0); } // break ist auch in Schleifen anwendbar 3D26E882-2673-8602.doc/05.07.02/dr.b. 41 4.5.15 Musteraufgabe „PIN“ Einlesen einer PIN // PIN-Eingabe #include <iostream.h> #include <conio.h> // für getch() erforderlich int main() { char pin1='1', pin2='2', pin3='7', pin4='8'; char e1, e2, e3, e4; neueEingabe: cout << "Bitte Geheimzahl eingeben: "; e1 = getch(); /* Einlesen eines Tastaturzeichens ohne Bildschirmausgabe (ohne Echodruck) */ cout << "*"; e2 = getch(); cout << "*"; e3 = getch(); cout << "*"; e4 = getch(); cout << "*"; if ((pin1!=e1) || (pin2!=e2) || (pin3!=e3) || (pin4!=e4)) {cout << "\nFalsche Geheimzahl\n"; goto neueEingabe;} cout << "\nProgrammende."; return(0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 42 4.6 Unterprogramme // Unterprogramme (Funktionen) // hier: Flächenberechnung #include <iostream.h> int berechnung(int, int); /*Funktionsdeklaration = Funktionsprototy der Rückgabewert ist vom Typ int, die vom Hauptprogramm übergebenen Wete sind ebenfalls vom Typ int*/ //*****************************Hauptprogramm int main() { int x=4, y=7, flaeche; flaeche = berechnung(x, y); /* x- und y-Werte werden an das Unterprogramm mit dem Namen berechnung übergeben, der Ergebniswert der Berechnung wird in die Speicherzelle flaeche eingespeichert */ cout << flaeche; return(0); } //********************************************** // Unterprogramm // Funktionsdefinition int berechnung(a,b) // a,b sind sog. lokale Variable { int ergebnis; ergebnis = a*b; return (ergebnis); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 43 4.7 Datenfelder (Arrays) 4.7.1 Eindimensionale Arrays // Datenfelder // bekannt: Textfeld char MeinName[20] = "Hans im Glück"; /* Datenfeld = Array (strukturierte Anordnung von Daten) = Gruppe von Speicherzellen für Daten desselben Typs, z.B. int, float => Daten haben den gleichen Variablennamen und erhalten zur Unterscheidung einen Laufindex | 22 | 04 | 12 | 83 | 0 1 2 3 hier: 4 Speicherzellen vom Typ int Zählnummer für die i-te Zelle Die einzelnen Zellen heißen Elemente des Arrays, also hier Array mit 4 Elementen. beachten: der Laufindex beginnt bei 0!!! bei nur einem Laufindex handelt es sich um ein eindimensionales Array. */ // Deklaration typ feldname[feldgroesse]; // z.B. int MeinErstesDatenfeld[4]; float hans[24]; // hier: Elemente vom Typ float // Definition (= Initialisierung) // a) einzeln MeinErstesDatenfeld[0] = 22; MeinErstesDatenfeld[1] = 4; // usw. // b) sofort bei Deklaration, bekannt int x=5; int MeinErstesDatenfeld[4] = {22, 4, 12, 83}; // c) über Formel o.ä. for (i=0; i<= 5; i++) { MeinZweitesDatenfeld[i] = 7*i + 48; } // es wird in MeinZweitesDatenfeld[0] der Wert 48 eingesp., usw. // Zugreifen auf das i-te Element int x, i=2; x = MeinErstesDatenfeld[2]; // x = 12 /* Vorteil: Die einzelnen Elemente lassen sich über eine Laufvariable (z.B. in einer Schleife) leicht ansprechen */ 3D26E882-2673-8602.doc/05.07.02/dr.b. 44 4.7.2 Mehrdimensionale Arrays /* Mehrdimensionale Arrays | 22 | 04 | 12 | 83 | | 23 | 06 | 17 | 99 | | 11 | 02 | 01 | 83 | 0 1 2 3 => */ 0 1 => Laufindex für Zeile 2 Laufindex für Spalte int feldname[zeilenzahl][spaltenzahl]; // hier: int otto[3][4]; // Zugriff: int y; y = otto[2][0]; // y = 11 Beispiel // Programm 52array.cpp #include <iostream.h> int main() { // Beispiel eindimensionales Array int i=0, claudia[6]; for (; i<=5; i++) { claudia[i] = 7*i + 48; cout << claudia[i] << "\n"; } // Beispiel mehrdimensionales Array int x=0, y=0; int richard[3][5] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; // Zeilenweises Auffüllen der Elemente des Arrays for (; x<=2; x++) { for (; y<=4; y++) { cout << richard[x][y] << " "; } y=0; cout << "\n"; } return(0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 45 4.7.3 Musteraufgabe „Schachbrett“ Aufgabe und Lösungsansatz /* Programm Reiskörner auf Schachfeld, Anzahl verdoppelt sich jeweils Am Ende soll die Körnerzahl des 20. Feldes nochmals ausgegeben werden Lösung: - verwenden Sie ein 2-dim. Array - vorteilhaft ist die exp-Fkt. Syntax: double ergebnis = pow(double basis, double exponent) */ // Vorlüberlegung, probieren Sie: #include <iostream.h> #include <math.h> int main() { double ergebnis, k=10; ergebnis = pow(2, k); cout << "2 hoch 10 = " << ergebnis; return(0); } /* Tips double brett[8][8]; mit i, j = Laufvariablen für beide Richtungen von 0 ... 7 in 2 verschachtelten Schleifen */ 3D26E882-2673-8602.doc/05.07.02/dr.b. 46 Lösung: // Reiskörner auf einem Schachbrett #include <iostream.h> #include <math.h> int main() { int i=0, j=0; double k=0; // Laufvariable für Potenzierung double Brett[8][8]; char z=65; for (;i<8;i++) { for (;j<8;j++) { Brett[i][j] = pow(2, k); k++; cout <<k <<"\t" <<z <<j+1 <<"\t" << Brett[i][j] << "\n"; } j=0; z++; cout << "\n"; } cout <<"\nDas 20. Feld (3. Reihe, 4. Spalte) enthält " << Brett[2][3] <<" Reiskörner.\n"; return 0; } 3D26E882-2673-8602.doc/05.07.02/dr.b. 47 5 Objektorientierte Programmierung 5.1 Methodischer Ansatz 5.1.1 Typen Menschen kategorisieren, d.h. sie klassifizieren, ordnen, gruppieren, unterteilen, usw. => Wir denken in Typen von Dingen. Typen besitzen ähnliche Merkmale. Typen sind aus der C++-Programmierung bereits bekannt, z.B. die Variablentypen wie int x; // x ist vom Typ integer. Damit ist festgelegt: • Speicherplatzgröße • Speicherbare Information • die mit der Variablen ausführbaren Aktionen. Standardtypen wie int heißen Basisklassen. Ein Programmierer kann sich eigene Typen erzeugen. Jeder neu definierte Type kann über die gesamte Funktionalität der vordefinierten Typen verfügen. 5.1.2 Klassen und Elemente Einen neuen Typ erzeugt man durch die Definition einer Klasse. Eine Klasse ist eine Sammlung von Variablen kombiniert mit einer Gruppe verwandter Funktionen und Fähigkeiten. 5.1.3 Klassen deklarieren Um eine Klasse zu deklarieren, verwendet man das Schlüsselwort class, gefolgt vom Namen und den Datenelemeten in {}. class Katze { int alter; int gewicht; miauen(); }; 3D26E882-2673-8602.doc/05.07.02/dr.b. 48 Diese Deklaration belegt noch keinen Speicherplatz für eine Katze. Sie ist eine Anweisung an den Compiler, was die Klasse der Katzen darstellt, welche Daten sie enthält und was sie kann. Der Compiler muß in diesem Beispiel für eine bestimmte Katze zwei Integer-Bereiche für Alter und Gewicht reservieren, aber keinen Bereich fürs Miauen, da es sich hierbei um eine Elementfunktion = Methode handelt, die keinen Speicherplatz benötigt. 5.1.4 Objekte definieren Katze Josie, FritzTheCat; Josie ist ein Objekt der Klasse / des Typs Katze. Mit dieser Anweisung wird ein konkretes Objekt der Klasse Katze definiert und dem Objekt der Name Josie zugewiesen. 5.1.5 Auf Klassenelemente zugreifen Josie ist ein Objekt vom Typ Katze. Mithilfe des Punktoperators (.) kann man auf die Elemente des Objekts zugreifen. Allg. Syntax: Objektname.Variablennamen oder Objektname.Methode Josie.gewicht = 4; // es wird der Wert 4 kg an die Elementvariable gewicht des Objekts Josie zugewiesen FritzTheCat.miauen(); 5.1.6 // Aufrufen der Funktion Miauen Definition einer Elementfunktion Elementfunktionen sind zu definieren. Allg. Form: Klassenname::Methodenname(Parameter) Beispiel: Katze::miauen() { cout << "Miauuuuuuu.\n" } Die Elementfunktion hat das Aussehen eines Unterprogramms, das bei Aufruf abgearbeitet wird. 3D26E882-2673-8602.doc/05.07.02/dr.b. 49 5.2 Musteraufgabe „Katzendatei“ // OOP Katzenprogramm #include <iostream.h> // Deklaration eines eigenen Typs ************************ class katzen // hier alle Eigenschaften aller Katzen aufgeführt { public: // das gesamte Programm kann nachstehendes nutzen float gewicht; char name[10]; miauen(); eingabe(); ausgabe(); }; // Semikolon nicht vergessen // METHODENDEFINITION ************************************ katzen::miauen() { cout << "\n ...Miauuuu... man hat mir auf den Schwanz getreten!!!\n"; } katzen::eingabe() { cout << "Name: cout << "Gewicht: cout << "\n"; } "; cin >> name; "; cin >> gewicht; katzen::ausgabe() { cout << "Die Katze mit Namen\t" << name << "\twiegt\t" << gewicht << " kg und schreit:"; } // HAUPTPROGRAMM int main() { katzen katze[3]; int i; ***************************************** // es gibt konkret 3 europäische Kauskatzen for(i=0; i<=2; i++) {katze[i].eingabe();} for(i=0; i<=2; i++) {katze[i].ausgabe(); katze[i].miauen();} return(0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 50 3D26E882-2673-8602.doc/05.07.02/dr.b. 51 6 Assembler-Programmierung // Beispiel Assembler-Routinen #include <iostream.h> int main() { int multiplikant, multiplikator, produkt; cout << "Multiplikant eingeben: "; cin >> multiplikant; cout << "Multiplikator eingeben: "; cin >> multiplikator; // in Assembler multiplizieren: // Ladebefehl für ein Register: mov ZIEL, QUELLE _asm { /* 32-Bit Akkumulatorregister eax (Vielzweckregister) ax = untere 16-bit von eax */ mov ax, multiplikant /* Der Ram-Speicher-Inhalt von multiplikant wird in den unteren Teil des eax-Registers eingspeichert*/ mov bx, multiplikator /* weiteres Vielzweckregister*/ mul bx /* bx wird mit ax multipliziert und in ax abgespeichert*/ mov produkt, ax /* auslagern des Rechenergebnisses nach produkt*/ } cout << "\n" << " * " << " = " return 0; } << multiplikant << multiplikator << produkt; 3D26E882-2673-8602.doc/05.07.02/dr.b. 52 7 Mathematische Methoden 7.1 Musteraufgabe „Sortieren“ // Sortieren nach dem Bubblesort-Algorithmus #include <iostream.h> int main() { int i, j, k, hilf, merke, a[]={7,3,1,5}; for (i=0; i<=3; i++) cout << "a[" << i << "] = " << a[i] << "\n"; cout << "\n"; // Minimales Element im verbleibenden Intervalls suchen for(i=0; i<3; i++) { merke = i; // Schleife über alle noch nicht sortierten Elemente // Vermerke aktuelles Element als bisher kleinstes for(j=i+1; j<4; j++) { if(a[j] < a[merke]) merke = j; // a[merke] ist das kleinste Element } // i-tes Element mit dem minimalen vertauschen hilf = a[i]; a[i] = a[merke]; a[merke] = hilf; for (k=0; k<=3; k++) cout << "a[" << k << "] = " << a[k] << "\n"; cout << "\n"; } cout << "\n"; for (i=0; i<=3; i++) cout << "a[" << i << "] = " << a[i] << "\n"; return (0); } 3D26E882-2673-8602.doc/05.07.02/dr.b. 53 8 Weitere Beispielaufgaben 8.1 Musteraufgabe „Bruchkürzen“ Schreiben Sie ein C++-Programm zum Kürzen von Brüchen. Es sind der Zähler und der Nenner eines Bruches ganzzahlig einzulesen. Der so definierte Bruch ist durch den größten gemeinsamen Teiler (ggT) von Zähler und Nenner zu kürzen, so daß ein nicht weiter kürzbarer neuer Bruch entsteht. Z.B. Zähler: 30 Nenner: 5 Ausgabe: 30 ---5 6 = ---1 Das Hauptprogramm soll nur die Funktionsaufrufe Eingabe(); Kuerze(); Ausgabe(); enthalten. Schreiben Sie die Funktionen eingabe, kuerze und ausgabe mit den notwendigen Übergabeparametern sowie das Gesamtprogramm. 3D26E882-2673-8602.doc/05.07.02/dr.b. 54 Lösung // Programm Bruchkuerzen #include <iostream.h> #include <iomanip.h> int z1,z2,n1,n2; // Globale Variable int eingabe() { cout << "Eingabe des Zählers: cin >> z1; cout << "Eingabe des Nenners: cin >> n1; cout << "\n\n\n"; return (0); } "; "; int kuerzen() { int ggt, ggt_max; if (z1>=n1) ggt_max=n1; else ggt_max=z1; for (ggt=1; ggt<=ggt_max; ggt++) { if ((z1%ggt==0) && (n1%ggt==0)) {z2=z1/ggt; n2=n1/ggt;} } return (0); } int ausgabe() { cout << setw(8) << z1 << setw(10) << z2 << "\n"; cout << " ----- = -----\n"; cout << setw(8) << n1 << setw(10) << n2; return (0); } // Hauptprogramm*********************** int main() { eingabe(); kuerzen(); ausgabe(); return 0; } 3D26E882-2673-8602.doc/05.07.02/dr.b. 55 8.2 Musteraufgabe „Geldautomat“ Es soll ein Geldautomat simuliert werden, der folgende Scheine ausgeben kann: 1000er-, 500er-, 200er-, 100er-, 50er-, 20er- und 10er-Scheine. Wie bei einem echten Geldautomaten soll zunächst eine vierstellige Geheimzahl (PIN) abgefragt werden. Bei der Eingabe der vier Ziffern darf jeweils nur ein ´*´ auf dem Bildschirm erscheinen und nicht die eingegebene Ziffer. Wird die Geheimzahl dreimal falsch eingegeben, so bricht das Programm mit einer entsprechenden Meldung ab. Bei richtiger Geheimzahl kann dann der gewünschte Betrag eingegeben werden. Ist der Betrag nicht durch 10 teilbar, erfolgt ein entsprechender Hinweis mit der Möglichkeit der nochmaligen Eingabe des gewünschten Betrages. Im Programm soll berechnet werden, wie der Betrag mit möglichst wenigen Scheinen ausgegeben werden kann. Als Nachweis erscheint ein Ausgabebeleg auf dem Bildschirm, z.B. bei 740 DM: 1 Fünfhunderter, 1 Zweihunderter, 2 Zwanziger. Entwickeln Sie für die Aufgabe zunächst ein Struktogramm und schreiben Sie dann ein ablauffähiges C++-Programm. Hinweis: Verwenden Sie vorzugsweise die Header-Dateien iostream.h, iomanip.h und conio.h. Letztere unterstützt das Einlesen von Tastaturzeichen ohne Echo auf dem Bildschirm durch Verwendung der Anweisung getch(). Beispiel: char g1; g1=getch(); /* Einlesen eines Tastaturzeichens ohne Ausgabe auf dem Bildschirm und Übergabe in die Speicherzelle g1. */ // g1 kann dann mit der entsprechenden PIN-Ziffer logisch auf Identität verglichen werden. 3D26E882-2673-8602.doc/05.07.02/dr.b. 56 Lösung: // Programm Geldautomat #include <iostream.h> #include <iomanip.h> #include <conio.h> // Deklaration der verwendeten Funktionen void geheimzahl(); int betragseingabe(); void berechnung(int betrag); // Hauptprogramm **************************** int main() { geheimzahl(); int betrag=betragseingabe(); berechnung(betrag); return(0); } // ******************************************* void geheimzahl() { char pin1='1'; char pin2='2'; char pin3='3'; char pin4='4'; char g1, g2, g3, g4; neueEingabe: cout << "Bitte geben Sie Ihre Geheimzahl ein: "; g1=getch(); cout << "*"; g2=getch(); cout << "*"; g3=getch(); cout << "*"; g4=getch(); cout << "*"; if ((g1!=pin1) || (g2!=pin2) || (g3!=pin3) || (g4!=pin4)) { cout << "\nDie Geheimzahl ist falsch!\n"; goto neueEingabe; } } 3D26E882-2673-8602.doc/05.07.02/dr.b. 57 int betragseingabe() { neueEingabe: // Sprungmarke für goto-Befehl cout << "\nBitte geben Sie den auszuzahlenden Betrag an: "; int betrag; cin >> betrag; if ((betrag%10)!=0) { cout << "Der Betrag muß durch 10 teilbar sein!!!\n\n"; goto neueEingabe; // Gehe zur Sprungmarke neueEingabe } return (betrag); } void berechnung(int betrag) { int array[] = {1000, 500, 200, 100, 50, 20, 10}; int i; cout << "Sie erhalten:\n"; for (i=0;i<=7;i++) { int anzahl = betrag/array[i]; betrag = betrag - anzahl*array[i]; if (anzahl != 0) cout << setw(2) << anzahl << setw(6) << array[i] << "-Mark-Schein(e)\n"; } } 3D26E882-2673-8602.doc/05.07.02/dr.b. 58