// ============================================ // Checkpoint C: Dynamische Liste (Vector) // Lösung für Selbsttest nach Modul 5-6 // Implementierung wie C++ std::vector // ============================================ #include #include #include // ============================================ // 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; }