You can do better than this!
What is an array? It's 3 variables: base, length and capacity. So why not decide that an array is just that. 3 variables of the right size and type.
#define ARRAY(T,S) T S;size_t S##_length;size_t S##_capacity
Then you can make one like this: ARRAY(int,xs);
You'll also need to initialise and these destroy array "objects". #define ARRAY_INIT(S) \
do { \
S=NULL; \
(S##_length)=0; \
(S##_capacity)=0; \
} while(0)
#define ARRAY_DESTROY(S) \
do { \
Array_Free(S); \
ARRAY_INIT(S); \
} while(0)
Add you'll probably want to add an item to an array too. #define ARRAY_ADD(S,X) \
do { \
if((S##_length)>=(S##_capacity)) { \
S=Array_Grow(S, \
sizeof *S, \
&(S##_length), \
&(S##_capacity)); \
S[S##_length++]=(X); \
} while(0)
So you might use them like this: ARRAY(int,xs);
ARRAY_INIT(xs);
for(int i=0;i<100;++i)
ARRAY_ADD(xs,i);
ARRAY_DESTROY(xs);
Array_Free is very simple, and Array_Grow is barely more complicated (however I wrote it off the cuff, so of course it could still be wrong). Both of these mainly exist just to keep stdlib.h out of the header. void Array_Free(void *p) {
free(p);
}
void *Array_Grow(void *base,size_t stride,size_t *length,size_t *capacity) {
*capacity+=*capacity/2;
*capacity=MAX(*capacity,MAX(MIN_CAPACITY,*length));
return realloc(base,*capacity*stride);
}
Array accesses and iteration and the like are just done in the traditional way: for(size_t i=0;i<xs_length;++i) {
printf("%d\n",xs[i]);
}
Even performs nicely with -O0.For a full implementation you'll probably also need a way of generating a static array. (I mainly found myself needing this for test code, which uses globals for convenience; most arrays I create normally are locals, or parts of structs.)
You'll also need a parameters list for use in a function declaration or definition, and a macro that expands to all 3 variables.
#define ARRAY_PARAMS(T,S) T *S,size_t S##_length,size_t S##_capacity
#define ARRAY_ARG(S) S,S##_length,S##_capacity
Like then you might have a function that takes a pointer to an "array": void FunctionThatTakesAnArray(ARRAY_PARAMS(T,*p));
And you call it like this: ARRAY(T,myarray);
FunctionThatTakesAnArray(ARRAY_ARG(&myarray));
(I found this cropped up often enough that I needed the macro, but it was less common than I thought.)There's more you can do, but the above is the long and the short of it.
This might all look terrible - or perhaps it sort of looks OK, but you're just not sure that it would actually work - but I've used this in a prototype project and thought it worked out well. (I've been using C for 20+ years, so hopefully even if I've got no taste, I've at least got a rough feel for what works out OK and what's going to end up a disaster.)