What is char ** in C or C++? Explaining Functions that Return char **

I just came across a weird API method in a C library for Windows that returned a list of strings as char **. Obviously, to read this back you need to know when to stop enumerating, so it told me this list is NULL terminated (terminated by a NULL pointer). Pretty cool, but I had no clue how to even allocate or to free this data type properly so I set up to create a proper example in a Visual C++ console application, since I couldn’t find any good articles on this online. So, effectively this list lives as a pointer to a pointer to a string. Here is how you can create one, read one back, and free one:

#include "stdafx.h"
#include <malloc.h>
#include <string.h>
 
char ** get_list() {
    char **result = (char **)malloc(3 * sizeof(char *));
    char *valueOne = new char[14];
    strcpy_s(valueOne, 14, "Hello, world.");
    result[0] = valueOne;
    char *valueTwo = new char[14];
    strcpy_s(valueTwo, 14, "Hello, again.");
    result[1] = valueTwo;
    result[2] = NULL;
    return result;
}
 
void free_list(char **list) {
    int i = 0;
    while (true) {
        char *value = *(list + i);
        if (value == NULL)
            break;
        delete[] value;
        i++;
    }
    free(list);
}
 
int main()
{
    char **list = get_list();
    int i = 0;
    while (true) {
        char *value = *(list + i);
        if (value == NULL)
            break;
        printf(value);
        printf("\n");
        i++;
    }
    free_list(list);
    return 0;
}

Hopefully you won’t have to spend a few hours on this like I just did. In addition, you would only use such a structure in production if you knew that none of your strings are ever to be NULL, or else they’d be mistaken for the NULL terminator and your deallocation method will fail miserably.