Kurz: Eine struct fasst zusammengehörige Variablen verschiedener Typen unter einem Namen zusammen:
Teil des Kurses C
struct: Daten bündeln
Eine struct fasst zusammengehörige Variablen verschiedener Typen unter einem Namen zusammen:
#include <stdio.h>
#include <string.h>
struct Person {
char name[32];
int alter;
double gewicht;
};
int main(void) {
struct Person mia = { "Mia", 17, 58.5 };
struct Person tom = { .name = "Tom", .alter = 19 }; // benannte Initialisierung, Rest = 0
mia.alter++;
strcpy(tom.name, "Tom K.");
printf("%s %d %.1f\n", mia.name, mia.alter, mia.gewicht);
printf("%s %d %.1f\n", tom.name, tom.alter, tom.gewicht);
struct Person kopie = mia; // Struktur komplett kopieren
kopie.alter = 99;
printf("%d %d\n", mia.alter, kopie.alter);
printf("Größe: %zu\n", sizeof(struct Person));
return 0;
}Ausgabe:
Mia 18 58.5
Tom K. 19 0.0
18 99
Größe: 48Mit typedef bekommt der Typ einen kürzeren Namen:
#include <stdio.h>
#include <math.h>
typedef struct {
double x, y;
} Punkt;
typedef struct {
Punkt links_oben;
double breite, hoehe;
} Rechteck;
double abstand(Punkt a, Punkt b) { return hypot(a.x - b.x, a.y - b.y); }
double flaeche(const Rechteck *r) { return r->breite * r->hoehe; } // -> bei Zeigern
int main(void) {
Punkt a = {0, 0}, b = {3, 4};
Rechteck r = { {1, 2}, 5, 3 };
printf("%.1f %.1f %.1f\n", abstand(a, b), flaeche(&r), r.links_oben.y);
return 0;
}Ausgabe:
5.0 15.0 2.0Große Strukturen übergibst du als const Struktur * (kein Kopieren); p->feld ist die Kurzform von (*p).feld. (Zum Linken von math.h kann -lm nötig sein.)
Arrays von Strukturen
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct { char name[16]; int punkte; } Spieler;
static int nach_punkten(const void *a, const void *b) {
return ((const Spieler *) b)->punkte - ((const Spieler *) a)->punkte; // absteigend
}
int main(void) {
Spieler liste[] = { {"Mia", 120}, {"Tom", 95}, {"Zoe", 210} };
int n = sizeof liste / sizeof liste[0];
qsort(liste, n, sizeof liste[0], nach_punkten);
for (int i = 0; i < n; i++) printf("%d. %-4s %3d\n", i + 1, liste[i].name, liste[i].punkte);
return 0;
}Ausgabe:
1. Zoe 210
2. Mia 120
3. Tom 95enum: benannte Konstanten
#include <stdio.h>
enum Ampel { ROT, GELB, GRUEN }; // 0, 1, 2
typedef enum { MO = 1, DI, MI, DO, FR } Tag; // 1, 2, 3, ...
const char *name(enum Ampel a) {
switch (a) {
case ROT: return "rot";
case GELB: return "gelb";
case GRUEN: return "grün";
}
return "?";
}
int main(void) {
enum Ampel a = GELB;
Tag t = MI;
printf("%s %d %d %d\n", name(a), a, t, FR);
return 0;
}Ausgabe:
gelb 1 3 5union: ein Speicherplatz, mehrere Sichten
Alle Felder einer union liegen am selben Speicherplatz. Es ist nur eines davon gleichzeitig gültig. Üblich ist die Kombination mit einem Kennzeichen (tagged union):
#include <stdio.h>
typedef struct {
enum { ZAHL, TEXT } art;
union { int zahl; const char *text; } wert;
} Wert;
void zeige(Wert w) {
if (w.art == ZAHL) printf("Zahl %d\n", w.wert.zahl);
else printf("Text %s\n", w.wert.text);
}
int main(void) {
Wert a = { ZAHL, .wert.zahl = 42 };
Wert b = { TEXT, .wert.text = "Hallo" };
zeige(a); zeige(b);
printf("%zu\n", sizeof(Wert));
return 0;
}Ausgabe:
Zahl 42
Text Hallo
16Bitfelder und Ausrichtung
Der Compiler fügt zwischen Feldern oft Füllbytes (Padding) ein, damit Felder an passenden Adressen liegen. Die Reihenfolge der Felder beeinflusst die Größe:
#include <stdio.h>
#include <stddef.h>
struct Schlecht { char a; int b; char c; }; // a, 3 Füllbytes, b, c, 3 Füllbytes
struct Besser { int b; char a; char c; };
int main(void) {
printf("%zu %zu\n", sizeof(struct Schlecht), sizeof(struct Besser));
printf("%zu %zu\n", offsetof(struct Schlecht, b), offsetof(struct Schlecht, c));
return 0;
}Ausgabe:
12 8
4 8Verkettete Liste: Struktur mit Zeiger auf sich selbst
#include <stdio.h>
#include <stdlib.h>
typedef struct Knoten {
int wert;
struct Knoten *weiter;
} Knoten;
Knoten *vorne(Knoten *kopf, int wert) {
Knoten *k = malloc(sizeof *k);
if (!k) return kopf;
k->wert = wert;
k->weiter = kopf;
return k;
}
int main(void) {
Knoten *liste = NULL;
for (int i = 1; i <= 4; i++) liste = vorne(liste, i * 10);
for (Knoten *k = liste; k; k = k->weiter) printf("%d -> ", k->wert);
printf("NULL\n");
while (liste) { Knoten *n = liste->weiter; free(liste); liste = n; } // aufräumen
return 0;
}Ausgabe:
40 -> 30 -> 20 -> 10 -> NULLMerke
structbündelt Felder; Zugriff mit.bzw.->bei Zeigerntypedefgibt Typen kürzere Namen; Strukturen lassen sich kopieren und per Zeiger übergebenenumfür benannte Ganzzahl-Konstanten;unionteilt sich einen Speicherplatz- Füllbytes machen Strukturen oft größer, als die Felder vermuten lassen
- Verkettete Strukturen entstehen mit Zeigern auf den eigenen Typ
Übungsaufgabe
Lege eine Struktur Buch (Titel, Autor, Jahr) an, speichere drei Bücher in einem Array und sortiere sie nach Jahr.
Quiz zur Selbstkontrolle
Wie greifst du auf ein Feld über einen Strukturzeiger p zu?
- p->feld (richtig)
- p.feld
- p::feld
- *p.feld
Was ist besonders an einer union?
- Alle Felder teilen sich denselben Speicherplatz (richtig)
- Sie vereint zwei Dateien
- Sie ist schneller als struct
- Sie hat keine Felder
Wofür ist typedef?
- Für einen neuen Namen eines Typs (richtig)
- Zum Definieren einer Funktion
- Zum Löschen von Typen
- Für Konstanten
Weiter im Kurs
Zurück: Zeiger
Weiter: Dynamischer Speicher
Alle Kapitel: C im Überblick