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: 48
Mit 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.0
Groß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 95
enum: 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 5
union: 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 16
Bitfelder 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 8
Verkettete 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 -> NULL
Merke
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
Aufgabe
Lege eine Struktur Buch (Titel, Autor, Jahr) an, speichere drei Bücher in einem Array und sortiere sie nach Jahr.