1 Cassebaum, Skript zur Programmierung mit C++ Programmierung mit C++ Skript für Schüler in Kursen an Fachgymnasien mit dem Schwerpunkt Informationstechnik Thomas Cassebaum Berufsbildende Schulen III Magdeburg 10. Mai 2004 Fehlerbereinigte Version vom 22. August 2011 Cassebaum, Skript zur Programmierung mit C++ Quellenverzeichnis [ 1 ] Schulgesetz des Landes Sachsen-Anhalt in der Fassung vom 27.08.1996 „Verordnung zur Gestaltung der gymnasialen Oberstufe in der Sekundarstufe II" Beschluss der Kultusministerkonferenz vom 07.07.1972 i.d.F. vom 22.10.1999 [ 2 ] Einheitliche Prüfungsanforderungen in der Abiturprüfung (Beschluss der Kultusministerkonferenz vom 01.06.1979 i.d.F. vom 01.12.1989) [ 3 ] Rd. Erl. des MK vom 25. 05. 1994-3-83200-202: „Leistungsbewertung an allgemeinbildenden Schulen und Schulen des zweiten Bildungsweges", MBl. LSA NR. 40/94, S. 200 [ 4 ] Bannach, Cassebaum, Hering, Jung, Richter, Rumpf, Wüstemann Rahmenrichtlinien [RRL] Fachgymnasium Informationstechnik Land Sachsen-Anhalt, Kultusministerium, Magdeburg 2003 [ 5 ] Bannach, Cassebaum, Hering, Jung, Richter, Rumpf, Wüstemann Einheitliche Prüfungsanforderungen in der Abiturprüfung Informatik Beschluss vom 1.12.1989 [6 ] P.Prinz, U.Kirch-Prinz C++, Lernen und Professionell anwenden, Mitp-Verlag, Bonn 2003, ISBN 3-8266-0824-0 [ 7 ] P.Prinz, U.Kirch-Prinz C++, Das Übungsbuch, Testfragen mit Aufgaben und Lösungen Mitp-Verlag, Bonn 2003, ISBN 3-8266-0998-0, 2.Auflage [ 8 ] Sedgewick, Robert Algorithmen in C Addison Wesley, Bonn-München-Paris 1992, ISBN 3-89319-669-2 [ 9 ] Schildt, Herbert C/C++ gepackt Mitp-Verlag, Bonn 2001, ISBN 3-8266-0684-1 [ 10 ] Louis, Dirk C/C++ new reference Markt & Technik, München 2001, ISBN 3-8272-6121-X [ 11 ] Cassebaum, Thomas C++ Trainer 2.1, C++ Entwicklungsumgebung für Lernzwecke Magdeburg, 2000...2005 [ 12 ] Cassebaum, Thomas Lehrscript zur C++ Programmierung, Grundlagen der Softwareentwicklung BbS III Magdeburg, 1999 Borland® C++, Borland Delphi®, Turbo Pascal® sind Warenzeichen der Borland Inc. USA, MS Windows® 98, NT®, Me®, 2000®, XP® , MS Internet Explorer®, MS Word®, MS Office®, MS Excel®, MS Visual C++®, MS Visual Basic® sind Warenzeichen der Microsoft Inc. USA, EasyCode EasyCase® (C++) ist eine geschützte Bezeichnung der BKR Software Beratung und – entwicklung GmbH, Deutschland, Pentium® ist ein Warenzeichen der Intel Inc. USA. 2 Cassebaum, Skript zur Programmierung mit C++ 3 Inhaltsverzeichnis VORWORT ...................................................................................................................................................5 1 GRUNDLAGEN DER PROGRAMMIERUNG ...........................................................................................6 1.1 PROGRAMME UND PROGRAMMIERSPRACHEN ......................................................................................... 6 1.1.1 Programmbegriff........................................................................................................................ 6 1.1.2 Programmzustände, Tools und Entwicklungstätigkeiten .......................................................... 6 1.1.3 Maschinenorientierte Programmiersprachen ........................................................................... 7 1.1.4 Problemorientierte Programmiersprachen ............................................................................... 8 1.2 DIE INTEGRIERTE ENTWICKLUNGSUMGEBUNG C++ TRAINER 2.X ................................................................ 9 1.2.1 Bedienelemente des C++ Trainers ............................................................................................. 9 1.2.2 Die Entwicklungsumgebung SmallCpp..................................................................................... 10 1.2.3 Erstes Übungsprogramm ......................................................................................................... 11 1.3 VARIABLEN UND DATENTYPEN ............................................................................................................ 12 1.3.1 Variablen .................................................................................................................................. 12 1.3.2 Datentypen .............................................................................................................................. 12 1.3.3 Tastaturein- und Bildschirmausgaben ..................................................................................... 13 1.4 OPERATOREN UND AUSDRÜCKE .......................................................................................................... 14 1.4.1 Operatoren .............................................................................................................................. 14 1.4.2 Numerische Ausdrücke ............................................................................................................ 15 1.4.3 Logische Ausdrücke.................................................................................................................. 15 Übungsaufgaben .................................................................................................................................. 16 1.5 STRUKTURANWEISUNGEN .................................................................................................................. 17 1.5.1 Sequenz .................................................................................................................................... 17 1.5.2 Selektion .................................................................................................................................. 17 1.5.3 Mehrfachauswahl (Fallunterscheidung) .................................................................................. 19 1.5.4 Kopfgesteuerte Schleifen ......................................................................................................... 20 1.5.5 Fußgesteuerte Schleife ............................................................................................................ 22 1.6 ALLGEMEINE PROBLEME ZUR SOFTWAREENTWICKLUNG .......................................................................... 24 1.6.1 Wasserfallmodell für den Lebenszyklus einer Software .......................................................... 24 1.6.2 Struktogramme ........................................................................................................................ 25 1.6.3 Trockentests............................................................................................................................. 26 2 ELEMENTARE EINFÜHRUNG IN C/C++ ............................................................................................. 28 2.1 FUNKTIONEN ................................................................................................................................... 28 2.1.1 Funktionsdefinition .................................................................................................................. 28 2.1.2 Prototypen ............................................................................................................................... 28 2.1.3 Funktionsparameter ................................................................................................................ 29 2.1.4 Die main() - Funktion ............................................................................................................... 29 2.1.5 Datenkapseln ........................................................................................................................... 30 2.1.6 „call by value“ und „call by reference“ .................................................................................... 30 2.1.7 Rekursionen ............................................................................................................................. 31 2.1.8 Funktionsüberladung ............................................................................................................... 32 Cassebaum, Skript zur Programmierung mit C++ 4 2.2 ARRAYS .......................................................................................................................................... 33 2.2.1 Ein- und mehrdimensionale Arrays (Felder) ............................................................................ 33 2.2.2 Zufallszahlen ............................................................................................................................ 33 2.2.3 Strings ...................................................................................................................................... 34 2.3 ADRESSEN UND ZEIGER...................................................................................................................... 36 2.3.1 Adressen .................................................................................................................................. 36 2.3.2 Zeiger (Pointer) ........................................................................................................................ 36 2.3.3 Zeiger und Strings .................................................................................................................... 38 2.3.4 Mehrfachzeiger ........................................................................................................................ 39 2.3.5 Zeigerarrays ............................................................................................................................. 39 3 GRUNDLEGENDE ALGORITHMEN .................................................................................................... 41 3.1 DYNAMISCHER SPEICHER („HEAP“) ..................................................................................................... 41 3.1.1 Speicherzuweisung .................................................................................................................. 41 3.1.2 Beispiel für dynamischen Speicher .......................................................................................... 42 3.2 EINIGE EINFACHE ALGORITHMEN ......................................................................................................... 43 3.2.1 Sortierung ................................................................................................................................ 43 3.2.2 Vertauschen zweier Werte ...................................................................................................... 43 3.2.3 Fakultät (Rekursion) ................................................................................................................. 44 3.2.4 Näherungswertbestimmung für den Sinus .............................................................................. 44 3.2.5 Euklidischer Algorithmus (ggT) ................................................................................................ 44 3.2.6 Sieb des Erastothenes (Primzahlen) ........................................................................................ 44 4 OBJEKTORIENTIERTE PROGRAMMIERUNG...................................................................................... 45 4.1 STRUKTUREN UND UNIONS (OHNE „OOP“) .......................................................................................... 45 4.1.1 Strukturen ................................................................................................................................ 45 4.1.2 Unions ...................................................................................................................................... 46 4.2 KLASSEN ......................................................................................................................................... 47 4.2.1 Objekt und Klasse .................................................................................................................... 47 4.2.2 Klassendefinition in C++ ........................................................................................................... 48 4.2.3 Objektbildung und –zugriff ...................................................................................................... 48 4.2.4 Konstruktor und Destruktor..................................................................................................... 49 4.2.5 Vererbung und Aggregation .................................................................................................... 49 4.2.6 Textdateien/ Streams .............................................................................................................. 51 4.3 LISTEN ............................................................................................................................................ 51 4.3.1 Liste, einfach verkettet ............................................................................................................ 51 4.3.2 Liste, doppelt verkettet............................................................................................................ 53 5 AUFGABEN ZUR PRÜFUNGSVORBEREITUNG ................................................................................... 55 5.1 THEORETISCHE FRAGEN, OHNE PC SCHRIFTLICH ZU LÖSEN ....................................................................... 55 5.2 PRAKTISCHE, AM PC ZU LÖSENDE AUFGABE .......................................................................................... 56 Index ......................................................................................................................................................... 56 KURZÜBERSICHT ....................................................................................................................................... 59 Cassebaum, Skript zur Programmierung mit C++ Vorwort Liebe Leser, das vorliegende Skript habe ich zur Unterstützung des Unterrichts im Programmierungsteil zum Profilfach „Informationstechnik“ im Fachgymnasium Technik geschaffen. Das Skript ist keinesfalls als Ersatz für ein umfassendes Lehrbuch zum gewählten Thema gedacht. Es soll vielmehr eine Gesprächsgrundlage zwischen Lehrer und Schüler darstellen, die dem Lehrer die Unterrichtsführung erleichtert und gleichzeitig das Lernen der Schüler auch bei der Vorbereitung von Klausuren oder Prüfungen vereinfachen soll. Die Idee dazu entstand parallel zu meiner Arbeit als Lehrer an der Berufsbildenden Schule „Otto von Guericke“ in Magdeburg und als langjähriges Mitglied der Arbeitsgruppe zur Erstellung der Rahmenrichtlinien und der Aufgaben für die schriftlichen Abiturprüfung im genannten Profilfach für das Fachgymnasium im Auftrag des Kultusministeriums des Landes Sachsen-Anhalt seit 1999. In diesem Skript werden nur die Themen zu den Profilfachbestandteilen der Kursstufen besprochen, die sich mit dem Thema „C++-Programmierung“ beschäftigen. Die Themen „Systemanalyse“, „Technische Kommunikation und Netzwerke“ und „Datenbanken“ werden nicht behandelt. Ausdrücklich sei gesagt, dass die von mir benutzte Programmiersprache C/C++ in den Rahmenrichtlinien für Fachgymnasien der meisten Bundesländer empfohlen oder gar vorgeschrieben wurden. Nach Gesprächen mit Vertretern der Praxis und meinen eigenen gesammelten Unterrichtserfahrungen begrüße ich diese Entscheidung. Ich verwende für die Durchführung von praktischen Schülerübungen und als Hilfsmittel für die Lösung der gestellten Programmieraufgaben die IDE „C++ Trainer“ in der aktuellen Version (August 07: 2.3.1). Diese auf dem freien Borland-C++ Compiler 5.5 basierende vollwertige C++ Entwicklungsumgebung mit didaktischen Unterstützungselementen für Lernende ist besonders leicht bedienbar und kann von meiner Webseite www.t-cassebaum.de im Download-Verfahren beschafft werden. Bitte beachten Sie vor der Installation die Lizenzbedingungen! Für Besitzer von 64-Bit-Computern ist der C++ Trainer leider ungeeignet. Deshalb nutze ich für diese Technik die noch im Aufbau befindliche Software „SmallCpp“. Es handelt sich um eine sehr kleine, aber trotzdem leistungsfähige Entwicklungsumgebung, die für den Unterricht und die Vorbereitung sinnvoll eingesetzt werden kann. Am Ende des Skripts finden Sie schliesslich eine kurze Übersicht zu den behandelten C- und C++Anweisungen, die auf zwei DIN A4 Doppelseiten Platz findet. Thomas Cassebaum 2011 5 6 Cassebaum, Skript zur Programmierung mit C++ 1 Grundlagen der Programmierung 1.1 Programme und Programmiersprachen 1.1.1 Programmbegriff Ein Computer besitzt aus der Sicht der Hardware die Fähigkeit, Maschinenprogramme abzuarbeiten. Das Maschinenprogramm besteht aus einer Folge von Prozessorbefehlen (Bitmuster), deren Realisierung durch den technischen Aufbau der Hardware (insbesondere des Prozessors) gewährleistet ist. Ein Maschinenbefehl oder Prozessorbefehl ist eine duale Codierung, die den Prozessor zu einer bestimmten Tätigkeit veranlasst. Abb. 1 S o f t w a r e Befehl 1 H a r d w a r e Prozessor Befehl 2 Befehl 3 … Befehl n Programm Ein Programm ist eine Verfahrensfestlegung mit Hilfe einer Befehlsfolge. 1.1.2 Programmzustände, Tools und Entwicklungstätigkeiten Ein Programm wird zunächst z.B. zeichnerisch als Struktogramm entworfen. Dann wird der codierte Programmtext (Q Quelle) über Tasteneingabe mit einem Editor erfasst („e editiert“). Der Compiler übersetzt den Text in Maschinencode, es entsteht das Objekt. Der Linker bindet dieses Objekt mit anderen notwendigen Objekten zum Task. Mit dem Debugger testet man das Programm. Nach dem Start belegt das Programm als „P Prozess“ Teile des Arbeitspeichers, von denen das Betriebssystem (z.B. Windows) die Programmabarbeitung leitet. Tools Tätigkeiten Zustände Editor Erfassung/ Bearbeitung des Quelltextes Quelle (.cpp) Compiler Übersetzung des Quelltextes (Borland 5.5) Objekt (.obj) ja Linker Fehler? Hilfstools StruktogrammEditor (Entwerfen) nein Verbindung mit C++Umgebungsmoduln Task (.exe) Texteditor (Dokumentie- ja Debugger Fehler? ren) nein Testen und Fehler finden ja Fehler? nein Start Prozess Tafel 1 7 Cassebaum, Skript zur Programmierung mit C++ 1.1.3 Maschinenorientierte Programmiersprachen Eine Programmiersprache, die genau eine Mnemonik (sprachliches Kürzel. z.B. „MOV“) für jeden Prozessorbefehl besitzt, bezeichnet man als Assemblersprache. Maschinen- und Assemblersprachen werden in der Informatik maschinenorientierte Programmiersprachen genannt. Eine Quelle ist ein Text (Folge von ASCII-Zeichen), der symbolische Befehle (meist in englischer Sprachanlehnung) enthält. Die Quelle wird in einer Quelldatei auf einem Datenträger gespeichert. Ein Assembler ist ein Übersetzungsprogramm, das einen symbolischen Befehl im Verhältnis 1:1 in einen binären Maschinenbefehl übersetzt. Das Ergebnis der Übersetzung ist das Objekt, dessen Inhalt, eine Folge von binären Prozessorbefehlen, als Binärdatei („O Objektdatei“) auf einem Datenträger (z.B. Festplatte) gespeichert wird. Beim Linken werden weitere für die Verarbeitung notwendige Objekte aus der Entwicklungsumgebung (z.B. Borland C++ Builder) zu einer gemeinsamen, startbaren Datei verbunden. Man nennt ein solche startfähige Datei “T Task“, "EXE-File", "ausführbares Programm", „executable binary file“ oder "startbares Programm". Sie wird auf einem Datenträger mit einem Namen gespeichert und von dort gestartet. Menschliche Sprache Programmiersprache Maschinensprache Addieren, Sortieren, Vergleichen, Suchen, ... Cout, cin, if, while, then, do, k++, k=k+12, ... 1100111100001011, 0011101111000011, ... Beispiel einer mnemonischen Befehlsfolge im Assembler einer Registermaschine: Operationsteil LD ADD STORE Operandenteil (hexadezimal) (Laden in den Akku) (Addieren zum Akku) (Speichern des Akkus) 1000 (Speicherstelle der zu lesenden Größe) 1004 (Speicherstellen der Summanden) 1008 (Angabe der Speicherstelle des Ziels) Um vom Prozessor ausgeführt werden zu können, müssen - da der Computer nur die Zustände 0 und 1 unterscheiden kann - auch die Befehle in binärer Form angegeben sein. Sind die Anweisungen in Binärcodes dargestellt, spricht man von einer Maschinensprache. Sie kann vom Prozessor unmittelbar (direkt) verstanden werden. Befehlsmnemonik (8086 -Assembler) Beispiel für einen Maschinenbefehl: Der Beispielbefehl füllt das 16-BitRegister AX („Akku“) mit dem Inhalt des Speicherplatzes, der durch die symbolische Adresse x erkannt wird. Ein Register ist ein kleiner Speicherbereich direkt im Prozessor. MOV 00010100 Operationsteil Prozessor CX-Register AX , 00011101 1. Operand x 11101111 2. Operand Arbeitsspeicher (RAM) x (Adresse) BX-Register AX-Reg. Akku Speicherplatz „x“ (16 Bits) Die binären Codes der Maschinenbefehle sind durch den benutzten Prozessortyp vorgegeben. Jeder Prozessortyp besitzt eine eigene, nur ihm verständliche Befehlsliste. Die Gesamtheit dieser Befehlscodes für einen Prozessortyp wird auch "M Maschinensprache" genannt. Es ist zwar möglich, mit Hilfe der binären Codes der Maschinensprache Programme zu codieren. Eine Codierung mit binären Befehlscodes durch den Menschen ist jedoch vergleichsweise schwierig und umständlich zu bewerkstelligen, weil die binären Zahlenfolgen der menschlichen Kommunikationsstruktur recht fremd sind. Cassebaum, Skript zur Programmierung mit C++ 1.1.4 Problemorientierte Programmiersprachen Programmiersprachen, deren Befehlssymbole vorrangig am zu lösenden Problem orientiert und damit für Menschen besser fassbar sind, bezeichnet man als problemorientierte Programmiersprachen. Ein symbolischer Befehl wird bei der Übersetzung in mehrere Maschinenbefehle - im Verhältnis 1:n – verwandelt. Populäre problemorientierte Programmiersprachen sind: ADA, (VISUAL-) BASIC, C, C++, Cobol, Delphi, Fortran, Java, (Turbo-)Pascal, Python, usw... Es existieren zwei Prinzipien zur Übersetzung eines problemorientierten Quelltextes: 1. Bei Verwendung eines Interpreters wird jeder symbolische Befehl des Quellprogramms unmittelbar vor seiner echten Realisierung einzeln durch den Prozessor übersetzt. Vom Interpreter wird also keine Objektdatei mit einer Folge von Prozessorbefehlen erzeugt und gespeichert. Damit verlängert sich die Abarbeitungszeit um die benötigte Übersetzungszeit. Programmierer arbeiten gern mit diesem Verfahren bei der Softwareentwicklung, weil die zu entwickelnden Programme nach Quelltextänderungen zur Beseitigung von Programmfehlern besonders schnell wieder ausgeführt werden können. Nach Fertigstellung der Software wird aber zur Optimierung der endgültigen Programmgeschwindigkeit dennoch ein Compiler zur Übersetzung eingesetzt. 2. Ein Compiler ist ein Übersetzungsprogramm, das die symbolischen Befehle einer problemorientierten Sprache aus einer Quelldatei vollständig in eine Folge binärer Maschinenbefehle einer abzuspeichernden Objektdatei verwandelt. Die Vorteile des Einsatzes von problemorientierten Sprachen sind die günstige, vereinfachte Programmentwicklung und die Portierbarkeit (Überführbarkeit in andere Systeme) der Lösungen. Lösungen mit maschinenorientierten Sprachen besitzen meist eine bessere rechentechnische Qualität (kurze Laufzeit, geringer Speicherplatzbedarf), weil sie der Maschinenstruktur besser angepasst sind. Hybridprogramme werden auf Basis problemorientierter Sprachen hergestellt, in denen einzelne rechentechnisch besonders relevante Bestandteile maschinenorientiert programmiert werden. Damit wird versucht, alle Vorteile der jeweiligen Sprachfamilien zu nutzen und deren Nachteile zu vermeiden. Übungsaufgaben 1. Nennen Sie Ihnen bekannte dreibuchstabige Programmdateitypen bei der Softwareentwicklung! Ordnen Sie dabei die Begriffe Quelle, Objekt, Task und Prozess zu! 2. Nennen Sie 3 allgemeine Übersetzertypen und erläutern Sie deren verschiedene Funktionsweisen! 3. Inwieweit unterscheidet sich die Arbeit des Linkers von der eines Compilers? 4. Erläutern Sie Unterschiede der problem- und maschinenorientierten Programmiersprachen! 5. Ist die Assemblersprache eine maschinenorientierte oder eine Maschinensprache? 6. Erklären Sie die Begriffe Datei, Verzeichnis, Programm, Maschinenbefehl, Befehlsbreite, modular, Projekt, Sequenz, Selektion, Iteration, E-V-A, Portierbarkeit und Hybridprogramm! 7. Welche Teilprozesse müssen bei der Entwicklung eines lauffähigen Programms durchlaufen werden? Erklären Sie die Ergebniszustände des zu entwickelnden Programms und die möglichen Fehler! In welcher Form (Speicherort und Codierung) liegen die Zustände vor? 8. Was sind syntaktische und was logische Programmfehler bei der Implementierung? 9. Nennen Sie mindestens 5 problemorientierte Programmiersprachen! Was sind „Dialekte“ und was „Versionen“ von Programmiersprachen? 10. Versuchen Sie, die Bedeutung des Begriffes „Skriptsprache“ durch Literatur- und/oder InternetRecherche selbst zu erkennen. Erklären Sie die Vor- und Nachteile dieser Sprachfamilie. 8 9 Cassebaum, Skript zur Programmierung mit C++ 1.2 Die integrierte Entwicklungsumgebung C++ Trainer 2.x 1 Für eine Softwareentwicklung empfiehlt sich der Einsatz eines speziellen Softwaresystems, das abgekürzt als „IIDE“ bezeichnet wird. Der Begriff IDE steht für Integrated Development Environment, deutsch: Integrierte Software-Entwicklungs-Umgebung. Es handelt sich um eine Sammlung von zueinander passenden Programmen, die für eine effektive Softwareentwicklung notwendig sind. Bei der Sprache C++ sind das Programme der C++ -Sprachumgebung, passende Toolprogramme und das sogenannte „front end“, das alles bequem durch den Programmierer ansteuerbar macht. Profi-IDE’s sind z.B. der Borland C++ Builder, MS Visual C++, Borland Delphi, MS Visual Basic die im Softwarehandel wie jede andere kommerzielle Software erhältlich sind. Die Lern-IDE C++ Trainer 2.3 kann frei unter http://www.t-cassebaum.de heruntergeladen werden. Empfehlenswert ist als weiterer Download von dieser Seite die ebenfalls freie Demoversion des Struktogramm-Tools Easycode EasyCase (C++) 6.8. Dieses Tool entwickelt aus gegebenen C/C++ Programmen Struktogrammzeichnungen oder schreibt umgekehrt automatisch generierte C/C++ Quellen anhand mit diesem Tool gefertigter Struktogramme. 1.2.1 Bedienelemente des C++ Trainers Neue Quelldatei Quelle öffnen/ speichern Struktogramm zeigen Quelle drucken Breakpoints Starten Debugger Hilfe ein/aus Bookmarkfinder Snippets für C++ zeigen Einrücken der C++Zeilen Snippets Text klein - groß Easycode Beamereinstellung ein/ aus Hinweise und Fehlermeldungen Assemblerquelle Statuszeile Abb. 2 Wichtige Bedienfunktionen der IDE „C++ Trainer 2.3“ Mit dem C++Trainer können C/C++/Assembler- Quellen eingegeben, übersetzt, getestet, gedruckt, gespeichert und wieder geöffnet werden. Für den Test stehen sofort nach der Installation geeignete Debugger für C++ und Assembler startbar zur Verfügung. 1 Cassebaum, Thomas, C++ Trainer 2.x, C++ Entwicklungsumgebung für Lernzwecke, Magdeburg, 2000...2007 10 Cassebaum, Skript zur Programmierung mit C++ Als didaktische Bestandteile besitzt diese IDE sogenannte Snippetlisten, die als Seitenleisten einfach die C++ Grundbestandteile erklären und rufen lassen. Viele der Snippets lassen sich mit HotKeys (z.B. Strg/F fügt in den Quelltext eine for-Anweisung ein) aufrufen. Als weiterer Zusatz existiert ein Verzeichnis „Lehre“, das neben ausgewählten Tafelbildern („Lehrseiten“) auch verlinkte Beispiele, Übungsaufgaben und deren Lösungen enthält. Wie die Programmhilfen werden die Fehler- und Warnmeldungen in deutscher Sprache gegeben. Die Darstellung mit dem Beamer wird in der Software „C++ Trainer“ mit einem Spezialbutton unterstützt, das alle Programmtextzeichen in vergrößerter, dicker und gut lesbarer Schriftart zeigt. Neben der C/C++ Syntax werden auch Quellen in Intel-Assembler, HTML, PHP, XML und DOS-Batches farbig syntax-highlighted dargestellt und können geändert und getestet werden. Einfache Texte lassen sich als RTF-Files speichern und mit Textformaten leicht austauschen. Es werden alle in den Rahmenrichtlinien geforderten Programmiertechniken unterstützt. Der C++Trainer kann aber auch echte Windows-Lösungen, OpenGl-Grafikprogramme und alle anderen C++ Programme schaffen, die durch den freien Compiler „C C++ Builder 5.5 free command line tools“ erstellt werden können. 1.2.2 Die Entwicklungsumgebung SmallCpp Diese noch neue Möglichkeit, besonders einfach C++-Entwicklungen durchzuführen, kann auch an 64-Bit-Systemen genutzt werden. Es gibt viele Ähnlichkeiten mit dem C++ Trainer. Drucken des aktuellen Quelltextes Neue Quelle mit Template öffnen Gespeicherte Quelldatei öffnen Speichern der aktuellen Quelle Speichern akt. Quelle an neuem Ort Alle offenen Quellen speichern Markierten Text ausschneiden Markierten Text kopieren Einfügen der Zwischenablage Markierten Text löschen Letzte Aktion rückgängig machen Letzte rückgäng. Aktion wiederholen Suchen und Ersetzen Lesezeichen in Cursorzeile setzen Lesezeichen in Cursorzeile entfernen Vor/Zurück zum nächsten Lesezeichen Abb. 3 Editorfenster Ausgabefenster Auch die Mini-IDE SmallCpp läßt sich von der Download-Seite http://www.t-cassebaum.de kostenfrei herunterladen. Ausgabefenster zeigen/ verbergen Schrift vergrößern/ verkleinern Debugger starten Übersetzen, Linken und Starten Hilfe zu C/ C++ Aufdecken versteckter Kommentare Lesezeichen („Bookmark“) Zeilennummern ein-/ ausschalten Alle Kommentare zeigen/ verstecken Nach der fertigen Eingabe eines Quelltextes im Editorfenster sollte er zunächst mit einem neuen Namen abgespeichert werden. Danach erfolgt Übersetzen, Linken und Start des Programmes in einem Schritt. Sollte das Programm nicht starten, werden im Ausgabefenster Fehler und Warnungen angezeigt. TempSrc.cpp 10: Call to undefined function 'IF' in function main() In diesem Fall wurde in der Zeile 10 eine Anweisung falsch mit Großbuchstaben eingegeben. Die Fehler müssen alle durch Änderung des Quelltextes beseitigt werden. Erst danach kann der erste Programmstart gelingen. Warnungen weisen auf eine ungenaue Programmierung hin, die erst nach tieferen Kenntnissen zur Sprache C++ erkannt und verbessert werden können. Mit der rechten Maustaste kann in das Editorfenster geklickt ein Menü aktiviert werden und das Ausgabefenster sichtbar und wieder unsichtbar gemacht werden. 11 Cassebaum, Skript zur Programmierung mit C++ 1.2.3 Erstes Übungsprogramm Das denkbar einfachste C++ Programm wird, wie auch in anderen Programmiersprachen, mit dem so genannten "Hello-world-Programm" vorgeführt. Der Hauptteil des Programms wird Hauptfunktion als bezeichnet und mit main() eingeleitet. Die folgenden, zwischen geschweiften Klammern angeordneten Anweisungen, werden unmittelbar nach dem Programmstart mit dem ersten Befehl beginnend nacheinander ausgeführt. Falls keine „return“-Anweisung zum Programmabbruch führt, wird das Erreichen der zur main()Funktion gehörigen schließenden geschweiften Klammer das Programm beenden. Zur Ausgabe des kurzen Textes auf dem Bildschirm kann die C++ -Ausgabefunktion "cout" benutzt werden. C++ ist „modularisiert“, d.h. nicht alle Funktionen sind ohne zusätzliche Modul-Anforderung erreichbar. Die Bibliotheks-Funktion "cout" (Standardausgabe) erfordert das Einfügen des Headers "iostream" mit der Präprozessor-Anweisung #include. Wird diese Einfügung vergessen, ist "cout" eine dem Compiler unbekannte Zeichenfolge. // Th.Cassebaum, 13.8.2011, all rights reserved #include <iostream> // Header für cout using namespace std; int main() { cout << "Hello world!"; getchar(); // Warten auf Tasteneingabe return 0; // Programm beenden mit Code 0 } // Ende der main()-Funktion Hello world! Der Präprozessor ist ein Programm, das die Quellzeilen, die mit einer Raute # beginnen, schon vor dem Compiler automatisch auswertet. #include führt zum Einfügen aller Zeilen einer beliebigen Textdatei anstelle der #include-Zeile. Im Beispiel wird die Textdatei „iostream.h“ eingefügt, die für nahezu jedes C++-Programm erforderlich wird. Die Anweisung using namespace std; stellt den Standard-Namensraum „std“ ein. Header (*.h / *.hpp) sind Textdateien, die C/C++ -Zeilen enthalten, die vom Compiler übersetzt werden. Der Header iostream.h ermöglicht beispielsweise den Zugriff auf die E/A-Stream-Bibliothek ( in der neben cout noch andere E/A-Funktionen enthalten sind ) von C++. Wird der Headername in <…> eingeschlossen, wird die Datei im include-Verzeichnis des Compilers gesucht. Falls er in “…“ eingeschlossen ist, wird sie im Verzeichnis der .cpp - Quelldatei gesucht. Beispielaufgabe 1 Das Programm fordert zur Eingabe eines Namens auf, speichert diesen Namen und begrüßt den Nutzer mit seinem Namen. z.B. „Guten Tag Paul. Wie geht’s?“ Kommentieren Sie jede Programmzeile. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 /* Thomas Cassebaum 2011, all rights reserved Mehrzeiliger Kommentar wird nicht vom Compiler bearbeitet beginnt mit: /* und endet mit: */ #include <iostream> // Zeile mit # ist für den Präprozessor, lädt Header "iostream" // Einzeiliger Kommentar beginnt mit // und endet am Zeilenende using namespace std; // Stellt den Standard-Namensraum "std" ein int main() // Erste Zeile der main-Funktion (Hauptfunktion) { string s; // Variable: s vom Datentyp: string cout << "Name: "; // Ausgabe der Ausschrift mit Leerzeichen am Ende cin >> s; // Eingabe von Tastatur wird in der Variablen s gespeichert cout << "Guten Tag " << s << ". Wie geht's?"; // Ausgabe des Antwortsatzes getchar(); // Wartet auf die Eingabe einer beliebigen Taste return 0; // Liefert Rückkehrcode der main-Funktion (0 bedeutet: Ablauf gut) } // Eine schließende geschweifte Klammer schließt die Funktion ab Aus- und Eingaben des Programmes nach dem Start: Name: Tim Guten Tag Tim. Wie geht’s? 12 Cassebaum, Skript zur Programmierung mit C++ 1.3 Variablen und Datentypen 1.3.1 Variablen In C/C++ ist eine Variable ein Datenobjekt mit veränderlichem Wert, das einen Namen und einen Datentyp besitzt, sowie einen Speicherplatz einer festgelegten Länge belegt. Variablen müssen vor ihrer ersten Verwendung für einen bestimmten Datentyp deklariert werden: <datentyp><Bezeichner>[,<Bezeichner>[,...]]; // z.B.: int x, y; Ein Bezeichner in C++ besteht aus einer Folge von Groß-/ Kleinbuchstaben, Ziffern oder der Unterstreichung _ . Das erste Zeichen darf keine Ziffer sein. Der Bezeichner darf beliebig lang sein, nur 250 Zeichen werden zur Erkennung benutzt und gelten als "signifikant". Schlüsselwörter der Sprache C++ - z.B. if, int, while, void, ... - dürfen nicht als Bezeichner genutzt werden. Bezeichner identifizieren C++ Programmelemente (z.B. Variablen, Strukturen, Funktionen, ... ). C++ unterscheidet bei Bezeichnern streng zwischen Groß- und Kleinbuchstaben!! Variablen erhalten durch eine Zuweisung ("Ergibtanweisung") in der Form: <variable_typ1> = <Ausdruck_typ1>; einen Wert. Der Wert errechnet sich durch einen Ausdruck, der von gleichem Datentyp wie die Variable ist oder in diesen automatisch konvertiert werden kann. Die Zuweisung kann schon in der Deklaration erfolgen. void main() { int var, VAR, Meine_Lieblingsvariable= 0; var = -3; VAR = 4; Meine_Lieblingsvariable = var + VAR; cout << Meine_Lieblingsvariable; getchar(); } 1 Im Beispiel werden drei Variablen im ganzzahligen Datentyp (int) deklariert. Die Variable "Meine_Lieblingsvariable" speichert nach der Addition var + VAR den Wert 1.3.2 Datentypen Jede Variable besitzt einen Datentyp, der die Art der Inhaltswerte und die Bytelänge klärt. Die Bytelänge ist die Anzahl der Bytes, die eine gespeicherte Variable dieses Datentyps im Speicher belegt. Typbezeichner in C++ sind z.B.: Bytes Typ 10 long double 8 double 4 float 4 int 2 short int 4 unsigned int 1 char ? string 1 bool 0 void int x, y; x = 0xff; Tafel 2 geeignet für sehr genaue reelle Zahlen (bis 18 Stellen) reelle Zahlen (bis 15 Stellen) wenig genaue reelle Zahlen (bis 7 Stellen) ganze Zahlen (-2.147.483.648...2.147.483.647) ganze Zahlen (-32.768...32.767) natürliche Zahlen (0...4.294.967.295) Zeichen (0...255) Zeichenketten (Klasse string) logische Werte (true oder false) leer (ohne Wertrückgabe, main() ohne return) bool a; a = true; double b; b = 1.2-02; string s; s = "\nJa"; Wertkonstante 123456.789012345678 -0.123456789012345 1.234567E02 -0x25 (0x: hexadezimal) +321 12 'a' "Zeichen abc" true char c; c = 'v'; y = x; Variablen dürfen auch schon in ihrer Definition initialisiert werden. z.B. char w='a'; int x=7; Nicht initialisierte Variablen behalten die zufälligen vorherigen Werte der Speicherbytes. Cassebaum, Skript zur Programmierung mit C++ 1.3.3 Tastaturein- und Bildschirmausgaben Tastatureingaben werden mit „cin >>“und Bildschirmausgaben mit „cout <<“eingeleitet. Mit cout << wird eine für den Bediener sichtbare Bildschirmdarstellung erzeugt. Als Ziel für Eingaben mit Hilfe von cin >> werden Variablen vereinbart (Beispiel: s und t). Die Variablen erhalten einen Typkennzeichner in der Definitionszeile (Beispiel: double). Beispielaufgabe 2 Das Programm fordert zur Eingabe eines Weges in Metern und einer Zeit in Sekunden auf, speichert diese in Variablen passenden Typs. Danach wird die Geschwindigkeit errechnet und in m/s und km/h auf dem Bildschirm kommentiert ausgegeben. 01 02 03 04 05 06 07 07 08 09 10 11 #include <iostream> Geschwindigkeitsberechnung using namespace std; int main() Weg s [in m] : 30 { double s,t; Zeit t [in s] : 5 cout << "\"Geschwindigkeitsberechnung\"\n"; cout << "\nWeg s [in m] : "; cin >> s; Geschwindigkeit : 6 m/s cout << "Zeit t [in s] : "; cin >> t; oder 21.6 km/h cout << "\nGeschwindigkeit : " << s/t << " m/s" << "\noder " << s/t * 3.6 << " km/h"; getchar(); // Wartet auf die Eingabe einer beliebigen Taste return 0; // Liefert Rückkehrcode der main-Funktion (0 bedeutet: Ablauf gut) } // Eine schließende geschweifte Klammer schließt die Funktion ab Einzel-Zeichen (engl.: character) werden in Apostrophen eingeschlossen (z.B.: '$') und bei Eingaben in Variablen vom Datentyp char gespeichert. C++ - Zeichenketten werden in Anführungsstrichen eingeschlossen (z.B.: "Kette") und bei Eingaben in Variablen vom Datentyp string gespeichert. Für Ausgaben können spezielle Zeichenfolgen innerhalb der Anführungszeichen einer auszugebenden Zeichenkette eine besondere Steuerung veranlassen. Steuerfolgen sind z.B.: \n → Nächste Zeile einstellen \t → Tabulatorabstand setzen \a → Piepsignal ausgeben \" → auszugebende Anführungsstriche " \\ → auszugebendes Einzel-Backslash \ Übungsaufgaben 11. Benennen Sie den Datentyp zur Speicherung folgender Wertvorgaben: a) natürliche Zahlen im Bereich von 0...25334 b) Ganze Zahlen (z.B. –3452, 0, +23, ...) c) die reellen Zahlen 12.1234567890123 bis zur letzten Stelle d) Nachnamen von Personen (z.B.“Krause“, “Lehmann“, ... Einzelne Buchstaben (z.B. ’a’,’b’,’c’,...) e) Logische Aussagen (true oder false) f) Ganze Zahlen (z.B. –3452, 0, +23, ...) g) In Größe soll nichts gespeichert oder zurückgegeben werden. h) Ganze Zahlen (z.B. –3452, 0, +23, ...) 12. Sie sehen eine Liste von insgesamt zehn C-Datentypen: a) long int b) int c) unsigned int d) signed int e) char f) string g) real h) long double i) float j) bool. Bestimmen Sie für alle 10 Typ-Buchstaben die richtige Datentyp-Zahl als Wertepaar. (Beispiel: a-3) (1) vorzeichenbehafteter Ganzzahlentyp (6) Arraydatentyp (11) einfacher Ganzzahltyp (2) einfacher reeller Typ (7 Stellen genau) (7) Zeichentyp (12) logischer Datentyp (3) doppelt genau reell (15 Stellen genau) (8) Ganzzahl (8Byte Länge) (13) Zeichenkettentyp (4) Zahlentyp der Reallogik (9) unsichtbarer Datentyp (14) Kommafolgentyp (5) langer Zeichenkettentyp (10) Typ für natürliche Zahlen (15) kein C-Datentyp 13. Geben Sie den C-Datentyp an, der zur Speicherung folgender Daten am besten geeignet ist: a) Alter eines Menschen b) Rauminhalt eines Hauses c) Kapazität eines Kondensators d) Kfz-Kennzeichen e) Telefonnummer (mit Fernwahl) f) Namen der Schüler einer Klasse g) Möglichst genaue Speicherung der Zahl (Pi) h) Geschlecht einer Person i) Das Geburtsdatum einer Person k) genaueste mögliche Zeitdauer 13 14 Cassebaum, Skript zur Programmierung mit C++ 1.4 Operatoren und Ausdrücke 1.4.1 Operatoren Operatoren beziehen sich auf einen oder zwei Operanden und liefern ein operationstypisches Resultat. Größen (z.B. Variablen, Werte, ...) der Sprache C++, die mit Operanden einfach oder vielfach verknüpft wurden, nennt man Operation oder Ausdruck. x = y+3; „y“ und „3“ sind Operanden, „+“ ist ein Operator, „y+3“ ist eine Operation. Die Operanden und das Resultat besitzen einen operationsabhängigen Datentyp. Die Einteilung der Operatoren in Gruppen geschieht in Abhängigkeit der nutzbaren Datentypen. Wichtige Operatoren: numerische Operatoren ++ (Inkrement) -- (Dekrement) % (modulo) + (Addition) logische Operatoren ! (Negation) > (größer?) == (gleich?) != (ungleich?) * (Multiplikation) - (Subtraktion) / (Division) >= (größer gleich?) < (kleiner?) <= (kleiner gleich?) && (logisches "UND") || (logisches "ODER") bitweise Operatoren ~ (Komplement) >> (Rightshift) << (Leftshift) & (AND) ^ (XOR) | (OR) Zuweisungsoperatoren = (ergibt) += (plus gleich) -= (minus gleich) *= (mal gleich) /= (durch gleich) &= (und gleich) %= (modulo gleich) sonstige Operatoren sizeof (Bytelänge) new (dynam. Speicher erstellen) delete[] (dynam. Speicher freigeben) typeid (Typidentifikation) (cast) (expliziter Typumwandler) <log.Ausdruck> ? <true-Wert> : <false-Wert> (Fragezeichenoperator) Beispiele: int x=2; x+=3<<1; cout << x; int y=11; cout << (--(y%5)); int x=5; cout << ((x-5)?5+x:x>>1); char x='A'; cout << x << "-" << (int)x; // // // // Ausgabe: Ausgabe: Ausgabe: Ausgabe: 8 0 2 A-65 Operatoren sind in eine Rangfolge geordnet, so dass innerhalb eines Ausdrucks zunächst die vorrangigen Operatoren realisiert werden. Ausdrücke mit Operatoren können mit Rundklammern geklammert werden, um die Operatoren in der Klammer im Rang zu bevorzugen. [()[]-> :: .][! ~ ++ -- sizeof new delete typeid (typumformer)] [.* ->* ][ * / % ][ + - ] [<< >> ][ < <= > >= ][ = = != ] Rangtabelle der Operatoren [ & ][ ^ ][ | ][ && ][ || ][ ?: ] [= += - = *= /= %= >>= <<= &= ^= ] Rangfolge aller Operatoren in eckigen Klammern [ … ] sind gleichrangig. Der Rang der Klammergruppen ist von oben nach unten absteigend, d.h. es gilt: „oben vor unten“. Der Rang der Klammergruppen ist von links nach rechts absteigend, d.h. es gilt: „links vor rechts“. Ohne Rundklammern werden gleichrangige Operatoren von links nach rechts abgearbeitet. Beispiele: 12/2+4 ergibt 10, 3+(x&&0) ergibt 3, aber: 12/(2+4) ergibt 2. aber: 3+x&&0 ergibt 4. 15 Cassebaum, Skript zur Programmierung mit C++ 1.4.2 Numerische Ausdrücke Numerische Ausdrücke <NA> sind alle C++ Bestandteile, die einen Zahlenwert besitzen. Wichtige Beispiele für numerische Ausdrücke sind: (1) (2) (3) (4) Logische Werte ( true besitzt den Wert 1, false besitzt den Wert 0 ), Zahlenwerte (Zahlkonstanten, ganzzahlig: 2, -4, 0xa, ... reell: 0., .3, 3.1e4,... ), C++Größen (Variablen, u.a.) mit numerischem Datentyp (int, float, double, ... ) Werte, die mit Operatoren verknüpft sind und ein numerisches Resultat liefern. (z.B.: 3>7 →0, 2!=3 →1, 5/3 →1, 7&12 →4, ~1 →-2, 5%3 →2, 5e1/5 →10.) Ausdrücke, die mit logischen Operatoren verknüpft sind und numerische Werte besitzen. (z.B.: 0&&true →false →0, (2>3)||(0!=1) →true →1, !(7==3)&&5 →true →1) (5) Beispiele für numerische Ausdrücke mit numerischem Ergebniswert: cout << "3 * 2 = " << 3 * 2; // 6 cout << "\n3 / 2 = " << 3 / 2; // 1 cout << "\n3 / 2. = " << 3 / 2.; // 1.5 cout << "\ntrue = " << true; // 1 cout << "\nfalse = " << false; // 0 cout << "\n0xa = " << 0xa; // 10 cout << "\n0xa = " << hex << 0xa; // a cout << "\n027 = " << dec << 027; // 23 cout << "\n027 = " << oct << 027; // 27 cout << dec << "\n7&12 = " << (7 & 12); // 4 cout << "\n5&3 = " << 5%3; // 2 cout << "\n5e1/5 = " << 5e2/50; // 10 (1 Rest 1) (hex a = dec 10) (hex a = hex a) (oct 27 = dec 23) (oct 27 = oct 27) (0111 & 1100 = 0100) (5/3 = 1 Rest 2) (5*10²/50 = 10) 1.4.3 Logische Ausdrücke Logische Ausdrücke <LA> sind alle C++ Bestandteile, die einen Wert true oder false besitzen. Wichtige Beispiele für logische Ausdrücke sind: (1) Logische Werte (Die Konstanten true (1) oder false (0) ), (2) Zahlenwerte (Ein Wert = 0 gilt per Definition false, alle Werte ungleich 0 sind true), (3) C++Größen (Variablen, Funktionsrufe, ...) mit Datentyp bool (besitzen einen log. Wert), (4) Werte, die mit Operatoren verknüpft sind und ein logisches Resultat liefern ( z.B.: 3>7→false, 2!=3→true, 7==3→false, "Hans">="Lutz" → false ) (5) Logische Ausdrücke, die mit logischen Operatoren verknüpft sind ( z.B.: 0&&true → false, (2>3)||(0!=1) → true, !(7==3)&&5 → true ). And && 1 0 1 1 0 0 Or || 1 0 not 0 1 1 1 1 0 0 0 1 0 0 1 ! Beispiele für logische Ausdrücke mit logischem Ergebniswert int i=2; bool a=false; double x=0.0; if (a) cout << "a ist true"; else cout << "a ist false"; if (i) cout << "i ist true"; else cout << "i ist false"; if (x) cout << "x ist true"; else cout << "x ist false"; if (i-2) cout << "i-2 ist true"; else cout << "i-1ist false"; if (!a) cout << "!a ist true"; else cout << "!a ist false"; cout<<"i==2||i==3 ";if(i==2||i==3)cout<<"true";else cout <<"false"; // // // // // // false true false false true true 16 Cassebaum, Skript zur Programmierung mit C++ Beispielaufgabe 3 Das Programm untersucht einen C++-Ausdruck hinsichtlich seines numerischen und logischen Wertes. Der numerische Wert wird als reelle Zahl und der logische als „true“ oder „false“ ausgegeben. 01 02 03 04 05 06 07 08 09 #include <iostream> using namespace std; int main() { string s = ((63/5)%7)?"true":"false"; cout << "numerisch: " << (double)((63/5)%7); cout << "\n logisch: " << s; getchar(); return 0; } numerisch: 5 logisch: true Beispielaufgabe 4 Das Programm untersucht die drei als Variablen a, b, c gegebenen möglichen Seitenlängen eines Dreiecks. Stellen Sie mit den Dreiecksungleichungen fest, ob die 3 Seiten ein Dreieck bilden können. Geben Sie das Ergebnis auf dem Bildschirm mit „Dreieck“ oder „kein Dreieck“ aus. 01 02 03 04 05 06 07 08 #include <iostream> using namespace std; int main() { float a=6, b=3, c=2.5; string s = (a+b>c)&&(a+c>b)&&(b+c>a)?"Dreieck":"Kein Dreieck"; cout << s; getchar(); Kein Dreieck return 0; } Übungsaufgaben Für die Lösung der folgenden Aufgaben wird vorausgesetzt, dass folgende Vereinbarungen vorher vorgenommen wurden: int a=2, x=0; bool b=true; double c=-2.4, d=3.1; 14.Schreiben Sie ein C++ Programm das die numerischen und logischen Werte der Variablen a, b, c, d und x auf dem Bildschirm ausgibt. 15.Welcher der folgenden Ausdrücke ist ein numerischer Ausdruck? Bestimmen Sie den numerischen Wert für alle numerischen Ausdrücke! a) main() b) x c) x + 2 d) // Berechnung e) a * 2 / 3 f) a > x g) (i==2) || (i==3) h) a % 5 i) true j) float k) a * 3 / 2 % 4 l)((3>4)-(3<4))*2 m) b + 7 n) "Willi" o) 5 + ’2’ p) 3++ q) { } r) d + b - 1.5 s) (a+b+d) /3 *2 t) !x u) iostream.h v) 2 ^ ( 1 / 2 ) w) 3.14 * a % 3 x) endl 16.Welche der Ausdrücke aus Aufgabe 15 sind logische Ausdrücke? Bestimmen Sie den logischen Wert für diese Ausdrücke! 17.Wenn im dezimalen Ausdruck 111.111 der Dezimalpunkt um eine Position nach rechts verschoben wird, verzehnfacht sich der numerische Wert. Bei einer Verschiebung nach links entsteht ein Ausdruck, der einem Zehntel des Ursprungswertes entspricht. Schreiben Sie diese beiden Sätze für a) hexadezimale und b) duale Werte auf ! 18.Erklären Sie die Begriffe a) Operator, b) Operation und c) Operand! 19.Beschreiben Sie die Bedeutung eines cast-Operators! Geben Sie drei Beispiele! 20.Definieren Sie eine passende Ergebnisvariable und weisen Sie dieser einen passenden Ausdruck zu! a) Die numerisch exakte Hälfte vom 5-fachen der Variablen a, b) falls c/x wahr ist, den vierfachen, sonst den zehnfachen Wert des Ausdrucks d+c , c) a und d sind die Katheten eines rechtwinkligen Dreiecks, gesucht ist die Hypotenusenlänge, d) das Produkt der Variablen c und b dividiert durch die Summe der Variablen a, b und x, e) der ASCII-Code des im Alphabet folgenden Buchstabens nach ’A’, f) das Zeichen mit dem ASCII-Code, der dem 12fachen des Ausdrucks (123%6) entspricht. 17 Cassebaum, Skript zur Programmierung mit C++ 1.5 Strukturanweisungen 1.5.1 Sequenz Sequenzen sind Programmstrukturen, die eine Folge von ausführbaren Anweisungen enthalten. In C/C++ werden die Anweisungen grundsätzlich mit einem Semikolon (nicht mit dem Zeilenende!!) abgeschlossen. Anweisungen werden in den Reihenfolgen "von links nach rechts" und "von oben nach unten" abgearbeitet. Abb.4 A Sequenzen in der Struktogramm-Darstellung: B Mit der in Abb.4 dargestellten Zeichnung wird bestimmt, dass der Block A vor dem Block B abgearbeitet wird. A:(BS) : "Spannung U[V]:" Ausgabe der Eingabeaufforderung am Bildschirm (BS). E:(Tas) : U Eingabe von Tastatur (Tas) in der Variablen U speichern. A:(BS) : "Stromstärke I[A]:" Ausgabe der Eingabeaufforderung am Bildschirm (BS) E:(Tas) : I Eingabe von Tastatur (Tas) in der Variablen I speichern. A:(BS) : U / I, "Ohm" Ausgabe des errechneten Ergebnisses am Bildschirm (BS) double U, I; cout << "Programm zur Widerstandsberechnung\n"; cout << "\nSpannung U [in V] : "; cin >> U; cout << "Stromstärke I [in A] : "; cin >> I; cout << "\nGeschwindigkeit : " << U/I << " Ohm"; // // // // // Variablen U und I definieren Ausgabe Titel Ausgabe und Eingabe U Ausgabe und Eingabe I Ausgabe Ergebnis U/I Übungsaufgaben 21.Sie lassen sich über Tastatur Name und Alter einer Person eingeben. Anschließend geben Sie über Bildschirm den Satz aus: In 10 Jahren bist Du schon <xx> Jahre alt, <Name>! Für <xx> wird das um 10 Jahre erhöhte, eingegebene Alter ersetzt, für <Name> der eingegebene Vorname! 22.Über Tastatur sollen drei Temperaturangaben a, b, c (mit 2 Kommastellen, <1000°C) eingegeben werden. Sie geben das arithmetische Mittel e mit folgendem Ergebnissatz aus: Das arithmetische Mittel der gegebenen Temperaturwerte … °C, … °C und … °C ist … °C! 23.Über Tastatur sollen die Kilometerstände von zwei vollen Betankungen eingegeben werden. Weiter werden der Rechnungsbetrag der 2.Betankung und der Literpreis des Kraftstoffs in Euro eingegeben. Bestimmen Sie den durchschnittlichen Verbrauch in Liter pro 100 km! 1.5.2 Selektion Eine Selektion (auch: Auswahl, Wahlstruktur, Alternative) ist eine Programmstruktur, die eine Verzweigung abhängig von einem logischen Ausdruck (abgekürzt <LA>, kann „wahr“→true oder „falsch“ →false sein) enthält. Eine einfache Selektion wird in C/C++ mit if (<llog. Ausdruck>) <A Anweisung>; konstruiert. Die Anweisung wird nur ausgeführt wird, wenn der <llogische Ausdruck> den Wert true enthält. Einfache Selektion in der Struktogramm - Darstellung <LLA> ? J A Mit der Zeichnung in Abb. 5 wird erklärt, dass wenn der logische Ausdruck <LLA> = true ist, der Block A ausgeführt und anderenfalls nichts geschieht. N Abb. 5 18 Cassebaum, Skript zur Programmierung mit C++ Für eine zweiseitige Selektion muss eine Anweisung „else“ unmittelbar nach der „if“-Anweisung eingefügt werden. Die else-Anweisung zeigt die auszuführende Anweisung für den „false“-Fall. if (<LA>) < Anweisung A im Fall <LA>=true >; else < Anweisung B im Fall <LA>=false >; Zweifache Selektion in der Struktogramm-Darstellung <LA> ? J A N B Abb. 6 Mit der Zeichnung in Abb. 6 wird erklärt, dass wenn der logische Ausdruck <LA> = true ist, der Block A ausgeführt wird. Für den Fall, dass der logische Ausdruck <LA> den Wert „false“ besitzt, wird der Block B realisiert. bool a; char s; cout << "Ist es hell draussen? [j/n] : "; cin >> s; if(s = = 'j') cout << "\nGuten Tag!"; // true-Fall else cout << "\nGute Nacht!"; // false-Fall a=(s = = 'j') ; // logische Wertzuweisung if(a) // einfache Selektion ohne else { cout << "\nDie Antwort war: Ja!"; // mit Mehrfachanweisung a = false ; } Nach "if(...) " oder "else" wird immer nur genau eine Anweisung bedingt realisiert (d.h. abhängig von dem logischen Ausdruck in der Klammer). Mehrere Anweisungen können durch Schaffung von Mehrfachanweisungen mit {…} geklammert und damit gemeinsam bedingt ausgeführt werden. Beispiel: if(x<2) { x++; cout << "x wurde inkrementiert"; } Sollen mehrere logische Ausdrücke geprüft werden, dürfen die logischen Verknüpfungsoperatoren && (and), || (or), ! (not) genutzt werden. Beispiel: if( (x>=0) && (x<130) ) cout << "x ist eine mögliche Altersangabe"; Eine einfache Wertzuweisung kann ebenfalls bedingt (d.h. abhängig vom Wert eines logischen Ausdrucks) erfolgen. Man benutzt den Fragezeichenoperator in der Form: <D> = <LA> ? <W1> : <W2>; Dem Datenobjekt <D> (z.B. x) wird der Wert <W1> (z.B. 0) zugewiesen, wenn der logische Ausdruck <LA> (z.B.(a<2)) wahr ist. Anderenfalls wird der <W2> (z.B. 4) zugewiesen. z.B.: int x = (a<2)?0:4; // x wird 0 für (a<2)=true, sonst 4 Übungsaufgaben 24. Geben Sie die gefahrenen Meter (k) und die benötigten Sekunden (s) für eine Fahrstrecke ein! Zeigen Sie über Bildschirm die Geschwindigkeit für den Fall k<1000 in m/s und sonst in km/h an! 25. Geben Sie die Nummer einer Ampelleuchte ein und antworten Sie mit deren Farbe! (z.B.: Eingabe: 2, Antwort: “gelb!“, Eingabe: 4, Antwort: “falsch!“) 26. Geben Sie drei Zahlen ein und geben Sie diese in aufsteigender Reihenfolge aus! 27. Antworten Sie auf eine Tasteneingabe passend mit „Buchstabe“, „Ziffer“ oder „Sonderzeichen“! 28. Geben Sie eine Tages-, eine Monats- und eine Jahreszahl ein. Entscheiden Sie, ob die Angabe ein gültiges Datum nach dem gregorianischen Kalender sein könnte. Hinweis: Jedes durch 4 teilbare Jahr ist ein Schaltjahr (29 Tage im Februar) mit Ausnahme aller durch 100 und nicht durch 400 teilbaren Jahreszahlen. 29. Welchem numerischen Wert entsprechen die Ausdrücke, wenn int a=4; bool b=true; vorlief? a) (!b)?a:b b) a?6:!b c) ((a<5)&&a)?a:3 d) (b||a)?a^6:11 e) ('e'-'a')?a&6:(~a) 19 Cassebaum, Skript zur Programmierung mit C++ 1.5.3 Mehrfachauswahl (Fallunterscheidung) Eine Mehrfachauswahl (auch: Fallunterscheidung) ist eine Programmstruktur, die abhängig vom Wert eines ganzzahligen Ausdrucks <GA> endlich viele Verzweigungen enthalten. Fallunterscheidung in der Struktogramm-Darstellung: <GA> ? 1 2 A B 3 C In Abb. 7 wird aufgezeigt, dass der abzuarbeitende Block x abhängig vom Wert des ganzzahligen Ausdrucks <GA> ausgeführt wird. Ist <GA> = 1, so wird Block A, für <GA> = 2 Block B, für <GA> = 3 Block C, ansonsten wird Block D ausgeführt. sonst D Abb. 7 Die Mehrfachauswahl wird in C/C++ konstruiert mit: switch ( <ganzzahliger Ausdruck> ) { case <ganzzahliger Ausdruck 1> : Anweisung 1 ;[ break ;] [[ case <ganzzahliger Ausdruck 2> : Anweisung 2 ;[ break ;]] ...] [ default : Anweisung 3 ;] } Die Anweisung nach einem case wird ausgeführt, wenn der in switch geklammerte ganzzahlige Ausdruck identisch mit dem Ausdruckswert des case ist. Danach werden alle folgenden Anweisungen bis zu der den switch-Block abschließenden geschweiften Klammer ausgeführt. Eine break-Anweisung beendet diese Ausführung schon vorher. Gerade diese Form der Beendigung eines case-Falles wird besonders häufig benötigt, weil ohne break alle nachfolgenden case-Fälle bis zum Auftreten eines break’s oder bis zur schließenden geschweiften Klammer der switchAnweisung abgearbeitet werden! 01 02 03 04 05 06 07 08 09 10 11 char s = 2; switch(s) { case 0: case 1: case 'c'-'a': case 3: case 4: case 'a': default: cout cout cout cout cout cout cout cout << << << << << << << << "\n0 kommt nicht"; "\n1 kommt nicht"; "\n2 kommt"; "\n3 kommt"; "\n3 kommt"; "\n4 kommt"; break; "\n'a' kommt nicht"; "\n kommt nicht"; } Was wird im dargestellten Beispiel ausgegeben? Betrachten Sie die Ausgaben nach einer Änderung der Zeile 01 für die Fälle s = { 0, 1, 2, 3, 4, 'a', …} ! Übungsaufgaben 30. Lösen Sie die Aufgabe 25 (Ampelaufgabe) noch einmal, aber diesmal mit switch/case! 31. Für einzugebende Dezimalziffern 0,…,9 soll wahlweise die englische oder die deutsche Wortschrift der Ziffer gezeigt werden. ( z.B.: Ziffer: 3 Sprache[d/e]: e Antwort: three) 32. Zeigen Sie den englischen Countdown in Wortschrift ab einer eingegebenen Dezimalziffer 0,…,9! (z.B.: Ziffer: 5 Ausgabe: five four three two one zero ) 33. Antworten Sie für die Buchstaben a, o, u, A, O, U mit den passenden deutschen Umlauten! (z.B.: Buchstabe: o Umlaut: ö) 20 Cassebaum, Skript zur Programmierung mit C++ 1.5.4 Kopfgesteuerte Schleifen Eine Mehrfachausführung einer Anweisung (eines Anweisungsblockes) wird Schleife ( auch: Zyklus, Wiederholstruktur, Iteration ) genannt. Die Eigenschaft „k kopfgesteuert“ steht dafür, dass die Arbeitsbedingung (ein logischer Ausdruck) schon vor Ausführung des „Schleifenkörpers“ auf den Inhalt „true“ überprüft wird. Der Schleifenkörper ist die Anweisung oder der Anweisungsblock in geschweiften Klammern { } der zyklisch auszuführenden Anweisungen. Wenn die Arbeitsbedingung den Wert „false“ enthält, wird die Schleifenbearbeitung beendet. Durch das Erreichen einer Anweisung „break“ kommt es ebenfalls zum Schleifenende. Wird im Schleifenkörper eine Anweisung „continue“ erreicht, wird die Bearbeitung der Anweisungen des Schleifenkörpers unterbrochen und die Schleife mit der erneuten Überprüfung der Arbeitsbedingung fortgesetzt. 1.5.4.1 WHILE Kopfgesteuerte Schleife in der Struktogramm-Darstellung: while (<LA>) Schleifenkörper Mit der dargestellten Zeichnung wird bestimmt, dass solange der logische Ausdruck <LA> = true ist, die Anweisung(en) des Schleifenkörpers ausgeführt werden. Sollte <LA> niemals false werden, so handelt es sich um eine unendliche Schleife. Die while-Anweisung konstruiert mit einem Parameter eine kopfgesteuerte Schleife (a abweisende Schleife). Abb. 8 while ( <log. Ausdruck> ) Anweisung ; while ( <log. Ausdruck> ) { A; B; C; } (1) Wenn der logische Ausdruck zum Schleifenbeginn false ist, endet die Bearbeitung der Schleife. (2) Wenn der logische Ausdruck zum Schleifenbeginn true ist, wird Anweisung(-sblock) ausgeführt. (3) Nach dem Beenden der Anweisung (ohne break) beginnt ein neuer Schleifenlauf mit (1). Anstelle einer einzelnen Anweisung nach „while(…)“ wird in den meisten Fällen eine in geschweifte Klammern gesetzter Block mehrerer Anweisungen aufgebaut („Mehrfachanweisung“). So besteht der Schleifenkörper aus beliebig vielen Anweisungen, die als Gesamtheit wiederholt ausgeführt werden. Die Schleife kann durch eine eingefügte break, return oder exit() -Anweisung abgebrochen werden. Normalerweise werden diese Anweisungen selektiv in einer if-Anweisung aufgerufen. Die Anweisung return beendet die Funktion und die Standardfunktion exit() beendet das gesamte Programm, in denen sie sich befinden. 01 #include <conio.h> 02 int z=0; 03 while(!kbhit()) 04 cout << z++ << " "; // // // // conio-Header für kbhit-Funktion Zählvariable kbhit() ist true, wenn eine Taste gedrückt wurde Zähle bis Tastendruck, Ausgabe: 1 2 3... Der logische Ausdruck „!kbhit()“ im Programmbeispiel ist eine asynchrone Arbeitsbedingung für eine while-Schleife. Eine Arbeitsbedingung wird dann asynchron genannt, wenn die Gesamtzahl der Schleifendurchläufe für das ausführende System nicht vorhersehbar ist. Sie heißt synchron, wenn die Schleifendurchlaufzahl berechenbar ist. Beispiele für eine synchrone Schleifen: int int int int i=5; i=5; i=5; i=5; while(i--) cout << i; // while(i>2) cout << i--; // while(i) {cout << i; i-=2; } // while(i) cout << " "; // gibt aus: 43210 gibt aus: 543 gibt aus: 531... Ausgabe unsichtbar (5 (3 (∞ (∞ Schleifendurchläufe) Schleifendurchläufe) Schleifendurchläufe) Schleifendurchläufe) 21 Cassebaum, Skript zur Programmierung mit C++ Eine oft benötigte Anwendung einer Schleife mit synchroner Arbeitsbedingung ist die Zählschleife, die für eine festzulegende Anzahl von Schleifendurchläufen konstruiert wird. In C/C++ gibt es eine zweite Form der kopfgesteuerten Schleife, die für die Konstruktion von Zählschleifen besonders gut geeignet ist. Sie wird im folgenden Kapitel betrachtet. 1.5.4.2 FOR Die for-Anweisung konstruiert mit 3 Parametern eine kopfgesteuerte (a abweisende) Schleife. Kopfgesteuerte Schleifen in Struktogrammen: Mit der dargestellten Zeichnung wird bestimmt, dass solange der logische Ausdruck <LA> = true ist, die Anweisung(en) des Schleifenkörpers ausgeführt werden. Sollte <LA> niemals false werden, so handelt es sich um eine unendliche Schleife. for (<A1>;<LA>;<A2>) Schleifenkörper <A3> Abb. 9 for (<Anweisung 1>;<log.Ausdruck>;<Anweisung 2>) Anweisung 3; <A1> <A1> while <LA> <LA>? <A3> <A2> <A3> Abb. 10 <A2> (1) In jedem Fall erfolgt die Ausführung von Anweisung 1 genau einmal vor der Arbeitsbedingungsprüfung. (2) Arbeitsbedingungsprüfung: wenn der log.Ausdruck zum Schleifenbeginn false ist, wird die Schleife beendet, sonst wird mit (3) fortgesetzt. (3) Ausführung der Anweisung 3 und nachfolgend Anweisung 2. Anschliessend wird mit (2) zyklisch fortgesetzt. In Abb. 10 wird als Struktogramm und als Programmablaufplan – „PAP“ gezeigt, in welcher Reihenfolge die Schrittfolge einer for-Anweisung abläuft. Mit etwas Überlegung wird erkennbar, dass jedes „for“Konstrukt auch als „while“-Konstrukt geschrieben werden kann. Die nachfolgenden Beispiele zeigen zwei im Ablauf identische Programmkonstrukte: int i = 0; while(i<4) { cout << i; i++; } // // // // <A1> <LA>? <A3> <A2> int i; for(i=0;i<4;i++) cout << i; // <A1>,<LA>,<A2> // <A3> Es handelt sich bei diesen Beispielen um je eine Zählschleife, die eine Laufvariable i zur Zählung der Schleifendurchläufe vom Startwert 0 bis zum nicht erreichten Endwert 4 mit der Schrittweite 1 verwenden. Es kommt zu 4 Zyklen { i= 0, 1, 2, 3 }. Anweisungen im Schleifenkörper werden auch hier meist als eine in geschweifte Klammern gesetzte Mehrfachanweisung aufgebaut. Für die Anweisung <A2> kann zum Einbau mehrerer Anweisungen an das Schleifenende auch mit dem Kommaoperator gearbeitet werden: 01 int sum=0, m=0, k=0; 02 for(int i=1 ; i<=100 ; i++,k++,m+=2 ) sum+=i; 03 cout << sum << endl << m << endl << k; Eine oft erforderliche Technik ist die Konstruktion von verschachtelten Schleifen. Im folgenden Beispiel wird eine Multiplikationstabelle mit zwei Zählschleifen zur Anzeige des „kleinen Einmaleins“ auf dem Bildschirm dargestellt: 01 for(int i=1;i<10;i++) 02 { for(int j=1;j<10;j++) 03 cout << i*j << “\t“; 04 cout << endl; 05 } // äußere for-Schleife // innere for-Schleife // Schleifenkörper der inneren Schleife // Teil des Schleifenkörpers der äußeren Schleife // Ende des Schleifenkörpers der äußeren Schleife Wie die while-Anweisung ist auch die for-Anweisung durch continue unterbrechbar, oder mit break, return oder exit()endgültig abbrechbar. 22 Cassebaum, Skript zur Programmierung mit C++ 1.5.5 Fußgesteuerte Schleife Die do-while-Anweisung konstruiert eine fußgesteuerte Schleife (n nicht abweisende Schleife). Schleifenkörper do while (<LA>); Abb. 11 (1) Ausführung der Anweisung(en) im Schleifenkörper (2) Nach dem Beenden der Anweisung (ohne break) wird der Wert des log. Ausdrucks ermittelt. Wenn der Wert false ist, endet die Schleife sofort, sonst beginnt ein neuer Durchlauf mit (1). do Anweisung; while ( <log. Ausdruck> ); 01 int x; 02 do { cout << "x: "; cin >> x; 03 } while(x<=0); 04 do { if(!(x%2)) cout << x << " "; 05 } while (--x>0); // Ausgabe aller geraden Zahlen, // beginnend mit einer eingege// benen Zahl x (rückwärts bis 2) Der Anweisungsblock {…} des Schleifenkörpers kann durch eine continue-Anweisung vorzeitig unterbrochen werden. Die Schleife wird danach sofort mit der Überprüfung des logischen Ausdrucks fortgesetzt und beginnt im true-Fall erneut die Anweisung abzuarbeiten. Wie die while-Anweisung ist auch die do-while-Anweisung durch break, return oder exit()endgültig abbrechbar. Die Anwendung der do-while-Schleife sollte in Fällen angewendet werden, wenn der erste Schleifendurchlauf in jedem Fall durchgeführt werden soll. Beispielaufgabe 5 Das Programm gibt auf dem Bildschirm eine Tabelle des kleinen Einmaleins für die Produkte der Zahlen von 1 bis 10 vollständig und geordnet aus. 01 02 03 04 05 06 07 08 09 10 #include <iostream> #include <iomanip> using namespace std; int main() { for( int i=1; i<=10; i++, cout<<endl ) for( int j=1; j<=10; j++ ) cout << setw(4) << i*j; getchar(); return 0; } 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 10 18 20 27 30 36 40 45 50 54 60 63 70 72 80 81 90 90 100 Der Header iomanip erlaubt zusätzliche Ein-/ Ausgabemanipulationen. Bei dieser Aufgabe wird für jede ausgegebene Zahl mit setw(4) eine Ausgabebreite von gleichbleibend 4 Zeichen bewirkt. Beispielaufgabe 6 m m! Bestimmen Sie den Wert des Binomialkoeffizienten . n n!(m n)! 01 02 03 04 05 06 07 07 08 09 10 11 #include <iostream> using namespace std; Binomial(7,3) = 21 int main() { float m=7, n=2, b=1; cout << "Binomial(" << m << "," << n << ") = "; if( m >= n ) while(n) // n!=0 ist true, n==0 ist false b *= m-- / n--; // erst nach Multiplikation und Division folgen die Dekremente -cout << b; getchar(); return 0; } Cassebaum, Skript zur Programmierung mit C++ Übungsaufgaben 34. Geben Sie über Bildschirm 30 mal das Wort „Software“ aus! Lösen Sie das Problem mit den Schleifenkonstruktionstypen a) for, b) while, c) do while! 35. Geben Sie Zahlenwerte nacheinander über Tastatur ein, bestimmen Sie das Maximum, das Minimum und das arithmetische Mittel und geben Sie die Ergebnisse kommentiert aus! 36. Es ist eine natürliche Zahl x über Tastatur einzugeben. Errechnen Sie die Summe aller ungeraden Zahlen u, für die gilt u<x und u>0! Bei Eingabefehlern wird eine Ausschrift gegeben (z.B. „x ist keine natürliche Zahl!“, „x ist zu groß oder zu“). 37. Der Bediener gibt eine Ziffer n und ein Zeichen ein. Geben Sie das Zeichen n mal aus! 38. Geben Sie über Tastatur 10 Werte ein und geben Sie diese absteigend sortiert über Bildschirm aus! 39. Geben Sie das Alphabet mit großen und kleinen Buchstaben (zyklisch!) aus! 40. Geben Sie alle geraden Zahlen zwischen a und b aus (Die ganzen Zahlen a und b sind vorher über Tastatur einzugeben). 41. Geben Sie dauerhaft Sternchen (*) über Bildschirm aus, bis eine beliebige Taste betätigt wird! 42. Errechnen Sie für ein Lottospiel anhand der einzugebenden höchstmöglichen Tippzahl (z.B.: tmax=49) und der Anzahl der Tippzahlen (z.B.: tz=6), wie viel verschiedene Tipps es gibt! Mathematisch: [tmax*(tmax-1)*(tmax-2)*…*(tmax-tz)*tmax-(tz+1)+ / *1*2*…*(n-2)*(n-1)*n] 43. Erzeugen Sie eine Potenzierungstabelle mit allen Werten des Ausdrucks xy für alle x,yЄ,1;2;…;9} ! 44. Benennen Sie eine C++ Anweisung zur Realisierung folgender Schritte: a) b) c) d) e) f) g) h) Definition zweier reeller Variablen doppelter Genauigkeit; Selektion nach dem Inhalt der ganzzahligen Variablen x für mehr als zwei Fälle; Verminderung des Inhaltes der ganzzahligen Variablen x um 1; Tastatureingabe einer reellen Zahl zur Speicherung in der Variablen a; Erhöhung der ganzzahligen Variablen x um 5, wenn die logische Variable y den Wert true besitzt; 6000-malige Bildschirmausgabe des Wortes „Test“; Die int-Variable x erhält Wert 1, wenn die float-Variable v<π ist. Sonst wird x=0 gesetzt; Summenbildung aller ganzen Zahlen von 300 bis 2000; 45. Schreiben Sie C++ - Programme und zeichnen Sie zu jeder der Lösungen ein Struktogramm! a) Geben Sie die ersten 6 Zeilen des Pascalschen Dreiecks auf dem Bildschirm aus! b) Geben Sie ein einzugebendes Wort gesperrt(Leerzeichen zwischen die Zeichen setzen) aus! c) Es geben 5 Personen ihr Körpergröße (in Meter) ein. Speichern Sie die einzugebenden Körpergrößen in einem Array! Bestimmen Sie die Körpergröße der größten, die der kleinsten Person und das arithmetische Mittel aller fünf Größenangaben. d) Verfassen Sie eine C++ - Funktion „Sum“, die einen Parameter p (natürliche Zahl) übernimmt und einen Ergebniswert s (natürliche Zahl) zurückgibt. Der Ergebniswert ist die Summe aller geraden Zahlen x, für die gilt: x p (x kleiner oder gleich p). Die Funktion Sum wird von einem Hauptprogramm aufgerufen, das vom Bediener die Eingabe eines aktuellen Parameters für diese Funktion abfordert und anschließend das Funktionsergebnis über Monitor ausgibt. e) Versuchen Sie mit beliebigen Zeichenausgaben eine Figur darzustellen, die einem Schachbrett nahe kommt! f) Schreiben Sie ein Programm, das bei Eingabe von Kleinbuchstaben immer Großbuchstaben zeigt. Alle anderen Zeichen erscheinen wie immer. 23 24 Cassebaum, Skript zur Programmierung mit C++ 1.6 Allgemeine Probleme zur Softwareentwicklung 1.6.1 Wasserfallmodell für den Lebenszyklus einer Software Das Wasserfallmodell stellt die einzelnen Tätigkeiten, die bei einer Software-Entwicklung anfallen, in einer zeitlichen Reihenfolge. Der jeweilige Folgeschritt kann nur mit Rückbezug auf die vorher laufenden Folgeschritte und einer gleichzeitigen eventuellen Nachbesserung aufgebaut werden. Ist-Analyse Soll-Analyse Entwurf Implementierung Test Abb. 12 Dokumentation, Archivierung Die Ist-Analyse beschreibt den Zustand des Prozesses vor dem Einsatz der neu zu entwickelnden Software. Sie stellt die Voraussetzung für die Schaffung der Soll-Analyse, die eine Aufgabenstellung zur neuen Software mit einem zugehörigen Pflichtenheft dar. Die drei in der Zeichnung rot gekennzeichneten Tätigkeiten stellen die Hauptprozesse der Entwicklung dar. Sie werden Entwurf, Implementierung und Test genannt. Im Entwurf wird die Aufgabenstellung in relevante Teile zerlegt. Es gibt eine Reihe von Methoden, die unter dem Oberbegriff „S Systemanalyse“ zusammengefasst werden. Besonders interessant ist die Zerlegung der künftigen Software in die drei Grundstrukturen Sequenz, Selektion und Iteration, die bereits im vorhergehenden ↑Kapitel 1.5 behandelt wurden. Dabei wird eine zeichnerische, sprachunabhängige Programmdarstellung als Struktogramme (↑nachfolgendes Kapitel1.6.2) geschaffen. Die Implementierung übernimmt den Entwurf und setzt ihn zu einer ungetesteten Programmlösung zusammen. Dazu werden die in dem ↑Kapitel1.1.2 erläuterten Teilschritte der Programmentwicklung benötigt. Gemeint sind die Codierung in einer Programmiersprache, die Übersetzung, das Linken und der Start des Tasks. Der Test dient der Prüfung und Nachbesserung des Ergebnisses der Implementierung. Es wird dabei getestet, ob das geschaffene Programmergebnis der vorgegebenen Ziel- und Aufgabenstellung entspricht, die im Pflichtenheft dokumentiert wurde. Dazu werden Testdaten genutzt, die möglichst sicher alle auftretetenden Praxissituationen nachbilden. Die Dokumentation fasst die Schritte der Entwicklung mit allen Teilschritten schriftlich zusammen und wird gemeinsam mit den Programmdateien und Testdaten abschließend archiviert. Übungsaufgaben 46. Erklären Sie die Begriffe Testdaten, Codierung, Sequenz, Implementierung, Iteration, Test, Projekt, Grundstruktur, Selektion, Struktogramm, Soll-Analyse, Pflichtenheft und Hybridprogramm! 47. Nennen Sie die Schnittstellen zwischen den einzelnen Tätigkeiten der Softwareentwicklung. Nennen Sie für jede Tätigkeit geeignete Software, die den Entwicklungsprozess verbessern könnte. 25 Cassebaum, Skript zur Programmierung mit C++ 1.6.2 Struktogramme Die Struktogramme stellen eine zeichnerische Methode zur Darstellung von Programmentwürfen dar, die den Entwickler zwingt, seinen Entwurf auf die drei Grundstrukturen Sequenz, Selektion und Iteration zu beschränken. Gleichzeitig wird das Programm in Strukturblöcke zerlegt, die alle nur einen Einund einen Ausgang besitzen („B Blockkkonzept“). Die Struktogrammtechnologie hat sich durch diese beschriebenen Vorteile zur bekanntesten Entwurfstechnologie in der Programmierung entwickelt und dabei die heute veralteten Methode des Programmablaufplans („PAP“) abgelöst. Die wichtigsten zeichnerischen Blockarten werden hier gezeigt: Sequenz, Folge A Selektion, Alternative J B A; B; B wird nach A verarbeitet. b? A Fallunterscheidung N B if(b) A; else B; Wenn b==true, dann arbeitet A, sonst B. 1 2 3 x A B C D E Kofgesteuerte Schleife Fußgesteuerte Schleife while b A do while b A switch(x){ case 1:A;… } while(b) { A; } do{ A; } while(b); Wenn x=1,dann arbeitet A,wenn x=2, dann B, … Wiederhole A, solange b==true. Starte A und wiederh. A, solange b==true. Break, Abbruch BREAK { break; } Abbruch des Blockes an der break-Position. Der äußere Halbrahmen des Struktogramms dient dem Eintrag zur Autoren- und Titelinformation. Die sprachlichen Inhalte der rechteckigen Strukturblöcke sind frei zum Zweck wählbar. Die grafische Form und deren Sinn sind aber zwingend vorgeschrieben. Das gesamte Struktogramm bildet immer ein volles Rechteck. Struktogramme werden im Normalfall ohne Farben gezeichnet. Beispielaufgabe 7 Fordern Sie den Bediener auf, eine reelle Zahl einzugeben. Geben Sie auf dem Bildschirm für eine positive Zahl das Zeichen ‚+‘, für eine negative ‚-‘ und für Null ‚0‘ aus. Zeichnen Sie das Struktogramm und erstellen Sie ein C++ Programm. Vorzeichen, 04.09.2011 01 02 03 04 05 06 07 08 09 10 #include <iostream> using namespace std; int main() { float x; cout << "Zahl: "; cin >> x; if(x>0) cout << "+"; else { if(x<0) cout << "-"; else cout << "0"; } getchar(); return 0; } Th. Cassebaum O:Scr "Reelle Zahl: " I:Kbd x J x>0 ? O:Scr "+" J x<0 ? Beispielaufgabe 8 Bestimmen Sie n! = 1 ⋅ 2 ⋅ … ⋅ n für eine einzugebene natürliche Zahl n. Zeichnen Sie das Struktogramm und erstellen Sie ein C++ Programm. 01 02 03 04 05 06 07 08 09 10 #include <iostream> using namespace std; int main() { int n; double f=1; do { cout << "Nat.Zahl: "; cin >> n; } while(n<0); while(n) f*=n--; cout << f; getchar(); return 0; } N N O:Scr "-" O:Scr "0" Fakultät, 22.7.2011 Th. Cassebaum f := 1 O:Scr "Nat.Zahl:" I:Kbd n do while ( n<0 ) while ( n ) f := f * n n := n - 1 O:Scr f 26 Cassebaum, Skript zur Programmierung mit C++ Der äußere Halbrahmen des Struktogramms dient dem Eintrag zur Autoren- und Titelinformation. Die sprachlichen Inhalte der rechteckigen Strukturblöcke sind frei zum Zweck wählbar. Die grafische Form und deren Sinn sind aber zwingend vorgeschrieben. Das gesamte Struktogramm bildet immer ein volles Rechteck. Struktogramme werden im Normalfall ohne Farben gezeichnet. Übungsaufgabe 48. Schreiben Sie C++ - Programme und zeichnen Sie zu jeder der Lösungen ein Struktogramm! a) Geben Sie die ersten 6 Zeilen des Pascalschen Dreiecks auf dem Bildschirm aus! b) Geben Sie ein einzugebendes Wort gesperrt (Leerzeichen zwischen die Zeichen setzen) aus! c) Es geben 5 Personen ihr Körpergröße (in Meter) ein. Speichern Sie die einzugebenden Körpergrößen in einem Array! Bestimmen Sie die Körpergröße der größten, die der kleinsten Person und das arithmetische Mittel aller fünf Größenangaben. d) Stellen Sie mit Zeichenausgaben eine Figur dar, die einem Schachbrett nahe kommt. e) Schreiben Sie ein Programm, das bei Eingabe von Kleinbuchstaben immer Großbuchstaben zeigt. Alle anderen Zeichen erscheinen wie immer. f) Geben Sie alle nat. Zahlen n<1000, die durch 3 oder 5 teilbar sind, auf dem Bildschirm aus. 1.6.3 Trockentests Die Methode der Trockentests („Schreibtischtests“) wird genutzt, um kleine Programmabschnitte ohne Computer testen zu können. Die dabei verwendeten Daten werden „T Testdaten“ genannt. Beispielaufgabe 9 Es soll folgendes C++ -Programmstück mit Hilfe eines Trockentests auf Richtigkeit kontrolliert werden. Es soll für einen vorgegebenen Wert x die mathematische Fakultätsfunktion f = !x errechnet werden. Als Menge der Testdaten wird gewählt: X = { 2; 1; 0 } . 01 02 03 04 05 unsigned x, f=1; cout << "x = "; cin >> x; while(x) f *= x--; cout << "x! = " << f; 2) Zeile 01 03 04 04 05 x f 1 1) Zeile 01 2 03 1 2 04 0 05 out→ x! = 2 x f 1 0) Zeile x f 01 1 1 03 0 0 1 05 out→ x! =1 out→ x! = 1 Bei der Auswahl der Testdaten sollte auf Eckdaten des Algorithmus zurück gegriffen werden, die Sonderfälle oder Schwachstellen des zu prüfenden Programmstückes testen. Im Beispiel hat der Trockentest gezeigt, dass in den Fällen 2) und 1) die letzte Multiplikation mit einer 1 unnötig und somit uneffektiv ist. Das Programmstück wird effektiver, wenn die Zeile 04 in die folgende Zeile verändert wird: [ 04 while(x>1) f *= x--; ]. Führen Sie mit der neuen Zeile alle Trockentests für die Testdatenmenge X = { 3; 1; 0 } durch! Übungsaufgaben 49.Bestimmen Sie den Wert der Variablen x nach dem Ablauf der folgenden C++ Programmstücke: a) int main() { int x=2, a=4; if(x<a) x+=a; b) int main() { int x=14%3, a=1; if(a--) x=x+a; 27 Cassebaum, Skript zur Programmierung mit C++ c) int main() { int x=3, a=4; do { a-=2; x+=a; } while(a); e) int main() { double x=2.2; i=3; while(i) { x+=2; i--; } g) int main() { int x=0, a[]={3,2,1,4}, i=3; while(i) x+=a[i--]; i) bool fkt(int a){ return !a; } int main() { int x=2; if(fkt(x)) x++; else x--; x+=x; d) int main() { int i,x= 'd'-'b'; for(i=0; i<2; i++) { x--; } if(x) x++; f) int main() { int x=6, i=-3; while(i) { x-=2; i+=2;} h) int main() { int a[3], i=0, x; for( ; i<3; i++) a[i]=i; x= a[0]+a[1]*(a[2]-1); j)unsigned fkt(unsigned c) { unsigned e=1; while(c) e+=c--; return e; } int main() { unsigned x=fkt(5)-fkt(4); 50.Bestimmen Sie den Wert der Variablen x nach dem Ablauf der folgenden Struktogramme: a) x=2 a=0 while (x > 0) a=a+3 x=x-1 x=a+1 b) x=2 a=2 while (a > 0) x=x*2 a=a-1 x=a/2 x=6 a=0 x%2 N a=a+x x=x-1 c) J do while ( x ) Geben Sie für die Aufgaben 46…49 den Wert der Variablen x nach Abarbeitung aller zur Teilaufgabe zugehörigen Anweisungen an: 51. a) int a, x=0; a= x+2; x += a; b) int a=0, x; x=a-3; x-=3; x++; c) int a=3, x=4; a=a*a*a/x++; x++; 52. a) double x,a=0.6; b) bool x=!true; x= 2+a--; if(!x)x=!(x||x); x= a*a/a-1; else x-=1; d) (x int while > 0)a, x=4; a= (++x)+4; x= a%2; c) int x=0,i=3; switch(i) { case 1: x=2; break; case 2: x++; default:--x; } 53.a) int x=2,a; b) bool a, x=-3; c) int x=0,i; bool b; for(a=3;a>1;a--) for(a=0; x; x++) if(i){for(i=-3; i<0; i++) --x;} { x*=a; } { x+=a; a++; else if(b&&i) x++; x*=x;} ++x; if(!b||i) x*=2; b)int i=0,x=-2; c)int x=0; d)int x=0,i=0; 54.a) int x=2; do for(;!x;x-=2) for(;i<=3;i++,x--) while(x<17) { x+=i; i+=x; x+=3; x *= i; x *= 3; } while(i>=-8); 55. Zeichnen Sie den Bildschirmaufbau nach dem Programmteilablauf! Es wird vorausgesetzt, dass die notwendigen Header vorher mit #include <iostream> gerufen wurden. a) int a=4; clrscr(); for(;a;a--) cout << "++"; b) int i=1, a=1; c) clrscr(); while(i<5) { cout << a++; i++;} int x=1; bool b; clrscr(); b=(x!=1); for(; !b; b=!b){cout << "###"} 28 Cassebaum, Skript zur Programmierung mit C++ 2 Elementare Einführung in C/C++ 2.1 Funktionen Die wesentlichsten ausführbaren Programmteile in C++ sind (g gerufene, gestartete) Funktionen, die wiederum von anderen (rrufenden) Funktionen gestartet werden. Eine Funktion kann mit „P Parametern“ Steuerinformation von der rufenden („übergeordneten“) Funktion übernehmen und mit einem „R Rückgabewert“ ein Resultat an die übergeordnete zurückgeben. 2.1.1 Funktionsdefinition Allgemein wird eine Funktion wie folgt definiert: <Datentyp><Funktionsname>([formaler Parameter1[,formaler Parameter2[,...]]]) { <Funktionskörper> [ return <Rückgabewert im Datentyp der Funktion>; ] } (nur wenn der Datentyp der Funktion nicht void ist) Der Funktionskörper enthält die C/C++Anweisungsfolge, die die Arbeitsweise nach dem Funktionsaufruf erklären. Eine Funktion des Datentyps void wird „A Auftragsfunktion“ genannt. Eine solche Funktion führt Tätigkeiten aus, besitzt aber kein Ergebnis in Form eines Wertes. Jeder andere Datentyp macht eine returnAnweisung in der Definition erforderlich, weil mit (return x; ) das datentypgerechte Wertergebnis an die rufende Funktion übergeben wird. Funktionen mit Wertrückgabe werden „A Anfragefunktion“ genannt. void aus(int x) // Auftrag { cout << x; } int main() { aus(8); // Aufruf ... } int doppel(int x) { return t+t; } int main() { cout << doppel(5); ... } // Anfrage // Aufruf Eine Funktion muss vor Ihrem ersten Aufruf in der Reihefolge der Quellzeilen definiert worden sein, d.h. die Reihenfolge der Funktionsdefinitionen ist von Bedeutung für deren spätere Ausführbarkeit. 2.1.2 Prototypen Die erste Zeile der Funktionsdefinition mit einem abschließenden Semikolon wird Prototyp genannt. Der Prototyp wird zum Modulbeginn eingefügt, damit die zugehörige Funktion schon vor der Definition für den Compiler als bekannt gilt. 01 02 03 04 05 06 07 08 09 10 11 12 void aus(int, int); // Prototypen int mult(int, int); int main() { aus(3,4); // Funktionsaufruf getchar(); return 0; } void aus(int a, int b) { cout <<a <<“*“ <<b <<“=“ <<mult(a,b); } int mult(int x, int y) { return x*y; } Ohne Prototypzeilen würde der Compiler für Zeile 09 einen Fehler anzeigen, weil die Funktion „mult()“ in dieser Zeile noch unbekannt ist. Der Compiler wertet Zeile für Zeile aus, so dass bei der Auswertung der Zeile 09 die Zeile 11 noch nicht bekannt ist. Durch den Prototyp in Zeile 02 ist die nebenstehende Variante fehlerfrei compilierbar. 29 Cassebaum, Skript zur Programmierung mit C++ 2.1.3 Funktionsparameter Parameter sind die Angaben in der nach dem Funktionsnamen folgenden Klammer. Sie besitzen einen Datentyp und werden anhand ihrer Position Parameterreihenfolge unterschieden. Die „fformalen“ Parameter in der Funktionsdefinition werden immer mit einem Datentyp und einem Namen definiert. Der Funktionskörper enthält die beim Funktionsaufruf auszuführenden Anweisungen, die die Parameter nutzen dürfen. Ist die Funktion nicht vom Datentyp void (steht für den "leer"), so gibt die Funktion mit der return-Anweisung einen datentypgerechten Funktionswert an die rufende Funktion zurück. Kennt eine Funktion den Namen einer anderen Funktion, so kann sie diese mit einem Funktionsaufruf starten. Im Funktionsaufruf werden die formalen Parameter durch „a aktuelle“ Parameter ersetzt. Die aktuelle Parameterliste des Funktionsaufrufs muß hinsichtlich der Parameteranzahl, -Reihenfolge und Datentypen vollständig mit der formalen Parameterliste harmonieren. <Funktionsname>([aktueller Parameter_1[,aktueller Parameter_2[,...]]]); string Multistring(string s, int r); void main(void) { cout << Multistring("Tick",5); getchar(); } string Multistring(string s, int r) { while(r--) s+=s; return s; // Rückgabewert } // Prototypzeile // Funktionsaufruf Gibt aus: TickTickTick… Wie viele Tick’s werden sichtbar? 2.1.4 Die main() - Funktion Ein C++ Programm wird mit Hilfe von Funktionen konstruiert, d.h. die wesentlichsten ausführbaren Programmteile sind Funktionen, die von anderen (rufenden) Funktionen gestartet werden. Der Start des gesamten Programmes wird vom Betriebssystem (z.B. in Windows durch Angabe des Namens der EXE-Datei) realisiert. Im C++ Programm startet danch zunächst die main-F Funktion, die Hauptfunktion des Programmes. Wie jede andere Funktion kann sie Parameter von der startenden Funktion empfangen und einen Ergebniswert zurückgeben. Da die main-Funktion vom Betriebssystem gestartet wird, empfängt sie Kommandozeilen-Parameter von der Startzeile und gibt üblicherweise einen ganzzahligen Ergebniscode an das Betriebssystem zurück (z.B. 0 für erfolgreiche und 1 für erfolglose Abarbeitung). int main( int argc, char* argv[] ) // Argumentanzahl/ Argumente { .. // Programmzeilen getchar(); // Warten auf Tasteneingabe vor Programmende return 0; // Rückgabe des Erfolgscodes 0 und Funktion beenden } Angenommen, das gezeigte Programm heisst myprog.exe und wird mit der Kommandozeile "myprog.exe Hans Lisa" gestartet. Dann gilt: argc=3 (3 Parameter) und argv[0]="C:\TEMP\CPPTRAIN\MAIN1.EXE", argv[1]="Hans", argv[2]="Lisa". In einer BAT-Kommandodatei kann der Rückkehrcode 1 ( return 1;) z.B. in der Zeile "if errorlevel 1 goto error" ausgewertet werden. Sollten weder Rückkehrcodes noch Argumente beim Programmstart verwendet, so könnte die "return xx"-Zeile weggelassen werden und die erste Zeile der main-Funktion wie folgt aussehen: void main(void) . 30 Cassebaum, Skript zur Programmierung mit C++ 2.1.5 Datenkapseln Als Datenkapsel wird ein C++-Konstrukt bezeichnet, das eigene „lokale“ Größen (z.B. Variablen) definiert. In verschiedenen Datenkapseln dürfen gleiche Bezeichner für unterschiedliche Daten genutzt werden. Funktionen sind Datenkapseln und besitzen damit eigene, nur ihnen zugeordnete Speicherbereiche. Ohne den Definitionszusatz „static“ werden die im Funktionskörper definierte Größen beim Aufruf der Funktion dynamisch im lokalen Stack der Funktion (rückwärts zählend) aufgebaut und zum Beenden der Funktion wieder freigegeben. Bei einem erneuten Aufruf der Funktion stehen die Wertinhalte des vorherigen Funktionslaufs somit nicht mehr zur Verfügung. Werden die lokalen Größen mit dem „static“-Zusatz definiert, bleiben deren Werte erhalten. Sie werden nicht beim Beenden der Funktion zerstört. Wird der Operator :: vor einen Datenbezeichner gesetzt (z.B. ::x=0;), so wird eine außerhalb von allen Funktionen definierte „g globale“ Größe über ihren Bezeichner angesprochen. Globale Größen sind mit :: in allen Funktionen erreichbar und können deshalb auch als primitive Form der Wertübergabe von einer Funktion zu einer anderen benutzt werden. int x=5; // globale Variable x (ausserhalb der Funktionen) void aend(void) { int x=1; // lokale, dynamische Variable x in aend() static int y=1; // lokale, statische Variable y cout << ++x << “ “ << ++y << “ “ << ++::x << endl; Gibt aus: } int main() 12 5 { int x=12; // lokale Variable x in main() 2 2 6 cout << x << “ “ << ::x << endl; 2 3 7 aend(); aend(); // zweimaliger Aufruf 12 7 cout << x << “ “ << ::x; getchar(); } Abb. 11 2.1.6 „call by value“ und „call by reference“ Wie bereits bekannt, werden Parameter benötigt, um Daten aus der rufenden Funktion an die gerufene Funktion zu übergeben. Es werden bei der Parameterübergabe zwei grundsätzliche Formen unterschieden. Zum einen können die Parameter als „W Wert“ (ccall by value), aber andererseits auch als „R Referenz“ (ccall by reference) übergeben werden. Bei Übernahme von Wertparametern wird in der gerufenen Funktion neuer Speicherplatz zur Aufnahme der übernommenen Parameterwerte bereitgestellt. Eine Änderung dieses funktionsinternen Speicherplatzes führt bei einer Änderung des Parameterinhaltes nicht gleichzeitig zur Änderung der Position im rufenden Programm. Ein Referenzparameter ist an einem vorangestellten & erkennbar. void aend(int x) Gibt aus: { cout << ++x;} 1 int main() { int x=1; 22 cout << x << endl; 1 aend(x); aend(x); cout << endl << x; getchar(); } void aend(int &x) Gibt aus: { cout << ++x;} 1 int main() 23 { int x=1; cout << x << endl; 3 aend(x); aend(x); cout << endl << x; getchar(); } 31 Cassebaum, Skript zur Programmierung mit C++ Der Parameter im rechten Beispiel wird als Referenz übergeben. Die Veränderung des Parameters ist vom rufenden Programm erkennbar. Ein Rückgabewert braucht nicht zwingend übergeben werden, wenn der Referenzparameter zur Ergebnisübergabe genutzt wird. Referenzen verweisen auf Objekte, können jedoch nur einmal mit einem Objekt initialisiert werden und danach nicht mehr auf andere Objekte umgelenkt werden. Weiter entfällt für Referenzen die Nutzung der typischen Zeigersyntax, sie werden wie die Variable selbst behandelt, die sie referenzieren. Wegen dieser einfachen Arbeitsweise werden Referenzen auch Alias ("Spitzname") genannt. #include <iostream.h> double quad_v(double w){return w*w;} // Wert als Parameter void quad_r(double &w){w*=w;} // Referenz als Parameter void main(void) { double x=12.; Gibt aus: x=quad_v(x); // call by value cout << "\n(1) 12*12= " << x; (1) 12*12= 144 x=12.; quad_r(x); // call by reference (2) 12*12= 144 cout << "\n(2) 12*12= " << x; getchar(); } 2.1.7 Rekursionen Kennt eine Funktion den Namen einer anderen Funktion, so kann sie diese mit einem Funktionsaufruf starten. Jede Funktion in C++ kennt sich selbst und kann sich deshalb auch selbst rufen. Gemeint ist, daß die Funktionsdefinition ihren eigenen Funktionsnamen für einen Funktionsaufruf in einer eigenen Definitionszeile enthält. Ruft eine Funktion in ihrer Definition sich selbst auf, wird sie rekursiv genannt. z.B.: string Multistring(string s, int r) // Funktionsdefinition { return r?Multistring(s+s,r-1):s; } void main(void) { cout << Multistring("Tick",5); // Funktionsaufruf getchar(); } Gibt aus: TickTickTick… Wie viele Tick’s werden sichtbar? Die Funktion Multistring sieht hier anders aus, als die rekursionsfreie Funktion im Kapitel 2.2.3 (S.26). Die Rekursion arbeitet bei näherem Betrachten wie eine Schleife, deren Abbuch durch einen logischen Ausdruck in der Funktionsdefinition erklärt wird. Im obigen Beispiel führt r==false zur Rückgabe des Strings s, was die Rekursion beendet. int fak(int x) // Funktionsdefinition { return x?fak(x-1)*x:1; } void main(void) { cout << fak(5); // Funktionsaufruf getchar(); } Die Funktion fak errechnet eine bekannte mathematische Funktion in nicht zu überbietenden Einfachheit. Es gibt insbesondere bei den sogenannten "divide and conqeur"-Verfahren Sortier-, Such- und Ordnungsalgorithmen, die äußerst effektiv (gemeint ist die Schnelligkeit) gerade wegen der rekursiven Lösung sind. 32 Cassebaum, Skript zur Programmierung mit C++ 2.1.8 Funktionsüberladung Wichtige äußere Eigenschaften einer Funktion sind die Anzahl, Reihenfolge und die einzelnen Datentypen der Parameter. Aus praktischen Gründen stellt man sich die Frage, ob es nicht vernünftig ist, unterschiedliche Parameterlisten für den gleichen Funktionsnamen zuzulassen. In C++ ist dies mit Hilfe des Overloading möglich. Der Begriff Overloading oder Überladung bezeichnet die Fähigkeit von C++, anhand der Parameterliste einen von mehreren existierenden Funktionsdefinitionen auszuwählen. double kreis(double radius) // Funktionsdefinition 1 { return M_PI * radius * radius; } double kreis(char* radius) // Funktionsdefinition 2 { double rad = atof(radius); return M_PI * rad * rad; } void main(void) { double r=3.1; char* rc = "3.1"; cout << kreis(r) << endl; // Funktionsaufrufe nach Def.1 cout << kreis(rc); // Funktionsaufrufe nach Def.2 getchar(); } Die Funktion kreis() ist im Beispiel zweimal definiert. Die erste Definition benutzt einen doubleParameter und die zweite Definition eine char*-Parameter. In den nachfolgenden Aufrufen erkennt C++ automatisch, welche der beiden Definitionen zur Anwendung kommt. Übungsaufgaben Verfassen Sie Funktionen für C++! 56. „Zins(K,S)“, die für ein Kapital K (in €) und einen Zinssatz Z (in %) den Zins (in €) errechnet! 57. „ZzKapital(K,S,J)“, die unter Nutzung der Funktion Zins(K,S) und der Zahl der Jahre J das Kapital errechnet, was sich unter Berücksichtigung des Zinseszinses ergibt! 58. „Ganz“, die prüft, ob eine reelle Zahl ganzzahlig ist. Wenn die Zahl ganzzahlig ist wird der Boolwert „true“, sonst „false“ zurückkgegeben. 59. Erklären Sie mit kurzen Worten, was die Funktion fkt berechnet: long fkt(int w) { w -= w%2; if(w<2) return 0; else return fkt(w-2)+w; } long fkt(int w) { int p=1; if(w<0) return 0; for(;w>0;p*=w--); return p; } void fkt(int w) { int p=0; for(p=0;p<w;p++) cout<<p; } bool fkt(int w) { if(w) return false; else return true; } 33 Cassebaum, Skript zur Programmierung mit C++ 2.2 Arrays 2.2.1 Ein- und mehrdimensionale Arrays (Felder) Arrays erlauben es, große Datenmengen gleichen Datentyps zu verwalten. Ein eindimensionales Array a[n] besteht aus den n Arrayelementen gleichen Datentyps: a[0], a[1], ..., a[n-1]. Speicherplatz für die n Elemente wird durch die Definitionszeile reserviert: <Datentyp><Arrayname>[<Elementanzahl>][={<wertel0>,...,<werteln-1>}]; Eine besondere Form ist das mehrdimensionale Array, das mehr als eine eckige Indexklammer benutzt. Die Anzahl der Indexklammern zur Arraydefinition oder zur Elementnutzung wird Dimension des Arrays genannt. Das mit float a[2][3]; definierte Array a ist ein zweidimensionales Array. Der Bezeichner b[0][0][0] greift auf das physikalisch erste Element des dreidimensionalen Arrays b zu. (1) int a[5]={2,1,5,3,4}; (2) int a[2][3]={{1,5,9},{4,2,3}}; Die Arraydefinitionen (1) und (2) führen zu folgendem Speicheraufbau: 2 1 5 3 4 1 Abb. 12 Die einzelnen Arrayelemente sind im Speicher auch bei mehrdimensionalen Arrays physisch zusammenhängend (in lückenloser Folge) gespeichert. Die Vorstellung des Arrays als Tabelle oder Matrix ist zur theoretischen Vorstellung der Werte recht praktikabel. Summation der Elemente einer 3,4 Matrix: int i,k; double m[3][4], s=0; for(i=0;i<3;i++) for(k=0;k<4;k++) s += m[i][k]; cout << "Summe: " << s; 2 5 9 4 2 3 Abb. 13 0 1 2 1 5 9 0 4 2 3 1 a[0][1]=5; a[1][0]=4; a[1][2]=3; Füllung eines Lotto-Arrays mit Zufallswerten int i,k,a[10][6]; randomize(); for(i=0;i<10;i++) for(k=0;k<6;k++) a[i][k]=random(49)+1; 3 S = mi ,k i 0 k 0 2.2.2 Zufallszahlen Zufallswerte lassen sich mit randomize(), random(n) und rand() automatisch entwickeln. randomize() Stellt einen zufälligen Start zum Finden der Werte ein. random(n) Liefert ganzen Zufallswert x mit 0 <= x < n, d.h. random(2) liefert nur 0 oder 1. rand() Liefert ganzen Zufallswert x mit 0 <= x < 65536. randomize(); int a = random(201)-100; // Zufallswert -100, ..., +100 int b = rand()-32768; // Zufallswert -32768, ..., +32767 float c = random(100)/10.; // reeller Zufallswert 0.0, ..., 9.9 char d = random(’Z’-’A’+1)+’A’; // Zufallsbuchstabe A, ..., Z 34 Cassebaum, Skript zur Programmierung mit C++ 2.2.3 Strings Strings sind Ketten von Zeichen, die gemeinsam verwaltbar sind und als Hauptanwendung Texte oder einzelne Worte speichern sollen. In C/C++ Programmen arbeitet man mit Stringkonstanten in der Form “xxx“. Zur Speicherung von Strings werden in C/C++ Arrays mit char-Elementen benutzt. Es gibt für Strings in C und in C++ zwei unterschiedliche Ansätze, die im folgenden in eigenen Kapiteln dargestellt werden. 2.2.3.1 C-STRINGS („NULLTERMINIERTE STRINGS“) Für einzelne Zeichen kommt der Datentyp char zur Anwendung. ( z.B.: char z='A'; ) Die Idee der älteren Sprache C bestand darin, Strings in Arrays vom Typ char zu speichern. Um die Länge des Strings flexibel zu gestalten, wurde das Byte (0000 0000) als Endekennung („Nullterminator“) benannt, das im Arrayelement nach dem letzten gültigen Zeichen des Strings gespeichert wird. Nullterminierter String, 8 Bytes reserviert, 4 Bytes belegt char s[7]; strcpy(s,"Turm"); Nullterminierter String, 5 Byte reserviert, 4 Bytes belegt char s[]= "Turm"; oder: char *s= "Turm"; 0 1 2 3 4 5 6 7 ’T’ ’u’ ’r’ ’m’ 0 0 1 2 3 4 ? ? ? ’T’ ’u’ ’r’ ’m’ 0 Die Definition char s[]= "Turm"; (oder mit *s) vereinbart einen String der Länge 4 inklusive Nullterminator in vereinfachter Form. Einzelne Zeichen innerhalb eines Arrays werden als Arrayelemente erreicht. So enthält im Beispiel das Element s[2] den Wert ’r’. Für die Einhaltung der Terminierung sind die strxxx-Funktionen zu nutzen. z.B. strcpy(x,"Otto"); fehlerhaft wäre allerdings: x="Otto"; Die nachfolgende Tabelle enthält eine Auswahl der strxxxFunktionen, die im Header string.h definiert sind. strcat(e,q) strcmp(e,q) strcpy(e,q) strlen(e) strlwr(e) strstr(e,q) strupr(e) string(e) An den String e (vor dem 1.Komma) wird der String q angehängt. Der String e wird mit dem String q verglichen. Es werden Ergebniswerte zurückgegeben: <0 für s<q , =0 für s=q, >0 für s>q Der Quellstring q wird in die Stringgröße e kopiert. Für Strings ist die Ergibtanweisung z=s; unzulässig. Stattdessen wird strcpy(z,s); genutzt. Liefert die Länge des Strings e (in Klammern) als int-Wert zurück. Im String e werden alle Groß- in Kleinbuchstaben verwandelt. Liefert einen Zeiger auf die Position des ersten Vorkommens des Strings q im String e. ( Zeiger werden in einem späteren Kapitel erklärt) Im String e werden alle Klein- in Großbuchstaben verwandelt. Liefert einen C++-String gleichen Inhalts wie e zurück. Die Ein-/Ausgaben über cin/cout können vereinfacht durch Weglassen der Indexangabe realisiert werden. In diesem Fall wird die cout-Ausgabe bis zum Nullterminator durchgeführt und die cin-Eingabe im Zielstring automatisch mit dem Nullterminator ergänzt. char s[20]; cin >> s; // Textinput bis Leerzeichen in s mit Nullterminator cin.get(s,127); // Textinput bis Ende in s mit Nullterminator setzen cout << s; // String s wird bis Nullterminator ausgegeben cout << s[1]; // Ausgabe des 2.Zeichens im String s s[2]= ’a’; // Zuweisung eines ASCII-a als 3.Zeichen im String s for(int i=0; i<strlen(s); i++) cout < s[i]; //Ausgabe aller Zeichen von s 35 Cassebaum, Skript zur Programmierung mit C++ 2.2.3.2 C++-STRINGS ( STRINGS DER KLASSE „string“ ) Eine modernere Stringnutzung als die nullterminierten Strings gestattet der Datentyp string. Eine string-Größe kann im Borland C++ Compiler 5.5 bis zu 4.294.967.281 Zeichen speichern. Der Speicherplatzbedarf wird dynamisch angepaßt, d.h. die größte Verwendungslänge eines Strings bleibt als seine Speicherkapazität erhalten. string s; s="Fenster"; s+="kreuz"; cout << s << " " << s.length(); // Ausgabe: Fensterkreuz 12 Es gibt eine große Zahl interessanter Stringfunktionen und -operatoren. So können die bekannten Operatoren wie "=" und "+=" zur Zuweisung und "+" zur Verkettung zweier Strings verwendet werden. string int string char* string int s.substr(p,l) s.compare(s2) s.append(s2) s.c_str() s.insert(i,s2) s.length() liefert einen Teilstring von s, der in Länge l ab Position p beginnt vergleicht s mit s2, für s<s2: <0, s==s2: ==0, s>s2: >0 hängt String s2 an s an gibt nullterminierten C-String gleichen Inhalts wie s zurück fügt ab i-Position s2 in s ein. liefert die aktuelle Länge von s Auf die Einzelzeichen eines C++-Strings kann wie auf die Elemente eines char-Arrays zugegriffen werden. Wichtig ist allerdings, dass der Index nur kleiner als die Längenkapazität des Strings gewählt werden darf. string s = "Gut Holz!"; for(int i=0;i<s.length();i++) if((s[i]>=’a’) && (s[i]<=’z’))// Ausgabe: alle Kleinbuchstaben in s cout << s[i]; // Ausgabe: utolz Übungsaufgaben 60. Füllen Sie ein ganzzahliges Array mit 100 Zufallswerten zwischen 1 und 49. Bestimmen Sie den größten Wert, die Zahl der Einsen und das arithmetische Mittel aller geraden Zahlen! 61. Füllen Sie ein ganzzahliges Array mit allen Primzahlen, die kleiner als 1000 sind! 62. Füllen Sie 1000 zufällige Buchstaben in einen String! Ermitteln Sie, wie oft "ei" vorkommt! 63. Schaffen Sie ein vierdimensionales Array, das Name, Alter und Gewicht von max. 100 Personen speichern könnte! Speichern Sie Phantasiedaten für 5 Personen ab und geben Sie die Daten aus! 64. Speichern Sie 10 zufällige Lottotipps in einem Array! Drucken Sie diese Tipps geordnet aus! Beachten Sie, dass ein Lottotipp je 6 Zahlen (1..49) enthält und keine Zahl mehrfach vorkommen darf! 65. Speichern Sie in einem dreidimensionalen Zahlenfeld (10x10x10) die Multiplikationsergebnisse a*b*c für alle möglichen Zahlentripel a,b,c für a (1,..,10), b (1,..,10), c (1,..,10). Geben Sie alle Ergebnisse für a=n als Tabelle auf dem Bildschirm aus! Die natürliche Zahl n ist vorher abzufragen und vom Bediener einzugeben. 66. Schreiben Sie eine Funktion „int pos(char *s,char *sub);“ für nullterminierte Strings, die beim Aufruf von „pos(s,sub)“ die Positionsnummer des 1.Zeichens des Teilstrings „sub“ im String „s“ zurückliefert. Sollte „sub“ nicht in „s“ enthalten sein, wird eine 0 zurückgeliefert. 67. Schaffen Sie eine Funktionsüberladung für Aufgabe 58, die die Funktion pos für C++-Strings löst. 68. Schreiben Sie Programme a) für C-Strings, b) für C++-Strings -, die die Eingabe von maximal 100 Strings nacheinander abfordern! Nach jeder Eingabe wird geprüft, ob die aktuelle Zeichenkette bereits Teil einer zuvor eingegebenen war. Wenn dies der Fall ist, wird die vorherige Zeichenkette mit einer passenden Ausschrift auf dem Bildschirm angezeigt und das Programm abgebrochen. 36 Cassebaum, Skript zur Programmierung mit C++ 2.3 Adressen und Zeiger 2.3.1 Adressen Eine Adresse ist eine Größe im Computersystem, die die Position (d.h. die „Nummer“ der Speicherposition) einer gespeicherten Größe darstellt. Eine Adresse wird meist hexadezimal aufgeschrieben ( z.B. in C++, 32 Bit: 0x0012FF84 ) Speicher Adresse 00000000 Adresse („Speicherende“) FFFFFFFF 00 00 00 00 00 00 00 00 z.B.Adresse z.B.Adresse 0012FF88 0012FF84 Abb. 14 In C/C++ werden die (static -) Speicherbereiche in der Reihenfolge der Quellzeilen beginnend mit einer Basisadresse gefüllt. Ohne den static -Zusatz werden die Bereiche rückwärts zählend ab einer vom Linker festgelegten Basisadresse (im „Stacksegment“) gefüllt. Größen mit dem static-Zusatz werden in Funktionen beim Wiederaufruf unverändert bereitgestellt. Ansonsten befinden sich die Größen im Urzustand. Der static -Bereich wird vom Betriebssystem in einem gesonderten Adress-Segment eingerichtet („Datensegment“). #include <iostream.h> func() { int i=1; static int j=1; cout << i++ << " " << j++ << endl;} int main() { func(); func(); func(); getchar(); return 0; } Gibt aus: 1 1 1 2 1 3 Abb.15 2.3.2 Zeiger (Pointer) Zeiger (Pointer) sind Größen, die Adressen von Variablen, Arrays,... unter einem eigenen Namen speichern. Der Operator * kennzeichnet eine zu definierende Größe als Zeiger. Der Operator & ruft die Adresse einer C++-Grösse auf. Für &x spricht man: „Adresse von x“. Adressen werden bei Ausgaben standardmäßig hexadezimal angezeigt. int a, *ptr; ptr = &a; Abb. 16 ptr Adresse 00000000 a 00 12 FF 88 00 00 00 03 z.B.Adresse z.B.Adresse 0012FF84 0012FF88 Adresse (Speicherende) FFFFFFFF „Der Zeiger (Pointer) ptr zeigt auf die Variable a“ Ein Zeiger speziell für einen bestimmten Datentyp gebildet, weil die Bytelängen der Typobjekte unterschiedlich sind. Ein mit „double *b;“ definierter Zeiger b zeigt auf einen double-typspezifischen Datenbereich mit 8 Byte Länge. Ein mit „int *a;“definierter Zeiger a zeigt auf einen int-typspezifischen Datenbereich mit 4 Byte Länge. 37 Cassebaum, Skript zur Programmierung mit C++ int *z_zahl, zahl, *z_a, a[4]={1,2,3,4}; z_zahl = &zahl; // Lies: z_zahl gleich Adresse von „zahl“ *z_zahl = 4; // Lies: Inhalt von z_zahl gleich 4, d.h.: zahl=4 cout << z_zahl; // Anzeige der Adresse von „zahl“ cout << &zahl; // dito cout << *z_zahl; // Anzeige Inhalt der Größe, auf die z_zahl zeigt z_a = &a[0] ; // Adresse des 1. Arrayelements des Arrays „a“ z_a = a; // dito (Zeiger „z_a“ wird Aliasname von „a“) cout << z_a[2]; // Ausgabe des 3.Arrayelements von „a“(mit Alias) cout << *z_a++; cout << ++*z_a; // Zeigerarithmetik z_a = a; cout << z_a++; cout << ++z_a; Zeigt ein Pointer auf das Startelement eines Arrays gleichen Typs, so kann mit diesem Pointer in der Arraysyntax gearbeitet werden (z.B. z_a[2] ). Ein gesetzter Zeiger auf ein Array kann wie ein zweiter Bezeichner (Alias) genutzt werden, d.h.: int *p, a[4]; p = &a[0]; p[0]=1; p[1]=5; …bewirkt, dass a[0] und a[1] mit 1 bzw. 5 gefüllt werden. a p 00 12 FF 88 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 00 p Abb. 17 a[0] (p[0]) Die Addition oder Subtraktion von Zeigern mit ganzzahligen Größen n wird Zeigerarithmetik genannt. Die gespeicherte Zeigeradresse wird dabei um des n-fache der Länge des Datentyps des Zeigers verändert. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 double *pd, d[11]; int *pi, i[11]; pd = d; pi = i; *pd = 21.34; *pi = 5; cout <<pd <<" " <<pi <<endl; pd++; pi+=3; *pd = 33.99; *pi = 6; cout <<pd <<" " <<pi <<endl <<d[0] <<" " <<d[1] <<endl <<i[0] <<" " <<i[3]; Aufbau und Initialisierung zweier Arrays mit Zufallswerten. Das Array „double d[11]“ wird mit reellen Zufallswerten <100 mit 2 Nachkommastellen gefüllt.Das Array „int i[11]“ wird mit ganzen Zufallswerten zwischen -100 und +100 initialisiert. Im Beispiel wird in Zeile 08 der Zeiger „pd“ mit pd++; passend zum doubleArray um eine Elementlänge (d.h. um 8 Byte) erhöht. Der Zeiger „pi“ des int-Arrays wird in Zeile 09 mit pi+=3; um drei Elementlängen (d.h. 3 * 4 = 12 Byte) passend zum Datentyp int erhöht. 01 02 03 04 05 05 06 07 08 double *pd,d[11]; int *pi,i[11]; pd = d; pi = i; randomize(); do { *pd = random(10000)/100.; *pi = random(201)-100; pd++; pi++; } while(pd <= &d[10]); 38 Cassebaum, Skript zur Programmierung mit C++ Übungsaufgaben 69. Füllen Sie Arrays verschiedener Datentypen mit Zufallswerten! Setzen Sie je einen Zeiger auf das erste Arrayelement und geben Sie danach die Arrayelemente nur mit Hilfe dieser Zeiger aus! 70. Zwei int- Variablen x und y definieren und mit beliebigen Werten initialisieren. Weiter werden die int-Zeiger px und py definiert und passend die Adressen von x und y eingetragen. Lassen Sie sich die Adressen und die Inhalte der Größen x, y, px und py anzeigen! 71. Ergänzen Sie die Aufgabe 62! Tauschen Sie mit einem Hilfszeiger die Eintragungen in px und py! Lassen Sie sich danach die Adressen und die Inhalte der Größen x, y, px und py noch einmal anzeigen! Interpretieren Sie die Unterschiede zur Anzeige aus Aufgabe 62! 72. Schreiben Sie eine Funktion PtrToStr(…), die einen String zurückgibt, der den Inhalt und die Adresse der Variablen , auf den der über Funktionsparameter p bereitgestellte Pointer zeigt, als kommentierten Text enthält. Beispielprogrammauszug für die Funktion PtrToStr(…): string PtrToStr(int *p); // Prototyp, später zu definieren int main() { int x, *px = &x; cout << endl << PtrToStr(px); // Adress-/ Inhaltsausgabe getchar(); return 0; } 73. Bilden Sie ein Array vom Typ double mit 5 Elementen und initialisieren Sie alle Elemente mit beliebigen reellen Zahlen! Lassen Sie sich die Adressen und die Inhalte aller Elemente auf dem Bildschirm mit Hilfe der Zeigerarithmetik anzeigen! 74. Rechnen Sie x aus: a) b) c) d) int a[2],*Pa; int i,x=2; a[0]=2; a[1]=5; Pa=&a[0]; for(i=0;i<2;i++) {x*=*Pa;Pa++; } int x=22; char a[3]={61,62,0}; char *Pa; Pa=&a[1]; Pa++; x+=*Pa-x; int fkt(int x) { if(x) return fkt(--x)+x; else return 0; } int main() { int x = fkt(4); } int x; char *a="Halle"; x=a[5]+4; cout << x; 2.3.3 Zeiger und Strings Ein Zeiger auf einen nullterminierten String unterliegt einer Sonderbehandlung. char *p = “Zeiger“; cout << p[0]; cout << p; p a Diese Anweisungsfolge bewirkt, dass 00 12 FF 88 ‘Z ‘e ‘i‘ ‘g ‘e ‘r‘ 00 an einer Position im ‘ ‘ ‘ ‘ Abb. 18 Speicher, deren Adp a[0] (p[0]) resse in p gespeichert wurde, für sechs Zeichen mit dem Inhalt „Zeiger“ und einen Nullterminator Speicherplatz bereitgestellt wurde. Der Zeiger p kann wie ein als char-Array definierter nullterminierter String verwendet werden. 39 Cassebaum, Skript zur Programmierung mit C++ 2.3.4 Mehrfachzeiger Ein Mehrfachzeiger ist ein Zeiger, dessen Inhalt auf einen Zeiger niederer Ordnung zeigt. In der Zeigerdefinition erklärt die Anzahl der Sternchen * die Ordnung des Zeigers. Der Zeiger p zeigt über den Zeiger p1 auf das Objekt a. p p1 p2 b a 00 12 FF 84 00 12 FF 88 00 12 FF 80 00 00 00 03 00 00 00 03 00 00 00 03 Adresse 0012FF7C Adresse 0012FF80 Adresse 0012FF84 Adresse 0012FF88 Adresse 0012FF8C Abb. 19 #include <iostream.h> int main() { int a=3,b[2]={5,6},**p,*p1,*p2; p1= &a; p2= b; p= &p1; cout <<"\nZeiger p zeigt auf " <<p <<" Inhalt: " << *p <<" und weiter auf " <<**p; cout <<"\nZeiger p1 zeigt auf " <<p1 <<" Inhalt: " <<*p1; getchar(); return 0; } 2.3.5 Zeigerarrays Ein Zeigerarray ist eine Folge von Zeigern gleichen Datentyps und gleicher Ordnung. #include <iostream.h> int main() { int a= 1, b= 2, c= 3; int *p[3], **pp= p; p[0]= &a; p[1]= &b; p[2]= &c; while( pp <= &p[2] ) { cout <<**pp++ <<endl; } getchar(); return 0; } **pp Abb. 20 *p[0] *p[1] *p[2] a b c Zeigersituation vor dem while… Im Beispiel zeigt der Zeiger 2.Ordnung „pp“ auf ein Array „p“ für Zeiger 1.Ordnung mit drei Elementen. Der Zeiger pp zeigt vor dem Beginn der while-Schleife auf p[0]. Es wird somit über **pp der Inhalt von a ausgegeben. Durch das zusätzliche ++ wird der Zeiger pp im Sinne der Zeigerarithmetik auf den nächsten Zeiger des p-Zeigerarrays gesetzt und daher b ausgegeben, usw… Cassebaum, Skript zur Programmierung mit C++ Übungsaufgaben 75. Bilden Sie ein Array von 10 Strings! Speichern Sie mit Pointerarithmetik in jedem der Arrayelemente einen automatisch erzeugten Zufallstext mit einer Länge von mindestens 5 und maximal 30 Buchstaben! Der Text beginnt in jedem Element mit einem Großbuchstaben enthält dann ausschließlich Kleinbuchstaben! Lösen Sie die Aufgabe a) für C++- und b) für C++-Strings! 76. Erstellen Sie eine Funktion Gross(char *t), die alle Kleinbuchstaben im nulterminierten String „t“ in Großbuchstaben umwandelt! Wandeln Sie mit dieser Funktion und einer Schleifenbildung mit Zeigerarithmetik alle Arrayelemente aus Aufgabe 66 um! Lassen Sie sich das Ergebnis auf dem Bildschirm anzeigen! 77. Es ist bekannt: Die Nummer des Zugangscodes steht als int-Wert gespeichert. Die Adresse „a“ der Adresse dieses int-Wertes wird einer Funktion „… Code(…)“ als Parameter übergeben. Die Funktion „Code“ gibt den dezimalen Zugangscode als String zurück. Schreiben Sie die Funktion Code(…) und einen passenden main()-Testrahmen! 78. Speichern Sie 56 Punkte und 8 mal den Buchstaben x in einem 8*8-Feld! Die x‘e sollen zufällig mit den Punkten gemischt sein. Geben Sie das gesamte Feld zweimal nebeneinander so aus, dass genau eines der x‘e um eine Position versetzt erscheint (Richtung zufällig). Benutzen Sie Zeigerzugriffe und -arithmetik bei Änderungen und Ausgaben! 79. Erstellen Sie ein Array „good“ von 10 guten und ein Array „bad“ von 10 schlechten menschlichen Eigenschaften ihrer Wahl! Legen Sie weiter ein Zeigerarray mit 2 Elementen an, die die Adressen von good und bad enthalten! Fragen Sie den Bediener nach seinem Namen und antworten Sie mit einem Satz der eine beliebige gute und eine beliebige schlechte Eigenschaft aus den Listen anzeigt! Sorgen Sie dafür, dass bei einer späteren erneuten gleichen Namenseingabe wieder der gleiche Satz angezeigt wird! ( z.B.: Traudi, Du bist wirklich schön, aber hinterlistig!) 80. Erstellen Sie zwei überladene Versionen der Funktion: a) Replik(s) String s auf dem Bildschirm ausgeben b) Replik(s,n) String s auf dem Bildschirm n mal ausgeben und eine Zusatzversion: c) Replik2(s,n) n-malige Verkettung des Strings s als String zurückgebe 40 41 Cassebaum, Skript zur Programmierung mit C++ 3 Grundlegende Algorithmen 3.1 Dynamischer Speicher („Heap“) 3.1.1 Speicherzuweisung Statische Arrays, deren Größe schon zur Programmentwicklungszeit bestimmt werden muß, erlauben es, große Datenmengen zu definieren und zu verwalten. Es besteht der Wunsch, die Größe des vereinbarten Speicherplatzes erst während der Laufzeit zu verändern. Dazu ist es erforderlich, Speicherplatz direkt vom Betriebssystem abzufordern. Das Betriebssystem gibt die Startadresse des zugeordneten Speicherplatzes im Erfolgsfall zurück. Ein solcher Bereich wird Heap oder dynamisches Array genannt. Anforderung des dynam. Speichers <typ> *p; p = new <typ>[n]; Nutzung des Heaps Betriebssystem Rückgabe Der Adresse im Zeiger p Speicher „Heap“… Adresse des Heaps delete p; Programmsequenz… Freigabe des nicht mehr benötigten Heaps. Abb. 21 In C++ leistet der Operator new die Auslösung einer Speicherplatzanforderung. Falls die angeforderte Speicher- platzmenge nicht mehr verfügbar ist, wird der Wert 0 zurückgegeben. Der Aufruf benötigt zur Wertrückgabe einen typgerechten Pointer: <Pointer im Datentyp> = new <Datentyp> [ n ] ; Es wird Speicherplatz für n Arrayelemente im angegebenen Datentyp vom Betriebssystem angefordert. Der Pointer enthält 0 (bei Nichterfolg) oder die Adresse des bereitgestellten Speicherbereichs. int *ip, i; randomize(); ip = new int[10]; if(!ip) { cout <<"\nSpeicherfehler!"; return 1; } for(i=0 ; i<10 ; i++) { ip[i]= random(10)+1; cout << "\nElement " << i << " = " << ip[i]; } delete ip; // Pointervereinbarung // Speicheranforderung für den Heap // Erfolgreich? // Freigabe des Heaps Der angeforderte Speicherplatz kann mit delete <pointer>; wieder freigegeben werden. Dadurch wird erreicht, daß der zuvor angeforderte Speicherbereich wieder für andere Zwecke zur Verfügung steht. 42 Cassebaum, Skript zur Programmierung mit C++ 3.1.2 Beispiel für dynamischen Speicher #include <iostream.h> int main() { string **q,*z[100],*pk; // Zeiger int i = 0; char a; do { z[i] = new string[32]; // Heap pk = z[i]; do{ cout << "Name: "; cin >> *pk; if(*pk++ == "#") break; } while(pk <= &z[i][31]); cout <<"\nNeue Klasse?[j/n]:"; cin >> a; i++; if(a=='n') break; } while(i<=99); z[i] = 0; q = z; while(*q) { pk = *q; while((*pk) != "#") cout << *pk++ << " "; cout << endl; delete[] *q++; // Freigabe } getchar(); return 0; } Es sollen die Schülernamen von beliebig vielen Schulklassen gespeichert werden. Vor der Eingabe der Namen einer weiteren Schulklasse wird Heap für 32 Namen angefordert. Maximal Klassen werden dürfen 100 gespeichert Übungsaufgaben 81. Speichern Sie in einem aufzubauenden dynamischen Speicherbereich eine zufällige Anzahl (5…5000) reeller Zahlen. Die per Zufallszahlen zu bestimmenden reellen Zahlen besitzen maximal zwei Nachkommastellen und sind aus dem Bereich -2000.00, …, +1999.99 . Errechnen Sie die Summe und den Mittelwert aller reellen Zahlen im dyn. Array und geben Sie das Ergebnis über Bildschirm aus! 82. Es sollen die Kennzeichen von maximal 1000 Fahrzeugen gespeichert werden. Für jeweils 10 eingebenen Kennzeichen wird dynamischer Speicher angefordert. Geben Sie nach dem letzten einzugebenden Fahrzeug ein ‚#‘-Zeichen als Endeerkennung ein. Listen Sie danach alle Fahrzeugkennzeichen aus, die mit „MD “ beginnen! 83. Geben Sie auf dem Bildschirm ein im Heap erzeugtes rechteckiges Zahlenfeld zufälliger natürlicher Zahlen (0,…,99) aus! Das Zahlenfeld besitzt die Länge x und die Höhe von y Werten. x und y sind zufällig aus dem Wertebereich (3,…,8) zu bestimmen. Geben Sie danach das Zahlenfeld sortiert auf dem Bildschirm aus! 84. Erfassen und ausgeben von beliebig vielen Strings in einem dynamischen Stringarray. Erfassen und ausgeben von beliebig vielen Strings in einem dynamischen Char-Array als C-Strings mit max. Speichersparsamkeit. 85. Es soll eine Matrix im Format (m,n) dynamisch aufgebaut und mit natürlichen Zufallszahlen (0..99) gefüllt werden. Die Matrix im Heap wird in Zeilen/Spalten geordnet über Display ausgegeben und danach freigegeben. 86. Es werden die Quadrate von 10000 reellen Werten errechnet. Die reellen Werte sind gleichmässig über den Bereich von xa bis xe verteilt. xa und xe wurden vorher eingegeben. Angezeigt werden nur ausgewählte je 10 Werte der beiden dynamischen Arrays p[0] und p[1]. (Werte werden z.B. für eine Parabelgrafik gebraucht.) 87. Das Programm erlaubt es, für maximal 10000 Schulklassen die Klassenbezeichnung und die Namen von maximal 50 Schülern pro Klasse zu speichern und danach auszugeben. Es soll möglichst wenig Speicher (als nullterminierte Strings) passend zur aktuellen Datenmenge im Heap angefordert werden. 43 Cassebaum, Skript zur Programmierung mit C++ 3.2 Einige einfache Algorithmen 3.2.1 Sortierung Eines der Grundprobleme der Algorithmierung ist das der Sortierung von Arrays. Voraussetzung für eine Sortierung ist das Vorhandensein einer Norm für die Größeneinordnung der Elemente des Arrays. Somit muß die Frage, ob gilt: Norm(Element_1) > Norm(Element_2) eindeutig entscheidbar sein. Es gibt viele verschiedene Sortierverfahren, die hinsichtlich ihrer Komplexität unterschiedlich zu bewerten sind. Hier werden zwei Arten mit sehr verschiedener Qualität dargestellt: Quicksort (divide and conquer) #define gr 20 unsigned int gr, T[gr]; void main(void) { quicksort(0,gr-1); } void quicksort(int l,int r) { int wert,t,i=l,j=r; wert=T[(l+r)/2]; do { while(T[i]<wert) i++; while(wert<T[j]) j--; if(i<=j) { t=T[i]; T[i++]=T[j]; T[j--]=t; } } while(i<=j); if(l<j) quicksort(l,j); if(i<r) quicksort(i,r); } Insertion Sort #define gr 20 unsigned int mi,i,j,gr,T[gr]; void main(void) { for( i=2;i<=gr;i++); { mi=T[i]; j=i; while((T[j-1]>mi)&&(j>1)) { T[j]=T[j-1]; j=j-1; } } T[j]=mi; } Die Präprozessoranweisung #define gr 20 definiert den Namen „gr“, der im folgenden Modul anstelle von „20“ in den Programmtext gesetzt werden kann. Es wird damit erreicht, dass Textteile mehrmals im Programm mit symbolischen Bezeichnern gesetzt werden dürfen, die später leicht in der Präprozessorzeile gemeinsam verändert werden können. 3.2.2 Vertauschen zweier Werte Der Tausch der Inhaltswerte von zwei Variablen ist eine kleines, aber dennoch interessantes Problem. Hier werden drei Varianten gezeigt, die auf Geschwindigkeit z.B. durch 100.000-fache Wiederholung getestet werden können. Alle drei Funktionen enthalten in den Klammern anstelle … die Referenzparameter a und b. Für zu tauschende ganzzahlige Größen könnte das so aussehen: (int &a, int &b). void swap1(...) { a^=b; b^=a; a^=b; } 1 a h 3 2 b void swap2(...) void swap3(...) { register short h; { b=b+a; h=a; // 1 a=b-a; a=b; // 2 b=b-a; b=h; // 3 } } Der Datentypzusatz „register“ kann den Zugriff auf Variablen beschleunigen, weil der CompiAbb. 22 ler versucht, die definierte Größe direkt in einem Prozessorregister zu speichern. 44 Cassebaum, Skript zur Programmierung mit C++ 3.2.3 Fakultät (Rekursion) Eine einfache Lösung zur Berechnung von n! = 1*2*…*(n-1)*n {0! = 1} ist die Basis für viele numerische Berechnungsverfahren: double faku(unsigned int f) { return( f<=1 ? 1 : f*faku(f-1) ); } 3.2.4 Näherungswertbestimmung für den Sinus Im folgenden Quellprogramm wird beispielhaft eine Näherungsrechnung mit dem nebestehenden mathematischen Ansatz für die Sinusfunktion realisiert. neu alt (1) ( i 1 ) 2 i i! Es wird zyklisch aus einer Näherungslösung «alt» die neue, bessere Näherungslösung «neu» errechnet, bis gilt : |«alt» - «neu»| < 10-6. Wenn die Näherungsreihe konvergiert, wird so eine Lösung mit einer Genauigkeit von 6 Stellen nach dem Komma erzielt. double mysin(double alpha) // Sinusberechnung { unsigned int i=1; double ergneu=0.,ergalt; do { ergalt=ergneu; ergneu=ergneu+pow(-1,(i-1)/2)*(pow(alpha,i)/faku(i++)); i++; } while (fabs(ergneu-ergalt)>1E-6); // auf 6 Stellen genau return(ergneu); } 3.2.5 Euklidischer Algorithmus (ggT) Mit dem euklidischen Algorithmus kann auf einfache Weise der größte gemeinsame Teiler von zwei natürlichen Zahlen ermittelt werden. Dieser wird beispielsweise beim Kürzen eines Bruches z/n benötigt. unsigned int ggT(unsigned int z,unsigned int n) { if(!n||!z) return 0; while(n) { if(z>n) { z+=n; n=z-n; z-=n; } // Tausch n-=z; } return z; } 3.2.6 Sieb des Erastothenes (Primzahlen) #include <iostream.h> #define N 1000 int main() { int i,j,a[N+1]; for(a[1]=0,i=2;i<=N;i++) a[i]=1; for(i=2;i<=N/2;i++) for(j=2;j<=N/i;j++) a[i*j]=0; for(i=1;i<=N;i++) if(a[i]){cout.width(4);cout<<i;} getchar(); return 0; } Das nebestehende C++-Programm setzt einen aus dem 3.Jh. vor Christus stammenden Algorithmus um, mit dem man alle Primzahlen, die kleiner als eine vorgegebene natürliche Zahl N sind, bestimmen kann. Im Beispiel kann die Zahl N in der Präprozessoranweisung #define N 1000 auch auf einen beliebigen anderen Maximalwert gesetzt werden. 45 Cassebaum, Skript zur Programmierung mit C++ 4 Objektorientierte Programmierung 4.1 Strukturen und Unions (ohne „OOP“) 4.1.1 Strukturen Strukturen fassen C++Speichergrößen, wie Variablen, Arrays,... zu einem unter einem eigenen Namen verwaltbaren "Datentyp" zusammen. Die mit dem Schlüsselwort struct zusammengefassten Speichergrößen werden Attribute der Struktur genannt. Strukturen sind keine objektorientierten Größen. Wegen ihrer großen Ähnlichkeit mit den objektorientierten Klassen werden sie in diesem Kapitel behandelt. struct Brotsorte { string Bez; // Attribut Bezeichnung double Preis; // Attribut Preis unsigned int stk; // Attribut Stückzahl } a[100]; // 100 Instanzen Brotsorte b[20]; // 20 weitere Instanzen Brotsorte *p; // Zeiger auf eine Strukturinstanz b[0].Bez = "Roggenbrot"; p = new Brotsorte; // dynamische Strukturinstanz p->Bez = "Weizenbrot"; // Attributzugriff mit Zeiger cout <<b[0].Bez <<endl <<p->Bez; Eine definierte Struktur belegt keinen Speicherplatz, der Daten aufnehmen kann. Sie ist vielmehr eine Vorschrift dafür, wie Speicherplatz zu dieser Struktur gebildet werden kann. Brotsorte bs; Brotsorte *p; // Instanz „bs“ bilden // Zeiger auf eine Strukturinstanz Analog einer Variablendefinition der Standardtypen kann anstelle des Datentyps der Name einer zuvor definierten Struktur benutzt werden. Die Verwendung des Strukturnamens bei Speicherdeklarationen organisiert Speicherplatz, der alle Strukturattribute aufnehmen kann. Strukturen können auch für dynamischen Speicher instanziiert werden. Dazu werden Zeigern des Strukturtyps Speicheradressen mit der new-Anweisung zugewiesen. Die Herstellung einer Strukturinstanz wird Instanzierung genannt. Strukturdefinition („Rezept“) struct person { string name; int alter; }; 01 02 03 04 05 Abb. 23 Instanziierungen person ich,du,es; Strukturinstanzen („belegen Speicher“) person ich; ich.name = ”Emil Krause”; ich.alter= 26; b[0].Bez = "Roggenbrot"; b[0].stk = 100; p = new Brotsorte; // dynamische Strukturinstanz p->Bez = "Weizenbrot"; // Attributzugriff mit Zeiger cout << b[0].Bez << endl << p->Bez; Der Zugriff auf die Attribute statisch gebildeter Strukturinstanzen erfolgt mit dem "Punktoperator" (z.B.: "b[0].Bez"). In der Zeile 01 wird auf das Attribut Bez des ersten Elementes des Instanzarrays b zugegriffen. In Zeile 02 wird die Stückzahl b[0] für eingetragen, d.h. es sind 100 Stück „Roggenbrot“ vorrätig. 46 Cassebaum, Skript zur Programmierung mit C++ Mit einem Zeiger, der die Adresse einer Strukturinstanz enthält, kann mit dem "Pfeiloperator ->" auf ein Attribut zugegriffen werden. z.B.: "p->Bez" greift in den Zeilen 04 und 05 auf das Attribut Bez der Instanz, auf deren Adresse der Zeiger p zeigt. 4.1.2 Unions Unions fassen C++Speichergrößen, wie Variablen, Arrays,... zu einem unter einem eigenen Namen verwaltbaren "Datentyp" zusammen. Das Besondere ist, dass alle Größen an der gleichen Speicheradresse beginnen. struct WORDREGS {unsigned short ax;}; struct BYTEREGS {unsigned char al,ah;}; union REGS { struct WORDREGS x; // Wortregister (16 Bit) struct BYTEREGS h; // Byteregister ( 8 Bit) } r; // Union-Instanz r r.x.ax = 0x0101; // Zuweisung zum Register ax cout << &r.x << " " << &r.h << endl; cout << (int)r.x.ax << endl; cout << (int)r.h.ah << " " << (int)r.h.al; Startadresse der union r Abb. 24 WORDREGS x BYTEREGS h Gemeinsam von x und h belegt. Der Vorteil der Nutzung von Unions ist neben möglicher speicherplatzsparender Arbeitsweise der Zugriff auf einen Speicherplatz mit verschiedenen Größen. Im Beispiel Union_1.cpp wird eine Union für Prozessorregister beispielhaft am Wort-Register ax und den Byte-Registern al und ah dargestellt. Tatsächlich sind das al- und ah-Register jeweils Teile des ax-Registers eines Intel-Prozessors. Die Union liefert ein praktikables Hilfsmittel für die Zugriffe auf diese Register. Übungsaufgaben 88. Für die Vorbereitung einer Festveranstaltung einer Berufsschule werden gedruckte Schülerlisten benötigt, die alphabetisch nach dem Namen, nach dem Alter und nach dem Geschlecht geordnet ausgegeben werden können. Erstellen Sie eine C++ Struktur Schueler, die als Attribute ein Textfeld "Name", ein logisches Feld zur Speicherung des Geschlechts und ein Ganzzahlenfeld "Alter" integriert. Bilden Sie Funktionen zur Dateneingabe Create() und zur Druckausgabe List(Sortierfeld). Testen Sie die Methoden Create und List in der Hauptfunktion (main) durch passende Aufrufe. 89. Erstellen Sie eine Struktur Fach zur Speicherung von bis zu 10 mündlichen und bis zu 10 schriftlichen Zensuren oder Notenpunkten (00...15) für ein Unterrichtsfach. Weiter werden die Bezeichnung des Unterrichtsfaches und der(die) Name(n) der bis zu 5 unterrichtenden Lehrer(innen) in die Struktur aufgenommen. Bilden Sie eine Funktion Fach_ein() zur Eingabe der Fachbezeichnung, der Lehrernamen und der Noten (gesondert nach mündlichen und schriftlichen Noten). Erstellen Sie eine Funktion Fach_aus() zur Ausgabe aller Daten dieser Struktur, ergänzt durch den Mittelwert der mündlichen und den der schriftlichen Noten. 90. Erweitern Sie die Struktur Schueler aus Aufgabe 82 um 20 Attributinstanzen der Struktur Fach aus Aufgabe 83. Schaffen Sie ein geeignetes Menü zur Bearbeitung von Schülerdaten. Nehmen Sie zusätzliche Funktionen zur Änderung Change(SNr) und Löschung Delete(Snr) von Schülerdaten anhand der Schülernummer in das Menü auf! 47 Cassebaum, Skript zur Programmierung mit C++ 4.2 Klassen Das Konzept der OOP beruht auf der Erfahrung, dass man reale Objekte nach zwei Maßen beurteilt: Erklärung Klasse Einmal nach Eigenschaften wie Form und Farbe, Zweitens nach dem Verhalten, das ein Objekt zeigt. Attribute In der OOP werden die Eigenschaften mit Daten (Attribute) und die Verhaltensweisen mit Methoden erklärt. Objekte, die mit den gleichen Attributen und Methoden definiert werden können, werden in einer Klasse zusammengefasst beschrieben. Methoden Objekt Objekt Objekt Attributwerte Attributwerte Attributwerte Methoden Tafel 6 Methoden Methoden Definition der Klasse Instanziierung der Klasse Objekt Konstruktor Vielfache Realisierung („Instanziierung“, „Objektbildung“) Nutzungsphase Tafel 7 Destruktor Objektfreigabe 4.2.1 Objekt und Klasse Der Mensch als Objekt: Menschen besitzen individuell Eigenschaften und Verhaltensweisen. Diese lassen sich aber durch benennbare gemeinsame Attribute und Methoden beschreiben: Ein Attribut ist z.B. die Größe des Menschen, der Wert dieses Attributes ist bei den einzelnen Menschen unterschiedlich. Erklärung (Klasse) Mensch Größe, Gewicht,... denken, lesen, ... Lisa Krause Wir sagen: Die Klasse „Mensch“ enthält die „Größe“ und das „Gewicht“ als Attribute. Er kann die Methoden „denken“ und „lesen“ funktional nutzen. Nach der Erklärung der Klasse „Mensch“ wird das Objekt „Lisa Krause“ gebildet („instanziiert“). 1,66m, 54 kg,... Konkretes denken, lesen, ... Abb. 25 Realisierung (Objekt) In der Programmiersprache C gibt es keine konkreten Elemente für die Umsetzung objektorientierter Bestandteile. Das gesamte objektorientierte Modell wurde in der Sprache C++ durch Anweisungen und passende Funktionalitäten verwirklicht. Die OOP-Realisierung stellt die wesentlichste Erweiterung von C auf C++ dar. 48 Cassebaum, Skript zur Programmierung mit C++ 4.2.2 Klassendefinition in C++ Klassen fassen C++Speichergrößen (Attribute), wie Variablen, Arrays, Strukturen,... und C++Funktionen (Methoden) zu einem unter einem eigenen Namen verwaltbaren "Datentyp" zusammen. Es werden geschützte (private oder protected) und öffentliche (public) Attribute und Methoden unterschieden. class bruch { public: bruch(int z, int n = 1); bruch Mul(bruch x); void Zeige(void); private:int zaehl,nenn; } a(3,4); int main() { bruch *p; p = new bruch(2,3); a.Zeige();cout<<" * ";p->Zeige(); cout<<" = "; a.Mul(*p).Zeige(); getchar(); return 0; } // Konstruktor // externen Methoden // private Attribute // Globalobjekt // // // // Klassenzeiger dynamisches Objekt Ausgabezeile: 3/4 * 2/3 = 6/12 Eine Klasse besitzt in ihrer Handhabung sehr große Ähnlichkeit mit den Strukturen der structAnweisung. Sie belegt selbst keinen Speicherplatz, wird zur Bildung von Instanzen als datentypähnlicher Begriff benutzt. Auch die Elementzugriffe sind sehr ähnlich. 4.2.3 Objektbildung und –zugriff Die Instanzen einer Klasse werden Objekte genannt. Die Instanziierung wird daher auch gern als Objektbildung bezeichnet. Der Zugriff auf die Attribute oder Methoden statisch gebildeter Objekte (Klasseninstanzen) erfolgt mit dem "Punktoperator ." z.B.: a.Mul(*p); Im Beispiel wird auf die Methode "Mul()" des Objektes "a" zugegriffen und als aktueller Parameter das dynamische Objekt *p genutzt. Mit einem Zeiger, der die Adresse eines Objektes enthält, kann mit dem "Pfeiloperator ->" auf Klassenattribute oder -methoden zugegriffen werden. z.B.: p->Zeige() greift auf die Methode Zeige() des Objektes, auf deren Adresse der Zeiger p zeigt. Ein gemeinsamer Begriff als „Teil einer Klasse“ ist „member“ oder „Element“ einer Klasse. Nur Attribute oder Methoden können member der Klasse sein. Methoden können auch als „Memberfunktion“, Attribute als „Elementeigenschaft“ bezeichnet werden. Die Zugriffsspezifizierer public, private und protected regeln, wie von innerhalb und außerhalb der Klasse auf deren Elemente zugegriffen werden kann. Sie sind daher ein wichtiges Instrument der Datenkapselung. + public - private # protected Das Element kann von jeder eigenen/fremden Klassen erreicht werden. Das Element kann nur von eigenen Methoden benutzt werden. Es gilt zunächst das gleiche, wie für private. Klassennname Zusätzlich ist jedoch die Benutzung durch Methoden Attribute von Klassen möglich, die von der deklarierten Klasse abgeleitet sind. Methoden Klassen können zeichnerisch als Klassendiagramm dargestellt werden. → Abb. 25 49 Cassebaum, Skript zur Programmierung mit C++ 4.2.4 Konstruktor und Destruktor Der Konstruktor ist die Methode, die wie die Klasse selbst benannt ist und zum Zeitpunkt der Objektbildung automatisch gestartet wird. Die Parameter der Konstruktorfunktion können in mehreren überladenen Varianten Attribute des gebildeten Objekts füllen. Sollte kein Konstruktor selbst definiert worden sein, füllt ein automatisch gebildeter Standardkonstruktor die Attribute mit Basiswerten. Vorsicht! Wenn ein beliebiger anderer Konstruktor gebildet wird, existiert dieser parameterlose Standardkonstruktor nicht!! Der Destruktor ist wie die Klasse selbst mit vorangestelltem ~ („Tilde“) benannt wird bei der Objektfreigabe gestartet. Konstruktoren und Destruktoren besitzen keine Datentypen und deshalb auch keinen Wert. Das Anlegen eines Destruktors ist keine Pflicht. Übungsaufgaben 91. Schaffen Sie eine Klasse zur Behandlung von Brüchen mit einem Konstruktor, der die Zähler- und Nennereingabe zum Zeitpunkt der Instanziierung ermöglicht! 92. Schaffen Sie neben den notwendigen Atttributen und dem Konstruktor eine Methode „Div“, mit deren Hilfe Sie zwei Brüche addieren können und eine Methode „Zeige“, die zur Ausgabe eines Bruches auf dem Bildschirm genutzt werden kann! 93. Schreiben Sie einen Destruktor, der auf dem Bildschirm ausgibt: „Freigabe des Objekts erfolgt!“! 94. Schreiben Sie eine neue private Methode void kuerze() zum Kürzen einer rationalen Zahl! Testen Sie mit einfachen Befehlen in der main-Funktion alle Methoden! Achten Sie auf die Lauffähigkeit Ihres Programmes! 4.2.5 Vererbung und Aggregation Eine Klasse „embryo“ heißt in die Klasse „mutti“ aggregiert, wenn sie eine Instanz innerhalb der Definition der Klasse „mutti“ besitzt: class mutti{ embryo x; ...}; class embryo{...}; mutti embryo embryo x; Über die Variable „x“ wird der Zugriff auf die Elemente der Klasse „mutti“ möglich. Eine Klasse heißt abgeleitet, wenn ihre Definitionszeile den Namen einer Basisklasse benennt: Abb. 26 vati class vati{...}; class kind: public vati{...}; Aggregation (Einbettung) und Vererbung (Ableitung) sind ähnliche Verfahrensweisen mit dem Ziel, den Zugriff auf Elemente anderer Klassen zu vereinfachen. Um die richtige Wahl zwischen beiden Verfahren treffen zu können, muß die konkrete Beziehung der Klassen zueinander untersucht werden. kind Wir betrachten beispielhaft die Klassen Auto, Motor und Sportwagen. Es soll der Zusammenhang der Klassen mit Blick auf die Möglichkeiten Aggregation oder Vererbung entschieden werden. Jeder Sportwagen ist ein Auto, ein Motor ist kein Auto. Jedes Auto enthält einen Motor. Deshalb sollte die Klasse Sportwagen von der Klasse Auto abgeleitet werden. Die Klasse Motor sollte dagegen als Objekt in die Klasse Auto aggregiert werden. 50 Cassebaum, Skript zur Programmierung mit C++ // Beispiel für privaten, geschützten und öffentlichen Zugriff class Recht { public: float Flaeche(); protected: float b, h; }; class Quader:public Recht { public: Quader(float bk,float hk,float lk) { b=bk; h=hk; l=lk; } float Volumen(); protected: float l; }; void main() { Quader Q(1,2,3); cout <<"Grundfläche: "<< Q.Flaeche(); cout <<"\nVolumen : "<< Q.Volumen(); } float Recht:: Flaeche() { return b*h; } float Quader:: Volumen() { return Flaeche()*l; } Abb. 27 Übungsaufgaben 95. Schaffen Sie eine Basisklasse „Kreis“, die anhand des Attributes „Radius“ mit passenden Methoden den Flächeninhalt und den Umfang berechnen kann! Erarbeiten Sie zwei abgeleitete Klassen „Kugel“ und „Zylinder“, die Methoden zur Errechnung des Volumens und der Oberfläche dieser Körper enthalten! 96. Erarbeiten Sie die Klassen „Schüler“, „Schulklasse“ und „Schule“! Treffen Sie eine sinnvolle Wahl hinsichtlich der Einbettung oder der Vererbung der Klassen untereinander! Erarbeiten Sie einige wenige Attribute und Methoden für jede Klasse und schaffen Sie von jeder Klasse Beispielobjekte mit sinnvollen Konstruktoren! Abb. 28 51 Cassebaum, Skript zur Programmierung mit C++ 4.2.6 Textdateien/ Streams Textdateien enthalten Folgen von ASCII-Zeichen. Besondere Zeichen sind in diesem Zusammenhang die Zeichen 0x0A (LF) und 0x0D (CR), die einen Zeilenumbruch bewirken. Unter C++ läßt sich die Arbeit mit Textdateien einfach mit Streams ("Strömen") realisieren. #include <fstream.h> // zusätzlicher Header int main() { ofstream OU; char z; // ofstream für Ausgabeströme OU.open("\\temp\\cpptrain\\MeinText.txt"); // Öffnen if(!OU) { cerr<<"Fehler!"; getchar(); return 1;} cout << "Gib Zeichen ein: "; do // Eingabeschleife bis * { z=getchar(); // Zeichen von Tastatur if(z!='*') OU.put(z); // Ausgabe in Datei } while (z!='*'); OU << "\n<EOF>"; // Textausgabe in Datei OU.close(); // Schliessen der Datei return 0; } Zunächst muss ein Stream für Ein-(ifstream) oder Ausgabe(ofstream) definiert werden. Im Beispiel wird ein Ausgabestream OU vereinbart. Mit OU.open(char* File) wird dieser Stream eröffnet. Wenn die open-Methode keine 0 zurückgibt, war der Vorgang erfolgreich, ansonsten ist ein Fehler aufgetreten. Nach dem Öffnen können Zeichen entweder mit der put-Methode oder mit den Bitstreamoperator << in passende Grössen ausgegeben werden. Mit der get-Methode oder mit den Bitstreamoperator >> kann aus einem geöffneten ifstream eingegeben werden. Zum Abschluss müssen geöffnete Dateien wieder geschlossen werden: OU.close(); 4.3 Listen 4.3.1 Liste, einfach verkettet Eine einfach verkettete Liste ist eine durch next-Zeiger verknüpfte Folge dynamisch erzeugter (d.h. mit „new“ erzeugter) Objekte. Jedes Objekt besitzt ein Folgeobjekt, dessen Adresse als Objektattribut im Zeigerformat Teil jedes Objektes ist. Das letzte Objekt führt im next-Zeiger entweder NULL oder die Adresse des Startelementes („Ringliste“). Listenadresse 1.Objekt next 2.Objekt next 3.Objekt Sonderform Ringliste: Listenadresse 1.Objekt next NULL next Abb. 29 2.Objekt next 3.Objekt next Jede einfach verkettete Liste besitzt ein erstes Objekt, dessen Adresse in Form eines Startzeigers die gesamte Liste adressiert. Meist wird zur Führung einer Liste eine „aktueller“ Zeiger genutzt, der die Adresse des in Arbeit befindlichen Listenobjektes enthält. Cassebaum, Skript zur Programmierung mit C++ // programmiert von Thomas Cassebaum, all rights reserved // Typdefinitionen und Methoden zur Nutzung einer einfach verketteten Liste // *** nicht-objektorientierte Lösung ************************************* void init(); Zeiger kopf,ende,aktuell auf NULL setzen(Liste beginnen) bool fuegeeinvor(); Inhalt von satz vor aktuellem Element einfügen (false:Speicherfehler) bool fuegeeinnach(); Inhalt von satz nach dem aktuellen Element einfügen (false:Speicherfehler) void lies(); satz mit dem aktuellen Element füllen (z.B. nach next(); ) void aendern(); aktuelles Element mit satz überschreiben void head(); erstes Element als aktuelles einstellen void tail(); letztes Element als aktuelles einstellen bool next(); folgendes Element als aktuelles einstellen (false:Tail) bool prev(); vorheriges Element als aktuelles einstellen (false:Head) bool listeleer(); Ist die Liste leer? (false:nein, true:ja) bool letzteselement(); Ist das aktuelle das letzte Element? (false:nein, true:ja) int anzahl(); Rückgabe der Elementanzahl in der Liste struct t_inhalt{ string name; string nummer; }; struct t_liste { t_inhalt inhalt; t_liste* next; }; typedef t_liste* t_zeiger ; t_zeiger kopf,ende,aktuell; t_inhalt satz; FILE *datei; void init() { kopf = NULL; ende = NULL; aktuell = NULL; } bool fuegeeinvor() { t_zeiger akt=new t_liste; if(akt==NULL) { cout<<"\nSpeicherfehler! Satz nicht eingefuegt!"; return false; } if(kopf==NULL) // Sonderfall: leere Liste { kopf = akt; ende = akt; akt->next = NULL; } else { if (kopf==aktuell) // Sonderfall: Element wird Kopfelement { kopf = akt; akt->next = aktuell; } else // allgemeiner Fall { akt->next = aktuell; // Vorwaertsverkettung } } akt->inhalt = satz; // Inhalt übertragen aktuell = akt; // das aktuelle Element ist das neue return true; } bool fuegeeinnach() { t_zeiger akt=new t_liste[1]; if(akt==NULL) { cout<<"\nSpeicherfehler! Satz nicht eingefuegt!"; return false; } if(kopf==NULL) // Sonderfall: leere Liste { kopf = akt; ende = akt; aktuell = akt; akt->next = NULL; } else { akt->next = aktuell->next; // Vorwaertsverkettung aktuell->next = akt; } 52 53 Cassebaum, Skript zur Programmierung mit C++ akt->inhalt = satz; if(aktuell==ende) ende = akt; aktuell = akt; return true; // Inhalt übertragen // ggf. Ende aktualisieren // das aktuelle Element ist das neue } void lies() { if(aktuell!=NULL) satz = aktuell->inhalt; } void aendern() { if(aktuell!=NULL) aktuell->inhalt = satz; // Uebertragen des Inhaltes else fuegeeinnach(); // Wenn Liste Leer, Element einfügen } void head() { aktuell = kopf; } void tail() { aktuell = ende; } bool next() { if(aktuell->next!=NULL) { aktuell = aktuell->next; return true; } else return false; } bool listeleer() { if(kopf==NULL) return true; else return false; } bool letzteselement() { if(aktuell==ende) return true; else return false; } int anzahl() { t_zeiger akt=kopf; int counter=0; while(akt!=NULL) { counter++; akt=akt->next; } return counter; } 4.3.2 Liste, doppelt verkettet Die Listenobjekte einer doppelt verketteten Liste besitzen neben dem next-Zeiger einen weiteren wichtigen Zeiger zur Elementverknüpfung: den prev-Zeiger. Jedes Folgeobjekt besitzt einen Vorgänger, dessen prev-Adresse als Objektattribut im Zeigerformat Teil jedes Objektes ist. Das letzte Objekt führt im prev-Zeiger entweder NULL oder die Adresse des letzten Elementes („doppelte Ringliste“). NULL 1. prev next 2. prev next 3. prev NULL next Listenadresse Abb. 30 Doppelringliste: 1. prev next 2. prev next 3. prev next // programmiert von Thomas Cassebaum, all rights reserved //Listenadresse Typdefinitionen und Methoden zur Nutzung einer doppelt verketteten Liste 54 Cassebaum, Skript zur Programmierung mit C++ // *** objektorientierte Lösung ******************************************* class d_list { friend class d_liste_l; public: d_list(void): head(0), tail(0) { } d_list &insHead(d_liste_l *el); d_list &insTail(d_liste_l *el); d_liste_l *getHead(void); d_liste_l *getTail(void); private: d_liste_l *head, *tail; }; // Klasse der Listen // Zugriff auf prev und next erlauben class d_liste_l { friend class d_list; public: d_liste_l *operator++(void) { return akt=akt?akt->next:liste.head;} d_liste_l *operator--(void) { return akt=akt?akt->prev:liste.tail;} protected: d_liste_l(void):prev(0),next(0),akt(0){} virtual ~d_liste_l(void) { } private: d_list liste; d_liste_l *prev, *next, *akt; }; // Klasse der Listenelemente // Zugriff auf prev und next erlauben d_list &d_list::insHead(d_liste_l *el) { if(head) head->prev = el; else tail = el; el->next=head; el->prev=0; head=el; return *this; }; // vorn einfügen d_list &d_list::insTail(d_liste_l *el) { if(tail) tail->next = el; else head = el; el->prev=tail; el->next=0; tail=el; return *this; }; // hinten anfügen d_liste_l *d_list::getHead(void) { d_liste_l *a=head; return a; } // gib erstes Element d_liste_l *d_list::getTail(void) { d_liste_l *a=tail; return a; } // gib letztes Element // // // // // Konstruktor: Liste leer vorn einfügen hinten anfügen gib erstes Element gib letztes Element // Anfangs-/Endelement // next Operator ++ // prev Operator -- // Konstruktor: kein Vorgg./Nachf. // Folge-/Vorgänger-/aktuelles Element class X: public d_liste_l // Kindklasse von s_liste_l mit Textfld { friend ostream &operator<<(ostream &ost, X *elp) { return ost << elp->str; } public: X(char *s): str(s) { } private: char *str; // Textfeld zusätzlich zur Elternklasse }; 55 Cassebaum, Skript zur Programmierung mit C++ 5 Aufgaben zur Prüfungsvorbereitung 5.1 Theoretische Fragen, ohne PC schriftlich zu lösen 1. Erläutern Sie den Begriff „Iteration“! Nennen Sie und bringen Sie kurze Beispiele zu allen C++Schleifenformen! 2. Erklären Sie die Funktion und die Arbeitsweise des Präprozessors! Nennen Sie zwei Präprozesoranweisungen und beschreiben Sie deren Einsatzzweck! 3. Erklären Sie die unterschiedlichen Typen zur Parameterübergabe „call by value“ und „call by reference!“ in C/C++. Beschreiben Sie den Einsatz von Referenzparametern! 4. Schreiben Sie beispielhaft je einen Quelltext für eine Rekursion und eine Funktionsüberadung auf! 5. Erörtern Sie den Begriff Zeiger. Definieren Sie verschiedene Zeigervariablen für unterschiedliche Datentypen! Füllen Sie die Zeiger mit passenden Adressen und lassen Sie sich die Adressen und deren Inhalt auf dem Bildschirm typgerecht anzeigen! 6. Erörtern Sie, warum eine Kombination aus ARRAY und STRUCT zur Speicherung größerer, logisch zusammengehöriger Datenmengen genutzt wird! Schreiben Sie ein beliebiges C++-Beispiel, das Ein- und Ausgaben für Elemente der Array-Struct-Kombination enthält! 7. Erklären Sie den Begriff „dynamisches Array“! Welche Anweisung wird zum Aufbau eines solchen Arrays verwendet (Quelltext-Beispielzeile in C++)? Wie wird ein Element eines dynamischen Arrays gerufen (Quelltext-Beispielzeile in C++)? Warum und wie wird das dynamische Array freigegeben? 8. Beschreiben Sie die Realisierung der Speicherung von Zeichenketten in C (nullterminierte Strings) und in C++ (string-Klasse)! Wie können Sie programmtechnisch das fünfte und wie das vorletzte Zeichen eines CStrings und wie bei einem C++-String inhaltlich erkennen (z.B. ausgeben)? 9. Sortieren Sie ein dynamisches Array mit ganzzahligen Zufallszahlen! Berechnen Sie die Summe und den Mittelwert aller Zufallszahlen! Bestimmen Sie die Anzahl aller enthaltenen ungeraden Zahlen! Vergrößern Sie ein dynamisches Array! 10. Begründen Sie, warum für größere Datenmengen häufig nicht ARRAYs, sondern verkettete Listen verwendet werden! 11. Nennen Sie zwei Motive zur Verwendung der heute oft genutzten objektorientierten Programmierung (OOP)! 12. Beschreiben Sie , wie die rechts dargestellte C++ Funktion arbeitet und erläutern Sie deren Zweck! 13. Schreiben Sie eine Funktion rnd(double &w, int s), die die reelle Zahl w auf s Stellen nach dem Komma rundet! 14. Beschreiben Sie , wie das rechts dargestellte Struktogramm arbeitet und erläutern Sie dessen Zweck! 15. Setzen Sie das Struktogramm als C++ Hauptprogramm um und testen Sie dieses Programm! double func(double w) { int z; w = w * 100 + 0.5; z = (int)w; w = (double)z/100; return w; } Eingabe String1 Beseitige alle Zeichen in String1, die keine Ziffern (0..9) sind! Falls String1 mit „049391“ oder mit „0391“ beginnt, entferne genau diese Ziffern aus String1 Ausgabe String1 Solange (String1 nicht leer) 16. Erklären Sie bei Funktionen in C/C++ die Unterschiede des Typs der Funktion zwischen void und einem anderen beliebigen Datentyp! Begründen Sie, warum sollten globale Variablen nur in Ausnahmefällen für den Datenaustausch zwischen den Funktionen verwendet werden! 17. Erörtern Sie die Unterschiede einer einfach und einer doppelt verketteten Liste! 18. Zeichnen Sie ein Klassendiagramm für die Daten zu den Post-Sendungen als verkettete Listen! Benutzen Sie eine virtuelle Basisklasse „Sendung“ und zwei Kindklassen „Brief“ und „Paket“. Ein Brief kann die logische Eigenschaft „Doppelbrief“ besitzen. Vom Paket ist das Gewicht relevant. Zeichnen Sie eine Lösung als ein- 56 Cassebaum, Skript zur Programmierung mit C++ fach und eine zweite als doppelt verkettete Liste! Neu zu erfassende Sendungen sind grundsätzlich dynamisch zu erstellen und beim Löschen wieder freizugeben! 19. Erklären Sie die Begriffe mit Bezug zur OOP: Klasse, Instanz, Kapselung, Vererbung, Attribut, Methode, Konstruktor, Destruktor, Parentalklasse, Basisklasse, Kindklasse, Polymorphismus, Memberfunktion, Objekt, Listenanker, prev-Zeiger. 5.2 Praktische, am PC zu lösende Aufgabe a) Zeichnen Sie ein Klassendiagramm zu folgender Problemstellung. Die Klasse "Tperson" hat die nicht öffentlichen Attribute: "pnr" Personalnummer "name" Name "anr" Abteilungsnummer "gehalt" Monats-Bruttogehalt Notieren Sie im Diagramm die zur Klasse gehörenden kompletten Quelltexte der Methoden "Setze" und "Zeige" zur jeweils vollständigen Ein- und Ausgabe aller Attribute. Notieren Sie im Diagramm einen Konstruktor, der die numerischen Attribute mit passenden Nullwerten und die Zeichenketten als leere Zeichenketten initialisiert. b) Setzen Sie das Klassendiagramm aus a) in Form eines Quelltexts um, erweitern Sie es mit einer passenden main() –Funktion und den folgenden Angaben! Erstellen Sie eine statischen Instanz "beschaeftigter" dieser Klasse. Notieren Sie Quelltextzeilen zum Aufrufen der Dateneingabe- und der DatenausgabeMethode für die Instanz " beschaeftigter". c) Formen Sie die gesamte in a) und b) geschaffene Lösung so, dass Sie beliebig viele neue Mitarbeiter in einer einfach verketteten Liste speichern, löschen, ändern und anzeigen können. Zeigen Sie auf dem Bildschirm ein kurzes Menü an, was die einzelnen Funktionen per Anfangsbuchstabe abrufbar macht! d) Schaffen Sie die Statistikmethoden gesamt_gehalt(), gehalts_mittel(abteilung), mitarbeiter_zahl(abteilung), gehalt_pro_mitarbeiter_mittel(abteilung) … und testen Sie diese im Hauptprogramm! define ....................................................... 62 #include ....................................................... 11 include ...................................................... 62 abs ................................................................ 60 abweisende Schleife ................................ 20, 21 Adressen ........................................................ 61 Adressoperator .............................................. 61 Aggregation ................................................... 49 aggregiert ...................................................... 49 aktueller Parameter ...................................... 29 Alias ............................................................... 31 Alternative ..................................................... 60 Anfragefunktion ............................................ 61 append .................................................... 35, 60 Arrays....................................................... 33, 61 Assembler ........................................................ 7 Assemblersprache ........................................... 7 assign .......................................................... 60 atan .............................................................. 60 atod .............................................................. 60 atof .............................................................. 60 atoi .............................................................. 60 Attribute .................................................. 45, 48 Auftragsfunktion............................................ 61 Ausdrücke ...................................................... 14 Beamer.......................................................... 10 Bezeichner ................................................ 12 Bildschirmausgaben ...................................... 13 Bitstreamoperator >> ................................ 51 bitweise Operatoren ..................................... 14 bool ....................................................... 12, 59 break ..................................................... 19, 60 c_str ..................................................... 35, 60 C++ Trainer 2.0................................................ 9 C++Trainer ...................................................... 9 capacity ..................................................... 60 case ....................................................... 19, 60 ceil ............................................................. 60 cerr ............................................................. 59 char......................................................... 13, 59 cin.......................................................... 13, 59 class ........................................................... 61 close ........................................................... 62 clreol ......................................................... 59 clrscr ......................................................... 59 Codierung........................................................ 6 compare ................................................. 35, 60 Compiler ......................................................... 8 const ........................................................... 60 continue ..................................................... 60 57 Cassebaum, Skript zur Programmierung mit C++ cos ................................................................ 60 cout.................................................... 11, 13, 59 C-String .......................................................... 60 Datenkapselung ............................................. 48 Datentypen .............................................. 12, 59 default.................................................. 19, 60 delete .......................................................... 41 delete[] ..................................................... 61 Destruktor ..................................................... 49 divide and conqeur ........................................ 31 divide and conquer ........................................ 43 do ............................................................ 22, 60 doppelt verketteten Liste .............................. 53 doppelte Ringliste.......................................... 53 double .................................................... 12, 59 do-while-Schleifen ......................................... 22 Dynamisches Array ........................................ 41 E/A-Stream-Bibliothek................................... 11 Easycode EasyCase (C++) 6.8 ........................... 9 einfach verkettete Liste ................................. 51 else ........................................................ 18, 60 empty ............................................................ 60 Entwicklungsumgebung .................................. 9 Ergibtanweisung ............................................ 12 exit .............................................................. 62 exp ................................................................ 60 fabs .............................................................. 60 Fallunterscheidung ........................................ 19 false ............................................................... 15 Felder ............................................................. 33 fill .............................................................. 62 float ...................................................... 12, 59 floor ............................................................ 60 for ................................................................ 60 For-Anweisung............................................... 21 formaler Parameter ....................................... 28 friend .......................................................... 61 Funktionen............................................... 28, 61 Funktionsüberladung .................................... 32 fußgesteuerte Schleife .................................. 22 gcvt .............................................................. 60 get .......................................................... 59, 62 getch ............................................................ 59 getchar........................................................ 59 getline........................................................ 62 get-Methode ................................................. 51 Gleitkomma ................................................... 59 Grossbuchstaben ........................................... 62 Grundlagen der Programmierung ................... 6 Header ........................................................... 11 Heap .............................................................. 41 hex ................................................................ 62 HotKeys ......................................................... 10 if ............................................................ 18, 60 ifstream .................................................. 51, 62 in .................................................................. 62 Inhaltsoperator ............................................. 61 insert ................................................... 35, 61 Insertion Sort ................................................ 43 Instanz........................................................... 49 int.......................................................... 12, 59 integrierten Entwicklungsumgebung ............. 9 Interfacemethode ......................................... 61 Interpreters..................................................... 8 ios:: ........................................................... 62 iostream.h .............................................. 11 Iteration ........................................................ 60 itoa ............................................................. 60 kbhit ........................................................... 59 Klassen .......................................................... 61 Klassendiagramm.......................................... 48 Klasseninstanzen........................................... 48 Konstruktor ................................................... 49 Kopfgesteuert ............................................... 60 kopfgesteuerte Schleife .......................... 20, 21 Kurzübersicht ................................................ 59 length ................................................... 35, 61 Liste, doppelt verkettet ................................ 53 Liste, einfach verkettet ................................. 51 Listen............................................................. 51 log................................................................ 60 Logische Ausdrücke ...................................... 15 logische Operatoren ..................................... 14 Logische Werte ............................................. 15 main( ).......................................................... 11 main-Funktion............................................... 29 Maschinenbefehl ............................................ 6 Maschinenorientierte Programmiersprachen 7 Mathematik .................................................. 60 max................................................................ 60 Mehrfachauswahl ......................................... 19 Methoden ............................................... 48, 61 min................................................................ 60 Mnemonik....................................................... 7 new ......................................................... 41, 61 next-Zeiger .................................................... 51 nicht abweisende Schleife ............................ 22 nocreate ..................................................... 62 NULL .............................................................. 51 Nullterminierte (C-)Strings............................ 60 Numerische Ausdrücke ................................. 15 numerische Operatoren ............................... 14 Objektbildung ............................................... 61 Objekte ......................................................... 48 58 Cassebaum, Skript zur Programmierung mit C++ Objektfreigabe ............................................... 61 Objektorientierte Programmierung .............. 45 oct ................................................................ 62 ofstream ................................................. 51, 62 open .............................................................. 62 OpenGl-Grafikprogramme............................. 10 Operandenteil ................................................. 7 Operationsteil .................................................. 7 Operatoren .............................................. 14, 59 Overloading ................................................... 32 Pfeiloperator -> ............................................. 48 PI .................................................................. 60 Pointer ........................................................... 36 pow ................................................................ 60 Präprozessor-Anweisung ............................... 11 precision ................................................... 62 prev-Zeiger .................................................... 53 private ..................................................... 48, 61 Problemorientierte Programmiersprachen..... 8 Programm ........................................................ 6 Programmbegriff ............................................. 6 Programmiersprachen ..................................... 6 Programmzustände ......................................... 6 protected ................................................. 48, 61 Prozessor ......................................................... 6 Prozessorbefehl ............................................... 6 public ....................................................... 48, 61 Punktoperator ............................................... 48 put ................................................................ 62 put-Methode ................................................. 51 Quicksort ....................................................... 43 rand .............................................................. 33 random .......................................................... 33 randomize ............................................. 33, 62 Rangfolge ................................................. 14, 59 Rangfolge aller Operatoren ........................... 14 reelle Zahlen .................................................. 59 Rekursionen ................................................... 31 replace........................................................ 61 resetiosflags .......................................... 62 return .................................................... 29, 61 Ringliste ......................................................... 51 Rückgabewertes ............................................ 28 runde ............................................................. 60 Schleife .......................................................... 60 Schulgesetz ...................................................... 2 Selektion .................................................. 17, 60 Sequenz ......................................................... 17 setiosflags ............................................... 62 settextposition ...................................... 59 setw .............................................................. 62 short ...................................................... 12, 59 sin................................................................ 60 Snippetlisten ................................................. 10 Softwareentwicklung .................................... 24 Sortierung ..................................................... 43 srand ........................................................... 62 Startzeigers ................................................... 51 static ......................................................... 61 strcat ......................................................... 60 strcmp ......................................................... 60 strcpy ......................................................... 60 Streams ......................................................... 51 string ...................................................... 13, 60 strlen ......................................................... 60 strnset ....................................................... 60 struct ......................................................... 61 Strukturattribute........................................... 45 Strukturen ............................................... 45, 61 substr ................................................... 35, 61 swap ............................................................. 61 switch ................................................... 19, 60 syntax-highlighted ........................................ 10 tan................................................................ 60 Tastatureingaben .......................................... 13 textbackground ....................................... 59 textcolor .................................................. 59 Textdateien ................................................... 51 Texteingabe .................................................. 59 time_t ......................................................... 62 true ............................................................... 15 Typbezeichner............................................... 12 Unions ..................................................... 45, 61 unsigned ............................................... 12, 59 uppercase .................................................. 62 Variablen ....................................................... 12 Vererbung ..................................................... 49 Verzweigungen ............................................. 19 void ............................................................. 59 Wasserfallmodell .......................................... 24 Wert .............................................................. 12 Wertkonstante .............................................. 12 while ........................................................... 60 width ........................................................... 59 Zahlen ........................................................... 60 Zahlenwerte .................................................. 15 Zeiger ...................................................... 36, 61 Zeigeradresse ................................................ 37 Zeigerarithmetik ........................................... 37 Zufallswert .................................................... 33 Zugriffsspezifizierer....................................... 48 Zuweisung ..................................................... 12 Zuweisungsoperatoren ................................. 14 Zyklus ............................................................ 60 Cassebaum, Kurzübersicht zur Programmiersprache C und C++ 59 Kurzübersicht zur Programmiersprache C und C++ <Ax> Kurzdarstellung einer Anweisung Ax. Es könnte sich um eine einzelne C/C++-Anweisung oder um eine Block- oder Mehrfachanweisung handeln. ( Mehrere Anweisungen in { …; } geklammert stehen für eine Anweisung!) <LA> Logischer Ausdruck LA (jeder Ausdruck, der einen Wert true oder false besitzt). z.B.: =0 → false, ≠0 → true <Wx> Kurzdarstellung eines Wertes Wx. Werte in C/C++ sind datentypabhängige Größen. Beispiele: bool: true/ false, char: ’a’, int: -1, float/double: 3.14E-2, string: “Schule” <Dx> Typabhängiges Datenobjekt Dx, z.B.: Variable, Arrayelement, Funktionspara., struct-Instanz, class-Objekt <typ> Datentypbezeichner, wie int, float, bool, double, char, … (xx.h) Header xx, der mit einer #include-Präprozessor-Direktive vor Nutzung des erklärten Kommandos aufzurufen ist. Operatoren || logisch „or“ + Addition, string-Verkettung < kleiner als > größer als && logisch „and“ Subtraktion <= kleiner oder gleich >= größer gleich ^ logisch „exclusive or“ * Multiplikation, Zeigertyp == gleich != ungleich ! logisch „not“ / Division = Zuweisung += aufaddieren | bitweises „or“ % modulo (Divisionsrest) -= abziehen *= aufmultiplzrn. ~ Bitkomplement, Destruktor -> Zeiger des Elements von . Element von /= aufdividieren & bitweises „and“, Adressoperator für Zeigerzuweisung, Referenzoperator ++ Inkrement () Ausdrucksvorrang {} Anweisungsblock [] Arrayindex -- Dekrement << Linksshift, Outputstream >> Rechtsshift, Inputstream :: Bereichszuordnung , Anweisungsverbd <<= Linksshift zuweisen >>= Rechtsshift zuweisen %= Modulo zuweisen &= bitw.“und“zws. sizeof(<D>)Bytezahl von D new <typ>[n];Heapforderung delete Heapfreigabe typeid Typinfo (cast)explizite Typumwandlung mit in () gesetzten Datentyp. z.B: (3/4) ergibt: 0, aber: (float)(3/4) ergibt 0.75 Rangfolge: (1)()•[]•->•::•.(2)!•~•++•--•*•&•sizeof•new•delete•typeid•cast(3).*•.->(4)*•/•% (6)<<•>>(7)<•<=•>•>=(8)==•!=(10)^(11)|(12)&&(13)||(14)?:(15)=•+=•-=•*=•/=•%=•>>=•<<=•&=•^= (5)+•- Datentypen int unsigned int short int char bool float double long double void Länge 4 Byte 4 Byte 2 Byte 1 Byte 1 Byte 4 Byte 8 Byte 10 Byte - Textausgabe clrscr(); clreol(); cout<<...; cerr<<...; cout.width(n); _settextposition (<Wy>, <Wx>); textcolor (<W>); textbackground (<W>); cout<<“\n“ cout<<endl; cout<<“\t“ cout<<“\r“ cout<<“\b“ cout<<”\\...\’...\“...“ cout<<“\a“; oder cout<<“\007“; (conio.h) Gesamten Text im Bildschirm löschen (conio.h) Löscht Zeile ab Cursor bis zum Zeilenende (iostream.h) „stream“ Standardausgabe (auf Bildschirm, umlenkbar) (iostream.h) „stream“ Fehlerausgabe (auf Bildschirm, umlenkbar) (iostream.h) Vorgabe der Ausgabebreite als Zeichenanzahl n (conio.h) Nächste Ausgabeposition festlegen, oben und links ist (1,1) (conio.h, iostream.h) Legt Textfarbe W fest (conio, iostream.h) Legt Texthintergrundfarbe W fest (iostream.h) Neue Zeile(CR - carriage return/LF - line feed) (iostream.h) Neue Zeile(CR/LF), endl leert auch den Puffer. (iostream.h) Tabulator, springt zu Position 9, 17, 25, 33, ... (iostream.h) Wagenrücklauf, Cursor kommt an Anfang der Zeile (iostream.h) Backspace, ein Zeichen wird gelöscht. (iostream.h) Backslash \, Apostroph ’, Anführungsstriche “ ausgeben. (iostream.h) Gibt einen Ton aus (kurzes Piepsen). Texteingabe cin>> <D>; char c=getch(); getchar(); while(!kbhit()) x++; char <D>; <D>=cin.get(); <D> = getch()-’0’; (iostream.h) „stream“ Standardeingabe in D von Tastatur (umlenkbar) (conio.h) Pause bis Taste gedrückt wird, Taste in c speichern (stdlib.h) Pause bis Taste gedrückt wird (stdio.h, conio.h) Warten und zählen, bis eine Taste betätigt wird; (iostream.h) Nimmt die nächste Taste, die der User eingibt, in D auf (conio.h) D erhält den Wert der nächsten Ziffer, die gegeben wird. 31 31 „Integer“, ganze Zahlen -2 …2 -1 32 „Dual ohne Vorzeichen“, natürliche Zahlen 0…2 -1 16 „Integer-kurz“, natürliche Zahlen 0…2 -1 8 „Zeichen“, natürliche Zahlen 0…2 -1 „Boolsch“, logische Werte true (≠0) oder false (=0) „Gleitkomma einfach“, reelle Zahlen 7 Stellen genau „Gleitkomma doppelt“, reelle Zahlen 15 Stellen genau „Gleitkomma lang doppelt“, reelle Zahlen 19 Stellen genau leer, „nichts“ Cassebaum, Kurzübersicht zur Programmiersprache C und C++ 60 Zahlen und Mathematik <D>*=-1;<D>/=2;<D>+=1;<D>-=1; Ändere <D> durch Multiplizieren von <D> mit -1, dividieren durch 2, … <D1>=<D2>++; Erhöhe <D2> nach Zuweisung, d.h.<D1> wird alter Wert zugewiesen. <D1>=--<D2>; Vermindere <D2> vor Zuweisung, d.h. <D1> bekommt den neuen Wert <D>=sin(<W>),cos,tan,atan,... (math..h) diverse mathematische Funktionen für Parameter W W2 <D>=exp(log(<W1>)*<W2>) (math.h) (W1) rechnen (Exposant) und D zuweisen. abs(<W>), fabs(<W>), labs(<W>) (math.h,stdlib.h) Die Absolutbeträge von int/float/long W2 <D>=pow (<W1>,<W2>) (math.h) (W1) rechnen und D zuweisen. <D>=ceil(<W>); (math.h) D den ganzzahlig aufgerundeten Wert von W zuweisen. <D>=floor(<W>); (math.h) D den ganzzahlig abgerundeten Wert von W zuweisen. <D>=min(<W1>,<W2>); (stdlib.h) D das Minimum von W1 und W2 zuweisen. <D>=max(<W1>,<W2>); (stdlib.h) D das Maximum von W1 und W2 zuweisen. 0x1A9F / 015237 hexadezimale Zahl (beginnt mit 0x) /oktale (beginnt mit 0) 3.14159f Wert anstelle von double(Standard) als float im Programm ablegen. 44. Wertkonstante anstelle von int (Standard ohne Punkt) als double ablegen. Maximalwerte für signed/unsigned: char: 127/255, int: 2,14Mrd. / 4,27Mrd., Maximalwerte/Stellengenauigk. float:3.4e38/7,double:1.7e308/15,long double:3.4e4932/19 M_PI (iostream.h) Zahlkonstante π (Pi) als double-Wert const long PI= 3.14159; Festlegen von Konstanten <D1>=atoi(<D2>); (stdlib.h) D1 wird der int-Zahlenwert vom String D2 zugewiesen <D1>=atod(<D2>); (stdlib.h) D1 wird der double-Wert vom String D2 zugewiesen <D1>=atof(<D2>); (stdlib.h) D1 wird der float-Zahlenwert vom String D2 zugewiesen itoa(<W>, <D>, n); (stdlib.h) int-Wert W Basis n:2|8|10|16 in C-String(nt.) D wandeln. gcvt(<W>, <D>, n); (stdlib.h) double-Wert W (n Stellen) in C-String(nullt.) D wandeln. Selektion (Alternative) if(<LA>)<A1>; if(<LA>)<A1>; else <A2>; switch(i) { case 1: case 2: <A1>; case 3: <A2>; break; default: <A3>;} <D>= <LA>? <W1>: <W2>; Wenn LA=true, wird Anweisung(-sblock) A1 abgearbeitet, sonst nicht. Wenn LA=true, wird Anweisung(-sblock) A1 abgearbeitet, sonst A2. Fallunterscheidung, Mehrfachselektion, i muss ganzzahlig sein, falls i den Wert 1 oder 2 enthält, wird A1 und danach A2 ausgeführt, falls i den Wert 3 enthält, wird nur A2 ausgeführt, jeder nicht als vorlaufendes case abgeprüfter Wert führt zur Bearbeitung von A3. ?-Operator: Falls LA=true, erhält D den Wert W1, sonst den Wert W2. Iteration (Schleife, Zyklus) for(<A1>; <LA>; <A2>) <A3>; Kopfgesteuert: Führt zuerst genau 1x Anweisung A1 aus, prüft dann den logischen Ausdruck LA. Solange LA=true, wird nun zyklisch zuerst A3 und dann A2 ausgeführt (bis LA=false). for(i=a; i<b; i+=c) <A>; Zählschleife: Anfangswert a, Endwert b, Schrittweite c (1: A läuft b mal) while(<LA>) <A>; Kopfgesteuert, Solange logischer Ausdruck LA=true, führe A aus do <A>; while(<LA>); Fußgesteuert, Wie while, LA wird erst nach der 1. Ausführung geprüft. break; sofortigerAbbruch eines switch-, for-, do-, oder while-Blockes continue; Fortsetzung mit Schleifenbeginn (kein Schleifenabbruch) Nullterminierte (C-)Strings char s[20]; char s[]= “Weissbrot“; strcpy(s, “Hallo“); strcat(s, “ Welt!“); <D>= strcmp (s, q); <D>= strlen(s); <D>= strnset(s, z, n); Definition eines C-Strings s (char-Array) mit maximal 20 Zeichen Definition eines C-Strings s mit Inhalt „Weissbrot“ für max. 9 Zeichen (string.h) C-String s wird mit Text und Nullterminator gefüllt. (string.h) An den C-String s wird angehängt, \0 wird angepasst (string.h) Vergleicht C-Strings s und q (s<q→D<0, s=q→D=0, s>q→D>0) (string.h) Ermittelt die Länge des Textes im String, ohne Terminator (string.h) C-String s wird mit n mal dem Zeichen (char) z gefüllt. (C++-)Strings der Klasse string string s; s+=“kette“; s.append(“kette“); s.append(“kette“, 0, 3); s.assign(“kette“); <D>= s.capacity(); <D>= s.c_str(); <D>= s.compare(q); <D>= s.empty(); s.erase(); Definition eines C++-Strings s (class string) hängt den String „kette“ an C++ String s an. hängt den String „kette“ an C++ String s an. hängt die ersten 3 Zeichen an C++ String s an. ersetzt den C++ String s durch „kette“. Gibt in D die Zeichenkapazität des C++ String s zurück. Übergibt im char-Array D den C++ String s als nullterminierten (C-)String vergleicht die C++ Strings s, q (s<q→D<0, s=q→D=0, s>q→D>0). fragt, ob der C++ String s leer ist. bool D ist true, wenn s leer ist. löscht den Inhalt des C++ Strings s, d.h. s erhält den leeren String als Inhalt. Cassebaum, Kurzübersicht zur Programmiersprache C und C++ <D>= s.find(q, 3); s.insert(3, q); <D>= s.length(); s.replace(a, l, q); s.resize(l, z); <D>= s.substr(a, l); s.swap(q); Funktionen void <Fktname>(...) <typ> <Fktname>(...) ... <Fktname>(void) return x; return; ... Fkt(char <D1>, int <D2>=9) ... <Fktname>(...); void Fkt() const static <D1>=999; Arrays <typ> arrn; int a5= {1, 2, 3, 4, 5}; float b354; 61 Sucht im C++ Strings s ab der 3.Position den String q. Gibt Position des Vorkommens von q in s als als int-Wert an D zurück. (0 für nicht gefunden). Fügt im C++ Strings s ab der 3.Position den String q ein. Gibt die Länge C++ Strings s in Zeichen an D zurück. Fügt im C++ Strings s ab der a.Position den String q in der Länge l ein. Füllt den C++ Strings s bis zur Länge l mit Zeichen z auf. Gibt den Teil des C++ Strings s ab Position a in Länge l zurück. Tauscht den Inhalt des C++ String s mit dem Inhalt von String q. Auftragsfunktion (liefert keinen Wert zurück) Anfragefunktion (liefert <typ>-Wert über return-Anweisung zurück) Funktion wird ohne Parameter aufgerufen Funktion gibt den Wert x zurück Beenden einer Funktion Wenn Fkt ohne 2.Parameter gerufen wird, dann wird Parameter D2=9. Prototyp, jede Funktion muss einmal im Voraus definiert werden Funktion ist read-only, d.h. kann keine Daten ändern. Statische Variable (innerhalb Funktion) deklarieren. Behält unveränderten Wert nach Beenden beim erneuten Ruf. (ohne static: Wert zerstört) b243= 17; Festlegen eines Arrays arr mit n Elementen vom Datentyp <typ>. Definieren des Arrays a mit 5 Elementen a[0]…a[4] mit Initialisierung. Festlegen eines (3)dimensionalen Arrays (Feldes). Dieses Array besitzt 3*4*5= 60 Elemente im Bereich von b000 bis b243. Wertzuweisung an ein Arrayelement Zeiger und Adressen char *Z1, double *Z2; Zeig1= &<D>; cout << *Z1; char *s= “Weissbrot“; int <D1>; int &<D2>=<D1>; int *p = new int[n]; delete[] p; Zeiger kann eine Adresse speichern und somit auf ein Objekt zeigen. Adressoperator, gibt die Adresse statt dem Wert von D zurück Inhaltsoperator * benutzt den Zeiger Z1 zur Ausgabe des Zeigeobjekts Definition eines C-Strings s mit Inhalt „Weissbrot“ für max. 9 Zeichen Referenz <D2> hat dieselbe Speicheradresse wie <D1>. („Alias“) Fordert ein dynamisches Array(Heap) p der Grösse n und Typ int ab. Gibt das dynamische Array(Heap) p wieder frei. Strukturen und Unions struct artikel { int ArtNr; double Umsatz ...;} In1; artikel In2, *In3; In1.ArtNr= 20; In3=new artikel; In3->ArtNr=33; union ... (siehe struct) Festlegen der Struktur artikel Festlegung des Strukturelementes ArtNr Implizite Instanziierung der Instanz In1 (In der Deklarationsanweisung); Explizite Instanziierung der Instanz In2 (Außerhalb der Strukturdeklar.); Eingabe der Werte für die Struktur artikel Dynamische Erstellung einer Strukturinstanz Zugriff auf ein Element einer dynamischen Strukturinstanz Wie struct, bloss dass alle Elemente denselben Speicherbereich nutzen. Klassen class xx { private: Definition einer Klasse „xx“ int x; Zugriff nur mit klasseneigenen Methoden möglich int met1(); parameterlose private Methode „met1()“ protected: ...; Zugriff mit klasseneigenen und ererbten Methoden möglich public: ...; öffentlicher Zugriff (alle dürfen zugreifen) void SetX(int xs){x=xs;} Interfacemethode, zum Setzen des Privatattributs x xx(int xs){x=xs;} Konstruktor, diese Methode wird bei der Objektbildung gestartet ~xx(); Destruktor, wird wird bei der Objektfreigabe gestartet (Prototyp) } Ob1,Ob2(3); Implizite Objektbildung der Objekte Ob1, Ob2 (oder: Instanz Ob1) xx Ob3; Implizite Objektbildung des Objektes Ob3 void xx::sp(void) (Ausserhalb der Klasse) Die Funktion sp gehört zur Klasse xx. xx::~xx() { cout<<"tot"; } Bei Freigabe einer Instanz von xx wird "tot" ausgegeben friend int freund(kla1, kla2); Deklaration der friend-Methode freund, welche Zugriff auf private class schueler:public mensch schueler erbt alles von der Klasse mensch (Zugang auf alles) class sch:public k1,k2,... sch erbt alles von k1, k2, ... Cassebaum, Kurzübersicht zur Programmiersprache C und C++ 62 Verschiedenes include“my_h.h“ Präprozessor: Header wird zuerst im Programmverzeichnis gesucht. define WERT 12 const Wert=12 Präprozessor: Festlegen von unveränderbaren Variablen. randomize(); (stdlib, stdio, time) aktiviert den Zufallsgenerator srand(getpid()); (stdlib, process) aktiviert einen besseren Zufallsgenerator time_t t; (time.h, stdlib.h, Zufallsgenerator wird mit neuen Zuf.werten initialisiert srand((unsigned)time(&t)); (process.h) (sehr nützlich!) b=rand()%100; (stdlib, stdio, time) b erhält einen Wert >=0 und <100 (int) exit(0); (process.h) Programm beenden, gibt den Rückkehrcode 0 zurück time_t jetzt=time(NULL); while (time(NULL)<jetzt+10); (time.h, dos.h) Pause von 10 Sekunden Streams cout.width (42) (iomanip.h) Daten über << werden in Breite 42 Zeichen ausgegeben cout << setw(10) << ”...” (iomanip.h) Links wird mit Leerzeichen bis Ausgabebreite 10 aufgefüllt. cout.fill('.'); (iomanip.h) Anstatt mit Leerzeichen wird (hier) mit . aufgefüllt. setiosflags(ios::left) (iomanip.h) Ausrichtung der Daten wird auf linksbündig geändert. resetiosflags(ios::left) (iomanip.h) setiosflags rückgängig machen cout.setf(ios::fixed); (iomanip.h) Zahlen gleicher Nachkommaanzahl (cout.precision vorher benutzen) cout.precision(x); (iostream.h) Angabe der Stellenzahl, mit der eine Zahl ausgegeben wird. cout<<setiosflags(ios::showpos) (iomanip.h) Auch bei positiven Zahlen wird das Vorzeichen angezeigt cout << dec oder hex oder oct (iomanip.h) Zahlen werden in bestimmten Zahlensystemen ausgegeben cout<<setiosflags(ios::uppercase; (iomanip.h) Hexzahlen A…F werden als Grossbuchstaben ausgegeben while((cin.peek())>’9’||cin. peek()<’0’)cin.ignore(); Untersucht Eingabezeichen ; nur Ziffern werden akzeptiert. cin.getline(text,127); (fstream.h) Das Eingegebene wird in text kopiert bis zum nächsten Return cin.get(text,127); (fstream.h) Das Eingegebene wird in text kopiert bis zum nächsten Return. ofstream Ausgabe; (iomanip, fstream.h) Erzeugung des ofstream-Objektes Ausgabe Ausgabe.open(datei1,ios::app) (iomanip, fstream.h)datei1 (= Name der Datei) wird geöffnet, Zeiger ans Dateiende setzen ios::in Lesen, verhindert bei Ausgabedateien Löschen ios::nocreate Kein Anlegen fehlender Dateien ios::out Schreiben; ohne Angabe weiterer Modi werden vorhandene Dateien gelöscht ios::app Ausgabe an Datei anhängen ios::ate Ausgabe an Datei anhängen, erlaubt nach erster Schreibanweisung. ios:noreplace Keine vorhandene Datei überschreiben ios::trunc Vorhandenen Dateiinhalt löschen Ausgabe.close(); (iomanip, fstream.h) Objektfreigabe von Ausgabe und Datei schliessen. ofstream Ausgabe2(d2,ios ::ate) (iomanip, fstream.h) Zeiger wird an den Anfang der Datei gesetzt. zeichen=eingabe.get()od:eingabe.get(z)(iomanip, fstream.h) Einzelne Zeichen worauf der Zeiger zeigt, wird in z kopiert. ausgabe.put(z) (iomanip, fstream.h) Das Zeichen auf das der Zeiger zeigt, wird durch z ersetzt.. ifstream test; Testet ob eine Datei existiert (löscht oder ändert nichts und test.open(te xt,ios::in|ios:nocreate); legt auch keine neue Datei an falls nicht vorhanden) if (test.good())... Falls der Test in der vorigen Zeile gut ausgefallen war, … ofstream Drucker(„PRN“,ios::out|ios::app);cout=Drucker; Umlenkung von cout auf den Drucke close Schliesst eine Datei put Schreibt ein einzelnes Zeichen get Liest Zeichen und lässt Stoppzeichen im stream read Liest Datenblock in einen Speicherbereich getline Liest Zeichen und entfernt Stoppz. aus Datei seekg,seekp Bewegt Dateizeiger ignore Entfernt Zeichen aus dem Datenstrom tellg,tellp Ermittelt Dateizeigerposition open Initialisiert das Objekt und öffnet eine Datei write Schreibt einen Speicherbereich als Datenblock peek Prüft Folgezeichen im stream, ohne zu lesen