C / C++ Char Pointers to Pointers and Arrays
-
11-06-2021 - |
Question
There is a function with a header such as this:
BPS_API int dialog_event_get_filebrowse_filepaths(bps_event_t* event,
char** file_paths[], int* num_paths);
This is from BlackBerry 10's Native SDK for anyone wondering (it can be found here).
The question is: what am I supposed to provide as the second argument. This function should populate an array of char pointers in order to return the file paths selected.
I tried to call it this way:
char* ar[2];
dialog_event_get_filebrowse_filepaths(event, &ar, &number_paths);
And I am getting an error from QNX Momentics as such:
cannot convert 'char * (*)[2]' to char * * * for argument 2 to int
dialog_event_get_filebrowse_filepaths(bps_event_t *, char * * *, int *)
This seems the most logical way to call it. It needs the memory address of an array of pointer in order to set them, as far as I understand. However, if I declare:
char** ar[2];
dialog_event_get_filebrowse_filepaths(event, ar, &number_paths);
It works, but this way I created an array of pointers to char pointers (an array of arrays of char*). Is this what I should really provide to the function?
Solution
The documentation really should have been more explicit, but I'm pretty sure this is what the function expects:
First, a few rules of thumb to help decode the function:
- the type is really equivalent to a
char***
. This means we have to find a meaning for three pointers. - a string in C is a
char*
(leaving out theconst
for brevity). As we expect the function to populate an array of strings, that's one*
accounted for. - an array in C is generally represented by a pointer. So that's the second
*
. - "output parameters" can be handled in one of two ways: either the caller allocates memory, and passes a pointer, telling callee where to write its data, or the caller does not allocate any memory, and simply passes in a pointer to a pointer. The callee will then modify the "innermost" pointer to point to a chunk of memory allocated by the callee itself. The second approach would account for the last
*
. This also explains the documentation note thatThe memory holding these values must be freed using bps_free() when no longer needed
-- because the memory was allocated by the library function, rather than by you, it is important that you use the correctfree
function.
So, the function should be called like this:
char** strs;
dialog_event_get_filebrowse_filepaths(foo, &strs, bar);
When the function returns, strs
will point to the first entry of an array of strings allocated by dialog_event_get_filebrowse_filepaths
.
OTHER TIPS
Just a guess, but I suspect it should be called like this:
char** ar = 0;
dialog_event_get_filebrowse_filepaths(event, &ar, &number_paths);
The fact that it is declared with array syntax is confusing, but this would be a common way for a C-style function to return an allocated array of strings.
the function will return a string-array and the length via arguments, you can use it like:
char **ar=0;
int i,number_paths = 0;
dialog_event_get_filebrowse_filepaths(event, &ar, &number_paths);
for( i=0; i<number_paths; i++ )
puts( ar[i] );
and you can/must free the memory ( see lib-docu ) like:
for( i=0; i<number_paths; i++ )
free( ar[i] );
free( ar );
Here is some (non-Blackberry) code that should satisfy the compiler:
char *file_paths[];
iret = dialog_event_get_filebrowse_filepaths (event, &ar, &number_paths);
The point is
1) do not assign a fixed length in the declaration.
2) pass addressof (&) array pointer to your function
3) make sure somebody (either the API function, or you) allocates the array, and all the strings in the array