Please, check the structure of my files add fix something, if you think it shoud be changed:
main.c:
#include <string.h>
#include <assert.h>
#include <math.h>

#include "stack.h"

typedef struct 
{
    int array[8];
    float d_variable;
} Value;

int main(int argc, char* argv[])
{
    void* stack = stack_create(sizeof(int));
    assert(stack_count(stack) == 0);
    
    stack_destroy(stack, NULL);

    return 0;
}

stack.h:
#include <stddef.h>  // size_t

static const size_t INVALID = ~((size_t)0);                                     // код ошибки для невалидных ситуаций

void * stack_create(size_t itemSize);                                           // Создать новый пустой стек. Размер элемента -- itemSize байт
void stack_destroy(void * stack, void(*destroy)( void * ));                     // Удалить существующий стек. Если указана функция destroy, то вызвать её для каждого удаляемого элемента

void * stack_init(void * stack, size_t itemSize, void(*destroy)(void*));        // Инициализировать стек новыми параметрами. Если stack содержит элементы, то сначала удалить все элементы, потом инициализировать стек с учетом новых параметров. Размер элемента -- itemSize байт. Если указана функция destroy, то вызвать её для каждого удаляемого элемента.
void stack_clear(void * stack, void(*destroy)( void * ));                       // Удалить все элементы из стека. Если указана функция destroy, то вызвать её для каждого удаляемого элемента

size_t stack_count(const void * stack);                                         // Количество элементов в стеке. В случае, если stack равен NULL, возвращает INVALID константу    
void * stack_push(void * stack);                                                // Добавить элемент на вершину стека. В случае успеха, функция возвращает указатель на добавленный элемент, иначе -- NULL
void stack_pop(void * stack, void(*destroy)( void * ));                         // Удалить элемент с вершины стека. Если указана функция destroy, то вызвать её для удаляемого элемента
void * stack_peek(const void * stack);                                          // Подсмотреть элемент с вершины стека, не удаляя его. В случае успеха, функция возвращает указатель на верхний элемент, иначе -- NULL

size_t stack_first(const void * stack);                                         // Идентификатор для элемента с вершины стека. Идентификатор может стать невалидным при модификации стека
size_t stack_next(const void * stack, size_t item_id);                          // По идентификатору текущего элемента получить идентификатор следующего элемента стека    
size_t stack_stop(const void * stack);                                          // Идентификатор, получаемый при попытке обратиться к элементу за пределами стека
void * stack_current(const void * stack, size_t item_id);                       // Получить указатель на элемент стека по его идентификатору

stack.c:
#include <stdlib.h>  // malloc, free
#include <string.h>  // memcpy 

#include "stack.h"

typedef struct 
{
    size_t itemSize;   // размер одного элемента
    size_t count;      // текущее число элементов
    size_t capacity;   // ёмкость (число элементов, которое мы можем хранить)
    void *data;        // указатель на память для элементов
} Stack;

void * stack_create(size_t itemSize) 
{
    if (itemSize == 0) return NULL;

    Stack *s = (Stack *)malloc(sizeof(Stack));
    if (!s) return NULL;

    s->itemSize = itemSize;
    s->count = 0;
    s->capacity = 0;
    s->data = NULL;

    return s;
}

size_t stack_count(const void *stack) 
{
    if (!stack) return INVALID;
    Stack *s = (Stack *)stack;
    return s->count;
}

void stack_destroy(void *stack, void (*destroy)(void *)) 
{
    if (!stack) return;

    Stack *s = (Stack *)stack;
    if (destroy) 
    {
        for (size_t i = 0; i < s->count; ++i) 
        {
            void *elem = (char *)s->data + i * s->itemSize;
            destroy(elem);
        }
    }

    free(s->data);
    free(s);
}