pointer to NULL terminated array of pointer

Discussion in 'C Programming' started by kpamafrederic@gmail.com, Aug 30, 2012.

  1. Guest

    Hi all,

    I have a little question regarding the subject of the topic. Sorry if it's seems like a silly question but I never really studied C and my knowledge comes from personal projects so I do need to learn.

    Currently I'm trying to pass an return a pointer to an array of pointer andI wanted to know how I can correctly implement it. Basically the function is supposed to look into a Database and return all string results in a pointer. Since the caller doesn't know how many results the function will return I was thinking of something like this (note that it is how I implemented it):

    int foo( char ***results);

    then the caller can walk through the result with something like this :

    char **results;
    int i=0;

    foo(&results);

    while ( results != 0 )
    {
    // do something with this entry.
    i++;
    }

    But I found the prototype of foo not really "self-explanatory". I also thought of something like this :

    int foo ( char *result[]);

    but I supposed this would means that the result is *const*ant while the user is in charge of freeing the results.

    Can somebody explain me how he would've done it please? Thanks you so much for your time.
     
    , Aug 30, 2012
    #1
    1. Advertising

  2. Fred K Guest

    On Thursday, August 30, 2012 2:02:43 PM UTC-7, wrote:
    > Hi all, I have a little question regarding the subject of the topic. Sorry if it's seems like a silly question but I never really studied C and my knowledge comes from personal projects so I do need to learn. Currently I'm trying to pass an return a pointer to an array of pointer and I wanted to know how I can correctly implement it. Basically the function is supposed tolook into a Database and return all string results in a pointer. Since thecaller doesn't know how many results the function will return I was thinking of something like this (note that it is how I implemented it): int foo( char ***results); then the caller can walk through the result with something like this : char **results; int i=0; foo(&results); while ( results != 0 ) { // do something with this entry. i++; } But I found the prototype of foo not really "self-explanatory". I also thought of something like this : int foo ( char *result[]); but I supposed this would means that the result is *const*ant while the user is in charge of freeing the results. Can somebody explain me how he would've done it please? Thanks you so much for your time.


    Your function "foo" is declared to return an int, but you never yse it. Whynot return the number of strings there?

    Other possibilities:

    char **names;
    int numNames;

    foo( &names, &numNames );
    with "void foo( char ***names, int *num)"

    names = foo( &num);
    with "char **foo( int *numNames )"

    In all of these cases it is unnecessary to include a sentinel in the array.Also, think about some instance where there is an actual null string in the middle of the array.
     
    Fred K, Aug 30, 2012
    #2
    1. Advertising

  3. Eric Sosman Guest

    On 8/30/2012 5:02 PM, wrote:
    > Hi all,
    >
    > I have a little question regarding the subject of the topic. Sorry if it's seems like a silly question but I never really studied C and my knowledge comes from personal projects so I do need to learn.
    >
    > Currently I'm trying to pass an return a pointer to an array of pointer and I wanted to know how I can correctly implement it. Basically the function is supposed to look into a Database and return all string results in a pointer. Since the caller doesn't know how many results the function will return I was thinking of something like this (note that it is how I implemented it):
    >
    > int foo( char ***results);
    >
    > then the caller can walk through the result with something like this :
    >
    > char **results;
    > int i=0;
    >
    > foo(&results);
    >
    > while ( results != 0 )
    > {
    > // do something with this entry.
    > i++;
    > }
    >
    > But I found the prototype of foo not really "self-explanatory". I also thought of something like this :
    >
    > int foo ( char *result[]);
    >
    > but I supposed this would means that the result is *const*ant while the user is in charge of freeing the results.


    Not sure where the notion of "*const*ant" comes from. This
    declaration is equivalent to

    int foo(char **result);

    .... which as you see is not the same as the original, not at all.

    > Can somebody explain me how he would've done it please? Thanks you so much for your time.



    I'd probably have returned the pointer as the function's value:

    char **foo(void) {
    ...
    return pointer_to_0th_string_pointer;
    }
    ...
    char **results = foo();

    If anything went wrong, foo() could return NULL to report the
    failure. Also, I'd have something like freefoo(char**) to release
    all the memory; that way, the caller wouldn't need to know details
    of how the memory was allocated (array of pointers to separately
    allocated strings, array of pointers to adjacent strings in one
    block, one omnibus block holding both the pointers and the strings,
    whatever).

    Your design has the advantage of being able to return more
    status information than a mere NULL/!NULL can, but if "failed"
    is enough and you don't need "failed because..." then returning
    a pointer seems clearer. One way to get the simplicity of a
    return value along with the flexibility of additional status
    information is to return a struct:

    struct {
    int status;
    char **result;
    double phase_of_moon;
    } foo_result;

    struct foo_result foo(void) {
    struct foo_result res;
    ...
    res.status = ...;
    res.result = ...;
    res.phase_of_moon = ...;
    return res;
    }
    ...
    struct foo_result gotcha = foo();
    if (gotcha.status < 0) report_error_and_die(gotcha.status);
    for (i = 0; res.result != NULL; ++i) {
    ...

    There are other variations, too, but these should get you
    started.

    --
    Eric Sosman
    d
     
    Eric Sosman, Aug 30, 2012
    #3
  4. On Thu, 30 Aug 2012 14:02:43 -0700 (PDT),
    wrote:

    >Hi all,
    >
    >I have a little question regarding the subject of the topic. Sorry if it's seems like a silly question but I never really studied C and my knowledge comes from personal projects so I do need to learn.
    >
    >Currently I'm trying to pass an return a pointer to an array of pointer and I wanted to know how I can correctly implement it. Basically the function is supposed to look into a Database and return all string results in a pointer. Since the caller doesn't know how many results the function will return I was thinking of something like this (note that it is how I implemented it):
    >
    >int foo( char ***results);
    >
    >then the caller can walk through the result with something like this :
    >
    >char **results;
    >int i=0;
    >
    >foo(&results);
    >
    >while ( results != 0 )
    >{
    >// do something with this entry.
    >i++;
    >}
    >
    >But I found the prototype of foo not really "self-explanatory". I also thought of something like this :
    >
    >int foo ( char *result[]);


    When used to declare the parameter of a function, char *result[] is
    IDENTICAL to char **result. As you can see, this is not the same as
    your first prototype for foo().

    >
    >but I supposed this would means that the result is *const*ant while the user is in charge of freeing the results.


    Why do you think result would be constant. Since it is a parameter,
    it is passed by value. Therefore any change you make to it will
    disappear as soon as the function returns. On the other hand, any
    change you make to the object this pointer points to live as long as
    the object does.

    Freeing memory applies only to allocated memory. If your function
    allocates memory without freeing it, then it is the responsibility of
    the calling function to eventually perform the clean up. It has
    nothing to do with the form of your parameter.

    >
    >Can somebody explain me how he would've done it please? Thanks you so much for your time.


    My personal preference: Rather than have foo remember to dereference
    the parameter each time, I would define a local char**, allocate (and
    possibly reallocate) memory to hold all the pointers to strings I need
    (this is effectively an array of pointers), and allocate memory for
    each string pointer to point to. When all done and in keeping with
    your subject, I would add one more pointer to string at the end of the
    array and set it to NULL. When all processing is complete, foo would
    return the value in the char** (instead of int as you have it).

    In the calling function, the call to foo would be in an assignment
    statement setting a local char** to the starting address of the array
    of pointers built by foo. After processing each pointer in the array,
    I would free it. (Alternately, I might wait until after processing
    all the pointers to free them in a fairly tight loop.) In either
    case, only after freeing each string would I then free the array
    itself (whose address is in my local char**).

    --
    Remove del for email
     
    Barry Schwarz, Aug 30, 2012
    #4
  5. Guest

    Thanks for your replies.

    Actually, like Eric remarked I chose this way to return an error code like sql error, no memory etc... But all those ideas makes sense.

    In fact Eric I have a problem with the hole "const" thing so I should ask you now : When I said that the *names[] would means a pointer to constant it's because I came to the conclusion that the array specifier means that thevalues into it are constants. Maybe I'm wrong?
     
    , Aug 30, 2012
    #5
  6. Eric Sosman Guest

    On 8/30/2012 6:20 PM, wrote:
    > Thanks for your replies.
    >
    > Actually, like Eric remarked I chose this way to return an error code like sql error, no memory etc... But all those ideas makes sense.
    >
    > In fact Eric I have a problem with the hole "const" thing so I should ask you now : When I said that the *names[] would means a pointer to constant it's because I came to the conclusion that the array specifier means that the values into it are constants. Maybe I'm wrong?


    As Barry Schwarz says, in a function's parameter list anything
    that looks like an array gets turned into a pointer to that array's
    element type:

    foo(char array[]) ==> foo(char *array)
    foo(int *array[]) ==> foo(int **array)
    foo(char **long[42]) ==> foo(long ***array)

    (In the third example, not even the "42" survives. There's a
    special case `foo(double array[static 42])', but even that
    doesn't change things much: inside the function, `array' is
    still of type `double*'.)

    Section 6 of the comp.lang.c Frequently Asked Questions
    (FAQ) page at <http://www.c-faq.com/> has more information on
    this and related issues.

    --
    Eric Sosman
    d
     
    Eric Sosman, Aug 30, 2012
    #6
  7. Guest

    On Friday, August 31, 2012 12:18:56 AM UTC+2, Barry Schwarz wrote:


    > When used to declare the parameter of a function, char *result[] is
    >
    > IDENTICAL to char **result. As you can see, this is not the same as
    >
    > your first prototype for foo().


    Yes. This is because I lost myself in pointers ^^. I meant **result[]. But note that your Idea :


    > Why do you think result would be constant. Since it is a parameter,
    >
    > it is passed by value. Therefore any change you make to it will
    >
    > disappear as soon as the function returns. On the other hand, any
    >
    > change you make to the object this pointer points to live as long as
    >
    > the object does.


    Ok so maybe I shouldn't pass an array as parameter (If I understood correctly what you meant!) Because note that :

    >
    >
    > Freeing memory applies only to allocated memory. If your function
    >
    > allocates memory without freeing it, then it is the responsibility of
    >
    > the calling function to eventually perform the clean up. It has
    >
    > nothing to do with the form of your parameter.


    Yes the caller is supposed to free the memory.

    >
    >
    >
    >
    > My personal preference: Rather than have foo remember to dereference
    >
    > the parameter each time, I would define a local char**, allocate (and
    >
    > possibly reallocate) memory to hold all the pointers to strings I need
    >
    > (this is effectively an array of pointers), and allocate memory for
    >
    > each string pointer to point to. When all done and in keeping with
    >
    > your subject, I would add one more pointer to string at the end of the
    >
    > array and set it to NULL. When all processing is complete, foo would
    >
    > return the value in the char** (instead of int as you have it).
    >

    Yes this is exactly what I tried to explain, sorry if I did not make myselfclear enough but the function is supposed to pass the results with the char **(*?) parameter. But I was wondering what's the best way to write the prototype of the function since with this solution in particular, there's no difference to tell that "char **" is in fact an *array* of pointer and not a simple string.

    So basically my function write the pointer to the array of results in the destination of the pointer ( *results = found_results, found_results beingmalloced and freed by the caller)
     
    , Aug 30, 2012
    #7
  8. Eric Sosman Guest

    On 8/30/2012 6:31 PM, Eric Sosman wrote:
    > [...]
    > As Barry Schwarz says, in a function's parameter list anything
    > that looks like an array gets turned into a pointer to that array's
    > element type:
    >
    > foo(char array[]) ==> foo(char *array)
    > foo(int *array[]) ==> foo(int **array)
    > foo(char **long[42]) ==> foo(long ***array)


    (Sigh.) Too much "editing for clarity" on that third example.
    Should have been

    foo(long **array[42]) ==> foo(long ***array)

    Sorry for any confusion.

    --
    Eric Sosman
    d
     
    Eric Sosman, Aug 31, 2012
    #8
  9. On Thu, 30 Aug 2012 15:35:23 -0700 (PDT),
    wrote:

    >On Friday, August 31, 2012 12:18:56 AM UTC+2, Barry Schwarz wrote:
    >
    >> When used to declare the parameter of a function, char *result[] is
    >> IDENTICAL to char **result. As you can see, this is not the same as
    >> your first prototype for foo().

    >
    >Yes. This is because I lost myself in pointers ^^. I meant **result[]. But note that your Idea :
    >
    >> Why do you think result would be constant. Since it is a parameter,
    >> it is passed by value. Therefore any change you make to it will
    >> disappear as soon as the function returns. On the other hand, any
    >> change you make to the object this pointer points to live as long as
    >> the object does.

    >
    >Ok so maybe I shouldn't pass an array as parameter (If I understood correctly what you meant!) Because note that :


    I have no idea how you could infer that from my comment.

    In your code, you didn't pass an array. You passed the address of an
    indeterminate char**. (foo() set the value of the char** so the value
    was no longer indeterminate when you used it.)

    Even if you had tried to pass an array, the compiler would have
    automatically converted it to a pointer. See my first comment
    regarding function parameters.

    >> Freeing memory applies only to allocated memory. If your function
    >> allocates memory without freeing it, then it is the responsibility of
    >> the calling function to eventually perform the clean up. It has
    >> nothing to do with the form of your parameter.

    >
    >Yes the caller is supposed to free the memory.
    >
    >> My personal preference: Rather than have foo remember to dereference
    >> the parameter each time, I would define a local char**, allocate (and
    >> possibly reallocate) memory to hold all the pointers to strings I need
    >> (this is effectively an array of pointers), and allocate memory for
    >> each string pointer to point to. When all done and in keeping with
    >> your subject, I would add one more pointer to string at the end of the
    >> array and set it to NULL. When all processing is complete, foo would
    >> return the value in the char** (instead of int as you have it).
    >>

    >Yes this is exactly what I tried to explain, sorry if I did not make myself clear
    >enough but the function is supposed to pass the results with the char **(*?) parameter.


    Your function can pass the result back to the calling program by
    simply using *result. But since the value to be passed is a char**,
    the parameter must be a char***.

    >But I was wondering what's the best way to write the prototype of the function
    >since with this solution in particular, there's no difference to tell that "char **" is
    >in fact an *array* of pointer and not a simple string.


    A char** would never point to a string. It would always point to a
    char*. That char* could point to a string but this is all irrelevant
    to your question. When you pass a pointer to a function, there is
    nothing in the C language or syntax that will tell the function how
    many consecutive objects the pointer points to. In your case,
    &results is the address of a single char**. You can store into
    results using *result if foo() but you would be in serious trouble if
    you would be in serious trouble if you tried to store into
    *(result+1).

    The fact that results is intended to point to an "array" of char* is
    something foo has to know as part of its design. After allocating
    space and storing the address in *result, you can assign values to
    each of the allocated char* with an expression of the form
    (*result), or the equivalent result[0] which I find easier on
    the eyes.

    >So basically my function write the pointer to the array of results in the destination of the pointer ( *results = found_results, found_results being malloced and freed by the caller)


    That is what you showed in the original post but you asked for other
    options.

    --
    Remove del for email
     
    Barry Schwarz, Aug 31, 2012
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roedy Green
    Replies:
    0
    Views:
    482
    Roedy Green
    Jul 9, 2003
  2. Replies:
    12
    Views:
    736
  3. Replies:
    14
    Views:
    510
  4. aneuryzma
    Replies:
    3
    Views:
    780
    Jim Langston
    Jun 16, 2008
  5. ssylee
    Replies:
    4
    Views:
    519
    CBFalconer
    Aug 12, 2008
Loading...

Share This Page