Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed5f4eedc8 | |||
| d56c77d77a |
153
bintree.c
153
bintree.c
@ -2,35 +2,158 @@
|
||||
#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)
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Releases all memory resources (including data copies).
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Returns the number of entries in the tree given by 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);
|
||||
}
|
||||
|
||||
BIN
doble_initial.exe
Normal file
BIN
doble_initial.exe
Normal file
Binary file not shown.
BIN
highscore.o
Normal file
BIN
highscore.o
Normal file
Binary file not shown.
@ -1 +1,4 @@
|
||||
Kilian;9927
|
||||
Kilian;9915
|
||||
Kilian;4975
|
||||
player1;3999
|
||||
|
||||
70
makefile
70
makefile
@ -1,4 +1,4 @@
|
||||
CC = gcc
|
||||
CC = gcc
|
||||
FLAGS = -g -Wall -lm
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
@ -13,10 +13,18 @@ else
|
||||
endif
|
||||
|
||||
raylibfolder = ./raylib
|
||||
unityfolder = ./unity
|
||||
unityfolder = ./unity
|
||||
|
||||
# --------------------------
|
||||
# Initiales Programm bauen (zum ausprobieren)
|
||||
# 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
|
||||
@ -26,24 +34,66 @@ doble_initial:
|
||||
# --------------------------
|
||||
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
|
||||
|
||||
doble : main.o $(program_obj_files)
|
||||
doble: main.o $(program_obj_files)
|
||||
$(CC) $(FLAGS) $^ -o doble
|
||||
|
||||
$(program_obj_filesobj_files): %.o: %.c
|
||||
$(CC) -c $(FLAGS) $^ -o $@
|
||||
# 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
|
||||
# --------------------------
|
||||
unitTests:
|
||||
echo "needs to be implemented"
|
||||
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
|
||||
del /f *.o doble doble_initial test_stack test_numbers
|
||||
else
|
||||
rm -f *.o doble
|
||||
rm -f *.o doble doble_initial test_stack test_numbers
|
||||
endif
|
||||
99
numbers.c
99
numbers.c
@ -5,22 +5,109 @@
|
||||
#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. */
|
||||
// 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)
|
||||
}
|
||||
|
||||
29
stack.c
29
stack.c
@ -1,33 +1,46 @@
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
8
stack.h
8
stack.h
@ -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
test_numbers.c
Normal file
142
test_numbers.c
Normal file
@ -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;
|
||||
}
|
||||
BIN
test_numbers.exe
Normal file
BIN
test_numbers.exe
Normal file
Binary file not shown.
BIN
test_numbers.o
Normal file
BIN
test_numbers.o
Normal file
Binary file not shown.
102
test_stack.c
Normal file
102
test_stack.c
Normal file
@ -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;
|
||||
}
|
||||
BIN
test_stack.exe
Normal file
BIN
test_stack.exe
Normal file
Binary file not shown.
BIN
test_stack.o
Normal file
BIN
test_stack.o
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user