Seitenleiste

Wiki

Community

Datentypen

Zählbare

Fließkomma

Datenstrukturen

Attribute

Speicherklassen

Typqualifizierer

Strukturen

Mit Strukturen kann man aus mehreren vorhandenen Datentypen neue Datentypen definieren. Doch wozu können wir so etwas brauchen? Ein einfaches Beispiel sollte dies verdeutlichen:
Für eine Bank sollen wir ein einfaches Programm zur Verwaltung der Konten ihrer Kunden schreiben. Dabei hat jeder Kunde einen Vor- und einen Nachnamen, eine Kontonummer und einen Kontostand.
Mit dem bisher gelernten wäre das nur sehr unsauber lösbar. Wir könnten zum Beispiel für jede dieser Daten ein Array des entsprechenden Datentyps anlegen und dann die Daten eines Kunden in alle Arrays an die Stelle mit dem selben Index schreiben. Das das keine schöne Lösung ist dürfte uns sehr schnell klar werden. Aber mit Strukturen gibt es dafür eine sehr elegante Lösung. Wir können uns damit einfach einen neuen Datentyp 'Bankkunde' definieren der alle Daten beinhaltet, und dann einfach ein großes Array mit Kunden anlegen.

Definition

Einen neuen Datentyp in Form einer Struktur erstellen wir mit dem Schlüsselwort 'struct' gefolgt vom gewünschten Namen der Struktur, nach dem in einem mit geschwungenen Klammer begrenzten Block die Variablen aufgelistet werden, die die Struktur beinhalten soll:

struct NameDesNeuenDatentyps
{
  Datentyp Variable;
  // ... (weitere Variablen)
};

Um das ganze noch besser zu verstehen schauen wir uns jetzt noch an wie das bei unserem Beispiel mit den Bankkunden ausschauen könnte:

struct BankKunde
{
  char *vorname_;
  char *nachname_;
  int   kontonummer_;
  int   kontostand_;
};

Wichtig ist bei der Definition einer Struktur auch das abschließende Semikolon, da wir sonst einen Compilerfehler erhalten würden.

Deklaration

Wir haben jetzt zwar einen neuen Datentyp erstellt, aber verwenden sollten wir ihn natürlich auch noch. Das ist eigentlich gar nicht weiter schwierig, da wir Strukturen gleich wie alle eingebauten Datentypen verwenden können:

struct BankKunde  ein_kunde;          // einen Kunden instanzieren
struct BankKunde  viele_kunden[123];  // ein Array von Kunden deklarieren
struct BankKunde *zeiger_auf_kunde;   // einen Zeiger auf einen Kunden deklarieren
zeiger_auf_kunde = &ein_kunde; // und auch gleich die Adresse von ein_kunde speichern

Zugriff auf Membervariablen

Die Variablen die wir innerhalb der Struktur definiert haben nennt man auch Membervariablen. Da wir diese natürlich auch verwenden wollen gibt es den sogenannten Strukturoperator (.), mit dem man einfach auf die Membervariabelen zugreifen kann und sie auch wie jede andere „normale“ Variable verwenden kann:

char vorname[]  = "Max";
char nachname[] = "Muster";
 
ein_kunde.vorname_  = malloc( strlen(vorname ) + 1 ); // Speicher für Vor- und Nachname
ein_kunde.nachname_ = malloc( strlen(nachname) + 1 ); // reservieren (mit abschließendem '\0')
 
strcpy( ein_kunde.vorname_,  vorname  ); // Vor- und Nachname in die entsprechenden
strcpy( ein_kunde.nachname_, nachname ); // Membervariablen der Struktur kopieren.
 
ein_kunde.kontostand_ = 1000; // Kontostand setzen
 
printf("Kontostand: %d\n", ein_kunde.kontostand_); // Kontostand ausgeben
 
viele_kunden[12].kontonummer_ = 123928;
viele_kunden[13].kontostand_ += 1300;

Wenn man jetzt aber einen Zeiger auf eine Struktur hat, dann kann man nicht direkt mit dem Strukturoperator auf die Membervariablen zugreifen, sondern muss den Zeiger mit dem Dereferenzierungsoperator (*) dereferenzieren:

(*zeiger_auf_kunde).kontostand_ = 0; // Klammern sind wichtig, da . in der Rangfolge vor * ist.

Da das für den Programmierer zu aufwändig war hat man einen neuen Operator eingeführt, der den Zugriff vereinfacht. Dieser Operator der wegen seiner Funktion bzw. Form auch Zeigeroperator (->) genannt wird können wir wie folgt verwenden:

zeiger_auf_kunde->kontostand_ = 1110; // Jetzt mit Zeigeroperator

Zusammenfassung

Wie wir gesehen haben sind Strukturen sehr praktisch um zusammenhängende Daten einfacher zu verwenden und auch als solche zu kennzeichnen. Da Strukturen sich fast wie die normalen eingebauten Datentypen verhalten, kann man sie auch als Funktionsargumente verwenden und somit auch die Funktionsköpfe durch einsparen von Parametern kürzer machen. Da Strukturen auch oft sehr groß werden können lohnt sich meistens die Übergabe mit Zeiger oder Referenz.


Autorendiskussion