Files
programming-concepts-universal/exercises/checkpoint_c.c

318 lines
9.4 KiB
C

// ============================================
// Checkpoint C: Dynamische Liste (Vector)
// Lösung für Selbsttest nach Modul 5-6
// Implementierung wie C++ std::vector
// ============================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ============================================
// DATENSTRUKTUR: Vector (wie std::vector)
// ============================================
typedef struct {
int* data; // Pointer zum Array
int size; // Aktuelle Anzahl Elemente
int capacity; // Maximale Kapazität
} Vector;
// ============================================
// KONSTRUKTOR / DESTRUKTOR
// ============================================
// Erstellt neuen Vector mit gegebener Kapazität
Vector* vector_create(int initial_capacity) {
Vector* vec = malloc(sizeof(Vector));
if (!vec) return NULL;
vec->data = malloc(initial_capacity * sizeof(int));
if (!vec->data) {
free(vec);
return NULL;
}
vec->size = 0;
vec->capacity = initial_capacity;
return vec;
}
// Zerstört Vector und gibt Speicher frei
void vector_destroy(Vector* vec) {
if (vec) {
free(vec->data); // Array freigeben
free(vec); // Struct freigeben
}
}
// ============================================
// KAPAZITÄTS-MANAGEMENT
// ============================================
// Verdoppelt Kapazität wenn nötig (privat)
static void vector_grow(Vector* vec) {
if (vec->size >= vec->capacity) {
int new_capacity = vec->capacity * 2;
int* new_data = realloc(vec->data, new_capacity * sizeof(int));
if (new_data) {
vec->data = new_data;
vec->capacity = new_capacity;
printf("[Info] Kapazität erhöht: %d -> %d\n", vec->capacity / 2, vec->capacity);
}
}
}
// ============================================
// ELEMENT-OPERATIONEN
// ============================================
// Fügt Element am Ende hinzu
void vector_push_back(Vector* vec, int value) {
vector_grow(vec); // Automatisch wachsen
vec->data[vec->size] = value;
vec->size++;
}
// Entfernt letztes Element
int vector_pop_back(Vector* vec) {
if (vec->size == 0) {
printf("[Fehler] Vector ist leer!\n");
return -1;
}
vec->size--;
return vec->data[vec->size];
}
// Greift auf Element zu (mit Bounds-Check)
int vector_get(const Vector* vec, int index) {
if (index < 0 || index >= vec->size) {
printf("[Fehler] Index %d außerhalb [0, %d]!\n", index, vec->size - 1);
return -1; // Fehlerwert
}
return vec->data[index];
}
// Setzt Element (mit Bounds-Check)
void vector_set(Vector* vec, int index, int value) {
if (index < 0 || index >= vec->size) {
printf("[Fehler] Index %d außerhalb [0, %d]!\n", index, vec->size - 1);
return;
}
vec->data[index] = value;
}
// Fügt Element an Position ein (verschiebt Rest)
void vector_insert(Vector* vec, int index, int value) {
if (index < 0 || index > vec->size) {
printf("[Fehler] Ungültiger Index!\n");
return;
}
vector_grow(vec);
// Elemente verschieben
for (int i = vec->size; i > index; i--) {
vec->data[i] = vec->data[i - 1];
}
vec->data[index] = value;
vec->size++;
}
// Entfernt Element an Position
void vector_erase(Vector* vec, int index) {
if (index < 0 || index >= vec->size) {
printf("[Fehler] Ungültiger Index!\n");
return;
}
// Elemente verschieben
for (int i = index; i < vec->size - 1; i++) {
vec->data[i] = vec->data[i + 1];
}
vec->size--;
}
// Sucht Element, gibt Index zurück oder -1
int vector_find(const Vector* vec, int value) {
for (int i = 0; i < vec->size; i++) {
if (vec->data[i] == value) {
return i;
}
}
return -1;
}
// ============================================
// HILFSFUNKTIONEN
// ============================================
// Gibt aktuelle Größe zurück
int vector_size(const Vector* vec) {
return vec->size;
}
// Prüft ob leer
int vector_empty(const Vector* vec) {
return vec->size == 0;
}
// Leert den Vector (ohne Speicher freizugeben)
void vector_clear(Vector* vec) {
vec->size = 0;
}
// Gibt alle Elemente aus
void vector_print(const Vector* vec) {
printf("[");
for (int i = 0; i < vec->size; i++) {
printf("%d", vec->data[i]);
if (i < vec->size - 1) printf(", ");
}
printf("] (size=%d, capacity=%d)\n", vec->size, vec->capacity);
}
// ============================================
// TEST-FUNKTIONEN
// ============================================
void test_basic_operations() {
printf("\n=== TEST 1: Grundoperationen ===\n");
Vector* vec = vector_create(2);
printf("Push: 10, 20, 30\n");
vector_push_back(vec, 10);
vector_push_back(vec, 20);
vector_push_back(vec, 30); // Trigger grow
vector_print(vec);
printf("Get[1]: %d\n", vector_get(vec, 1));
printf("Set[1] = 25\n");
vector_set(vec, 1, 25);
vector_print(vec);
printf("Pop: %d\n", vector_pop_back(vec));
vector_print(vec);
vector_destroy(vec);
printf("✓ Test 1 bestanden\n\n");
}
void test_insert_erase() {
printf("=== TEST 2: Insert & Erase ===\n");
Vector* vec = vector_create(5);
vector_push_back(vec, 1);
vector_push_back(vec, 2);
vector_push_back(vec, 4);
vector_push_back(vec, 5);
printf("Vorher: ");
vector_print(vec);
printf("Insert 3 an Index 2\n");
vector_insert(vec, 2, 3);
vector_print(vec);
printf("Erase Index 1\n");
vector_erase(vec, 1);
vector_print(vec);
vector_destroy(vec);
printf("✓ Test 2 bestanden\n\n");
}
void test_edge_cases() {
printf("=== TEST 3: Edge Cases ===\n");
Vector* vec = vector_create(3);
printf("Leerer Vector: ");
vector_print(vec);
printf("Empty? %s\n", vector_empty(vec) ? "Ja" : "Nein");
printf("Pop auf leerem Vector:\n");
vector_pop_back(vec); // Sollte Fehler ausgeben
printf("Get mit ungültigem Index:\n");
int val = vector_get(vec, 0); // Sollte Fehler ausgeben
printf("Rückgabe: %d\n", val);
printf("Fill bis zur Kapazität\n");
for (int i = 1; i <= 10; i++) {
vector_push_back(vec, i);
}
vector_print(vec);
printf("Find 7: Index %d\n", vector_find(vec, 7));
printf("Find 99: Index %d\n", vector_find(vec, 99));
vector_destroy(vec);
printf("✓ Test 3 bestanden\n\n");
}
void test_clear() {
printf("=== TEST 4: Clear ===\n");
Vector* vec = vector_create(5);
for (int i = 0; i < 5; i++) {
vector_push_back(vec, i * 10);
}
printf("Vor clear: ");
vector_print(vec);
vector_clear(vec);
printf("Nach clear: ");
vector_print(vec);
printf("Nochmal befüllen:\n");
vector_push_back(vec, 100);
vector_print(vec);
vector_destroy(vec);
printf("✓ Test 4 bestanden\n\n");
}
// ============================================
// HAUPTPROGRAMM
// ============================================
int main() {
printf("╔══════════════════════════════════════════════════════════╗\n");
printf("║ CHECKPOINT C: DYNAMISCHE LISTE (LÖSUNG) ║\n");
printf("║ Eigene Vector-Implementierung wie C++ STL ║\n");
printf("╚══════════════════════════════════════════════════════════╝\n\n");
printf("Implementierte Funktionen:\n");
printf(" ✓ vector_create / vector_destroy\n");
printf(" ✓ vector_push_back (automatisch wachsen)\n");
printf(" ✓ vector_pop_back\n");
printf(" ✓ vector_get / vector_set (mit Bounds-Check)\n");
printf(" ✓ vector_insert / vector_erase\n");
printf(" ✓ vector_find\n");
printf(" ✓ vector_size / vector_empty / vector_clear\n");
printf(" ✓ vector_print\n\n");
// Alle Tests ausführen
test_basic_operations();
test_insert_erase();
test_edge_cases();
test_clear();
printf("╔══════════════════════════════════════════════════════════╗\n");
printf("║ ALLE TESTS BESTANDEN! ║\n");
printf("╠══════════════════════════════════════════════════════════╣\n");
printf("║ Lernziele erreicht: ║\n");
printf("║ ✓ Dynamische Arrays (malloc/realloc/free) ║\n");
printf("║ ✓ Automatische Kapazitätsverwaltung ║\n");
printf("║ ✓ Bounds-Checking für Sicherheit ║\n");
printf("║ ✓ Array-Elemente verschieben (insert/erase) ║\n");
printf("║ ✓ Modularer Aufbau (struct + Funktionen) ║\n");
printf("╚══════════════════════════════════════════════════════════╝\n");
return 0;
}