C pointer based growable stack rev2
stack-&gt;data = (uint8_t *)realloc(stack-&gt;data, stack-&gt;capacity * stack-&gt;itemSize);



This is wrong, because if realloc() failed, then there's now no way to access the memory previously pointed to by stack-&gt;data.  The correct pattern for realloc() is:

void *newData = realloc(stack-&gt;data, stack-&gt;capacity * stack-&gt;itemSize);
if (!newData) {
    // Insert error handling - you'll want to restore the old stack-&gt;capacity here
    // or (better) wait until we're okay before updating.
    return FAILURE:
}
stack-&gt;data = newData;




I recommend against casting the result of malloc() family when assigning - these functions return void*, which is assignable to any pointer type without a cast.  The unnecessary cast just distracts the reader (because casts generally indicate danger areas in code).  The same is true for conversions from pointer types to void*, such as this one:


return (void *)item;



That can simply be

return item;




The stack_pop interface is difficult to use - callers have to deal with possible null pointer return, and must remember to free() the result.  Instead, consider having the caller provide memory to write into:

void stack_pop(Stack *stack, void *target);


The caller should already know the size required for target, and can now get  results in local (auto) storage:

int foo;
stack_pop(&amp;stack, &amp;foo);
// no need to check for null, or to call free()