23 Commits
Author SHA1 Message Date
Max-R 4fcaa410fa merge 2025-12-12 10:08:12 +01:00
Max-R c13d39f60c Merge remote-tracking branch 'origin/Krisp' into RMax 2025-12-12 10:07:09 +01:00
Max-R f90dc12bd0 neuer rekord 2025-12-12 10:05:14 +01:00
Kristin 9fb140fecf cleartree angepasst, Kommentare vollständig 2025-12-11 16:16:52 +01:00
Kristin 99a974cc9b getduplicate neu 2025-12-10 21:09:03 +01:00
Kristin 799667ed1c numbers.c bintree.c änderungen 2025-12-10 21:05:36 +01:00
Max-R c3b1cdd3a3 numbers 2025-12-09 10:37:20 +01:00
Max-R 9d32e06f3a highscores kristin geknackt 2025-12-09 10:27:42 +01:00
Kristin d9222b83b4 highscore zum gitignore hinzugefügt 2025-12-09 10:27:18 +01:00
Max-R 9268113f38 mein clean 2025-12-09 10:21:16 +01:00
Max-R 8f2dfb507c Merge remote-tracking branch 'origin/Krisp' into RMax 2025-12-09 10:19:21 +01:00
Kristin 9bf5e6a541 stacktest clearstack pointer null setzen 2025-12-09 10:10:13 +01:00
Kristin 57f9914e2b stacktest überarbeitet 2025-12-09 09:57:41 +01:00
Kristin 09d7f457dd stacktest überarbeitet 2025-12-09 09:49:46 +01:00
Kristin 13cb5d8c86 push test im teststack verbessert 2025-12-09 09:13:18 +01:00
Kristin 6528686fb0 Fehler bei nichtreservierung von Speicher, stack.c kommentiert 2025-12-07 20:11:40 +01:00
Kristin a3d0585ac1 stack.c eingebunden 2025-12-07 19:05:11 +01:00
Kristin 68563ec297 erste version 2025-12-07 18:35:22 +01:00
Max-R 8cccbcf441 makefile änderung 2025-12-05 12:08:25 +01:00
Kristin 55532cbb42 makefile mit rm 2025-12-05 11:52:08 +01:00
Kristin d3904ac6e4 alle tests 2025-12-05 11:50:51 +01:00
Kristin 5e96ec050c test_stack mit & 2025-12-05 11:24:35 +01:00
Kristin f42a997683 clearstack mit ** 2025-12-05 11:12:30 +01:00
16 changed files with 775 additions and 288 deletions
+1
View File
@@ -1,3 +1,4 @@
doble_initial.exe doble_initial.exe
*.o *.o
*.exe *.exe
highscore.txt
+111 -15
View File
@@ -1,6 +1,6 @@
#include <string.h>
#include "stack.h"
#include "bintree.h" #include "bintree.h"
#include "stack.h"
#include <string.h>
// TODO: binären Suchbaum implementieren // TODO: binären Suchbaum implementieren
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv), /* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv),
@@ -8,29 +8,125 @@
* `treeSize`: zählt die Knoten im Baum (rekursiv), * `treeSize`: zählt die Knoten im Baum (rekursiv),
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */ * `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 // typedef int (*CompareFctType)(const void *arg1, const void *arg2);
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). // Adds a copy of data's pointer destination to the tree using compareFct for
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) // 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 *createTreeNode(const void *data, size_t dataSize) {
TreeNode *node =
malloc(sizeof(TreeNode)); // Speicher für neuen Knoten reservieren
if (node == NULL)
return NULL; // Abbrechen bei Fehler
node->data = malloc(dataSize); // Speicher für Daten reservieren
if (node->data == NULL) {
free(node);
return NULL;
} }
// 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. memcpy(node->data, data, dataSize); // Standardfunktion string.h, kopiert
// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element, // size bytes von data nach node->data,
// push the top node and push all its left nodes. // daten dürfen sich nicht überschneiden
void *nextTreeData(TreeNode *root) // speichern der Daten in node->data
{ node->left = NULL; // Kinder sind NULL
node->right = NULL;
return node;
}
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
CompareFctType compareFct, int *isDuplicate) {
// isDuplicate initialisieren (auf 0 setzen), verhindert Änderung am Baum
if (isDuplicate) {
*isDuplicate = 0;
} // bei 0: neuer Wert wurde eingefügt, bei 1: Wert war bereits im Baum
// leerer Baum
if (root == NULL) {
return createTreeNode(data, dataSize);
}
// mit compareFct <0 links >0 rechts =0 Duplikat
int compare = compareFct(data, root->data);
if (compare < 0) { // Eintrag links
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
} else if (compare > 0) { // Eintrag rechts
root->right =
addToTree(root->right, data, dataSize, compareFct, isDuplicate);
} else { // Duplikat
// isDuplicate auf 1 setzen, keine Änderung am Baum
if (isDuplicate) {
*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.
void *nextTreeData(TreeNode *root) {
static StackNode *stack = NULL; // static -> behält Wert bei mehreren Aufrufen
// Neue Iteration starten
if (root != NULL) {
clearStack(&stack); // alte Stack-Inhalte werden gelöscht
TreeNode *currentNode = root;
while (currentNode !=
NULL) { // alle linken Knoten werden vom root an auf den Stack gelegt
StackNode *oldStack = stack;
StackNode *newStack = push(stack, currentNode);
if (newStack == oldStack)
return NULL; // push fehlgeschlagen
stack = newStack;
currentNode = currentNode->left;
}
}
if (stack == NULL)
return NULL; // wenn Stack leer ist sind keine Elemente mehr vorhanden,
// Iteration beendet
// oberster Knoten vom Stack
TreeNode *node = top(stack);
stack = pop(stack);
// Rechten Teilbaum pushen
TreeNode *currentNode = node->right;
while (currentNode != NULL) {
StackNode *oldStack = stack;
StackNode *newStack = push(stack, currentNode);
if (newStack == oldStack)
return NULL; // push fehlgeschlagen
stack = newStack;
currentNode = currentNode->left;
}
return node->data; // Pointer auf Daten
} }
// Releases all memory resources (including data copies). // Releases all memory resources (including data copies).
void clearTree(TreeNode *root) void clearTree(TreeNode **root) { // rekursive Funktion zum freigeben des
{ // Speichers und Nullsetzen der Pointer
if (root == NULL || *root == NULL)
return;
clearTree(&(*root)->left); // linken Teilbaum löschen
clearTree(&(*root)->right); // rechten Teilbaum löschen
free((*root)->data); // Daten freigeben
(*root)->data = NULL;
free(*root); // Knoten freigeben
*root = NULL; // Zeiger auf NULL setzen
} }
// Returns the number of entries in the tree given by root. // Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *root) unsigned int treeSize(const TreeNode *root) {
{
if (root == NULL)
return 0;
return 1 + treeSize(root->left) + treeSize(root->right);
} }
+14 -9
View File
@@ -5,22 +5,27 @@
typedef int (*CompareFctType)(const void *arg1, const void *arg2); typedef int (*CompareFctType)(const void *arg1, const void *arg2);
typedef struct node typedef struct node {
{
void *data; void *data;
struct node *left; struct node *left;
struct node *right; struct node *right;
} TreeNode; } TreeNode;
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates TreeNode *createTreeNode(const void *data, size_t dataSize);
// 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); // Adds a copy of data's pointer destination to the tree using compareFct for
// 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. // ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores
// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element, // duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
// push the top node and push all its left nodes. 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); void *nextTreeData(TreeNode *root);
// Releases all memory resources (including data copies). // Releases all memory resources (including data copies).
void clearTree(TreeNode *root); void clearTree(TreeNode **root);
// Returns the number of entries in the tree given by root. // Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *root); unsigned int treeSize(const TreeNode *root);
+40 -45
View File
@@ -1,23 +1,22 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "highscore.h" #include "highscore.h"
#include "bintree.h" #include "bintree.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LEN 100 #define MAX_LINE_LEN 100
#define MAX_PLAYER_NAME_LEN 20 #define MAX_PLAYER_NAME_LEN 20
typedef struct typedef struct {
{
char name[MAX_PLAYER_NAME_LEN]; char name[MAX_PLAYER_NAME_LEN];
int score; int score;
} HighscoreEntry; } HighscoreEntry;
static TreeNode *highscoreTree = NULL; static TreeNode *highscoreTree = NULL;
// Compare two highscore entries by score (descending), then by name (ascending). // Compare two highscore entries by score (descending), then by name
static int compareHighscoreEntries(const void *arg1, const void *arg2) // (ascending).
{ static int compareHighscoreEntries(const void *arg1, const void *arg2) {
const HighscoreEntry *entry1 = (const HighscoreEntry *)arg1; const HighscoreEntry *entry1 = (const HighscoreEntry *)arg1;
const HighscoreEntry *entry2 = (const HighscoreEntry *)arg2; const HighscoreEntry *entry2 = (const HighscoreEntry *)arg2;
@@ -30,12 +29,10 @@ static int compareHighscoreEntries(const void *arg1, const void *arg2)
} }
// Create a new highscore entry from name and score. // Create a new highscore entry from name and score.
static HighscoreEntry createHighscoreEntry(const char *name, int score) static HighscoreEntry createHighscoreEntry(const char *name, int score) {
{
HighscoreEntry entry = {"", score}; HighscoreEntry entry = {"", score};
if(name != NULL) if (name != NULL) {
{
strncpy(entry.name, name, MAX_PLAYER_NAME_LEN); strncpy(entry.name, name, MAX_PLAYER_NAME_LEN);
entry.name[MAX_PLAYER_NAME_LEN - 1] = '\0'; entry.name[MAX_PLAYER_NAME_LEN - 1] = '\0';
} }
@@ -44,29 +41,26 @@ static HighscoreEntry createHighscoreEntry(const char *name, int score)
} }
// Calculate score based on time used and number of shown numbers. // Calculate score based on time used and number of shown numbers.
static int calculateScore(double timeInSeconds, unsigned int len) static int calculateScore(double timeInSeconds, unsigned int len) {
{
return (1000.0 - timeInSeconds) * len; return (1000.0 - timeInSeconds) * len;
} }
// Load highscores from file into memory. // Load highscores from file into memory.
void loadHighscores(const char *path) void loadHighscores(const char *path) {
{
FILE *file = fopen(path, "r"); FILE *file = fopen(path, "r");
if(file != NULL) if (file != NULL) {
{
char buffer[MAX_LINE_LEN + 1]; char buffer[MAX_LINE_LEN + 1];
while(fgets(buffer, MAX_LINE_LEN+1, file) != NULL) while (fgets(buffer, MAX_LINE_LEN + 1, file) != NULL) {
{
char *name = strtok(buffer, ";\n"); char *name = strtok(buffer, ";\n");
char *scoreStr = strtok(NULL, ";\n"); char *scoreStr = strtok(NULL, ";\n");
if(name != NULL && scoreStr != NULL) if (name != NULL && scoreStr != NULL) {
{ HighscoreEntry entry =
HighscoreEntry entry = createHighscoreEntry(name, strtol(scoreStr, NULL, 10)); createHighscoreEntry(name, strtol(scoreStr, NULL, 10));
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL); highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry),
compareHighscoreEntries, NULL);
} }
} }
@@ -75,19 +69,23 @@ void loadHighscores(const char *path)
} }
// Add a new highscore entry and return the calculated score. // Add a new highscore entry and return the calculated score.
int addHighscore(const char *name, double timeInSeconds, unsigned int len) int addHighscore(const char *name, double timeInSeconds, unsigned int len) {
{ HighscoreEntry entry =
HighscoreEntry entry = createHighscoreEntry(name, calculateScore(timeInSeconds, len)); createHighscoreEntry(name, calculateScore(timeInSeconds, len));
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL); highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry),
compareHighscoreEntries, NULL);
return entry.score; return entry.score;
} }
// Print highscores (up to NUMBER_OF_SHOWN_HIGHSCORES) in a formatted table. // Print highscores (up to NUMBER_OF_SHOWN_HIGHSCORES) in a formatted table.
void showHighscores() void showHighscores() {
{ const char *blanks =
const char *blanks = " "; " "
const char *stripes = "------------------------------------------------------------------------------------------------------------------------"; " ";
const char *stripes =
"------------------------------------------------------------------------"
"------------------------------------------------";
const char *header = "H I G H S C O R E S"; const char *header = "H I G H S C O R E S";
const int lineWidth = MAX_PLAYER_NAME_LEN + MAX_PLAYER_NAME_LEN + 5; const int lineWidth = MAX_PLAYER_NAME_LEN + MAX_PLAYER_NAME_LEN + 5;
@@ -96,28 +94,26 @@ void showHighscores()
HighscoreEntry *entry = nextTreeData(highscoreTree); HighscoreEntry *entry = nextTreeData(highscoreTree);
printf("+%*.*s+\n", lineWidth, lineWidth, stripes); printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
printf("|%*.*s%s%*.*s|\n", blankSpace, blankSpace, blanks, header, blankSpace, blankSpace, blanks); printf("|%*.*s%s%*.*s|\n", blankSpace, blankSpace, blanks, header, blankSpace,
blankSpace, blanks);
printf("+%*.*s+\n", lineWidth, lineWidth, stripes); printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
for(int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) for (int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) {
{ printf("| %-*s | %*d |\n", MAX_PLAYER_NAME_LEN, entry->name,
printf("| %-*s | %*d |\n", MAX_PLAYER_NAME_LEN, entry->name, MAX_PLAYER_NAME_LEN, entry->score); MAX_PLAYER_NAME_LEN, entry->score);
printf("+%*.*s+\n", lineWidth, lineWidth, stripes); printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
entry = nextTreeData(NULL); entry = nextTreeData(NULL);
} }
} }
// Save highscores to file (up to NUMBER_OF_SHOWN_HIGHSCORES). // Save highscores to file (up to NUMBER_OF_SHOWN_HIGHSCORES).
void saveHighscores(const char *path) void saveHighscores(const char *path) {
{
FILE *file = fopen(path, "w"); FILE *file = fopen(path, "w");
if(file != NULL) if (file != NULL) {
{
HighscoreEntry *entry = nextTreeData(highscoreTree); HighscoreEntry *entry = nextTreeData(highscoreTree);
for(int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) for (int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) {
{
fprintf(file, "%s;%d\n", entry->name, entry->score); fprintf(file, "%s;%d\n", entry->name, entry->score);
entry = nextTreeData(NULL); entry = nextTreeData(NULL);
} }
@@ -127,8 +123,7 @@ void saveHighscores(const char *path)
} }
// Free all memory used for highscores. // Free all memory used for highscores.
void clearHighscores() void clearHighscores() {
{ clearTree(&highscoreTree);
clearTree(highscoreTree);
highscoreTree = NULL; highscoreTree = NULL;
} }
+9 -1
View File
@@ -1,2 +1,10 @@
max20;19879
max10;9970
max;9965
Kristin;9944
Kristin;7947
Kristin;6962
Kristin;5987
Kristin;5975
krisp;4986 krisp;4986
player1;3999 krisp;4985
+25 -27
View File
@@ -1,30 +1,28 @@
#include <stdlib.h> #include "highscore.h"
#include <stdio.h>
#include "numbers.h" #include "numbers.h"
#include "timer.h" #include "timer.h"
#include "highscore.h" #include <stdio.h>
#include <stdlib.h>
#include <time.h>
// Read an unsigned integer from stdin with prompt (retries until valid). // Read an unsigned integer from stdin with prompt (retries until valid).
int inputNumber(const char *promptText) int inputNumber(const char *promptText) {
{
unsigned int number; unsigned int number;
int numberOfInputs = 0; int numberOfInputs = 0;
while(numberOfInputs != 1) while (numberOfInputs != 1) {
{
printf("%s", promptText); printf("%s", promptText);
numberOfInputs = scanf("%u", &number); numberOfInputs = scanf("%u", &number);
while(getchar() != '\n') {} // clear input buffer while (getchar() != '\n') {
} // clear input buffer
} }
return number; return number;
} }
// Print an array of numbers. // Print an array of numbers.
void showNumbers(const unsigned int *numbers, unsigned int len) void showNumbers(const unsigned int *numbers, unsigned int len) {
{ if (numbers != NULL) {
if(numbers != NULL)
{
printf("Numbers:"); printf("Numbers:");
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
@@ -34,18 +32,16 @@ void showNumbers(const unsigned int *numbers, unsigned int len)
} }
} }
// Main game loop: generate numbers, ask user for duplicate, measure time, update highscores. // Main game loop: generate numbers, ask user for duplicate, measure time,
int main(int argc, char *argv[]) // update highscores.
{ int main(int argc, char *argv[]) {
srand(time(NULL)); // seed für srand
int exitCode = EXIT_FAILURE; int exitCode = EXIT_FAILURE;
if(argc != 2) if (argc != 2) {
{
fprintf(stderr, "Usage: %s <player name>\n", argv[0]); fprintf(stderr, "Usage: %s <player name>\n", argv[0]);
exitCode = EXIT_FAILURE; exitCode = EXIT_FAILURE;
} } else {
else
{
const char *highscorePath = "highscores.txt"; const char *highscorePath = "highscores.txt";
const char *playerName = argv[1]; const char *playerName = argv[1];
unsigned int *numbers = NULL; unsigned int *numbers = NULL;
@@ -56,7 +52,8 @@ int main(int argc, char *argv[])
// ask until valid number of elements (3..1000) // ask until valid number of elements (3..1000)
while (numberOfElements < 3 || numberOfElements > 1000) while (numberOfElements < 3 || numberOfElements > 1000)
numberOfElements = inputNumber("Wie viele Zahlen sollen gezeigt werden: "); numberOfElements =
inputNumber("Wie viele Zahlen sollen gezeigt werden: ");
// create numbers and show them // create numbers and show them
numbers = createNumbers(numberOfElements); numbers = createNumbers(numberOfElements);
@@ -70,13 +67,14 @@ int main(int argc, char *argv[])
duplicate = getDuplicate(numbers, numberOfElements); duplicate = getDuplicate(numbers, numberOfElements);
// check result and update highscores // check result and update highscores
if(userInput == duplicate) if (userInput == duplicate) {
{
int score = addHighscore(playerName, measuredSeconds, numberOfElements); int score = addHighscore(playerName, measuredSeconds, numberOfElements);
printf("Sie haben die korrekte Zahl in %.6lf Sekunde(n) gefunden und %u Punkte erzielt.\n", measuredSeconds, score); printf("Sie haben die korrekte Zahl in %.6lf Sekunde(n) gefunden und %u "
} "Punkte erzielt.\n",
else measuredSeconds, score);
printf("Leider ist %u nicht korrekt. Richtig waere %u gewesen.\n", userInput, duplicate); } else
printf("Leider ist %u nicht korrekt. Richtig waere %u gewesen.\n",
userInput, duplicate);
loadHighscores(highscorePath); loadHighscores(highscorePath);
showHighscores(); showHighscores();
+29 -7
View File
@@ -25,32 +25,54 @@ doble_initial:
# -------------------------- # --------------------------
# Selbst implementiertes Programm bauen # Selbst implementiertes Programm bauen
# -------------------------- # --------------------------
# alle Objektdateien
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
# alle ausführbaren Dateien zu ausführbarem Programm linken
doble : main.o $(program_obj_files) doble : main.o $(program_obj_files)
$(CC) $(FLAGS) $^ -o doble $(CC) $(FLAGS) $^ -o doble
# Regel Kompilieren allgemein
$(program_obj_files): %.o: %.c $(program_obj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@ $(CC) -c $(FLAGS) $^ -o $@
# -------------------------- # --------------------------
# Unit Tests # Unit Tests
# -------------------------- # --------------------------
unitTests:
TEST_BIN = runTests
unitTests: stack.o test_stack.o STACK_TEST_BIN = runStackTests
$(CC) $(FLAGS) $(ASAN_FLAGS) -I$(unityfolder) -o $(TEST_BIN) stack.o test_stack.o $(unityfolder)/unity.c NUMBERS_TEST_BIN = runNumbersTests
BINARY_TEST_BIN = runBinaryTests
# --- Stack Tests ---
stackTests: stack.o test_stack.o
$(CC) $(FLAGS) -I$(unityfolder) -o $(STACK_TEST_BIN) stack.o test_stack.o $(unityfolder)/unity.c
test_stack.o: test_stack.c test_stack.o: test_stack.c
$(CC) $(FLAGS) -I$(unityfolder) -c test_stack.c -o test_stack.o $(CC) $(FLAGS) -I$(unityfolder) -c test_stack.c -o test_stack.o
# --- Numbers Tests ---
numbersTests: numbers.o bintree.o stack.o test_numbers.o
$(CC) $(FLAGS) -I$(unityfolder) -o $(NUMBERS_TEST_BIN) numbers.o bintree.o stack.o test_numbers.o $(unityfolder)/unity.c
test_numbers.o: test_numbers.c
$(CC) $(FLAGS) -I$(unityfolder) -c test_numbers.c -o test_numbers.o
# --- Binary Tree Tests ---
binaryTests: bintree.o stack.o test_binary.o
$(CC) $(FLAGS) -I$(unityfolder) -o $(BINARY_TEST_BIN) bintree.o stack.o test_binary.o $(unityfolder)/unity.c
test_binary.o: test_binary.c
$(CC) $(FLAGS) -I$(unityfolder) -c test_binary.c -o test_binary.o
# -------------------------- # --------------------------
# Clean # Clean
# -------------------------- # --------------------------
clean: clean:
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
rm -f *.o doble del /f *.o doble
else else
rm -f *.o doble rm -f *.o doble
endif endif
+85 -15
View File
@@ -1,26 +1,96 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "numbers.h" #include "numbers.h"
#include "bintree.h" #include "bintree.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// TODO: getDuplicate und createNumbers implementieren // TODO: getDuplicate und createNumbers implementieren
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen. /**Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen. * Zufallszahlen. Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
* Duplizieren eines zufälligen Eintrags im Array. * Duplizieren eines zufälligen Eintrags im Array.
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */ * 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 len random numbers between 1 and 2x len in random order which are all
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while // different, except for two entries. Returns NULL on errors. Use your
// creating random numbers. // implementation of the binary search tree to check for possible duplicates
unsigned int *createNumbers(unsigned int len) // while creating random numbers.
{
// vergleicht zwei Werte: a<b: -1 a>b: 1 a=b: 0
int compareUnsignedInt(const void *a, const void *b) {
unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b;
return (x < y) ? -1 : (x > y);
} }
// Returns only the only number in numbers which is present twice. Returns zero on errors. unsigned int *createNumbers(unsigned int len) {
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) if (len < 2) // Duplikat bei zwei Einträgen sinnlos
{ return NULL;
unsigned int *numbersArray = malloc(
sizeof(unsigned int) * len); // Speicher für das Ausgabearray reservieren:
// Größe eines Eintrags * Größe des Arrays
if (!numbersArray) // Speicher konnte nicht reserviert werden
return NULL;
TreeNode *root =
NULL; // Binärbaum zum Generieren der Zufallszahlen ohne Duplikate
for (unsigned int i = 0; i < len; i++) {
unsigned int currentNumber;
int isDuplicate;
do { // mindestens eine Zufallszahl erzeugen
currentNumber = (rand() % (2 * len)) + 1; // Zahlenbereich 1 bis 2*len
isDuplicate = 0;
root = addToTree(root, &currentNumber, sizeof(unsigned int),
compareUnsignedInt,
&isDuplicate); // compareUnsignedInt wird zum Verwenden
// bei Vergleichen übergeben
} while (isDuplicate); // wenn isDuplicate gesetzt wird, muss eine neue Zahl
// erzeugt werden, die Schleife wird wiederholt
numbersArray[i] = currentNumber;
}
// Ein zufälliges Duplikat erzeugen
unsigned int duplicateIndex =
rand() % len; // Index des Duplikats per Zufall bestimmen
unsigned int newIndex;
do {
newIndex = rand() % len;
} while (newIndex == duplicateIndex); // zweiten Index bestimmen, der nicht
// mit dem ersten übereinstimmt
numbersArray[newIndex] =
numbersArray[duplicateIndex]; // Wert vom ersten Index kopieren
clearTree(&root); // Speicher wieder freigeben, wird nicht mehr benötigt
return numbersArray;
}
// 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) { // array numbers, sowie die Länge wird übergeben
if (!numbers || len < 2)
return 0; // fehlerhaftes Array
TreeNode *root = NULL; // leerer Baum
unsigned int duplicateValue = 0; // Wert des Duplikats
for (unsigned int i = 0; i < len && duplicateValue == 0; i++) { // Schleife
int isDuplicate = 0;
// Zahl in den Baum einfügen
root = addToTree(root, &numbers[i], sizeof(unsigned int),
compareUnsignedInt, &isDuplicate);
// Duplikat erkannt
if (isDuplicate && duplicateValue == 0) {
duplicateValue = numbers[i]; // Duplikat merken, for-Schleife wird beendet
}
}
clearTree(&root); // Baum freigeben
return duplicateValue; // 0, falls kein Duplikat
} }
+8 -4
View File
@@ -1,12 +1,16 @@
#ifndef NUMBERS_H #ifndef NUMBERS_H
#define NUMBERS_H #define NUMBERS_H
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries. int compareUnsignedInt(const void *a, const void *b);
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
// creating random numbers. // 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); unsigned int *createNumbers(unsigned int len);
// Returns only the only number in numbers which is present twice. Returns zero on errors. // 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); unsigned int getDuplicate(const unsigned int *numbers, unsigned int len);
#endif #endif
+52 -37
View File
@@ -6,6 +6,7 @@
void *data; void *data;
struct StackNode *next; struct StackNode *next;
struct StackNode *prev;
} StackNode;*/ } StackNode;*/
@@ -15,71 +16,85 @@
* `top`: liefert das oberste Element zurück, * `top`: liefert das oberste Element zurück,
* `clearStack`: gibt den gesamten Speicher frei. */ * `clearStack`: gibt den gesamten Speicher frei. */
StackNode *createNode(void *data) // [A] -> [B] -> [C] -> NULL
{ // stack -> stack.next
StackNode *node =
malloc(sizeof(StackNode)); // Speicher reservieren, Speicherplatz für das
// struct StackNode
// Funktion zum erstellen neuer nodes
StackNode *createNode(void *data) {
// Speicher reservieren
StackNode *node = malloc(sizeof(StackNode));
// Speicher konnte nicht reserviert werden
if (node == NULL) if (node == NULL)
return NULL; // Speicher konnte nicht reserviert werden return NULL;
node->data = data; // Zeiger auf data neuer node node->data = data;
node->next = NULL; // nächster Zeiger ist NULL, Ende der Liste node->next = NULL;
node->prev = NULL;
return node; // pointer auf den neuen Knoten zurückgeben return node;
} }
// Pushes data as pointer onto the stack. // Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data) StackNode *push(StackNode *stack, void *data) {
{
StackNode *newNode = createNode(data); // Speicher für neuen Knoten
// reservieren
if (newNode == NULL) StackNode *newNode = createNode(data);
{ // wenn Speicher nicht reserviert werden konnte, wird
// stack unverändert zurückgegeben // Fehler beim Reservieren des Speichers, stack wird unverändert zurückgegeben
if (newNode == NULL) {
return stack; return stack;
} }
newNode->next = stack; // pointer verschieben // der aktuelle Kopf wird der nächste Node
newNode->next = stack;
return newNode; // Zeiger auf neuen Speicherbereich zurückgeben // bisheriger Kopf bekommt Pointer auf oberstes Element
if (stack != NULL) {
stack->prev = newNode;
} }
// Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be return newNode; // neuer Kopf wird zurückgegeben
// freed by caller.) }
StackNode *pop(StackNode *stack)
{ // 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) {
// Stack ohne Elemente
if (stack == NULL) if (stack == NULL)
return NULL; return NULL;
// Element unter Kopf wird als nextNode gespeichert
StackNode *nextNode = stack->next; StackNode *nextNode = stack->next;
if (nextNode != NULL) {
nextNode->prev = NULL; // der Zeiger zum Kopf wird auf NULL gesetzt
}
free(stack); free(stack);
stack = NULL; stack = NULL; // Speicher des Kopfes freigeben
return nextNode; return nextNode; // neuen Kopf zurückgeben
} }
// Returns the data of the top element. // Returns the data of the top element.
void *top(StackNode *stack) { return stack != NULL ? stack->data : NULL; } void *top(StackNode *stack) {
// wenn stack leer ist, wird NULL zurückgegeben
// Zeiger auf Daten des obersten Elements
return stack ? stack->data : NULL;
}
// Clears stack and releases all memory. // Clears stack and releases all memory.
void clearStack(StackNode **stack) void clearStack(StackNode **stack) { // Zeiger auf den Zeiger auf den Stackkopf
{ // verändert den Zeiger selbst, mit *stack lokale Kopie
while (*stack != NULL) // im Aufruf &stack verwenden
{ while (*stack != NULL) {
StackNode *next = (*stack)->next; (*stack)->prev = NULL; // späteren Pointerzugriff verhindern
free(*stack); StackNode *next = (*stack)->next; // nächstes Element speichern
(*stack)->data = NULL;
(*stack)->next = NULL;
(*stack)->prev = NULL;
(*stack) = next;
(*stack)->next = NULL; // späteren Pointerzugriff verhindern
free(*stack); // aktuelles Element freigeben
*stack = next; // Zeiger auf nächsten Knoten setzen
} }
} }
-10
View File
@@ -19,16 +19,6 @@ typedef struct StackNode {
StackNode *createNode(void *data); StackNode *createNode(void *data);
typedef struct StackNode {
void *data;
struct StackNode *next;
struct StackNode *prev;
} StackNode;
StackNode *createNode(void *data);
// Pushes data as pointer onto the stack. // Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data); StackNode *push(StackNode *stack, void *data);
BIN
View File
Binary file not shown.
+126
View File
@@ -0,0 +1,126 @@
#include "unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bintree.h"
int compareUnsignedInt(const void *a, const void *b) {
unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b;
if (x < y)
return -1;
if (x > y)
return 1;
return 0;
}
TreeNode *root = NULL;
void setUp(void) {
root = NULL; // vor jedem Test leeren
}
void tearDown(void) { clearTree(&root); }
// Test, ob addToTree Knoten korrekt hinzufügt
/*TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
CompareFctType compareFct, int *isDuplicate) */
void test_addToTree_basic(void) {
int isDuplicate;
unsigned int testInt = 10;
root = addToTree(root, &testInt, sizeof(testInt), compareUnsignedInt,
&isDuplicate);
TEST_ASSERT_NOT_NULL(root); // Knoten wurde erfolgreich erzeugt
TEST_ASSERT_EQUAL_UINT(
10,
*(unsigned int *)root
->data); // Datenzeiger wurde richtig gesetzt, void pointer auf
// unsigned int pointer casten, mit *wird der Wert abgerufen
TEST_ASSERT_EQUAL_INT(0, isDuplicate); // kein Duplikat
TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); // der tree hat einen Eintrag
}
// Test, dass Duplikate erkannt werden
void test_addToTree_duplicate(void) {
int isDuplicate;
unsigned int val1 = 10, val2 = 10; // Duplikate
root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt,
&isDuplicate); // val 1 zum leeren Baum hinzufügen
TEST_ASSERT_EQUAL_INT(0, isDuplicate); // erster Knoten->kein Duplikat
root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt,
&isDuplicate); // val 2 hinzufügen
TEST_ASSERT_EQUAL_INT(1, isDuplicate); // Duplikat erkannt
TEST_ASSERT_EQUAL_UINT(1,
treeSize(root)); // Duplikate wurde nicht hinzugefügt
}
// Test nextTreeData Traversierung
void test_nextTreeData_in_order(void) {
unsigned int values[] = {20, 10, 30}; // erwartete Ausgabe: 10 -> 20 -> 30
int isDuplicate;
for (int i = 0; i < 3; i++) {
root = addToTree(root, &values[i], sizeof(values[i]), compareUnsignedInt,
&isDuplicate); // Baum füllen
}
unsigned int expected[] = {10, 20, 30}; // erwartet in Order Reihenfolge
int valueID = 0;
void *data;
// Neue Iteration starten
data = nextTreeData(root);
while (data != NULL) {
TEST_ASSERT_EQUAL_UINT(expected[valueID],
*(unsigned int *)data); // entspricht erwartetem Wert
valueID++;
data = nextTreeData(NULL); // weitere Elemente abrufen
}
TEST_ASSERT_EQUAL_INT(3, valueID); // alle 3 Knoten besucht
}
// Testet, dass clearTree Speicher freigibt und Root auf NULL setzt
void test_clearTree_sets_root_null(void) {
int isDuplicate;
unsigned int val1 = 10, val2 = 20;
root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDuplicate);
root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, &isDuplicate);
// Vor dem Clear prüfen, dass Root nicht NULL ist
TEST_ASSERT_NOT_NULL(root);
clearTree(&root);
// Nach dem Clear muss Root auf NULL gesetzt sein
TEST_ASSERT_NULL(root);
}
// Test treeSize zählt korrekt
void test_treeSize(void) {
unsigned int testInts[] = {10, 20, 5};
int isDuplicate;
for (int i = 0; i < 3; i++) {
root = addToTree(root, &testInts[i], sizeof(testInts[i]),
compareUnsignedInt, &isDuplicate);
}
TEST_ASSERT_EQUAL_UINT(3, treeSize(root));
}
int main(void) {
UNITY_BEGIN();
printf(
"\n------------------------binarytree test------------------------\n\n");
RUN_TEST(test_addToTree_basic);
RUN_TEST(test_addToTree_duplicate);
RUN_TEST(test_nextTreeData_in_order);
RUN_TEST(test_clearTree_sets_root_null);
RUN_TEST(test_treeSize);
return UNITY_END();
}
+73
View File
@@ -0,0 +1,73 @@
#include "unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "numbers.h"
#define TEST_ARRAY_LEN 100
// Speicher für ein Array wird reserviert
void test_createNumbers_length(void) { // erstellt ein Array der Länge hundert
unsigned int *testArray = createNumbers(TEST_ARRAY_LEN);
TEST_ASSERT_NOT_NULL(testArray);
free(testArray);
}
// Duplikat ist genau einmal vorhanden
void test_createNumbers_single_duplicate(void) {
unsigned int *testArray = createNumbers(TEST_ARRAY_LEN); // Array erstellen
TEST_ASSERT_NOT_NULL(testArray); // Speicher konnte reserviert werden
unsigned int duplicate =
getDuplicate(testArray, TEST_ARRAY_LEN); // Duplikat holen
TEST_ASSERT_TRUE(duplicate > 0); // Duplikat ist größer als 0
TEST_ASSERT_TRUE(
duplicate <
(2 * TEST_ARRAY_LEN)); // Duplikat liegt im vorgegebenen Zahlenbereich
unsigned int count = 0; // Anzahl der Duplikate
for (unsigned int i = 0; i < TEST_ARRAY_LEN;
i++) { // Einträge des testArrays auf Duplikate prüfen
if (testArray[i] == duplicate) {
count++;
}
}
TEST_ASSERT_EQUAL_UINT(2, count); // Duplikat zwei mal vorhanden
free(testArray); // Speicher freigeben
}
// getDuplicate testen
void test_getDuplicate_manual_array(
void) { // duplikat in fremden array wird gefunden
unsigned int numbers[5] = {10, 20, 30, 40, 20};
unsigned int duplicate = getDuplicate(numbers, 5);
TEST_ASSERT_EQUAL_UINT(20, duplicate);
}
// getDuplicate erkennt fehlerhaftes Array
void test_getDuplicate_invalid_input(void) {
TEST_ASSERT_EQUAL_UINT(
0, getDuplicate(NULL, 5)); // unsigned int getDuplicate(const unsigned int
// *numbers, unsigned int len)
unsigned int testArray[1] = {2};
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(testArray, 1));
}
void setUp(void) {}
void tearDown(void) {}
int main(void) {
UNITY_BEGIN();
printf("\n------------------------numbers test------------------------\n\n");
RUN_TEST(test_createNumbers_length);
RUN_TEST(test_createNumbers_single_duplicate);
RUN_TEST(test_getDuplicate_manual_array);
RUN_TEST(test_getDuplicate_invalid_input);
return UNITY_END();
}
+103 -19
View File
@@ -5,40 +5,124 @@
#include "stack.h" #include "stack.h"
// StackNode *createNode(void *data) testen
void test_createNode(void) { void test_createNode(void) {
int testInt = 26; int testInt = 26;
StackNode *testNode = createNode(&testInt); // Adresse des testInts
StackNode *testNode = createNode(&testInt); TEST_ASSERT_NOT_NULL(
testNode); // Speicher konnte reserviert werden, malloc ist nicht NULL
TEST_ASSERT_EQUAL_PTR(&testInt, testNode->data); // data pointer gesetzt
TEST_ASSERT_NULL(testNode->next); // vorheriger und nächster Eintrag NULL
TEST_ASSERT_NULL(testNode->prev);
TEST_ASSERT_NOT_NULL(testNode); free(testNode); // Speicher freigeben
TEST_ASSERT_EQUAL_PTR(&testInt, testNode->data);
TEST_ASSERT_NULL(testNode->next);
free(testNode);
} }
void test_pushDataToStack(void) {} // StackNode *push(StackNode *stack, void *data) testen
void test_pushDataToStack(void) {
void test_deleteTopElement(void) {} int testInts[] = {27, 28};
void test_returnData(void) {} StackNode *testStack = NULL; // leeren testStack initialisieren
testStack =
push(testStack, &testInts[0]); // leerer Stack mit Adresse des testInts
TEST_ASSERT_NOT_NULL(testStack); // im Fehlerfall wird testStack unverändert
// zurückgegeben -> bei Fehler NULL
TEST_ASSERT_EQUAL_PTR(&testInts[0], testStack->data); // data pointer gesetzt
TEST_ASSERT_NULL(testStack->next); // vorheriger und nächster pointer auf NULL
// gesetzt, da es nur einen Knoten gibt
TEST_ASSERT_NULL(testStack->prev);
// zweiter Push
StackNode *oldHead = testStack; // bisherigen head speichern
testStack = push(testStack, &testInts[1]);
TEST_ASSERT_NOT_NULL(testStack);
TEST_ASSERT_NOT_EQUAL(
oldHead,
testStack); // bei malloc Fehler wird der head unverändert zurückgegeben
TEST_ASSERT_EQUAL_PTR(&testInts[0],
oldHead->data); // data pointer wurden richtig gesetzt
TEST_ASSERT_EQUAL_PTR(&testInts[1], testStack->data);
// richtige Verkettung: NULL <- testStack -> testStack->next -> oldHead ->
// NULL
TEST_ASSERT_EQUAL_PTR(oldHead, testStack->next);
TEST_ASSERT_EQUAL_PTR(testStack, oldHead->prev);
TEST_ASSERT_NULL(testStack->prev);
// Speicherfreigabe
testStack->next = NULL; // pointer ungültig machen, damit nicht ausversehen
// später aufgerufen
oldHead->prev = NULL;
free(oldHead);
free(testStack);
}
void test_deleteTopElement(void) {
int testInts[] = {10, 20, 30};
StackNode *stack = NULL;
for (int i = 0; i < 3;
i++) { // Stack mit drei Elementen, oberestes Element mit data 30
stack = push(stack, &testInts[i]);
}
TEST_ASSERT_EQUAL_PTR(&testInts[2], stack->data); // oberstes Element ist 30
stack = pop(stack); // oberstes Element löschen
TEST_ASSERT_EQUAL_PTR(&testInts[1], stack->data);
TEST_ASSERT_NULL(
stack->prev); // pointer zum alten head wurde auf NULL gesetzt
stack = pop(stack);
TEST_ASSERT_EQUAL_PTR(&testInts[0], stack->data);
TEST_ASSERT_NULL(stack->prev);
stack = pop(stack); // bei leerem Stack wird NULL zurückgegeben
TEST_ASSERT_NULL(stack);
}
void test_returnData(void) {
int testInts[] = {10, 20, 30};
StackNode *stack = NULL;
for (int i = 0; i < 3; i++) {
stack = push(stack, &testInts[i]);
}
TEST_ASSERT_EQUAL_PTR(&testInts[2],
top(stack)); // top gibt richtige Adresse zurück
stack = pop(stack); // oberstes Element löschen
TEST_ASSERT_EQUAL_PTR(&testInts[1], top(stack));
stack = pop(stack);
TEST_ASSERT_EQUAL_PTR(&testInts[0], top(stack));
stack = pop(stack); // bei leerem Stack wird NULL zurückgegeben
TEST_ASSERT_NULL(stack);
}
void test_clearStack(void) { void test_clearStack(void) {
int testInts[] = {1, 2, 3, 4, 5}; int testInts[] = {1, 2, 3, 4, 5};
StackNode *testStack = NULL; StackNode *stack = NULL;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
stack = push(stack, &testInts[i]);
testStack = push(testStack, &testInts[i]);
} }
//printf("testints: %d,%d,%d,%d,%d",testInts[0],testInts[1],testInts[2],testInts[3],testInts[4]); //printf("testints: %d,%d,%d,%d,%d",testInts[0],testInts[1],testInts[2],testInts[3],testInts[4]);
clearStack(&testStack); clearStack(&stack);
TEST_ASSERT_NULL(testStack);
TEST_ASSERT_NULL(stack);
} }
void setUp(void) {} void setUp(void) {}
@@ -48,13 +132,13 @@ int main(void) {
UNITY_BEGIN(); UNITY_BEGIN();
printf("------------------------stack test------------------------\n"); printf("\n------------------------stack test------------------------\n\n");
RUN_TEST(test_createNode); RUN_TEST(test_createNode);
RUN_TEST(test_pushDataToStack); RUN_TEST(test_pushDataToStack);
RUN_TEST(test_deleteTopElement); RUN_TEST(test_deleteTopElement);
RUN_TEST(test_returnData); RUN_TEST(test_returnData);
RUN_TEST(test_clearStack); RUN_TEST(test_clearStack);
RUN_TEST(test_clearStack);
return UNITY_END(); return UNITY_END();
} }
BIN
View File
Binary file not shown.