Home > Enterprise >  How to traverse through a double pointer containing an array of strings?
How to traverse through a double pointer containing an array of strings?

Time:09-21

// Online C compiler to run C program online
#include <stdio.h>
#include <stdlib.h>

char* word(char w[]) {
    char *temp = w;
    return temp;
}

char** tokens() {
    char *one = word("One");
    char *two = word("two");
    char *three = word("three");
    char *four = word("four");
    char *five = word("five");
    char *six = word("six");
    char *seven = word("seven");
    char *eight = word("eight");
    char *nine = word("nine");
    char *ten = word("ten");
    char *eleven = word("ten");
    char *twelve = word("ten");
    char *thirteen = word("ten");
    
    char *words[13];
    
    words[0] = one;
    words[1] = two;
    words[2] = three;
    words[3] = four;
    words[4] = five;
    words[5] = six;
    words[6] = seven;
    words[7] = eight;
    words[8] = nine;
    words[9] = ten;
    words[10] = eleven;
    words[11] = twelve;
    words[12] = thirteen;
    
    char **pp = words;
    return pp;
}

int main() {
    // Write C code here
    char **pp = (char **)malloc(13 * sizeof(char));
    
    pp = tokens();
    
    for (int i = 0; i < 12; i  ) {
        printf("%s\n", *pp);
        *pp  ;
    }
    // for (; *pp; *pp  ) {
    //     printf("%s\n", *pp);
    // }
    
    return 0;
}

I want the code to print every word contained in the tokens() method. However, in the for loop in main(), it only prints: one, two, three, four, null, and then gets a segmentation fault. If I use the for loop that is commented, it only prints: one, two, three, four. I'm new to C, so pointers are still pretty confusing. I'd appreciate any help. Thanks.

CodePudding user response:

You have quite a few errors:

char **pp = (char **)malloc(13 * sizeof(char));

When allocating memory, you want to allocate sizeof(<oneLevelUp>) * numOfElements. In this case, you're allocating for a char**, so "one level up" is a char*. Additionally, no need to cast the return value of malloc. Change that to

 char **pp = malloc(13 * sizeof(char*));

Finally, the best-considered practice is to include the variable name when using sizeof. This means there will be less maintenance if variable type ever changes:

 char **pp = malloc(13 * sizeof(*pp));  // preferred method

*pp is a char* type. If you change that to

 int **pp = malloc(13 * sizeof(*pp));

now *pp is an int* type automatically, without having to change the sizeof parameter from char* to int*.

The other problems have already been addressed in comments and answers. word essentially does nothing, as it simply returns the argument passed into it; this function will surely get optimized out. @AndreasWenzel's answer explains what's wrong with tokens. The top-rated answer here has an amusing anecdote about returning pointers to local variables.

One more final note, even if tokens didn't invoke UB, you would be/are creating a memory leak by assigning pp to the return value of tokens.

char **pp = malloc(13 * sizeof(*pp));
if (pp == NULL)
{
  // uh oh, we're out of memory, handle the error however you want. For this example, just exit
  exit(-1);
}

// uh oh, by making this assignment, pp no longer points to the memory block
// returned from `malloc`. Now that memory is reserved and nothing points to
// it. If we did this over and over, our process would continue to consume
// memory until none was left.
pp = tokens();

CodePudding user response:

The lifetime of the array words ends as soon as the function tokens returns. Therefore, it is not meaningful for the function tokens to return a pointer to this object, because that pointer will be pointing to an object that no longer exists. Dereferencing that pointer will cause undefined behavior (i.e. your program may crash).

If you want the function tokens to return a pointer to a valid object, you must ensure that the lifetime of words does not end, for example by using dynamic memory allocation (i.e. malloc) or change the lifetime of words to static, by using the static keyword.

In your case, it would be best to remove the function tokens and to simply define the variable words inside the function main, like this:

static const char *const words[] = {
    "one", "two", "three", "four", "five",
    "six", "seven", "eight", "nine", "ten",
    "eleven", "twelve", "thirteen"
};

If you really want to keep the function tokens, then you can rewrite it like this:

const char *const * tokens( void )
{
    static const char *const words[] = {
        "one", "two", "three", "four", "five",
        "six", "seven", "eight", "nine", "ten",
        "eleven", "twelve", "thirteen"
    };

    return words;
}

That way, the function tokens will return a pointer to a statically allocated object, which has static (unlimited) lifetime.

  • Related