How to filter elements from an array into a new array (edge‑case‑safe) in C

1 Answer

0 votes
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

/* ---------------------------------------------------------
   Predicate function type: returns true if the element should be kept
   --------------------------------------------------------- */
typedef bool (*predicate_fn)(int);

/* ---------------------------------------------------------
   Example predicate: keep only even numbers
   --------------------------------------------------------- */
bool is_even(int x) {
    return x % 2 == 0;
}

/* ---------------------------------------------------------
   Count how many elements satisfy the predicate.
   Safe for empty arrays (n == 0).
   --------------------------------------------------------- */
size_t count_matching(const int *arr, size_t n, predicate_fn pred) {
    if (!arr || !pred) return 0;

    size_t count = 0;
    for (size_t i = 0; i < n; i++) {
        if (pred(arr[i])) {
            count++;
        }
    }
    return count;
}

/* ---------------------------------------------------------
   Filter array into a newly allocated array.
   Returns NULL if no elements match or on invalid input.
   Caller must free() the returned array.
   --------------------------------------------------------- */
int *filter_array(const int *arr, size_t n, predicate_fn pred, size_t *out_n) {
    if (!arr || !pred || !out_n) {
        if (out_n) *out_n = 0;
        return NULL;
    }

    size_t count = count_matching(arr, n, pred);
    *out_n = count;

    if (count == 0) {
        return NULL;  // No matches
    }

    int *result = malloc(count * sizeof(int));
    if (!result) {
        *out_n = 0;
        return NULL;  // Allocation failure
    }

    size_t idx = 0;
    for (size_t i = 0; i < n; i++) {
        if (pred(arr[i])) {
            result[idx++] = arr[i];
        }
    }

    return result;
}

/* ---------------------------------------------------------
   Print array
   --------------------------------------------------------- */
void print_array(const int *arr, size_t n) {
    printf("[");
    for (size_t i = 0; i < n; i++) {
        printf("%d", arr[i]);
        if (i + 1 < n) printf(", ");
    }
    printf("]");
}

/* ---------------------------------------------------------
   Test cases
   --------------------------------------------------------- */
int main(void) {
    int a1[] = {1, 2, 3, 4, 5, 6};
    int a2[] = {1, 3, 5, 7};
    int a3[] = {};  // empty array

    size_t out_n;
    int *filtered;

    printf("Test 1: Mixed numbers → even filter\n");
    filtered = filter_array(a1, 6, is_even, &out_n);
    print_array(filtered, out_n);
    printf("\n");
    free(filtered);

    printf("Test 2: No even numbers\n");
    filtered = filter_array(a2, 4, is_even, &out_n);
    if (!filtered) {
        printf("[] (no matches)\n");
    } else {
        print_array(filtered, out_n);
        free(filtered);
    }

    printf("Test 3: Empty input array\n");
    filtered = filter_array(a3, 0, is_even, &out_n);
    if (!filtered) {
        printf("[] (empty input)\n");
    } else {
        print_array(filtered, out_n);
        free(filtered);
    }

    return 0;
}


/*
OUTPUT:

Test 1: Mixed numbers → even filter
[2, 4, 6]
Test 2: No even numbers
[] (no matches)
Test 3: Empty input array
[] (empty input)

*/

 



answered Mar 29 by avibootz

Related questions

...