Template
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed5f4eedc8 | ||
|
|
d56c77d77a |
No files matched your search
-62
@@ -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.
@@ -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 +0,0 @@
|
||||
player1;3999
|
||||
@@ -1,49 +0,0 @@
|
||||
CC = gcc
|
||||
FLAGS = -g -Wall -lm
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
include makefile_windows.variables
|
||||
else
|
||||
UNAME = $(shell uname)
|
||||
ifeq ($(UNAME),Linux)
|
||||
include makefile_linux.variables
|
||||
else
|
||||
include makefile_mac.variables
|
||||
endif
|
||||
endif
|
||||
|
||||
raylibfolder = ./raylib
|
||||
unityfolder = ./unity
|
||||
|
||||
# --------------------------
|
||||
# Initiales Programm bauen (zum ausprobieren)
|
||||
# --------------------------
|
||||
doble_initial:
|
||||
$(CC) -o doble_initial $(BINARIES)/libdoble_complete.a
|
||||
|
||||
# --------------------------
|
||||
# Selbst implementiertes Programm bauen
|
||||
# --------------------------
|
||||
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
|
||||
$(CC) -c $(FLAGS) $^ -o $@
|
||||
|
||||
# --------------------------
|
||||
# Unit Tests
|
||||
# --------------------------
|
||||
unitTests:
|
||||
echo "needs to be implemented"
|
||||
|
||||
# --------------------------
|
||||
# Clean
|
||||
# --------------------------
|
||||
clean:
|
||||
ifeq ($(OS),Windows_NT)
|
||||
del /f *.o doble
|
||||
else
|
||||
rm -f *.o doble
|
||||
endif
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
#include <string.h>
|
||||
#include "stack.h"
|
||||
#include "bintree.h"
|
||||
|
||||
// Fügt ein neues Element in den Binärbaum ein.
|
||||
// - data wird kopiert (tiefe Kopie)
|
||||
// - compareFct bestimmt die Sortierreihenfolge
|
||||
// - Duplikate sind erlaubt, außer isDuplicate ist gesetzt
|
||||
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
|
||||
CompareFctType compareFct, int *isDuplicate)
|
||||
{
|
||||
// Ungültige Parameter → Baum unverändert zurückgeben
|
||||
if (data == NULL || compareFct == NULL)
|
||||
return root;
|
||||
|
||||
// Fall: leerer Teilbaum → neuer Knoten wird erzeugt
|
||||
if (root == NULL)
|
||||
{
|
||||
// Speicher für neuen Baumknoten reservieren
|
||||
TreeNode *node = malloc(sizeof(TreeNode));
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
|
||||
// Speicher für die Nutzdaten reservieren
|
||||
node->data = malloc(dataSize);
|
||||
if (node->data == NULL)
|
||||
{
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Daten in den Knoten kopieren
|
||||
memcpy(node->data, data, dataSize);
|
||||
|
||||
// Linke und rechte Kindzeiger initialisieren
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
|
||||
// Kein Duplikat, da neuer Knoten
|
||||
if (isDuplicate != NULL)
|
||||
*isDuplicate = 0;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Vergleich der neuen Daten mit den Daten im aktuellen Knoten
|
||||
int cmp = compareFct(data, root->data);
|
||||
|
||||
if (cmp < 0)
|
||||
{
|
||||
// Neuer Wert ist kleiner → Rekursion im linken Teilbaum
|
||||
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
|
||||
}
|
||||
else if (cmp > 0)
|
||||
{
|
||||
// Neuer Wert ist größer → Rekursion im rechten Teilbaum
|
||||
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gleicher Wert → Duplikat
|
||||
if (isDuplicate != NULL)
|
||||
{
|
||||
// Duplikat melden, aber nicht einfügen
|
||||
*isDuplicate = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Duplikate sind erlaubt → z.B. links einfügen
|
||||
root->left = addToTree(root->left, data, dataSize, compareFct, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Wurzel des (Teil-)Baumes zurückgeben
|
||||
return root;
|
||||
}
|
||||
|
||||
// Globaler interner Stack für die Baum-Traversierung
|
||||
// Ermöglicht ein strtok-ähnliches Iterator-Verhalten
|
||||
static StackNode *iterStack = NULL;
|
||||
|
||||
// Hilfsfunktion:
|
||||
// Legt den Startknoten und alle seine linken Nachfolger auf den Stack
|
||||
static void pushLeftPath(TreeNode *start)
|
||||
{
|
||||
// Solange noch ein Knoten existiert
|
||||
while (start != NULL)
|
||||
{
|
||||
// Aktuellen Knoten auf den Stack legen
|
||||
iterStack = push(iterStack, start);
|
||||
|
||||
// Zum linken Kind weitergehen
|
||||
start = start->left;
|
||||
}
|
||||
}
|
||||
|
||||
// Gibt nacheinander die Daten des Baumes in sortierter Reihenfolge zurück.
|
||||
// - Beim ersten Aufruf root ≠ NULL → neue Traversierung
|
||||
// - Danach root == NULL → nächstes Element liefern
|
||||
void *nextTreeData(TreeNode *root)
|
||||
{
|
||||
if (root != NULL)
|
||||
{
|
||||
// Neue Traversierung starten → alten Stack leeren
|
||||
if (iterStack != NULL)
|
||||
{
|
||||
clearStack(iterStack);
|
||||
iterStack = NULL;
|
||||
}
|
||||
|
||||
// Wurzel und alle linken Knoten auf den Stack legen
|
||||
pushLeftPath(root);
|
||||
}
|
||||
|
||||
// Kein weiteres Element vorhanden
|
||||
if (iterStack == NULL)
|
||||
return NULL;
|
||||
|
||||
// Oberstes Stack-Element holen (nächster Baumknoten)
|
||||
TreeNode *node = (TreeNode *)top(iterStack);
|
||||
iterStack = pop(iterStack);
|
||||
|
||||
// Rechten Teilbaum dieses Knotens behandeln
|
||||
// → dessen linker Pfad wird auf den Stack gelegt
|
||||
if (node->right != NULL)
|
||||
pushLeftPath(node->right);
|
||||
|
||||
// Daten des aktuellen Knotens zurückgeben
|
||||
return node->data;
|
||||
}
|
||||
|
||||
// Gibt den gesamten Speicher des Baumes frei (inkl. gespeicherter Daten)
|
||||
void clearTree(TreeNode *root)
|
||||
{
|
||||
// Abbruchbedingung der Rekursion
|
||||
if (root == NULL)
|
||||
return;
|
||||
|
||||
// Zuerst linken Teilbaum freigeben
|
||||
clearTree(root->left);
|
||||
|
||||
// Dann rechten Teilbaum freigeben
|
||||
clearTree(root->right);
|
||||
|
||||
// Danach Daten und Knoten selbst freigeben
|
||||
free(root->data);
|
||||
free(root);
|
||||
}
|
||||
|
||||
// Liefert die Anzahl aller Knoten im Baum
|
||||
unsigned int treeSize(const TreeNode *root)
|
||||
{
|
||||
// Leerer Baum hat Größe 0
|
||||
if (root == NULL)
|
||||
return 0;
|
||||
|
||||
// 1 (aktueller Knoten) + Größe linker + Größe rechter Teilbaum
|
||||
return 1u + treeSize(root->left) + treeSize(root->right);
|
||||
}
|
||||
File renamed without changes.
Binary file not shown.
File renamed without changes.
File renamed without changes.
BIN
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
Kilian;9927
|
||||
Kilian;9915
|
||||
Kilian;4975
|
||||
player1;3999
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,99 @@
|
||||
CC = gcc
|
||||
FLAGS = -g -Wall -lm
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
include makefile_windows.variables
|
||||
else
|
||||
UNAME = $(shell uname)
|
||||
ifeq ($(UNAME),Linux)
|
||||
include makefile_linux.variables
|
||||
else
|
||||
include makefile_mac.variables
|
||||
endif
|
||||
endif
|
||||
|
||||
raylibfolder = ./raylib
|
||||
unityfolder = ./unity
|
||||
|
||||
# --------------------------
|
||||
# Phony Targets
|
||||
# --------------------------
|
||||
.PHONY: all doble doble_initial unitTests test_stack test_numbers clean vorbereitungen prepare
|
||||
|
||||
# Standard-Target
|
||||
all: doble
|
||||
|
||||
# --------------------------
|
||||
# Initiales Programm bauen (zum Ausprobieren)
|
||||
# --------------------------
|
||||
doble_initial:
|
||||
$(CC) -o doble_initial $(BINARIES)/libdoble_complete.a
|
||||
|
||||
# --------------------------
|
||||
# Selbst implementiertes Programm bauen
|
||||
# --------------------------
|
||||
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
|
||||
|
||||
doble: main.o $(program_obj_files)
|
||||
$(CC) $(FLAGS) $^ -o doble
|
||||
|
||||
# Generische Regel zum Bauen von .o aus .c
|
||||
%.o: %.c
|
||||
$(CC) $(FLAGS) -c $< -o $@
|
||||
|
||||
# Abhängigkeiten (optional, aber hilfreich für inkrementelles Bauen)
|
||||
main.o: main.c numbers.h stack.h bintree.h timer.h highscore.h
|
||||
numbers.o: numbers.c numbers.h bintree.h
|
||||
bintree.o: bintree.c bintree.h stack.h
|
||||
stack.o: stack.c stack.h
|
||||
timer.o: timer.c timer.h
|
||||
highscore.o: highscore.c highscore.h
|
||||
|
||||
test_stack.o: test_stack.c stack.h
|
||||
test_numbers.o: test_numbers.c numbers.h bintree.h stack.h
|
||||
|
||||
# --------------------------
|
||||
# Unit Tests
|
||||
# --------------------------
|
||||
test_stack: test_stack.o stack.o
|
||||
$(CC) $(FLAGS) $^ -o test_stack
|
||||
|
||||
test_numbers: test_numbers.o numbers.o stack.o bintree.o
|
||||
$(CC) $(FLAGS) $^ -o test_numbers
|
||||
|
||||
unitTests: test_stack test_numbers
|
||||
./test_stack
|
||||
./test_numbers
|
||||
|
||||
# --------------------------
|
||||
# Vorbereitungen zum Bauen des Programms
|
||||
# --------------------------
|
||||
vorbereitungen:
|
||||
@echo "== Vorbereitungen zum Bauen des Programms =="
|
||||
@echo "Prüfe benötigte Dateien..."
|
||||
@test -f numbers.c || (echo "FEHLT: numbers.c" && exit 1)
|
||||
@test -f numbers.h || (echo "FEHLT: numbers.h" && exit 1)
|
||||
@test -f bintree.c || (echo "FEHLT: bintree.c" && exit 1)
|
||||
@test -f bintree.h || (echo "FEHLT: bintree.h" && exit 1)
|
||||
@test -f stack.c || (echo "FEHLT: stack.c" && exit 1)
|
||||
@test -f stack.h || (echo "FEHLT: stack.h" && exit 1)
|
||||
@test -f timer.c || (echo "FEHLT: timer.c" && exit 1)
|
||||
@test -f timer.h || (echo "FEHLT: timer.h" && exit 1)
|
||||
@test -f highscore.c || (echo "FEHLT: highscore.c" && exit 1)
|
||||
@test -f highscore.h || (echo "FEHLT: highscore.h" && exit 1)
|
||||
@test -f main.c || (echo "FEHLT: main.c" && exit 1)
|
||||
@echo "Alle Dateien vorhanden."
|
||||
@echo "Vorbereitung abgeschlossen!"
|
||||
|
||||
# englischer Alias
|
||||
prepare: vorbereitungen
|
||||
|
||||
# --------------------------
|
||||
# Clean
|
||||
# --------------------------
|
||||
clean:
|
||||
ifeq ($(OS),Windows_NT)
|
||||
del /f *.o doble doble_initial test_stack test_numbers
|
||||
else
|
||||
rm -f *.o doble doble_initial test_stack test_numbers
|
||||
endif
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,113 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "numbers.h"
|
||||
#include "bintree.h"
|
||||
|
||||
// Hilfsfunktion für qsort und den Binärbaum: Vergleich von unsigned int
|
||||
static int compareUnsignedInt(const void *a, const void *b)
|
||||
{
|
||||
const unsigned int *ua = (const unsigned int *)a;
|
||||
const unsigned int *ub = (const unsigned int *)b;
|
||||
|
||||
if (*ua < *ub)
|
||||
return -1;
|
||||
else if (*ua > *ub)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (len < 2)
|
||||
return NULL;
|
||||
|
||||
unsigned int *numbers = malloc(len * sizeof(unsigned int));
|
||||
if (numbers == NULL)
|
||||
return NULL;
|
||||
|
||||
// Zufall initialisieren
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
TreeNode *root = NULL;
|
||||
unsigned int i = 0;
|
||||
|
||||
// len-1 verschiedene Zufallszahlen im Bereich [1, 2*len] erzeugen
|
||||
while (i < len - 1)
|
||||
{
|
||||
unsigned int candidate = (unsigned int)(rand() % (2 * len)) + 1;
|
||||
int isDuplicate = 0;
|
||||
|
||||
TreeNode *newRoot = addToTree(root, &candidate, sizeof(unsigned int),
|
||||
compareUnsignedInt, &isDuplicate);
|
||||
if (newRoot == NULL && root == NULL)
|
||||
{
|
||||
// Speicherfehler beim ersten Einfügen
|
||||
clearTree(root);
|
||||
free(numbers);
|
||||
return NULL;
|
||||
}
|
||||
root = newRoot;
|
||||
|
||||
if (!isDuplicate)
|
||||
{
|
||||
numbers[i] = candidate;
|
||||
++i;
|
||||
}
|
||||
// bei Duplikat wird einfach eine neue Zufallszahl generiert
|
||||
}
|
||||
|
||||
// Einen zufälligen Eintrag aus den ersten len-1 duplizieren
|
||||
unsigned int duplicateIndex = (unsigned int)(rand() % (len - 1));
|
||||
numbers[len - 1] = numbers[duplicateIndex];
|
||||
|
||||
// Baum wird nicht mehr benötigt
|
||||
clearTree(root);
|
||||
|
||||
// Das Array durchmischen (Fisher-Yates-Shuffle), damit das Duplikat an zufälliger Position steht
|
||||
for (unsigned int j = len - 1; j > 0; --j)
|
||||
{
|
||||
unsigned int k = (unsigned int)(rand() % (j + 1));
|
||||
unsigned int tmp = numbers[j];
|
||||
numbers[j] = numbers[k];
|
||||
numbers[k] = tmp;
|
||||
}
|
||||
|
||||
return numbers;
|
||||
}
|
||||
|
||||
// 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 == NULL || len < 2)
|
||||
return 0;
|
||||
|
||||
// Kopie des Arrays anlegen, da qsort in-place sortiert
|
||||
unsigned int *copy = malloc(len * sizeof(unsigned int));
|
||||
if (copy == NULL)
|
||||
return 0;
|
||||
|
||||
memcpy(copy, numbers, len * sizeof(unsigned int));
|
||||
|
||||
// Sortieren mit qsort
|
||||
qsort(copy, len, sizeof(unsigned int), compareUnsignedInt);
|
||||
|
||||
// Benachbarte Elemente vergleichen, um das Duplikat zu finden
|
||||
unsigned int duplicate = 0;
|
||||
for (unsigned int i = 1; i < len; ++i)
|
||||
{
|
||||
if (copy[i] == copy[i - 1])
|
||||
{
|
||||
duplicate = copy[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(copy);
|
||||
return duplicate; // 0 falls kein Duplikat gefunden (Fehlerfall)
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,46 @@
|
||||
#include <stdlib.h>
|
||||
#include "stack.h"
|
||||
|
||||
// Pushes data as pointer onto the stack.
|
||||
StackNode *push(StackNode *stack, void *data)
|
||||
{
|
||||
StackNode *node = (StackNode *)malloc(sizeof(StackNode));
|
||||
if (node == NULL)
|
||||
return stack; // keine Änderung bei Speicherfehler
|
||||
|
||||
node->data = data;
|
||||
node->next = stack;
|
||||
return node;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (stack == NULL)
|
||||
return NULL;
|
||||
|
||||
StackNode *next = stack->next;
|
||||
free(stack);
|
||||
return next;
|
||||
}
|
||||
|
||||
// Returns the data of the top element.
|
||||
void *top(StackNode *stack)
|
||||
{
|
||||
if (stack == NULL)
|
||||
return NULL;
|
||||
|
||||
return stack->data;
|
||||
}
|
||||
|
||||
// Clears stack and releases all memory.
|
||||
void clearStack(StackNode *stack)
|
||||
{
|
||||
while (stack != NULL)
|
||||
{
|
||||
StackNode *next = stack->next;
|
||||
free(stack);
|
||||
stack = next;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,12 @@ The latest element is taken from the stack. */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
//TODO: passenden Datentyp als struct anlegen
|
||||
// einfacher verketteter Stack
|
||||
typedef struct StackNode
|
||||
{
|
||||
void *data;
|
||||
struct StackNode *next;
|
||||
} StackNode;
|
||||
|
||||
// Pushes data as pointer onto the stack.
|
||||
StackNode *push(StackNode *stack, void *data);
|
||||
@@ -23,3 +28,4 @@ void *top(StackNode *stack);
|
||||
void clearStack(StackNode *stack);
|
||||
|
||||
#endif
|
||||
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "numbers.h"
|
||||
|
||||
/*
|
||||
* Unit-Tests für createNumbers und getDuplicate:
|
||||
* - createNumbers liefert ein gültiges Array
|
||||
* - alle Zahlen liegen im Bereich [1, 2*len]
|
||||
* - genau eine Zahl kommt doppelt vor
|
||||
* - getDuplicate findet genau diese doppelte Zahl
|
||||
* - Fehlerfälle (NULL-Pointer, zu kleine Länge)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Prüft ein Zahlenarray auf Korrektheit:
|
||||
* - Array darf nicht NULL sein
|
||||
* - Wertebereich muss stimmen
|
||||
* - genau eine Zahl darf doppelt vorkommen
|
||||
*/
|
||||
static void check_numbers_array(unsigned int *numbers, unsigned int len)
|
||||
{
|
||||
unsigned int maxValue = 2 * len; // Maximal erlaubter Zahlenwert
|
||||
unsigned int *counts; // Array zum Zählen der Vorkommen
|
||||
unsigned int i;
|
||||
unsigned int duplicatesCount = 0; // Zähler für doppelte Werte
|
||||
|
||||
assert(numbers != NULL); // Sicherstellen, dass das Array existiert
|
||||
|
||||
// Speicher für Zähler-Array reservieren und mit 0 initialisieren
|
||||
counts = (unsigned int *)calloc(maxValue + 1, sizeof(unsigned int));
|
||||
assert(counts != NULL); // Prüfen, ob Speicher erfolgreich reserviert wurde
|
||||
|
||||
// Schleife über alle Elemente des numbers-Arrays
|
||||
// Zählt die Werte und prüft gleichzeitig den gültigen Wertebereich
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
unsigned int v = numbers[i]; // Aktueller Wert
|
||||
assert(v >= 1 && v <= maxValue); // Wertebereich prüfen
|
||||
counts[v]++; // Anzahl dieses Wertes erhöhen
|
||||
}
|
||||
|
||||
// Schleife über alle möglichen Werte
|
||||
// Prüft, dass genau ein Wert doppelt vorkommt
|
||||
for (i = 1; i <= maxValue; ++i)
|
||||
{
|
||||
if (counts[i] == 2)
|
||||
duplicatesCount++; // Ein doppelter Wert gefunden
|
||||
else
|
||||
assert(counts[i] == 0 || counts[i] == 1); // Alle anderen max. einmal
|
||||
}
|
||||
|
||||
assert(duplicatesCount == 1); // Es darf genau ein Duplikat geben
|
||||
|
||||
free(counts); // Speicher freigeben
|
||||
}
|
||||
|
||||
/*
|
||||
* Testet createNumbers und getDuplicate für eine gegebene Länge
|
||||
*/
|
||||
static void test_createNumbers_and_getDuplicate(unsigned int len)
|
||||
{
|
||||
printf("test_createNumbers_and_getDuplicate(len=%u)...\n", len);
|
||||
|
||||
// Zahlenarray erzeugen
|
||||
unsigned int *numbers = createNumbers(len);
|
||||
assert(numbers != NULL); // Rückgabewert prüfen
|
||||
|
||||
// Struktur und Inhalt des Arrays überprüfen
|
||||
check_numbers_array(numbers, len);
|
||||
|
||||
// Erneutes Zählen, um das erwartete Duplikat zu ermitteln
|
||||
unsigned int maxValue = 2 * len;
|
||||
unsigned int *counts = (unsigned int *)calloc(maxValue + 1, sizeof(unsigned int));
|
||||
assert(counts != NULL);
|
||||
|
||||
// Schleife zum Zählen aller Werte
|
||||
for (unsigned int i = 0; i < len; ++i)
|
||||
{
|
||||
unsigned int v = numbers[i];
|
||||
counts[v]++;
|
||||
}
|
||||
|
||||
// Schleife zur Bestimmung des doppelten Wertes
|
||||
unsigned int expectedDuplicate = 0;
|
||||
for (unsigned int v = 1; v <= maxValue; ++v)
|
||||
{
|
||||
if (counts[v] == 2)
|
||||
{
|
||||
expectedDuplicate = v; // Doppelten Wert merken
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(expectedDuplicate != 0); // Es muss ein Duplikat existieren
|
||||
|
||||
// getDuplicate-Funktion testen
|
||||
unsigned int found = getDuplicate(numbers, len);
|
||||
assert(found == expectedDuplicate); // Ergebnis vergleichen
|
||||
|
||||
free(counts); // Speicher freigeben
|
||||
free(numbers);
|
||||
|
||||
printf("...OK\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Testet Fehlerfälle für getDuplicate
|
||||
*/
|
||||
static void test_getDuplicate_error_cases(void)
|
||||
{
|
||||
printf("test_getDuplicate_error_cases...\n");
|
||||
|
||||
// Test mit NULL-Pointer
|
||||
unsigned int dup = getDuplicate(NULL, 10);
|
||||
assert(dup == 0);
|
||||
|
||||
// Test mit zu kleiner Länge (< 2)
|
||||
unsigned int dummy[1] = {42};
|
||||
dup = getDuplicate(dummy, 1);
|
||||
assert(dup == 0);
|
||||
|
||||
printf("...OK\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Hauptfunktion: startet alle Unit-Tests
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
printf("Running numbers unit tests...\n\n");
|
||||
|
||||
// Typische Testfälle mit unterschiedlichen Array-Längen
|
||||
test_createNumbers_and_getDuplicate(5);
|
||||
test_createNumbers_and_getDuplicate(10);
|
||||
test_createNumbers_and_getDuplicate(20);
|
||||
|
||||
// Test der Fehlerfälle
|
||||
test_getDuplicate_error_cases();
|
||||
|
||||
printf("\nAll numbers tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
+102
@@ -0,0 +1,102 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "stack.h"
|
||||
|
||||
/*
|
||||
* Einfache Unit-Tests für den Stack:
|
||||
* - push/pop: LIFO-Verhalten
|
||||
* - top: richtiges Element
|
||||
* - Verhalten bei leerem Stack
|
||||
*/
|
||||
|
||||
static void test_push_pop_lifo(void)
|
||||
{
|
||||
printf("test_push_pop_lifo...\n");
|
||||
|
||||
StackNode *stack = NULL;
|
||||
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int c = 3;
|
||||
|
||||
stack = push(stack, &a);
|
||||
stack = push(stack, &b);
|
||||
stack = push(stack, &c);
|
||||
|
||||
// LIFO: zuerst c
|
||||
assert(top(stack) == &c);
|
||||
stack = pop(stack);
|
||||
|
||||
// dann b
|
||||
assert(top(stack) == &b);
|
||||
stack = pop(stack);
|
||||
|
||||
// dann a
|
||||
assert(top(stack) == &a);
|
||||
stack = pop(stack);
|
||||
|
||||
// jetzt leer
|
||||
assert(stack == NULL);
|
||||
assert(top(stack) == NULL);
|
||||
|
||||
printf("...OK\n");
|
||||
}
|
||||
|
||||
static void test_empty_stack_operations(void)
|
||||
{
|
||||
printf("test_empty_stack_operations...\n");
|
||||
|
||||
StackNode *stack = NULL;
|
||||
|
||||
// pop auf leerem Stack sollte einfach NULL liefern
|
||||
stack = pop(stack);
|
||||
assert(stack == NULL);
|
||||
|
||||
// top auf leerem Stack sollte NULL liefern
|
||||
assert(top(stack) == NULL);
|
||||
|
||||
// clearStack auf leerem Stack darf nicht crashen
|
||||
clearStack(stack);
|
||||
|
||||
printf("...OK\n");
|
||||
}
|
||||
|
||||
static void test_clearStack(void)
|
||||
{
|
||||
printf("test_clearStack...\n");
|
||||
|
||||
StackNode *stack = NULL;
|
||||
int values[10];
|
||||
int i;
|
||||
|
||||
// Wir legen 10 Elemente auf den Stack
|
||||
for (i = 0; i < 10; ++i)
|
||||
{
|
||||
values[i] = i;
|
||||
stack = push(stack, &values[i]);
|
||||
}
|
||||
|
||||
// Stack leeren – clearStack muss alle StackNodes freigeben
|
||||
clearStack(stack);
|
||||
stack = NULL; // Pointer selbst auf NULL setzen
|
||||
|
||||
// Auf leerem Stack dürfen die Operationen nicht crashen
|
||||
assert(top(stack) == NULL);
|
||||
stack = pop(stack);
|
||||
assert(stack == NULL);
|
||||
|
||||
printf("...OK\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("Running stack unit tests...\n\n");
|
||||
|
||||
test_push_pop_lifo();
|
||||
test_empty_stack_operations();
|
||||
test_clearStack();
|
||||
|
||||
printf("\nAll stack tests passed.\n");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user