Strukturen

Melting Pot der Programmierung

Das Kapitel über Strings muss dich bestimmt empört haben. Da stellt sich doch heraus, dass im Geheimen ein weiterer Datentyp existiert hat! Und du wirst noch viel schockierter sein: Tatsächlich haben wir dir eine ganze Menge mehr Datentypen verschwiegen. Um genau zu sein: unendlich viele sogar. 


Wir hoffen, du wirst Verständnis haben, wenn wir die nicht alle aufzählen können. Brauchen wir aber auch nicht. Denn eigentlich meinen wir damit, dass du als Programmierer selbst die Möglichkeit hast, neue Datentypen zu definieren – jeden erdenklichen. Sei es ein Datentyp „auto“, ein Datentyp „pferd“ oder ein Datentyp „komplexe Zahl“. Und wie das geht, wollen wir dir in diesem Kapitel über „Strukturen“ näher bringen.


Ein neuer Datentyp ist dabei im Grunde nicht gänzlich neu, sondern viel eher eine Kombination aus den uns bereits vorhandenen elementaren Datentypen. Dir sind also gewissermaßen Schrauben, Muttern und Metallplatten gegeben, baust sie aber zu einem komplexeren Bauteil zusammen, das anschließend Verwendung in einer größeren Maschine findet. Und genau so verhält es sich auch mit Strukturen. Strukturen sind eine Zusammenfassung mehrerer Komponenten zu einem komplexen Datentyp. 


Ähnlich wie Funktionen werden Strukturen außerhalb des main-Programms definiert. Dies geschieht nach folgendem Muster:


    struct Strukturname {

        Datentyp1 komponente1;

        Datentyp2 komponente2;

    };


Da die abstrakte Syntax nicht immer zwangsläufig zu einer Eingebung führt, wollen wir uns das Definieren einer Struktur mal an einem Beispiel vorführen. Lass uns dafür einen Datentyp „person“ anlegen:


    struct person {

        string name;

        string vorname;

        int alter;

        int ausweisnummer;

        char geschlecht;

    };


Eine Struktur wird also immer durch das Schlüsselwort „struct“ eingeleitet, ehe der selbst gewählte Name sowie die Liste an Komponenten folgt. Hast du das eingegeben, kannst du dich eigentlich schon zurücklehnen: Denn mehr braucht man beim Anlegen eines komplexen Datentyps nicht zu beachten. 


Im Hauptprogramm kannst du nun ebenso wie für Integer-, Float- oder Character-Werte Variablen deines komplexen Datentyps anlegen:

    person p1;


Auf die Nennung des Datentyps folgt wie gewohnt der Variablenname. Spannender gestaltet sich da die konkrete Wertzuweisung. Denn anders als gewöhnliche Datentypen bestehen Strukturen aus einer ganzen Liste an Komponenten. Jeder einzelnen kann ein entsprechender Wert zugewiesen werden – das pfiffige Hilfsmittel, das uns dies ermöglicht, nennt sich „Punktoperator“:

    p1.name=“von Seestern“;

    p1.vorname=“Katrielle“;

    p1.alter=22;

    p1.ausweisnummer=3114;

    p1.geschlecht='w';


Auch ein Array kann als Strukturkomponente fungieren. Der Zugriff auf die Arrayelemente erfolgt dabei wie gewohnt mit dem Indexoperator „[ ]“. Und wo wir gerade bei Arrays sind: Genauso wie wir ein Array für int- oder float-Werte anlegen konnten, ist es uns nun auch möglich, ein Array für unsere komplexen Datentypen anzulegen:

    person liste[100];


Das Deklarieren eines Arrays beginnt dabei wieder mit dem Datentyp, gefolgt von dem Arraynamen und der Maximalzahl an Elementen in eckigen Klammern. Da stauen sich nun 100 Strukturen des Typs „person“ in unserem Array. Wie greift man aber auf eine Struktur an einer gewissen Indexposition zu – und noch viel wichtiger: Wie weist man ihren Komponenten Werte zu?


Dies folgt alles einer bestimmten Logik. Bei normalen Datentypen konnten wir mittels array[i] auf einen Wert an der Indexposition i zugreifen. Und auch bei Strukturen ändert sich an der Syntax zunächst nichts Grundlegendes. Auf die i-te Struktur greift man mit liste[i] zu. Das Element, das sich hinter „liste[i]“ verbirgt, ist nun aber ein komplexes – es besteht aus mehreren Komponenten. Diesen Komponenten wird wieder mittels des Punktoperators ein Wert zugewiesen. Sprich: An Position i erhält die Komponente n der Struktur den und den Wert. In der C++-Syntax heißt dies:

    liste[0].name=“Petrovich“;

    liste[7].alter=45;

    liste[18].geschlecht='m';


