Compare commits

...

21 Commits
main ... Krisp

Author SHA1 Message Date
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
Kristin
d9222b83b4 highscore zum gitignore hinzugefügt 2025-12-09 10:27:18 +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
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
Kristin
8b44089f23 Remove object files 2025-12-05 10:25:10 +01:00
Kristin
654fb615a2 Remove object files 2025-12-05 10:24:32 +01:00
Kristin
422ac38d54 gitignore 2025-12-05 10:21:33 +01:00
Kristin
90612e4d04 stack.c 2025-12-05 10:20:17 +01:00
Kristin
17f4155891 stack.c 2025-12-05 10:08:55 +01:00
Kristin
a002901e2f highscore.txt zu gitignore 2025-12-02 10:40:28 +01:00
Kristin
55b25a227b makefile 2025-12-02 10:32:52 +01:00
13 changed files with 746 additions and 155 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
doble_initial.exe
*.o
*.exe
highscore.txt

123
bintree.c
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,122 @@
* `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) {
{ if (root == NULL)
return;
clearTree(root->left);
clearTree(root->right);
free(root->data);
free(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) {
{
if (root == NULL)
return 0;
return 1 + treeSize(root->left) + treeSize(root->right);
} }

View File

@ -5,19 +5,24 @@
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);

View File

@ -1 +1,10 @@
player1;3999 Kristin;49209
krisp;29797
krisp;29792
Kristin;29782
Kristin;19943
krisp;19934
krisp;19916
kristin;19861
Kristin;19858
krisp;19460

52
main.c
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();

View File

@ -24,26 +24,49 @@ 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_filesobj_files): %.o: %.c $(program_obj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@ $(CC) -c $(FLAGS) $^ -o $@
# -------------------------- # --------------------------
# Unit Tests # Unit Tests
# -------------------------- # --------------------------
unitTests:
echo "needs to be implemented" STACK_TEST_BIN = runStackTests
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
$(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) rm -f *.o doble $(STACK_TEST_BIN) $(NUMBERS_TEST_BIN) $(BINARY_TEST_BIN)
del /f *.o doble
else
rm -f *.o doble
endif

View File

@ -1,26 +1,94 @@
#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) {
if (!numbers || len < 2)
return 0; // Sicherheit: kein Array oder zu kurz
TreeNode *root = NULL;
unsigned int duplicateValue = 0;
for (unsigned int i = 0; i < len; i++) {
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]; // das erste Duplikat merken
}
}
clearTree(root); // Baum freigeben
return duplicateValue; // 0, falls kein Duplikat
} }

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

95
stack.c
View File

@ -1,33 +1,100 @@
#include <stdlib.h>
#include "stack.h" #include "stack.h"
#include <stdio.h>
#include <stdlib.h>
/*typedef struct {
void *data;
struct StackNode *next;
struct StackNode *prev;
} StackNode;*/
// TODO: grundlegende Stackfunktionen implementieren: // TODO: grundlegende Stackfunktionen implementieren:
/* * `push`: legt ein Element oben auf den Stack, /* `push`: legt ein Element oben auf den Stack,
* `pop`: entfernt das oberste Element, * `pop`: entfernt das oberste Element,
* `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. */
// Pushes data as pointer onto the stack. // [A] -> [B] -> [C] -> NULL
StackNode *push(StackNode *stack, void *data) // stack -> stack.next
{
// Funktion zum erstellen neuer nodes
StackNode *createNode(void *data) {
// Speicher reservieren
StackNode *node = malloc(sizeof(StackNode));
// Speicher konnte nicht reserviert werden
if (node == NULL)
return NULL;
node->data = data;
node->next = NULL;
node->prev = NULL;
return node;
} }
// Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be // Pushes data as pointer onto the stack.
// freed by caller.) StackNode *push(StackNode *stack, void *data) {
StackNode *pop(StackNode *stack)
{
StackNode *newNode = createNode(data);
// Fehler beim Reservieren des Speichers, stack wird unverändert zurückgegeben
if (newNode == NULL) {
return stack;
}
// der aktuelle Kopf wird der nächste Node
newNode->next = stack;
// bisheriger Kopf bekommt Pointer auf oberstes Element
if (stack != NULL) {
stack->prev = newNode;
}
return newNode; // neuer Kopf wird zurückgegeben
}
// 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)
return NULL;
// Element unter Kopf wird als nextNode gespeichert
StackNode *nextNode = stack->next;
if (nextNode != NULL) {
nextNode->prev = NULL; // der Zeiger zum Kopf wird auf NULL gesetzt
}
free(stack);
stack = NULL; // Speicher des Kopfes freigeben
return nextNode; // neuen Kopf zurückgeben
} }
// Returns the data of the top element. // Returns the data of the top element.
void *top(StackNode *stack) 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
// im Aufruf &stack verwenden
while (*stack != NULL) {
(*stack)->prev = NULL; // späteren Pointerzugriff verhindern
StackNode *next = (*stack)->next; // nächstes Element speichern
(*stack)->next = NULL; // späteren Pointerzugriff verhindern
free(*stack); // aktuelles Element freigeben
*stack = next; // Zeiger auf nächsten Knoten setzen
}
} }

22
stack.h
View File

