Which option would be preferable depends on the context. If there is already some family of functions (to which f can also be attributed) allocating memory when calling, then it makes sense to give preference to the first option: int *f() . If the functions of the mentioned family work with a pre-allocated memory, then it is reasonable to use the second option: void f() . In any case, the documentation should describe who is responsible for freeing one or another memory pointed by the pointer.
When comparing use cases, you can also see the pros and cons in both cases:
Option 1:
int* ptr = f(); use(ptr); free(ptr);
Option 2a:
int* ptr = malloc(...); f(ptr); use(ptr); free(ptr);
Option 2b:
int ptr[] = {...}; f(ptr); use(ptr);
The first option clearly requires working with dynamically allocated memory. In the second option, in addition, you can use stack or globally allocated memory. Failure to malloc / free can give a significant performance boost in certain situations.
Option 1 compared to 2b for user code will be shorter, because does not require explicit memory allocation, and the ptr variable is initialized in place.
From the standard functions for the first version, only strdup remembered so strdup . Although, I think there should be more options. But the functions of the second type are definitely more.