Compare commits

..
6 Commits
29 changed files with 126 additions and 375 deletions
+62
View File
@@ -0,0 +1,62 @@
# ---> C
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
Startcode/doble_initial
Startcode/doble
Startcode/unitTests
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# IDE folders
.vscode/
.idea/
# macOS
.DS_Store
Binary file not shown.
+2 -45
View File
@@ -10,44 +10,11 @@
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
// Hilfsfunktion: neuen Knoten erstellen und Daten kopieren
TreeNode* newNode(const void* data, size_t dataSize) {
TreeNode* node = malloc(sizeof(TreeNode));
if (!node) return NULL;
node->data = malloc(dataSize);
if (!node->data) {
free(node);
return NULL;
}
memcpy(node->data, data, dataSize); // Daten kopieren
node->left = node->right = NULL;
return node;
}
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
CompareFctType compareFct, int *isDuplicate)
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
{
if (root == NULL) {
*isDuplicate = 0; // kein Duplikat, neuer Knoten
return newNode(data, dataSize); // neuer Knoten wird Wurzel
}
int result = compareFct(data, root->data);
if (result < 0) {
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
} else if (result > 0) {
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
} else {
// result == 0 → Duplikat
*isDuplicate = 1;
}
return root;
}
// Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction.
// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element,
// push the top node and push all its left nodes.
@@ -59,17 +26,7 @@ void *nextTreeData(TreeNode *root)
// Releases all memory resources (including data copies).
void clearTree(TreeNode *root)
{
if (root == NULL) return; // Basisfall: leerer Teilbaum
// Rekursiv zuerst die Kinder freigeben
clearTree(root->left);
clearTree(root->right);
// Daten freigeben
free(root->data);
// Knoten selbst freigeben
free(root);
}
// Returns the number of entries in the tree given by root.
View File
View File
+4 -4
View File
@@ -29,21 +29,21 @@ program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
doble : main.o $(program_obj_files)
$(CC) $(FLAGS) $^ -o doble
$(program_obj_filesobj_files): %.o: %.c
$(program_obj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@
# --------------------------
# Unit Tests
# --------------------------
unitTests:
$(CC) $(FLAGS) $^ -o test_stack test_stack.c stack.c -Wall && ./test_stack
echo "needs to be implemented"
# --------------------------
# Clean
# --------------------------
clean:
ifeq ($(OS),Windows_NT)
del /f *.o doble test_stack
del /f *.o doble
else
rm -f *.o doble test_stack
rm -f *.o doble
endif
+26
View File
@@ -0,0 +1,26 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "numbers.h"
#include "bintree.h"
//TODO: getDuplicate und createNumbers implementieren
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
* Duplizieren eines zufälligen Eintrags im Array.
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
// creating random numbers.
unsigned int *createNumbers(unsigned int len)
{
}
// Returns only the only number in numbers which is present twice. Returns zero on errors.
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{
}
View File
+33
View File
@@ -0,0 +1,33 @@
#include <stdlib.h>
#include "stack.h"
//TODO: grundlegende Stackfunktionen implementieren:
/* * `push`: legt ein Element oben auf den Stack,
* `pop`: entfernt das oberste Element,
* `top`: liefert das oberste Element zurück,
* `clearStack`: gibt den gesamten Speicher frei. */
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data)
{
}
// 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)
{
}
// Returns the data of the top element.
void *top(StackNode *stack)
{
}
// Clears stack and releases all memory.
void clearStack(StackNode *stack)
{
}
-7
View File
@@ -8,13 +8,6 @@ The latest element is taken from the stack. */
#include <stdlib.h>
//TODO: passenden Datentyp als struct anlegen
typedef struct StackNode
{
void *data;
struct StackNode *next;
struct StackNode *prev;
}StackNode;
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data);
View File
View File
-57
View File
@@ -1,57 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "numbers.h"
#include "bintree.h"
// TODO: getDuplicate und createNumbers implementieren
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
* Duplizieren eines zufälligen Eintrags im Array.
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
// creating random numbers.
unsigned int *createNumbers(unsigned int len)
{
int n;
printf("Wie viele Zufallszahlen sollen erstellt werden? ");
scanf("%d", &n);
int array[n];
srand(time(NULL)); // Zufallsgenerator initialisieren
for (int i = 0; i < n; i++)
{
int zahl;
char vorhanden;
do
{
vorhanden = 0;
zahl = rand() % n; // Zufallszahl zwischen 1 und 100
// Prüfen, ob Zahl schon im Array existiert
for (int j = 0; j < i; j++)
{
if (array[j] == zahl)
{
vorhanden = 1;
break;
}
}
} while (vorhanden); // solange wiederholen, bis Zahl einzigartig ist
array[i] = zahl;
}
return 0;
}
// Returns only the only number in numbers which is present twice. Returns zero on errors.
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{
}
-76
View File
@@ -1,76 +0,0 @@
#include <stdlib.h>
#include "stack.h"
//TODO: grundlegende Stackfunktionen implementieren:
/* * `push`: legt ein Element oben auf den Stack,
* `pop`: entfernt das oberste Element,
* `top`: liefert das oberste Element zurück,
* `clearStack`: gibt den gesamten Speicher frei. */
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data)
{
// Speicher für den neuen Knoten allokieren
StackNode *newNode = (StackNode *)malloc(sizeof(StackNode));
// Prüfen, ob die Allokierung erfolgreich war
if (newNode == NULL)
{
return stack; // Unveränderter Stack bei Fehler
}
// Neuen Knoten initialisieren
newNode->data = data;
newNode->next = stack; // Zeigt auf die aktuelle Spitze des Stacks
// Neuen Knoten als neue Spitze des Stacks zurückgeben
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)
{
// Prüfen, ob der Stack leer ist
if (stack == NULL)
{
return NULL;
}
// Zeiger auf den nächsten Knoten speichern (wird zur neuen Spitze)
StackNode *newTop = stack->next;
// Aktuellen obersten Knoten freigeben (aber NICHT die Daten - Verantwortung des Aufrufers)
free(stack);
// Neue Spitze des Stacks zurückgeben
return newTop;
}
// Returns the data of the top element.
void *top(StackNode *stack)
{
// Prüfen, ob der Stack leer ist
if (stack == NULL)
{
return NULL;
}
// Datenzeiger des obersten Knotens zurückgeben
return stack->data;
}
// Clears stack and releases all memory.
void clearStack(StackNode *stack)
{
StackNode *current = stack;
StackNode *next;
// Durch alle Knoten iterieren und freigeben
while (current != NULL)
{
next = current->next; // Nächsten Knoten speichern
free(current); // Aktuellen Knoten freigeben (aber NICHT die Daten)
current = next; // Zum nächsten Knoten weitergehen
}
}
-187
View File
@@ -1,187 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "stack.h"
// Hilfsfunktion: Gibt "PASSED" oder "FAILED" aus
void printTestResult(const char *testName, int passed)
{
if (passed)
{
printf("[PASSED] %s\n", testName);
}
else
{
printf("[FAILED] %s\n", testName);
}
}
// Test 1: Leerer Stack
void test_emptyStack()
{
StackNode *stack = NULL;
// Top auf leerem Stack sollte NULL zurückgeben
void *result = top(stack);
printTestResult("Test 1: top() auf leerem Stack", result == NULL);
// Pop auf leerem Stack sollte NULL zurückgeben
stack = pop(stack);
printTestResult("Test 1: pop() auf leerem Stack", stack == NULL);
}
// Test 2: Push und Top
void test_pushAndTop()
{
StackNode *stack = NULL;
// Integer-Werte allokieren
int *val1 = (int *)malloc(sizeof(int));
*val1 = 42;
// Wert auf den Stack legen
stack = push(stack, val1);
// Obersten Wert abrufen
int *topVal = (int *)top(stack);
int passed = (topVal != NULL && *topVal == 42);
printTestResult("Test 2: push() und top()", passed);
// Aufräumen
free(val1);
clearStack(stack);
}
//Test 3 mehrmaliges pushen
void test_multiplePush()
{
StackNode *stack = NULL;
//Speicher für Werte allokieren
int *val1 = (int *) malloc(sizeof(int));
int *val2 = (int *) malloc(sizeof(int));
int *val3 = (int *) malloc(sizeof(int));
*val1 = 10;
*val2 = 20;
*val3 = 30;
//Testwerte auf den Stack legen
stack = push(stack, val1);
stack = push(stack, val2);
stack = push(stack, val3);
// Oberster Wert sollte 30 sein (LIFO)
int *topVal = (int *)top(stack);
int passed = (topVal != NULL && *topVal == 30);
printTestResult("Test 3: Mehrfache push() - LIFO-Prinzip", passed);
// Aufräumen
free(val1);
free(val2);
free(val3);
clearStack(stack);
}
// Test 4: Push und Pop
void test_pushAndPop()
{
StackNode *stack = NULL;
// Drei Werte auf den Stack legen
int *val1 = (int *)malloc(sizeof(int));
int *val2 = (int *)malloc(sizeof(int));
int *val3 = (int *)malloc(sizeof(int));
*val1 = 100;
*val2 = 200;
*val3 = 300;
stack = push(stack, val1);
stack = push(stack, val2);
stack = push(stack, val3);
// Oberster Wert: 300
int *topVal1 = (int *)top(stack);
int test1 = (topVal1 != NULL && *topVal1 == 300);
// Pop - neuer oberster Wert: 200
stack = pop(stack);
int *topVal2 = (int *)top(stack);
int test2 = (topVal2 != NULL && *topVal2 == 200);
// Pop - neuer oberster Wert: 100
stack = pop(stack);
int *topVal3 = (int *)top(stack);
int test3 = (topVal3 != NULL && *topVal3 == 100);
// Pop - Stack sollte leer sein
stack = pop(stack);
int test4 = (stack == NULL);
int passed = test1 && test2 && test3 && test4;
printTestResult("Test 4: push() und pop() - Korrekte Reihenfolge", passed);
// Aufräumen
free(val1);
free(val2);
free(val3);
}
// Test 5: ClearStack
void test_clearStack()
{
StackNode *stack = NULL;
// Mehrere Werte auf den Stack legen
int *val1 = (int *)malloc(sizeof(int));
int *val2 = (int *)malloc(sizeof(int));
int *val3 = (int *)malloc(sizeof(int));
int *val4 = (int *)malloc(sizeof(int));
int *val5 = (int *)malloc(sizeof(int));
*val1 = 1;
*val2 = 2;
*val3 = 3;
*val4 = 4;
*val5 = 5;
stack = push(stack, val1);
stack = push(stack, val2);
stack = push(stack, val3);
stack = push(stack, val4);
stack = push(stack, val5);
// Stack löschen
clearStack(stack);
stack = NULL; // Nach clearStack ist der Stack leer
printTestResult("Test 5: clearStack() - Alle Knoten freigegeben", 1);
// Daten müssen manuell freigegeben werden (Verantwortung des Aufrufers)
free(val1);
free(val2);
free(val3);
free(val4);
free(val5);
}
int main()
{
printf("=== Stack Unit-Tests ===\n\n");
test_emptyStack();
test_pushAndTop();
test_multiplePush();
test_pushAndPop();
test_clearStack();
/*test_stressTest();*/
printf("\n=== Alle Tests abgeschlossen ===\n");
printf("\nCode-Review: Speicherverwaltung\n");
printf("--------------------------------\n");
printf("✓ Aufrufer gibt Daten frei, Stack-Funktionen geben Knoten frei\n");
return 0;
}