Created
September 26, 2025 04:08
-
-
Save leok7v/3f657c378560167d1bb54c418df6cc81 to your computer and use it in GitHub Desktop.
growing arrays on heap and stack with bounds checks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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