Wie Strukturen in einem Array gelagert sind, verdeutlicht dir diese Grafik:

Als Komponenten einer Struktur sind nicht nur die elementaren Datentypen verwendbar, sondern auch andere Strukturen. Mit anderen Worten, es ist möglich, Strukturen miteinander zu verschachteln. Schaue dir dazu folgendes Beispiel an:


    struct adresse {

        string straße;

        int hausnummer;

        int plz;

        string ort;

    };


    struct person {

        string name;

        string vorname;

        int alter;

        int ausweisnummer;

        char geschlecht;

        adresse adr;

    };

Die Struktur „Person“ verwendet als Komponente die Struktur „Adresse“. Um die Komponente „Adresse“ mit Werten belegen zu können, erfolgt eine doppelte Verwendung des Punktoperators. Macht zunächst einen verwirrenden Eindruck, lässt sich aber in Wirklichkeit einfach realisieren. Überzeuge dich selbst:


    person p1;

    p1.name=“Schmidt“;

    p1.adr.ort=“München“;

Bei der Wertzuweisung in verschachtelten Strukturen gehst du im Prinzip wie in einem Dateiverzeichnis vor: Innerhalb der Struktur Person öffnest du die die Struktur Adresse. In der Struktur Adresse greifst du auf die Komponente „ort“ zu. Exakt nach diesem Schema funktionieren unsere verschachtelten Strukturen.


Mit Strukturen gelingt dir also das Zusammenfassen von Datensätzen zu einem völlig neuen, komplexen Typ – ein „melting pot“ der Programmierung gewissermaßen. Strukturen verleihen deinem Programm deswegen – nun ja – Struktur eben. 

Aufgaben: Strukturen

A1: Quiz dich schlau!

Created with Sketch.

Nachfolgend sind einige Fragen aufgeführt, die du nach diesem Abschnitt beantworten können solltest:

(1) Wofür werden Strukturen in C++ eingesetzt?

(2) Wie definiert man syntaktisch eine Struktur?

(3) Wie greift man auf eine einzelne Komponente einer bestimmten Struktur zu?

A2: Fuhrpark

Created with Sketch.

Ein Autohändler möchte eine Inventur seines derzeitigen Bestandes machen. Schreibe hierfür bitte ein Programm zur Kategorisierung von Kraftfahrzeugen mittels einer struct-Definition, die folgende Punkte erfassen soll:
- Kennzeichen
- Automarke
- Farbe
- Preis (Brutto und Netto)
- E-Fahrzeug? ja-nein

Weiterhin soll diese definierte Struktur für folgende Funktionen verwendet werden:
- die Liste aller Fahrzeugdaten ausgeben
- Daten eines Autos erfassen und speichern
- alle Daten eines Fahrzeuges für ein gegebenes Kennzeichen, einschließlich der Differenz Brutto-Netto Preis ausgeben

A3: Veranstaltungsverwaltung

Created with Sketch.

Langsam werden unsere Programme größer. So auch das folgende.
Eine Konzertagentur benötigt ein C++‐Programm zur Verwaltung von Konzertdaten. Dazu muss eine Struktur entwickelt werden, die folgende Daten aufnehmen kann:
- Name des Künstlers
- Name des Konzerts
- Preis
- Datum (Tag, Monat, Jahr)
- Ort

Hinweis: Bitte in den Beispielen nur Bezeichnungen verwenden, die aus einem Wort bestehen, also keine Namen und Konzertbezeichnungen, die Leerzeichen enthalten.

Die Datensätze sollen in einem Array verwaltet werden. Es sollen bis zu 200 Datensätze mit Konzertdaten gespeichert werden können.

Teil a) Kannst du bitte die Struktur (unter der Bezeichnung event) entwickeln, die zur Speicherung eines Datensatzes für eine Veranstaltung eingesetzt werden kann. Insgesamt sollen in dem Programm bis zu 200 Datensätzen mit Konzertdaten gespeichert werden. Wie sieht die Datenstruktur dafür aus?

Teil b) Schreib bitte anschließend eine Funktion
void printAllEvents(event list[], int evcount);
die alle gespeicherten Datensätze auf den Bildschirm ausgibt. In dem Array list sind die Datensätze gespeichert, die Variable evcount gibt an, wie viele Datensätze dort bereits vorhanden sind.
(Hinweis: Oben ist die Signatur der Funktion gegeben, die Sie implementieren sollen.)

