dynarr – yet another simple C dynamic array library

I wrote my own dynamic array library for C as I was not happy with the others I found. It is very crude but the basic logic should be correct, it mainly revolves making realloc easier to use and avoiding repetitive code.

Please offer your suggestions and criticisms!

#include <stdlib.h>
#include <string.h>

#define DYNARRAY_H_INCREMENT 50

typedef struct dynarr dynarr;

struct dynarr {
    void *actual;
    size_t size;
    size_t e_size;
    size_t occupied;
    size_t increment;
    void (*mem_callback)(dynarr *);
};

void *dynarr_nomen(dynarr *array) {
    if (array->mem_callback) array->mem_callback(array);
    array->actual = NULL;
    array->occupied = 0;
    return NULL;
}

dynarr dynarr_init_full(size_t e_size, size_t increment, void (*mem_callback)(dynarr *)) {
    return (dynarr){
        .actual = NULL,
        .size = 0,
        .e_size = e_size,
        .occupied = 0,
        .increment = increment,
        .mem_callback = mem_callback,
    };
}

dynarr dynarr_init(size_t element_size) {
    return dynarr_init_full(element_size, DYNARRAY_H_INCREMENT, NULL);
}

void *dynarr_push(dynarr *array, void *data) {
    if (array->occupied == array->size) {
        // Array is full
        // Increase size
        size_t new_real_size = (array->size + array->increment) * array->e_size;
        array->actual = realloc(array->actual, new_real_size);
        if (!array->actual) return dynarr_nomen(array);
        array->size += array->increment;
    }
    
    // Copy data
    char *charr = (char *) array->actual;
    memcpy(charr + array->occupied++ * array->e_size, data, array->e_size);
    
    return array->actual;
}

void *dynarr_get(dynarr *array, size_t *size) {
    if (size) *size = array->occupied;
    return array->actual;
}

void *dynarr_compact(dynarr *array) {
    if (array->occupied == array->size) goto end;
    array->actual = realloc(array->actual, array->occupied * array->e_size);
    if (!array->actual) return dynarr_nomen(array);
    array->size = array->occupied;
    end: return array->actual;
}

void dynarr_free(dynarr *array) {
    free(array->actual);
    array->actual = NULL;
    array->occupied = 0;
}

I intend to split declarations into a separate header in the future, I have kept it as a simple single source file for now.

I also made a very crude example program which could definitely use some major improvements… or maybe it can even be replaced by something else.

#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "dynarr.c"

volatile sig_atomic_t signaled = false;

void trap_interrupt(int sig) {
    signaled = true;
}

int main(void) {
    signal(SIGINT, trap_interrupt); 
    
    int c;
    char data;
    dynarr input = dynarr_init(sizeof data);
    
    for (;;) {
        if (signaled) break;
        c = getc(stdin);
        if (c == EOF) break;
        data = c;
        if (!dynarr_push(&input, &data)) {
            puts("Ran out of memory!!!");
            break;
        };
    }
    
    size_t count;
    dynarr_get(&input, &count);
    printf("Stored %zu bytes in dynamic arrayn", count);
    
    return EXIT_SUCCESS;
}