@ -1,25 +1,35 @@
#ifndef STACK_H #ifndef STACK_H
#define STACK_H #define STACK_H
/* A stack is a special type of queue which uses the LIFO (last in, first out) principle. /* A stack is a special type of queue which uses the LIFO (last in, first out)
This means that with each new element all other elements are pushed deeper into the stack. principle. This means that with each new element all other elements are pushed
The latest element is taken from the stack. */ deeper into the stack. The latest element is taken from the stack. */
#include <stdlib.h> #include <stdlib.h>
// TODO: passenden Datentyp als struct anlegen // TODO: passenden Datentyp als struct anlegen
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);
// Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be // Deletes the top element of the stack (latest added element) and releases its
// freed by caller.) // memory. (Pointer to data has to be freed by caller.)
StackNode *pop(StackNode *stack); StackNode *pop(StackNode *stack);
// Returns the data of the top element. // Returns the data of the top element.
void *top(StackNode *stack); void *top(StackNode *stack);
// Clears stack and releases all memory. // Clears stack and releases all memory.
void clearStack(StackNode *stack); void clearStack(StackNode **stack);
#endif #endif

106
test_binary.c Normal file
View File

@ -0,0 +1,106 @@
#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
void test_addToTree_basic(void) {
int isDup;
unsigned int val = 10;
root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup);
TEST_ASSERT_NOT_NULL(root);
TEST_ASSERT_EQUAL_UINT(10, *(unsigned int *)root->data);
TEST_ASSERT_EQUAL_INT(0, isDup);
TEST_ASSERT_EQUAL_UINT(1, treeSize(root));
}
// Test, dass Duplikate erkannt werden
void test_addToTree_duplicate(void) {
int isDup;
unsigned int val1 = 10, val2 = 10;
root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDup);
TEST_ASSERT_EQUAL_INT(0, isDup);
root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, &isDup);
TEST_ASSERT_EQUAL_INT(1, isDup);
TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); // Duplikate nicht hinzufügen
}
// Test nextTreeData Traversierung
void test_nextTreeData_in_order(void) {
unsigned int values[] = {20, 10, 30};
int isDup;
for (int i = 0; i < 3; i++) {
root = addToTree(root, &values[i], sizeof(values[i]), compareUnsignedInt,
&isDup);
}
unsigned int expected[] = {10, 20, 30};
int idx = 0;
void *data;
// **Neue Iteration starten**
data = nextTreeData(root);
while (data != NULL) {
TEST_ASSERT_EQUAL_UINT(expected[idx], *(unsigned int *)data);
idx++;
data = nextTreeData(NULL); // weitere Elemente abrufen
}
TEST_ASSERT_EQUAL_INT(3, idx); // alle 3 Knoten besucht
}
// Test clearTree gibt Speicher frei
void test_clearTree(void) {
unsigned int val = 42;
int isDup;
root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup);
clearTree(root);
root = NULL; // clearTree löscht nicht die root-Variable selbst
TEST_ASSERT_NULL(root);
}
// Test treeSize zählt korrekt
void test_treeSize(void) {
unsigned int vals[] = {10, 20, 5};
int isDup;
for (int i = 0; i < 3; i++) {
root =
addToTree(root, &vals[i], sizeof(vals[i]), compareUnsignedInt, &isDup);
}
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);
RUN_TEST(test_treeSize);
return UNITY_END();
}

61
test_numbers.c Normal file
View File

@ -0,0 +1,61 @@
#include "unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "numbers.h"
#define TEST_ARRAY_LEN 100
void test_createNumbers_length(void) {
unsigned int *arr = createNumbers(TEST_ARRAY_LEN);
TEST_ASSERT_NOT_NULL(arr);
free(arr);
}
void test_createNumbers_single_duplicate(void) {
unsigned int *arr = createNumbers(TEST_ARRAY_LEN);
TEST_ASSERT_NOT_NULL(arr);
unsigned int duplicate = getDuplicate(arr, TEST_ARRAY_LEN);
TEST_ASSERT_TRUE(duplicate > 0);
unsigned int count = 0;
for (unsigned int i = 0; i < TEST_ARRAY_LEN; i++) {
if (arr[i] == duplicate) {
count++;
}
}
TEST_ASSERT_EQUAL_UINT(2, count);
free(arr);
}
void test_getDuplicate_manual_array(void) {
unsigned int numbers[5] = {10, 20, 30, 40, 20};
unsigned int dup = getDuplicate(numbers, 5);
TEST_ASSERT_EQUAL_UINT(20, dup);
}
void test_getDuplicate_invalid_input(void) {
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(NULL, 5));
unsigned int arr[1] = {42};
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(arr, 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();
}

143
test_stack.c Normal file
View File

@ -0,0 +1,143 @@
#include "unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"
// StackNode *createNode(void *data) testen
void test_createNode(void) {
int testInt = 26;
StackNode *testNode = createNode(&testInt); // Adresse des testInts
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);
free(testNode); // Speicher freigeben
}
// StackNode *push(StackNode *stack, void *data) testen
void test_pushDataToStack(void) {
int testInts[] = {27, 28};
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) {
int testInts[] = {1, 2, 3, 4, 5};
StackNode *stack = NULL;
for (int i = 0; i < 5; i++) {
stack = push(stack, &testInts[i]);
}
clearStack(&stack);
TEST_ASSERT_NULL(stack);
}
void setUp(void) {}
void tearDown(void) {}
int main(void) {
UNITY_BEGIN();
printf("\n------------------------stack test------------------------\n\n");
RUN_TEST(test_createNode);
RUN_TEST(test_pushDataToStack);
RUN_TEST(test_deleteTopElement);
RUN_TEST(test_returnData);
RUN_TEST(test_clearStack);
return UNITY_END();
}