I've been researching this for a day and I've found a lot of conflicting information on multiple websites. I'm writing a simple test that will allocate and initialize a char** (array of strings, char*). I've distilled the code down to the relevant parts below. I'm running this on Linux with Eclipse IDE for C/C++.
I do realize that I could just create a simple char arr[rows][cols]; of whatever size but I want this test to create dynamic memory on the heap.
After the char** arr malloc, I've read to do multiple things and I can't tell which is one right or wrong because even running with Valgrind, I get no errors. Therefore, what is the best practice way to accomplish the questions inline with the code below?
void init_str_list(uint size) {
if (size == 0) {
fprintf(stderr, "Cannot allocate an array of size 0.");
return;
}
// Allocate enough memory plus the NULL of the list array.
char** arr = (char**)malloc(sizeof(char*) * size + 1);
if (arr == NULL) {
fprintf(stderr, "Unable to allocate string array.");
return;
}
// QUESTION: How to properly initialize arr?
// I've seen multiple examples of such:
// 1) arr[0] = NULL; // If not sure if this is really needed like it is for a single char*
// 2) arr[size - 1] = NULL; // I would think this must always be done.
// 3) Some places say to do nothing though if so, draws into question of malloc "size + 1"
// 4) I've even seen where one is supposed to loop arr and NULL each arr[i].
// Valdrind will give no errors if these are commented or uncommented
// I suppose because we are initializing each string in the array
// below?
// arr[0] = NULL;
// arr[size - 1] = NULL;
// Do nothing?
// Cap the array at 30 bytes.
size_t len = 30;
for (int i = 0; i < size; i++) {
// I know, should check for NULL after the malloc but for brevity, assume
// it allocated OK.
arr[i] = (char*)malloc(sizeof(char) * len + 1);
// QUESTION: Should there be a null terminated like below even
// though snprintf NUL terminates it?
// arr[i][0] = '\0';
// snprintf appends the NUL at the end.
snprintf(arr[i], len, "arr[%d] = %d", i, i);
}
for (int i = 0; i < size; i++) {
printf(arr[i]);
free(arr[i]);
}
free(arr);
}
To summarize, I'm looking for the best practice for null terminating the char** and in this example, nul terminating each char* in the char** since I'm using snprintf. There is just so much conflicting information on how to properly do this.
Any help would be much appreciated.