Search code examples
arrayscfor-loopiterationdynamic-memory-allocation

Array of pointers in C with easy iteration


Recently I was pondering over this question: how to make an easier way to iterate over an array of pointer in C.

If I create an array of string in C, it should look like this right?

int size = 5;
char ** strArr = (char **) malloc(sizeof(char *) * size);
if (strArr == NULL) return;

But the problem is, when you want to iterate over this array for some reason (like printing all values inside it), you have to keep track of its current size, storing in another variable.

That's not a problem, but if you create lots of arrays, you have to keep track of every single one of their sizes inside the code. If you pass this array to another function, you must pass its size as well.

void PrintValues (char ** arr, int size) {
    for (int i = 0; i < size; i++)
        printf("%s\n", arr[i]);
}

But when iterating over a string, it's different. You have the '\0' character, which specifies the end of the string. So, you could iterate over a string like this, with not need to keep its size value:

char * str = (char *) malloc(sizeof(char) * 4);
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';

for (int i = 0; str[i] != '\0'; i++)
    printf("%c", str[i]);
printf("\n");

Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?

char ** strArr = (char **) malloc(sizeof(char *) * (5   +1);
if (strArr == NULL) return;
strArr[0] = PseudoFunc_NewString("Car");
strArr[1] = PseudoFunc_NewString("Car#1");
strArr[2] = PseudoFunc_NewString("Car#2");
strArr[3] = PseudoFunc_NewString("Tree");
strArr[4] = PseudoFunc_NewString("Tree#1");
strArr[5] = NULL; // Stop iteration here as next element is not allocated

Then I could use the NULL pointer to control the iterator:

void PrintValues (char ** arr) {
    for (int i = 0; arr[i] != NULL; i++)
        printf("%s\n", arr[i]);
}

This would help me to keep the code cleaner, though it would consume more memory as a pointer size is larger than a integer size.

Also, when programming with event-based libraries, like Gtk, the size values would be released from the stack at some point, so I would have to create a pointer to dynamically store the size value for example.

In cases like this, it ok to do this? Or is it considered something bad?

Is this technique only used with char pointers because char type has a size of only 1 byte?

I miss having a foreach iterator in C...


Solution

  • Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?

    This is ok, the final NULL is called a sentinel value and using one is somewhat common practice. This is most often used when you don't even know the size of the data for some reason.

    It is however, not the best solution, because you have to iterate over all the data to find the size. Solutions that store the size separately are much faster. An arrays of structs for example, containing both size and data in the same place.