Search code examples
cpointersstructrealloc

Re: Struct Array with Varying Size Structs--Clarification


I have a question regarding one of the solutions that was posted--the accepted one on this thread: https://stackoverflow.com/a/4982586/5854333 .

I would have left a comment on it instead of starting a new question thread, but I do not currently have the experience necessary. The program indeed runs as promised and is similar to what I intend to actually implement, but I'm still confused as to whether there may be subtle memory issues in it.

For example, in the portion:

void addStringToHolder(stringHolder * holder, const char * string) {
    char ** newStrings = realloc(holder->strings, newStringCount * sizeof(char *));
    if (newStrings != NULL) {
        holder->strings = newStrings;
    }
}

(we are working in this function with the struct)

typedef struct {
    int numberOfStrings;
    char ** strings;
}stringHolder;

Can the double pointer strings really be modified in this function? I thought we always had to pass in a pointer to the thing we wanted to modify, rather than the thing itself. Wouldn't we have to pass in a triple pointer if we wanted to modify the double pointer?

Of course we are also passing in a pointer to the struct in the first place, so does that make this work? I think I'm getting lost in all of these pointers. A little clarity would be helpful. Hopefully understanding this case will allow me to understand the others.


Solution

  • Can the double pointer strings really be modified in this function?

    Shortly, yes.

    To elaborate:

    A pointer in C is just a location in the memory, when you pass it to a function you simply tell the function where to preform its operation.

    By passing in a pointer to the struct, we are calling all of its elements by reference, and thus we can modify any of its elements, including the double pointer strings.

    Say we have a pointer to your struct stringHolder* h_ptr where:

    typedef struct {
       int numberOfStrings;
       char ** strings;
    }stringHolder;
    

    Now using * to dereference the pointer(s) you can access every level:

    h_ptr /*some adress in memory*/
    *h_ptr /*the value stored in said adress (we know its a stringHolder)*/
    

    using the syntax x->y instead of (*x).y for readability

    h_ptr->numberOfStrings /*the integer value stored in this struct*/
    h_ptr->strings /*a pointer to an array of C string pointers*/
    *(h_ptr->strings) /*the first "string" in said array, same as saying
                        a pointer to the first char in the first "string"*/
    **(h_ptr->strings) /*the first char of the first "string"*/
    

    And with pointer arithmetic we can get wherever we want and modify the values (as long as we keep the C convention of null terminated strings)

    *(h_ptr->strings + 1) /*the second "string" in strings array*/
    *(*(h_ptr->strings + 2) + 4) /*the fifth char in the third "string"*/
    

    and so on.