Merge pull request 'main' (#3) from main into JD_Branch
Reviewed-on: #3
This commit is contained in:
commit
db14f57789
40
.vscode/launch.json
vendored
Normal file
40
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug test_stack",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/test_stack.exe",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "C:/ProgramData/mingw64/mingw64/bin/gdb.exe",
|
||||||
|
"preLaunchTask": "Build via Makefile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug test_numbers",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/test_numbers.exe",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "C:/ProgramData/mingw64/mingw64/bin/gdb.exe",
|
||||||
|
"preLaunchTask": "Build via Makefile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug test_bintree",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/test_bintree.exe",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "C:/ProgramData/mingw64/mingw64/bin/gdb.exe",
|
||||||
|
"preLaunchTask": "Build via Makefile"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
27
.vscode/tasks.json
vendored
Normal file
27
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Build via Makefile",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "mingw32-make",
|
||||||
|
"args": ["${input:target}"],
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"problemMatcher": "$gcc"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"id": "target",
|
||||||
|
"type": "pickString",
|
||||||
|
"description": "Welches Makefile-Target soll gebaut werden?",
|
||||||
|
"options": ["test_stack", "test_numbers", "test_bintree", "doble", "unitTests"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
150
bintree.c
150
bintree.c
@ -1,36 +1,148 @@
|
|||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
#include "bintree.h"
|
#include "bintree.h"
|
||||||
|
|
||||||
//TODO: binären Suchbaum implementieren
|
/*
|
||||||
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv),
|
Schiebt einen Knoten und alle seine linken Nachfolger
|
||||||
* `clearTree`: gibt den gesamten Baum frei (rekursiv),
|
(entlang der "linken Kante") auf den Iterator-Stack.
|
||||||
* `treeSize`: zählt die Knoten im Baum (rekursiv),
|
iterStackPtr: Zeiger auf den Top-Zeiger des Stacks (LIFO) für die Wiederholung
|
||||||
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */
|
knoten: aktueller Startknoten, dessen linke Kette abgelegt wird
|
||||||
|
*/
|
||||||
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
|
static void bintree_pushLefts(StackNode **iterStackPtr, TreeNode *knoten)
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
|
while (knoten != NULL)
|
||||||
|
{
|
||||||
|
*iterStackPtr = push(*iterStackPtr, knoten); // aktuellen Knoten oben auf den Stack legen
|
||||||
|
knoten = knoten->left; // zum linken Kind weiterlaufen
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
Fügt eine Kopie der Daten (Speicherbereich von 'data' mit Länge 'dataSize') in den Baum ein.
|
||||||
// push the top node and push all its left nodes.
|
Die Ordnung wird über 'compareFct' festgelegt.
|
||||||
void *nextTreeData(TreeNode *root)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
Duplikate:
|
||||||
|
- Wenn 'isDuplicate' != NULL übergeben wird: Duplikate werden NICHT eingefügt,
|
||||||
|
stattdessen wird *isDuplicate = 1 gesetzt (bei neuem Eintrag = 0).
|
||||||
|
- Wenn 'isDuplicate' == NULL: Duplikate SIND erlaubt; der Duplikat-Eintrag
|
||||||
|
wird in den rechten Teilbaum eingefügt.
|
||||||
|
|
||||||
|
Rückgabe:
|
||||||
|
- Zeiger auf die (ggf. unveränderte oder neue) Wurzel des Teilbaums.
|
||||||
|
- NULL bei Speicherfehlern beim Anlegen des ersten Knotens.
|
||||||
|
*/
|
||||||
|
TreeNode *addToTree(TreeNode *wurzel,
|
||||||
|
const void *daten,
|
||||||
|
size_t datenGroesse,
|
||||||
|
CompareFctType vergleichFkt,
|
||||||
|
int *istDuplikat)
|
||||||
|
{
|
||||||
|
// Standardmäßig annehmen: kein Duplikat (falls Ausgabefeld vorhanden)
|
||||||
|
if (istDuplikat != NULL)
|
||||||
|
*istDuplikat = 0;
|
||||||
|
|
||||||
|
// Leerer Baum/Teilbaum: neuen Knoten erzeugen
|
||||||
|
if (wurzel == NULL)
|
||||||
|
{
|
||||||
|
TreeNode *neuerKnoten = (TreeNode *)malloc(sizeof(TreeNode));
|
||||||
|
if (neuerKnoten == NULL)
|
||||||
|
return NULL; // Speicherfehler
|
||||||
|
|
||||||
|
neuerKnoten->data = malloc(datenGroesse);
|
||||||
|
if (neuerKnoten->data == NULL)
|
||||||
|
{
|
||||||
|
free(neuerKnoten);
|
||||||
|
return NULL; // Speicherfehler für Datenbereich
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(neuerKnoten->data, daten, datenGroesse); // tiefe Kopie der Nutzdaten
|
||||||
|
neuerKnoten->left = neuerKnoten->right = NULL; // Blatt
|
||||||
|
return neuerKnoten;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vergleich der einzufügenden Daten mit dem aktuellen Knoten
|
||||||
|
int vergleich = vergleichFkt(daten, wurzel->data);
|
||||||
|
|
||||||
|
if (vergleich < 0)
|
||||||
|
{
|
||||||
|
// links einfügen
|
||||||
|
wurzel->left = addToTree(wurzel->left, daten, datenGroesse, vergleichFkt, istDuplikat);
|
||||||
|
}
|
||||||
|
else if (vergleich > 0)
|
||||||
|
{
|
||||||
|
// rechts einfügen
|
||||||
|
wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Gleichheit (potenzielles Duplikat)
|
||||||
|
if (istDuplikat != NULL)
|
||||||
|
{
|
||||||
|
*istDuplikat = 1; // Duplikat erkannt, NICHT einfügen
|
||||||
|
// keine Änderung am Baum
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Duplikate erlaubt -> konventionell in den rechten Teilbaum einfügen
|
||||||
|
wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wurzel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Releases all memory resources (including data copies).
|
void *nextTreeData(TreeNode *wurzel)
|
||||||
void clearTree(TreeNode *root)
|
|
||||||
{
|
{
|
||||||
|
static StackNode *iteratorStack = NULL; // interner Zustand über Aufrufe hinweg
|
||||||
|
|
||||||
|
// Neuer Baum übergeben -> Iterator zurücksetzen/initialisieren
|
||||||
|
if (wurzel != NULL)
|
||||||
|
{
|
||||||
|
clearStack(iteratorStack); // ggf. alten Stack leeren (Speicher freigeben)
|
||||||
|
iteratorStack = NULL; // Top-Zeiger zurücksetzen
|
||||||
|
bintree_pushLefts(&iteratorStack, wurzel); // Wurzel und linke Kette ablegen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kein weiterer Eintrag?
|
||||||
|
if (iteratorStack == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Nächsten Knoten holen (oberstes Stack-Element)
|
||||||
|
TreeNode *aktuellerKnoten = (TreeNode *)top(iteratorStack);
|
||||||
|
iteratorStack = pop(iteratorStack);
|
||||||
|
|
||||||
|
// Falls rechter Teilbaum existiert: dessen linke Kette ablegen
|
||||||
|
if (aktuellerKnoten->right != NULL)
|
||||||
|
bintree_pushLefts(&iteratorStack, aktuellerKnoten->right);
|
||||||
|
|
||||||
|
// Daten des aktuellen Knotens zurückgeben
|
||||||
|
return aktuellerKnoten->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of entries in the tree given by root.
|
/*
|
||||||
unsigned int treeSize(const TreeNode *root)
|
Gibt den gesamten Baum frei (inkl. der tief kopierten Daten).
|
||||||
|
*/
|
||||||
|
void clearTree(TreeNode *wurzel)
|
||||||
{
|
{
|
||||||
|
if (wurzel == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearTree(wurzel->left);
|
||||||
|
clearTree(wurzel->right);
|
||||||
|
|
||||||
|
free(wurzel->data);
|
||||||
|
free(wurzel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Liefert die Anzahl der Knoten/Einträge im Teilbaum 'wurzel'.
|
||||||
|
*/
|
||||||
|
unsigned int treeSize(const TreeNode *wurzel)
|
||||||
|
{
|
||||||
|
if (wurzel == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1U + treeSize(wurzel->left) + treeSize(wurzel->right);
|
||||||
}
|
}
|
||||||
74
bintree.h
74
bintree.h
@ -1,27 +1,81 @@
|
|||||||
|
|
||||||
#ifndef BINTREE_H
|
#ifndef BINTREE_H
|
||||||
#define BINTREE_H
|
#define BINTREE_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Typdefinition für die Vergleichsfunktion.
|
||||||
|
|
||||||
|
Die Funktion muss zwei Datenzeiger vergleichen und zurückgeben:
|
||||||
|
- < 0, wenn arg1 kleiner als arg2 ist
|
||||||
|
- 0, wenn arg1 gleich arg2 ist
|
||||||
|
- > 0, wenn arg1 größer als arg2 ist
|
||||||
|
*/
|
||||||
typedef int (*CompareFctType)(const void *arg1, const void *arg2);
|
typedef int (*CompareFctType)(const void *arg1, const void *arg2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Struktur für einen Binärbaum-Knoten.
|
||||||
|
|
||||||
|
Enthält:
|
||||||
|
- data: Zeiger auf die gespeicherten Daten (beliebiger Typ, dynamisch allokiert)
|
||||||
|
- left: Zeiger auf linken Teilbaum
|
||||||
|
- right: Zeiger auf rechten Teilbaum
|
||||||
|
*/
|
||||||
typedef struct node
|
typedef struct node
|
||||||
{
|
{
|
||||||
void *data;
|
void *data; // Zeiger auf die Nutzdaten
|
||||||
struct node *left;
|
struct node *left; // Zeiger auf linken Kindknoten
|
||||||
struct node *right;
|
struct node *right; // Zeiger auf rechten Kindknoten
|
||||||
} TreeNode;
|
} TreeNode;
|
||||||
|
|
||||||
// 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).
|
Fügt eine Kopie der Daten in den Binärbaum ein.
|
||||||
|
|
||||||
|
Parameter:
|
||||||
|
root : Wurzel des (Teil-)Baums
|
||||||
|
data : Zeiger auf die einzufügenden Daten
|
||||||
|
dataSize : Größe der Daten in Bytes
|
||||||
|
compareFct : Vergleichsfunktion für die Ordnung
|
||||||
|
isDuplicate : Optionaler Zeiger:
|
||||||
|
- Wenn NULL: Duplikate sind erlaubt
|
||||||
|
- Wenn != NULL: Duplikate werden ignoriert und *isDuplicate wird gesetzt:
|
||||||
|
- 0: neuer Eintrag eingefügt
|
||||||
|
- 1: Duplikat erkannt, nicht eingefügt
|
||||||
|
|
||||||
|
Rückgabe:
|
||||||
|
Zeiger auf die (ggf. neue) Wurzel des Baums oder NULL bei Speicherfehler.
|
||||||
|
*/
|
||||||
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate);
|
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.
|
Iteriert über den Baum in Inorder-Reihenfolge.
|
||||||
|
|
||||||
|
Verhalten:
|
||||||
|
- Erster Aufruf mit root != NULL: Iterator initialisieren
|
||||||
|
- Folgeaufrufe mit root == NULL: nächstes Element zurückgeben
|
||||||
|
|
||||||
|
Rückgabe:
|
||||||
|
Zeiger auf die Daten des nächsten Knotens oder NULL, wenn Ende erreicht.
|
||||||
|
|
||||||
|
Hinweis:
|
||||||
|
Intern wird ein Stack verwendet. Nicht threadsicher.
|
||||||
|
*/
|
||||||
void *nextTreeData(TreeNode *root);
|
void *nextTreeData(TreeNode *root);
|
||||||
// Releases all memory resources (including data copies).
|
|
||||||
|
/*
|
||||||
|
Gibt den gesamten Baum frei (inklusive der gespeicherten Daten).
|
||||||
|
|
||||||
|
Nach dem Aufruf sind alle Zeiger ungültig.
|
||||||
|
*/
|
||||||
void clearTree(TreeNode *root);
|
void clearTree(TreeNode *root);
|
||||||
// Returns the number of entries in the tree given by root.
|
|
||||||
|
/*
|
||||||
|
Liefert die Anzahl der Knoten im Baum.
|
||||||
|
|
||||||
|
Rückgabe:
|
||||||
|
Anzahl der Knoten (0 bei leerem Baum).
|
||||||
|
*/
|
||||||
unsigned int treeSize(const TreeNode *root);
|
unsigned int treeSize(const TreeNode *root);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
BIN
doble_initial.exe
Normal file
BIN
doble_initial.exe
Normal file
Binary file not shown.
@ -1 +1,10 @@
|
|||||||
player1;3999
|
Player1;19887
|
||||||
|
Player1;19843
|
||||||
|
Lena;19811
|
||||||
|
Lena;19702
|
||||||
|
Player1;19578
|
||||||
|
player_name;9981
|
||||||
|
Lena;9980
|
||||||
|
Lena;9978
|
||||||
|
Lena;9978
|
||||||
|
Lena;9976
|
||||||
|
|||||||
32
makefile
32
makefile
@ -29,14 +29,38 @@ 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
|
$(CC) $(FLAGS) $^ -o doble
|
||||||
|
|
||||||
$(program_obj_filesobj_files): %.o: %.c
|
# pattern rule to build .o from .c
|
||||||
$(CC) -c $(FLAGS) $^ -o $@
|
%.o: %.c
|
||||||
|
$(CC) -c $(FLAGS) $< -o $@
|
||||||
|
|
||||||
# --------------------------
|
# --------------------------
|
||||||
# Unit Tests
|
# Unit Tests
|
||||||
# --------------------------
|
# --------------------------
|
||||||
unitTests:
|
unitTests: test_stack test_numbers test_bintree
|
||||||
echo "needs to be implemented"
|
@total=0; passed=0; failed=0; \
|
||||||
|
for t in test_stack test_numbers test_bintree; do \
|
||||||
|
total=$$((total+1)); \
|
||||||
|
printf "Running %s...\n" "$$t"; \
|
||||||
|
./$$t; rc=$$?; \
|
||||||
|
if [ $$rc -eq 0 ]; then \
|
||||||
|
printf "%s: PASS\n\n" "$$t"; \
|
||||||
|
passed=$$((passed+1)); \
|
||||||
|
else \
|
||||||
|
printf "%s: FAIL (exit %d)\n\n" "$$t" $$rc; \
|
||||||
|
failed=$$((failed+1)); \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
printf "Summary: %d tests run, %d passed, %d failed\n" $$total $$passed $$failed; \
|
||||||
|
exit $$failed
|
||||||
|
|
||||||
|
test_stack: test_stack.c stack.c
|
||||||
|
$(CC) $(FLAGS) test_stack.c stack.c -o test_stack
|
||||||
|
|
||||||
|
test_numbers: test_numbers.c numbers.c bintree.c stack.c
|
||||||
|
$(CC) $(FLAGS) test_numbers.c numbers.c bintree.c stack.c -o test_numbers
|
||||||
|
|
||||||
|
test_bintree: test_bintree.c bintree.c stack.c
|
||||||
|
$(CC) $(FLAGS) test_bintree.c bintree.c stack.c -o test_bintree
|
||||||
|
|
||||||
# --------------------------
|
# --------------------------
|
||||||
# Clean
|
# Clean
|
||||||
|
|||||||
191
numbers.c
191
numbers.c
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@ -5,22 +6,194 @@
|
|||||||
#include "numbers.h"
|
#include "numbers.h"
|
||||||
#include "bintree.h"
|
#include "bintree.h"
|
||||||
|
|
||||||
//TODO: getDuplicate und createNumbers implementieren
|
/**
|
||||||
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
|
* @brief Vergleichsfunktion für unsigned int-Werte zur Verwendung im Binärbaum.
|
||||||
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
|
*
|
||||||
* Duplizieren eines zufälligen Eintrags im Array.
|
* Diese Funktion wird von der Binärbaum-Implementierung genutzt, um die
|
||||||
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */
|
* Ordnung der Knoten zu bestimmen. Sie vergleicht die dereferenzierten
|
||||||
|
* unsigned int-Werte a und b.
|
||||||
|
*
|
||||||
|
* @param a Pointer auf einen unsigned int-Wert (linker Operand)
|
||||||
|
* @param b Pointer auf einen unsigned int-Wert (rechter Operand)
|
||||||
|
* @return -1, falls *a < *b; 1, falls *a > *b; 0, falls *a == *b
|
||||||
|
*/
|
||||||
|
static int compareUInt(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
unsigned int va = *(const unsigned int *)a;
|
||||||
|
unsigned int vb = *(const unsigned int *)b;
|
||||||
|
if (va < vb) return -1;
|
||||||
|
if (va > vb) return 1;
|
||||||
|
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
|
* @brief Vergleichsfunktion für qsort() zur Sortierung von unsigned int-Arrays.
|
||||||
// creating random numbers.
|
*
|
||||||
|
* @param a Pointer auf einen Arrayeintrag
|
||||||
|
* @param b Pointer auf einen Arrayeintrag
|
||||||
|
* @return -1, 0, 1 analog zu compareUInt()
|
||||||
|
*/
|
||||||
|
static int qsort_uint_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
unsigned int va = *(const unsigned int *)a;
|
||||||
|
unsigned int vb = *(const unsigned int *)b;
|
||||||
|
if (va < vb) return -1;
|
||||||
|
if (va > vb) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Erzeugt ein Array aus len Zufallszahlen im Bereich [1 .. 2*len],
|
||||||
|
* das genau einen duplizierten Wert enthält (d. h. len-1 eindeutige + 1 Duplikat),
|
||||||
|
* und mischt die Reihenfolge zufällig.
|
||||||
|
*
|
||||||
|
* Funktionsweise:
|
||||||
|
* - Es werden zunächst len-1 eindeutige Zufallszahlen erzeugt. Die Eindeutigkeit wird
|
||||||
|
* mithilfe eines Binärsuchbaums (BST) geprüft: addToTree() fügt die Zahl ein
|
||||||
|
* und signalisiert per isDup, ob sie bereits vorhanden war.
|
||||||
|
* - Anschließend wird eine der bereits erzeugten Zahlen zufällig ausgewählt und
|
||||||
|
* noch einmal an das Ende des Arrays geschrieben, um das geforderte Duplikat sicherzustellen.
|
||||||
|
* - Zum Schluss wird das gesamte Array mittels Fisher–Yates-Algorithmus gemischt.
|
||||||
|
*
|
||||||
|
* Fehlerbehandlung:
|
||||||
|
* - Bei len < 2 wird NULL zurückgegeben, da das Problem ein Duplikat erfordert.
|
||||||
|
* - Bei Speicher- oder Baum-Insertionsfehlern wird aufgeräumt und NULL zurückgegeben.
|
||||||
|
* Wichtig: Der Baumzeiger root wird erst nach erfolgreichem Insert aktualisiert,
|
||||||
|
* um im Fehlerfall kein bereits aufgebautes Teilbaum-Objekt zu verlieren.
|
||||||
|
*
|
||||||
|
* Randbedingungen / Annahmen:
|
||||||
|
* - addToTree(root, &val, sizeof(val), compareUInt, &isDup) setzt isDup:
|
||||||
|
* isDup == 1 bedeutet „Duplikat gefunden, Baum unverändert“,
|
||||||
|
* isDup == 0 bedeutet „neuer Wert eingefügt (oder Fehler)“.
|
||||||
|
* - Bei Speicherfehler gibt addToTree NULL zurück und isDup bleibt 0.
|
||||||
|
* - clearTree(root) darf mit NULL-Argument aufgerufen werden (No-Op).
|
||||||
|
*
|
||||||
|
* Komplexität:
|
||||||
|
* - Durchschnittlich O(len * log(len)) für die len-1 Einfügungen in den BST.
|
||||||
|
* - Shuffle in O(len).
|
||||||
|
*
|
||||||
|
* @param len Anzahl der zu erzeugenden Werte (muss >= 2 sein)
|
||||||
|
* @return Pointer auf ein Array mit len Einträgen bei Erfolg; NULL bei Fehlern
|
||||||
|
*/
|
||||||
unsigned int *createNumbers(unsigned int len)
|
unsigned int *createNumbers(unsigned int len)
|
||||||
{
|
{
|
||||||
|
if (len < 2)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
unsigned int *numbers = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
||||||
|
if (numbers == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Zufallszahlengenerator nur einmal pro Prozess initialisieren.
|
||||||
|
// Hintergrund: Wird createNumbers mehrfach schnell hintereinander gerufen,
|
||||||
|
// kann time(NULL) identische Seeds liefern und damit identische Zahlenfolgen erzeugen.
|
||||||
|
static int seeded = 0;
|
||||||
|
if (!seeded) {
|
||||||
|
srand((unsigned int)time(NULL));
|
||||||
|
seeded = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *root = NULL;
|
||||||
|
unsigned int range = 2 * len;
|
||||||
|
|
||||||
|
// Schritt 1: len-1 eindeutige Zufallszahlen erzeugen
|
||||||
|
for (unsigned int i = 0; i < len - 1; i++)
|
||||||
|
{
|
||||||
|
unsigned int val;
|
||||||
|
int isDup;
|
||||||
|
|
||||||
|
// Wiederholen, bis eine wirklich neue Zahl eingefügt wurde
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
isDup = 0; // vor jedem Insert zurücksetzen, um „alte“ Werte zu vermeiden
|
||||||
|
val = (unsigned int)(rand() % range) + 1; // Wertebereich [1 .. 2*len]
|
||||||
|
|
||||||
|
// addToTree kann bei Erfolg einen (ggf. neuen) Wurzelzeiger liefern.
|
||||||
|
// Zur Vermeidung eines Speicherlecks bei Fehlern zunächst in temp speichern.
|
||||||
|
TreeNode *newRoot = addToTree(root, &val, sizeof(val), compareUInt, &isDup);
|
||||||
|
|
||||||
|
if (newRoot == NULL && isDup == 0) {
|
||||||
|
// Vermutlich Speicher-/Insertionsfehler: aufräumen und abbrechen
|
||||||
|
free(numbers);
|
||||||
|
clearTree(root); // root zeigt noch auf den gültigen Teilbaum
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDup) {
|
||||||
|
// Einfügen war erfolgreich und der Wert ist eindeutig.
|
||||||
|
root = newRoot;
|
||||||
|
numbers[i] = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Andernfalls Duplikat: Neue Zufallszahl versuchen.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schritt 2: Eine der bestehenden Zahlen zufällig duplizieren
|
||||||
|
unsigned int idx = (unsigned int)(rand() % (len - 1)); // Index im Bereich [0 .. len-2]
|
||||||
|
numbers[len - 1] = numbers[idx];
|
||||||
|
|
||||||
|
// Schritt 3: Fisher–Yates-Shuffle über das gesamte Array
|
||||||
|
for (unsigned int i = len - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
unsigned int j = (unsigned int)(rand() % (i + 1));
|
||||||
|
unsigned int tmp = numbers[i];
|
||||||
|
numbers[i] = numbers[j];
|
||||||
|
numbers[j] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aufräumen: Baum freigeben
|
||||||
|
clearTree(root);
|
||||||
|
return numbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns only the only number in numbers which is present twice. Returns zero on errors.
|
/**
|
||||||
|
* @brief Findet den einzigen duplizierten Wert in einem Array aus len unsigned int.
|
||||||
|
*
|
||||||
|
* Funktionsweise:
|
||||||
|
* - Es wird eine Kopie des Eingabearrays erstellt, um die Reihenfolge des
|
||||||
|
* Originalarrays nicht zu verändern.
|
||||||
|
* - Die Kopie wird mittels qsort() aufsteigend sortiert.
|
||||||
|
* - Beim Durchlauf werden benachbarte Elemente verglichen. Da genau ein Wert
|
||||||
|
* doppelt vorkommt, finden wir ihn als erstes Paar gleicher Nachbarn.
|
||||||
|
*
|
||||||
|
* Fehlerbehandlung:
|
||||||
|
* - Bei ungültigen Parametern (numbers == NULL oder len < 2) wird 0 geliefert.
|
||||||
|
* - Bei Speicherfehlern beim Kopieren ebenfalls 0.
|
||||||
|
*
|
||||||
|
* Komplexität:
|
||||||
|
* - Sortieren in O(len * log(len)), anschließender Linearpass O(len).
|
||||||
|
*
|
||||||
|
* @param numbers Pointer auf das Eingabearray
|
||||||
|
* @param len Länge des Arrays (muss >= 2 sein)
|
||||||
|
* @return Der doppelte Wert; 0 bei Fehlern oder falls kein Duplikat gefunden wurde
|
||||||
|
* (gemäß Aufgabenstellung sollte aber genau ein Duplikat existieren).
|
||||||
|
*/
|
||||||
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
||||||
{
|
{
|
||||||
|
if (numbers == NULL || len < 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Kopie erstellen, damit das Original unangetastet bleibt
|
||||||
|
unsigned int *copy = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
||||||
|
if (copy == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(copy, numbers, sizeof(unsigned int) * len);
|
||||||
|
|
||||||
|
// Sortieren der Kopie
|
||||||
|
qsort(copy, len, sizeof(unsigned int), qsort_uint_cmp);
|
||||||
|
|
||||||
|
// Linearer Scan: erstes Paar identischer Nachbarn ist das Duplikat
|
||||||
|
unsigned int result = 0;
|
||||||
|
for (unsigned int i = 0; i + 1 < len; i++)
|
||||||
|
{
|
||||||
|
if (copy[i] == copy[i + 1]) {
|
||||||
|
result = copy[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(copy);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
32
stack.c
32
stack.c
@ -1,33 +1,47 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
|
|
||||||
//TODO: grundlegende Stackfunktionen implementieren:
|
// Push Daten auf den Stack legen.
|
||||||
/* * `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 *push(StackNode *stack, void *data)
|
||||||
{
|
{
|
||||||
|
StackNode *node = malloc(sizeof(StackNode));
|
||||||
|
if(node == NULL)
|
||||||
|
return stack; // allocation failed -> return unchanged stack
|
||||||
|
|
||||||
|
node->data = data; // Setze Daten
|
||||||
|
node->next = stack; // Setze nächsten Knoten auf aktuellen Stack
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 memory. (Pointer to data has to be
|
||||||
// freed by caller.)
|
// freed by caller.)
|
||||||
StackNode *pop(StackNode *stack)
|
StackNode *pop(StackNode *stack)
|
||||||
{
|
{
|
||||||
|
if(stack == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
StackNode *next = stack->next;
|
||||||
|
// Speicher des aktuellen Knotens freigeben
|
||||||
|
free(stack);
|
||||||
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the data of the top element.
|
// Returns the data of the top element.
|
||||||
void *top(StackNode *stack)
|
void *top(StackNode *stack)
|
||||||
{
|
{
|
||||||
|
if(stack == NULL)
|
||||||
|
return NULL;
|
||||||
|
return stack->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears stack and releases all memory.
|
// Clears stack and releases all memory.
|
||||||
void clearStack(StackNode *stack)
|
void clearStack(StackNode *stack)
|
||||||
{
|
{
|
||||||
|
while(stack != NULL)
|
||||||
|
{
|
||||||
|
StackNode *next = stack->next;
|
||||||
|
// Do NOT free stack->data here; caller owns the pointed data
|
||||||
|
free(stack);
|
||||||
|
stack = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
7
stack.h
7
stack.h
@ -7,7 +7,12 @@ The latest element is taken from the stack. */
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
//TODO: passenden Datentyp als struct anlegen
|
// Stack node for linked-list based stack. Data pointer is stored but not freed by stack operations.
|
||||||
|
typedef struct StackNode
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
struct StackNode *next;
|
||||||
|
} StackNode;
|
||||||
|
|
||||||
// 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
test_bintree
Executable file
BIN
test_bintree
Executable file
Binary file not shown.
48
test_bintree.c
Normal file
48
test_bintree.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "bintree.h"
|
||||||
|
|
||||||
|
// comparator for unsigned int values stored by value in heap
|
||||||
|
static int cmp_uint_ptr(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
unsigned int va = *(const unsigned int *)a;
|
||||||
|
unsigned int vb = *(const unsigned int *)b;
|
||||||
|
if(va < vb) return -1;
|
||||||
|
if(va > vb) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
TreeNode *root = NULL;
|
||||||
|
unsigned int vals[] = {5, 2, 8, 1, 3, 7, 9};
|
||||||
|
const size_t n = sizeof(vals)/sizeof(vals[0]);
|
||||||
|
|
||||||
|
// insert values (copy made by addToTree)
|
||||||
|
for(size_t i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
int isDup = 0;
|
||||||
|
root = addToTree(root, &vals[i], sizeof(unsigned int), cmp_uint_ptr, &isDup);
|
||||||
|
if(root == NULL && isDup == 0) { fprintf(stderr, "addToTree allocation failed\n"); return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int sz = treeSize(root);
|
||||||
|
if(sz != n) { fprintf(stderr, "treeSize expected %zu got %u\n", n, sz); clearTree(root); return 2; }
|
||||||
|
|
||||||
|
// inorder traversal using nextTreeData
|
||||||
|
unsigned int last = 0;
|
||||||
|
int first = 1;
|
||||||
|
unsigned int *data = nextTreeData(root);
|
||||||
|
while(data != NULL)
|
||||||
|
{
|
||||||
|
unsigned int v = *data;
|
||||||
|
if(!first && v < last) { fprintf(stderr, "inorder traversal not sorted: %u after %u\n", v, last); clearTree(root); return 3; }
|
||||||
|
last = v; first = 0;
|
||||||
|
data = nextTreeData(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTree(root);
|
||||||
|
printf("test_bintree: OK\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
20
test_bintree.dSYM/Contents/Info.plist
Normal file
20
test_bintree.dSYM/Contents/Info.plist
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.apple.xcode.dsym.test_bintree</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>dSYM</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
test_bintree.dSYM/Contents/Resources/DWARF/test_bintree
Normal file
BIN
test_bintree.dSYM/Contents/Resources/DWARF/test_bintree
Normal file
Binary file not shown.
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
triple: 'x86_64-apple-darwin'
|
||||||
|
binary-path: test_bintree
|
||||||
|
relocations:
|
||||||
|
- { offset: 0x26, size: 0x8, addend: 0x0, symName: _main, symObjAddr: 0x0, symBinAddr: 0x1000007A0, symSize: 0x220 }
|
||||||
|
- { offset: 0x49, size: 0x8, addend: 0x0, symName: _main, symObjAddr: 0x0, symBinAddr: 0x1000007A0, symSize: 0x220 }
|
||||||
|
- { offset: 0x121, size: 0x8, addend: 0x0, symName: _cmp_uint_ptr, symObjAddr: 0x220, symBinAddr: 0x1000009C0, symSize: 0x5A }
|
||||||
|
- { offset: 0x21B, size: 0x8, addend: 0x0, symName: _addToTree, symObjAddr: 0x0, symBinAddr: 0x100000A20, symSize: 0x1C0 }
|
||||||
|
- { offset: 0x228, size: 0x8, addend: 0x0, symName: _nextTreeData, symObjAddr: 0x1C0, symBinAddr: 0x100000BE0, symSize: 0xC0 }
|
||||||
|
- { offset: 0x24D, size: 0x8, addend: 0x0, symName: _nextTreeData.iterStack, symObjAddr: 0xFB0, symBinAddr: 0x100002000, symSize: 0x0 }
|
||||||
|
- { offset: 0x2EC, size: 0x8, addend: 0x0, symName: _addToTree, symObjAddr: 0x0, symBinAddr: 0x100000A20, symSize: 0x1C0 }
|
||||||
|
- { offset: 0x376, size: 0x8, addend: 0x0, symName: _bintree_pushLefts, symObjAddr: 0x280, symBinAddr: 0x100000CA0, symSize: 0x50 }
|
||||||
|
- { offset: 0x3A8, size: 0x8, addend: 0x0, symName: _clearTree, symObjAddr: 0x2D0, symBinAddr: 0x100000CF0, symSize: 0x60 }
|
||||||
|
- { offset: 0x3CC, size: 0x8, addend: 0x0, symName: _treeSize, symObjAddr: 0x330, symBinAddr: 0x100000D50, symSize: 0x56 }
|
||||||
|
- { offset: 0x47F, size: 0x8, addend: 0x0, symName: _push, symObjAddr: 0x0, symBinAddr: 0x100000DB0, symSize: 0x60 }
|
||||||
|
- { offset: 0x4C3, size: 0x8, addend: 0x0, symName: _push, symObjAddr: 0x0, symBinAddr: 0x100000DB0, symSize: 0x60 }
|
||||||
|
- { offset: 0x507, size: 0x8, addend: 0x0, symName: _pop, symObjAddr: 0x60, symBinAddr: 0x100000E10, symSize: 0x50 }
|
||||||
|
- { offset: 0x53D, size: 0x8, addend: 0x0, symName: _top, symObjAddr: 0xB0, symBinAddr: 0x100000E60, symSize: 0x40 }
|
||||||
|
- { offset: 0x565, size: 0x8, addend: 0x0, symName: _clearStack, symObjAddr: 0xF0, symBinAddr: 0x100000EA0, symSize: 0x3F }
|
||||||
|
...
|
||||||
BIN
test_numbers
Executable file
BIN
test_numbers
Executable file
Binary file not shown.
91
test_numbers.c
Normal file
91
test_numbers.c
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "numbers.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Selbsttest für createNumbers() und getDuplicate().
|
||||||
|
*
|
||||||
|
* Erzeugt ein Array aus len Zufallszahlen mit genau einem duplizierten Wert,
|
||||||
|
* validiert die Eigenschaften per Zähl-Array (Wertebereich, Häufigkeiten)
|
||||||
|
* und prüft anschließend, ob getDuplicate() dasselbe Duplikat ermittelt.
|
||||||
|
*
|
||||||
|
* Rückgabecodes:
|
||||||
|
* 0: OK
|
||||||
|
* 1: createNumbers() fehlgeschlagen
|
||||||
|
* 2: Speicherfehler für counts
|
||||||
|
* 3: Wert außerhalb des Bereichs [1..2*len]
|
||||||
|
* 4: Ein Wert erscheint öfter als zweimal
|
||||||
|
* 5: Nicht genau ein Duplikat gefunden
|
||||||
|
* 6: getDuplicate() liefert anderes Ergebnis als Zählung
|
||||||
|
*/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
unsigned int len = 100; // Anzahl zu erzeugender Zahlen
|
||||||
|
unsigned int *nums = createNumbers(len);
|
||||||
|
if (nums == NULL) {
|
||||||
|
fprintf(stderr, "createNumbers returned NULL\n");
|
||||||
|
return 1; // Erzeugung fehlgeschlagen
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int maxVal = 2 * len; // Erlaubter Bereich: [1 .. 2*len]
|
||||||
|
|
||||||
|
// Zähl-Array für Häufigkeiten pro Wert (Index 0 bleibt ungenutzt)
|
||||||
|
unsigned int *counts = calloc(maxVal + 1, sizeof(unsigned int));
|
||||||
|
if (counts == NULL) {
|
||||||
|
free(nums);
|
||||||
|
return 2; // Speicherfehler bei counts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Häufigkeiten bestimmen und gleichzeitig Bereich prüfen
|
||||||
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
unsigned int v = nums[i];
|
||||||
|
if (v == 0 || v > maxVal) { // sollte nicht passieren, wenn createNumbers korrekt ist
|
||||||
|
fprintf(stderr, "value out of expected range\n");
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
counts[v]++; // Auftreten des Werts v zählen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exakt ein Wert muss doppelt vorkommen; keiner darf >2-mal vorkommen
|
||||||
|
int duplicatesFound = 0;
|
||||||
|
unsigned int duplicateValue = 0;
|
||||||
|
|
||||||
|
for (unsigned int v = 1; v <= maxVal; v++) {
|
||||||
|
if (counts[v] == 2) {
|
||||||
|
duplicatesFound++;
|
||||||
|
duplicateValue = v; // den doppelten Wert merken
|
||||||
|
} else if (counts[v] > 2) {
|
||||||
|
fprintf(stderr, "value %u appears more than twice\n", v);
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
return 4; // Vertragsbruch: zu häufiges Auftreten
|
||||||
|
}
|
||||||
|
// counts[v] == 0 oder 1 sind unkritisch
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duplicatesFound != 1) {
|
||||||
|
fprintf(stderr, "expected exactly one duplicated value, found %d\n", duplicatesFound);
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
return 5; // zu wenige/zu viele Duplikate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ergebnis von getDuplicate() mit der Zählung abgleichen
|
||||||
|
unsigned int found = getDuplicate(nums, len);
|
||||||
|
if (found != duplicateValue) {
|
||||||
|
fprintf(stderr, "getDuplicate returned %u expected %u\n", found, duplicateValue);
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
return 6; // Abweichung zwischen Methoden
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ressourcen freigeben und Erfolg melden
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
printf("test_numbers: OK (duplicate = %u)\n", duplicateValue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
20
test_numbers.dSYM/Contents/Info.plist
Normal file
20
test_numbers.dSYM/Contents/Info.plist
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.apple.xcode.dsym.test_numbers</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>dSYM</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
test_numbers.dSYM/Contents/Resources/DWARF/test_numbers
Normal file
BIN
test_numbers.dSYM/Contents/Resources/DWARF/test_numbers
Normal file
Binary file not shown.
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
triple: 'x86_64-apple-darwin'
|
||||||
|
binary-path: test_numbers
|
||||||
|
relocations:
|
||||||
|
- { offset: 0x26, size: 0x8, addend: 0x0, symName: _main, symObjAddr: 0x0, symBinAddr: 0x1000013A0, symSize: 0x287 }
|
||||||
|
- { offset: 0x41, size: 0x8, addend: 0x0, symName: _main, symObjAddr: 0x0, symBinAddr: 0x1000013A0, symSize: 0x287 }
|
||||||
|
- { offset: 0x12E, size: 0x8, addend: 0x0, symName: _createNumbers, symObjAddr: 0x0, symBinAddr: 0x100001630, symSize: 0x1D0 }
|
||||||
|
- { offset: 0x152, size: 0x8, addend: 0x0, symName: _createNumbers, symObjAddr: 0x0, symBinAddr: 0x100001630, symSize: 0x1D0 }
|
||||||
|
- { offset: 0x23E, size: 0x8, addend: 0x0, symName: _compareUInt, symObjAddr: 0x1D0, symBinAddr: 0x100001800, symSize: 0x60 }
|
||||||
|
- { offset: 0x290, size: 0x8, addend: 0x0, symName: _getDuplicate, symObjAddr: 0x230, symBinAddr: 0x100001860, symSize: 0x110 }
|
||||||
|
- { offset: 0x2FE, size: 0x8, addend: 0x0, symName: _qsort_uint_cmp, symObjAddr: 0x340, symBinAddr: 0x100001970, symSize: 0x5A }
|
||||||
|
- { offset: 0x3C5, size: 0x8, addend: 0x0, symName: _addToTree, symObjAddr: 0x0, symBinAddr: 0x1000019D0, symSize: 0x1C0 }
|
||||||
|
- { offset: 0x3D2, size: 0x8, addend: 0x0, symName: _nextTreeData, symObjAddr: 0x1C0, symBinAddr: 0x100001B90, symSize: 0xC0 }
|
||||||
|
- { offset: 0x3F7, size: 0x8, addend: 0x0, symName: _nextTreeData.iterStack, symObjAddr: 0xFB0, symBinAddr: 0x100003000, symSize: 0x0 }
|
||||||
|
- { offset: 0x496, size: 0x8, addend: 0x0, symName: _addToTree, symObjAddr: 0x0, symBinAddr: 0x1000019D0, symSize: 0x1C0 }
|
||||||
|
- { offset: 0x520, size: 0x8, addend: 0x0, symName: _bintree_pushLefts, symObjAddr: 0x280, symBinAddr: 0x100001C50, symSize: 0x50 }
|
||||||
|
- { offset: 0x552, size: 0x8, addend: 0x0, symName: _clearTree, symObjAddr: 0x2D0, symBinAddr: 0x100001CA0, symSize: 0x60 }
|
||||||
|
- { offset: 0x576, size: 0x8, addend: 0x0, symName: _treeSize, symObjAddr: 0x330, symBinAddr: 0x100001D00, symSize: 0x56 }
|
||||||
|
- { offset: 0x629, size: 0x8, addend: 0x0, symName: _push, symObjAddr: 0x0, symBinAddr: 0x100001D60, symSize: 0x60 }
|
||||||
|
- { offset: 0x66D, size: 0x8, addend: 0x0, symName: _push, symObjAddr: 0x0, symBinAddr: 0x100001D60, symSize: 0x60 }
|
||||||
|
- { offset: 0x6B1, size: 0x8, addend: 0x0, symName: _pop, symObjAddr: 0x60, symBinAddr: 0x100001DC0, symSize: 0x50 }
|
||||||
|
- { offset: 0x6E7, size: 0x8, addend: 0x0, symName: _top, symObjAddr: 0xB0, symBinAddr: 0x100001E10, symSize: 0x40 }
|
||||||
|
- { offset: 0x70F, size: 0x8, addend: 0x0, symName: _clearStack, symObjAddr: 0xF0, symBinAddr: 0x100001E50, symSize: 0x3F }
|
||||||
|
...
|
||||||
52
test_stack.c
Normal file
52
test_stack.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "stack.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
StackNode *s = NULL;
|
||||||
|
|
||||||
|
// push 3 integers
|
||||||
|
int *a = malloc(sizeof(int));
|
||||||
|
*a = 1;
|
||||||
|
s = push(s, a);
|
||||||
|
int *b = malloc(sizeof(int));
|
||||||
|
*b = 2;
|
||||||
|
s = push(s, b);
|
||||||
|
int *c = malloc(sizeof(int));
|
||||||
|
*c = 3;
|
||||||
|
s = push(s, c);
|
||||||
|
|
||||||
|
// oben liegt c (3)
|
||||||
|
int *topv = (int *)top(s);
|
||||||
|
if(topv == NULL || *topv != 3) { fprintf(stderr, "stack top expected 3\n"); return 1; }
|
||||||
|
|
||||||
|
// oben liegt nun 2
|
||||||
|
s = pop(s);
|
||||||
|
topv = (int *)top(s);
|
||||||
|
if(topv == NULL || *topv != 2) { fprintf(stderr, "stack top expected 2 after pop\n"); return 2; }
|
||||||
|
|
||||||
|
// oben liegt nun 1
|
||||||
|
s = pop(s);
|
||||||
|
topv = (int *)top(s);
|
||||||
|
if(topv == NULL || *topv != 1) { fprintf(stderr, "stack top expected 1 after pop\n"); return 3; }
|
||||||
|
|
||||||
|
// letzen Stapelinhalt holen
|
||||||
|
s = pop(s);
|
||||||
|
if(s != NULL) { fprintf(stderr, "stack expected empty after popping all\n"); return 4; }
|
||||||
|
|
||||||
|
// Eigenen Speicher freigeben
|
||||||
|
free(a);
|
||||||
|
free(b);
|
||||||
|
free(c);
|
||||||
|
|
||||||
|
// test clearStack mit leerem Stack
|
||||||
|
s = push(s, malloc(sizeof(int)));
|
||||||
|
s = push(s, malloc(sizeof(int)));
|
||||||
|
clearStack(s); // clearStack must free nodes but not payload; free payloads not necessary because we leaked intentionally for test of API
|
||||||
|
// Note: above payloads are not freed (stack API spec); this test ensures clearStack doesn't crash.
|
||||||
|
// Funktioniert alles
|
||||||
|
printf("test_stack: OK\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
20
test_stack.dSYM/Contents/Info.plist
Normal file
20
test_stack.dSYM/Contents/Info.plist
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.apple.xcode.dsym.test_stack</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>dSYM</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
test_stack.dSYM/Contents/Resources/DWARF/test_stack
Normal file
BIN
test_stack.dSYM/Contents/Resources/DWARF/test_stack
Normal file
Binary file not shown.
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
triple: 'x86_64-apple-darwin'
|
||||||
|
binary-path: test_stack
|
||||||
|
relocations:
|
||||||
|
- { offset: 0x26, size: 0x8, addend: 0x0, symName: _main, symObjAddr: 0x0, symBinAddr: 0x100000B80, symSize: 0x249 }
|
||||||
|
- { offset: 0x4E, size: 0x8, addend: 0x0, symName: _main, symObjAddr: 0x0, symBinAddr: 0x100000B80, symSize: 0x249 }
|
||||||
|
- { offset: 0x10A, size: 0x8, addend: 0x0, symName: _push, symObjAddr: 0x0, symBinAddr: 0x100000DD0, symSize: 0x60 }
|
||||||
|
- { offset: 0x14E, size: 0x8, addend: 0x0, symName: _push, symObjAddr: 0x0, symBinAddr: 0x100000DD0, symSize: 0x60 }
|
||||||
|
- { offset: 0x192, size: 0x8, addend: 0x0, symName: _pop, symObjAddr: 0x60, symBinAddr: 0x100000E30, symSize: 0x50 }
|
||||||
|
- { offset: 0x1C8, size: 0x8, addend: 0x0, symName: _top, symObjAddr: 0xB0, symBinAddr: 0x100000E80, symSize: 0x40 }
|
||||||
|
- { offset: 0x1F0, size: 0x8, addend: 0x0, symName: _clearStack, symObjAddr: 0xF0, symBinAddr: 0x100000EC0, symSize: 0x3F }
|
||||||
|
...
|
||||||
BIN
test_stack.exe
Normal file
BIN
test_stack.exe
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user