Teil c) Schreib bitte eine Funktion
int readEvents(event list[], int evcount);
die genau einen Datensatz einliest und am Ende des schon vorhandenen Arrays speichert.
Die Anzahl der anschließend in der Liste gespeicherten Elemente soll als Rückgabewert der Funktion zurückgegeben werden.

Teil d) Schreibe bitte jetzt die main‐Funktion mit einem kleinen Menü zur Auswahl der Funktionen. Diese kannst du zum Test der bereits programmierten Funktionen einsetzen.

Teil e) Schreib bitte zur Verwaltung von Konzertdaten folgende weiteren Funktionen. In der Aufgabenstellung ist jeweils die Signatur angegeben, Diese Funktionen sollen implementieren werden.
void printEventsForCity(event list[], int evcount, string city);
Die Funktion soll alle Veranstaltungen ausgeben, an einem gegebenen Ort stattfinden. Die Ortsangabe soll Eingabeparameter für die Funktion sein. Die Ausgabe soll in der Funktion programmiert werden, es sollen die Informationen Datum und Künstler angezeigt werden.
void printEventsForArti(event list[], int evcount, int month, int year, string city);
Es sollen alle Veranstaltungen ausgegeben werden, die an einem gegebenen Ort in einem gegebenen Monat und Jahr stattfinden. Die Informationen (Datum, Künstler, Programm) sollen dabei angezeigt werden.

Musterlösungen

L1: Quiz dich schlau!

Created with Sketch.

(1) Zusammenfassung mehrerer Werte zu einem Datensatz; Kategorisierung von Daten

(2) struct name {
         datentyp komponente1;
         datentyp komponente2;
      };


(3) mithilfe des Punktoperators: variable.komponente

L2: Fuhrpark

Created with Sketch.

L3: Veranstaltungsverwaltung

Created with Sketch.

#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>

using namespace std;

typedef struct {
    string artist;
    string concert;
    float preis;
    int year;
    int month;
    int day;
    string city;
} ev;

void printEvents(ev list[], int evnumberElemente) {
    int i;
    cout << endl << " Veranstaltungen " << endl << endl;
    for (i = 0; i < evnumberElemente; i++) {
        cout << setw(12) << list[i].artist;
        cout << setw(15) << list[i].concert;
        cout << setw(10) << list[i].city;
        cout << setw(3) << list[i].day;
        cout << setw(3) << list[i].month;
        cout << setw(5) << list[i].year;
        cout << setw(6) << "  Preis: " << list[i].preis << " Euro " << endl;
    }
    return;
}

int readEvents(ev list[200], int evnumberElemente) {
    char answer;
    do {
        cout << endl << "Bitte einen Kuenstlernamen eingeben: ";
        cin >> list[evnumberElemente].artist;

        cout << endl << " Bitte einen Konzertname eingeben: ";
        cin >> list[evnumberElemente].concert;
        cout << endl << " Bitte einen Ort eingeben: ";
        cin >> list[evnumberElemente].city;
        cout << endl << " Bitte ein Datum eingeben:  (day month year) ";
        cin >> list[evnumberElemente].day;
        cin >> list[evnumberElemente].month;
        cin >> list[evnumberElemente].year;
        cout << endl << " Bitte den Preis eingeben: ";
        cin >> list[evnumberElemente].preis;

        evnumberElemente++;
        cout << endl << endl << "\n\n Weiteren Datensatz eingeben? (j/n) ";
        fflush(stdin);
        cin >> answer;
    } while (answer != 'n');
    return(evnumberElemente);
}

void writeEventsInFile(string dateiname,
    ev list[], int evnumberElemente) {   
    fstream evFile;    
    int i;

    evFile.open(dateiname, ios::out);   
    if (evFile){    
        for (i = 0; i<evnumberElemente; i++) {  
            evFile << list[i].artist << " ";   
            evFile << list[i].concert << " ";
            evFile << list[i].city << " ";
            evFile << list[i].day << " " << list[i].month << " " << list[i].year << " ";
            evFile << list[i].preis << endl;
        }
    }
    evFile.close(); 
    return;
}

int readEventsFromFile(string dateiname, ev list[]) {      
    fstream evFile;          
    int i = 0; 
    evFile.open(dateiname, ios::in);    
    if (!evFile) {
        return(0);
    } 
   else{
       do {
           evFile >> list[i].artist;     
           evFile >> list[i].concert;
           evFile >> list[i].city;
           evFile >> list[i].day;
           evFile >> list[i].month;
           evFile >> list[i].year;
           evFile >> list[i].preis;
           i++;
       } while (!evFile.eof());   
       evFile.close();       
       return(i - 1); 
    }
}

