Skip to content

Instantly share code, notes, and snippets.

@leok7v
Created September 26, 2025 04:08
Show Gist options
  • Select an option

  • Save leok7v/3f657c378560167d1bb54c418df6cc81 to your computer and use it in GitHub Desktop.

Select an option

Save leok7v/3f657c378560167d1bb54c418df6cc81 to your computer and use it in GitHub Desktop.
growing arrays on heap and stack with bounds checks
#include <alloca.h>
#include <assert.h>
#include <limits.h> // INT_MAX
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h> // malloc/calloc/realloc/free
#include <string.h> // memcpy
#ifndef countof
#define countof(a) (sizeof(a) / sizeof((a)[0]))
#endif
struct _array {
void* data;
int count;
int capacity;
bool heap;
};
#define array_of(type) { \
type* data; \
int count; \
int capacity; \
}
bool _array_new(struct _array* a, size_t count, size_t es);
bool _array_grow(struct _array* a, size_t count, size_t es);
bool _array_push(struct _array* a, void* data, size_t n, size_t es);
void _array_free(struct _array* a);
int _array_check(struct _array* a, int i) {
assert(0 <= i && i < a->count);
return i;
}
#define _array_es(a) sizeof((a)->data[0]) // element size
#define array_new(a, n) _array_new((struct _array*)(a), n, _array_es(a))
#define array_free(a) _array_free((struct _array*)(a))
#define array_grow(a, n) _array_grow((struct _array*)(a), n, _array_es(a))
#define array_push(a, d, n) _array_push((struct _array*)(a), d, n, _array_es(a))
#define array_get(a, i) ((a)->data[_array_check((struct _array*)(a), i)])
#define array_set(a, i, v) (a)->data[_array_check((struct _array*)(a), i)] = v
#define array_init(a, n) _array_init((struct _array*)(a), n, alloca((n) * _array_es(a)))
void _array_init(struct _array* a, size_t count, void* data) {
assert(data != NULL);
assert(count <= INT_MAX);
a->count = 0;
a->data = data;
a->capacity = (a)->data ? (int)(count) : 0;
a->heap = false;
}
bool _array_new(struct _array* a, size_t count, size_t es) {
assert(count <= INT_MAX);
a->count = 0;
a->data = malloc(count * es);
a->capacity = a->data ? (int)count : 0;
a->heap = true;
return a->data;
}
bool _array_grow(struct _array* a, size_t count, size_t es) {
assert(a->count <= a->capacity);
if (a->heap) {
assert(a->capacity < count && count <= INT_MAX);
void* data = (char*)realloc((void*)a->data, count * es);
if (data) { a->data = data; a->capacity = (int)count; }
return data;
} else {
assert(count <= a->capacity);
if (count <= a->capacity) {
a->count = (int)count;
return true;
} else {
return false;
}
}
}
bool _array_push(struct _array* a, void* data, size_t n, size_t es) {
assert(n + 1 < INT_MAX - a->count);
size_t c = a->count + n;
if (a->heap && c >= a->capacity) {
size_t d = a->capacity * 2; // double of capacity
if (!_array_grow(a, c > d ? c : d, es)) { return false; }
}
if (a->count + n <= a->capacity) {
memcpy(a->data + a->count * es, data, n * es);
a->count += n;
return true;
} else {
return false;
}
}
void _array_free(struct _array* a) {
if (a->heap && a->data) { free(a->data); }
memset(a, 0, sizeof(*a));
}
struct int_array array_of(int);
int main(int argc, const char* argv[]) {
printf("main\n");
struct int_array a;
array_init(&a, 4);
assert(a.count == 0 && a.capacity == 4 && a.data != NULL);
int c[] = {1,2,3,4};
array_push(&a, c, countof(c));
assert(a.count == 4);
printf("a[]: %d %d %d %d\n", array_get(&a, 0), array_get(&a, 1),
array_get(&a, 2), array_get(&a, 3));
printf("a[]: %d %d %d %d\n", a.data[0], a.data[1], a.data[2], a.data[3]);
a.data[0] = 4;
a.data[1] = 3;
a.data[2] = 2;
a.data[3] = 1;
printf("a[]: %d %d %d %d\n", a.data[0], a.data[1], a.data[2], a.data[3]);
array_set(&a, 0, 1);
array_set(&a, 1, 2);
array_set(&a, 2, 3);
array_set(&a, 3, 4);
printf("a[]: %d %d %d %d\n", array_get(&a, 0), array_get(&a, 1),
array_get(&a, 2), array_get(&a, 3));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment