In your `get_result()` example, the caller won't be able obtain the address of the new allocation in case the callee allocates. The pointer itself is passed by value and any modifications on it by the callee are done on a local copy. If the function was allocating, it would require a double pointer like so:
int get_result(my_api_t api, api_result_t **result);
...
api_result_t *result;
get_result(api, &result);
A lot of confusion comes when API and library authors start typedef-ing pointer types into opaque types like that:
typedef api_result_t *API_RESULT;
...
API_RESULT res;
&res; // is this a single or a double pointer?
res; // is this a pointer at all?
If you meant that the function could possibly allocate fields of `result`, the API should always have a `free_result()`.
> If you meant that the function could possibly allocate fields of `result`, the API should always have a `free_result()`.
Yea that's what I meant. But this sort of gets into the weirdness of docs, if there is a `free_result` somewhere then authors should make sure to put a "see also free_result()" in their doc comments, especially when you don't have the niceties of constructors/destructors.
All depends on what "api_result_t" is, right? If the API's result is a bucket of scalars, then passing the pointer could be perfectly fine. Same if api_result_t contains a pointer to a buffer, and the call just makes the buffer pointer point to a previously allocated block.