Systempraktikum C - Klausur (Variante 2: Erweitert)

Zeit: 2,5 Stunden

Hilfsmittel: Manpages, ASCII-Tabelle

Hinweis: Alle Aufgaben sind in separaten Dateien zu bearbeiten. Makefiles und Header-Dateien sind vorhanden, sofern nicht explizit anders angegeben. Achten Sie auf eine saubere Code-Struktur, sinnvolle Kommentare und umfassende Fehlerbehandlung. Punkte werden nicht nur für die Funktionalität, sondern auch für die Codequalität vergeben. Überlegen Sie bei jeder Aufgabe, wie Sie Ihren Code robust und effizient gestalten können.

Aufgabe 1: Verkettete Liste (6 Punkte)

Datei: linked_list.c

Header: linked_list.h (enthält die Definition von struct node)

Implementieren Sie folgende Funktionen für eine einfach verkettete Liste:

 
struct node {
 
int x;
 
struct node *next;
 
};
 
 
 
void add_front(struct node **list, int x);
 
void add_back(struct node **list, int x);
 
int remove_value(struct node **list, int x); // NEU: Wert entfernen
 
void free_list(struct node **list); // NEU: Liste freigeben
 
  • add_front: Fügt ein neues Element mit dem Wert x am Anfang der Liste ein.
  • add_back: Fügt ein neues Element mit dem Wert x am Ende der Liste ein.
  • remove_value: Entfernt alle Elemente mit dem Wert x aus der Liste. Gibt die Anzahl der entfernten Elemente zurück. Achten Sie auf korrekte Speicherverwaltung!
  • free_list: Gibt den gesamten Speicher der Liste frei.

Zusatzaufgabe (2 Bonuspunkte): Implementieren Sie remove_value so, dass die Reihenfolge der übrigen Elemente erhalten bleibt.

Aufgabe 2: Zombie-Prozesse vermeiden (3 Punkte)

Datei: zombie.c

Schreiben Sie eine Funktion wait_for_all_children(), die sicherstellt, dass der aufrufende Prozess auf alle Kindprozesse wartet und Zombie-Prozesse vermieden werden. Die Funktion soll auch im Falle von Signalunterbrechungen korrekt funktionieren.

 
void wait_for_all_children(void);
 

Aufgabe 3: Dynamische Strukturen (4 Punkte)

Datei: composite.c

Header: composite.h (enthält die Definition von struct composite)

Gegeben sei folgende Struktur:

 
struct composite {
 
int x;
 
float y;
 
};
 

Implementieren Sie folgende Funktionen:

 
struct composite create_composite(int a, float b);
 
struct composite* add_composite(const struct composite *a, const struct composite *b);
 
void free_composite(struct composite *c); // NEU: Speicher freigeben
 
  • create_composite: Erstellt eine neue struct composite mit den Werten x = a und y = b und gibt diese by value zurück.
  • add_composite: Erstellt eine neue, dynamisch allozierte struct composite. Die Werte x und y der neuen Struktur sollen die Summe der entsprechenden Werte der übergebenen Strukturen a und b sein. Die Funktion gibt einen Zeiger auf die neue Struktur zurück oder NULL im Fehlerfall.
  • free_composite: Gibt den Speicher einer dynamisch allozierten struct composite frei.

Aufgabe 4: Pipes und String-Manipulation (5 Punkte)

Datei: pipe_string.c

Schreiben Sie eine Funktion transform_string, die einen String über eine Pipe empfängt, diesen in Großbuchstaben umwandelt und die Länge des transformierten Strings zurückgibt. Die Funktion soll die Pipe nicht selbst erstellen. Die Pipe-Deskriptoren werden als Parameter übergeben.

 
int transform_string(int read_fd, int write_fd);
 

Zusatzaufgabe (2 Bonuspunkte): Erweitern Sie die Funktion, sodass sie zusätzlich alle Leerzeichen aus dem String entfernt, bevor sie ihn in Großbuchstaben umwandelt.

Aufgabe 5: Sockets (6 Punkte)

Datei: socket_client.c

Schreiben Sie einen Client, der eine TCP-Verbindung zu einem Server aufbaut. Der Server erwartet nach dem Verbindungsaufbau einen String. Der Client soll einen vom Benutzer eingegebenen String an den Server senden und die Antwort des Servers auf der Konsole ausgeben. Verwenden Sie getaddrinfo() für die Adressauflösung. Die IP-Adresse und der Port des Servers werden als Kommandozeilenparameter übergeben. Achten Sie auf eine robuste Implementierung mit Fehlerbehandlung.

Zusatzaufgabe (2 Bonuspunkte): Implementieren Sie eine Schleife, die es dem Benutzer erlaubt, mehrere Nachrichten an den Server zu senden, ohne die Verbindung nach jeder Nachricht zu schließen. Die Verbindung soll erst beendet werden, wenn der Benutzer “exit” eingibt.

Aufgabe 6: Kommandozeilenargumente und Signale (5 Punkte)

Datei: signal_handler.c

Schreiben Sie ein Programm, das zwei Kommandozeilenargumente entgegennimmt: eine Prozess-ID (PID) und eine Signalnummer. Das Programm soll das angegebene Signal an den Prozess mit der angegebenen PID senden. Implementieren Sie außerdem einen Signal-Handler für das Signal SIGINT. Wenn das Programm SIGINT empfängt, soll es eine Nachricht auf der Konsole ausgeben und sich anschließend selbst beenden.

Zusatzaufgabe (2 Bonuspunkte): Überprüfen Sie, ob die als Kommandozeilenparameter übergebene PID gültig ist, bevor Sie das Signal senden. Geben Sie eine Fehlermeldung aus, falls die PID ungültig ist.

Aufgabe 7: Dateioperationen (4 Punkte)

Datei: file_stats.c

Schreiben Sie eine Funktion, die Informationen über eine Datei ausgibt. Der Dateiname wird als Kommandozeilenparameter übergeben. Die Funktion soll folgende Informationen ausgeben:

  • Dateigröße in Bytes
  • Letzter Änderungszeitpunkt (als lesbarer String)
  • Ob die Datei lesbar, schreibbar und/oder ausführbar ist.

Achten Sie auf Fehlerbehandlung.

Dieses erweiterte Klausurformat prüft nicht nur die grundlegenden Kenntnisse in C und Systemprogrammierung, sondern auch die Fähigkeit, robusten, effizienten und gut strukturierten Code zu schreiben. Viel Erfolg!# Übungsklausuren Overview

type: folder_brief_live
×

MyUniNotes is a free, non-profit project to make education accessible for everyone. If it has helped you, consider giving back! Even a small donation makes a difference.

These are my personal notes. While I strive for accuracy, I’m still a student myself. Thanks for being part of this journey!