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 array\n", count);
return EXIT_SUCCESS;
}