diff --git a/numbers.c b/numbers.c index f59d9a2..741a27d 100644 --- a/numbers.c +++ b/numbers.c @@ -11,16 +11,105 @@ * 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) -{ +// ------------------------------------------------------------- +// Vergleichsfunktion für qsort (Aufsteigend sortieren) +// ------------------------------------------------------------- +static int compareUnsignedInt(const void *a, const void *b) +{ + const unsigned int *ia = a; + const unsigned int *ib = b; + + if (*ia < *ib) return -1; + if (*ia > *ib) return 1; + return 0; } -// Returns only the only number in numbers which is present twice. Returns zero on errors. + + +// ------------------------------------------------------------- +// createNumbers +// Erzeugt ein Array aus len Zufallszahlen (1..2*len), alle verschieden. +// Danach wird genau EIN zufälliger Eintrag dupliziert. +// Parameter: len = Anzahl der gewünschten Zufallszahlen +// Rückgabe: Pointer auf das erzeugte Array (muss mit free() freigegeben werden) +// ------------------------------------------------------------- +unsigned int *createNumbers(unsigned int len) +{ + if (len < 2) + return NULL; + + srand(time(NULL)); + + unsigned int *numbers = malloc(len * sizeof(unsigned int)); + if (!numbers) + return NULL; + + unsigned int count = 0; + + // alle Werte verschieden erzeugen + while (count < len) + { + unsigned int value = (rand() % (2 * len)) + 1; + + // Duplikatsprüfung (linear) + int exists = 0; + for (unsigned int i = 0; i < count; i++) { + if (numbers[i] == value) { + exists = 1; + break; + } + } + + if (!exists) + numbers[count++] = value; + } + + // EIN Duplikat erzeugen + unsigned int i1 = rand() % len; + unsigned int i2 = rand() % len; + while (i2 == i1) + i2 = rand() % len; + + numbers[i2] = numbers[i1]; + + return numbers; +} + + + +// ------------------------------------------------------------- +// getDuplicate +// Findet die einzige Zahl, die im Array zweimal vorkommt. +// Sortiert dazu eine Kopie des Arrays und vergleicht benachbarte Werte. +// Parameter: numbers = Array von Zufallszahlen +// len = Anzahl der Elemente +// Rückgabe: die doppelte Zahl oder 0 bei Fehler +// ------------------------------------------------------------- unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) { + if (!numbers || len < 2) + return 0; -} \ No newline at end of file + // Kopie erzeugen, damit das Original unverändert bleibt + unsigned int *copy = malloc(len * sizeof(unsigned int)); + if (!copy) + return 0; + + memcpy(copy, numbers, len * sizeof(unsigned int)); + + // Sortieren + qsort(copy, len, sizeof(unsigned int), compareUnsignedInt); + + // benachbarte Elemente vergleichen + 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; +} diff --git a/numbers.o b/numbers.o new file mode 100644 index 0000000..b7f4041 Binary files /dev/null and b/numbers.o differ diff --git a/test_numbers b/test_numbers new file mode 100755 index 0000000..edb4975 Binary files /dev/null and b/test_numbers differ diff --git a/test_numbers.c b/test_numbers.c new file mode 100644 index 0000000..4293952 --- /dev/null +++ b/test_numbers.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include "unity.h" +#include "numbers.h" + + +// ------------------------------------------------------------- +// Hilfsfunktion: zählt, wie oft ein Wert im Array vorkommt +// ------------------------------------------------------------- +static unsigned int countOccurrences(const unsigned int *arr, unsigned int len, unsigned int value) +{ + unsigned int count = 0; + for (unsigned int i = 0; i < len; i++) + if (arr[i] == value) + count++; + return count; +} + + + +// ------------------------------------------------------------- +// Test 1: Array wird korrekt erzeugt (nicht NULL) +// ------------------------------------------------------------- +void test_createNumbersReturnsNotNull(void) +{ + unsigned int len = 20; + unsigned int *numbers = createNumbers(len); + + TEST_ASSERT_NOT_NULL(numbers); + + free(numbers); +} + + + +// ------------------------------------------------------------- +// Test 2: Alle Zahlen liegen im erlaubten Bereich (1..2*len) +// ------------------------------------------------------------- +void test_numbersAreInCorrectRange(void) +{ + unsigned int len = 50; + unsigned int *numbers = createNumbers(len); + + TEST_ASSERT_NOT_NULL(numbers); + + for (unsigned int i = 0; i < len; i++) + { + TEST_ASSERT_TRUE(numbers[i] >= 1); + TEST_ASSERT_TRUE(numbers[i] <= 2 * len); + } + + free(numbers); +} + + + +// ------------------------------------------------------------- +// Test 3: Es gibt GENAU EIN Duplikat +// ------------------------------------------------------------- +void test_exactlyOneDuplicateExists(void) +{ + unsigned int len = 80; + unsigned int *numbers = createNumbers(len); + + TEST_ASSERT_NOT_NULL(numbers); + + unsigned int duplicatesFound = 0; + + for (unsigned int i = 0; i < len; i++) + { + unsigned int occurrences = countOccurrences(numbers, len, numbers[i]); + if (occurrences == 2) + duplicatesFound++; + } + + // Da das Duplikat an zwei Positionen vorkommt, + // erwarten wir duplicatesFound == 2 + TEST_ASSERT_EQUAL_UINT(2, duplicatesFound); + + free(numbers); +} + + + +// ------------------------------------------------------------- +// Test 4: getDuplicate() findet die richtige doppelte Zahl +// ------------------------------------------------------------- +void test_getDuplicateFindsCorrectValue(void) +{ + unsigned int len = 100; + unsigned int *numbers = createNumbers(len); + + TEST_ASSERT_NOT_NULL(numbers); + + unsigned int duplicate = getDuplicate(numbers, len); + + TEST_ASSERT_TRUE(duplicate >= 1); + TEST_ASSERT_TRUE(duplicate <= 2 * len); + + TEST_ASSERT_EQUAL_UINT(2, countOccurrences(numbers, len, duplicate)); + + free(numbers); +} + + + +// ------------------------------------------------------------- +// Test 5: createNumbers() erzeugt len Elemente +// ------------------------------------------------------------- +void test_arrayLengthIsCorrect(void) +{ + unsigned int len = 30; + unsigned int *numbers = createNumbers(len); + + TEST_ASSERT_NOT_NULL(numbers); + + // Unity-Funktion prüft nicht direkt Länge, aber wir können checken, + // ob Zugriff auf alle Elemente möglich ist (Segfault würde Test crashen). + for (unsigned int i = 0; i < len; i++) + TEST_ASSERT_TRUE(numbers[i] >= 1); + + free(numbers); +} + + + +// ------------------------------------------------------------- +// Leere setUp/tearDown +// ------------------------------------------------------------- +void setUp(void) {} +void tearDown(void) {} + + + +// ------------------------------------------------------------- +// Hauptprogramm für Unity-Tests +// ------------------------------------------------------------- +int main(void) +{ + UNITY_BEGIN(); + + printf("\n============================\nNumbers tests\n============================\n"); + + RUN_TEST(test_createNumbersReturnsNotNull); + RUN_TEST(test_numbersAreInCorrectRange); + RUN_TEST(test_exactlyOneDuplicateExists); + RUN_TEST(test_getDuplicateFindsCorrectValue); + RUN_TEST(test_arrayLengthIsCorrect); + + return UNITY_END(); +} diff --git a/test_numbers.o b/test_numbers.o new file mode 100644 index 0000000..139baad Binary files /dev/null and b/test_numbers.o differ