diff --git a/stack.c b/stack.c index e3a90d4..ddf0437 100644 --- a/stack.c +++ b/stack.c @@ -11,13 +11,56 @@ StackNode *push(StackNode *stack, void *data) { + // 1. Einen neuen StackNode erstellen + StackNode *newNode = (StackNode *)malloc(sizeof(StackNode)); + + // Überprüfen, ob die Speicherreservierung erfolgreich war + if (newNode == NULL) + { + // Wenn malloc fehlschlägt, geben wir NULL zurück, um einen Fehler anzuzeigen. + return NULL; + } + + // 2. Die Daten in den neuen Knoten legen + newNode->data = data; + + // 3. Den 'next'-Zeiger des neuen Knotens auf den aktuellen Stack-Top setzen + // Der neue Knoten zeigt nun auf das Element, das zuvor ganz oben war. + newNode->next = stack; + + // 4. Den neuen Knoten als neuen Stack-Top zurückgeben + // Er ist jetzt das oberste Element. + return newNode; } // Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be // freed by caller.) StackNode *pop(StackNode *stack) { +// 1. Überprüfen, ob der Stack leer ist + if (stack == NULL) + { + // Wenn der Stack leer ist, gibt es nichts zu entfernen. + // Wir geben NULL zurück, da der Stack immer noch leer ist. + return NULL; + } + // 2. Einen Zeiger auf das aktuelle oberste Element speichern + // Dieses Element wollen wir entfernen und dessen Speicher freigeben. + StackNode *oldTop = stack; + + // 3. Den Stack-Zeiger auf das nächste Element im Stack setzen + // Das Element, das unter dem alten Top lag, wird jetzt zum neuen Top. + StackNode *newTop = stack->next; + + // 4. Den Speicher des alten obersten Elements freigeben + // Wichtig: Die Daten, auf die oldTop->data zeigt, werden hier NICHT freigegeben. + // Das muss, wie in der .h-Datei beschrieben, vom Aufrufer erledigt werden, + // falls die Daten dynamisch alloziert wurden. + free(oldTop); + + // 5. Den neuen Stack-Top zurückgeben + return newTop; } // Returns the data of the top element. @@ -30,4 +73,4 @@ void *top(StackNode *stack) void clearStack(StackNode *stack) { -} \ No newline at end of file +} diff --git a/test_stack.c b/test_stack.c new file mode 100644 index 0000000..b919500 --- /dev/null +++ b/test_stack.c @@ -0,0 +1,196 @@ +#include // Für printf +#include // Für malloc, free +#include "stack.h" // Für die Stack-Funktionen und -Strukturen + +// Globale Zähler für die Testergebnisse +int test_count = 0; +int test_failed = 0; + +// Hilfsfunktion für Assertionen +void assert_equals_int(int expected, int actual, const char *test_name) { + test_count++; + if (expected == actual) { + printf(" [PASS] %s\n", test_name); + } else { + printf(" [FAIL] %s - Erwartet: %d, Tatsächlich: %d\n", test_name, expected, actual); + test_failed++; + } +} + +void assert_equals_ptr(void *expected, void *actual, const char *test_name) { + test_count++; + if (expected == actual) { + printf(" [PASS] %s\n", test_name); + } else { + printf(" [FAIL] %s - Erwartet: %p, Tatsächlich: %p\n", test_name, expected, actual); + test_failed++; + } +} + +// Hilfsfunktion zum Freigeben der Daten im Stack, bevor der Stack selbst geleert wird +void free_stack_data(StackNode *stack) { + StackNode *current = stack; + while (current != NULL) { + if (current->data != NULL) { + free(current->data); // Freigabe der Integer-Daten + current->data = NULL; // Optional: Pointer auf NULL setzen + } + current = current->next; + } +} + +// --- Testfälle --- + +void test_push_single_element() { + printf("--- Test: push_single_element ---\n"); + StackNode *stack = NULL; + int *data1 = (int *)malloc(sizeof(int)); *data1 = 10; + + stack = push(stack, data1); + + assert_equals_ptr(data1, top(stack), "Top should be 10"); + assert_equals_ptr(NULL, stack->next, "Next element should be NULL"); + + // Aufräumen + free_stack_data(stack); // Daten freigeben + clearStack(stack); // StackNodes freigeben +} + +void test_push_multiple_elements() { + printf("--- Test: push_multiple_elements ---\n"); + StackNode *stack = NULL; + int *data1 = (int *)malloc(sizeof(int)); *data1 = 10; + int *data2 = (int *)malloc(sizeof(int)); *data2 = 20; + int *data3 = (int *)malloc(sizeof(int)); *data3 = 30; + + stack = push(stack, data1); // Stack: [10] + stack = push(stack, data2); // Stack: [20, 10] + stack = push(stack, data3); // Stack: [30, 20, 10] + + assert_equals_int(30, *(int*)top(stack), "Top should be 30"); + assert_equals_int(20, *(int*)stack->next->data, "Second element should be 20"); + assert_equals_int(10, *(int*)stack->next->next->data, "Third element should be 10"); + assert_equals_ptr(NULL, stack->next->next->next, "Fourth element should be NULL"); + + // Aufräumen + free_stack_data(stack); + clearStack(stack); +} + +void test_pop_from_empty_stack() { + printf("--- Test: pop_from_empty_stack ---\n"); + StackNode *stack = NULL; + StackNode *result = pop(stack); + assert_equals_ptr(NULL, result, "Pop from empty stack should return NULL"); + assert_equals_ptr(NULL, stack, "Stack should remain NULL"); // stack pointer passed by value, so it's still NULL +} + +void test_pop_single_element() { + printf("--- Test: pop_single_element ---\n"); + StackNode *stack = NULL; + int *data1 = (int *)malloc(sizeof(int)); *data1 = 10; + + stack = push(stack, data1); // Stack: [10] + assert_equals_int(10, *(int*)top(stack), "Top should be 10 before pop"); + + // Daten freigeben, bevor der Knoten freigegeben wird + free(top(stack)); // Freigabe von data1 + stack = pop(stack); // Stack: [] + + assert_equals_ptr(NULL, stack, "Stack should be empty after popping last element"); + assert_equals_ptr(NULL, top(stack), "Top should be NULL after popping last element"); +} + +void test_pop_multiple_elements() { + printf("--- Test: pop_multiple_elements ---\n"); + StackNode *stack = NULL; + int *data1 = (int *)malloc(sizeof(int)); *data1 = 10; + int *data2 = (int *)malloc(sizeof(int)); *data2 = 20; + int *data3 = (int *)malloc(sizeof(int)); *data3 = 30; + + stack = push(stack, data1); + stack = push(stack, data2); + stack = push(stack, data3); // Stack: [30, 20, 10] + + // Pop 1 (30) + free(top(stack)); // Freigabe von data3 + stack = pop(stack); // Stack: [20, 10] + assert_equals_int(20, *(int*)top(stack), "Top should be 20 after first pop"); + + // Pop 2 (20) + free(top(stack)); // Freigabe von data2 + stack = pop(stack); // Stack: [10] + assert_equals_int(10, *(int*)top(stack), "Top should be 10 after second pop"); + + // Pop 3 (10) + free(top(stack)); // Freigabe von data1 + stack = pop(stack); // Stack: [] + assert_equals_ptr(NULL, stack, "Stack should be empty after third pop"); + assert_equals_ptr(NULL, top(stack), "Top should be NULL after third pop"); +} + +void test_top_function() { + printf("--- Test: top_function ---\n"); + StackNode *stack = NULL; + int *data1 = (int *)malloc(sizeof(int)); *data1 = 100; + int *data2 = (int *)malloc(sizeof(int)); *data2 = 200; + + assert_equals_ptr(NULL, top(stack), "Top of empty stack should be NULL"); + + stack = push(stack, data1); + assert_equals_int(100, *(int*)top(stack), "Top should be 100"); + + stack = push(stack, data2); + assert_equals_int(200, *(int*)top(stack), "Top should be 200"); + + // Aufräumen + free_stack_data(stack); + clearStack(stack); +} + +void test_clear_stack_function() { + printf("--- Test: clear_stack_function ---\n"); + StackNode *stack = NULL; + int *data1 = (int *)malloc(sizeof(int)); *data1 = 1; + int *data2 = (int *)malloc(sizeof(int)); *data2 = 2; + int *data3 = (int *)malloc(sizeof(int)); *data3 = 3; + + stack = push(stack, data1); + stack = push(stack, data2); + stack = push(stack, data3); // Stack: [3, 2, 1] + + // Zuerst die Daten freigeben + free_stack_data(stack); + // Dann die StackNodes freigeben + clearStack(stack); + // WICHTIG: Der lokale 'stack'-Zeiger muss manuell auf NULL gesetzt werden, + // da clearStack ihn nicht ändern kann (pass-by-value). + stack = NULL; + + assert_equals_ptr(NULL, stack, "Stack should be NULL after clearStack"); + assert_equals_ptr(NULL, top(stack), "Top of cleared stack should be NULL"); +} + +int main() { + printf("Starte Stack Unit-Tests...\n"); + + test_push_single_element(); + test_push_multiple_elements(); + test_pop_from_empty_stack(); + test_pop_single_element(); + test_pop_multiple_elements(); + test_top_function(); + test_clear_stack_function(); + + printf("\n--- Testergebnisse ---\n"); + printf("Gesamtzahl der Tests: %d\n", test_count); + printf("Fehlgeschlagene Tests: %d\n", test_failed); + + if (test_failed == 0) { + printf("Alle Tests erfolgreich bestanden! 🎉\n"); + return EXIT_SUCCESS; + } else { + printf("Einige Tests sind fehlgeschlagen. 😟\n"); + return EXIT_FAILURE; + } +}