Add Checkpoint solution: checkpoint_c.c
This commit is contained in:
317
exercises/checkpoint_c.c
Normal file
317
exercises/checkpoint_c.c
Normal file
@@ -0,0 +1,317 @@
|
||||
// ============================================
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user