void printEventsForCity(ev list[], int evnumber, string city) {
   cout << endl << endl << "Veranstaltungen in " << city << ":" << endl;

    for (int i = 0; i<evnumber; i++) {
        // Vergleich mit Citysangabe beim Konzert

        if (city == list[i].city) {
            cout << setw(12) << list[i].artist;
            cout << setw(15) << list[i].concert;
            cout << setw(3) << list[i].day << setw(3) <<
            list[i].month << setw(5) << list[i].year << endl;
        }
    }
}

void printEventsForCityAndDate(ev list[], int evnumber, string city, int month, int year) {
    cout << endl << endl << "Veranstaltungen in " << city << ":" << endl;

    for (int i = 0; i<evnumber; i++) {
        // Vergleich mit Citysangabe beim Konzert

        if ((city == list[i].city) && (list[i].month == month) && (list[i].year== year)) {
            cout << setw(12) << list[i].artist;
            cout << setw(15) << list[i].concert;
            cout << setw(3) << list[i].day << setw(3) <<
            list[i].month << setw(5) << list[i].year << endl;
        }
    }
}

void printEventsForArtist(ev list[], int evnumber, string artist) {
    cout << endl << endl << "Veranstaltungen von " << artist << ":" << endl;
    for (int i = 0; i<evnumber; i++) {
        // Vergleich mit Künstlernamen beim Konzert
        if (list[i].artist.find(artist)!=-1) {
            cout << setw(10) << list[i].city;
            cout << setw(15) << list[i].concert;
            cout << setw(3) << list[i].day << setw(3) <<
            list[i].month << setw(5) << list[i].year << endl;
        }
    }
}

int countEventsForArtist(ev list[], int evnumber, string artist) {
    int counter = 0;
    for (int i = 0; i<evnumber; i++) {
        // Vergleich mit Künstlernamen beim Konzert
        if (list[i].artist.find(artist) !=-1) {
            counter++;
        } 
    }
    return(counter);
}

int main() {
    string dateiname = "events.txt";
    ev list[200];
    int evnumber = 0;
    char antwcity;
    int auswahl;
    string artist, city;
    int month, year; 

    evnumber = readEventsFromFile(dateiname, list);

    do {
        cout << endl << endl << " 1 - Ausgabe aller Veranstaltungen" << endl;
        cout << " 2 - Ausgabe aller Veranstaltungen eines Kuenstlers" << endl;
        cout << " 3 - Ausgabe aller Veranstaltungen in einer Stadt" << endl;
        cout << " 4 - Ausgabe aller Veranstaltungen in einer Stadt zu einem Termin" << endl;
        cout << " 5 - Eingabe einer weiteren Veranstaltung" << endl;
        cout << endl;
        cout << "     Ihre Auswahl (Ende mit 0)   ";
        cin >> auswahl;

        if (auswahl == 1) {
            printEvents(list, evnumber);
        }
        else if (auswahl == 2) {
            cout << "Gesuchten Kuenstler eingeben: ";
            cin >> artist;
            printEventsForArtist(list, evnumber, artist);
            cout << endl << "   Der Kuenstler hat " <<  countEventsForArtist(list, evnumber, artist) << " Veranstaltung(en) " << endl;
        }

        else if (auswahl == 3) {
            cout << "Gesuchten Ort eingeben: ";
            cin >> city;
            printEventsForCity(list, evnumber, city);
        }
        else if (auswahl == 4) {
            cout << "Gesuchten Ort eingeben: ";
            cin >> city;
            cout << "Gesuchten Monat eingeben: ";
            cin >> month;
            cout << "Gesuchtes Jahr eingeben: ";
            cin >> year;
            printEventsForCityAndDate(list, evnumber, city, month, year);
        }
       else if (auswahl == 5) {
           evnumber = readEvents(list, evnumber);
           printEvents(list, evnumber);
        }
    } while (auswahl != 0);

    printEvents(list, evnumber);

    cout << "Datenbestand wurde in die Datei gespeichert";
    writeEventsInFile(dateiname, list, evnumber);
    return(0);
}

Fragen, Anregungen?

Ist etwas unverständlich oder du hast Fragen zu einem Thema, Aufgabe oder einfach zur C++-Welt? 
Dann schreibe uns einfach eine Mail!