Оптимальный вариант в вашем случае: возвращайте значение на указатель типа void, после чего принимающая функция уже будет взаимодействовать с ним как с обьектом нужного вам типа.
void* f(int i){
int array[i];
return (void*)array;
}
int main(){
int * array2 = (int*)f(5);
return 0;
}
Но вообще это плохо. Очень плохо :)
Типы были придуманы именно для таких ситуаций.
Конечно, можно работать с данными, выбирая тип по своему желанию, но это увеличивает шанс ошибки.