Home
c++ einfuehrung - theopenunderground.de
Contents
1. ASCII Kurzzeichen Bezeichnung Darstellung 7 BEL Alarm Warnton a 8 BS R ckschritt Backspace XD 9 HT Horizontal Tabulator END 10 LF Zeilenvorschub Line Feed Ein 11 VT Vertikal Tabulator ar 12 FF Seitenvorschub Form Feed I 13 CR Wagenr cklauf Carriage Return REN 34 ji Anf hrungszeichen END 92 Backslash IN 96 Apostroph Hochkomma Ta In String Konstanten k nnen nicht druckbare Zeichen ebenso wie in Zeichenkonstanten verwendet werden Der String Erste Zeile nZweite Zeile enth lt ein Zeilenvorschub Zeichen Wenn Sie innerhalb einer Stringkonstante nichtdruckbare Zeichen in der allgemeinen Form verwenden ist Vorsicht angebracht Wollen Sie etwa auf einem Standard Nadeldrucker die Kursivschrift einschalten so m ssen Sie die Sequenz Esc 4 senden Sie k nnen also erst das Zeichen 33 und dann das Zeichen 4 senden Wenn Sie beide Zeichen in einem String zusammenfassen ergibt sich 334 Dies wird aber als String mit nur einem Zeichen 334 mit dem Oktalcode 0334 oder dem Dezimalcode 220 aufgefa t denn der Oktalcode darf bis zu drei Stellen besitzen Sie k nnen dieses Problem vermeiden indem Sie den Oktal oder Sedezimalcode mit f hrenden Nullen auf drei Stellen auff llen 0334 1 6 Ausdr cke und Operatoren Wie in Pascal werden Ausdr cke auch in C aus elementaren Einheiten durch beliebige Anwendung von Operatoren geb
2. I Test der Zugriffsmethoden I I II II VI main unsigned a b C i a b 0 a und b leere Meng a a a Komplement a 0 15 for i 2 i lt 10 i a amp 1 lt lt i Elemente 2 9 entfernen a 0 1 10 15 for i 4 i lt 12 i De ESI 882155 Elemente 4 11 einf gen b 4 11 cout lt lt n neue Zeile zeigeBits a zeigeBits b None e era b c Vereinigung von a und b 0 1 4 15 zeigeBits c ce a amp b c Durchschnitt von a und b 10 11 zeigeBits c Die Nachteile eines solchen Programmierstils ohne Prozedurabstraktionen d rften klar auf der Hand liegen Hier k nnen sich bei jeder Mengenoperation Fehler einschleichen weil immer wieder maschinennahe Operationen verwendet werden berdies sind solche Programme nur mit ausf hrlichen Kommentaren lesbar Bei Kommentaren kann man sich aber nie sicher sein ob sie wirklich den aktuellen Stand des Programms wiedergeben Schon deshalb d rfte es vern nftiger sein eine lesbare Version eines Programms zu verfassen Die n chste Version zeigt wie man in nicht objektorientierten Sprachen abstrakte Datentypen realisieren kann indem sie das Klassenkonzept von C ignoriert IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII I II I II I II I II IV BITSET1 CPP Realisierung eines abstrakten Datentyps FE mit konventionellen Mitteln
3. Komplexe Deklarationen Verschachtelte Deklarationen sind in C nicht ganz einfach zu durchschauen weil der Aufbau nicht wie in Pascal geradlinig von links nach rechts geschieht sondern unter Ber cksichtigung der Vorrangregeln Eine Deklaration in C besteht aus einem Typnamen und dahinter einem verschachtelten Ausdruck der den Namen des zu deklarierenden Objekts enth lt Zum Verst ndnis mu man wissen da dieser Ausdruck ein Objekt vom Typ des davorstehenden Typnamens bezeichnet Ein Beispiel soll dies verdeutlichen int a n Diese Deklaration definiert ein Objekt a mit der Eigenschaft da a n vom Typ int ist Welchen Typ hat demnach a selbst Die Frage l t sich schrittweise beantworten a n ist von Typint a ist vom Typ Vektor von int a ist vom Typ Zeiger auf Vektor von int Wichtig f r die richtige Interpretation verschachtelter Deklarationen ist die Kenntnis der Vorrangregel Un re einstellige Operatoren und dazu geh ren insbesondere die Vektorklammern 1 und die Funktionsklammern sind rechtsassoziativ Um es nochmals zu wiederholen Wenn rechts und links von einem Ausdruck ein solcher Operator steht wird zun chst der rechte Operator angewendet Lassen wir in der obigen Deklaration die runden Klammern weg ndert sich die Bedeutung int aln vollst ndig geklammert int aln aln ist von Typ int a n ist vom Typ Zeiger auf int a ist vom Typ Vektor von Zeig
4. return rl int operator rational amp rl rational amp r2 Zahlen sind immer normiert return rl p r2 p amp amp rl q r2 g int operator rational amp rl rational amp r2 return rl r2 ostream amp operator lt lt ostream amp s rational r return s lt lt r p lt lt lt lt r g Die Gefahr eines berlaufs bei der Long Arithmetik l t sich verringern wenn wir bei einigen Operatoren zus tzliche K rzungen versuchen Hier sind die Alternativen rational operator rational rl rational r2 rational r long t ggr rl q r2 qg g errl g 6 p r g r2 p r q t rl p q r2 g eturn rational r p r q k rzen DI IF rational operator rational rl rational r2 long t ggT rl p r2 q if E21 rE p Fe tr 22 40 et t ggT rl q r2 p IE ES HELLES Er ED Jet return rational rl p r2 p rl q r2 qg rational operator rational rl rational r2 long t ggr rl p r2 p IE er gt E E a FEED Petr t ggT rl gq r2 q if e gt 1 elg J Ei r2 qg gt tr return rational rl p r2 q rl q r2 p Es folgt ein kleines Programm das einige der Operatoren testet II I II III I II I II I II RATIOTST CPP I II I II I II I II I II Test von RATIONAL CPP Arithmetik mit rationalen Zahlen Va Projekt besteht aus RATI
5. Kreis Kreis int x0 int y0 int r0 Figur x0 y0 Radius r0 void Kreis zeige circle x y Radius void Kreis loesche setcolor BLACK circle x y Radius setcolor WHITE Implementierung der Klasse Rechteck Rechteck Rechteck int x0 int y0 int xl int yl Figur x0 y0 a x1 x0 b yl y0 void Rechteck zeige rectangle x y xta y tb void Rechteck loesche setcolor BLACK rectangle x y Xta ytb setcolor WHITE _Test der Klassen 1 1 1 1 1 1 1111111111 int main char c int graphdriver DETECT graphmode initgraph amp graphdriver amp graphmode borlandce bgi outtextxy 10 8 Figur mit Cursortasten bewegen outtextxy 10 24 Figur wechseln R Jechteck K reis outtextxy 10 40 Ende Esc Kreis K getmaxx 2 getmaxy 2 40 Rechteck R 0 0 80 60 Figur aktuelleFfigur amp K aktuelleFigur gt zeige do c getch auf Tastendruck warten if c 0 normale Zeichentaste andere Figur aktuelleFigur gt loesche switch toupper c case K aktuelleFigur amp K break case R aktuelleFigur amp R break aktuelleFigur gt zeige else erweiterter Tastencode Cursorbewegung ce getch
6. class fVektor public fVektor long i0 long il char Datei fVektor DateiPos operator long i protected FILE Dateizeiger char Dateiname MAXPATH long Groesse Basis F3 1 1 1 1 1 1 1 1 _ implementierung 1 1 1 1 1 1 1 1 11 111 1 DateiPos operator INT Typkonvertierung INT n fseek Dateizeiger Position SEEK SET fread amp n sizeof INT 1 Dateizeiger return n r r void DateiPos operator INT i fseek Dateizeiger Position SEEK _ SET fwrite amp i sizeof INT 1 Dateizeiger ostream amp operator lt lt ostream amp s DateiPos p return s lt lt INT p Dem Konstruktor wird der Indexbereich und der Name der tempor ren Datei angegeben fVektor fVektor long i0 long il char Datei Groesse il i0 1 Basis i0 strcpy Dateiname Datei Dateizeiger fopen Datei w t Der Destruktor l scht die Datei automatisch fVektor fVektor fclos Dateizeiger remov Dateiname DateiPos fVektor operator long i DateiPos p p Dateizeiger Dateizeiger p Position i Basis sizeof INT return p IIIIIIII III II III III II III III I II Test IIIIIIIIIIII III III II III VI main int iy fVektor A 10000 20000 C SVEKTORS TMP cout lt lt n for i 10000 i lt 20000 i 1000 cout lt lt Ali lt lt cout
7. FIALA AAN II LAA IAII ILAA ALAALA ALALIA ELALLA ILA ALAALA ILLA AAAI AAAA EA include lt iostream h gt define INT_BITS 16 ifndef BOOLEAN Definition des Datentyps boolean define BOOLEAN enum false true typedef int boolean endif Definition des Datentyps bitset typedef unsigned bitset I I Zugriffsfunktionen von bitset I II void loesche bitset amp s s 0 void incl bitset amp s int i s 1 lt lt i void excl bitset amp s int i s amp 1 lt lt i boolean enthaelt bitset s int i return s amp 1 lt lt i gt 0 void vereinige bitset amp s bitset sl s sl void schneide bitset amp s bitset sl s amp sl void komplementiere bitset amp s s s void zeige bitset s COuUE lt lt R for int 1 0 I lt INI BITS IFFY cout lt lt enthaelt 5 I R TET 2 7 cout lt lt n I Test der Zugriffsmethoden I I II II I main bitset a b c loesche a loesche b for int i 0 i lt 8 i incl a i for i 4 i lt 12 i incl b i cout lt lt n neue Zeile cout lt lt a zeige a cout lt lt b zeige b c a vereinige c b cout lt lt Vereinigung von a und b zeige C c a schneide c b cout lt lt Durchschnitt v
8. berladen haben m ssen Sie den Operator trotzdem explizit berladen wenn Sie ihn verwenden wollen Trotz dieser Unabh ngigkeit sollten Sie diese Operatoren so implementieren da sie die Kombination des arithmetischen Operators und der Zuweisung darstellen Die Inkrementierungsoperatoren Diese Operatoren k nnen nach dem berladen sowohl als Pr fix wie auch als Postfix Operatoren verwendet werden Die Wirkung ist aber in beiden F llen die gleiche Die Gleichheitsrelation und die Ungleichheitsrelation Im Gegensatz zum Zuweisungsoperator gibt es keine Standard Behandlung der Gleichheits bzw Ungleichheitsrelation Wenn Sie Klassenobjekte auf Gleichheit oder Ungleichheit pr fen m chten m ssen Sie diese Operatoren berladen es sei denn Sie definieren einen Konvertierungsoperator in einen Standard Datentyp und der Vergleich der konvertierten Werte liefert das von Ihnen gew nschte Ergebnis Der Ungleichheitsoperator ist auch nicht automatisch das logische Gegenteil des Gleichheitsoperators Es m ssen also wenn sie ben tigt werden stets beide Operatoren berladen werden Der Vektorklammer Operator 11 Dieser Operator wird verwendet um bei selbstdefinierten Vektor oder Matrixtypen die bliche Schreibweise anwenden zu k nnen Der Operator ist ein zweistelliger Operator der aber in seiner Syntax etwas aus dem Rahmen f llt W hrend die blichen zweistelligen Operatoren zwischen den beiden Operande
9. case K aktuelleFigur K break case R aktuelleFigur R break switch aktuellerFigur case K K zeige break case R R zeige break else erweiterter Tastencode Cursorbewegung c getch switch aktuelleFigur case K switch c case 72 K bewege 0 10 break aufw rts case 80 K bewege 0 10 break abw rts case 75 K bewege 10 0 break links case 77 K bewege 10 0 break rechts break case TRE switch c case 72 R bewege 0 10 break aufw rts case 80 R bewege 0 10 break abw rts case 75 R bewege 10 0 break links case 77 R bewege 10 0 break rechts break while c 33 Esc Taste closegraph return 0 Vererbung des Zugriffsschutzes Es bleibt nur noch ein kleines Problem Die Elemente x und y der Klasse Punkt sind als private deklariert Deshalb kann die Klasse Kreis darauf nicht zugreifen Um private Elemente auch abgeleiteten Klassen zug nglich zu machen verwendet man das Schl sselwort protected W hrend privat Elemente nur Elementfunktionen der Klasse selbst zug nglich sind k nnen protected Elemente auch von abgeleiteten Klassen angesprochen werden Der Vollst ndigkeit halber sei hier auch die Bedeutung des Schl sselworts public im Kopf abgeleiteter Klassen erw hnt In der Definition class B public A erkl rt der Zugriffsmodifizierer public da
10. Die do Anweisung Die repeat Anweisung aus Pascal wird in C durch die do Anweisung ersetzt repeat Anweisungsfolge do Anweisung until Ausdruck while Ausdruck Beachten Sie bitte folgende Unterschiede repeat wird durch do ersetzt until durch while Statt einer Abbruchbedingung in Pascal wird in C eine Wiederholungsbedingung angegeben also das logische Gegenteil Die Bedingung wird wie in der if und while Anweisung auch in runde Klammern gesetzt Die Syntax der repeat Anweisung f llt in Pascal etwas aus dem Rahmen Sie ist die einzige strukturierte Anweisung in die nicht nur eine sondern beliebig viele Unteranweisungen eingesetzt werden d rfen ohne sie zu einer Verbundanweisung zu klammern Die Klammerung bernimmt hier das abschlie ende Schl sselwort until Obwohl die entsprechende Anweisung in C formal gleichartig aufgebaut ist darf trotzdem nur genau eine Anweisung eingesetzt werden repeat do a Be a i i i ec a a T until i gt n while i lt n Das Schl sselwort while wird in C also f r zwei verschiedene Zwecke eingesetzt F r die Anfangsabfrage der while Anweisung und f r die Endabfrage der do Anweisung Das Schl sselwort do steht in C einzig f r die do Schleife In Pascal wird es f r ganz andere Zwecke verwendet nach while for und with Die for Anweisung Die for Anweisung in Pascal ist nicht gerade ppig ausgestattet for Variable Ausdruck to Ausdruck do Anweisung
11. switch c case 72 aktuelleFigur gt bewege 0 10 break aufw rts case 80 aktuelleFigur gt bewege 0 10 break abw rts case 75 aktuelleFigur gt bewege 10 0 break links case 77 aktuelleFigur gt bewege 10 0 break rechts while c 33 Esc Taste closegraph return 0 bungsaufgabe 13 Was gibt das folgende Programm aus include lt iostream h gt class Klassel public void frueheBindung cout lt lt fr heBindung Klassel n virtual void spaeteBindung cout lt lt sp teBindung Klassel n Fs class Klasse2 public Klassel public void frueheBindung cout lt lt fr heBindung Klasse2 n virtual void spaeteBindung cout lt lt sp teBindung Klasse2 n F3 void main Klassel Objekt1 Klasse2 Objekt2 Klassel ptrl ptr2 cout lt lt n ptrl amp Objektl ptr2 amp Objekt2 ptrl gt frueheBindung ptr2 gt frueheBindung ptrl gt spaeteBindung ptr2 gt spaeteBindung r r Polymorphe Listen Eine typische Anwendung der sp ten Bindung sind po ymorphe Listen Ein CAD Programm mu zum Beispiel eine Vielzahl verschiedener Objekte speichern Hierzu definiert man eine abstrakte Basisklasse mit virtuellen Funktionen von der alle ben tigen Objekttypen abgeleitet werden k nnen Alle Objekte k nnen dann in einer Liste von Zeigern auf die B
12. Gr ines Elements int Vergleichsfunktion const void const void char xip 73 for i Basis t Anzahl 1 Groesse i gt Basis i Groesse for j Basis j lt i j Groesse if Vergleichsfunktion i j lt 0 vertausche i j Groesse int VglInt int i int j return i jJ main int i static int A 1l0 31 41 59 26 53 58 97 93 23 84 cout lt lt nunsortiert n for i 0 i lt 10 i cout lt lt Ali lt lt bsort A 10 sizeof int VglInt cout lt lt nsortiert n for i 0 i lt 10 it cout lt lt Ali lt lt cout lt lt n Bitte bedenken Sie da der Bubblesort Algorithmus bei gr eren Datenmengen ziemlich ineffektiv arbeitet In der Standard Bibliothek von C STDLIB H gibt es auch eine Quicksort Implementierung qsort die mit genau den gleichen Parametern aufgerufen wird 1 11 Deklarationen und Definitionen Die beiden Begriffe Deklaration und Definition sind geeignet vollst ndige Verwirrung hervorzurufen weil ihre Bedeutung in verschiedenen Kontexten v llig unterschiedlich gehandhabt wird Folgen wir einem modernen Standardwerk der Informatik Watt90 so ist eine Deklaration ein Programmst ck das einen Namen mit einem Objekt im weitesten Sinne verbindet Existiert dieses Objekt bereits so spricht man von einer Definition Einige Beispiele in Pascal m gen dies kl ren const n 1 Definition Bindung
13. program BitsetTest type bitset set of 0 15 var i integer a b c bitset procedure zeigeBitset b bitset var i integer begin for i 0 to 15 do if i in b then write lse write writeln end begin a leere Menge Del for i 2to 9doa a t il LOr 1 3526 80or rdo b ss bet EE write a zeigeBitset a write b zeigeBitset b c a b write a b zeigeBitset c a b write a b zeigeBitset c c a b write a b zeigeBitset c end Hier wird der in Modula 2 brigens schon vordefinierte Datentyp bitset eingef hrt Anschlie end werden die in Pascal verf gbaren Mengenoperationen Vereinigung Durchschnitt und Mengendifferenz getestet In C gibt es keine Mengentypen Deshalb setzen wir in einer ersten Version die Mengenoperationen direkt in die entsprechenden Bit Operationen um IIIIIIIIIIIIIIII I II III I III III I II III II III III I II II III I II I II BITSETO CPP Konventionelle L sung Direkter Zugriff auf einzelne Bits a 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 111 include lt iostream h gt define INT BITS 16 abh ngig vom Compiler void zeigeBits unsigned s COUE lt lt MET for int i 0 i lt INT_BITS T cout lt lt s amp 1 lt lt i 0 2 2 cout lt lt n
14. 1 4 kein Fehler float z 1 5 Rundungsfehler weil 1 5 periodischer Dualbruch Bei der dritten Zuweisung ergibt sich im Dezimalsystem ein abbrechender Bruch 0 2 Im Computer wird die Zahl jedoch im Dualsystem dargestellt und ergibt den periodischen Dualbruch 0 00110011 In manchen Anwendungen zum Beispiel in der Computergrafik bei der Speicherung von Schnittpunkten zweier Geraden wird eine exakte Darstellung von rationalen Zahlen ben tigt F r solche Anwendungen wollen wir eine Klasse rational entwickeln die rationale Zahlen exakt darstellt indem sie Z hler und Nenner speichert Das erschwert nat rlich die arithmetischen Operationen etwas Z hler und Nenner werden in den privaten Elementen p und q vom Typ long gespeichert Zun chst sehen Sie die Header Datei II III III III III I II I RATIONAL H I II I II I III I II I II I II L Arithmetik mit rationalen Zahlen IIIIIIIIIIIIII I II I II III II II I II I I II I II III I II I II I II I II ifndef RATIONAL H define RATIONAL H include lt iostream h gt class rational public rational long Zaehler 0 long Nenner 1 private friend rational operator rational r un res Minus friend rational operator rational rl rational r2 friend rational operator rational rl rational r2 friend rational operator rational rl rational r
15. Compiler gibt hier eine Warnung aus wenn void weggelassen wird while 1 Vorbedingung der while Schleife 2 Nachbedingung in do Schleife Operator 1 Trenner zwischen Funktionsparametern 2 Komma Operator Operator 1 Funktionsaufruf bzw Parameterliste 2 Typ Umwandlung Typname Ausdruck 3 Cast Operator Typ Ausdruck Operator 1 Bin r Multiplikationsoperator 2 Un r pr fix Dereferenzierungsoperator auch zur Zeigerdefinition Operator amp 1 Un r pr fix Adre Operator 2 Un r postfix Referenz Operator 3 Bin r Bitweise Und Verkn pfung Operator 1 Bitweise Negation 2 Bezeichnung des Destruktors Operator 1 Bin r Klassenspezifikation 2 Un r Ansprechen globaler Objekte D Unterschiede zwischen C und C C ist eine Fortentwicklung der Sprache C Das hei t aber nicht da jedes C Programm automatisch auch mit dem C Compiler bersetzt werden kann Die Kompatibilit t besteht vielmehr darin da C Moduln und C Moduln beliebig zu lauff higen Programmen gebunden werden k nnen C selbst hat mehrere Entwicklungsstufen durchlaufen In der urspr nglichen Version vor der ANSI Normierung gab es keinerlei berpr fung von Funktionsaufrufen auf korrekte Parameter und R ckgabetypen C war eine Sprache von Freaks f r Freaks Was machte es da schon da ein Programm vom Compiler klaglos bersetzt wurde dann beim Lauf abst rzte und ein langwierige
16. die Zugriffsattribute bei abgeleiteten Klassen erhalten bleiben Wenn Sie den Zugriffsmodifizierer weglassen oder private verwenden sind in der abgeleiteten Klasse alle aus der Basisklasse geerbten Elemente privat Einen genauen berblick soll die folgende Tabelle geben Zugriff in abgeleiteter Klasse bei Zugriffsmodifizierer Zugriff in Basisklasse public private public public private protected protected private private kein Zugriff m glich kein Zugriff m glich Aufrufreihenfolge von Konstruktoren und Destruktoren Wenn ein Objekt einer abgeleiteten Klasse erzeugt wird wird nicht nur der Konstruktor der abgeleiteten Klasse aufgerufen sondern auch der Konstruktor der Basisklasse Zus tzlich m ssen noch die Konstruktoren aller Datenelemente der abgeleiteten Klasse aufgerufen werden Manchmal h ngt die Korrektheit eines Programms von der Reihenfolge dieser Aufrufe ab Die Konstruktoren werden immer in der folgenden Reihenfolge aufgerufen 1 Der Konstruktor der Basisklasse 2 die Konstruktoren der Datenelemente der abgeleiteten Klasse 3 der Konstruktor der abgeleiteten Klasse selbst Falls die Basisklasse wieder eine abgeleitete Klasse ist setzt sich das Spiel rekursiv fort Die Destruktoren werden in umgekehrter Reihenfolge aufgerufen Das folgende Beispiel verdeutlicht den Mechanismus und zeigt au erdem da eine gew hnliche Elementfunktion die in der abgeleiteten Klasse neu definiert wird
17. int Monatslaenge int Monat int Jahr static int MoLg 12 31 28 31 30 31 30 31 315 30 31 30 31 if Monat 2 return Schaltjahr Jahr 29 28 else return MoLg Monat 1 boolean Schaltjahr int Jahr return Jahr 4 0 amp amp Jahr 100 0 Jahr 400 0 Auf der Diskette zum Buch finden Sie ein Programm KALENDER das einen Jahreskalender einschlie lich der beweglichen Feste auf dem Bildschirm zeigt Zun chst wird das aktuelle Jahr dargestellt Mit den Cursortasten k nnen beliebige Jahre gew hlt werden 3 6 Definition von Typumwandlungen Ganze Zahlen sind spezielle rationale Zahlen Es ist daher nat rlich arithmetische Operationen zwischen ganzen und rationalen Zahlen zu erlauben Wenn wir alle m glichen Kombinationen ber cksichtigen wollen m ssen wir die Klassendeklaration allein f r die Addition so erweitern class rational public friend rational operator rational rl rational r2 friend rational operator int i rational r2 friend rational operator rational rl int i 7 Sicher sind Sie nicht begeistert von der Vorstellung f r alle Operatoren alle m glichen Typ Kombinationen zu implementieren Zum Gl ck geht es auch einfacher Es gen gt die Addition zwischen zwei Operanden vom Typ rational zu definieren wenn der Compiler wei wie er int Zahlen in den Typ rational umwandeln kann Bei den Standard Datentypen haben Sie die implizit
18. Durch eine for Anweisung der Form for Anweisung l t sich also eine Endlosschleife darstellen Die switch Anweisung Mit der case Anweisung in Pascal kann die folgende Anweisung vom Wert einer ordinalen Selektor Variablen abh ngig gemacht werden Der gleiche Mechanismus steht auch in C zur Verf gung case Monat of switch Monat 1 Tage 31 case 1 Tage 31 break 2 Tage 28 case 2 Tage 28 break 3 Tage 31 case 3 Tage 31 break 4 Tage 30 case 4 Tage 30 break 5 Tage 31 case 5 Tage 31 break case 6 Tage 30 break 6 Tage 30 case 7 Tage 31 break 7 Tage 31 u P case 8 Tage 31 break 8 Tage 31 case 9 Tage 30 break 9 Tage 30 _ case 10 Tage 31 break 10 Tage 31 ra case 11 Tage 30 break EN case 12 Tage 31 break 12 Tage 31 g D 5 end Das Pascal Schl sselwort case wird in C durch switch ersetzt Der Selektorausdruck wird in C in runde Klammern gesetzt daf r entf llt das Wort of Vor jeden einzelnen Fall mu das Wort case gesetzt werden Der wichtigste Unterschied liegt in der Art der Abarbeitung Pascal f hrt nur die Anweisung nach der zutreffenden Konstanten aus C dagegen alle Anweisungen ab der zutreffenden Konstante Wird dies nicht gew nscht das ist der Normalfalll mu die Abarbeitung der weiteren Anweisungen durch das Schl sselwort break verhindert werden Nur durch diese merkw rdige
19. ENDE 0 Sie k nnen und sollen hier noch nicht alle Details der rechten Spalte v llig verstehen Es geht einfach darum da Sie eine gewisse Vorstellung von der syntaktischen Form eines C Programms bekommen Auf einige Besonderheiten m chte ich hier schon eingehen Sie werden sie alle sp ter noch einmal systematisch kennenlernen Zeile 1 Das Schl sselwort program entf llt in C ersatzlos Stattdessen sehen Sie rechts einen Kommentar Zeilen 2 4 Diese Zeilen entsprechen den uses Anweisungen in Turbo Pascal Die Pascal Version ben tigt keine speziellen Units Zeile 6 In C gibt es nur typisierte Konstanten Zeile 8 In C gibt es keinen speziellen String Typ Die Deklaration entspricht array O n of char Zeile 10 Variablen werden in C ohne ein spezielles Schl sselwort deklariert Erst kommt der Typname und dann der oder die Bezeichner Zeile 12 Auch Funktionsdefinitionen kommen in C ohne ein eigenes Schl sselwort aus Der Typ des Funktionswerts steht am Anfang Es gibt keinen eigenen Typ boolean Zeilen 16 17 Die Schl sselw rter begin und end werden in C durch geschweifte Klammern ersetzt Lokale Deklarationen stehen in C innerhalb der Blockklammern Zeilen 18 19 F r die Zuweisung verwendet C das einfache Gleichheitszeichen In Pascal werden Strings ab eins indiziert in C dagegen ab Null Zeile 20 21 Bei der while Anweisung entf llt das Schl sselwort do Daf r mu die Bedi
20. Namen des Objekts folgt durch einen Punkt getrennt der Name des Elements Puffer P Definition eines Objekts vom Typ Puffer P Anfang 0 versuchter Zugriff auf privates Element P leere Elementfunktion Die zweite Zeile dieses Beispiels f hrt zu einem Fehler weil das Element Anfang privat ist Die dritte Zeile zeigt den Aufruf der Elementfunktion leere Welches Objekt geleert werden soll sagt der Objektname P Es gibt also bei jeder Elementfunktion einen impliziten Parameter n mlich einen Zeiger auf das Objekt von dem aus die Funktion aufgerufen wurde Dieser Zeiger ist brigens auch explizit unter dem Schl sselwort this ansprechbar was allerdings selten n tig ist Klassen und Strukturen Ein abstrakter Datentyp der so realisiert wird wie wir es hier getan haben wird in der objektorientierten Programmierung Klasse genannt Deshalb wird in C statt struct vorzugsweise das Schl sselwort class verwendet Der einzige Unterschied zwischen struct und class besteht darin da in einer struct alle Elemente ffenlich sind falls sie nicht als private erkl rt werden in einer class dagegen sind alle Elemente privat wenn sie nicht als public erkl rt werden Es gibt vielleicht zu Ihrer Beruhigung noch einen Unterschied zwischen Funktions und Datenelementen Jedes Objekt einer Klasse hat seine eigenen Datenelemente Die Funktionen werden dagegen nur einmal f r die Klasse gespeichert Im allgemeinen sollte man s
21. Unterschied zwischen Text und Bin rdateien Es ist m glich in einer Datei Text und Bin rabschnitte unterzubringen Wir betrachten hier die Dateifunktionen nach der ANSI Norm Alternativ dazu gibt es in Borland C auch die Dateifunktionen des Betriebssystems UNIX Wenn Sie die ANSI Dateifunktionen verwenden m ssen Sie die Header Datei STDIO H einbinden Neben den Funktionsdeklarationen ist dort der Datentyp FILE definiert Er enth lt alle Komponenten die zur Bearbeitung einer Datei ben tigt werden Obwohl Ihnen diese Komponenten zug nglich sind in Standard C gab es im Gegensatz zu C noch keinen Schutzmechanismus zum Verbergen von Typ Details sollten Sie den Typ FILE als Black Box auffassen und auf ihn nur mit den im folgenden besprochenen Funktionen zugreifen ffnen einer Datei Eine Datei wird mit der Funktion FILE fopen const char path Dateiname const char mode Art des Zugriffs er fffnet F r die Art des Zugriffs kann eingesetzt werden mode Datei wird ge ffnet men zum Lesen read w zum Schreiben write war zum Schreiben ans Ende der Datei append NERY existierende Datei zum Lesen und Schreiben w neue Datei zum Lesen und Schreiben a berall lesen schreiben nur am Ende Ohne eine Datei zu ffnen k nnen folgende FILE Zeiger verwendet werden tdin Standard Eingabe tdout Standard Ausga
22. bergeben Da es sich um Wertparameter handelt kann die Prozedur zwar nicht diese Adressen ndern Die Adressen sind aber der Schl ssel zum Zugriff auf die eigentlichen Zahlenwerte In Turbo Pascal k nnte man diese Prozedur etwa so aufrufen program Test1 type IntPtr integer procedure tausche pa pb IntPtr var h integer begin h pa pa pbs PEA h end var a b integer begin are Deir WriteLn a 4 b 4 tausche Addr a Addr b WriteLn a 4 b 4 end Wenn Sie diese beiden Varianten vergleichen w ren Sie sicher nicht begeistert wenn Sie von nun an auf Referenzparameter verzichten m ten In Standard C gibt es aber tats chlich nur Wertparameter Deshalb sind C Programmierer zu einer Zeigerakrobatik verurteilt wie wir sie gerade gesehen haben Zum Gl ck wurde dieses Manko beim bergang von C nach C beseitigt Es folgen jetzt die Versionen unseres Beispiels in C und C Ver nderung von Parametern in C Wertparameter und Adre bergabe Ver nderung von Parametern in C Re void tausche int pa int pb void tausche int amp a int amp b int h int h h pa h a pa pb a b pb h b h void main void main inta D int a b a 1 arm iy b 2 b 2 printf 4 4 n a b printf 4 4 n a b tausche amp a amp b tausche a b printf 4 4 n a b printf 4 4 n a b Sie sehen also da sich
23. const void src size_t n size t i char Ziel char Quelle ziel char dest Quelle char src for i 0 i lt n i Zielli Quelle i return dest Um jede beliebige Anzahl von Bytes kopieren zu k nnen haben wir die universellen Zeiger hier in char Zeiger umgewandelt Der Typ char belegt in jeder Implementierung genau ein Byte Damit k nnen wir das oben formulierte Kopieren von Vektoren kurz so schreiben memcpy A B 4 sizeof int Vielleicht fragen Sie sich wie man in C Vektoren darstellen kann deren Indizes nicht bei Null anfangen Eine etwas undurchsichtige L sung dieses Problems ist die Verschiebung eines Zeigers auf den Vektoranfang var A array n0 nl of integer int AO nl1 n0 1 int A A0 n0 F r eine saubere L sung mit Index berpr fung m ssen Sie sich bis zur Einf hrung des Klassenkonzepts gedulden In Pascal gibt es eine spezielle Zeigerkonstante ni1 die auf kein Objekt zeigt und mit jedem Zeigertyp vertr glich ist Diese Konstante nil hat intern den Wert Null In C ist es ganz hnlich Obwohl Zeigertypen nicht mit dem Typ int vertr glich sind kann die int Konstante Null jedem Zeigertyp zugewiesen werden Man sollte hierf r aber besser die in der Datei stdde f h vordefinierte Konstante NULL verwenden Das ist lesbarer und erh ht die Chance mit zuk nftigen Sprach nderungen vertr glich zu bleiben bungsaufgabe 5 Warum ergibt die doppelte Zuweisung
24. erster string s2 zweiter string s3 dritter s3 sl 32 cout lt lt sl lt lt s2 lt lt s3 lt lt n Nun haben Sie die n tigen Kenntnisse um hnliche Aufgaben wie etwa Matrizenrechnung elegant zu l sen Hierzu soll ein Hinweis gen gen Sie k nnen eine Matrix als Vektor von Zeilenvektoren definieren Ist m eine Matrix dann sollte der Operator f r Mm i eine Referenz auf den i ten Zeilenvektor von m liefern Dann ist automatisch M i k eine Referenz auf das entsprechende Matrix Element Anhang B L sungen der bungsaufgaben Aufgabe 1 if a gt 0 amp amp a lt 4 b a Aufgabe 2 Die for Schleife wird bei i 21 mit der break Anweisung abgebrochen F r i 0 20 also 21 mal wird n um 100 erh ht Die Zeile n wird erst ab i 10 also 11 mal ausgef hrt Damit bekommt n den Wert 21 100 11 2111 Aufgabe 3 F r die nicht angegebenen Parameter wird die kleinstm gliche int Zahl eingesetzt Sie ist in der Header Datei LIMITS H definiert include lt limits h gt int max0 int a int b INT_MIN int c INT MIN if a gt b if a gt c return a else return c else if b gt c return b else return c Es folgt eine alternative L sung mit einem bedingten Ausdruck int max int a int b INT MIN int c INT MIN return a gt b a gt c a c b gt c b cc Aufgabe 4 F arl IIIN f Tria Li TB ETEN Fehler
25. lt lt n for i 10000 i lt 20000 i Ali for i 10000 i lt 20000 i 1000 cou cout lt lt n H zZ Ali lt lt el g 3 7 Statische Elemente Objekte eines Klassentyps greifen auf gemeinsame Klassenmethoden zu Sie k nnen sich nur in der aktuellen Belegung ihrer Datenelemente unterscheiden Manchmal werden auch Datenelemente ben tigt die nur einmal f r die Klasse existieren und von allen Objekten genutzt werden k nnen zum Beispiel um die zum Erzeugen von Objekten zur Verf gung stehenden Ressourcen zu berwachen Hierf r wird das Schl sselwort static in einer neuen Bedeutung verwendet Ein mit deklariertes Datenelement existiert nur einmal pro Klasse Es kann von allen Objekten angesprochen werden Eine mit deklarierte Elementfunktion der Klasse x wird mit x aufgerufen Sie kann alternativ auch von einem Datenelement x der Klasse mit x aufgerufen werden hat aber auch dann keinen this Zeiger und darf demnach nicht auf nicht statische Datenelemente zugreifen Ein Skelett Programm zeigt die M glichkeiten und Grenzen auf class A public int i static int j statisches Datenelement v rd 6b static v id g statische Elementfunktion F7 void A f Eine nicht statische Elementfunktion i darf auf nicht statische j und statische Datenelemente zugreifen void A g i Fehler statisch
26. nur in der aktuellen Version aufgerufen wird include lt iostream h gt class Hilfsklasse public Hilfsklasse Hilfsklasse Fs class Basis public Basis Basis void f Es class Abgeleitet public Basis public Abgeleitet Abgeleitet void f Hilfsklasse h Hilfsklasse Hilfsklasse cout lt lt Konstr Hilfsklasse n Hilfsklasse Hilfsklasse cout lt lt Destr Hilfsklasse n Basis Basis cout lt lt Konstr Basis n Basis Basis cout lt lt Destr Basis n void Basis f cout lt lt Fkt Basis n Abgeleitet Abgeleitet cout lt lt Konstr Abgeleitet n Abgeleitet Abgeleitet cout lt lt Destr Abgeleitet n void Abgeleitet f cout lt lt Fkt Abgeleitet n main Abgeleitet b b f 0 Das Programm erzeugt folgende Ausgabe Konstr Basis Konstr Hilfsklasse Konstr Abgeleitet Fkt Abgeleitet Destr Abgeleitet Destr Hilfsklasse Destr Basis Bei der Erkl rung der Aufrufreihenfolge der Konstruktoren sind wir stillschweigend davon ausgegangen da die Basisklasse einen Konstruktor ohne Parameter besitzt Es gibt auch einen speziellen Mechanismus um Konstruktoren von Basisklassen aufzurufen die Argumente verlangen n mlich die Initialisierer Liste Dazu wird zwischen Funktionskopf und Funktionsblock nach einem Doppelpunkt der explizite Konstr
27. p cerr lt lt p lt lt n exit 1 string string int n p new stringDaten p gt s new char n 1 p gt Referenzen 1 string string const char s p new stringDaten p gt s new char strlen s 1 strcpy p gt s s p gt Referenzen 1 string string const string amp s s p gt Referenzentt t p S p string string if p gt Referenzen 0 delete p gt s delete p inline int string length return strlen p gt s string amp string operator const string amp s if p gt Referenzen 0 delete p gt s delete p s p gt Referenzentt pP SiP return this char amp string operator int i if i lt O i gt strlen p gt s error unerlaubter Index return p gt s i int operator const string amp s const string amp t return strcmp s p gt s t p gt s 0 int operator const string amp s const string amp t return strcmp s p gt s t p gt s 0 ostream amp operator lt lt ostream amp s string amp t return s lt lt t p gt s lt lt t p gt Referenzen lt lt string operator const string amp sl const string amp s2 int 11 strlen sl p gt s string t 11 strlen s2 p gt s strcpy t p gt s s1l p gt s strcepy t p gt s 1l1l s2 p gt s return t main string sl
28. r Textdateien oder p f r Bin rdateien anh ngen Wenn Sie keinen Buchstaben anh ngen wird ein Standardwert gew hlt der in einer globalen Variablen _fmode gespeichert und auf t voreingestellt ist Lesen aus einer Datei size_t fread void ptr Puffer Adresse size_t size Elementgr e in Bytes size_t n Anzahl derElemente FILE stream Dateizeiger Die Funktion fread file read entspricht der Turbo Pascal Prozedur BlockRead W hrend Sie bei BlockRead eine Puffer Variable bergeben k nnen m ssen Sie bei fread die Adresse explizit bergeben Beim Lesen von Vektoren ersparen die beiden Parameter size und n eine Multiplikation Als Funktionswert wird die Anzahl der tats chlich gelesenen Elemente nicht Bytes zur ckgegeben char fgets char s Pufferadresse int n Puffergr e FILE stream Dateizeiger fgets file put string entspricht in etwa der readin Prozedur in Pascal Die Funktion liest bis zum n chsten Zeilenwechsel und schreibt die Zeile mit dem Zeilenende Zeichen als String mit 0 abgeschlossen in den Puffer s Das Lesen wird vorzeitig abgebrochen wenn die Puffergr e n nicht ausreicht Als Funktionswert wird die Pufferadresse s zur ckgegeben Wird beim Lesen das Dateiende berschritten ist das Ergebnis NULL int fgetc FILE stream fgetc file get character liest ein Zeichen in einer Datei und gibt das gelesene Zei
29. 2 sin Pi 2 wird berechnet Die Vorrangregeln In Pascal m ssen Sie ziemlich viele Klammern setzen weil es nur vier Vorrangstufen gibt Am st rksten bindet der not Operator danach kommen die multiplikativen Operatoren div mod and dann die additiven Operatoren or und schlie lich mit schw chster Bindung die Vergleichsoperatoren lt gt lt gt gt lt in C bietet eine 16 stufige Operatorenhierarchie Deshalb ist die einfachste Faustregel Wenn Sie die Vorrangregeln nicht ganz sicher beherrschen sollten Sie lieber einige Klammern zuviel als zuwenig verwenden Eine vollst ndige Tabelle aller Operatoren auch der Ihnen bisher unbekannten finden Sie im Anhang Hier sollen einige Hinweise gen gen Sehr oft kommen logische Verkn pfungen von Vergleichsrelationen vor In Pascal m ssen die Vergleiche geklammert werden in C ist das berfl ssig if a gt 0 and b gt 0 then if a gt 0 amp amp b gt 0 Einige Operatoren verhalten sich anders als Sie es vielleicht erwarten So binden die Schiebe Operatoren schw cher als die Addition und Subtraktion Die Ausdr cke a 16 1unda lt lt 4 1 sind nicht quivalent Sie werden n mlich so interpretiert a 16 1unda lt lt 4 1 Un re einstellige Operatoren und Zuweisungsoperatoren sind rechtsassoziativ Das hei t Wennrechts und links von einem Ausdruck ein solcher Operator steht wird zun chst der rechte O
30. Diagramm verdeutlicht die M glichkeiten der Dereferenzierung von Zeiger Objekten Jetzt st rt noch da wir den Speicherplatz explizit belegen und zum Schlu wieder freigeben m ssen In Pascal geschieht dies automatisch der Speicherplatz wird mit der Deklaration reserviert und bei Verlassen des G ltigkeitsbereichs automatisch freigegeben Daf r mu die Gr e ein konstanter Ausdruck sein w hrend es in C auch m glich ist die Gr e erst zur Laufzeit zu bestimmen Von dieser neuen Freiheit haben wir in unserem Beispiel gar keinen Gebrauch gemacht In solchen F llen k nnen wir uns noch weiter der Pascal Schreibweise n hern Array in Pascal Array in C 3 Version program ArrayTest main var i integer ine I A array 0 3 of integer int A 4 begin for i 0 to 3 do for i 0 i lt 4 i A i i A i i end Durch eine Deklaration der Form Vektor Deklaration Typname Variablenname int Konstante wird Speicherplatz f r int Konstante Objekte von Typname reserviert und Variablenname mit der Adresse dieses Speicherplatzes initialisiert Der Zeiger Variablenname wird als Konstante aufgefa t Beim Verlassen des G ltigkeitsbereichs wird der so belegte Speicher automatisch freigegeben Obgleich die letzte Version schon fast wie in Pascal aussieht sollten Sie sich immer wieder vergegenw rtigen da es eigentlich keine Arrays in C gibt Was geschieht etwa in folgendem Beispiel main int
31. Fest String 4 lt lt n Fest 49 cout lt lt Pfingstsonntag lt lt Fest String 4 lt lt n Fest Busstag J cout lt lt Bu und Bettag lt lt Fest String 4 lt lt n n cout lt lt Heute ist lt lt jetzt String lt lt n cout lt lt Mozart ist am lt lt Mozart String lt lt geboren n cout lt lt Seitdem sind lt lt jetzt Mozart lt lt Tage vergangen n Es folgt die Implementierung der Klasse Dat um Um innerhalb eines Jahres nicht zwischen Tagen vor und nach dem Schalttag unterscheiden zu m ssen rechnen wir hier intern so als ob das Jahr erst am 1 M rz anfinge So war es tats chlich vor der Julianischen Kalenderreform Weiter sei zum Verst ndnis daran erinnert da seit der Gregorianischen Kalenderreform die durch 100 aber nicht durch 400 teilbaren Jahre keine Schaltjahre sind zum Beispiel war 1900 kein Schaltjahr 2000 ist aber ein Schaltjahr IIIII III IIII II III I II III I III II III III III I II III I II I II I II I II A DATUM CPP Klasse Datum f r Kalenderberechnungen TEE ES E SEEE TE E T E E S E ET ELS T OE TET include lt string h gt include lt stdlib h gt include lt dos h gt verwendet MK_ FP intdos include datum h void DosGetDate int amp Tag int amp Monat int amp Jahr REGS Reg Reg h ah 0x2A MS DOS 0x2A Get Date intdos amp Reg amp Reg Tag Reg h dl Monat Reg h
32. Jahr void Busstag int Jahr void operator long Tage void operator long Tage friend long operator Datum protected int t o mr Jy long Tagnummer void berechneTagnummer void berechneTMJ TEE aa Datum Tag extern Monatsnamen extern char MoName 12 char WoTag 7 3 extern int Monatslaenge extern boolean Schaltjahr int Monat int Jahr 1 1 1 1 1 inline Funktionen inline int Datum Tag return t inline int Datum Monat return m inline int Datum Jahr return j endif DATUM H 2 Di Mo Monat Laufende Nummer aus t m aus Tagnummer Namen der Wochentage 3 Mi 17 So 31 12 1990 Differenz in Tagen Jahr 2 Buchstaben int Jahr 1 IIIIIIIIIIII III I II IV Das folgende kurze Beispielprogramm demonstriert einige typische Methoden der Klasse Datum a LAILL AILALLAALIILILALAAI LAAL LAA ULALA ILALA LALALA AAA DAT TEST CPP Demonstration der Klasse Datum a ASL AAL AAA ILAIA SLAAI LAAAAAIL LAAL AUAL AAAA LAA LAAS AAI IAIA include lt iostream h gt include datum h main Datum Mozart 27 1 1756 jetzt heute int J jetzt Jahr jetzt Fest cout lt lt nBewegliche Feste lt lt J lt lt n n Fest Ostern J cout lt lt Ostersonntag lt lt
33. Konvention ist es in C m glich mehreren Konstanten die gleiche Anweisung zuzuordnen case Monat of switch Monat 1 3 5 7 8 10 12 Tage 31 case 1 2 Tage 28 case 3 4 6 9 11 Tage 30 case 5 else Tage 0 case 7 end case 8 case 10 case 12 Tage 31 break case 2 Tage 28 break case 4 case 6 Ko case case 11 Tage 30 break default Tage 0 Hier bietet Pascal die elegantere Form In diesem Beispiel sehen Sie auch wie Werte behandelt werden k nnen zu denen es keine case Konstante gibt Daf r dient das Schl sselwort default Das entsprechende else im Pascal Beispiel ist eine spezielle Spracherweiterung von Turbo Pascall Die case Anweisung in Pascal und die swit ch Anweisung in C haben folgende Gemeinsamkeiten Die Reihenfolge der Konstanten ist beliebig es darf auch L cken zwischen den Konstanten geben Alle angegebenen Konstanten m ssen verschieden sein Sie sollten sich klarmachen da das Resultat einer case switch Anweisung extrem von der Implementierung des Compilers abh ngt W hrend etwa if oder while Anweisungen in stets gleichbleibender Weise in Maschinensprache umgesetzt werden h ngt die optimale Umsetzung einer switch Anweisung vom individuellen Fall ab Gibt es nicht zu viele L cken zwischen den einzelnen Konstanten bietet sich eine Sprungtabelle an die durch den Wert der Selektor Variablen indiziert wird Wenige Konstanten die aber weit auseinanderliegen sol
34. Maximall nge 20 erzeugen Die Implementierung k nnte so aussehen string string int n if n lt 1 n else if n gt 25 aktLg 0 maxlLg n s new char n t1 n 1 Maximall nge 0 sinnlos 5 n 255 Unsere Implementierung unterscheidet sich von der in Turbo Pascal darin da die L nge in einem int Element gespeichert wird Deshalb sind wir hier nicht an die Beschr nkung der Maximall nge auf 255 gebunden Wenn wir bei der Implementierung die Bibliotheksfunktionen zur String Verarbeitung verwenden wollen m ssen wir dem String noch ein Nullbyte anh ngen k nnen Deshalb werden in der letzten Zeile n 1 Bytes reserviert Destruktoren Mit dem Bereitstellen des Speicherplatzes allein ist es allerdings nicht getan Wir m ssen auch daf r sorgen da beim Verlassen des G ltigkeitsbereichs des Objekts der dynamische Speicher wieder freigegeben wird Hierf r dient ein Destruktor Ein Destruktor wird wie ein Konstruktor geschrieben nur wird das Tilde Zeichen davorgestellt Destruktoren d rfen keine Parameter haben Da unser Konstruktor der string Klasse zus tzlichen Speicherplatz anfordert ben tigen wir einen Destruktor der den Speicher wieder freigibt Es folgt ein komplettes Programm in dem exemplarisch die String Prozedur insert wie in Turbo Pascal implementiert ist SAVAMALA VAVAI LALA UAN LA LANAA LALAU L LALAU IALA IAV UAA VUIAN LLII TPSTRING CPP Turbo Pascal Strings in C RE Bei
35. Somit gibt es keine M glichkeit zu berpr fen ob der rechtm ige Bereich eines Strings verlassen wird Es folgt eine Umsetzung des Pascal Programms nach C include lt iostream h gt include lt string h gt Deklarationen der String Funktionen char s1 10 s2 10 main stropy sl String strcpy s2 Verkettung strcat sl s2 cout lt lt sl Betrachten wir dieses Programm Schritt f r Schritt Die Deklaration char s1 10 reserviert 10 Bytes Jetzt ist s1 ein konstanter Zeiger auf char Das gleiche gilt f r s2 Die Pascal Anweisung s1 String kann man in C nicht etwa durch sl String ersetzen Sie wissen ja bereits da man Vektorinhalte nicht einfach zuweisen kann weil die Variable nur f r eine Adresse steht Beim Zuweisen von Strings verwendet man in C die Bibliotheksfunktion strcpy string copy Diese Funktion kopiert einfach Byte f r Byte vom zweiten String zum ersten bis sie auf ein Null Byte st t Mit strcpy sl String werden also die acht Bytes S t r i n g 0 nach s1 kopiert In der n chsten Zeile soll der String Verkettung nach s2 kopiert werden Hier geschieht ein Malheur denn verkettung hat 10 Buchstaben es werden also mit dem Null Byte 11 Bytes kopiert eines mehr als daf r reserviert wurde Zum Verketten von Zeichenketten dient die Bibliotheksfunktion strcat Damit wird der Inhalt des zweiten Arguments dem ersten Argumen
36. Typ einen Namen geben typedef char charptr Jetzt l t sich die Umwandlung so schreiben charptr p Wenn Sie nicht jedem Typ einen Namen geben wollen k nnen Sie auch eine alternative Form der expliziten Typumwandlung verwenden den cast Operator In Standard C gibt es brigens nur den cast Operator Der Zieltyp wird in runde Klammern gesetzt und vor den Ausdruck geschrieben Im letzten Beispiel k nnte man also schreiben char p Vereindeutigung von Funktionsaufrufen Die M glichkeiten des berladens von Funktionen sowie der Verwendung von Vorgabe Argumenten k nnen in Extremf llen zu schwer durchschaubaren Konflikten f hren Betrachten Sie folgendes Beispiel include lt iostream h gt char f int a return A char g int a int b 0 return B char g long a return C main cout lt lt f 1L lt lt g 1 2 lt lt g 1 lt lt g 1L lt lt g 1L 2 Was geschieht bei den f nf Funktionsaufrufen im Hauptprogramm f 1L Die Funktion f verlangt ein Argument vom Typ int Das bergebene Argument vom Typ long wird automatisch nach int konvertiert Der Funktionswert ist also a g 1 2 Die Funktion g ist berladen Zun chst pr ft der Compiler ob die Parametertypen einer Version exakt passen Dies ist bei der ersten Version der Fall Der Funktionswert ist B g 1 Auch hier wird eine exakte Typ bereinstimmung mit der ersten Version gefunden F r den nicht bergebenen
37. auch ein nicht sequentieller Dateizugriff m glich Mit fseek kann der Dateizeiger positioniert werden mit fte11 kann die Position abgefragt werden int fseek FILE stream Dateizeiger long offset Relativposition int whence Bezug der Relativposition F r den Parameter whence kann eingesetzt werden SEEK_SET relativ zum Dateianfang absolute Position SEEK_CUR relativ zur aktuellen Position SEEK_END relativ zum Dateiende fseek mu immer vor einem Wechsel zwischen Lesen und Schreiben und umgekehrt aufgerufen werden au er wenn beim Lesen das Dateiende erreicht wird long ftell FILE stream gibt die absolute Position zur ck Schlie en einer Datei int fclose FILE stream Fehlerbehandlung int feof FILE f p feof file end of file gibt an ob beim letzten Zugriff das Dateiende erreicht wurde int ferror FILE f fp ferror gibt an ob beim Dateizugriff ein Fehler aufgetreten ist Ein Beispielprogramm zur Dateibehandlung Das folgende Beispielprogramm zeigt einige der besprochenen Dateifunktionen und erlaubt es mit dem nicht sequentiellen Zugriff ein wenig zu experimentieren Versuchen Sie zum Beispiel einmal hinter das Dateiende zu positionieren und dann zu schreiben Die Funktion Auswahl dient zum Abfragen eines Men Buchstabens und ist auch au erhalb dieses Programms einsetzbar Als Parameter wird ein String a
38. beim berladen von Operatoren erweisen So werden wir etwa sehen wie Sie die von Pascal her gewohnte Art von Vektoren Arrays mit beliebigem Anfangsindex in C selbst implementieren k nnen Dazu m ssen Sie die Bedeutung des Operators f r den Vektortyp neu definieren berladen damit Sie in gewohnter Weise Ausdr cke der Form A i f r Ihren eigenen Datentyp verwenden k nnen W rde der Ausdruck A i einen Wert zur ckliefern dann w ren aber Zuweisungen wie A i b ebenso sinnlos wie 3 b denn einem Wert kann man nat rlich nichts zuweisen Dieses Problem l t sich l sen wenn a i statt des Wertes des i ten Elements von A die entsprechende Referenz zur ckliefert Zusammenfassung Der Operator amp dient zur Deklaration von Referenzparametern und Referenzvariablen Au erhalb von Variablen Definitionen dient er als Adre operator Bei der Definition einer Referenzvariablen wird durch die Initialisierung die Referenz hergestellt berladen von Funktionsnamen Nicht selten ben tigt man verschiedene Varianten einer Funktion die sich nur durch die bergebenen Typen unterscheiden So k nnte man etwa folgende Funktionen zur Berechnung des Absolutbetrags einer Zahl erkl ren int abs int n if n lt 0 return n else return n double fabs double x if x lt 0 return x else return x In C d rfen Sie beiden Funktionen den gleichen Namen geben den Funktionsnamen berladen um damit anzudeute
39. denn bei der Konvertierung k nnen zum Beispiel durch Rundungsfehler oder Abschneiden Daten verf lscht werden Deshalb sollten Sie sich ber die Wirkung automatischer Konvertierungen im Klaren sein Stehen links und rechts eines bin ren Operators Operanden verschiedener Typen geht C so vor 1 Operanden vom Typ char und short werden in int umgewandelt 2 Operanden vom Typ float werden in double umgewandelt Jetzt enth lt der Ausdruck nur noch Operanden der Typen long double double unsigned long long unsigned int 3 Der niedrigere der beiden Operanden wird in den h heren Typ umgewandelt Das Ergebnis ist dann vom h heren Typ Bei Zuweisungen wird automatisch der Wert der rechten Seite in den Typ der linken Seite umgewandelt Ebenso wird bei der bergabe von Wertparametern an Prozeduren verfahren In beiden F llen k nnen Werte verf lscht werden wenn der Zieltyp das korrekte Ergebnis nicht aufnehmen kann Viele Compiler weisen durch Warnungen auf solche Gefahren hin Bei der Konvertierung von einem ganzzahligen in einen anderen ganzzahligen Typ wird so verfahren gleichbleibende L nge Der Inhalt wird unver ndert bernommen Er kann allerdings anders interpretiert werden Beispiel unsigned u OxFFFF u 65535 int i u i 1 Zweierkomplement Ziel kleiner als Quelle Die Quelle wird durch Abschneiden der h herwertigen Bits auf die gew nschte L nge gebracht Ziel gr e
40. der undef Direktive wieder aufgehoben werden bungsaufgabe 10 Untersuchen Sie das folgende Programm Erkl ren Sie die Fehler und ersetzen Sie die Makros durch inline Funktionen define Quadrat x x x define Doppelt x x x main int aby amp a Quadrat b c a Doppelt b c Bedingte Compilierung Oft ist es n tig mehrere Versionen eines Programms zu entwickeln die sich nur in wenigen Details unterscheiden Diese Unterschiede k nnen in der Anpassung an eine bestimmte Hardware Konfiguration Grafik Aufl sung Koprozessor etc oder an verschiedene Compiler begr ndet sein Man k nnte hierzu eine Kopie des Quelltextes anfertigen und darin die nderungen anbringen Oft fallen aber sp ter Korrekturen im versionsunabh ngigen Programmteil an Diese m ssen dann immer in allen Versionen angebracht werden Dabei geht leicht die bersicht verloren Man kann sich viel Verwirrung und Speicheraufwand ersparen indem man die verschiedenen Versionen mit den Compiler Direktiven zur bedingten Compilierung verwaltet ifdef Bezeichner Programmst ck1 telse Programmst ck2 endif Das Programmst ck1 wird bersetzt falls der Bezeichner mit define definiert ist Ist er nicht definiert so wird das Programmst ck2 bersetzt Die Definition des Bezeichners sollte ganz am Anfang des Programms stehen So l t sich durch ndern einer Zeile zwischen zwei Programmversionen umschalten Wie blich darf der els
41. der Compiler eindeutig erkennen kann welche Parameter weggelassen wurden gilt die Einschr nkung da solche Vorgabe Argumente am Ende der Parameterliste stehen m ssen Die Vorgabeargumente d rfen nur bei der ersten Deklaration angegeben werden Als Beispiel schreiben wir eine Funktion mit dem doppeldeutigen Namen Ellipse bei der die Winkelargumente weggelassen werden k nnen void Ellipse int x int y int a int b int wO 0 int w1 360 ellipse x y w0 wl a b Dann werden durch die beiden Aufrufe Ellipse 40 40 30 20 lipse 80 40 30 20 0 90 ra eine volle und eine viertel Ellipse gezeichnet bungsaufgabe 3 Schreiben Sie eine Funktion max die das Maximum von zwei drei oder vier int Werten ermittelt Inline Funktionen Wenn Sie in Pascal sehr einfache und kurze Programmst cke als Prozedur oder Funktion implementieren erkaufen Sie sich die bessere Lesbarkeit des Programms durch Verminderung der Programmgeschwindigkeit In einem zeitkritischen Programm k nnten Sie in Versuchung geraten anstelle von einfachen Funktionsaufrufen wie Version A Funktionsaufruf int max int i int j if i gt j return i else return j m max a b direkt den Inhalt der Funktionsdefinition zu schreiben Version B Direkte Implementierung if a gt b m a else m b Um Ihnen einen Anhaltspunkt f r solche Entscheidungen zu geben habe ich die Codest
42. deren Lebensdauer die Programmlaufzeit ist Hierzu wird ebenfalls das Schl sselwort static verwendet Damit ist es m glich Funktionen mit einem Ged chtnis auszustatten Betrachten Sie als Beispiel folgenden Zufallszahlengenerator int random int n erzeugt Zufallszahl im Bereich 0 n 1 static unsigned long r 1 r r 1103515245 12345 return unsigned r gt gt 16 n Gegen ber einer globalen Variablen wie es in Pascal erforderlich w re bietet die lokale static Variable zwei Vorteile Erstens wird so vermieden da inhaltlich zusammengeh rende Informationen im Programm verstreut werden m ssen Zweitens ist die lokale Variable vor versehentlichem Zugriff von au erhalb der Funktion gesch tzt Wenn eine globale und eine lokale Variable den gleichen Namen haben kann in Pascal nur die lokale Variable angesprochen werden In C k nnen mit dem un ren Pr fix Operator globale Variablen auf Programmebene angesprochen werden wenn sie mit einer lokalen Variablen kollidieren Im folgenden Beispiel werden drei Variablen n definiert Auf Programmebene mit Wert 1 im Hauptblock der Funktion main Wert 2 und in einem inneren Block der Funktion main Wert 3 Vom inneren Block aus ist die Variable des umfassenden Blocks nicht ansprechbarl Test des Global Operators include lt stream h gt int n 1 main int n 2 int n 3 cout lt lt lokal lt lt n lt lt global lt lt
43. des Namens n an Zahl type Zahl integer Deklaration Zahl ist neuer Typ var i integer Deklaration neue Variable wird erzeugt In der Pascal Terminologie spricht man gew hnlich nur von Deklarationen Durch eine Deklaration wird im Normalfall eine Variable eingef hrt oder eine Funktion oder Prozedur definiert Im Gegensatz dazu wird durch eine forward Deklaration keine Funktion definiert sondern nur die Schnittstelle einer an anderer Stelle definierten Funktion erkl rt Die Standardwerke ber C sind sich darin einig da eine Deklaration die die angesprochene Variable oder Funktion wirklich bereitstellt Definition genannt wird Der Begriff Deklaration wird nicht einheitlich verwendet Bei Stroustrup Stro86 wird er als Oberbegriff benutzt Es fehlt also ein Begriff f r eine Nur Deklaration Lippman Lipm89 versteht unter einer Deklaration eine Nur Deklaration In diesem Fall fehlt der Oberbegriff Um nicht ein neues Wort sch pfen zu m ssen wollen wir uns im allgemeinen der Sprechweise von Stroustrup anschlie en aber Ausnahmen machen wenn dies aus dem Zusammenhang klar wird In Pascal besteht eine klare Trennung zwischen Deklarationen und Anweisungen Jeder Block besteht aus einem Deklarationsteil und einem Anweisungsteil Im Deklarationsteil gibt es wiederum einen speziellen Abschnitt f r Variablendeklarationen beginnend mit dem Schl sselwort var Turbo Pascal hat zwar die Reihenfolge innerhalb des
44. einfache Implementierung des Operators Zum K rzen wird der bekannte Euklidische Algorithmus verwendet 1 _RATIONAL CPP II II I II III I II IH Arithmetik mit rationalen Zahlen a include rational h include lt stdlib h gt long ggT long a long b Euklidischer Algorithmus while b gt 0 Voraussetzung a b gt 0 long m a 3 b a b b m return a rational rational long Zaehler long Nenner p Zaehler q Nenner if q lt 0 p p q q Nenner immer positiv long t ggT labs p if t gt 1 p t q k rzen falls m glich rational operator rational r N O aa E return r rational operator rational rl rational r2 return rational ELp T2 qk C2 i ksgy 21 4 Ersay rational operator rational rl rational r2 return rl r2 rational operator rational rl rational r2 return rational risp r2 p rl q r2 g rational operator rational rl rational r2 return rational rl p r2 q rl q r2 p rational amp operator rational amp rl rational r2 rl rl r2 return rl rational amp operator rational amp rl rational r2 a Fl E return rl rational amp operator rational amp rl rational r2 rl ri r2 return rl rational amp operator rational amp rl rational r2 1 8 2 22
45. mehrdeutig f 1 1 Fehler mehrdeutig f i long i A f 1 int i B Aufgabe 5 In der einfachen Zuweisung wird der mit allen Zeigertypen vertr gliche NULL Zeiger zugewiesen Die doppelte Zuweisung ist so zu lesen pl p2 NULL Dabei ist der Klammerausdruck vom Typ long und nicht typvertr glich mit int Aufgabe 6 Ab der Adresse s werden alle Bytes mit v beschrieben Systemzusammenbruch Aufgabe 7 Der Compiler reserviert den Speicherplatz f r die drei Strings unmittelbar hintereinander Deshalb k nnen die vorderen Strings in die hinteren berlaufen Das Diagramm zeigt den Speicherbereich Schritt f r Schritt Dabei steht ein Backslash f r das Null Byte E SA WIRKLICH WUNDER IRKLICH WUNDERLICH Die L sung ist also WUNDERLICH Aufgabe 8 Ate Bog Cihy Dis Eee Erb rd Hia Aufgabe 9 int Aln int In 6 4201 3 5 0 A ist 1 Vektor n von 2 Zeigern auf 3 Funktion int mit Wert 4 Zeiger auf 5 Vektor n von 6 int typedef int Typ5 n Typ5 ist Vektor n von int typedef Typ5 Typ4 Typ4 ist Zeiger auf Typ5 typedef Typ4 Typ3 int Typ3 ist Funktion int mit Wert Typ4 typedef Typ3 Typ2 Typ2 ist Zeiger auf Typ3 typedef Typ2 TyplIn Typl ist Vektor n von Typ2 Typl a Aufgabe 10 Quadrat b c wird zu b c b c erweitert was gleichb c b cist Doppelt ist ein Makro ohne Pa
46. n lt lt n 3 1 cout lt lt lokal lt lt n lt lt global lt lt n lt lt n 2 1 Funktionen Sie wissen bereits wie Funktionen definiert werden F r eine Funktionsdeklaration nimmt man die Funktionsdefinition ohne den Funktionsblock setzt ein Semikolon dahinter und das Schl sselwort extern davor extern int Summe int a int b Deklaration der Funktion Summe int Summe int a int b Definition der Funktion Summe return a b Das Schl sselwort extern darf bei der Deklaration auch weggelassen werden Ebenso wie bei Variablen kann die Sichtbarkeit einer Funktion mit dem Schl sselwort static auf die Datei beschr nkt werden in der sie definiert ist Funktionsdeklarationen k nnen zum einen wie die forward Deklarationen in Pascal verwendet werden etwa bei sich wechselseitig aufrufenden rekursiven Funktionen Zum anderen werden sie ben tigt um Funktionen verwenden zu k nnen die in einer anderen Datei definiert sind bersicht Sichtbarkeit und Lebensdauer globale Variablen Funktionen lokale Variablen Definition au erhalb von Funktionen innerhalb von Funktionen Deklaration mit extern au erhalb oder keine weitere Deklaration innerhalb von Funktionen Sichtbarkeit mit static Datei Block sonst alle Dateien Lebensdauer Programmlaufzeit mit static Programmlaufzeit sonst Block Ausf hrung
47. ngig Sie sollten Ihren Objekten m glichst pr gnante Namen geben Es ist manchmal nicht ganz einfach einen treffenden und dennoch nicht allzu langen Namen zu finden Manchmal erfordert es ein paar Minuten Nachdenken einen m glichst kurzen aussagekr ftigen Namen zu finden Solche Sorgfalt zahlt sich beim sp teren Bearbeiten des Programms mit Sicherheit aus In manchen F llen ist es brigens durchaus angebracht einzelne Buchstaben als Variablennamen zu verwenden so etwa f r lokale Laufvariablen oder f r die Argumente abstrakter mathematischer Funktionen Es kann leicht zu Mi verst ndnissen f hren wenn Abk rzungen zusammengesetzter W rter verschmolzen werden Da die Syntax von C wie fast aller Programmiersprachen keine Leerzeichen in einem Namen erlaubt mu man sich hier anders behelfen Bei Pascal und Modula 2 Programmierern ist es blich die einzelnen W rter l ckenlos hintereinanderzuschreiben aber die neuen W rter mit einem Gro buchstaben zu beginnen Beispiel aus Turbo Pascal MemAvail ist wesentlich besser lesbar als memavail Diese Konvention empfiehlt sich auch in C Allerdings m ssen Sie wegen der Unterscheidung von Gro und Kleinbuchstaben auf stets gleiche Schreibweise achten Alternativ dazu k nnen Teilw rter auch durch einen Unterstrich getrennt werden F r nicht englischsprachige Programmierer erhebt sich auch die Frage ob man der Einheitlichkeit wegen selbst englische Namen oder im Interesse der L
48. nnen das leicht feststellen wenn Sie ein Objekt ber den Hilfetext oben auf dem Bildschirm bewegen Beim L schen wird einfach schwarz gezeichnet ohne R cksicht auf den Hintergrund Besser w re es nat rlich vor jeder Bewegung den Bildhintergrund zu speichern und sp ter wieder zu rekonstruieren Sie sollen hier aber nicht durch technische Details vom prinzipiellen Problem abgelenkt werden Im Hauptprogramm werden je ein Kreis und ein Rechteck erzeugt Der Kreis wird als aktuelles Objekt angesehen Das aktuelle Objekt der Kreis wird an seiner Anfangsposition auf dem Bildschirm gezeigt Dann wird die Tastatur abgefragt bis die Esc Taste gedr ckt wird Dabei werden die Tastendr cke so verarbeitet Taste K Der Kreis wird gezeigt Taste R Das Rechteck wird gezeigt Cursortasten Das aktuelle Objekt wird in Pfeilrichtung verschoben Zur grafischen Darstellung werden die in GRAPHICS H deklarierten Routinen BGI Grafik verwendet Die Implementierung enth lt keine besonderen Tricks oder Schwierigkeiten IIIIII II III III III III III III III III III III III III III III I II I II III III IV I FIGURENO CPP Geometrische Objekte ohne Vererbung a ALLAAA ILALA IAI LALLI LILLIA ALAALA ALLANA ILAA include lt graphics h gt include lt ctype h gt include lt conio h gt class Kreis public Kreis int x0 int y0 int r0 void zeige void loesche void bewege int dx int dy private INE X
49. oder for Variable Ausdruck downto Ausdruck do Anweisung Zumindest eine von 1 abweichende Schrittweite w re w nschenswert Was hier allerdings die entsprechende Konstruktion in C bietet ist so m chtig da wir uns zun chst mit der direkten Umsetzung einer or Schleife aus Pascal begn gen wollen for i 1 to 10 do For er Ir 20 ee 1 s S i s s tji for i 10 downto 1 do for i 10 i gt 1 i i 1 s S i s s tji Nach diesem Schema k nnen alle or Anweisungen aus Pascal bertragen werden Doch die merkw rdig anmutende Ausdrucksweise in C l t erahnen da die M glichkeiten damit bei weitem nicht ausgesch pft sind Die or Anweisung hat in C die allgemeine Form for Anweisung Ausdruck Ausdruck Anweisung Da in C jede Anweisung mit einem Semikolon endet stehen zwischen den runden Klammern also zwei Semikolal Eine Anweisung der Form for Anfangsanweisung Fortsetzungsbedingung Inkrementierung Schleifenanweisung hat die gleiche Bedeutung wie das Programmst ck Anfangsanweisung while Fortsetzungsbedingung Schleifenanweisung Inkrementierung Damit l t sich unter anderem jede while Schleife darstellen indem man die Anfangsanweisung und die Inkrementierung wegl t while Bedingung Anweisung k nnte aber sollte keinesfalls ersetzt werden durch for Bedingung Anweisung Eine fehlende Fortsetzungsbedingung wird als wahr interpretiert
50. ohne Parameter die runden Klammern stehen Das folgende Beispiel zeigt wie Zeiger auf Funktionen definiert werden und wie man ihnen Funktionen als Wert zuweist tnt fj Int f ist Zeiger auf Funktion mit einem Argument vom Typ int und Ergebnistyp int int fl int i return i int f2 int n return 2 n int f3 float x return 3 x main f fl steht f r f amp fl n f 1 steht f r n f 1 jetzt ist n 1 f f2 n f 1 jetzt istn 2 h 735 Fehler unvertr gliche Zeigertypen Das folgende Beispiel eines einfachen Sortieralgorithmus Bubblesorf zeigt eine sinnvolle Anwendung von Funktionszeigern Die Funktion bsort kann Vektoren eines beliebigen Datentyps sortieren Dazu wird die Adresse des Vektors die Anzahl der Elemente und die Gr e des Datentyps in Bytes bergeben Zum Sortieren mu au erdem noch gesagt werden wie zwei Elemente verglichen werden denn das h ngt von der Interpretation der Daten ab So kann zum Beispiel ein Speicherwort 2 Bytes in dem alle Bits gesetzt sind die unsigned Zahl 65535 oder die int Zahl 1 bedeuten BSORT CPP include lt iostream h gt void vertausche void pl void p2 size_t Groesse char h char cpl pl cp2 p2 for int i 0 i lt Groesse i h cpl il cpl i l cp2 i cp2 i l h void bsort void Basis Adresse des Sortierbereichs size t Anzahl Anzahl der Elemente size_t Groesse
51. return s ostream amp operator lt lt ostream amp s bitset b Br ie for int i 0 i lt INT_BITS it s lt lt 1 lt b Mean lt lt wm return S void BitsetDemo bitset a b c for int i 2 i lt 1l0 I a i for i 6 i lt 1l4 I b i cout lt lt a lt lt a lt lt n EOUE xx T Jo lt lt b lt lt n ce a tb cout lt at tb lt lt c lt lt n ce a b cout lt lt a bs lt lt c lt lt n c a b cout lt lt a b s lt lt c lt lt n ce ra cout lt lt va lt lt ce lt lt n void TastenDemo enum shiftstate RShift LShift Ctrl Alt ScrollLock NumLock CapsLock bitset far FlagPtr bitset far MK_FP 0x0040 0x17 volatile bitset far amp Flags FlagPtr bitset alteFlags neueFlags AbbruchFlags gesuchteFlags cout lt lt n Anzeige der Tasten Shift Ctrl Alt Ende beide Shift Tasten n gesuchteFlags RShift gesuchteFlags LShift gesuchteFlags Ctrl gesuchteFlags Alt AbbruchFlags RShift AbbruchFlags LShift do neueFlags Flags neueFlags neueFlags gesuchteFlags if neueFlags alteFlags alteFlags neueFlags cout lt lt ngedr ckte Umschalttasten if neueFlags leer cout lt lt gt if RShift lt neueFlags cout lt lt RShift if LShift lt neu
52. typischen Anwendungsf lle lassen sich mit Hilfe der Bitfelder meist wesentlich klarer und problemn her beschreiben Operatoren zur Bitmanipulation Pascal C un r bitweise Negation not bin r bitweises Und and amp bitweises Oder or bitweises exkl Oder xor 2 Linksverschiebung shl lt lt Rechtsverschiebung shr gt gt Die bitweisen Verschiebungen werden oft zur schnelleren Multiplikation oder Division mit Zweierpotenzen verwendet Dies ist bei modernen optimierenden Compilern meist berfl ssig und sollte daher m glichst vermieden werden Das Rechtsschieben von vorzeichenbehafteten Zahlen ist brigens nicht portabel Manche Compiler schieben Nullen nach andere schieben das Vorzeichenbit nach arithmetische Verschiebung damit auch negative Zahlen durch Zweierpotenzen dividiert werden k nnen In Pascal werden f r die logischen Operatoren und f r die Bitoperatoren die gleichen Operanden verwendet Dieses sogenannte berladen von Operatoren ist in Pascal m glich da sich dort Zahlen von Wahrheitswerten im Typ unterscheiden Sie k nnen Ihr Verst ndnis der Operatoren an den folgenden Beispielen berpr fen Pascal C Ausdruck Wert Ausdruck Wert 3 gt 2 and 3 lt 4 true 3 gt 2 amp amp 3 lt 4 3 gt 2 amp 3 lt 4 5 and 6 4 5 amp 6 4 5 amp amp 6 3 gt 2 and 4 Syntaxfehler 3 gt 2 amp
53. 2 friend rational operator rational rl rational r2 friend rational amp operator rational amp r rational r2 friend rational amp operator rational amp r rational friend rational amp operator rational amp r rational friend rational amp operator rational amp r rational friend int operator rational amp rl rational amp r2 friend int operator rational amp rl rational amp r2 friend ostream amp operator lt lt ostream amp s rational r long p q Fs endif RATIONAL H Nun folgt die Implementierung der Klasse rational Hier wird ein m glicher berlauf bei der Arithmetik mit long Zahlen ignoriert In Borland C gibt es keine M glichkeit Bereichs berschreitungen bei Ganzzahltypen abzufangen Man k nnte beispielsweise die long Multiplikation durch folgende Funktion ersetzen long Produkt long a long b if LONG MAX a lt b cerr lt lt n berlauf bei Rational Arithmetik n exit 1 else return a b Das ginge allerdings sehr auf Kosten der Effizienz F r den praktischen Einsatz k nnte man auch eine Assembler Routine f r die Multiplikation schreiben die das berlauf Flag des Prozessors abfragt Der Konstruktor bringt die rationale Zahl auf eine eindeutige Normalform Z hler und Nenner sind gek rzt und der Nenner ist positiv Auch alle Operatoren bringen ihre Ergebnisse immer in diese Normalform Das ist die Voraussetzung f r die
54. 7 int y int Radius E class Rechteck public Rechteck int x0 int y0 int x1 int yl void zeige void loesche void bewege int dx int dy private int x int y int a b die beiden Seiten Ez Implementierung der Klasse Kreis Kreis Kreis int x0 int y0 int r0 x x0 y y0 Radius r0 void Kreis zeige circle x y Radius void Kreis loesche setcolor BLACK circle x y Radius setcolor WHITE void Kreis bewege int dx int dy loesche x dx y dy zeige Implementierung der Klasse Rechteck Rechteck Rechteck int x0 int y0 int xl int yl x x0 y y0 a x1 x0 b yl y0 void Rechteck zeige rectangle x y xta y tb void Rechteck loesche setcolor BLACK rectangle x y Xta ytb uhr setcolor WHITE void Rechteck bewege int dx int dy loesche x dx y dy zeige I I Test der Klassen I I IIIII I II VI int main char c int graphdriver DETECT graphmode int dx dy initgraph amp graphdriver amp graphmode borlandc bgi outtextxy 10 8 Figur mit Cursortasten bewegen outtextxy 10 24 Figur wechseln R Jechteck K reis outtex
55. 75 77 r1 r2 33 28 r1 15 14 r2 5 6 rl r2 5 21 r1 r2 25 28 r1 r2 9 7 r1 15 14 r2 10 13 r1 r2 55 182 r1 r2 75 91 r1 r2 39 28 r1 15 14 r2 5 7 r1l r2 5 14 r1 r2 75 98 r1 r2 3 2 Datumsberechnungen Als weiteres Beispiel f r das berladen von Operatoren betrachten wir eine Klasse Datum f r Berechnungen mit Kalenderdaten Zur Berechnung der Zeitspanne in Tagen zwischen zwei Kalenderdaten bietet sich der Minus Operator an zur Erh hung eines Kalenderdatums um eine Anzahl von Tagen der Operator Intern wird zu jedem Datum eine fortlaufende Tageszahl berechnet Dabei ist es gleichg ltig auf welches Anfangsdatum sich diese Zahl bezieht weil sie nur f r die Berechnung von Datumsdifferenzen verwendet wird Weiter sollen Wochentage und bewegliche Feste berechnet werden und Kalenderdaten im Klartext angegeben werden k nnen So kommen wir zur folgenden Header Datei IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII II III II III III III I II I II III I II IV DATUM H Klasse Datum f r Kalenderberechnungen a ifndef DATUM H define DATUM H ifndef define BOO enum false true typedef int boolean ndif BOOLEAN BOOLEAN EAN class Datum public Datum int Tag 1 void heute int Monat 1 int Jahr 2000 bernimmt das Datum von MS DOS 1 Mo z B int Wochentag char String int Tag int Monat int Jahr void Ostern int
56. A 4 B 4 A B Da A und B Zeiger sind h tte die Zuweisung die Wirkung da A auf die gleiche Adresse wie B zeigt Der f r A urspr nglich reservierte Speicherplatz w re nun unerreichbar Tats chlich verbietet der Compiler hier die Zuweisung weil A als konstantem Zeiger kein Wert zugewiesen werden kann Das vielleicht beabsichtigte Kopieren k nnte man stattdessen etwa so formulieren for i 0 i lt 4 i A i B i Wie Sie gesehen haben gibt es zu jedem Datentyp in C einen entsprechenden Zeigertyp Daneben gibt es den universellen Zeigertyp void Einer Variablen dieses Typs d rfen Sie jeden beliebigen Zeiger zuweisen In der umgekehrten Richtung m ssen Sie die Typumwandlung explizit angeben void univZeiger int intZeiger univZeiger intZeiger intZeiger int univZeiger korrekte Typumwandlung intZeiger univZeiger Syntaxfehler Universelle Zeiger k nnen nicht dereferenziert werden weil ihnen ja kein Datentyp zugeordnet ist Ein Beispiel f r die Anwendung von universellen Zeigertypen ist die Bibliotheksfunktion memcpy void memcpy void dest const void src size_t n memcpy kopiert n Bytes ab der Adresse src an die Adresse dest Dabei d rfen sich Ziel und Quelle nicht berlappen Der Datentyp size_t ist ein maschinenabh ngig definierter Ganzzahltyp Als Funktionswert wird der Zeiger dest zur ckgegeben Wir k nnten die Funktion etwa so nachimplementieren void memcpy void dest
57. Deklarationsteils liberalisiert die Trennung zwischen Deklarations und Anweisungsteil bleibt aber bestehen In C gibt es diese Trennung nicht Hier d rfen Deklarationen fast berall stehen Wir wollen auf die M glichkeiten im einzelnen eingehen Variablen Eine Variablendefinition besteht aus der Typbezeichnung gefolgt vom Namen Die Variable kann bei der Definition schon mit einem Anfangswert initialisiert werden int n Einfache Definition inta Initialisierung int i j 3 k mehrere Variable gleichen Typs k nnen gemeinsam definiert werden Globale Variablen sind alle Variablen die au erhalb einer Funktionsdefinition definiert oder deklariert werden Eine globale Variable lebt w hrend der ganzen Laufzeit des Programms Sie mu in genau einer Datei einmal definiert werden Wenn sie in anderen Dateien angesprochen werden soll mu sie dort deklariert werden Eine Deklaration wird durch das vorangestellte Schl sselwort extern gekennzeichnet Im folgenden Beispiel wird in der Datei 1 eine Variable n vom Typ int definiert Diese Variable kann zun chst nur in der Datei angesprochen werden in der sie definiert wurde Soll sie in einer anderen Datei angesprochen werden mu sie dort zun chst deklariert werden Datei 1 int n hier wird die Variable n definiert Datei 2 extern int n Deklaration der anderswo definierten Variablen n Bei einer Deklaration stellt der Compiler keinen Speicherpla
58. II I II I II I II II FIGUREN CPP Einfache Demonstration virtueller Funktionen am Beispiel der Bewegung von geometrischen Objekten a 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 111 include lt graphics h gt include lt ctype h gt include lt conio h gt class Punkt public Punkt int x0 int y0 protected int x int y class Figur public Punkt abstrakte Basisklasse public f r Grafik Objekte Figur int x0 int y0 virtual void zeige 0 rein virtuelle Funktion virtual void loesche 0 If dto void bewege int dx int dy Es class Kreis public Figur public Kreis int x0 int y0 int r0 virtual void zeige virtual void loesche protected int Radius F class Rechteck public Figur public Rechteck int x0 int y0 int x1 int yl virtual void zeige virtual void loesche protected int a b die beiden Seiten 7 Implementierung der Klasse Punkt Punkt Punkt int x0 int y0 x x0 y y0 1 1 Implementierung der Klasse Figur Figur Figur int x0 int y0 Punkt x0 y0 void Figur bewege int dx int dy loesche x dx y dy zeige Implementierung der Klasse Kreis
59. Kopf ihres Sch pfers entstehen sich sp ter aber jedem Versuch einer Korrektur oder Anpassung mit unerkl rlichem Fehlverhalten entziehen Die Prozedurabstraktion kommt einem in diesem Sinne guten Programmierstil entgegen Die Implementierung einer Prozedur kann jederzeit ge ndert oder verbessert werden ohne da der Rest des Programms davon beeintr chtigt wird solange die Anzahl und die Typen der Parameter gleich bleiben Gerade hier st t man aber an die Grenzen der Prozedurabstraktion Oft stellt sich sp ter heraus da bestimmte Datentypen besser anders definiert werden sollten Dann m ssen aber alle Prozeduren und Programmteile ge ndert werden die auf diese Datentypen zugreifen Wir wollen das einfache Beispiel eines Puffers betrachten wie er zum Beispiel als Tastaturpuffer oder als Druckerpuffer verwendet wird Ein Puffer auch Warteschlange Queue dient dazu Datenelemente in unserem Beipiel wollen wir einzelne Bytes puffern bis zu einer maximalen Anzahl zwischenzuspeichern und bei Bedarf in richtiger Reihenfolge wieder auszugeben Mit einem Puffer m ssen also folgende Operationen durchgef hrt werden k nnen den Puffer in den Anfangszustand leer bringen angeben ob der Puffer voll ist angeben ob der Puffer leer ist ein Byte puffern ein Byte ausgeben Prozeduren die diese Operationen ausf hren m ssen auf die Datenstruktur des Puffers zugreifen Nun ist es aber keineswegs klar wie man einen Datentyp Puff
60. LE dokumentiert werden Es folgt ein Beispiel f r den Zortech Compiler f r ein Programm das von zwei Quelldateien und einer Header Datei abh ngt grafdemo exe qgrafdemo obj grafik ob ztc ml ografdemo grafdemo obj qrafik obj grafdemo obj qgrafik h grafdemo cpp ztc ml c ografdemo obj grafdemo cpp grafik obj grafik h grafik cpp ztc ml c ografik obj grafik cpp Diese Datei besteht aus drei Regeln Jede Regel besteht aus zwei Zeilen In der ersten Zeile steht der Name des gew nschten Produkts dann ein Doppelpunkt und danach die ben tigten Zutaten In der zweiten Zeile die einger ckt sein mu folgt das Rezept zur Herstellung des Produkts Das Dienstprogramm MAKE pr ft ob eine oder mehrere der Zutaten neueren Datums als das Produkt sind Nur in diesem Fall wird das Rezept neu ausgef hrt Wurde in unserem Beispiel die Datei grafdemo cpp ge ndert so betrifft dies zun chst die zweite Regel grafdemo cpp wird neu bersetzt Danach ist grafdemo ob5 neuer als grafdemo exe Es wird also auch die erste Regel ausgef hrt Danach ist das Projekt auf dem neuesten Stand ohne da grafik cpp neu bersetzt wurde Dieses einfache Beispiel konnte nat rlich nur ein Schlaglicht auf MAKE werfen Tats chlich gibt es noch weitere M glichkeiten wie implizite Regeln und Makros Wenn Sie in Borland C programmieren steht Ihnen das MAKE Programm zwar zur Verf gung Sie ben tigen es aber nur wenn Sie die K
61. November this Datum 22 11 Jahr this Wochentag 4 3 7 void Datum operator Tagnummer Tage berechneTMJ void Datum operator long Tage long Tage Tagnummer Tage berechneTMJ long operator Datum D1 Datum D2 return D1 Tagnummer static long Maerztag berechnet fortlauf D2 Tagnummer int J nd Basis 0 return 365L j 3 7 4 5 100 j 400 void Datum berechneTagnummer Tagesnummer des 0 M rz im Jahr j M rz 0 steht f r 28 Februar 1 v Chr L nge der Gemeinjahre Alle 4 Jahre ist Schaltjahr au er in den durch 100 aber nicht durch 400 teilbaren Jahren OQ int M m J j if M gt 2 M 3 M rz 0 April 1 else M_ 9 J Jan u Feb zum alten Jahr Tagnummer Maerztag J Tagnummer des 1 M rz MoAnf M L nge der verstrichenen Monate ab M rz amp Ss Ty Tage im laufenden Monat void Datum berechneTMJ int Rest j 1 Tagnummer 365 j ist mindestens um 1 zu gro do jr r misches Jahr suchen Rest Tagnummer Maerztaqg jJ while Rest lt 0 Rest verstrichene Tage ab 1 M rz m 11 Anfang mit letzem Monat Februar while MoAnf m gt Rest m richtigen Monat suchen t Rest 1 MoAnf f m if m gt 9 m 9 j in richtige Monate umrechnen else m 3
62. OTST CPP RATIONAL H RATIONAL CPP include rational h void main void cout lt lt n n for int i 10 i lt 15 i for int j 11 j lt 15 j rat 1onal rl ALES iy rational r2 10 jJ rational d rl r2 rational p r1 r2 rational q rl r2 EOUE LS PREISEN STELLE Ty EBEN AK E2 RS N Elere d lt lt ri r2 lt lt p lt lt ril r2 lt lt q lt lt n Dieses Programm erzeugt folgende Ausgabe r1 3 2 r2 10 11 r1l r2 13 22 rl r2 15 11 r1 r2 33 20 r1 3 2 r2 5 6 r1l r2 2 3 r1 r2 5 4 r1 r2 9 5 r1 3 2 r2 10 13 r1l r2 19 26 r1 r2 15 13 r1 r2 39 20 r1 3 2 r2 5 7 r1l r2 11 14 r1 r2 15 14 r1l r2 21 10 r1 15 11 r2 10 11 rl r2 5 11 rl r2 150 121 r1 r2 3 2 r1 15 11 r2 5 6 r1l r2 35 66 r1 r2 25 22 r1 r2 18 11 r1 15 11 r2 10 13 r1 r2 85 143 r1 r2 150 143 r1 r2 39 22 r1 15 11 r2 5 7 r1 r2 50 77 r1 r2 75 77 r1l r2 21 11 r1 5 4 r2 10 11 r1l r2 15 44 r1 r2 25 22 r1 r2 11 8 r1 5 4 r2 5 6 rl r2 5 12 r1 r2 25 24 r1 r2 3 2 r1 5 4 r2 10 13 r1l r2 25 52 r1 r2 25 26 r1 r2 13 8 r1 5 4 r2 5 7 r1 r2 15 28 r1 r2 25 28 rl r2 7 4 r1 15 13 r2 10 11 r1 r2 35 143 r1 r2 150 143 r1 r2 33 26 r1 15 13 r2 5 6 r1l r2 25 78 r1l r2 25 26 r1 r2 18 13 r1 15 13 r2 10 13 r1 r2 5 13 r1l r2 150 169 r1 r2 3 2 r1 15 13 r2 5 7 r1l r2 40 91 r1 r2 75 91 r1 r2 21 13 r1 15 14 r2 10 11 r1 r2 25 154 r1 r2
63. Sprachelemente C hat zwar auf den ersten Blick einen recht kleinen Sprachumfang Viele Schl sselw rter und Operatoren haben allerdings in verschiedenen Kontexten unterschiedliche Bedeutungen Hier finden Sie eine bersicht mehrdeutiger Sprachelemente die Ursache von Programmierfehlern sein k nnen const 1 const Variablen K nnen nicht ver ndert werden 2 const Zeiger Nicht der Zeiger ist konstant sonden das Objekt das er adressiert 3 const Elementfunktion friend 1 befreundete Klasse darf auf private Elemente zugreifen 2 befreundete Member Funktion operator 1 berladen von Operatoren member friend 2 implizite Typkonvertierung static 1 Funktionen und globale Variablen Sichtbarkeit auf die Datei beschr nkt 2 lokale Variablen Lebensdauer auf Programmlaufzeit ausgedehnt 3 Klassenelemente Nur einmal f r eine Klasse vorhanden virtual 1 virtuelle Funktion 2 virtuelle Basisklasse bei Mehrfachvererbung void 1 leerer Ergebnistyp von Funktionen void gotoxy int x int y 2 Bezeichnung einer leeren Parameterliste z B int rand void Diese Verwendung ist in C berfl ssig Sie ist in ANSI C n tig um klarzumachen da keine Parameter vergessen worden sind 3 void bezeichnet universellen Zeiger 4 In Zortech C leere Anweisung Hiermit wird angedeutet da wirklich eine leere Anweisung gew nscht wird Beispielwhile keypressed void Der Zortech
64. Technik 1996 Meye88 B Meyer Object oriented Software Construction Prentice Hall New York 1988 Deutsche bersetzung Objektorientierte Software Entwicklung Hanser M nchen 1990 Scha95 M Schader S Kuhlins Programmieren in C Einf hrung in den Sprachstandard C Springer Berlin 3 Aufl 1995 Seth89 R Sethi Programming Languages Concepts and Constructs Addison Wesley Reading 1989 Stro91 B Stroustrup The C Programming Language Bell Telephone Laboratories Incorporated 2 Aufl 1991 Reprinted with corrections December 1994 Deutsche bersetzung Die C Programmiersprache Addison Wesley Bonn 2 Aufl 4 berarbeiteter Nachdruck 1994 Watt90 D A Watt Programming Language Concepts and Paradigms Prentice Hall New York 1990 Wien88 R Wiener L Pinson An Introduction to Object Oriented Programming and C Addison Wesley Reading 1988 Zur ck
65. Warnung Sie k nnen diese Warnung vermeiden indem Sie das Schl sselwort void f r die leere Anweisung einsetzen while keineTasteGedrueckt void In Borland C verboten Die Verbundanweisung Wie in Pascal verlangt die Syntax an manchen Stellen genau eine Anweisung Deshalb mu es m glich sein aus mehreren Anweisungen formal eine Anweisung zu machen Hierzu werden in C anstelle der Pascal Schl sselw rter begin und end die geschweiften Klammern verwendet In C wird durch eine Verbundanweisung ein lokaler Block eingef hrt Variablen die hier deklariert werden sind au erhalb der Verbundanweisung nicht sichtbar und ihr Speicherplatz wird nach Beendigung der Verbundanweisung wieder freigegeben Die if Anweisung if Ausdruck Anweisung if Ausdruck then Anweisung el Anweisung SiLSE else Anweisung Die i Anweisung ist in C strukturgleich mit Pascal Sie k nnten die gewohnte Pascal Schreibweise beibehalten und die bersetzung dem Pr prozessor berlassen Dazu m ten Sie folgende Definitionen in Ihr Programm einf gen define IF FE il define THEN define ELSE else Genaueres ber den Pr prozessor erfahren Sie im Abschnitt 2 1 Ich empfehle Ihnen nicht diese Pr prozessor Definitionen wirklich zu verwenden Sie sollen Ihnen lediglich die Umsetzung von Pascal nach C klarmachen Wie Sie sehen wird in C die Bedingung in runde Klammern gesetzt daf r entf llt das Schl sselw
66. Zahl operator Zahl z1 Zahl z2 Verwendet wird dieser berladene Operator dann wie blich Es gibt zwei verschiedene M glichkeiten berladene Operatoren zu definieren Definition au erhalb der Klasse Falls der Operator auf ein privates Element der Klasse zugreift das ist der Normalfall mu die Klasse ihn als friena deklarieren Definition innerhalb der Klasse berladene Operatoren k nnen auch als Elementfunktion definiert werden falls das erste Argumet eine Referenz auf ein Objekt der Klasse ist In diesem Fall wird das erste Argument nicht explizit angegeben Im folgenden sinnlosen Beispiel sehen Sie beide Arten der Definition von berladenen Operatoren class Zahl public void operator Zahl b private friend void operator Zahl amp a Zahl b friend Zahl operator Zahl a Zahl b rat ng fa Der Operator ist innerhalb der Klasse definiert au erhalb der Klasse Hier sollen die verschiedenen M glichkeiten demonstriert werden In der Praxis sollte man nat rlich einen einheitlichen Stil w hlen F r den Operator haben wir keine andere Wahl als ihn au erhalb der Klasse zu definieren weil sein erstes Argument keine Referenz auf die Klasse ist Es folgt die Implementierung der Klasse void Zahl operator Zahl b n b n void operator Zahl amp a Zahl b a n b n Zahl operator Zahl a Zahl b Zahl s s n a n b n return s Anwendung a
67. Zur ck Vorwort C ist keine Sprache f r Programmieranf nger H chstwahrscheinlich besitzen Sie schon Grundkenntnisse in einer h heren Programmiersprache Dann m chten Sie nicht mit ausf hrlichen Erkl rungen der elementaren Konzepte h herer Programmiersprachen gelangweilt werden sondern erfahren worin sich C von der Ihnen bekannten Sprache unterscheidet Dieses Buch wendet sich vor allem an Leser die bereits in Pascal programmiert haben Die Sprachkonstruktionen die sich in C kaum von Pascal unterscheiden werden nur ganz knapp gegen bergestellt So bleibt gen gend Raum die wirklich entscheidenden Neuerungen in C darzustellen und vor besonderen Fallstricken f r Pascal Programmierer zu warnen Nat rlich gen gt es nicht Pascal Formulierungen in C umsetzen zu k nnen Sie werden vor allem auch in die Denkweise der objektorientierten Programmierung eingef hrt Das Buch besteht aus drei gro en Teilbereichen Die Kapitel 1 und 2 dienen dem Umstieg von der Pascal Programmierung zur konventionellen Programmierung in C Hier gen gen knappe Programmbeispiele die die vorgestellten Sprachmittel auf m glichst engem Raum kl ren Das dritte Kapitel f hrt Sie in die objektorientierte Programmierung in C ein Danach sollten Sie diese neue Denkweise und die wichtigsten Sprachmittel von C im Prinzip beherrschen Einige weniger wichtige Konzepte wurden bewu t vernachl ssigt Hier wurde einer soliden Beherrschung der
68. able p hei t und der Typ Zeiger auf int ist Wenn Sie aber mehrere Zeigervariablen hintereinander erkl ren m ssen Sie aufpassen int p1 p2 deklariert nicht etwa zwei Zeigervariablen wie die Schreibweise suggeriert sondern eine Zeigervariable p und eine int Variable p2 Hier m ten Sie int pl p2 schreiben new Typ reserviert Speicherplatz f r ein Objekt des Datentyps Typ und liefert einen Zeiger auf dieses Objekt Dies kann dann einem entsprechenden Zeiger zugewiesen werden Beispiel Int ptr ptr new int Wahlweise kann man mit Hilfe des new Operators auch ein Vielfaches des Speicherplatzes f r den Zeigertyp anfordern In der Anweisung ptr new int 4 reserviert new zusammenh ngenden Speicher f r vier int Zahlen und liefert einen Zeiger auf den Anfang dieses Speicherplatzes zur ck Nach der Zuweisung zeigt ptr also auf die erste der vier int Zahlen Wie k nnen aber die brigen Zahlen angesprochen werden Erinnern Sie sich In Pascal sind alle aritnmetischen Operationen mit Zeigern verboten Welchen Sinn h tte auch etwa das Produkt zweier Zeiger Um die soeben definierten vier int Objekte ansprechen zu k nnen w re es hilfreich wenn man Zeigeradressen erh hen k nnte etwa so ptrl ptr sizeof int hypothetische Zeigerarithmetik ptr2 ptr 2 sizeof int ptr3 ptr 3 sizeof int C erlaubt tats chlich die Addition oder Subtraktion von int Zahlen zu Zeigertypen Um da
69. allem wohl folgende H rden zu berwinden Zun chst gibt es einige sehr harmlose Unterschiede n mlich Sprachmittel die in C im Prinzip wie in Pascal aber mit anderen Symbolen ausgedr ckt werden Zum Beispiel wird der logische Operator or aus Pascal in C durch dargestellt Hier k nnte man also bei der gewohnten Schreibweise bleiben und vor dem bersetzen eines Programmes mit einem Texteditor berall or durch ersetzen Diese Umsetzung kann der Compiler sogar selbst mit Hilfe des sogenannten Pr prozessors bernehmen Wenn Ihnen das hilft k nnen Sie f r eine bergangszeit bei einigen besonders ungew hnlichen Operatoren die vertraute Pascal Schreibweise beibehalten Die Art der Bezeichnung von Zeigertypen insbesondere in h heren Stufen ist nicht ganz einfach zu durchschauen Hier lassen sich Anfangsh rden vermeiden indem jeder verwendete Zeigertyp zun chst in einer Typdeklaration mit einem Namen versehen wird C l t Ihnen als Programmierer viel mehr Freiheiten als etwa Pascal oder gar Modula 2 Insbesondere erlaubt C verlangt es aber nicht einen extrem kompakten Programmierstil der f r Unge bte nur sehr schwer zu durchschauen ist Die verschiedenen M glichkeiten zur Darstellung der gleichen Situation f hren dazu da jeder Programmierer seinen individuellen Stil entwickelt der oft von anderen schwer nachvollzogen werden kann In dieser Einf hrung verzichte ich bewu t auf einige M glichkeiten der Sprach
70. allerdings explizit verlangen setcolor word BLUE Der soeben definierte Aufz hlungstyp sieht in C ganz hnlich aus enum Farbe BLACK BLUE GREEN CYAN RED MAGENTA BROWN LIGHTGRAY DARKGRAY LIGHTBLUE LIGHTGREEN LIGHTCYAN LIGHTRED LIGHTMAGENTA YELLOW WHITE Der wesentliche Unterschied besteht in der etwas geringeren Typstrenge von C Ein mit enum definierter Typ wird zwar vom Typ int unterschieden aber es gibt implizite Konvertierungen in beiden Richtungen zwischen jedem enum Typ und int Da ein enum Typ nur int Werte enthalten kann ist eine Konvertierung von enum nach int unproblematisch In der umgekehrten Richtung ergibt nicht jede int Zahl in einen enum Typ umgewandelt einen Sinn Deshalb verlangt das Handbuch von Borland C da einer enum Variablen nur Werte der gleichen Aufz hlung zugewiesen werden d rfen Tats chlich begn gt sich der Compiler mit einer Warnung Der Zortech Compiler gibt hier eine Fehlermeldung aus Im Normalfall werden den Elementen eines Aufz hlungstyps aufeinanderfolgende Werte ab Null zugewiesen Manchmal ist es aus technischen Gr nden n tig den Elementen bestimmte nicht unbedingt aufeinanderfolgende Werte zu geben Deshalb ist es erlaubt an einzelne Elemente explizite Werte zu vergeben enum kleinePrimzahl ZWEI 2 DREI FUENF 5 Elemente denen kein Wert zugewiesen wurde bekomme
71. amp 4 3 gt 2 amp 4 0 In Pascal werden einige der Operatoren auch noch f r Mengenoperationen und String Verkettung benutzt Das berladen von Operatoren steht in C generell dem Programmierer als Sprachmittel zur Verf gung Wir werden sp ter sehen da sich so das Mengenkonzept von Pascal identisch in C realisieren l t obwohl es nicht zur Sprache geh rt Vergleichsoperatoren Hier gen gt eine tabellarische Gegen berstellung Vergleichsoperatoren Pascal C Gleichheit Ungleichheit lt gt l kleiner lt lt kleiner oder gleich lt lt gr er gt gt gr er oder gleich gt gt Nur die Gleichheits und die Ungleichheitsrelation werden anders als in Pascal geschrieben Schreiben Sie in C versehentlich lt gt anstelle von weist Sie der Compiler darauf hin Wenn Sie dagegen die Gleichheitsrelation in der von Pascal gewohnten Weise schreiben kann das unangenehme Folgen haben wie Sie sogleich sehen werden Zuweisungoperatoren Die Zuweisung wird in C mit dem einfachen Gleichheitszeichen ohne vorgestellten Doppelpunkt dargestellt Wie Sie bereits zu Beginn dieses Abschnitts erfahren haben sind in C auch Zuweisungen Ausdr cke mit einem Wert n mlich dem des zugewiesenen Ausdrucks Damit sind auch Zuweisungsketten m glich a b 1 ist gleichbedeutend mita b 1 Der Wer
72. anten Beispielprogramme solange zur ckstellen bis wir sie mit objektorientierten Methoden angehen k nnen 1 1 Programmstruktur Nach diesen Vorbemerkungen wollen wir an einem ersten Beispiel einige wichtige Unterschiede zwischen Pascal und C betrachten Das folgende Programm liest einen String ein wandelt alle Kleinbuchstaben in Gro buchstaben um und pr ft ob die vorkommenden runden Klammern paarweise passend angeordnet sind So erzeugt etwa die Eingabe a b c die Ausgabe richtig A B C Das ganze soll kein sinnvolles Programm sein sondern nur auf engem Raum m glichst viele typische elementare Sprachelemente vorf hren Bevor Sie beim Vergleich der beiden Programmversionen C in Grund und Boden verdammen bedenken Sie bitte da es sich hier um einen ungleichen Wettbewerb handelt Sie sehen auf der rechten Seite gewisserma en ein C mit angezogener Handbremse Hier kommt keine der St rken von C zum Tragen So ist es kein Wunder wenn Pascal hier wegen seiner lesbareren Syntax noch das Rennen macht 1 program Klammern Klammern include lt string h gt include lt ctype h gt include lt iostream h gt 5 const n 80 const int n 80 type Zeile string n typedef char Zeile n 1l 10 var s Zeile Zeile s 15 20 25 30 38 40 45 50 55 function korrekt s Zeile boolean pr ft Zeichenkette auf korrekte Klammerstruktur var i offe
73. asisklasse verwaltet werden Eine Bildschirmauffrischung besteht dann einfach darin da f r alle Elemente der Liste die virtuelle Methode zum Zeichnen aufgerufen wird Sie k nnen zum Beispiel das Figuren Programm mit wenig Aufwand so erweitern da es eine Liste Im einfachsten Fall als Vektor von Zeigern auf Figur verwalten kann 3 10 Mehrfache Vererbung Die Art der Vererbung die Sie bisher kennengelernt haben w rde man in der Biologie als ungeschlechtliche Fortpflanzung bezeichnen Jede Klasse hat h chstens ein Elternteil n mlich die Klasse von der sie abgeleitet ist Ebenso wie ein Kind Eigenschaften der Mutter und des Vaters erben kann ist es in C erlaubt da eine Klasse von mehreren sogar beliebig vielen Klassen abgeleitet wird Bei mehrfacher Vererbung m ssen bei der Deklaration einer Klasse mehrere Basisklassen angegeben werden Dabei werden die einzelnen Basisklassen durch Kommata getrennt Vor der Initialisierung eines Objekts werden die Konstruktoren aller Basisklassen in der Reihenfolge aufgerufen in der sie bei der Klassendefinition angegeben wurden Dabei k nnen auch Initialisierer Listen verwendet werden in denen die einzelnen Konstruktor Aufrufe durch Kommata getrennt werden Ein einfaches Beispiel Soll zum Beispiel eine Klasse Stringfeld von den Klassen String und Position abgeleitet werden sieht das so aus class Stringfeld public String public Position Es folgt ein einfaches und damit pra
74. auf diese Speicherstelle Die Adresse wird mit der Funktion MK_FP MaKe Far Pointer aus Segment und Offset gebildet bitset far FlagPtr bitset far MK_FP 0x0040 0x17 Das Attribut far bewirkt da auch bei einem kleinen Datenmodell hier eine vollst ndige Adressierung mit Segment und Offset vorgenommen wird Um die Dereferenzierung dieses Zeigers zu verbergen definieren wir eine bitset Referenz auf diese Adresse volatile bitset far amp Flags FlagPtr Die Variable Flags ndert sich bei Tastendr cken au erhalb der Kontrolle unseres Programms durch eine Interrupt Routine Dies k nnte dem Programm entgehen wenn der Compiler das Programm optimiert und den Wert in ein Prozessor Register kopiert Deshalb mu mit dem Attribut volatile verhindert werden da der Compiler erneutes Lesen aus dem Hauptspeicher wegoptimiert IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII I II III II I II I I II II I II I II III LT BITS Mit ET3 CPP Konstruktoren und berladen von Operatoren a LALTIAAI LAAI IALL ALA LAAL LILILA LIAA AAAI LALALALA IAAL LALA include lt iostream h gt include lt dos h gt defin INT_BITS 16 ifndef BOOLEAN define BOOLEAN enum false true typedef int boolean ndif class bitset nur f r Tastendemo 0 public bitset Konst
75. be tderr Fehlerausgabe mit stdout identisch wenn stdout nicht umgeleitet wird un un un Unter MS DOS ist noch eine kleine Komplikation zu beachten W hrend unter UNIX die Konvention gilt da der Zeilenwechsel in einer Textdatei durch das Zeichen n Zeilenvorschub gekennzeichnet wird gilt in der MS DOS Welt die merkw rdige Vereinbarung da die Textzeilen durch eine Folge von zwei Bytes n mlich r n Wagenr cklauf Zeilenvorschub getrennt werden Das ist ein Relikt aus den Zeiten der Fernschreiber Mit der Trennung von Wagenr cklauf und Zeilenvorschub war es beispielsweise m glich eine Zeile zun chst zu schreiben und anschlie end nach einem Wagenr cklauf zu unterstreichen Abgesehen davon da dieses historische Relikt unn tig Speicher verschlingt ist sie auch ein Fallstrick beim Programmieren in C Um die Portabilit t von C Programmen zu garantieren die auf Textdateien zugreifen werden Textdateien auch in den MS DOS Versionen von C intern im UNIX Format behandelt Obwohl C keinen formalen Unterschied zwischen Text und Bin rdateien macht mu man unter MS DOS beim ffnen der Datei angeben ob sie als Bin rdatei oder als Textdatei behandelt werden soll Im letzteren Fall wird Lesen aus der Datei automatisch die Byte Folge r n in das Zeichen n umgewandelt Beim Schreiben geschieht dies in umgekehrter Richtung Um die Art der Umsetzung anzugeben k nnen Sie an den Modus String den Buchstaben t f
76. ben Im folgenden Beispiel teilen sich drei Bitfeld Komponenten ein Maschinenwort struct Beispiell int i 6 Wertebereich 32 31 unsigned u 3 Wertebereich 0 7 unsigned 5 7 Wertebereich 0 327 F Zum Auff llen von L cken k nnen auch unbenannte Bitfelder verwendet werden struct Beispiel2 unsigned i 4 unsigned 3 nicht ansprechbare L cke von 3 Bits unsigned j 9 Falls Sie Bitfelder verwenden wollen sollten Sie folgende Hinweise beherzigen Es gibt keine Vorschrift wie ein Compiler die einzelnen Bitfelder einer Struktur im Speicher anordnen soll Wenn Sie Daten verarbeiten die nicht von Ihrem Programm erzeugt worden sind k nnen Sie sich nicht darauf verlassen da ein anderer Compiler die Daten ebenso interpretiert In diese Abh ngigkeit vom verwendeten Compiler begeben Sie sich zum Beispiel wenn Sie einem Zeiger auf eine geeignete Struktur mit Bitfeldern die Adresse der Speicherstelle mit den Tastenflags zuweisen Die Sprachdefinition schreibt lediglich vor da unsigned Bitfelder unterst tzt werden m ssen Bitfelder vom Typ int in Zweierkomplement Darstellung k nnen m ssen aber nicht unterst tzt werden Borland C unterst tzt int Bitfelder Zortech C nicht Bitfelder k nnen nicht Elemente einer Union sein Da Bitfelder im allgemeinen nicht auf Byte Grenzen beginnen darf der Adre Operator nicht auf Bitfelder angewendet werden Zeigertypen und Vektoren Auc
77. ben A F und x und ebenso das E f r den Dezimal Exponenten in Gleitkommakonstanten wahlweise gro oder klein geschrieben werden Oktale Konstanten beginnen mit einer Null und d rfen nur die Oktalziffern 0 bis 7 enthalten Auf Byte orientierten Rechnern wie dem IBM PC sind Sedezimal Konstanten meist sinnvoller Sie sollten daran denken da Sie niemals Dezimalzahlen mit f hrenden Nullen auff llen weil sie sonst als Oktalzahlen interpretiert werden Zahlkonstanten geh ren dem kleinstm glichen Datentyp an So ist etwa 17 vom Typ int aber 100000 vom Typ long Durch den nachgestellten Buchstaben 1 oder L 1 kann leicht mit 1 verwechselt werden k nnen auch kleine Zahlen als Long definiert werden Ebenso kann durch den nachgestellten Buchstaben u oder U der Typ unsigned erzwungen werden Auch die Kombination UL ist m glich 17 int 17L long 40000 long zu gro f r int a0000U unsigned int 1000000 unsigned long zu gro f r unsigned int Nicht druckbare Zeichen Konstanten k nnen auch mit Hilfe ihres ASCII Codes dargestellt werden und zwar wahlweise durch die Zeichenfolge x gefolgt von bis zu drei Sedezimalziffern oder durch das Zeichen gefolgt von bis zu drei Oktalziffern So k nnen Sie zum Beispiel das Escape Zeichen ASCII 27 wahlweise durch x1B x01B 33 oder 033 darstellen F r einige oft ben tigte Steuerzeichen gibt es spezielle Standarddarstellungen
78. chen zur ck nachdem es zun chst nach unsigned char und dann nach int konvertiert wurde Ist das Dateiende erreicht wird die Konstante EOF zur ckgegeben Schreiben in eine Datei size_t fwrite const void ptr Puffer Adresse size_t size Elementgr e in Bytes size_t n Anzahl der Elemente FILE stream Dateizeiger fwrite entspricht BlockWrite in Turbo Pascal und hat die gleichen Parameter wie fread int fputs const char s FILE streanm fputs ist das Gegenst ck von fgets Es schreibt den String s der mit 0 abgeschlossen sein mu in die Datei und h ngt nicht automatisch ein Zeilenwechselzeichen an Das folgende einfache Beispiel gibt eine Textdatei am Bildschirm aus In der Praxis sollte man auf m gliche Fehler abfragen include lt stdio h gt int main FILE char s 256 f fopen test cpp rt while fgets s 256 f fputs s stdout fclose f return 0 Wenn wir hier fputs s stdout durch puts s ersetzen wird am Bildschirm nach jeder Zeile eine Leerzeile eingef gt weil fgets den Zeilenwechsel mitliest und puts die Ausgabe immer mit einem Zeilenvorschub beendet int fpute int c FILE stream fputc schreibt das Zeichen char c in die Datei und gibt es als Funktionswert zur ck bei Erreichen des Dateiendes wird EOF zur ckgegeben Positionieren in einer Datei Im Gegensatz zu Standard Pascal ist
79. cht auf den ersten Blick erkennen da die Ausdr cke identisch sind Eine Hilfsvariable kann dieses Problem teilweise aber nicht ganz mildern int t a ll0 i b k IE ES lt 5 all0O i b k t Als Ziel der Zuweisung mu weiterhin das Originalobjekt angegeben werden C erlaubt auch Referenzvariablen die ebenso wie Referenzparameter als Synonyme f r eine andere Variable stehen int amp t a ll0 i b k t ist Referenz auf a ll0 i b k in tasa ee t t Bevor eine Referenzvariable als Synonym f r ein anderes Objekt verwendet werden kann mu sie mit diesem Objekt verbunden werden Dies geschieht bei der zwingend vorgeschriebenen Initialisierung Betrachten Sie bitte das Programmfragment int i a i b Hier wird zun chst die Variable i definiert der Anfangswert a zugewiesen und anschlie end mit dem Wert b berschrieben Sie sehen da die Wirkung einer Initialisierung und einer separaten Zuweisung identisch ist Bei der Behandlung von Klassen werden Sie sehen da es doch einen wichtigen Unterschied zwischen Initialisierung und Zuweisung gibt Bei Referenzvariablen sieht es v llig anders aus Hier wird durch die Initialisierung vereinbart zu welchem Objekt die Variable synonym sein soll Danach steht die Variable dann f r ihr Synonym Es folgt das entspechende Beispiel int amp i a i ist Referenz auf a i b gleichbedeutend mit a Besonders klar wird sich der Nutzen von Referenzen
80. cke die der Compiler von Borland C f r den 80286 Prozessor erzeugt miteinander verglichen Der Code f r den Funktionsaufruf Version A belegt 10 Bytes Dazu kommen einmalig noch 22 Bytes f r den Code der Funktion max Die Version B ben tigt 13 Bytes Hier gibt es keinen eindeutigen Gewinner Bei bis zu 7 Aufrufen von max ist die Version B platzsparender ab dem 8 Aufruf liegt die Version A vorn Ganz anders sieht es allerdings bei der Geschwindigkeit aus Version A ben tigt 32 Prozessortakte f r den Funktionsaufruf und 57 oder 59 Takte je nach Ergebnis des Vergleichs f r die Abarbeitung der Funktion insgesamt also rund 90 Takte Die Version B begn gt sich mit nur 15 oder 18 Takten ist also 5 bis 6 mal schneller Dieser gewaltige Unterschied erkl rt sich dadurch da vor einem Funktionsaufruf die Parameter auf den Stack gebracht werden m ssen die Kontrolle an die Funktion bergeben und anschlie end die Parameter wieder vom Stack genommen werden m ssen So kommt es da bei einer so einfachen Funktion wie der max Funktion dieser rein organisatorische Aufwand ber viermal soviel Zeit ben tigt wie die eigentliche Rechnung C bietet Ihnen gl cklicherweise die M glichkeit die Lesbarkeit der Version A mit der Effizienz der Version B zu vereinen Sie k nnen eine Funktion als inline Funktion deklarieren indem Sie ihr das Schl sselwort inline voranstellen Damit wird der Compiler angewiesen jeden Funktionsaufruf so zu co
81. der Compiler keinen Fehler obwohl die Klasse keinen Gleichheitsoperator mehr hat und was ist der Unterschied in der Behandlung der Gleichheit Beispiel Auf eine Datei ausgelagerte gro e Vektoren Das folgende Beispiel geh rt eigentlich zum Thema berladen von Operatoren zeigt aber auch eine Anwendung der Typumwandlungen Wir wollen einen Typ fvektor definieren der wie ein Pascal Array einen beliebigen Indexbereich hat Dazu m ssen wir die Indizes die in C immer ab Null gez hlt werden umrechnen Weiter wollen wir annehmen da der Hauptspeicher zu klein ist um den Vektor unterzubringen Wir lagern den Vektor daher auf eine Datei aus Trotz allem soll er in der blichen Weise mit dem Operator indiziert werden Eine naheliegende M glichkeit w re es nun den Operator so zu berladen da er den Wert des angesprochenen Elements zur ckliefert Damit w ren zwar Anweisungen wie n Alil m glich nicht aber eine Zuweisung der Form Offenbar darf der Operator nicht den Wert des Objekts R Wert sondern eine Referenz L Wert zur ckliefern Aber auch das l st unser Problem noch nicht denn eine Referenz steht f r ein Objekt im Hauptspeicher unsere Objekte befinden sich aber an einer bestimmten Stelle einer Datei Deshalb definieren wir einen Typ DateiPos der f r eine bestimmte Position in einer ge ffneten Datei steht Jetzt bekommen wir die Zuweisung in den Griff indem wir eine Typumwandlung von DateiPos nach int de
82. der Zeiger verpackt Zum Verst ndnis m ssen Sie wissen da un re Operatoren rechtsassoziativ sind Ziel steht also f r Ziel und nicht etwa f r Ziel Weiter m ssen Sie sich klarmachen da der Wert von Ziel die Adresse vor dem Erh hen ist Ein solch kryptischer Stil wird immerhin von modernen Compilern mit mehreren Warnungen bedacht Die Form while a b k nnte ein Pascal Programmierer versehentlich statt while a b geschrieben haben Au erdem ist eine leere Anweisung nach einer while Bedingung verd chtig In diesem Fall kann man diese Warnungen ignorieren aber im allgemeinen k nnen Sie sich viel Kummer ersparen wenn Sie jede Warnung des Compilers berpr fen Schlie lich sehen Sie das Beispiel noch einmal f r or Liebhaber char strcpy char Ziel const char Quelle for Ziel Quelle t bungsaufgabe 6 Was bewirkt das folgende Programmst ck char s 10 strepy s Vorsicht strcepy s 1 s bungsaufgabe 7 Testen Sie folgendes Programm und erkl ren Sie das merkw rdige Verhalten include lt iostream h gt include lt string h gt main char s1 6 s2 4 s3 6 strcpy s3 BAR strcpy s2 WIRKLICH strcpy sl WUNDER strcat sl s3 cout lt lt n lt lt sl S S Zeiger auf Funktionen In C k nnen Sie keine Variablen erkl ren die Funktionen als Wert haben Dies scheitert technisch daran da je zwei Funk
83. der virtuellen Funktion die zum Objekt geh rende Version angibt Ist eine Funktion einmal als virtuell erkl rt ist sie automatisch in jeder abgeleiteten Klasse wieder virtuell Zum besseren Verst ndnis sollte man das Schl sselwort virtual bei jeder Neudefinition in einer abgeleiteten Klasse wiederholen obwohl C das freistellt In unserem Figuren Programm werden in der Basisklasse Figur die gemeinsamen Eigenschaften der konkreten Klassen Kreis und Rechteck definiert Es hat keinen Sinn Objekte der Basisklasse selbst zu definieren denn eine allgemeine Figur kann weder gezeigt noch gel scht werden Man spricht in solchen F llen von einer abstrakten Basisklasse In C kann man bei virtuellen Funktionen in einer Basisklasse auf eine Implementierung verzichten indem man 0 hinter die Funktionsdeklaration schreibt Eine solche Funktion hei t dann rein virtuell pure virtual Eine Klasse mit mindestens einer rein virtuellen Funktion ist eine abstrakte Basisklasse Die Definition von Objekten einer solchen Klasse betrachtet der Compiler als Fehler In der folgenden Version des Figuren Programms werden im Hauptprogramm je ein Kreis und ein Rechteck definiert Einem Zeiger Figur aktuelleFigur kann wahlweise die Adresse des Kreises oder des Rechtecks zugewiesen werden Die Wirkung der Anweisung aktuelleFigur gt zeige kann deshalb erst zur Laufzeit ermittelt werden VIIIIIIIIIIIIIIIIIIIIIIIIIIIIII III I III III I III IIII I
84. dh Jahr Reg x cx char MoName l12 Januar Februar M rz April Mai Juni Juli August September Oktober November Dezember char WoTag 7 3 Z Mo Di Mi Do Fr tsat sory static int MoAnf 12 0 31 bl 92 122 153 184 214 245 275 306 337 Mrz Apr Mai Jun Jul Aug Sep Okt Nov Dez Jan Feb Datum Datum int Tag int Monat int Jahr t T g m Monat j Jahr berechneTagnummer void Datum heute int t nm j DosGetDate t m J this Datum t m J int Datum Wochentag return 1 Tagnummer 2 7 char Datum String static char s 15 Beispiel 01 07 1991 strcpy s WoTag Wochentag 1 Di s 2 Di DREI itoa t 100 s 3 10 J Dipo 3 Na Di 01 itoa m 100 s 6 10 IF DE 01102 s 6 s 9 FF DE OL2LOT FRE itoa j s t10 10 Di 01 07 1991 return S void Datum Ostern int Jahr Formel von Gau Hartmann nach Schlag nach int q Jahr 4 Bibliographisches Institut Mannheim 1960 int a Jahr 19 gilt in dieser Form nur von 1900 2099 int b 204 11 a 30 if b gt 27 b int c Jahr q b 13 7 int E 28 br if t gt 31 this Datum t 31 4 Jahr else this Datum t 3 Jahr void Datum Busstag int Jahr Bu tag ist Mittwoch 16 bis 22
85. die Prozedur in C ganz wie in Pascal programmieren l t Um einen formalen Parameter als Referenzparameter zu kennzeichnen stellt man das Zeichen amp hinter den Typnamen Wird das Zeichen amp nicht in einer Parameterliste und nicht in einer Variablendeklaration verwendet so wirkt es wie in C als Adre Operator Den werden Sie aber in C nur selten ben tigen Referenzparameter sollten Sie immer dann verwenden wenn eine Prozedur die ihr bergebenen Parameter ver ndert Aber auch bei unver nderlichen Parametern kann eine Referenz bergabe in manchen F llen gerechtfertigt sein n mlich dann wenn eine Prozedur mit so speicheraufwendigen Parametern arbeitet da das Kopieren eines Parameters gegen ber der Adre bergabe wesentlich aufwendiger w re Sie sollten sich aber auch ber die Nachteile solcher technischen Referenzparameter klar sein Damit verschenken Sie die M glichkeit beliebige Ausdr cke zu bergeben und automatische Typkonvertierung zu erzwingen C geht sogar noch einen Schritt weiter als Pascal und erlaubt die bergabe von Referenzen nicht nur in Parameterlisten Betrachten wir folgendes Programmst ck if allO i b k 3 all0 i b k 5 all0O i b k all0 i b k Hier wird mehrmals das gleiche Objekt angesprochen F lle dieser Art bedeuten erstens hohen Schreibaufwand und zweitens mu falls der Compiler hier nicht optimiert mehrmals die gleiche Adresse berechnet werden berdies kann man ni
86. dieren als ob er direkt implementiert w re Damit k nnen wir also eine dritte Version schreiben Version C inline Funktion inline int max int i int j if i gt j return i else return j m max a b Diese Version erzeugt den gleichen Code wie die Version B F r das Beispiel der max Funktion ist das die optimale L sung Wegen der fehlenden Parameter bergabe sind inline Funktionen immer schneller als normale Funktionen Sie sollten allerdings nur extrem kurze Funktionen als inline deklarieren denn bei l ngeren inline Funktionen die oft im Programmtext verwendet werden macht sich der erh hte Speicherbedarf schnell bemerkbar Das Schl sselwort inline ist brigens keine Garantie da die Funktion auch wirklich als inline Funktion bersetzt wird Borland C ignoriert es bei zu komplizierten Funktionen Zur Erleichterung der Arbeit mit dem Debugger gibt es eine Option die das Schl sselwort inline wirkungslos macht 1 9 Typkonvertierungen Implizite Konvertierungen C ist bei der Verwendung der elementaren Typen in Ausdr cken Zuweisungen und Prozeduraufrufen recht liberal Im Gegensatz etwa zu Modula 2 wo jede Konvertierung ausdr cklich vom Programmierer angefordert werden mu nimmt C eine ganze Menge von Standard Konvertierungen vor Innerhalb von Ausdr cken d rfen die vordefinierten Datentypen im Prinzip beliebig gemischt werden Hiervon sollten Sie allerdings m glichst mit Ma en Gebrauch machen
87. e passenden Methoden einzusetzen Bei einer Anweisung wie Objekt zeige pr ft der Compiler den Typ der Variablen Objekt und setzt dann die Methode zeige aus der entsprechenden Klasse ein Das nennt man fr he Bindung oder auch statische Bindung Von sp ter Bindung oder dynamischer Bindung spricht man dann wenn der Typ eines Objekts noch nicht vom Compiler erkannt werden kann sondern erst zur Laufzeit des Programms Sp te Bindung er ffnet einerseits ungeahnte neue M glichkeiten andererseits mu sie mit einem kleinen Verlust an Effizienz erkauft werden Deshalb kann man in C zwischen fr her und sp ter Bindung w hlen Zun chst ist die Typstrenge wie folgt aufgelokkert Einer Variablen vom Typ Zeiger auf eine Klasse darf man einen Zeiger auf eine abgeleitete Klasse zuweisen Ruft man ber diesen Zeiger eine Methode auf so mu im Normalfall der fr hen Bindung der Compiler entscheiden aus welcher Klasse er die Methode nehmen soll Dabei mu er sich nach dem Typ der Zeigervariablen richten Bei sp ter Bindung wird zur Laufzeit der aktuelle Typ des Objekts auf das der Zeiger zeigt zugrundegelegt Sp te Bindung wird in C durch virtuelle Funktionen realisiert Durch das Schl sselwort virtual vor der Deklaration einer Elementfunktion wird dem Compiler mitgeteilt da er sp te Bindung verwenden soll Technisch wird dies dadurch realisiert da jedes Objekt der Klasse zus tzlich einen Zeiger auf eine Tabelle enth lt die zu je
88. e Funktion kann nicht auf nicht statisches Element zugreifen so werden statische Detenelemente initialisiert H je c D u Il oO int main Aa a f 0 ASEE 7 Fehler nicht statische Elementfunktion kann nur von einem Objekt nicht von der Klasse aufgerufen werden a g vorher mu A g korrigiert werden A g 3 7a Zeiger auf Elementfunktionen wird noch nachgetragen 3 8 Vererbung Mit Hilfe der Vererbung ist es m glich Klassen zu definieren die sich von einer schon vorhandenen Klasse nur in einigen Details unterscheiden Damit wird die Wiederverwendung von Klassen enorm erleichtert Ein einfaches Grafik Programm Zur Motivation der Vererbung betrachten wir einen primitiven Prototyp eines CAD Programms Mit diesem einfachen Programm k nnen Sie lediglich zwei vorgegebene Objekte einen Kreis und ein Rechteck auf dem Bildschirm bewegen Dazu werden zwei Klassen Kreis und Rechteck definiert die beide neben ihrem Konstruktor die folgenden Methoden kennen void zeige zeichnet das Objekt in Vordergrundfarbe void loesche zeichnet das Objekt in Hintergrundfarbe void bewege int dx int dy relative Verschiebung Die Methode bewege l uft in drei Schritten ab 1 Das Objekt wird gel scht 2 Die Koordinaten werden verschoben 3 Das Objekt wird mit den neuen Koordinaten gezeigt Diese Art der Bewegung auf dem Bildschirm hat ihre Grenzen Sie k
89. e Zweig auch entfallen telse Direktive und Programmst ck2 Mit der ifnde f Direktive kann auch gepr ft werden ob der Bezeichner nicht definiert ist Die Direktiven zur bedingten Compilierung d rfen selbstverst ndlich verschachtelt werden In der integrierten Umgebung von Borland C k nnen define Anweisungen auch im Men Options Compiler Code Generation Defines angegeben werden Das ist vor allem dann praktisch wenn diese Definitionen in mehreren Dateien ben tigt werden 2 2 Modularisierung Bisher haben wir nur Programme betrachtet deren Quelltext in einer Datei abgespeichert ist Nicht ganz kleine Programmierprojekte werden aber in der Praxis sinnvollerweise modular aufgebaut Der Programmtext wird so in mehrere Dateien zerlegt da einzelne dieser Dateien m glichst f r andere Zwecke wiederverwendet werden k nnen Jede dieser Dateien wird einzeln bersetzt und die bersetzten Objekte zu einem lauff higen Programm zusammengebunden Turbo Pascal bietet hierf r ab der Version 4 0 das Unit Konzept an Eine erste Vorstellung wie Sie in C Programme modular aufbauen k nnen sollen Ihnen die folgenden Programmskelette geben unit Hilf hilf cpp interface var i integer int i function f i integer char implementation var k integer procedure p i integer begin static int k static void p int i end function f i integer char char f int i begin end end program Ha
90. e und empfehle Ihnen einen einfachen Programmierstil der es Ihnen erm glicht wenigstens Ihre eigenen Programme sp ter wieder zu durchschauen Was die Schwierigkeit einer Programmiersprache betrifft so sollten Sie unterscheiden zwischen der Schwierigkeit die Sprache zu erlernen und der Schwierigkeit Probleme mit der Sprache zu l sen Ein Bagger ist zwar schwieriger zu bedienen als ein Suppenl ffel Beim Ausheben einer Baugrube werden Sie sich aber mit dem Bagger leichter tun In diesem Sinne ist C ein leistungsf higer Bagger ber dessen Design und Ergonomie man sicher geteilter Meinung sein kann Dieses einf hrende Kapitel soll Ihnen den Umstieg von Pascal nach C m glichst leicht machen Sie werden deshalb haupts chlich die Sprachmittel kennenlernen die es in gleicher oder hnlicher Form auch in Pascal oder im erweiterten Sprachvorrat von Turbo Pascal gibt Wenn Sie sich am Ende dieses Kapitels sich noch nicht f r C erw rmen k nnen liegt das einfach daran da Sie die Sprachmittel die den eigentlichen Wert von C ausmachen erst sp ter kennenlernen werden Sie werden in diesem Kapitel vergeblich nach umfangreicheren realistischen Programmbeispielen suchen Daf r gibt es zwei Gr nde Zum einen sind Sie ja bereits mit Pascal oder vielleicht Modula 2 vertraut so da knappe Gegen berstellungen ausreichen d rften um Ihnen die Unterschiede in der Syntax zu verdeutlichen Zum anderen m chte ich die wirklich interess
91. e zwei Klassenargumente annimmt bitset Durchschnitt bitset a bitset b Durchschnitt bitset s s bits a bits amp b bits return s Leider ist das aber so nicht m glich weil das Element bits privat ist W rde man aber deshalb pits als public erkl ren hie e das auf alle Vorteile des Geheimnisprinzips zu verzichten C bietet hier die M glichkeit gezielte Ausnahmen der Privatheit zu erkl ren Eine Klasse kann einer Funktion au erhalb der Klasse den Zugriff auf ihre privaten Elemente erlauben Hierzu wird innerhalb der Klassendefinition eine Deklaration der zugriffsberechtigten Funktion eingef gt und das Schl sselwort friend davorgestellt In unserem Beispiel s he das so aus class bitset friend bitset Durchschnitt bitset a bitset b 7 Es ist auch erlaubt eine andere Klasse als friend zu erkl ren class A friend class B 7 Mit dieser Erkl rung haben alle Funktionen der Klasse B das Zugriffsrecht auf die privaten Elemente der Klasse A Es gibt keine Vorschrift an welcher Stelle in einer Klassendefinition die friend Erkl rungen stehen sollen Da dies Informationen sind die f r den Benutzer der Klasse unwesentlich sind empfiehlt es sich sie im privaten Teil der Klassendefinition unterzubringen Zwei Klassen k nnen sich auch gegenseitig das Zugriffsrecht geben Hier mu die Klasse die im Text zuerst erscheint die andere Klasse als Freund erkl ren Da die andere Klasse hier aber n
92. eFlags cout lt lt LShift if Ctrl lt neuerFlags cout lt lt Ctrl if Alt lt neuerFlags COUE lt lt VAT T while AbbruchFlags lt neueFlags main BitsetDemo TastenDemo Hinweise f r das berladen der einzelnen Operatoren Allgemeines Beim berladen von Operatoren haben Sie die Freiheit jedem Operator im Zusammenhang mit einer Klasse eine beliebige Bedeutung zu geben Dabei sollten aber in jedem Fall Erwartungen ber cksichtigt werden die sich aus der blichen Insert Bedeutung des Operators aufdr ngen So kann es sinnvoll sein den Operator wie in Pascal f r die Verkettung von Strings oder f r die Vereinigung von Mengen zu verwenden Wenn keine naheliegende Analogie zur blichen Verwendung eines Operators besteht sollte man lieber auf Operatoren verzichten und eine sinnvoll benannte Funktion verwenden Der Zuweisungoperator Wenn der Zuweisungsoperator nicht berladen wird wird ein Standard Mechanismus verwendet Alle Datenelemente werden einzeln zugewiesen Das ist oftmals nicht das gew nschte n mlich meist dann wenn die Klasse Zeigerelemente enth lt Wenn statt der Zeiger die Daten kopiert werden sollen auf die die Zeiger zeigen mu der Zuweisungsoperator berladen werden Die arithmetischen Zuweisungsoperatoren usw Diese Operatoren ergeben sich nicht automatisch aus den entsprechenden arithmetischen Operatoren und dem Zuweisungsoperator Wenn Sie und
93. eben in denen sich ein Kreis von einem Punkt abhebt class Kreis public Punkt Kreis ist von Punkt abgeleitet public Kreis int x0 int y0 int r0 void zeige void loesche void bewege int dx int dy private int Radius FS Die Implementierung k nnen wir von der ersten Version bernehmen Es folgt das vollst ndige Programm IIIIIIIIIIII III ELALI III III III III III III IAIL III I II I II LIIL FIGUREN1 CPP Geometrische Objekte mit Vererbung IIIIIIIIIIIIIII III III III III III III III III III I II III III III I II I II I II include lt graphics h gt include lt ctype h gt include lt conio h gt class Punkt public Punkt int x0 int yO int x Die Datenkomponenten sind hier vorl ufig public int y Der Grund wird im n chsten Abschnitt verst ndlich E class Kreis public Punkt public Kreis int x0 int y0 int r0 void zeige void loesche void bewege int dx int dy private int Radius E class Rechteck public Punkt public Rechteck int x0 int y0 int x1 int yl void zeige void loesche void bewege int dx int dy private int a b die beiden Seiten p 1 Implementierung der Klasse Punkt Punkt Punkt int x0 int y0 x x0 y y0 1 Implementierung der Klasse Kreis Kreis Kreis int x0 int y0 int r0 Punkt x0 y0 Radius r0 v
94. ehl IF ERRORLEVEL abgefragt werden kann Hier beginnt das vollst ndige Programm FILETEST CPP include lt stdio h gt include lt conio h gt getch include lt string h gt include lt ctype h gt char Auswahl const char erlaubt char zZ do z toupper getch Er 2 S IND erweiterter IBM Code getch n chstes Zeichen aus dem Tastaturpuffer holen while strchr erlaubt z NULL return zZ long filesize FILE f long pos laenge pos ftell f aktuelle Position des Dateizeigers fseek f OL SEEK_END positioniert ans Ende der Datei laenge ftell f fseek f pos SEEK_SET setzt den Dateizeiger zur ck return laenge int main int n Wert Ergebnis long Pos FILE char zi printf n n if fopen test dat r b printf Die bestehende Datei wurde er ffnet n printf Dateigr e ld Bytes n filesize f else if f fopen test dat w b printf die Datei wurde neu angelegt n else printf Datei kann nicht angelegt werden n return 1 while 1 Pos ftell f printf aktuellePosition ld L esen S chreiben P ositionieren E nde n Pos z Auswahl LSPE switch z case L n fread amp Wert siz
95. eine F lle von Variablen zu verwalten deren Wertebereich sehr klein ist typischerweise logische Werte Flags Um hier nicht f r jede Variable ein Byte oder gar Wort zu verschwenden werden mehrere Informationen in ein Byte gepackt Typische Beispiele sind die Variablen im Systembereich Ihres PCs So gibt es etwa an der Speicheradresse 417H ein Byte das in seinen einzelnen Bits st ndig den Zustand der Umschalttasten sowie der Strg und Alt Tasten widerspiegelt Da die kleinste adressierbare Einheit Ihres Rechners das Byte ist sind schon einige Verrenkungen n tig um einzelne Bits zu manipulieren Zum Pr fen eines Bits kann man etwa eine bitweise Und Verkn fung mit einer Konstanten vornehmen die genau an der richtigen Stelle ein gesetztes Bit hat und pr fen ob das Ergebnis von Null verschieden ist Solche Kunstst cke machen das Lesen eines Programms allerdings zur Qual und sollten nach M glichkeit vermieden werden In Pascal bietet sich zur L sung solcher Probleme das Mengenkonzept an So k nnen etwa 16 durch einen Aufz hlungstyp definierte Flags in einem Maschinenwort untergebracht werden Wir werden sp ter sehen wie sich solche Probleme mit Hilfe des Klassenkonzepts in C elegant l sen lassen Deshalb k nnen Sie diesen Abschnitt ohne Schaden berspringen Aus Standard C steht die M glichkeit zur Verf gung innerhalb von Strukturen Bitfelder zu definieren Das sind Ganzzahl Komponenten die eine Breite von 1 bis 16 Bits ha
96. el das beide Umwandlungsarten und m gliche Fehlerquellen aufzeigt Hier ist die Umwandlung von TypA nach TypB mit beiden Methoden definert Der Compiler meldet diese Mehrdeutigkeit als Fehler aber nur wenn im Programm wirklich eine Umwandlung ben tigt wird Demonstration von Typ Umwandlungen class TypB class TypA public TypA 0 TypA int i Konstruktor zur Umwandlung int gt TypA operator int Umwandlung TypA gt int operator TypB Umwandlung TypA gt TypB private int n P3 class TypB public TypB TypB TypA a Konstruktor zur Umwandlung TypA gt TypB operator TypA Umwandlung TypB gt TypA private int n TypA TypA TypA operator int return n TypA TypA int i n i TypB TypB 0p TypB TypB TypA a n a TypB operator TypA return TypA n int main TypA a TypB b inEsL I eia i b Fehler keine Umwandlung von TypB nach int definiert a i a Sby b i b a Fehler Typumwandlung mehrdeutig a TypA operator TypB b TypB TypB TypA bungsaufgabe 11 Erweitern Sie die Klasse bitset im Programm BITSET3 CPP um implizite Typ Umwandlungen von und nach int bungsaufgabe12 Entfernen Sie aus der Klasse rational die Operatoren und Schreiben Sie dann ein Testprogramm in dem zwei rationale Zahlen auf Gleichheit gepr ft werden Warum meldet
97. ellt man dazu ein Axiomensystem auf das den Datentyp mit seinen Methoden eindeutig beschreibt In der Praxis gen gt es meist die Methoden verbal zu beschreiben Wir k nnten den abstrakten Datentyp Puffer etwa durch folgende konkrete Implementierung darstellen const int MAX 10 struct Puffer char D MAX int Anfang Ende 1 void leere Puffer amp P Referenzparameter wird ver ndert P Anfang P Ende 0 boolean istLeer Puffer P Wertparameter wird nur abgefragt return P Anfang P Ende boolean istVoll Puffer P return P Anfang P Ende 1 MAX void lege Puffer amp P char c Einschr nkung if istVoll P return Fehler wird ignoriert P D P End e7 if P Ende gt MAX P Ende 0 char entnimm Puffer amp P if istLeer P return 0 Hl ATO char z P D P Anfang if P Anfang gt MAX P Anfang 0 return zZ Hier wird eine zyklische Anordnung der Elemente des Puffers in einem Vektor der L nge MAX verwendet Das erste Element hat den Index Anfang das letzte den Index Ende 1 Ist Anfang gleich Ende so ist der Puffer leer Um einen vollen von einem leeren Puffer unterscheiden zu k nnen d rfen h chstens max 1 Elemente gepuffert werden Der Puffer ist voll wenn dem Index Ende in der zyklischen Anordnung der Index Anfang direkt folgt Wenn man sich jetzt konsequent daran h lt nur ber die Methoden au
98. en Typ Konvertierungen bereits kennengelernt Aufgrund dieser automatischen Umwandlungen d rfen Sie zum Beispiel der Bibliotheksfunktion sin Argumente eines beliebigen Zahltyps bergeben Jetzt wollen wir sehen wie man implizite Typ Umwandlungen bei eigenen Typen selbst definieren kann Wir unterscheiden zwei F lle Umwandlung von einem beliebigen Typ in einen Klassentyp Hierzu mu in der Klasse ein Konstruktor mit einem Argument des beliebigen Typs definiert werden Der Konstruktor der Klasse rational ist ein Beispiel hierf r rational long Zaehler 0 long Nenner 1 Hiermit werden eigentlich drei Konstruktoren deklariert ohne Argument mit einem und mit zwei Argumenten Hier interessiert der Konstruktor mit einem Argument Er erm glicht zum Beispiel die folgende Zuweisung rational r long 1 r i Konvertierung von long nach rational Umwandlung von einem Klassentyp in einen beliebigen Typ Hierf r kann das Schl sselwort operator in einer neuen Bedeutung verwendet werden Es wird eine Elementfunktion der Form operator Typ deklariert Als Beispiel f gen wir in die Klasse rational eine implizite Typ Umwandlung in den Typ double ein Dazu setzen wir im public Abschnitt der Klassen Deklaration die zus tzliche Zeile operator double ein Die Implementierung sieht so aus rational operator double return double p double q Es folgt ein etwas komplizierteres kommentiertes Skelett Beispi
99. en letzte Komponente eine union ist F r unseren einfachen Spezialfall bietet sich in C eine sogenannte anonyme union an Dabei wird kein Name f r die union vergeben Die Komponenten d rfen dann nicht mit anderen Namen ihres Geltungsbereichs kollidieren und k nnen direkt angesprochen werden include lt iostream h gt main union int i unsigned u i el cout lt lt u Ergebnis 65535 Aufz hlungstypen Aufz hlungstypen sind ein sehr n tzliches Mittel implementierungsinterne Codierungen zu verbergen und damit Programme lesbarer zu machen In Pascal k nnte man etwa die 16 Standard Farben des EGA Adapters so definieren type Farbe BLACK BLUE GREEN CYAN RED MAGENTA BROWN LIGHTGRAY DARKGRAY LIGHTBLUE LIGHTGREEN LIGHTCYAN LIGHTRED LIGHTMAGENTA YELLOW WHITE Die so definierten Namen haben die Werte O bis 15 Wenn wir allerdings jetzt zum Beispiel eine Farbe setzen wollen mit setcolor BLUE Type mismatch bekommen wir eine Fehlermeldung Type mismatch In der Unit Graph sind die Farben n mlich nicht als Aufz hlungstyp sondern als Konstanten vom Typ word definiert Die Prozedur setcolor verlangt ein Argument vom Typ word und nicht vom Typ Farbe Obgleich die Elemente unseres Aufz hlungstyps die gleichen Werte repr sentieren sind sie nicht typvertr glich mit den word Konstanten Wir k nnen die Typanpassung
100. en von Vorteil langeVariable 2 i j langeVariable 2 i j 2 ist m hsamer zu schreiben und nicht so leicht lesbar wie langeVariable 2 i j 2 Zudem macht diese Schreibweise dem Compiler klar da er die Adresse der Variablen nicht zweimal berechnen mu In entsprechender Bedeutung gibt es die Operatoren x gt gt lt lt amp Besonders oft kommt eine Erh hung oder Verminderung einer Variablen um eins vor Daf r hat Turbo Pascal von Modula 2 die Prozeduren INC und DEC bernommen C bietet hierf r die un ren Operatoren und an Statt a 1 k nnen Sie auch a oder a schreiben a 1 k nnen Sie durch a oder a ersetzen Zwischen der Pr fix und der Postfix Schreibweise gibt es einen feinen Unterschied der nur dann von Bedeutung ist wenn der Wert eines solchen Ausdrucks ausgewertet werden soll Der Wert eines Pr fixausdrucks ist der neue Wert der Variablen der des Postfix Ausdrucks der alte Wert Jetzt k nnen Sie sich auch die Bedeutung des Namens C erkl ren Das Programmst ck 2 le a printf A 2 Le a printf B schreibt 2 mal A aber nur einmal B Der Operator sizeof Mit diesem Operator den es hnlich auch in Turbo Pascal gibt kann die Gr e eines Datentyps oder eines Ausdrucks in Bytes ermittelt werden Er wird formal wie eine Funktion verwendet Beispiele Int i sizeof int jJ sizeof i Der Bedingungso
101. eof int 1 f if n 1 printf Wert ld d n Pos Wert else printf Lesen gescheitert d n n break case S printf Wert scanf d amp Wert printf n n fwrite amp Wert sizeof int 1 f if n 1 printf Wert wurde geschrieben n else printf Schreiben gescheitert d n n break case P printf neue Position scanf 31ld amp Pos printf n Ergebnis fseek f Pos SEEK_SET if Ergebnis 0 printf Positionieren erfolgreich n else printf Positionieren gescheitert n break case E fclose f return 0 String Funktionen Die Funktionen strcpy und strcat haben wir bereits mehrfach verwendet Bevor Sie eigene Funktionen zur String Manipulation schreiben sollten Sie einen Blick in die lange Liste der vorhandenen Bibliotheksfunktionen werfen Datei STRING H Hier gibt es Funktionen zum Suchen Vergleichen zur Umwandlung von Gro und Kleinbuchstaben und vieles mehr Mathematische Funktionen Die Header Datei MATH H enth lt die Deklarationen der mathematischen Funktionen nach der ANSI Norm Dazu geh ren fast alle Pascal Standard Funktionen bis auf trunc round odd sqr und viele weitere Funktionen Weitere wichtige ANSI Funktionen Hier konnte nur eine kleine Auswahl wichtiger Bibliotheksfunktionen vorgestellt werden Es gibt eine F lle weiterer Bibliotheksfunktionen nach der ANSI Norm die Ihnen viel Arbeit abnehmen k nnen wie e
102. er implementiert Man k nnte eine einfach verkettete Liste verwenden mit je einem Zeiger auf den Anfang und das Ende Ebensogut ist es aber m glich eine zyklische Liste mit nur einem Zeiger auf das Ende zu verwenden der Anfang ist dann einfach der Nachfolger des Endes In vielen F llen gen gt aber auch ein Vektor fester L nge mit zwei Indexvariablen Die Implementierung aller Puffer Prozeduren h ngt nun entscheidend von der gew hlten Darstellung der Daten ab Ebenso wie man mit einer Prozedur die Details einer Implementierung verbirgt w re es w nschenswert auch die Details eines Datentyps zu verbergen Wenn ein Datentyp aber seine Struktur nicht mehr preisgibt wie kann man dann Operationen mit diesem Datentyp programmieren Die Antwort ist Der Datentyp mu selbst alle mit ihm m glichen Operationen ausf hren k nnen In unserem Beispiel eines Puffers haben wir vier Grundoperationen aufgez hlt Das Prinzip der Datenabstraktion besteht nun darin die Datenstruktur Puffer zusammen mit den Grundoperationen den sogenannten Methoden des Datentyps zu einem Paket so zusammenzuschn ren da nur noch indirekt n mlich mit Hilfe der Methoden auf die Datenstruktur zugegriffen werden mu Man spricht von einem abstrakten Datentyp wenn nur beschrieben wird welche Operationen man mit den Daten ausf hren kann nicht aber wie dies geschieht Die Methoden werden also unabh ngig von einer konkreten Datenstruktur beschrieben In der Theorie st
103. ern auf int Statt dieser schrittweisen Zerlegung von au en nach innen lassen sich komplexe Deklarationen mit etwas bung unmittelbar von innen beim zu deklarierenden Namen beginnend nach au en beim Typnamen endend lesen indem man gem der Vorrangregel wenn m glich zun chst nach rechts geht int aln 32er Die Zahlen O bis 3 zeigen hier die Schritte 0 a ist 1 Vektor von 2 Zeigern auf 3 int Machen Sie sich bitte den Unterschied zwischen den beiden folgenden Deklarationen klar int f VO 3 102 0 f ist 1 Zeiger auf 2 Funktion mit Wert 3 int NE FL 0 3 2 0 0 f ist 1 Funktion mit Wert 2 Zeiger auf 3 int Ein letztes Beispiel dient als nicht nachahmenswerter H rtetest Im n chsten Abschnitt sehen Sie wie man komplexe Deklarationen vermeiden kann EHESTEN FF EP el 6 5 3 1 0 2 4 0 ist 1 Zeiger auf 2 Funktion mit Wert 3 Zeiger auf 4 Vektor von 5 Zeigern auf 6 int bungsaufgabe 8 Orden Sie die Variablen A H im folgenden Pascal Programm den entsprechenden Variablen a n im anschlie enden C Programm zu program PascalProgramm const n 9 type ArrayOf_Int array O0 n 1 of integer ArrayOf_ArrayOf_ Int array O n 1 of ArrayOf_ Int PointerTo_Int integer PointerTo ArrayOf_Int ArrayOf_ Int ArrayOf_PointerTo Int array O n 1 of PointerTo_ Int PointerTo PointerTo_ Int PointerTo_Int var A array O
104. erschwendung wenn wir pauschal 256 Bytes reservieren w rden Stattdessen verwenden wir einen Zeiger dem der wirklich ben tigte Speicher zur Verf gung gestellt wird Konstruktoren C erlaubt es zu jeder Klasse einen oder mehrere Konstruktoren zu definieren Ein Konstruktor ist eine Methode die automatisch aufgerufen wird wenn das Programm in den G ltigkeitsbereich eines Objekts eintritt Um verschiedenartige Objekte einer Klasse definieren zu k nnen darf der Konstruktor auch eine nichtleere Parameterliste haben In unserem Beispiel k nnten wir einen Parameter verwenden in dem die Maximall nge des Strings angegeben wird Wie wird nun ein Konstruktor definiert Formal ist er eine Elementfunktion ohne Funktionswert deren Name der Klassenname ist Allerdings wird bei einem Konstruktor auch der Pseudo Typ void weggelassen der sonst f r einen nicht vorhandenen Funktionswert angegeben wird Sie sehen hier eine unvollst ndige String Klasse mit einem Konstruktor class string public string int n 255 Konstruktor private char s int aktLg int maxLg jez Hier hat der Konstruktor ein Argument mit einem Standardwert Genau genommen haben wir damit zwei Konstruktoren definiert n mlich einen ohne Argument und einen mit einem int Argument Damit k nnen wir Strings fast wie in Pascal definieren Die Definition string sl s2 20 soll einen String s1 der Maximall nge 255 Standard und einen String s2 der
105. es dann mit dem Kopier Konstruktor neu erzeugt Diese Vorgehensweise ist allerdings extrem ineffizient Um das zu verstehen wollen wir etwas genauer betrachten wie der Compiler die Zuweisung eines Funktionswertes handhabt Zuweisung eines Funktionswertes Betrachten Sie folgendes Programmfragment int E int a int b f int t a b return t main int ap D ers i az by Was geschieht in der letzten Programmzeile Zun chst wird die Funktion aufgerufen Diese erzeugt das lokale Objekt t und gibt es mit der return Anweisung zur ck Anschlie end wird der Zuweisungsoperator aufgerufen Aber jetzt existiert die lokale Variable t gar nicht mehr Aus diesem Grund wird in der return Anweisung ein verborgenes tempor res Objekt erzeugt das beim Aufruf des Zuweisungsoperators noch existiert und irgendwann sp ter gel scht wird Wann das genau geschieht ist vom Compiler abh ngig Referenzenz hler Bei unserem String Beispiel wird die Operator Funktion aufgerufen und erzeugt ein tempor res Objekt Dieses wird beim Verlassen der Funktion in eine verborgene tempor re Variable kopiert und diese wird schlie lich in die Zielvariable kopiert Stellen Sie sich vor Sie m chten zwei 100 mal 100 Matrizen addieren Dann best nde die Hauptarbeit des Programms im zweimaligen Kopieren des errechneten Ergebnisses In der Praxis w rden Sie dann vermutlich auf die Eleganz einer Zuweisung der Form verzichten und sich eine Fu
106. esbarkeit muttersprachliche Namen verwenden sollte In diesem Buch verwende ich mit R cksicht auf viele Leser weitgehend deutsche Namen mache aber Ausnahmen in solchen F llen wo bereits englische Namen weitverbreitet sind 1 3 Kommentare Kommentare k nnen zum Verst ndnis eines Programms beitragen wenn sie sinnvoll verwendet werden berfl ssige Kommentare k nnen aber sogar den berblick ber ein Programm erschweren Im Zweifelsfall sollten Sie zun chst versuchen den Programmcode so klar zu gestalten da Kommentare berfl ssig werden Insbesondere ist es nicht der Sinn eines Kommentars die Bedeutung eines Namens zu erkl ren Das sollte der Name selbst tun Kommentare sollten nicht wiederholen was aus dem Programmcode unmittelbar hervorgeht Kommentare sind insbesondere dann sinnvoll wenn die Implementierung eines Algorithmus inhaltlich nicht unmittelbar verst ndlich ist In C gibt es zwei verschiedene M glichkeiten f r Kommentare Mit wird der Beginn mit das Ende eines Kommentars angezeigt Hiermit k nnen gr ere Kommentarbl cke eingeschlossen werden Oft stehen kurze Kommentare am Ende einer Zeile Hierf r gibt es in C eine bequeme Alternative Durch wird der Rest der Zeile zum Kommentar erkl rt Kommentare d rfen nicht ineinander verschachtelt werden Es ist aber erlaubt zwischen und Zeilenendkommentare einzuschlie en 1 4 Elementare Datentypen Die Speicherdarstellung der Standard Datentype
107. f die Objekte vom Typ Puffer zuzugreifen darf die Datenstruktur sp ter beliebig ge ndert werden vorausgesetzt die Methoden werden so angepa t da sie den gleichen Axiomen gen gen Wir k nnten also ohne Probleme auf eine der oben erw hnten verketteten Listendarstellungen umsteigen Unsere konkrete Darstellung des Typs Puffer entspricht brigens genau der Implementierung des Tastaturpuffers in den das BIOS Basic Input Output System Ihres PC Tastenanschl ge auf Abruf zwischenspeichert Das BIOS bietet auch Methoden an mit deren Hilfe man auf diesen Puffer zugreifen kann ohne seine Struktur zu kennen Die oben entwickelte Implementierung des abstrakten Datentyps Puffer steht und f llt mit der Konsequenz mit der wir uns an das Gebot halten nicht direkt auf die Datenstruktur zuzugreifen Ein wirksamer Schutz w re es wenn man den direkten Zugriff einfach verbieten k nnte Man spricht dann vom Geheimnisprinzip Data hiding Man kann zwar in jeder Programmiersprache abstrakte Datentypen realisieren um das Geheimnisprinzip einhalten zu k nnen bedarf es aber einer Spracherweiterung 3 2 Abstrakte Datentypen in C Das Klassenkonzept Elementfunktionen C bietet eine elegante M glichkeit abstrakte Datentypen unter Wahrung des Geheimnisprinzips darzustellen Betrachten wir einfach einmal eine Darstellung unseres Puffers in C const int MAX 10 struct Puffer public boolean istLeer const boolean istVoll con
108. fglg memmove stAnfLg tEinfgLg s AnfLg EndLg Ende aufr cken memmove s tAnfLg Einfg s EinfgLg Einfg in L cke kopieren aktLg AnfLg EinfgLg EndLg void string setze char source int n strlen source if n gt maxlg n maxlg notfalls beschneiden memmove s source n aktLg n void string writeln s aktLg 0 cout lt lt s lt lt n main string s 21 t 20 s setze Einsturzgefahr t setze Computer ist cout lt lt n s writeln writeln insert t 4 writeln un un q Standard Konstruktoren und Destruktoren Wenn Sie eine Klasse ohne Konstruktor definieren erzeugt C automatisch einen Konstruktor ohne Argumente den Standard Konstruktor Dieser Standard Konstruktor tut einfach das was Sie von Pascal her gewohnt sind Den Datenelementen wird beim Eintritt des Programms in den G ltigkeitsbereich des Objekts der entsprechende Speicherplatz bereitgestellt Dabei werden die Daten nicht initialisiert sondern haben unvorhersagbare Anfangswerte Wenn Sie wollen da Objekte automatisch einen bestimmten Anfangswert bekommen k nnen Sie daf r einen eigenen Konstruktor definieren der die Elemente nach Wunsch initialisiert Wenn Sie keinen Destruktor definieren wird der Standard Destruktor verwendet der einfach nur die direkten Datenelemente beseitigt Sobald Sie aber irgendeinen Konstrukt
109. finieren Um die zweite Zuweisung zu erm glichen berladen wir den Operator f r die Zuweisung von int nach DateiPos Jetzt l uft die Zuweisung so ab Ali ist vom Typ DateiPos Dieser wird der Wert n zugewiesen Das hat die Wirkung da an der richtigen Stelle in der Datei der Wert von n geschrieben wird Die nun folgende Implementierung soll nur das Prinzip darstellen und verzichtet bewu t auf eine Fehlerbehandlung II III II III II III III III I II EVEKTOR CPP III III I II I II I II IV Auf Datei ausgelagerte gro e Vektoren Prinzip Version FF a A LALALALA AALALA ALAALA LILAI ILAA AAAI ILALA ALAALA LIAA ILA include lt stdio h gt include lt string h gt include lt iostream h gt include lt dir h gt MAXPATH define INT int zur einfachen Umstellung auf andere Typen I I Klassen DateiPos und Vektor I I fVektor definiert einen Vektor dessen Inhalt in einer Datei gehalten wird DateiPos dient dem Verweis auf eine Dateiposition a 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1111 class DateiPos public operator INT Typkonvertierung void operator INT i friend ostream amp operator lt lt ostream amp s DateiPos p protected friend class fVektor FILE Dateizeiger long Position
110. function max3 a b c real real float max3 float a float b var max real float c float max begin if a gt b then max a if a gt b max a else max b else max b if c gt max then max c if c gt max max cC max3 max return max end Beachten Sie bitte folgende Unterschiede in C Im Funktionskopf steht der Typ des Funktionswertes am Anfang daf r entf llt das Schl sselwort function In der Parameterliste mu zu jedem einzelnen Parameter der Datentyp angegeben werden und zwar vor dem Namen Bei einer leeren Parameterliste d rfen die runden Klammern nicht weggelassen werden Beispiel int ohneParameter Wenn Sie die Klammern vergessen ist das gef hrlich weil dann statt des Funktionswerts die Adresse der Funktion gemeint ist was nicht immer einen Syntaxfehler nach sich zieht Mehr dar ber erfahren Sie in einem eigenen Abschnitt Lokale Variablen k nnen an beliebiger Stelle innerhalb des Funktionsblocks deklariert werden Der Funktionswert wird mit der return Anweisung zur ckgegeben Damit wird gleichzeitig die Ausf hrung der Funktion abgebrochen Prozeduren werden wie Funktionen mit dem Ergebnistyp void behandelt In Pascal ist eine beliebige Verschachtelung von Prozeduren und Funktionen erlaubt eine Prozedur kann lokal zu einer anderen Prozedur sein Damit ist es m glich da f r eine Unterprozedur die lokalen Variablen der aufrufenden Prozedur global sind Die we
111. h wenn Sie in Pascal bisher die Verwendung von Zeigern gemieden haben in C k nnen Sie nicht erfolgreich programmieren ohne sich um das Zeigerkonzept zu k mmern Das liegt daran da es in C keine Arrays im Sinne von Pascal gibt Wir werden die Pascal Arrays sp ter mit Hilfe des Klassenkonzepts nachbilden Ein Zeiger Pointer ist zun chst einmal eine Speicheradresse Dazu tr gt er aber noch eine Typinformation Diese wird zum Zugriff auf das Objekt an der Zeigeradresse Dereferenzierung ben tigt So k nnen etwa ein char Zeiger und ein int Zeiger auf die gleiche Adresse aber auf verschiedene Objekte zeigen Zeiger werden ben tigt wenn w hrend der Laufzeit eines Programms dynamisch Speicherplatz vergeben wird so etwa zum Aufbau von B umen oder verketteten Listen Die folgende Gegen berstellung zeigt die Unterschiede in der Bezeichnung und Dereferenzierung von Zeigern Zeiger in Pascal Zeiger in C var p integer Int py new p p new int p l p 1 dispose p delete p Es folgt eine systematische Gegen berstellung Zeigertypen Pascal C Deklaration Typ Variable Dereferenzierung Variable Variable Speicherreservierung new Variable Variable new Typ Speicherfreigabe dispose Variable delete Variable Bei der Deklaration einer Zeigervariable in C kann man nat rlich statt int p auch int p schreiben um anzudeuten da die Vari
112. ich beim Entwurf von Klassen an folgende Faustregel halten Die Klassenelemente sind privat au er wenn sie wirklich von Benutzern der Klasse verwendet werden sollen Daraus folgt insbesondere da im Regelfall alle Datenelemente privat sein sollten Der Zugriff auf die Datenelemente soll nur ber spezielle Zugriffsmethoden m glich sein die vor allem unerlaubte Zuweisungen verhindern sollen Betrachten wir folgendes Klassenfragment class Pixel public void setze int x int y int getX const int getY const void plot int Farbe zeigt den Grafik Punkt private int px py FS Hier sind die Koordinaten des Punkts nicht direkt zug nglich sondern nur ber die Methoden setze getX und getY Daher k nnen wir in der Implementierung dieser Methoden daf r sorgen da ein Pixel immer innerhalb des Bildschirms liegt W ren die Koordinaten ffentlich m te die Funktion plot jedesmal auf korrekte Koordinaten pr fen Der Nachteil solcher Datenkapselung besteht darin da zus tzliche Zugriffsfunktionen zu schreiben sind Diese Funktionen sind meist so einfach da sie als inline deklariert werden sollten Dann erkauft man die zus tzliche Sicherheit nicht mit langsamerem Programmlauf Nat rlich mu man sich nicht sklavisch an diese Regeln halten Wenn klar ist da die Datenstrukturen sp ter nicht ver ndert werden und es keine verbotenen Werte gibt kann man nat rlich auch auf die Privatheit der Daten verz
113. icht verst ndliche Prototyp Version mit ausf hrlichen Erkl rungen Umfangreichere komfortable Versionen mit weiterer Dokumentation finden Sie auf der dem Buch beiliegenden Diskette Unter diesen Programmen befinden sich interessante Spiel und Simulationsprogramme aber auch praktisch einsetzbare Programme wie ein komfortables Zeichenprogramm f r Graphenstrukturen Dazu erhalten Sie ein komplettes Entwicklungspaket f r Programme unter einer komfortablen grafischen Benutzeroberfl che f r alle g ngigen Grafikkarten Was Sie in der Hand halten m te man daher eigentlich als Diskette mit beiliegendem Buch bezeichnen Alle Programmbeispiele in diesem Buch und auf der beiliegenden Diskette sind unter Borland C lauff hig Solange keine Programme f r Microsoft Windows entwickelt werden gibt es keine wesentlichen Unterschiede zwischen Borland C und Turbo C Alles was in diesem Buch ber Borland C gesagt wird gilt auch f r Turbo C F r Anwender von Zortech C enth lt die Diskette Hinweise zur Portierung Viele Programme so auch die grafische Benutzeroberfl che verwenden keine Borland spezifischen Funktionen und sind unver ndert auch unter Zortech C einsetzbar 1 Von Pascal nach C Man h rt oft die Meinung C sei eine schwierige Programmiersprache Da C eine Erweiterung von C ist jedes C Programm ist auch ein C Programm gilt dies umso mehr auch f r C Wenn Sie von Pascal nach C umsteigen wollen haben Sie vor
114. ichten So w re es sicher unkritisch wenn man in einer Klasse f r komplexe Zahlen den Real und Imagin rteil einer komplexen Zahl ffentlich deklarieren w rde Borland C h lt sich allerdings an die Regel und vereinbart die Elemente des Datentyps complex als private Implementierung der Elementfunktionen In der Klassendefinition sind die Methoden zwar deklariert aber nicht definiert Die Implementierung einer Klasse wird au erhalb der Klassendefinition nachgeholt Dabei wird vor jeden Funktionsnamen der Klassenname geschrieben getrennt durch zwei Doppelpunkte In den Funktionsdefinitionen kann direkt auf die Elemente zugegriffen werden auch und nur hier auf die privaten Elemente boolean Puffer istLeer const return Anfang Ende boolean Puffer istVoll const return Anfang Ende 1 MAX void Puffer leere Anfang Ende 0 void Puffer lege char c if istVoll return D Ende c if Ende gt MAX Ende 0 char Puffer entnimm if istLeer return 0 char z D Anfangt t if Anfang gt MAX Anfang 0 return zZ Ein vollst ndiges Beispiel Bitsets Wir wollen als zweites Beispiel ein vollst ndiges Programm betrachten und schrittweise die erweiterten M glichkeiten von C einf hren In Pascal kann man mit Hilfe des Operators set of Teilmengentypen eines Ordinaltyps definieren Betrachten Sie bitte folgendes Pascal Programm
115. igt Der hierf r beschriebene Datentyp wird alternativ als lineare Liste und als AVL Baum implementiert 3 3 Konstruktoren und Destruktoren Motivation Selbstdefinierte Klassen bringen uns dem Ziel mit eigenen Datentypen ebenso unkompliziert umgehen zu k nnen wie mit den Standard Datentypen einen gro en Schritt n her Bisher fehlen uns aber bei eigenen Datentypen noch ein paar M glichkeiten Ein Problem ist die dynamische Speicherplatzverwaltung Wenn Sie eine Variable definieren wird beim Eintritt des Programms in den G ltigkeitsbereich der Variablen Speicherplatz bereitgestellt und beim Verlassen des G ltigkeitsbereichs automatisch wieder freigegeben Das war bei unserer bitset Klasse kein Problem weil der ben tigte Speicher direkt als Datenelement deklariert wurde Bei Objekten deren Speicherbedarf nicht immer gleich ist mu man aber zus tzlichen Speicher anfordern und darf am Ende nicht vergessen diesen Speicher wieder freizugeben Das folgende Turbo Pascal Programm definiert zwei Strings und f hrt eine einfache Operation damit aus var s string 21 t string 20 begin S Einsturzgefahr t Computer ist writeln s writeln t insert t s 4 writeln s end Wir wollen jetzt versuchen eine Klasse zu definieren die die Turbo Pascal Strings nachbildet Ein String hat in Turbo Pascal eine Maximall nge die bei der Deklaration in eckigen Klammern angegeben wird Es w re Speicherplatzv
116. ildet Die Unterschiede liegen in der Abgrenzung dieser Operatoren In Pascal kann mit dem Zuweisungsoperator kein Ausdruck gebildet werden sondern die Zuweisung ist eine spezielle Anweisung In C dagegen nimmt der Zuweisungsoperator nicht diese Sonderstellung ein Das bedeutet Auch die Zuweisung ist in C ein Ausdruck und hat demnach einen Wert Der Wert einer Zuweisung ist der Wert des zugewiesenen Ausdrucks Zun chst gibt es alle von Pascal her bekannten Operatoren auch in C allerdings teilweise in recht exzentrischer Schreibweise Wenn Ihnen die Symbole f r einige Operatoren in C berhaupt nicht gefallen k nnen Sie f r eine Eingew hnungsphase bei den Pascal Bezeichnungen bleiben wenn Sie die folgenden Zeilen mit Pr prozessor Definitionen am Anfang Ihrer Programme einf gen define MOD define DIV define NOT define AND define OR define XOR gt mn N 0 gt a Arithmetische Operatoren Arithmetische Operatoren Pascal C Un r un res Plus F un res Minus u bin r Addition ae Subtraktion a Multiplikation 5 Ganzzahl Division div Gleitkomma Division oo Modulo Operator mod Logische boolesche Operatoren Logische Operatoren Pascal C un r Negation not bin r Und Verkn pfung and amp amp Oder Verkn
117. ile 46 In C ist das Hauptprogramm formal eine Funktion mit dem speziellen Namen main Zeile 47 Aus der repeat Schleife wird in C eine do Schleife mit zwei wichtigen Unterschieden Erstens darf nach dem do nur eine Anweisung stehen Zweitens pr ft C nicht wie Pascal eine Abbruchbedingung sondern das logische Gegenteil n mlich eine Fortsetzungsbedingung Zeile 48 49 cout steht f r die Standardausgabe Was rechts vom Operator lt lt steht wird dorthin ausgegeben Strings werden in C in echte Anf hrungszeichen eingeschlossen Ein Zeilenwechsel kann innerhalb eines Strings durch n dargestellt werden Es k nnen beliebig viele Objekte mit einer Anweisung ausgegeben werden Zum Beispiel kann die Anweisung write Pi 3 12459 durch cout lt lt Pi lt lt 3 14159 ersetzt werden Zeile 50 cin steht f r die Standardeingabe Die Eingabe wird der Variablen rechts vom Operator gt gt bergeben Die Wirkung ist nicht exakt die gleiche wie in der Pascal Version Zeile 57 Im Umgang mit Strings unterscheiden sich Pascal und C wesentlich Zur Pr fung auf Gleichheit ben tigen Sie die Bibliotheksfunktion strcmp Das Ergebnis ist Null genau dann wenn beide Strings gleich sind Die elegantere Pascal Schreibweise werden wir sp ter mit Hilfe des Klassenkonzepts nachbilden 1 2 Namen Namen Bezeichner f r benutzerdefinierte Objekte Variablen Konstanten Typen Funktionen werden fast wie in Turbo Pascal gebi
118. ilersteuerung mit dem Pr prozessor Wir haben schon in vielen Beispielen die Pr prozessor Direktiven include und define verwendet Hier finden Sie eine Zusammenstellung die auch weitere M glichkeiten des Pr prozessors umfa t Vor jedem Compilerlauf wird die Quelldatei mit dem Pr prozessor bearbeitet Dabei werden Kommentare ausgeblendet und Pr prozessor Direktiven ausgef hrt Der Compiler von Borland C umfa t den Pr prozessor und erzeugt keine Zwischendatei Es kann aber manchmal n tzlich sein die Wirkung des Pr prozessors zu sehen vor allem um unerkl rliche Fehler aufzusp ren Deshalb gibt es bei Borland C den Pr prozessor auch als eigenst ndiges Programm Pr prozessor Direktiven sind vom eigentlichen Programmtext durch das Zeichen am Zeilenanfang klar zu unterscheiden Im Gegensatz zur Syntax von C f r die Zeilenwechsel keine Bedeutung haben mu jede Compiler Direktive mit einem Zeilenwechsel abgeschlossen werden Einf gen von Dateien Eine Direktive der Form include Dateiname veranla t da diese Zeile durch den Inhalt der Datei Dateiname ersetzt wird Die Datei wird zun chst im aktuellen Verzeichnis gesucht anschlie end werden die voreingestellten Include Verzeichnisse nach der Datei durchsucht Wird der Dateiname statt in Anf hrungszeichen in spitze Klammern eingeschlossen werden nur die voreingestellten Include Verzeichnisse nach der Datei durchsucht include lt stdlib h gt im Incl
119. im folgenden Programm einen Syntaxfehler w hrend die beiden einfachen Zuweisungen korrekt sind include lt stddef h gt int pl long p2 NULL NULL p2 NULL O E T u Zeichenketten Strings Die Behandlung von Strings unterscheidet sich in C grunds tzlich von der in Turbo Pascal In Turbo Pascal beginnen Strings mit einem Byte das die aktuelle L ngenangabe enth lt Deshalb k nnen Strings nicht l nger als 255 Bytes werden In C sind Strings im Prinzip char Vektoren und d rfen beliebig lang werden Wenn Sie eine String Konstante definieren h ngt der Compiler automatisch ein zus tzliches Byte mit dem Wert Null an Alle Standardfunktionen zur String Behandlung halten sich ebenfalls an die Konvention da das Ende eines Strings durch ein Nullbyte angezeigt wird Wenn Sie beim Programmieren mit den String Funktionen von Turbo Pascal Fehler machen wie etwa im folgenden Programm sind die Auswirkungen gew hnlich ziemlich harmlos program StringFehler var sl s2 string 10 begin sl String s2 Verkettung sl concat sl s2 writeln sl end Die Verkettung von s1 und s2 ergibt String Verkettung Dies ist aber zu lang um der Variablen s komplett zugewiesen zu werden Deshalb geht der Rest verloren und am Bildschirm erscheint nur String Ver In C sind die Folgen solcher Fehler viel bedrohlicher Ein String ist ein Vektor und damit im Prinzip nur ein Zeiger auf den Anfang
120. ine variable Anzahl von Argumenten akzeptiert Nur der Typ der ersten Arguments wird gepr ft Das erste Argument ist der Format String Er kann beliebig viele Konvertierungs Anweisungen enthalten die jeweils mit einem Prozent Zeichen beginnen Zu jeder Konvertierungsanweisung im Format String mu anschlie end genau ein Argument des entsprechenden Typs folgen int puts const char str puts Abk rzung f r put string gibt den mit einem Nullbyte abgeschlossenen String auf stdout aus und macht einen Zeilenvorschub Dateizugriff In Standard Pascal werden Dateitypen mit Hilfe der Konstruktion file of lt Datentyp gt deklariert Damit ist eine sehr starre Form vorgegeben Die Datei mu in exakt gleich strukturierten Portionen abgearbeitet werden In der Praxis ist es aber oft sinnvoll Daten verschiedener Typen hintereinander zu speichern So kann etwa am Anfang einer Datei ein Vorspann stehen der eine Typinformation enth lt und anschlie end je nach Typ Daten unterschiedlicher Formate Dieser freien Form der Dateiverwaltung kommen in Turbo Pascal die untypisierten Dateien mit den Prozeduren BlockWrite und BlockRead entgegen Wenn Sie diese Prozeduren kennen werden Sie schnell mit den entsprechenden Bibliotheksfunktionen von C zurechtkommen Neben den typisierten Dateien gibt es in Pascal noch den vordefinierten Dateityp text f r Textdateien die in variabel lange Zeilen gegliedert sind In C gibt es keinen formalen
121. it Ausdruck Ausdruck amp bitweises Und Ausdruck amp Ausdruck bitweises exklusives Oder Ausdruck Ausdruck bitweises Oder Ausdruck Ausdruck amp amp logisches Und Ausdruck amp amp Ausdruck logisches Oder Ausdruck Ausdruck bedingter Ausdruck Ausdruck Ausdruck Ausdruck Zuweisung Lvalue Ausdruck Zuweisung mit Multiplikation Lvalue Ausdruck Zuweisung mit Division Lvalue Ausdruck o Zuweisung mit Rest Lvalue Ausdruck Zuweisung mit Addition Lvalue Ausdruck Zuweisung mit Subtraktion Lvalue Ausdruck lt lt Zuweisung mit Linksschieben Lvalue lt lt Ausdruck gt gt Zuweisung mit Rechtsschieben Lvalue gt gt Ausdruck amp Zuweisung mit bitweisem Und Lvalue amp Ausdruck Zuweisung mit bitweisem Oder Lvalue Ausdruck Zuweisung mit bitweisem exkl Oder Lvalue Ausdruck Sequenzoperator Ausdruck Ausdruck Literaturverzeichnis Gamm95 E Gamma R Helm R Johnson J Vlissides Design Patterns Elements of Reusable Object Oriented Software Addison Wesley Reading 1995 Kern88 B W Kernighan D M Ritchie The C Programming Language 2nd Ed Prentice Hall Englewood Cliffs N J 1988 Lipp89 S B Lippmann A C Primer Addison Wesley Reading 1989 Deutsche bersetzung C Einf hrung und Leitfaden Addison Wesley Bonn 1990 Louis96 D Louis C und C Programmierung und Referenz Markt und
122. ldet Dort mu ein Name mit einem Buchstaben keine Umlaute etc beginnen danach d rfen Buchstaben Ziffern und Unterstriche _ beliebig folgen In C darf ein Name auch mit einem Unterstrich beginnen Allerdings sind solche Namen f r die Sprachimplementierung reserviert und sollen nicht vom Programmierer definiert werden Die Anzahl der signifikanten Zeichen ist compilerabh ngig In C wird im Gegensatz zu Pascal zwischen Gro und Kleinbuchstaben unterschieden Die Schl sselw rter von C sind reserviert und d rfen nicht als Namen definiert werden Schl sselw rter von C asm auto bool break case catch char class const const_cast continue default delete do double dynamic_cast else enum explicit extern false float for friend goto if inline int long mutable namespace new operator private protected public register reinterpret_cast return short signed sizeof static static_cast struct switch template this throw true try typedef typeid typename union unsigned using virtual void volatile wchar_t while Die beiden kursiv gekennzeichneten Schl sselw rter werden in diesem Buch nicht behandelt auto ist ein Relikt aus fr heren Versionen asm weist darauf hin da die n chste Anweisung oder der n chste Block in Assembler formuliert ist und ist daher maschinenabh
123. lement gt dto mit Dereferenzierung Zeiger gt Element Vektorelement Zeiger int Ausdruck Funktionsaufruf Fkt Ausdr Parameterliste Typumwandlung Typ Ausdruck sizeof Gr esizeof Ausdruck sizeof Gr esizeof Typ Pr Inkrementierung Lvalue Post Inkrementierung Lvalue Pr Dekrementierung Lvalue Post Dekrementierung Lvalue bitweise Negation Ausdruck logische Negation Ausdruck un res Plus Ausdruck un res Minus Ausdruck amp Adre operator amp Lvalue Dereferenzierung Ausdruck new Speicherreservierung new Typ new Speicherreservierung new Typ int Ausdruck delete Speicherfreigabe delete Zeiger delete Speicherfreigabe delete L int Ausdruck Zeiger Typkonvertierung Cast Typ Ausdruck gt Auswahloperationen f r Zeiger in diesem Buch nicht behandelt Multiplikation Ausdruck Ausdruck Division Ausdruck Ausdruck Rest Modulo Ausdruck Ausdruck x ao Addition Ausdruck Ausdruck Subtraktion Ausdruck Ausdruck lt lt bitweises Linksschieben Ausdruck lt lt Ausdruck gt gt bitweises Rechtsschieben Ausdruck gt gt Ausdruck lt kleiner als Ausdruck lt Ausdruck gt gr er als Ausdruck gt Ausdruck lt kleiner als oder gleich Ausdruck lt Ausdruck gt gr er als oder gleich Ausdruck gt Ausdruck Gleichheit Ausdruck Ausdruck Ungleichhe
124. lt lt i void bitset excl int i bits amp 1 lt lt i boolean bitset enthaelt int i return bits amp 1 lt lt i gt 0 void bitset vereinige bitset s bits s bits void bitset schneide bitset s bits amp s bits void bitset komplementiere bits bits void bitset zeige cout lt lt for int i 0 i lt INT_BITS itt cout lt lt enthaelt i 2 M cout lt lt n Test der Klasse bitset I II I I I I II main bitset a b c a loesche b loesche for int i 0 i lt 8 i t a incl i for i 4 i lt 12 i b incl i cout lt lt a a zeige cout lt lt b b zeige c a c vereinige b cout lt lt Vereinigung von a und b c zeige c a c schneide b cout lt lt Durchschnitt von a und b c zeige c komplementiere cout lt lt Komplement davon c zeige Wenn nun der private Teil der Klasse bitset hier nur die Variable bits ge ndert und die Implementierung entsprechend angepa t wird kann die Anwendung der Klasse hier die Funktion main v llig unver ndert weiterverwendet werden Ein realistischeres Beispiel f r diese Trennung zwischen abstrakter Beschreibung und konkreter Implementierung eines Datentyps finden Sie im Projektteil dieses Buchs Abschnitt 4 6 Hier wird f r einen Funktionsinterpreter eine Symboltabelle ben t
125. lten in eine Abfrage der Form if else if umgesetzt werden Bei einer gr eren Anzahl von weit gestreuten Konstanten bieten sich dagegen Hash Verfahren oder bin re Suche an Mit der optimalen Umsetzung in allen F llen d rften die meisten Compiler wohl berfordert sein Eine Anweisung wie etwa switch Preis case 99 Anweisungl break case 199 Anweisung2 break case 299 Anweisung3 break case 9999 Anweisung99 break default Anweisung break l uft unter Borland C um ein vielfaches langsamer als die quivalente Form if Preis 100 99 switch Preis 100 case 0 Anweisungl break case 1 Anweisung2 break case 2 Anweisung3 break case 99 Anweisung99 break default Anweisung0 break else Anweisung0 bungsaufgabe 1 Machen Sie sich die Wirkung des folgenden Programmst cks klar und ersetzen Sie es durch eine einfache Anweisung if a gt 0 amp amp a lt 4 b 1 switch case 4 case 3 case 2 a o 0 Sprunganweisungen Bei der while Anweisung wird die Fortsetzungsbedingung am Anfang abgefragt bei der do Schleife am Ende Im Prinzip w rde eine der beiden Konstuktionen ausreichen So l t sich etwa die allgemeine while Anweisung while Bedingung do Anweisung ersetzen durch if Bedingung do Anweisung while Bedingung Trotzdem empfinden Sie es sicher als angenehm da Sie in beiden F llen die ma geschneiderte Schleifensteuer
126. m Jetzt kann der Compiler die passende Funktion an Hand der Anzahl der aktuellen Parameter ausw hlen Beachten Sie da alle Varianten von berladenen Funktionen sich eindeutig an Hand der Anzahl oder Typen der Parameterliste unterscheiden m ssen Eine Unterscheidung allein im Typ des Funktionswerts ist nicht erlaubt berladen von Funktionen ist immer dann sinnvoll wenn mehrere Funktionen etwas bedeutungsgleiches mit verschiedenen Datentypen tun etwa sie auf dem Bildschirm darstellen Vorgabe Argumente Beim Entwurf von Funktionen steht man oft vor der Wahl ob die Funktion unkompliziert in der Anwendung oder universell verwendbar sein soll Betrachten wir als Beispiel die Funktion die Borland C zum Zeichnen von Ellipsen bietet void ellipse int x int y int stangle int endangle int xradius int yradius Die ersten beiden Parameter geben den Mittelpunkt der Ellipse an die letzen beiden Parameter die beiden Halbachsen Die Parameter stangle und endangle erlauben einen Teil der Ellipse zu zeichnen Sie geben den Anfangs und Endwinkel in Altgrad an F r den Normalfall einer vollst ndige Ellipse m ssen hier stets die Werte O und 360 eingesetzt werden Die Funktion w re leichter zu merken wenn man diese beiden Werte weglassen k nnte Deshalb ist es in C erlaubt bei der Deklaration einer Funktion Argumenten Vorgabewerte zu geben die automatisch verwendet werden wenn die Argumente weggelassen werden Damit
127. n da es sich beide Male um den gleichen Vorgang handelt Der Compiler sucht dann jeweils an Hand der Anzahl und der Typen der aktuellen Parameter die passende Version In der Standard Funktionsbibliothek von C finden Sie brigens die beiden Funktionen unter den Namen abs und fabs und zus tzlich noch die Variante Labs f r Argumente vom Typ long Das liegt daran da in C das berladen von Funktionen noch nicht erlaubt war Sie werden vielleicht einwenden da es berladene Funktionen auch in Pascal gibt denn die Pascal Funktion abs ist auf Argumente beliebiger Zahltypen anwendbar Das ist zwar richtig aber gerade hier zeigt sich ein Schwachpunkt von Pascal Die Sprache benutzt Mittel deren Verwendung dem Anwendungsprogrammierer verwehrt ist G be es die Funktion abs nicht als Standardfunktion in Pascal k nnte man sie in Pascal nicht implementieren Ebenso verh lt es sich mit der Pascal Prozedur write Sie ist auf alle Standard Datentypen anwendbar nicht jedoch auf neu definierte Typen So ergibt sich eine Zwei Klassen Sprache in der den neu definierten Typen weniger M glichkeiten offenstehen als den etablierten Typen Als weiteres Beispiel nehmen wir an da Sie fter das Maximum von zwei oder drei Ganzzahlen bestimmen m ssen Sie k nnten dann schreiben int max int a int b if a gt b return a else return b int max int a int b int c int m if a gt b m a else m b if c gt m m cC return
128. n integer begin i 1 offen 0 while i lt Length s and offen gt 0 do begin if s i then offen offen 1 else if s i then offen offen 1 AREE a NE 15 end korrekt offen 0 end procedure bearbeite var s Zeile verwandelt alle Buchstaben in Gro buchstaben var i integer begin for i 1 to Length s do case s i of rate ns ee VAR SELL KON Kell ee tdr else s i UpCase s i end end begin repeat writeln write Ausdruck readln s bearbeite s if korrekt s then write richtig else write falsch writeln s until s ENDE end int korrekt Zeile s pr ft eine Zeichenkett auf korrekte Klammerstruktur int i offen i 0 offen 0 while i lt strlen s amp amp offen gt 0 TE STIN gt offen offen 1 else if s i offen offen 1 ve 1 return offen 0 void bearbeite Zeile s verwandelt alle Buchstaben in Gro buchstaben LDE 1 for i 0 i lt strlen s i i l switch s i case s i break case s i break case s i break default s i toupper s i main do cout lt lt nAusdruck cin gt gt Ss bearbeite s if korrekt s cout lt lt richtig else cout lt lt falsch cout lt lt s lt lt n while strcmp s
129. n of array O n 1 of array 0 n 1 of integer B array D n of array O n 1 of integer C array 0 n of ArrayOf_ Int D ArrayOf ArrayOf_ Int E array OD n of PointerTo_ Int F ArrayOf_PointerTo_ Int G PointerTo ArrayOf_ Int H PointerTo PointerTo_Int begin end C Programm const int n 10 int a 2b n tom Ad lo e n n n n n g n n hIn In main Typbezeichnungen Von Pascal kennen Sie die M glichkeit eigene Typen zu definieren Dabei ist zu beachten da jede Typdefinition einen eigenen Typ definiert Betrachten wir ein Beispiel type typl integer typ2 integer var a b typl ce typ2 d integer a b korrekt a und b vom gleichen Typ a c Type mismatch a d Type mismatch Sie sehen da zwei Typen auch dann inkompatibel sind wenn sie identisch definiert sind In C ist die Situation etwas verworren Vergegenw rtigen Sie sich bitte da es in C zwei unterschiedliche Methoden zur Bildung abgeleiteter Datentypen gibt Zum einen gibt es die Operatoren und zur Bildung von Zeiger Vektor und Funktionstypen zum anderen die Schl sselw rter struct und union zur Bildung von Strukturen und Varianten Zwischen diesen beiden Gruppen besteht auch ein wesentlicher formaler Unterschied Mit den Operatoren werden namenlose Typen gebildet w hrend die beiden Schl sselw rter neue Typen im Sinne
130. n stehen verteilt sich der Operator das Zeichen steht zwischen den Operanden das Zeichen steht hinter dem zweiten Operanden Wenn Sie den Operator sowohl in Ausdr cken wie a b i als auch in Ausdr cken wie b i a anwenden wollen mu die Operatorfunktion eine Referenz zur ckgeben b i mu ein L Wert sein Im folgenden Abschnitt finden Sie hierzu ein Beispiel in dem gro e Vektoren auf eine tempor re Datei ausgelagert werden Der Unterschied zwischen Zuweisung und Initialisierung Es ist wichtig da Sie sich den Unterschied zwischen Zuweisungen und Initialisierungen klarmachen Bei der Zuweisung bekommt ein schon initialisiertes Objekt einen neuen Wert bei der Initialisierung wird ein neues Objekt mit Hilfe des Kopier Konstruktors erst erzeugt Bei den Standard Datentypen ist der Unterschied unerheblich int i 1 i wird mit 1 initialisiert int j j wird nicht initialisiert unbestimmter Wert TES 2 jetzt bekommt j den Wert 2 Ganz anders sieht es aber oft bei Klassentypen aus Betrachten wir nochmals die string Klasse Das Problem der Initialisierung durch einen anderen String haben wir mit Hilfe des Kopier Konstruktors gel st F r den neuen String wird Speicherplatz bereitgestellt und der Inhalt des anderen Strings kopiert Bei einer Zuweisung eines Strings an einen anderen haben beide schon ihren eigenen Speicher Jetzt sollte nur der Inhalt kopiert werden In der bisherigen Form der String Klas
131. n den um eins erh hten Wert ihres Vorg ngers das Erste Element den Wert Null In der Praxis sollten Sie nur Werte in einer Aufz hlung zusammenfassen die auch irgendwie logisch zusammengeh ren Neben den enum Typen lassen sich auch unbenannte Aufz hlungen definieren indem man einfach den Namen wegl t enum SCHWARZ WEISS Unbenannte Aufz hlungen definieren keinen eigenen Typ sondern stellen eine Sammlung von int Konstanten bereit Sie k nnen so zum Beispiel die von Pascal gewohnten Wahrheitswertkonstanten definieren enum false true Naheliegend w re auch die folgende Definition des Datentyps boolean enum boolean false true Da aber die logischen Operatoren in C int Werte liefern bekommt man so Vertr glichkeitsprobleme Man sollte also die unbenannte Aufz hlung zusammen mit der Definition typedef int boolean verwenden Das folgende Beispiel zeigt nochmals den Umgang mit Aufz hlungstypen enum FARBE ROT GRUEN benannt num eigener Typ enum SPRACHE C PASCAL dto enum false true unbenannte enum ist int typedef int boolean int main FARBE fa SPRACHE s boolean b f s nicht erlaubt in Borland C nur Warnung f b nicht erlaubt in Borland C nur Warnung f true nicht erlaubt in Borland C nur Warnung pf erlaubt b false erlaubt Bitfelder In der systemnahen Programmierung gibt es oft
132. n ist compilerabh ngig In der folgenden bersicht ist jeweils die Gr e in Bits f r Windows 3 1 Windows 95 aufgef hrt Standard Datentypen Turbo Pascal C Bits Gleitkommatypen real 48 Extended long double 80 Double double 64 Single float 32 Ganzzahltypen unsigned long 32 LongInt long 32 Word unsigned 16 32 integer int 16 32 Word unsigned short 16 integer short 16 Byte unsigned char 8 ShortInt char 8 Den Datentyp boolean gibt es in C nicht Stattdessen gilt die Konvention da die Zahl Null f r den Wahrheitswert false steht alle brigen Zahlen f r den Wahrheitswert true In den MS DOS Implementierungen stimmt der Datentyp short mit int berein und ist daher berfl ssig 1 5 Konstanten Die folgende Gegen berstellung gibt Ihnen einen berblick ber die Darstellung von Konstanten in C Turbo Pascal C Dezimal 122 192 Sedezimal Hexadezimal 7A 0x7A Oktal sna 0172 Gleitkommazahl 3 14 3 14 1 4E 10 1 4E 10 Zeichen KZA tz Strings Zeichenketten Beispiel Beispiel Wie Sie sehen unterscheidet sich die Darstellung nur bei Sedezimalzahlen und bei Strings Sedezimale Konstanten werden mit den 16 Ziffern 0123456789ABCDEF gebildet und mit 0x eingeleitet Dabei k nnen die Buchsta
133. ngung in runde Klammern eingeschlossen werden Die logische Und Verkn pfung wird in C durch amp amp ausgedr ckt Die Klammerung der beiden Teilaussagen kann in C entfallen weil es dort differenziertere Vorrangregeln gibt Zeile 22 Die if Anweisung verh lt sich wie die while Anweisung Hier entf llt das Schl sselwort then Die Bedingung mu ebenfalls in runde Klammern eingeschlossen werden F r die Gleichheitsrelation wird in C ein doppeltes Gleichheitszeichen verwendet Zeilen 23 24 In Pascal darf vor else kein Semikolon stehen in C mu es stehen Das liegt daran da in C jede Anweisung mit einem Semikolon endet in Pascal dagegen das Semikolon nur zwischen zwei Anweisungen steht Vor dem else endet zwar eine Anweisung mit dem else beginnt aber keine neue Anweisung sondern nur der else Zweig der umfassenden Anweisung Zeile 28 Der Funktionswert wird in C mit der return Anweisung wie in Modula 2 zur ckgegeben Zeile 31 C macht keinen Unterschied zwischen Funktionen und Prozeduren Eine Prozedur ist formal eine Funktion mit leerem Wertebereich void Zeile 37 Die or Anweisung hat in C eine wesentlich flexiblere aber auch schwerer lesbare Struktur der Form for Anfangsaktion Fortsetzungsbedingung Inkrementierungsaktion Anweisung Zeilen 38 43 Auch die case Anweisung sieht in C etwas anders aus Statt case steht in C switch das Wort case wird in C den einzelnen Selektoren vorangestellt Ze
134. nigen sinnvollen Anwendungsf lle hierf r k nnen meist mit Hilfe des Klassenkonzepts von C besser dargestellt werden C verzichtet auf ein hierarchisches Prozedurkonzept Es wird nicht einmal ein formaler Unterschied zwischen dem Hauptprogramm und den Prozeduren gemacht Das Hauptprogramm ist in C einfach eine spezielle Funktion mit dem reservierten Namen main Die Reihenfolge der Prozeduren ist in Pascal mit R cksicht auf Einschritt Compiler eingeschr nkt eine aufgerufene Funktion mu im Programmtext vor der aufrufenden Funktion erscheinen Wenn dies nicht m glich ist wie etwa bei zwei sich wechselseitig aufrufenden Prozeduren mu vor dem Aufruf eine forward Deklaration stehen Dies ist in C nicht anders Wenn eine Funktion aufgerufen wird mu sie in der gleichen Datei vorher deklariert sein Wenn Sie sich von den Anordnungszw ngen frei machen wollen k nnen Sie einfach Deklarationen f r alle verwendeten Funktionen im C Jargon Prototypen an den Anfang des Programms setzen In Pascal d rfen nur einfache Typen als Funktionswert zur ckgegeben werden Dies ist ein ernsthafter Versto gegen das Typvollst ndigkeitsprinzip So ist es mit der naheliegenden Definition type komplex record x y real end nicht m glich Funktionen wie etwa function komplexeSumme zl z2 komplex komplex zu schreiben Dieses Manko umgeht man in der Regel durch eine Prozedur mit einem zus tzlichen Referenzparameter f r den Funktio
135. nktion schreiben die die Multiplikation ohne unn tige Kopien erreicht Das w rde dann vielleicht so aussehen addiere A B C Es gibt doch eine M glichkeit die Eleganz mit der Effizienz zu paaren allerdings mit einigen formalen Verrenkungen Der Schl ssel zur L sung liegt darin da wir die eigentlichen und speicheraufwendigen Daten vom Objekt trennen Wir zerlegen den String in ein Objekt vom Typ string und ein Objekt vom Typ stringDaten Ein string enth lt jetzt nur noch einen Zeiger auf seine stringDaten So ist es m glich da mehrere gleiche string Objekte auf die gleichen stringDaten zeigen Bei dieser L sung m ssen wir nur folgendes beachten Bei einer Zuweisung an einen string mu gepr ft werden ob er seine stringDaten mit anderen string Objekten teilt Hierf r bekommt die Klasse stringDaten ein zus tzliches Element Referenzen das z hlt wieviele string Objekte derzeit auf ein stringDaten Objekt zeigen Ist er der einzige Referenzen 1 ruft er den Destruktor seiner stringDaten auf und h ngt sich an die stringDaten des zugewiesenen Strings Ist Referenzen gt 1 wird der Z hler nur um eins vermindert Der Destruktor eines Strings vermindert den Referenzenz hler seiner stringDaten um eins und ruft den Destruktor der stringDaten nur dann auf wenn der Referenzenz hler Null erreicht hat Implementierung der Klassen stringInfo und string In der Implementierung des Operato
136. nswert In C gibt es diese Einschr nkung nicht Jeder Typ kann als Funktionswert verwendet werden Referenzen Betrachten wir zun chst das einfache Problem zwei Variablen mit Hilfe einer Prozedur zu vertauschen Ein typischer Anf ngerfehler w re es dies in Pascal so zu formulieren procedure tausche a b integer ohne Wirkung var h integer begin h a b end ar b h Warum ist diese Prozedur wirkungslos Pascal kennt zwei Arten der Parameter bergabe an Prozeduren Im Normalfall wird der Wert des aktuellen Parameters an den formalen Parameter bergeben Wertparameter Die Prozedur kann nun den formalen Parameter ver ndern ohne da sich dies auf den aktuellen Parameter auswirkt In unserem Beispiel sollen aber die bergebenen Variablen duch die Prozedur ver ndert werden In diesem Fall mu man Referenzparameter Variablenparameter verwenden Dann arbeitet die Prozedur nicht mit einer Kopie der formalen Variablen sondern mit diesen selbst Dies wird in Pascal durch Voranstellen des Schl sselworts var ausgedr ckt procedure tausche var a b integer korrekte Version var h integer begin N 2 a s p7 loe aie end G be es keine Referenzparameter in Pascal so k nnte man das Problem auf folgende Weise angehen type IntPtr integer procedure tausche a b IntPtr var h integer begin Ha as 3b DA z h end Hier wurden nicht die Werte der Variablen sondern ihre Adressen
137. ntlichen Unterschied In Pascal wird mit der record Konstruktion ein namenloser Datentyp gebildet Dieser kann entweder direkt einer Variablen zugeordnet oder zur Deklaration eines Typnamens verwendet werden In dieser Weise mehrfach definierte Typen sind nicht kompatibel In C wird mit der struct Konstruktion ein neuer Datentyp deklariert der im Rest der bersetzungseinheit G ltigkeit hat Daher entfallen die Inkompatibilit tsprobleme Gleichzeitig mit der Struktur Deklaration k nnen auch Variablen dieses Typs definiert werden Werden mit der Typdefinition keine Variablen definiert mu trotzdem nach der schlie enden geschweiften Klammer ein Semikolon stehen Es folgt ein vergleichendes Beispiel type komplex record x y real end var a komplex struct komplex float x y a b c record x y real end d record x y real end komplex b begin a b Type mismatch main O a b b d Type mismatch end Strukturen sind in C Spezialf lle der Klassen auf denen die objektorientierte Programmierung aufbaut Varianten Unions Ein Sprachmittel von Pascal das in der Praxis meist zweckentfremdet eingesetzt wird ist der variante Record Er ist daf r vorgesehen da am Ende eines Records abh ngig vom Inhalt einer Selektor Komponente verschiedenartige Daten am gleichen Platz gespeichert werden k nnen um somit Speicherplatz zu sparen Diese Konstruktion ist insofern etwas problematisch als damit die T
138. och nicht definiert ist wird eine vorherige Deklaration der zweiten Klasse ben tigt wie das folgende konstruierte Beispiel zeigt class LONG Deklaration der Klasse LONG class INT public void addiere LONG 1 private friend class LONG int n F3 class LONG Definition der Klasse LONG public void addiere INT i private friend class INT long n 1 void INT addiere LONG 1 n int 1 n void LONG addiere INT i n long i n 3 5 berladen von Operatoren Sie wissen bereits da in C Funktionen berladen werden d rfen Da Operatoren nur eine andere Schreibweise f r Funktionen sind ist es naheliegend auch das berladen von Operatoren zu erlauben Der Compiler kommt ja ohnehin schon mit den vordefinierten arithmetischen Operatoren zurecht die je nach Datentyp v llig verschiedene Funktionen aufrufen Deklaration berladener Operatoren C erlaubt das berladen von Operatoren allerdings mit zwei Einschr nkungen Es d rfen nur die in der Sprache schon vorhandenen Operatoren bis auf wenige Ausnahmen berladen werden Mindestens ein Argument des Operators mu ein Klassentyp sein Bei der Deklaration berladener Operatoren wird der Operator formal wie eine gew hnliche Funktion dargestellt indem ihm das Schl sselwort operator vorangestellt wird Wenn Sie etwa eine Klasse zahl z B f r gro e Zahlen definieren k nnen Sie die Summenfunktion f r diesen Typ so deklarieren
139. oid Kreis zeige circle x y Radius void Kreis loesche setcolor BLACK circle x y Radius setcolor WHITE void Kreis bewege int dx int dy loesche x dx y dy zeige IIIIIIIIII III II IIIIIIIII III III 1 1 Implementierung der Klasse Rechteck Rechteck Rechteck int x0 int y0 int x1 int yl x x0 y 0 a x1 x0 b yl y0 void Rechteck zeige rectangle x y Xta ytb Punkt x0 y0 void Rechteck loesche setcolor BLACK rectangle x y Xta ytb setcolor WHITE void Rechteck bewege int dx int dy loesche x dx y dy zeige I I I I Test der Klassen I I I I IIIIII II int main char c int graphdriver DETECT graphmode initgraph amp graphdriver amp graphmode borlandce bgi outtextxy 10 8 Figur mit Cursortasten bewegen outtextxy 10 24 Figur wechseln R Jechteck K reis outtextxy 10 40 Ende Esc Kreis K getmaxx 2 getmaxy 2 40 Rechteck R 0 0 80 60 char aktuelleFigur K K zeige do c getch auf Tastendruck warten if c 0 normale Zeichentaste andere Figur switch aktuelleFigur case K K loesche break case R R loesche break switch toupper c
140. ommandozeilenversion des Compilers verwenden Innerhalb der integrierten Oberfl che von C k nnen Sie die eingebaute automatische Projektverwaltung verwenden Sie erkl rt sich fast selbst Sie brauchen nur in einem Dialog die Programmdateien anzugeben aus denen Ihr Projekt besteht Die Abh ngigkeit von den darin importierten Header Dateien findet die Projektverwaltung selbst heraus 2 5 Bibliotheken Wenn Sie Programmdateien geschrieben haben die Sie immer wieder in verschiedenen Projekten ben tigen und die soweit ausgereift sind da sie nicht mehr st ndig ge ndert werden m ssen gibt es einen bequemeren Weg als die Dateien mit Hilfe der Projektverwaltung einzubinden Sie k nnen mehrere Objekt Dateien mit Hilfe des Bibliotheksverwaltungsprogramms bei Borland C hei t es TLIB EXE in eine Bibliothek zusammenfassen Entweder erzeugen Sie eine neue Bibliothek oder f gen die Dateien in die Standard Bibliothek ein Die Bedienung von TLIB ist im Benutzerhandbuch von Borland C bei Turbo C in einer mitgelieferten Datei genau beschrieben Falls Sie daran interessiert sind Programme zu erzeugen die bescheiden mit dem Speicherplatz umgehen sollten Sie folgendes beachten W hrend Turbo Pascal beim Binden optimiert und nur die Prozeduren einbindet die auch wirklich verwendet werden werden bei C immer komplette Objekt Dateien eingebunden Deshalb kann es sich auszahlen wenn Sie anstelle einer gro en Objektdatei eine Bibliothek mi
141. on a und b zeige C komplementiere c cout lt lt Komplement davon zeige C Wir haben auf die Variablen vom Typ bitset hier diszipliniert zugegriffen Das Geheimnisprinzip ist allerdings nicht verwirklicht bitset ist als unsigned deklariert und kann beliebig manipuliert werden Nun sehen Sie das gleiche Programm noch einmal mit einer Klasse in der die Daten vor direktem Zugriff verborgen sind IIIIIIII III II III III III III II III III III III III II III III II III III II III IV ef BITSET2 CPP Verwendung von Klassen a LAAL AAA NAALALA S ALALLAAN AALALA LLALLA IA include lt iostream h gt defin INT_BITS 16 ifndef BOOLEAN Definition des Datentyps boolean define BOOLEAN enum false true typedef int boolean ndif Definition der Klasse bitset 1 1 1 1 11 111 class bitset public void loesche void incl int i Element einf gen void excl int i Element entfernen void vereinige bitset s Mengenvereinigung mit s bilden void schneide bitset s Mengendurchschnitt mit s bilden void komplementiere Mengenkomplement bilden boolean enthaelt int i ist i Element void zeige private unsigned bits p3 Implementierung der Klasse bitset void bitset loesche bits 0 void bitset incl int i bits 1
142. or definieren ist der Standard Konstruktor nicht mehr verf gbar Kopier Konstruktoren Noch ein zweiter Typ von Konstruktoren wird vom Compiler automatisch erzeugt wenn Sie ihn nicht explizit definieren n mlich der Kopier Konstruktor Der Kopier Konstruktor dient der Initialisierung eines Objekts mit dem Wert eines anderen Objekts der gleichen Klasse Wenn Definitionen wie A a int a int b m glich sind warum sollte man dann nicht auch string s 20 string t s schreiben d rfen Sie d rfen es nur ist die Wirkung nicht so wie sie sein sollte Da wir in der string Klasse keinen Kopier Konstruktor definiert haben wird hier der Standard Kopier Konstruktor verwendet Dieser erzeugt eine Kopie aller Datenelemente Das bedeutet aber da auch der Zeiger s s nach t s kopiert wird Damit teilen sich die Strings s und t den gleichen Speicherplatz Das hat recht unangenehme Folgen Wenn ein String ge ndert wird wird der Inhalt des anderen mitge ndert die L nge akt Lg aber nicht Au erdem wird sp ter beim Aufruf der Destruktoren versucht den gleichen Speicherplatz zweimal freizugeben Hier m ssen wir also einen Kopier Konstruktor definieren Ist x eine Klasse so hat der Kopier Konstruktor die Form x const X amp Wir erg nzen also in der Klassendefinition die Zeile string const string amp t Wie sieht nun die Implementierung aus H tten wir keinen Kopier Konstruktor definiert w rde automatisch einer erzeug
143. ort then Die folgenden beiden Zeilen IF a lt 0 THEN b IF a lt 0 THEN b 0 05 ELSE b 3 14 w rden expandiert zu den korrekten C Anweisungen lse b 1 Beachten Sie das Semikolon vor dem else Da in C jede Anweisung mit einem Semikolon endet mu auch hier eines stehen In Pascal w re dies ein Fehler Gemeinsam ist beiden Sprachen da nach dem then und dem else jeweils nur eine Anweisung stehen darf Mehrere Anweisungen m ssen zu einer Verbundanweisung gemacht werden if x lt y Z X x y y 27 EX Ze x y end y then begin X yi Zi I I A In der Sprachdefinition von C wird wie in Pascal festgelegt da in syntaktisch mehrdeutigen Anweisungen wie der folgenden if Ausdruck if Ausdruck Anweisung else Anweisung jedes else dem letztm glichen if zugeordnet wird Da es in C keinen Datentyp boolean gibt darf f r den Bedingungsausdruck ein beliebiger arithmetischer Ausdruck oder ein Ausdruck eines Zeigertyps stehen Die Bedingung ist erf llt wenn der Ausdruck von Null verschieden ist Die while Anweisung while Ausdruck do Anweisung while Ausdruck Anweisung Auch die while Anweisung ist strukturgleich mit Pascal Sie k nnte mit folgenden Pr prozessor Anweisungen bersetzt werden define WHILE while define DO Wie bei der if Anweisung wird in C auch hier die Bedingung in runde Klammern gesetzt Daf r entf llt das Schl sselwort do
144. perator Der Bedingungsoperator hat eine etwas ungew hnliche Syntax Er ist der einzige dreistellige Operator in C Er erlaubt es den Wert eines Ausdrucks von einer Bedingung abh ngig zu machen ohne eine if Anweisung zu verwenden Die Syntax lautet logischerAusdruck Ausdruck1 Ausdruck2 Der Wert eines solchen bedingten Ausdrucks ist der Wert von Ausdruck1 bzw Ausdruck2 je nachdem ob der logische Ausdruck wahr oder falsch ist Es folgen einige Beispiele ohne Bedingungsoperator mit Bedingungsoperator if a lt b A i j x else A i j y A li j a lt b x y if x lt y return x return lt 8 f else return y x y 5 Y Der Komma Operator Dieser Operator wird hier nur der Vollst ndigkeit halber erw hnt Er ist ein hervorragendes Mittel Programme unlesbar zu machen Sie sollten ihn nur in Ihren passiven Sprachschatz aufnehmen Zwei Ausdr cke k nnen durch ein Komma dazwischen zu einem Ausdruck verschmolzen werden Ausdruck1 Ausdruck2 Bei der Auswertung werden der Reihe nach beide Ausdr cke ausgewertet Der Wert des Gesamtausdrucks ist der Wert des zweiten Ausdrucks Einige abschreckende Beispiele zeigen die M glichkeiten mit dem Komma Operator Verwirrung zu schaffen i x gt 0 it j t k t k wird immer erh ht i und j falls x gt 0 x sin 3 14159 Fehler sin erwartet nur ein Argument x sin 3 14159 sin 14159 wird berechnet x sin Pi 3 14159 Pi
145. perator angewendet So steht etwa p f r p oder ali f r ali oder x y zf rx y z Alle brigen bin ren Operatoren sind inksassoziativ a y z bedeutet also x y z 1 7 Anweisungen Im letzten Abschnitt haben Sie bereits erfahren da Zuweisungen in C keine Anweisungen sondern Ausdr cke sind Jeder Ausdruck wird aber zu einer Anweisung wenn man ein Semikolon anh ngt Es folgen ein paar Beispiele Anweisungen Ausdr cke 2 g a b 1l ee atty a kons a 3 amp E Nicht jede Anweisung ist wirklich sinnvoll So berechnet die dritte Beipiel Anweisung die Summe a 3 ohne da dies irgendwelche Konsequenzen h tte Der Wert von a bleibt unver ndert Beachten Sie auch da in C das abschlie ende Semikolon Bestandteil der Anweisung ist w hrend in Pascal das Semikolon nicht zu einer Anweisung geh rt sondern als Trenner in Verbundanweisungen dient Dieser feine Unterschied ist wichtig Wir gehen nun im einzelnen auf die verschiedenen Anweisungsformen ein Dabei l t es sich nicht ganz vermeiden da wir in einigen Beispielen schon auf sp ter erkl rte Sprachmittel zur ckgreifen Die leere Anweisung Die eere Anweisung besteht lediglich aus einem Semikolon Sie wird zum Beispiel ben tigt wenn mit einer while Anweisung unt tig auf das Eintreffen eines Ereignisses wie etwa eines Tastendrucks gewartet wird whil keineTasteGedrueckt Diese Anweisung entlockt dem Zortech Compiler eine
146. pfung or exklusives Oder xor AR Wie schon erw hnt gibt es in C keinen speziellen Typ boolean f r Wahrheitswerte Die logischen Operatoren erwarten Argumente vom Typ int Hat ein Argument den Wert Null wird es als falsch interpretiert sonst als wahr Die logischen Operatoren geben f r den Wahrheitswert true immer die Zahl 1 zur ck In Turbo Pascal kann der Compiler so eingestellt werden da er logische Ausdr cke nur soweit wie n tig auswertet Hat der Ausdruck links von einem Und Operator den Wert false so steht bereits fest da der Operator den Wert false zur ckliefert Deshalb braucht die rechte Seite nicht mehr untersucht zu werden Das entsprechende gilt wenn auf der linken Seite eines Oder Operators ein wahrer Ausdruck steht In C ist dieses optimierte Auswerten von logischen Ausdr cken in der Sprachdefinition vorgeschrieben Sie k nnen sich also darauf verlassen da etwa die Anweisung if q gt 0 amp amp p q 2 r keine Division durch Null ausf hrt Die merkw rdigen Doppelsymbole f r die logischen Operatoren geh ren mit Sicherheit nicht zu den sthetischen Glanzlichtern von C Wie Sie sogleich sehen werden gibt es auch die entsprechenden einfachen Symbole allerdings in anderer Bedeutung Operatoren zur Bitmanipulation von Ganzzahltypen Diese Operatoren sollten nur in begr ndeten F llen verwendet werden Sie erlauben den direkten Zugriff auf einzelne Bits Die
147. r Name HILF_H unbekannt Deshalb wird der Text zwischen ifndef und endif eingelesen Hierbei wird der Name HILF_H definiert als leere Zeichenkette und ist dem Pr prozessor beim zweiten Einbinden dieser Datei bekannt In diesem Fall wird der Text zwischen ifndef und endif bersprungen 2 4 Verwaltung von Programm Projekten Wenn Sie ein Programm in einzelne Moduln zerlegen k nnen Sie nicht nur die berschaubarkeit erh hen Sie sparen auch noch wertvolle Entwicklungszeit ein Denn nach einer nderung in einem der Programm Moduln brauchen Sie nicht Ihr ganzes Programm neu zu bersetzen sondern nur den ver nderten Modul Bei gr eren Projekten ist es aber nicht ganz einfach die notwendigen Konsequenzen einer nderung zu berschauen Haben Sie etwa Korrekturen in einer Header Datei angebracht so m ssen alle Quelltexte neu bersetzt werden die diese Datei eventuell indirekt importieren Anschlie end mu der Linker aufgerufen werden um das ausf hrbare Programm auf den neuesten Stand zu bringen Eine unbefriedigende L sung des Problems w re eine Stapeldatei die pauschal s mtliche Schritte der bersetzung und Bindung erledigt Damit ginge aber der zeitliche Vorteil der getrennten bersetzung verloren Im Betriebssystem UNIX gibt es deshalb das Dienstprogramm MAKE das automatisch die erforderlichen Schritte ausf hrt Dazu m ssen die Abh ngigkeiten der Datei zun chst einmal in einer Projektbeschreibungsdatei MAKEFI
148. r als Quelle Quelle signed Die h herwertigen Stellen werden mit dem Vorzeichenbit aufgef llt Quelle unsigned Die h herwertigen Stellen werden mit Nullen aufgef llt Explizite Konvertierungen Sie k nnen auch explizit eine Typumwandlung erzwingen indem Sie den Namen des Zieltyps wie einen Funktionsaufruf vor den urspr nglichen Ausdruck setzen long 1 int i i i int 1 L Die Umwandlung von 1 in den Typ int wird hier in der vorletzten Zeile explizit angefordert In der letzten Zeile wird die Konvertierung automatisch ausgef hrt allerdings mit einer Warnung des Compilers da die Umwandlung von 1 nach int Unsinn ergibt wenn der Wert von 1 zu gro ist Bei der expliziten Konvertierung erhalten Sie keine Warnung Sie geben dem Compiler die Blanko Vollmacht Ihre Zahl notfalls zu verst mmeln Manchmal kann eine explizite Konvertierung den Compiler auch vor berfl ssiger Arbeit bewahren int i n 1 double x 1 2 i n x i n int x In der vorletzten Zeile wird zun chst n nach double konvertiert anschlie end die Summe mit Gleitkomma Arithmetik errechnet und zum int Wert 2 konvertiert Die letzte Zeile kommt zum gleichen Ergebnis mit nur einer Konvertierung und schnellerer Ganzzahl Arithmetik Der cast Operator Die soeben beschriebene explizite Konvertierung ist nur mit Typnamen m glich Wollen Sie etwa einen Zeiger p in einen Zeiger auf char umwandeln so m ssen Sie zun chst diesem
149. rameter weil nach dem Namen ein Leerzeichen folgt Deshalb wird Doppelt b c zu x x x b c erweitert Syntaxfehler Ersatz inline Quadrat int x return x x inline Doppelt int x return x tx Aufgabe 11 Die Klasse bitset wird erweitert class bitset public bitset int i Konversion int gt bitset operator int Konversion bitset gt int ES Implementierung bitset int i bits i operator int return bits inline bitset inline bits Aufgabe 12 Wenn der Gleichheitsoperator nicht berladen wird verwendet der Compiler die implizite Konvertierung nach double Dabei kann das Resultat aber durch Rundungsfehler verf lscht werden Erst wenn Sie auch die Typumwandlung operator double entfernen gibt der Compiler eine Fehlermeldung aus Aufgabe 13 ptr1 und ptr2 sind vom gleichen Typ Zeiger auf Klasse1 Daher setzt der Compiler in den beiden Anweisungen trl gt frueheBindung tr2 gt frueheBindung P P die Funktion der Klasse 1 ein In den beiden Anweisungen ptrl gt spaeteBindung ptr2 gt spaeteBindung wird eine virtuelle Funktion aufgerufen Deshalb werden zur Laufzeit die Funktionsversionen nach dem Typ des Objekts auf das der Zeiger zeigt ermittelt Insgesamt werden so die vier Zeilen ausgegeben fr heBindung Klassel fr heBindung Klassel sp teBindung Klassel sp teBindung Klasse2 C Mehrdeutige
150. rs wird zun chst eine lokale Variable t der passenden L nge erzeugt Der Referenzenz hler steht jetzt auf 1 Bei der bergabe des Funktionswertes wird er in die verborgene tempor re Variable kopiert Jetzt steht der Referenzenz hler auf 2 Bevor die Zuweisung ausgef hrt wird wird der Destruktor der lokalen Variable t aufgerufen Dabei werden die stringDaten nicht vernichtet sondern nur der Referenzenz hler von 2 auf 1 herabgesetzt IIIIIIIIIIIIIIIII I II I II STRING CPP I II I II I II I II I II Verwendung von Referenzenz hlern f7 zur Vermeidung unn tiger Kopien fr IIIIIIIIIIIIIII III III III III III III III III III I II III I II I II LIULL include lt iostream h gt include lt string h gt include lt stdlib h gt struct stringDaten char s int Referenzen Ez class string public string int string s 256 string const char string s abc string const string amp string t s string int length string amp operator const string amp t s char amp operator int i friend ostream amp operator lt lt ostream amp string amp friend string operator const string amp s const string amp t friend int operator const string amp s const string amp t friend int operator const string amp s const string amp t private stringDaten p Kr void error char
151. ruktor Initialisierung void operator int i Element einf gen void operator int i Element entfernen boolean leer Leere Menge private friend boolean operator lt int i bitset s Element friend bitset operator bitset sl bitset s2 Vereinigung friend bitset operator bitset sl bitset s2 Durchschnitt friend bitset operator bitset sl bitset s2 Mengendiff friend boolean operator lt bitset sl bitset s2 Teilmenge friend bitset operator bitset sl Komplement friend ostream amp operator lt lt ostream amp s bitset b unsigned bits inline bitset bitset bits 0 inline void bitset operator int i bits 1 lt lt i inline void bitset operator int i bits amp 1 lt lt i inline boolean bitset leer return bits 0 boolean operator lt int i bitset s Element return s bits amp 1 lt lt i gt 0 bitset operator bitset sl bitset s2 Vereinigung bitset s s bits sl bits s2 bits return s bitset operator bitset sl bitset s2 Durchschnitt bitset s s bits sl bits amp s2 bits return s bitset operator bitset sl bitset s2 Mengendifferenz bitset s s bits sl bits amp s2 bits return s boolean operator lt bitset sl bitset s2 Teilmenge return si bits amp s2 bits 0 sl s2 f bitset operator bitset sl Komplement bitset s s bits sl bits
152. rung hinter die letzte Anweisung der Schleife Das bedeutet Die Schleife wird mit der n chsten Bedingungsabfrage fortgesetzt bei der or Schleife wird vorher noch die Inkrementierungsanweisung ausgef hrt Wie in Pascal gibt es auch in C aus historischen Gr nden eine allgemeine Sprunganweisung goto deren Gebrauch allerdings nur in seltenen F llen zu rechtfertigen ist z B Sprung aus verschachtelten Schleifen bungsaufgabe 2 Was gibt folgendes Programm aus include lt iostream h gt main int n 0 for int i 0 i lt 30 i if i gt 20 break n 100 if i lt 10 continue n cout lt lt n 1 8 Funktionen In Pascal werden gew hnliche Prozeduren mit dem Schl sselwort procedure eingeleitet Funktionsprozeduren mit dem Schl sselwort function Im Prinzip w re diese Unterscheidung nicht n tig denn Funktionsprozeduren kann man ja schon an der Angabe des Ergebnistyps erkennen Deshalb verzichtet Modula 2 auf das Schl sselwort FUNCTION und verwendet das Schl sselwort PROCEDURE f r beide Arten von Prozeduren In C dagegen spricht man nur von Funktionen Eine Prozedur wird also in C als eine Funktion mit leerem Wertebereich Pseudo Datentyp void angesehen Die Syntax der Prozedurdefinitionen ist so entworfen da kein spezielles Schl sselwort ben tigt wird Das folgende Beispiel zeigt in beiden Sprachen eine Funktion die das Maximum dreier Zahlen ermittelt
153. s Speicherplatzes f r den String aus dem Konstruktor entfernen und hierf r eine separate Elementfunktion einf hren class string Alternative f r Vektoren von Strings public initialisiere int n 255 string private char s int aktlLg int maxLg Es int main string S 10 for int i 0 i lt 10 i S i initialisiere 20 Damit gehen allerdings die Vorteile des Konstruktors verloren Jetzt besteht die Gefahr da die Initialisieruung versehentlich mehrfach aufgerufen wird Der Destruktor der Klasse string kann unver ndert weiterverwendet werden 3 4 Friend Funktionen Manchmal ist es sinnvoll Funktionen mit Argumenten einer Klasse au erhalb der Klasse zu definieren Unsere Bitset Klasse bietet zum Beispiel eine Methode void bitset schneide bitset s Hier wird einer Menge der Durchschnitt dieser Menge mit einer anderen Menge zugewiesen Manchmal w re aber auch eine Funktion sinnvoll die den Durchschnitt zweier Mengen als Ergebnis zur ckgibt Man k nnte auch hier eine Methode bitset bitset Durchschnitt bitset s innerhalb der Klasse definieren Wollen wir den Durchschnitt d zweier Bitsets a und b berechnen k nnten wir wahlweise d a Durchschnitt b oder d b Durchschnitt a schreiben Diese Asymmetrie ist hier sthetisch unbefriedigend denn beide Argumente sind ja v llig gleichberechtigt Deshalb bietet sich hier eine Funktion au erhalb der Klasse an di
154. s Suchspiel begann Der Pascal Entwickler Niklaus Wirth hat k rzlich wieder in einem Interview iX 5 1991 die Sprache C in Grund und Boden verdammt Nat rlich wei ich auch da man mit der sch nsten Programmiersprache scheu liche Programme konzipieren kann Da gibt es leider so viele Beispiele Mit C ist es weitaus schlimmer man kann einfach alles damit machen wenn man gerissen ist Da wird dann herumgetrickst ganz schrecklich ist das W hrend C durch die ANSI Norm wohl nun eine stabile Sprachdefiniton ist wird C sich durchaus noch weiterentwickeln Der in diesem Buch behandelte Sprachstandard wie er in Borland C implementiert ist entspricht der 1989 erschienenen Version 2 0 des Sprachentwicklers AT amp T In fr heren Versionen gab es noch keine mehrfache Vererbung Auch wurde die Typstrenge etwas lockerer gehandhabt C hat zwar viele M ngel von C abgelegt Trotzdem ist es wohl immer noch eine gef hrliche Programmiersprache Das liegt einerseits daran da viele Sprachkonzepte etwas undurchsichtig und unsystematisch entworfen sind andererseits an den vielen berfl ssigen Freiheiten die einen einheitlichen Programmierstil geradezu torpedieren Dieses Buch sollte ein wenig dazu beitragen die in C verborgenen Gefahren auf ein ertr gliches Ma zu begrenzen E Rangfolge der Operatoren Op Bezeichnung Anwendung Klassenspezifikation Klasse Element globales Objekt Name Elementauswahl Record E
155. s umst ndliche und fehleranf llige Multiplizieren mit der Typgr e zu vermeiden rechnet C hierbei automatisch in Vielfachen der Typgr e und nicht in Bytes Die Zuweisung ptr3 ptr 3 addiert zur Zeigeradresse von ptr dreimal die Typgr e von int also zum Beispiel 6 Bytes Wir k nnen also die drei zus tzlichen Objekte so ansprechen piri ptr TE Zeigerarithmetik in C ptr2 ptr 2 ptr3 ptr 3 Additionen und Subtraktionen zu Zeigern sind auch mit Hilfe der Operatoren und erlaubt Au erdem kann man die Differenz zweier Zeiger gleichen Typs berechnen Das Ergebnis ist eine int Zahl Sie gibt die Differenz der Zeiger Adressen in Typ Einheiten an Wir wollen jetzt sehen wie wir die Array Behandlung von Pascal nach C bertragen k nnen Array in Pascal Array in C 1 Version program ArrayTest main var i integer ine i A array 0 3 of integer int A begin A new int 4 for i 0 to 3 do for i 0 i lt 4 i Ali l i Ati i delete A end Gl cklicherweise gibt es alternativ eine besser lesbare Schreibweise Ist A ein Zeiger und i eine int Zahl so darf man statt Ati auch Ali schreiben Array in Pascal Array in C 2 Version program ArrayTest main var i integer int i A array 0 3 of integer int A begin A new int 4 for i 0 to 3 do for i 0 i lt 4 i Ali l i Alil i delete A end Das folgende
156. se funktioniert das aber nicht weil der Standard Mechanismus f r die Zuweisung verwendet wird Es wird einfach das Zeiger Element s kopiert mit den oben diskutierten Folgen Deshalb mu hier auch die Zuweisung berladen werden class string public string amp operator string amp source string amp string operator string amp source int n source aktlg if n gt maxLg n maxlg memmove s source s n aktLg n return this Hier liefert die Zuweisung eine Referenz auf das Zugewiesene zur ck wie dies in C blich ist Nur so k nnen auch berladene Zuweisungen verkettet werden Zum Vergleich folgt nochmals die Implementierung des Kopier Konstruktors string string const string amp t maxLg t maxlg aktLg t aktlg s new char maxLg t1 memmove s t s aktLg Die Zuweisung hnelt zwar sehr dem Kopier Konstruktor Beide kopieren nicht das Zeiger Element sondern die Daten auf die es zeigt W hrend aber der Kopier Konstruktor erst ein Objekt erzeugen mu existiert das Objekt bei der Zuweisung schon Arithmetik mit rationalen Zahlen Bei der Division zweier ganzer Zahlen erh lt man rationale Zahlen N herungsweise l t sich eine rationale Zahl durch eine Gleitkommazahl darstellen Die Darstellung wird aber ungenau wenn die Gleitkomma Darstellung periodisch ist Es folgen einige Beispiele float x 1 3 Rundungsfehler weil 1 3 periodischer Dualbruch float y
157. spiel f r die Verwendung von Konstruktoren und Destruktoren Ti VIIIIIIIIIIII III III III III III III III III III III III III III I II III I II I II IV include lt iostream h gt include lt string h gt class string public string int n 255 Konstruktor string Destruktor int length void insert string amp Einfg int Index void setze char s void writeln private char s int aktlLg int maxLg 7 string string int n if n lt 1 n 1 else if n gt 255 n 255 aktLg 0 maxLg n s new char n 1 string string delete s int string length return aktlg void string insert string amp Einfg int Index int Anflg L nge des Anfangsst cks bleibt stehen int Endlg L nge des Endst cks wird verschoben int Einfglg L nge des einzuf genden Strings AnfLg Index 1 Indizierung in Pascal ab 1 if AnfLg lt 0 AnfLg 0 Fehler abfangen else if AnfLg gt aktLg AnfLg aktlg dto EinfgLg Einfg length falls Einfg keinen Platz hat beschneiden if Anflg EinfgLg gt maxLg EinfgLg maxLg Anflig EndLg aktLg Anflg falls verschobenes Endst ck keinen Platz hat beschneiden if AnfLg EinfgLg EndLg gt maxlLg EndLg maxLg AnfLg Ein
158. st void leere void lege char c char entnimm private char D MAX int Anfang Ende Wenn Sie diese Struktur mit der zuvor definierten vergleichen bemerken Sie folgende Neuerungen Die Strukturdefinition ist in zwei Abschnitte aufgeteilt Mit public beginnt der ffentliche Teil mit private der private Teil Elemente Komponenten members des privaten Teils sind f r Benutzer dieser Struktur nicht zug nglich L t man diese Bereichsmarken weg ist die ganze Struktur ffentlich Die Struktur enth lt neben Datenelementen auch Funktionen Das sind die Methoden der Datenstruktur Die Methodenfunktionen haben jeweils einen Parameter weniger als in unserer vorherigen Definition Das h ngt mit der ver nderten Sichtweise zusammen W hrend man in der prozedurorientierten Programmierung einer Prozedur die Daten bergibt sind in der objektorientierten Programmierung die Daten die zentralen Objekte Diese Objekte k nnen selbst alle denkbaren Operationen ausf hren Deshalb k nnen sie ihre interne Struktur nach au en verbergen In der Smalltalk Sprechweise werden Botschaften an die Objekte geschickt die Objekte veranlassen dann selbst ndig das N tige In unserem jetzigen Stadium ist das einfach nur eine andere Sichtweise des gleichen Sachverhalts Da daraus v llig neue M glichkeiten erwachsen werden Sie sp ter sehen Elementfunktionen werden in der gleichen Weise angesprochen wie Datenelemente Dem
159. t der alle Datenelemente kopiert string string const string amp t maxLg t maxlg aktLg t aktlg StB Wir wollen aber da die Kopie eigenen Speicherplatz f r einen String bekommt und schreiben daher string string const string amp t maxLg t maxlg aktLg t aktlg s new char maxLg t1 memmove s t s aktlLg Vektoren von Objekten Wir haben gesehen da bei der Definition eines Objekts dem Konstruktor Parameter bergeben werden k nnen In der Definitions Anweisung string s 20 wird dem Konstruktor f r die Klasse string der aktuelle Parameter 20 bergeben Solche Parameter bergaben sind in C nur in einfachen Definitionen m glich nicht aber in Vektordefinitionen Vektoren von Objekten k nnen deshalb nur definiert werden wenn f r die Klasse entweder gar kein Konstruktor oder ein Konstruktor ohne Parameter definiert wurde Im ersten Fall wird f r jedes Element der Standard Konstruktor verwendet Die Definitions Anweisung string s 10 erzeugt einen Vektor aus 10 Elementen vom Typ string Dabei wird 10 mal der Konstruktor ohne Argumente aufgerufen In unserer Implementierung wird also f r jeden String die maximale L nge von 255 Bytes reserviert Wenn wir einen Vektor aus 10 Strings mit der Maximall nge 20 ben tigen ist das mit unserer string Klasse nicht m glich In solchen F llen mu man die Klasse anders konzipieren Wir k nnten etwa die Reservierung de
160. t deren Unterabteilungen sich in m glichst wenig Details abheben Ein bekanntes Beispiel f r solche Klassenbildungen ist die von Carl von Linn begr ndete Systematik der Tier und Pflanzenarten So geh rt zum Beispiel ein Buntspecht der Ordnung der Spechte an die Spechte der Klasse der V gel und die V gel dem Unterstamm der Wirbeltiere Die F rbung des Buntspechts ist ein Artmerkmal Seinen kr ftigen Mei elschnabel hat er mit allen Spechten gemeinsam das Federkleid mit allen V geln und das Knochenger st mit allen Wirbeltieren Auch in der Programmierung hat man es immer wieder mit Datentypen zu tun die sich zwar nicht gleichen aber doch gemeinsame Elemente besitzen Um hier hierarchische Modelle zu erm glichen besitzen objektorientierte Sprachen die M glichkeit der Vererbung Die Gemeinsamkeiten zwischen Buntspechten und Gr nspechten f hren zur Bildung der Oberklasse Specht Welche Gemeinsamkeiten besitzen unsere Klassen Kreis und Rechteck Beide besitzen einen Bezugspunkt x y der ihre aktuelle Lage beschreibt Wir definieren also eine Klasse Punkt class Punkt public Punkt int x0 int y0 private Int x int y ES mit dem Konstruktor Punkt Punkt int x0 int y0 x x0 y y0 Jetzt wollen wir erkl ren da ein Kreis eine von Punkt abgeleitete Klasse ist Das hei t Kreis besitzt zun chst einmal alle Eigenschaften von Punkt In der Definition von Kreis werden nur die Eigenschaften angeg
161. t angeh ngt Obwohl die verwendeten Funktionen strcpy und strcat sich in der Standard Bibliothek befinden wollen wir hier zur Vertiefung des Verst ndnisses zumindest die Funktion strcpy nachimplementieren An diesem Beispiel m chte ich Ihnen auch exemplarisch zeigen welche F lle von verschiedenartigen Formulierungen C f r ein und dieselbe Aufgabe anbietet Sie sollten versuchen zumindest passiv die verschiedenen Varianten in ihrer Bedeutung zu erfassen Zun chst fassen wir die beiden Strings als Vektoren auf und sprechen die einzelnen Positionen durch Indizes an enum false true Nachbildung des Pascal Typs boolean typedef int boolean char strcpyl char Ziel const char Quelle int i 0 boolean fertig false while fertig zielli Quelle i if Quelle i 0 fertig true else i i tl Byte f r Byte wird der Quellstring zum Zielstring kopiert Wenn das erste Nullbyte kopiert wurde ist die Arbeit getan Die boolesche Variable fertig dient hier zum Verlassen der Schleife Diese Variable l t sich einsparen wenn wir eine Endlosschleife verwenden die mit der Schleifenabbruch Anweisung break verlassen wird char strcpy char Ziel const char Quelle int i 0 tor a Endlosschleife zielli Quelle i if Quelle i 0 break i Kurzschreibweise f r i i 1 Eine weitere Vereinfachung ergibt sich wenn man ber cksichtigt da der Wert einer Anweis
162. t vielen kleinen Objektdateien verwenden 2 6 Bibliotheksfunktionen Zur Sprache C geh rt nach der ANSI Norm eine reichhaltige Funktionsbibliothek Dies erm glicht eine weitgehende Portabilit t von C Programmen denn man kann sich darauf verlassen da diese Funktionen in jeder neueren Implementierung vorhanden sind Hier finden Sie nur eine Auswahl wichtiger Funktionen Zun chst werden die Funktionen zur Datei Behandlung von ANSI C dargestellt Sie sind in der Datei STDIO H deklariert Anschlie end finden Sie kurze Hinweise zu weiteren wichtigen Standard Funktionen In C gibt es auch eine objektorientierte Ein Ausgabe Bibliothek Header Datei IOSTREAM H die allerdings noch nicht genormt ist In diesem Buch verwenden wir nur elementare M glichkeiten der objektorientierten Ein Ausgabe ber weitere Details und ber weitere Funktionen k nnen Sie sich jederzeit mit der eingebauten Hilfe Funktion von Borland C informieren Cursor auf den Funktionsnamen setzen und Strg Fl dr cken Bildschirmausgabe printf const char format Die Funktion printf Abk rzung f r print formatted dient zur formatierten Ausgabe am Bildschirm und bietet eine F lle m glicher Darstellungsarten f r deren Details Sie bitte Ihr Referenzhandbuch oder die eingebaute Hilfe von Borland C zu Rate ziehen Zun chst fallen die drei Punkte am Ende der Deklaration auf Damit wird dem Compiler mitgeteilt da die Funktion e
163. t von b 1 ist 1 und wird a zugewiesen Beim Umstieg von Pascal nach C tut sich hier eine der ber chtigtsten Fallgruben auf a 0 a 0 if a 1 then write ja if a 1 printf ja lse writ nein else printf nein Das Pascal Programm sagt nein C entscheidet sich f r ja Was ist der Grund Der Ausdruck nach dem if ist im Pascal Programm eine Gleichheitsrelation mit dem Ergebnis false in C eine Zuweisung mit dem Ergebnis 1 was von Null verschieden und damit wahr ist W rden Sie in Pascal den gleichen Fehler machen n mlich versehentlich a 1 anstelle a 1 schreiben w rde der Compiler das nicht durchgehen lassen weil nach dem if nur ein Ausdruck aber keine Anweisung stehen darf Auf der linken Seite einer Zuweisung mu ebenso wie in Pascal ein Objekt stehen dem eine bestimmte Speicheradresse zugeordnet ist In der C Terminologie spricht man von einem L Wert L value L f r linke Seite Auf der rechten Seite darf ein beliebiger Ausdruck stehen Dieser Ausdruck mu vom gleichen Typ wie der L Wert sein oder in den L Wert umgewandelt werden k nnen Die genauen Regeln f r solche Typkonvertierungen erfahren Sie in einem sp teren Abschnitt Neben der gew hnlichen Zuweisung gibt es noch eine ganze Reihe von Kombinationen von Zuweisungen mit arithmetischen Operationen Anstelle von a a t b k nnen Sie auch die Kurzschreibweise a b verwenden Dies ist besonders bei komplizierten Objekt
164. ter public Mutter In diesem Beispiel hat jedes Objekt der Klasse Kind die aus der Klasse Ahn geerbten Elemente doppelt Um das zu vermeiden l t sich die Basisklasse als virtuelle Basisklasse deklarieren Q lass Mutter virtual public Ahn lass Vater virtual public Ahn lass Kind public Vater public Mutter Q Q Hier wurde Ahn zu einer virtuellen Basiklasse und gibt seine Elemente nur einmal an Kind weiter 3 11 Dynamische Objekte als Funktionswert Ein Ziel von C ist es vom Anwender definierten Datentypen die gleichen M glichkeiten wie Standard Datentypen geben zu k nnen In der Praxis tauchen dabei allerdings einige technische Probleme auf die nicht ganz einfach zu umgehen sind Wir wollen nochmals einen Datentyp string entwerfen diesmal aber nicht nach dem Vorbild von Turbo Pascal sondern so flexibel da ein String im Prinzip jede beliebige Gr e annehmen kann F r diese Klasse wollen wir die Verkettung mit dem Operator definieren Sind s1 s2 und s3 vom Typ string so soll die Zuweisung sl s2 s3 die Strings s2 und s3 verketten und das Ergebnis der Stringvariablen s1 zuweisen Das soll auch dann klappen wenn s1 derzeit zu kurz ist Dazu k nnten wir so vorgehen Die Operatorfunktion gibt den gew nschten verketteten String zur ck Der Zuweisungsoperator wird so berladen da er zun chst das aktuelle Objekt s1 l scht es hat ja meist eine nicht passende Gr e und
165. thoden stecken Im Alltagsleben w re eine sinnvolle Kommunikation ohne Polymorphie nicht m glich Sie brauchen nur einmal ein Kochrezept durchzulesen und sich zu berlegen was die darin enthaltenen Anweisungen f r Sie bedeuten je nachdem ob Sie der Klasse der Elektroherdbesitzer oder der Gasherdbesitzer angeh ren ob Sie eine K chenmaschine haben und so weiter hnliches haben wir auch in den Klassen Kreis und Rechteck Die Methoden zeige und loesche sind f r beide Klassen unterschiedlich Dagegen stimmt der Text der Methode bewege in beiden Implementierungen berein Jedes geometrische Objekt kann bewegt werden indem es zun chst gel scht und dann mit neuen Koordinaten wieder gezeigt wird Es bietet sich an zu den Klassen Kreis und Rechteck eine Oberklasse Figur einzuf hren in der wir unabh ngig von der Art der Figur Kreis oder Rechteck beschreiben wie eine Figur bewegt wird class Figur public Punkt Basisklasse public f r Grafik Objekte Figur int x0 int y0 void bewege int dx int dy void Figur bewege int dx int dy loesche x dx y dy zeige Der Haken daran ist nur da der Compiler hier streikt weil er in Figur bewege die Methoden loesche und zeige gar nicht kennt Objektorientierte Sprachen bieten einen Ausweg aus dieser Situation Sie haben C bisher als eine typstrenge Sprache kennengelernt Der Compiler mu bei jedem Objekt wissen von welchem Typ es ist um di
166. tionen im allgemeinen verschiedenen Speicherbedarf haben Erlaubt sind dagegen Zeiger auf Funktionen Ebenso wie Datenzeiger sind Funktionszeiger typisiert Zwei Funktionszeiger sind nur dann kompatibel wenn sie auf Funktionen mit dem gleichen Parameterschema gleiche Anzahl gleiche Typen und typgleichem Funktionswert zeigen Wie werden Zeiger auf Funktionen definiert Nehmen Sie eine Funktionsdeklaration in der Kurzform ohne Parameternamen setzen Sie vor den Funktionsnamen einen Stern und klammern Sie den Funktionsnamen mit dem Stern ein Zum Beispiel wird mit char Summe int int eine Funktion deklariert die zwei Argumente vom Typ int verlangt und einen Wert vom Typ char zur ckgibt Mit char FktZeiger int int wird ein Zeiger auf eine solche Funktion definiert Die Klammern um den Namen mit dem Stern d rfen Sie nicht vergessen denn mit char Zeiger int int wird kein Zeiger auf eine Funktion deklariert sondern eine Funktion die einen Zeiger auf char zur ckgibt Wenn Sie einem Zeiger auf eine Funktion etwas zuweisen m chten m ten Sie eigentlich die Adresse einer Funktion bilden Um die Schreibweise zu vereinfachen gilt hier eine hnliche Konvention wie bei den Vektortypen Funktionsnamen stehen prinzipiell f r einen Zeiger auf die Funktion Erst durch die runden Klammern der Parameter dahinter wird der Zeiger dereferenziert und die Funktion aufgerufen Deshalb m ssen in C auch beim Aufruf einer Funktion
167. twa Quicksort qsort bin re Suche bsearch Zufallszahlengenerator rand Zeit und Datums Routinen Sie sollten einmal einen Streifzug durch das Referenzhandbuch machen damit Sie sp ter bei Bedarf das richtige Werkzeug finden 3 Objektorientierte Programmierung 3 1 Datenabstraktion Wenn Sie gefragt w rden warum Sie in Pascal lieber programmieren als beispielsweise in BASIC w rden Sie h chstwahrscheinlich auf das Prozedurkonzept zu sprechen kommen Nachdem Sie sich einmal Gedanken dar ber gemacht haben wie ein bestimmtes Problem zu l sen ist verpacken Sie die gefundene L sung in eine Prozedur Anschlie end brauchen Sie nur noch zu wissen was die Prozedur mit den bergebenen Parametern tut nicht wie Diese M glichkeit der Prozedurabstraktion erm glicht es schrittweise immer komplexere Operationen als elementare Einheiten anzusehen und somit zur berschaubaren Behandlung immer komplexerer Probleme vorzudringen Steht Ihnen etwa die Bibliotheksfunktion sin f r die Sinusfunktion zur Verf gung ist ihre Verwendung ebenso einfach wie die der Funktion abs f r den Absolutbetrag Mit Hilfe selbst definierter Prozeduren ist es m glich die Programmiersprache zu erweitern und sich selbst ein immer m chtigeres Werkzeug zu schaffen Ein wichtiges Kriterium f r einen guten Programmierstil ist die Leichtigkeit der Anpassung an ver nderte Bedingungen Wer kennt nicht jene Programme die als holographisches Gesamtkunstwerk im
168. txy 10 40 Ende Esc Kreis K getmaxx 2 getmaxy 2 40 Rechteck R 0 0 80 60 char aktuelleFigur K K zeige do c getch auf Tastendruck warten if c 0 normale Zeichentaste andere Figur switch aktuelleFigur case K K loesche break case R R loesche break switch toupper c case K aktuelleFigur K break case R aktuelleFigur R break switch aktuelleFigur case K K zeige break case R R zeige break else erweiterter Tastencode Cursorbewegung c getch switch c case 72 dx 0 dy 10 break aufw rts case 80 dx 0 dy 10 break abw rts case 75 dx 10 dy 0 break links case 77 dx 10 dy 0 break rechts switch aktuelleFigur case K K bewege dx dy break case R R bewege dx dy break while c 33 Esc Taste closegraph return 0 Zusammenfassung von Gemeinsamkeiten Vererbung Wenn Sie die beiden Klassen Kreis und Rechteck betrachten sehen Sie da sie folgende gemeinsamen Elemente besitzen Die Methoden zeige Loesche und bewege die Datenelemente x und y Die Methoden unterscheiden sich allerdings in ihrer Implementierung In der Wissenschaft wie im t glichen Leben versucht man der F lle von Objekten und Ph nomenen Herr zu werden indem man das Gemeinsame herausarbeitet und so Klassen bilde
169. tz zur Verf gung sondern erh lt nur die Information da anderswo eine solche Variable existiert Wenn Sie versehentlich eine Variable deklarieren die nirgendwo definiert ist kann dieser Fehler erst vom Binder erkannt werden Das Schl sselwort extern suggeriert leicht ein Mi verst ndnis Das mit extern deklarierte Objekt mu nicht in einer anderen Datei definiert werden Es kann auch in der gleichen Datei an anderer Stelle definiert sein Mit extern wird lediglich eine Deklaration von einer Definition unterschieden Manchmal ist es angebracht die Sichtbarkeit einer globalen Variablen auf die Datei zu beschr nken in der sie definiert ist Hierzu dient das Schl sselwort static static int n n ist aus anderen Dateien nicht ansprechbar Lokale Variablen werden innerhalb eines Blocks also auch innerhalb einer Funktion definiert Sie sind nur in dem Block sichtbar in dem sie definiert sind Sie k nnen an beliebiger Stelle im Block definiert werden d rfen aber nicht vor ihrer Definition angesprochen werden Lokale Variablen k nnen nicht deklariert werden Dies w re auch nicht sinnvoll da sie au erhalb des Blocks nicht sichtbar sind In Pascal werden alle lokalen Variablen bei ihrer Definition auf dem Stack angelegt und beim Verlassen des Blocks wieder beseitigt Dadurch wird es oft notwendig globale Variablen anzulegen die nur f r eine bestimmte Funktion relevant sind In C k nnen Sie auch lokale Variablen definieren
170. ude Verzeichnis include hilfe h im aktuellen Verzeichnis Wie die Include Verzeichnisse spezifiziert werden ist von der Implementierung des Compilers abh ngig Bei den meisten C Compilern wird daf r eine Umgebungsvariable des Betriebssystems gesetzt In der integrierten Umgebung von Borland C werden die Verzeichnisse im Men Options Directories angegeben include Direktiven d rfen verschachtelt werden Eingebundene Dateien d rfen wieder include Direktiven enthalten Textersetzungen Die define Direktive erlaubt Textersetzungen Makros mit oder ohne Parameter Sie sind ein wichtiges Hilfsmittel in Standard C Sie haben aber auch einen gro en Nachteil Mit Textersetzungen l t sich sehr leicht die Typstrenge von C unterlaufen In C sollten Konstanten Definitionen Aufz hlungen oder inline Funktionen bevorzugt werden Sie d rfen den kurz gehaltenen Rest dieses Abschnitts deshalb mit gutem Gewissen berfliegen Ein Makro ohne Parameter hat folgende Form define Name Ersetzungstext Dabei mu der Name ein g ltiger Bezeichner sein f r den Ersetzungtext gibt es keine Einschr nkungen Er kann sogar leer sein Hinter dem Namen darf auch eine Parameterliste stehen Argumente g ltige Bezeichner durch Kommata getrennt in runde Klammern eingeschlossen Zwischen dem Namen und der ffnenden Klammer der Parameterliste darf keinL ckenzeichen Leerzeichen Tabulator etc stehen Definierte Makros k nnen mit
171. uf die Klasse bitset Wir setzen die neu gewonnenen M glichkeiten nun f r eine abschlie ende Version der Klasse bitset ein Dies sind die Neuerungen Ein Konstruktor ohne Argumente sorgt daf r da jedes Objekt mit der leeren Menge initialisiert wird Es werden implizite Typkonvertierungen von int nach bitset und umgekehrt eingef hrt Die von Pascal gewohnten Operatoren f r Vereinigung Durchschnitt und Differenzmenge werden bernommen und durch weitere naheliegende Operatoren f r das Einf gen und L schen von Elementen Komplement und Elementrelation erg nzt Den Pascal Operator in k nnen wir nicht bernehmen weil in C leider keine neuen Operatorsymbole eingef hrt werden k nnen Stattdessen berladen wir hier das Kleiner Zeichen lt In der Implementierung werden die Mengenoperationen durch die entsprechenden Bit Operatoren ersetzt Als praktische Anwendung dient die Funktion TastenDemo in der der Zustand der Umschalttasten der Strg Ctrl und der Alt Taste auf einem IBM kompatiblen PC abgefragt wird Eigentlich sollte hierzu die entsprechende BIOS Routine aufgerufen werden in Borland C auch unter bioskey 2 verf gbar um Portabilit t zu garantieren Hier soll aber ein konkretes Beispiel f r Referenzen und f r volatile Variablen gegeben werden Deshalb wird die Speicherstelle 417H abgefragt die st ndig in ihren einzelnen Bits die zur Zeit gedr ckten Umschalttasten wiedergibt FlagPtr ist ein Zeiger
172. uktor Aufruf angegeben Im folgenden Prinzip Beispiel wird vor dem Konstruktor der Klasse Angeleitet mit Hilfe der Initialisierer Liste Basis i der Konstruktor der Basisklasse aufgerufen class Basis public Basis int i pa class Abgeleitet public Basis public Abgeleitet j Basis Basis int i Abgeleitet Abgeleitet Basis i 3 9 Virtuelle Funktionen Sp te Bindung Das allj hrliche Brutgesch ft l t sich f r die Klasse aller V gel in stark vereinfachter Form so beschreiben 1 Sorge f r einen geeigneten Nistplatz 2 lege Eier 3 br te die Eier aus 4 versorge die Jungv gel bis sie selbst ndig sind Eine schrittweise Zerlegung eines Problems in Teilprobleme ist in der Programmierung nichts neues Was die Sache hier allerdings interessant macht ist die Tatsache da wir eine Methode f r eine Klasse formuliert haben die auf Hilfsmethoden zugreift die erst in den Unterklassen definiert werden k nnen So bedeutet Methode 1 je nach Unterklasse H hle zimmern Spechte H hle suchen Eulen Nest bauen Amsel Wirtsnest aufsp ren Kuckuck Auch die brigen Methoden unterscheiden sich in den Unterklassen So kann bei Methode 3 das Br ten Aufgabe des Weibchens des M nnchens oder beider sein oder es kann sogar delegiert werden Kuckuck Man spricht hier von polymorphen vielgestaltigen Methoden weil hinter einer Bezeichnung je nach Klasse verschiedene Me
173. ung in C gleich dem Wert der rechten Seite ist char strcpy char Ziel const char Quelle int i 0 while Zielli Quelle i 0 i Ein solch knapper Programmierstil ist sicher eine Zumutung f r die meisten Leser Trotzdem m ssen Sie darauf gefa t sein immer wieder solchen Formulierungen von C Programmierern zu begegnen Fast jedes Programm l t sich noch weiter vereinfachen Da es in C keinen Unterschied zwischen Wahrheitswerten und Zahlen gibt und da char mit int vertr glich ist l t sich jede Abfrage der Form Variable 0 durch Variable ersetzen char strcpy char Ziel const char Quelle int i 0 while Ziel li Quelle i i Manche C Programmierer m gen die while Anweisung nicht und schreiben lieber char strcpy char Ziel const char Quelle for int i 0 Zielli Quelle i i Der Aufwand f r die indizierten Variablen l t sich einsparen Es steht jas 0 f r s s 1 f r s 1 usw Anstatt jeweils den Index zu erh hen k nnen wir auch die Zeiger selbst erh hen char strcpy char Ziel const char Quelle while Ziel Quelle Quelle t Zielt t Im Standardwerk von Kernighan Ritchie Kern88 wird folgende Extrem L sung vorgeschlagen char strcpy char Ziel const char Quelle while Ziel Quelle Hier wird in der while Bedingung das Kopieren und das Erh hen
174. ung verwenden k nnen Nun gibt es aber auch Schleifen bei denen die Fortsetzungsbedingung logisch weder am Anfang noch am Ende sondern irgendwo in der Mitte des Anweisungsblocks steht Im folgenden Beispiel sollen solange ganze Zahlen eingegeben und deren Kehrwerte aufsummiert werden bis eine Null eingegeben wird Mit unseren bisherigen Mitteln k nnten wir das etwa so formulieren include lt iostream h gt main int n float s 0 0 int Abbruch 0 while Abbruch Gin S gt Th f n 0 Abbruch 1 else s 1 0 n H cout lt lt Summe lt lt s Hier mu eine k nstlich anmutende logische Variable Abbruch eingef hrt und der letzte Teil des Anweisungsblocks bedingt ausgef hrt werden Das Beispiel wird durchsichtiger wenn auch hier eine ma geschneiderte Konstruktion verwendet wird n mlich eine Endlosschleife mit der Abbruchbedingung in der Mitte include lt iostream h gt main int ni float s 0 0 for Endlosschleife cin gt gt n if n 0 break bedingter Schleifenabbruch s 1 0 n cout lt lt Summe lt lt Ss Die break Anweisung beendet vorzeitig eine Schleife while do oder for oder wie Sie bereits wissen eine switch Anweisung Bei mehreren geschachtelten Schleifen wird jeweils nur die aktuelle Schleife verlassen Eine weitere allerdings seltener ben tigte Sprunganweisung ist die continue Anweisung Sie bewirkt einen Sp
175. upt uses Hilf var k integer begin end haupt cpp extern int i extern char f int i static int k void main Beachten Sie folgenden Unterschied Zu einem Pascal Programm geh ren genau eine program Datei und beliebig viele unit Dateien In C gibt es keinen formalen Unterschied zwischen den einzelnen Dateien Alle k nnen Deklarationen und Funktionen in beliebiger Folge enthalten aber genau eine Datei mu die Hauptfunktion main enthalten 2 3 Header Dateien Die mit einem Modul ben tigten Deklarationen fa t man blicherweise in einer Header Datei zusammen Diese erh lt die Extension h Damit sieht die Gegen berstellung der Hauptmoduln so aus program Haupt haupt cpp uses Hilf include lt hilf h gt var k integer static int k begin void main Er Die Header Datei k nnte so aussehen hil f h extern int i extern char f i integer Innerhalb von Include Dateien k nnen wiederum Dateien mit include eingebunden werden a h include lt b h gt include lt c h gt b h include lt d h gt Ch include lt d h gt Mit dem Pr prozessorbefehl include lt a h gt wird die Datei d h zweimal eingebunden Um dies zu verhindern sollte man alle Header Dateien nach folgendem Schema absichern hilf h ifndef HILF_H define HILF_H extern int i char f i integer char endif Beim ersten Einbinden dieser Datei ist dem Pr prozessor de
176. us den m glichen Buchstaben bergeben Die Funktion wartet dann solange bis einer dieser Buchstaben eingegeben wurde und gibt ihn als Funktionswert zur ck Ein eingegebener Buchstabe wird in Gro buchstaben umgewandelt Dann wird mit der Bibliotheksfunktion strchr gepr ft ob er im String vorkommt Deshalb ist es wichtig da im String nur Gro buchstaben eingesetzt werden Die Funktion filesize ermittelt die L nge einer ge ffneten Datei indem sie den Dateizeiger ans Ende positioniert Im Hauptprogramm wird eine Datei zum Lesen und Schreiben ge ffnet Anschlie end kann man men gesteuert auf beliebige Byte Positionen positionieren und dort int Werte lesen oder schreiben In der Zeile if fopen test dat r b wird der Wert von fopen Dateizeiger der Variablen zugewiesen und gleichzeitig gepr ft ob er von NULL verschieden ist Solche Abfragen von Zuweisungswerten sind zwar in der C Programmierung allgemein blich k nnen aber auch darauf hinweisen da versehentlich mit verwechselt wurde Deshalb gibt der Compiler hier eine Warnung aus Wenn Sie diesen Stil vermeiden wollen k nnen Sie solche Anweisungen auch in zwei Anweisungen aufl sen f fopen test dat r b if f Beachten Sie auch da die Funktion main einen R ckgabewert vom Typ int hat Hier wird normalerweise der Wert Null zur ckgegeben bei einem Scheitern des Programms ein von Null verschiedener Wert der unter MS DOS mit dem Stapel Bef
177. vermeiden wenn man die gew nschten Konvertierungen explizit vorgibt Dehalb ist es nicht unbedingt n tig da Sie das Schema zur Vereindeutigung beherrschen Am folgenden Beispiel k nnen Sie sich die Wirkung der Regeln klarmachen include lt iostream h gt void f int a cout lt lt A void E float a cout lt lt B main int i unsigned u float x double y char c Schritt Ausgabe FC Fk Da A x 1 B Flle Li 2 A f u A 3 Fehler Mehrdeutigkeit float int int u 1 RI E y II IS Fehler Mehrdeutigkeit float int bungsaufgabe 4 Entfernen Sie die fehlerhaften Zeilen aus dem folgenden Programm Was gibt das Programm jetzt aus include lt iostream h gt void f int a long b cout lt lt A void f long a int b cout lt lt B main Int 15 ong 1 f 1 1 f 1 1 f i i f 1 1 f i long i f 1 int i 1 10 Abgeleitete Datentypen Strukturen C erlaubt ebenso wie Pascal die Definition von Verbundtypen n mlich Datentypen die aus mehreren Elementen Komponenten fester aber beliebiger Typen zusammengesetzt sind Ein einfaches Beispiel zeigt die syntaktischen Unterschiede type Stadt struct Stadt record Name string 40 char Name 41 PLZ integer int PLZ Einwohner longint long Einwohner end var sl s2 Stadt Stadt sl s2 Beachten Sie bitte folgenden wese
178. von Pascal bilden Um den namenlosen Typen auch Bezeichnungen geben zu k nnen hat C die typedef Anweisung von Standard C bernommen Diese gleicht einer Variablendefinition mit dem vorangestellten Schl sselwort typede Hiermit wird anstelle eines Variablennamens eine Typbezeichnung eingef hrt So wird etwa mit typedef int intZeiger eine Bezeichnung f r den Datentyp Zeiger auf int eingef hrt Mit der typedef Anweisung wird nur ein alternativer Name Synonym f r einen Typ eingef hrt jedoch kein neuer Typ definiert Betrachten Sie die feinen Unterschiede im folgenden Beispiel struct typl int x y typl und typ2 sind strukturgleich struct typ2 int x y aber nicht vertr glich typedef typ2 typ3 typ3 ist Synonym zu typ2 typedef int intZeiger typl a typ2 b typ3 CH intZeiger p int q main a b Fehler typl und typ2 sind verschiedene Datentypen b c korrekt typ2 und typ3 sind Synonyme p q korrekt intZeiger ist Synonym f r int bungsaufgabe 9 Welcher Datentyp wird durch folgende Deklaration eingef hrt int Aln int In Definieren Sie diesen Typ mit einer Folge von einfachen Typdeklarationen 2 Projektentwicklung in C Nachdem Sie nun die Sprachmittel f r die konventionelle Programmierung in C kennengelernt haben befassen wir uns in diesem Kapitel mit dem Proze der Programmentwicklung und den dazu n tigen Hilfsmitteln 2 1 Comp
179. wichtigen Konzepte der Vorzug vor Vollst ndigkeit gegeben Zweifelsf lle werden vor allem dann behandelt wenn sie zu schwer auffindbaren Programmfehlern f hren k nnen nicht aber wenn sie eindeutig durch den Compiler erkannt und erkl rt werden Nun verh lt es sich aber mit Programmiersprachen und ganz besonders mit so komplexen Sprachen wie C hnlich wie mit dem Schachspiel Die Kenntnis der Regeln macht noch keinen Schachspieler Entscheidend ist die F higkeit die erlernten Regeln in praktisches Handeln umzusetzen Diese F higkeit kann man sich nicht allein anlesen Sie mu durch eigenes Tun erworben werden Der Weg l t sich aber deutlich verk rzen wenn man an den Erfahrungen anderer teilhaben kann Das vierte Kapitel bietet Ihnen deshalb die M glichkeit Ihre neu erworbenen Kenntnisse im praktischen Einsatz zu vertiefen Der Nutzen objektorientierter Methoden erschlie t sich vor allem bei gr eren Programmierprojekten Deshalb stelle ich Ihnen in diesem letzten Kapitel des Buchs Projekte vor in denen sinnvoll einsetzbare Programme entwickelt werden Es ist eine Erfahrungsregel da erst ein Bruchteil der Arbeit getan ist wenn ein Programm im Prinzip fertig ist Den Hauptteil der Arbeit machen dann solche Kleinigkeiten aus wie eine komfortable Benutzeroberfl che Robustheit gegen Fehlbedienung oder kleine zus tzliche Verbesserungen der Funktion der Appetit kommt mit dem Essen Sie finden zu jedem Projekt eine le
180. xisfernes Beispiel Ein Stringfeld hat einen Inhalt und eine Position auf dem Bildschirm die in zwei getrennten Basisklassen beschrieben werden include lt string h gt include lt conio h gt class String public String char s protected char str 80 String String char s if strlen s lt 80 strcpy str s class Position public Position int x int y protected int x0 y0 F Position Position int x int y x0 x class Stringfeld public String public Position pu blre Stringfeld char s int x int y void zeige F Stringfeld Stringfeld char s int x int y String s Position x y zeige void Stringfeld zeige gotoxy x0 y0 cputs str int main Stringfeld s Stringfeld 35 13 return 0 Dieses Programm gibt die Zeichenkette Stringfeld etwa in der Mitte des Bildschirm aus Ein sinnvolles Beispiel f r mehrfache Vererbung finden Sie zum Beispiel im Modul EDT des Projekts DIAGRAMM auf der Diskette zum Buch Virtuelle Basisklassen Ein Problem bei mehrfacher Vererbung ist die Inzucht Wenn eine Klasse von mehreren Basisklassen abgeleitet wird die wiederum eine gemeinsame Basisklasse haben gibt es die Elemente dieser gemeinsamen Basisklasse mehrfach Das f hrt zu Mehrdeutigkeiten und erh htem Speicherbedarf class Mutter public Ahn class Vater public Ahn class Kind public Va
181. ypstrenge von Pascal unterlaufen wird Der Compiler kann das korrekte Ansprechen der varianten Komponenten n mlich nicht berpr fen In maschinennahen Programmen m chte man manchmal auch bewu t bestimmte Daten unter verschiedenen Aspekten interpretieren Da es in Pascal hierzu kein offizielles Sprachmittel gibt wird zu diesem Zweck oft der variante Record mi braucht Tats chlich ist es sogar erlaubt die in diesem Fall berfl ssige Selektorvariable ganz wegzulassen wie das folgende Beispiel zeigt var doppelt record case integer of 1 u Word 2 i integer end begin doppelt i 1 writeln doppelt u 8 Ergebnis 65535 end In Turbo Pascal gibt es f r solche Zwecke eine direktere L sung var u Word i integer absolute u begin 3 8 write u 8 end C bietet zum gleichen Zweck die union Konstruktion an Eine union hat die gleiche syntaktische Struktur wie eine struct W hrend aber alle st ruct Komponenten im Speicher hintereinander angelegt werden beginnen alle union Komponenten an der gleichen Stelle Der Speicherplatz einer union ist also gleich dem Speicherplatz seiner gr ten Komponente Damit l t sich das Beispiel in C so schreiben include lt iostream h gt main union doppelt int i unsigned u d ee cout lt lt d u Ergebnis 65535 Nat rlich l t sich auch ein orthodoxer varianter Record in C direkt nachbilden Ihm entspricht eine struct der
182. zweiten Parameter wird der Vorgabewert eingesetzt Der Funktionswert ist B g 1L Der Parameter vom Typ long pa t auf die zweite Version Der Funktionswert ist UGH g 1L 2 Von der Anzahl der Parameter her kommt nur die erste Version von g in Frage Der erste Parameter wird nach int konvertiert Der Funktionswert ist B Beachten Sie da die Aufrufe g 1 und g 1L bei beiden Versionen von g korrekt w ren wenn es die jeweils andere nicht g be Sind beide vorhanden sucht sich der Compiler die passendere heraus nach folgendem etwas vereinfachten Schema Vereindeutigung eines Aufrufs berladener Funktionen 1 Stimmt die Parameterliste einer Version in Anzahl und Typ mit den Argumenten berein so wird sie ausgew hlt Da sich alle Varianten von berladenen Funktionen eindeutig an Hand der Anzahl oder Typen der Parameterliste unterscheiden m ssen kann es h chstens eine solche Variante geben 2 Gibt es beim ersten Schritt keine exakte bereinstimmung werden folgende Konvertierungen der Argumente vorgenommmen char nach int unsigned char nach int float nach double Jetzt wird wieder wie im ersten Schritt auf exakte bereinstimmung gepr ft 3 Gibt es beim zweiten Schritt immer noch keine exakte bereinstimmung wird versucht durch Standard Konvertierungen eine bereinstimmung herzustellen Gibt es hier mehrere M glichkeiten wird dies vom Compiler als Fehler eingestuft Viele Probleme lassen sich
Download Pdf Manuals
Related Search
Related Contents
医療関連企業のポートアイランド(第2期)への進出について 3G CAMERA USER MANUAL - Million Legend Technology Ltd Ergänzung Manual de instalación - Homocrisis by Toshiba Calefacción & Aire User and maintenance manual Benutzer electronic cuber model ec 105 CJ Series EtherNet/IP and FH Vision Systems Connection SP-1000 User & Service Manual Global Machinery Company TVisto User's Manual 2.5 プロフェット V 2.5 Copyright © All rights reserved.
Failed to retrieve file