Zusammengesetzter Typ
Mit Arrays können Variablen gleichen Typs zusammengestellt werden. In der realen Welt gehören aber meist Daten unterschiedlichen Typs zusammen. So hat ein Auto einen Markennamen und eine Typbezeichnung, die als Zeichenkette unterzubringen ist. Dagegen eignet sich für Kilometerzahl und Leistung eher der Typ Integer. Für den Preis bietet sich der Typ float an. Bei bestimmten Autohändlern könnte auch double erforderlich sein. Alles zusammen beschreibt ein Auto.Modell
Vielleicht werden Sie einwerfen, dass ein Auto noch mehr Bestandteile hat. Da gibt es Bremsscheiben, Turbolader und Scheibenwischer. Das ist in der Realität richtig. Ein Programm interessiert sich aber immer nur für bestimmte Eigenschaften, die der Programmierer mit dem Kunden zusammen festlegt. Unser Beispiel würde für einen kleinen Autohändler vielleicht schon reichen. Eine Autovermietung interessiert sich vielleicht überhaupt nicht für den Wert des Autos, aber möchte festhalten, ob es für Nichtraucher reserviert ist. Eine Werkstatt dagegen könnte sich tatsächlich für alle Teile interessieren. Ein Programm, das die Verteilung der Firmenfahrzeuge verwaltet, interessiert sich vielleicht nur für das Kennzeichen. Es entsteht also ein Modell eines Autos, das bestimmte Bestandteile enthält und andere vernachlässigt, je nachdem was das Programm benötigt. Bereits in C gab es für solche Zwecke die Struktur, die mehrere Variablen zu einer zusammenfasst. Das Schlüsselwort für die Bezeichnung solch zusammengesetzter Variablen lautet struct. Nach diesem Schlüsselwort folgt der Name des neuen Typen. In dem folgenden geschweiften Klammernblock werden die Bestandteile der neuen Struktur aufgezählt. Diese unterscheiden sich nicht von der bekannten Variablendefinition. Den Abschluss bildet ein Semikolon.struct
Um ein Auto zu modellieren, wird ein neuer Variablentyp namens TAutoTyp geschaffen, der ein Verbund mehrerer Elemente ist.struct TAutoTyp // Definiere den Typ { char Marke[MaxMarke]; char Modell[MaxModell]; long km; int kW; float Preis; }; // Hier vergisst man leicht das Semikolon!
Syntaxbeschreibung
Das Schlüsselwort struct leitet die Typdefinition ein. Es folgt der Name des neu geschaffenen Typs, hier TAutoTyp. In dem nachfolgenden geschweiften Klammerpaar werden alle Bestandteile der Struktur nacheinander aufgeführt. Am Ende steht ein Semikolon, das man selbst als erfahrener Programmierer immer wieder einmal vergisst.Variablendefinition
Damit haben wir den Datentyp TAutoTyp geschaffen. Er kann in vieler Hinsicht verwendet werden wie der Datentyp int. Sie können beispielsweise eine Variable von diesem Datentyp anlegen. Ja, Sie können sogar ein Array und einen Zeiger von diesem Datentyp definieren.TAutoTyp MeinRostSammler; // Variable anlegen TAutoTyp Fuhrpark[100]; // Array von Autos TAutoTyp *ParkhausKarte; // Zeiger auf ein Auto
Elementzugriff
Die Variable MeinRostSammler enthält nun alle Informationen, die in der Deklaration von TAutoTyp festgelegt sind. Um von der Variablen auf die Einzelteile zu kommen, wird an den Variablenname ein Punkt und daran der Name des Bestandteils gehängt.// Auf die Details zugreifen MeinRostSammler.km = 128000; MeinRostSammler.kW = 25; MeinRostSammler.Preis = 25000.00;
Zeigerzeichen
Wenn Sie über einen Zeiger auf ein Strukturelement zugreifen wollten, müssten Sie über den Stern referenzieren und dann über den Punkt auf das Element zugreifen. Da aber der Punkt vor dem Stern ausgewertet wird, müssen Sie eine Klammer um den Stern und den Zeigernamen legen.TAutoTyp *ParkhausKarte = 0; // Erst einmal keine Zuordnung ParkhausKarte = &MeinRostSammler; // Nun zeigt sie auf ein Auto (*ParkhausKarte).Preis = 12500; // Preis für MeinRostSammler
Das mag zwar logisch sein, aber es ist weder elegant noch leicht zu merken. Zum Glück gibt es in C und C++ eine etwas hübschere Variante, über einen Zeiger auf Strukturelemente zuzugreifen. Dazu wird aus Minuszeichen und Größer-Zeichen ein Symbol zusammengesetzt, das an einen Pfeil erinnert.
ParkhausKarte->Preis = 12500;
L-Value
Strukturen sind L-Values. Sie können also auf der linken Seite einer Zuweisung stehen. Andere Strukturen des gleichen Typs können ihnen zugewiesen werden. Dabei wird die Quellvariable Bit für Bit der Zielvariable zugewiesen.TAutoTyp MeinNaechstesAuto, MeinTraumAuto; MeinNaechstesAuto = MeinTraumAuto;Trotzdem die beiden Strukturvariablen nach dieser Operation ganz offensichtlich gleich sind, kann man dies nicht einfach durch eine Anwendung des doppelten Gleichheitszeichen nachprüfen. Sie können bei Strukturen die Typdeklaration und die Variablendefinition zusammenfassen, indem der Name der Variablen direkt nach der geschweiften Klammer eingetragen wird.
struct // hier wird kein Typ namentlich festgelegt { char Marke[MaxMarke]; char Modell[MaxModell]; long km; int kW; float Preis; } MeinErstesAuto, MeinTraumAuto;Hier werden im Beispiel die Variablen MeinErstesAuto und MeinTraumAuto gleich mit ihrer Struktur definiert. Werden auf diese Weise gleich Variablen dieser Struktur gebildet, muss ein Name für den Typ nicht unbedingt angegeben werden. Damit ist dann natürlich keine spätere Erzeugung von Variablen dieses Typs möglich.
Initialisierung
Auch Strukturen lassen sich initialisieren. Dazu werden wie bei den Arrays geschweifte Klammern verwendet. Auch hier werden die Werte durch Kommata getrennt.TAutoTyp JB = {"Aston Martin", "DB5", 12000, 90, 12.95}; TAutoTyp GWB = {0};
Klassenähnlich
Die Struktur ist bereits mit C eingeführt worden und ist dort die einzige Möglichkeit, Datenverbünde zu definieren. In C++ werden zu diesem Zweck normalerweise Klassen eingesetzt, die allerdings wesentlich mehr können als die C-Strukturen. Schon aus Kompatibilität ist das Schlüsselwort in C++ noch vorhanden und wird auch erwartungsgemäß übersetzt. Allerdings kann eine Struktur in C++ wesentlich mehr. Sie ist dort so definiert, dass sie eine Klasse entspricht, deren Elemente öffentlich zugänglich sind.Im Buch befindet sich an dieser Stelle der Syntaxgraf von struct (grafstruct).
Den Syntaxgraf für VarDef finden Sie auf Seite (grafvardef). An dieser Stelle befinden sich also Variablendefinitionen. Dabei sind auch Arrays, Zeiger oder weitere Strukturen zulässig. Als Vars dürfen Variablen von der Struktur aufgezählt werden. Hier dürfen Zeiger und Arrays gebildet werden. Bei der Definition mehrerer Variablen müssen sie durch Komma getrennt werden.
Beispiel: Bermuda
Nachdem das Spielfeld modelliert wurde, sollen hier die Schiffe nachgebildet werden. Jedes Schiff hat eine x- und eine y"=Koordinate. Des Weiteren müssen Sie ein Schiff markieren können, wenn es gefunden wurde. Also brauchen wir noch eine boolesche Variable namens gefunden. Um das Schiff in dieser Form zusammenzusetzen, wird eine Struktur verwendet. Nach der Spielanleitung gibt es im Spiel insgesamt vier Schiffe, sodass ein Array von Strukturen angelegt werden muss.const int MaxSchiff=4; struct tSchiff { int x; int y; bool gefunden; }; tSchiff Schiff[MaxSchiff];
Im nächsten Schritt müssen die Schiffe versteckt werden. Natürlich dürfen wie bei den Lottozahlen nicht zwei Schiffe die gleiche Position haben. Demzufolge ist der Algorithmus sehr ähnlich. Hier sehen Sie das komplette Programm:
// Bermuda: Einführung der Strukturen #include <iostream> using namespace std; #include <stdlib.h> const int X=9; // Spielfeldausdehnung waagerecht const int Y=7; // Spielfeldausdehnung senkrecht const int MaxSchiff=4; // Anzahl der Schiffe struct tSchiff { // Nachbildung eines Schiffes int x; // Position waagerecht int y; // Position senkrecht bool gefunden; }; tSchiff Schiff[MaxSchiff]; // Unsere Flotte int main() { int i, j; // Zählervariablen bool neueZahl; // ist eine Position gefunden? srand(0); for(i=0; i<MaxSchiff; i++) // alle Schiffe { Schiff[i].gefunden = false; // Bestimmung der Position do { // Einmal Position würfeln Schiff[i].x = rand() % X; Schiff[i].y = rand() % Y; neueZahl = true; // Prüfe, ob eines der bisherigen Schiffe die // Position schon innehat for (j=0; j<i; j++) { if (Schiff[j].x==Schiff[i].x && Schiff[j].y==Schiff[i].y) { // Da saß schon eins! neueZahl = false; } } // erst bei neuer Position fertig } while (!neueZahl); } // Zur Kontrolle alle anzeigen for (i=0; i<MaxSchiff; i++) { cout << Schiff[i].x << "," << Schiff[i].y << " "; } cout << endl; }
Nun sind die Datenstrukturen für das Bermuda-Programm geschaffen.
Im nächsten Schritt wird es um das Gliedern der Funktionalität gehen.