In addition to the wonderful answer given by Jean-François Fabre, I would point out that even a known size can change as a program evolves, for this reason it is useful to end lists with a known terminator (i.e. NULL or NaN).
I assume you're just beginning with C, but it's a good habit to get in to (the habit of seeking everything as transient and minimizing pre-conceptions in your code).
Although people point out that strdup
isn't standard C, it is widely available. I will avoid it just for kicks. I hope you notice the error checks (excessive? maybe... but real code should be filled with these things).
Consider the following code (but don't use it, it might be slightly broken ):
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **string_array_dup(char *const *ary) {
int count = 0;
char **copy;
if (!ary)
return NULL;
/* count string items - this is unsafe */
while (ary[count++])
;
if (!count)
return NULL;
/* allocate memory for array and set terminator. */
copy = malloc(sizeof(*copy) * (count + 1));
if (!copy)
perror("ERROR"), exit(errno);
copy[count - 1] = NULL;
/* itterate over array, allocate and copy strings. */
count = 0;
while (ary[count]) {
int register len = (int)strlen(ary[count]);
copy[count] = malloc(len + 1); /* remember NUL byte */
if (!ary[count])
perror("ERROR"), exit(errno);
memcpy(copy[count], ary[count], len + 1); /* copy NUL byte */
count += 1;
}
return copy;
}
void string_array_print(char **ary) {
int count = 0;
while (ary[count]) {
printf("%s ", ary[count++]);
}
printf("\n");
}
void string_array_free(char **ary) {
int count = 0;
/* free each string */
while (ary[count]) {
free(ary[count++]);
}
/* free container */
free(ary);
}
int main(void) {
char *array[] = {
"String", "array", "is", "always", "terminated", "with", NULL,
};
char **copy = string_array_dup(array);
if (!copy)
perror("ERROR"), exit(errno);
string_array_print(copy);
string_array_free(copy);
return 0;
}
By the way, this code could be optimized to use only a single malloc
(or using realloc
) and a single free
- at the cost of a more complicated copy process (and improving locality of the data and data access times).