Implement createNumbers alternative + tests

This commit is contained in:
Pia Keil 2025-12-09 08:07:35 +01:00
parent a1debfe55a
commit 83b96c9442
5 changed files with 248 additions and 7 deletions

103
numbers.c
View File

@ -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;
}
// 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;
}

BIN
numbers.o Normal file

Binary file not shown.

BIN
test_numbers Executable file

Binary file not shown.

152
test_numbers.c Normal file
View File

@ -0,0 +1,152 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#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();
}

BIN
test_numbers.o Normal file

Binary file not shown.