Compare commits

..
11 Commits
32 changed files with 643 additions and 165 deletions

No files matched your search

-62
View File
@@ -1,62 +0,0 @@
# ---> 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.
-36
View File
@@ -1,36 +0,0 @@
#include <string.h>
#include "stack.h"
#include "bintree.h"
//TODO: binären Suchbaum implementieren
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv),
* `clearTree`: gibt den gesamten Baum frei (rekursiv),
* `treeSize`: zählt die Knoten im Baum (rekursiv),
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */
// 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).
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
{
}
// 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.
void *nextTreeData(TreeNode *root)
{
}
// Releases all memory resources (including data copies).
void clearTree(TreeNode *root)
{
}
// Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *root)
{
}
-1
View File
@@ -1 +0,0 @@
player1;3999
-26
View File
@@ -1,26 +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)
{
}
// 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)
{
}
-33
View File
@@ -1,33 +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)
{
}
// 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)
{
}
+164
View File
@@ -0,0 +1,164 @@
#include <string.h>
#include "stack.h"
#include "bintree.h"
//TODO: binären Suchbaum implementieren
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv),
* `clearTree`: gibt den gesamten Baum frei (rekursiv),
* `treeSize`: zählt die Knoten im Baum (rekursiv),
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */
// 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
static TreeNode* createNode(const void* data, size_t dataSize)
{
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
if (node == NULL)
{
return NULL;
}
node->data = malloc(dataSize);
if (node->data == NULL)
{
free(node);
return NULL;
}
memcpy(node->data, data, dataSize);
// dataSize wird NICHT im struct gespeichert, da es nicht im Header ist
node->left = NULL;
node->right = NULL;
return node;
}
// Fügt eine Kopie der Daten in den Baum ein (rekursiv)
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
CompareFctType compareFct, int *isDuplicate)
{
// Basisfall: leerer Baum oder Blattknoten erreicht
if (root == NULL)
{
// isDuplicate auf 0 setzen, wenn nicht NULL
if (isDuplicate != NULL)
{
*isDuplicate = 0;
}
return createNode(data, dataSize);
}
// Daten vergleichen
int result = compareFct(data, root->data);
if (result < 0)
{
// Daten sind kleiner -> in linken Teilbaum einfügen
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
}
else if (result > 0)
{
// Daten sind größer -> in rechten Teilbaum einfügen
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
}
else
{
// result == 0 → Duplikat gefunden
if (isDuplicate != NULL)
{
*isDuplicate = 1; // Duplikat, nicht einfügen
}
else
{
// Duplikate sind erlaubt -> in rechten Teilbaum einfügen
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
}
}
return root;
}
// Statischer Stack für die Iterator-Funktion (wie bei strtok)
static StackNode *iteratorStack = NULL;
// Iteriert über den Baum (In-Order-Traversierung mit Stack)
// Funktioniert wie strtok: beim ersten Aufruf root übergeben, dann NULL
void *nextTreeData(TreeNode *root)
{
// Wenn root != NULL: neuer Iterator-Durchlauf starten
if (root != NULL)
{
// Alten Stack löschen, falls vorhanden
clearStack(iteratorStack);
iteratorStack = NULL;
// Alle linken Knoten auf den Stack pushen (bis zum kleinsten Element)
TreeNode *current = root;
while (current != NULL)
{
iteratorStack = push(iteratorStack, current);
current = current->left;
}
}
// Wenn Stack leer ist, sind wir fertig
if (iteratorStack == NULL)
{
return NULL;
}
// Oberstes Element vom Stack holen
TreeNode *node = (TreeNode *)top(iteratorStack);
iteratorStack = pop(iteratorStack);
// Wenn der Knoten einen rechten Teilbaum hat,
// alle linken Knoten des rechten Teilbaums auf den Stack pushen
if (node->right != NULL)
{
TreeNode *current = node->right;
while (current != NULL)
{
iteratorStack = push(iteratorStack, current);
current = current->left;
}
}
// Daten des aktuellen Knotens zurückgeben
return node->data;
}
// Gibt den gesamten Baum frei (rekursiv, Post-Order)
void clearTree(TreeNode *root)
{
if (root == NULL)
{
return; // Basisfall: leerer Teilbaum
}
// Erst linken Teilbaum löschen
clearTree(root->left);
// Dann rechten Teilbaum löschen
clearTree(root->right);
// Dann Daten und Knoten selbst löschen
free(root->data);
// Knoten selbst freigeben
free(root);
}
// Zählt die Knoten im Baum (rekursiv)
unsigned int treeSize(const TreeNode *root)
{
if (root == NULL)
{
return 0; // Basisfall: leerer Teilbaum
}
// Rekursiv: Größe = 1 (aktueller Knoten) + linker Teilbaum + rechter Teilbaum
return 1 + treeSize(root->left) + treeSize(root->right);
}
+4 -3
View File
@@ -7,9 +7,10 @@ typedef int (*CompareFctType)(const void *arg1, const void *arg2);
typedef struct node
{
void *data;
struct node *left;
struct node *right;
void *data; // Zeiger auf die Daten
size_t dataSize; // ← NEU: Größe der Daten
struct node *left; // Linker Teilbaum
struct node *right; // Rechter Teilbaum
} TreeNode;
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
File renamed without changes.
File renamed without changes.
+5
View File
@@ -0,0 +1,5 @@
manu;9959
manu;9949
player2;9925
manu;4983
player1;3999
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
File renamed without changes.
+5 -4
View File
@@ -29,21 +29,22 @@ 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_files): %.o: %.c
$(program_obj_filesobj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@
# --------------------------
# Unit Tests
# --------------------------
unitTests:
echo "needs to be implemented"
$(CC) $(FLAGS) $^ -o test_stack test_stack.c stack.c -Wall && ./test_stack
$(CC) $(FLAGS) $^ -o test_numbers test_numbers.c numbers.c bintree.c stack.c -Wall && ./test_numbers
# --------------------------
# Clean
# --------------------------
clean:
ifeq ($(OS),Windows_NT)
del /f *.o doble
del /f *.o doble test_stack test_numbers
else
rm -f *.o doble
rm -f *.o doble test_stack test_numbers
endif
File renamed without changes.
File renamed without changes.
File renamed without changes.
+135
View File
@@ -0,0 +1,135 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "numbers.h"
#include "bintree.h"
// Vergleichsfunktion für unsigned int (für Binärbaum und qsort)
static int compareUnsignedInt(const void *a, const void *b)
{
unsigned int valA = *(unsigned int *)a;
unsigned int valB = *(unsigned int *)b;
if (valA < valB) return -1;
if (valA > valB) return 1;
return 0;
}
// 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.
// Erzeugt ein Array mit len eindeutigen Zufallszahlen zwischen 1 und 2*len
// Verwendet Binärbaum zur Duplikatsvermeidung
// Gibt dann eine zufällige Zahl doppelt zurück
unsigned int *createNumbers(unsigned int len)
{
// Eingabevalidierung
if (len == 0)
{
return NULL;
}
// Array allokieren
unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
if (numbers == NULL)
{
return NULL;
}
// Binärbaum zur Duplikatsprüfung erstellen
TreeNode *tree = NULL;
// Zufallsgenerator initialisieren
static int seedInitialized = 0;
if (!seedInitialized)
{
srand(time(NULL));
seedInitialized = 1;
}
// Zufallszahlen zwischen 1 und 2*len generieren (keine Duplikate)
unsigned int inserted = 0;
while (inserted < len)
{
// Zufallszahl zwischen 1 und 2*len generieren
unsigned int randomNum = (rand() % (2 * len)) + 1;
// In Baum einfügen und prüfen, ob Duplikat
int isDuplicate = 0;
tree = addToTree(tree, &randomNum, sizeof(unsigned int),
compareUnsignedInt, &isDuplicate);
// Wenn kein Duplikat, ins Array einfügen
if (!isDuplicate)
{
numbers[inserted] = randomNum;
inserted++;
}
}
// Baum aufräumen
clearTree(tree);
// Einen zufälligen Eintrag duplizieren
// Wähle zwei verschiedene Indizes
unsigned int sourceIndex = rand() % len;
unsigned int targetIndex;
do
{
targetIndex = rand() % len;
} while (targetIndex == sourceIndex);
// Kopiere Wert von source nach target (erzeugt Duplikat)
numbers[targetIndex] = numbers[sourceIndex];
return numbers;
}
// Findet das Duplikat durch Sortieren und Vergleich benachbarter Elemente
// Gibt 0 bei Fehlern zurück
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{
// Eingabevalidierung
if (numbers == NULL || len < 2)
{
return 0; // Fehler
}
// Kopie des Arrays erstellen (um Original nicht zu verändern)
unsigned int *sortedNumbers = (unsigned int *)malloc(len * sizeof(unsigned int));
if (sortedNumbers == NULL)
{
return 0; // Speicherfehler
}
// Array kopieren
memcpy(sortedNumbers, numbers, len * sizeof(unsigned int));
// Array mit qsort sortieren
qsort(sortedNumbers, len, sizeof(unsigned int), compareUnsignedInt);
// Benachbarte Elemente vergleichen, um Duplikat zu finden
unsigned int duplicate = 0;
for (unsigned int i = 0; i < len - 1; i++)
{
if (sortedNumbers[i] == sortedNumbers[i + 1])
{
duplicate = sortedNumbers[i];
break;
}
}
// Aufräumen
free(sortedNumbers);
return duplicate;
}
View File
File renamed without changes.
+76
View File
@@ -0,0 +1,76 @@
#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
}
}
+7
View File
@@ -8,6 +8,13 @@ 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);
+60
View File
@@ -0,0 +1,60 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "stack.h"
#include "numbers.h"
int main()
{
printf("=== Test createNumbers & getDuplicate ===\n\n");
unsigned int len = 10;
unsigned int *numbers = createNumbers(len);
if (numbers == NULL)
{
printf("Fehler: createNumbers() gab NULL zurück\n");
return 1;
}
printf("Generierte Zahlen: ");
for (unsigned int i = 0; i < len; i++)
{
printf("%u ", numbers[i]);
}
printf("\n\n");
unsigned int duplicate = getDuplicate(numbers, len);
if (duplicate == 0)
{
printf("Fehler: Kein Duplikat gefunden\n");
}
else
{
printf("Gefundenes Duplikat: %u\n", duplicate);
// Prüfen, ob es wirklich zweimal vorkommt
int count = 0;
for (unsigned int i = 0; i < len; i++)
{
if (numbers[i] == duplicate)
{
count++;
}
}
printf("Anzahl Vorkommen: %d\n", count);
if (count == 2)
{
printf("\n[PASSED] Test erfolgreich!\n");
}
else
{
printf("\n[FAILED] Duplikat kommt %d mal vor (erwartet: 2)\n", count);
}
}
free(numbers);
return 0;
}
+187
View File
@@ -0,0 +1,187 @@
#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;
}
View File
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.