You as the programmer need to decide how will you store the data. You have multiple options, bear in mind that:
- 'string' is an array characters stored terminated with a zero byte, ie.
'\0'
- You need to store how many array elements there are in an array.
- In case of 'strings' the number of elements in an array / the number of characters in a string may be computed by counting the number of characters until the zero byte '\0' is encountered.
- For all other arrays you have two options.
- You explicitly set the last array member to NULL/zero, like you did in case of
str_arr1[] = { "sdfddsf", "foo1", 0 };
. When copying such array you need to remember to explicitly set the last member to zero. In this case you will often see a magic + 1
in code when calculating size, like malloc(sizeof(char) * (strlen(string) + 1))
.
- You can store the array size in a separate variable, typically of
size_t
type.
- You have 3 arrays of strings, ie. three arrays terminated by NULL of array terminated by zero byte of characters.
- You want to have an array of arrays of strings. You need to decide how will you track the size of that array and the size of inside arrays.
- I don't like having an explicit array termination value. I like storing sizes of an array using separate variable of type
size_t
. Usually I wrap a pointer to the array and the variable that stores the size in one structure. That way I can write separate libraries for each level of array.
- Please don't decide for
char ***var;
. It makes code unreadable.
#define _GNU_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void store_pointers_to_arrys_of_strings_null_delimeterd(
const char * const * const strings_to_copy[], size_t strings_to_copy_len)
{
const char * const **the_arrays;
// alloc memory
const size_t the_arrays_len = strings_to_copy_len + 1;
the_arrays = malloc(sizeof(the_arrays) * the_arrays_len);
if (the_arrays == NULL) {
perror("malloc failed\n");
abort();
}
// copy pointers
for (size_t i = 0; i < strings_to_copy_len; ++i) {
the_arrays[i] = strings_to_copy[i];
}
the_arrays[strings_to_copy_len] = NULL;
for (size_t i = 0; the_arrays[i] != NULL; ++i) {
for (size_t j = 0; the_arrays[i][j] != NULL; ++j) {
printf("%s: %zu %zu %s\n", __func__, i, j, the_arrays[i][j]);
}
}
free(the_arrays);
}
void store_strings_themselves_as_arrays_of_strings_null_delimeterd(
const char * const * const strings_to_copy[], size_t strings_to_copy_len)
{
const char ***the_arrays;
// allocate for arrays
const size_t the_arrays_len = strings_to_copy_len + 1;
the_arrays = malloc(sizeof(the_arrays) * the_arrays_len);
if (the_arrays == NULL) {
perror("malloc failed\n");
abort();
}
// copy strings
for (size_t i = 0; i < strings_to_copy_len; ++i) {
size_t cnt = 1;
for (size_t j = 0; strings_to_copy[i][j] != NULL; ++j) {
++cnt;
}
the_arrays[i] = malloc(sizeof(the_arrays[i]) * cnt);
memcpy(the_arrays[i], strings_to_copy[i], cnt * sizeof(the_arrays[i]));
}
the_arrays[strings_to_copy_len] = NULL;
// print
for (size_t i = 0; the_arrays[i] != NULL; ++i) {
for (size_t j = 0; the_arrays[i][j] != NULL; ++j) {
printf("%s: %zu %zu %s\n", __func__, i, j, the_arrays[i][j]);
}
}
// free
for (size_t i = 0; the_arrays[i] != NULL; ++i) {
free(the_arrays[i]);
}
free(the_arrays);
}
void store_strings_in_array_of_strings_in_array_of_array_of_strings_null_delimeterd(
const char * const * const strings_to_copy[], size_t strings_to_copy_len)
{
char ***the_arrays;
// allocate for arrays
const size_t the_arrays_len = strings_to_copy_len + 1;
the_arrays = malloc(sizeof(the_arrays) * the_arrays_len);
if (the_arrays == NULL) {
perror("malloc failed\n");
abort();
}
// copy string pointers
for (size_t i = 0; i < strings_to_copy_len; ++i) {
size_t cnt = 0;
for (size_t j = 0; strings_to_copy[i][j] != NULL; ++j) {
++cnt;
}
// allocate memory for string pointers
const size_t the_arrays_i_len = cnt + 1;
the_arrays[i] = malloc(sizeof(the_arrays[i]) * the_arrays_i_len);
if (the_arrays[i] == NULL) { perror("AA"); abort(); }
// copy the strings themselves
for (size_t k = 0; k < cnt; ++k) {
the_arrays[i][k] = strdup(strings_to_copy[i][k]);
if (the_arrays[i][k] == NULL) { perror("AA"); abort(); }
}
the_arrays[i][cnt] = NULL;
}
the_arrays[strings_to_copy_len] = NULL;
// print
for (size_t i = 0; the_arrays[i] != NULL; ++i) {
for (size_t j = 0; the_arrays[i][j] != NULL; ++j) {
printf("%s: %zu %zu %s\n", __func__, i, j, the_arrays[i][j]);
}
}
// free
for (size_t i = 0; the_arrays[i] != NULL; ++i) {
for (size_t j = 0; the_arrays[i][j] != NULL; ++j) {
free(the_arrays[i][j]);
}
free(the_arrays[i]);
}
free(the_arrays);
}
void store_pointers_to_arrays_of_strings_in_a_struct(
const char * const * const strings_to_copy[], size_t strings_to_copy_len)
{
struct arrays_of_array_of_strings_s {
const char * const **strs;
size_t strscnt;
};
const size_t the_arrays_cnt = strings_to_copy_len;
struct arrays_of_array_of_strings_s the_arrays;
the_arrays.strs = malloc(sizeof(the_arrays.strs[0]) * the_arrays_cnt);
if (the_arrays.strs == NULL) {
perror("malloc failed\n");
abort();
}
// fill array
for (size_t i = 0; i < strings_to_copy_len; ++i) {
the_arrays.strs[i] = strings_to_copy[i];
}
the_arrays.strscnt = the_arrays_cnt;
// print
for (size_t i = 0; i < the_arrays.strscnt; ++i) {
for (size_t j = 0; the_arrays.strs[i][j] != NULL; ++j) {
printf("%s: %zu %zu %s\n", __func__, i, j, the_arrays.strs[i][j]);
}
}
// free
free(the_arrays.strs);
the_arrays.strscnt = 0;
}
void store_pointers_to_strings_in_array_of_structs(
const char * const * const strings_to_copy[], size_t strings_to_copy_len)
{
struct array_of_strings_s {
const char * const *strs;
};
const size_t the_arrays_cnt = strings_to_copy_len;
struct array_of_strings_s * const the_arrays = malloc(sizeof(the_arrays[0]) * the_arrays_cnt);
if (the_arrays == NULL) {
perror("malloc failed\n");
abort();
}
// fill array
for (size_t i = 0; i < strings_to_copy_len; ++i) {
the_arrays[i].strs = strings_to_copy[i];
}
// print
for (size_t i = 0; i < the_arrays_cnt; ++i) {
for (size_t j = 0; the_arrays[i].strs[j] != NULL; ++j) {
printf("%s: %zu %zu %s\n", __func__, i, j, the_arrays[i].strs[j]);
}
}
// free
free(the_arrays);
}
void store_strings_in_an_array_of_structs_delimeterd_by_null_of_arrays_of_strings_delimeterd_by_null(
const char * const * const strings_to_copy[], size_t strings_to_copy_len)
{
struct array_of_strings_s {
const char * *arrstrs;
};
const size_t the_arrays_cnt = strings_to_copy_len + 1;
struct array_of_strings_s * const the_arrays = malloc(sizeof(the_arrays[0]) * the_arrays_cnt);
if (the_arrays == NULL) {
perror("malloc failed\n");
abort();
}
// fill array
for (size_t i = 0; i < strings_to_copy_len; ++i) {
size_t cnt = 0;
for (size_t j = 0; strings_to_copy[i][j] != NULL; ++j) {
++cnt;
}
const size_t the_arrays_i_strs_cnt = cnt + 1;
the_arrays[i].arrstrs = malloc(sizeof(the_arrays[i].arrstrs[0]) * cnt);
if (the_arrays[i].arrstrs == NULL) { perror("AA"); abort(); }
for (size_t k = 0; k < cnt; ++k) {
the_arrays[i].arrstrs[k] = strings_to_copy[i][k];
}
the_arrays[i].arrstrs[cnt] = NULL;
}
the_arrays[strings_to_copy_len].arrstrs = NULL;
// print
for (size_t i = 0; the_arrays[i].arrstrs != NULL; ++i) {
for (size_t j = 0; the_arrays[i].arrstrs[j] != NULL; ++j) {
printf("%s: %zu %zu %s\n", __func__, i, j, the_arrays[i].arrstrs[j]);
}
}
// free
for (size_t i = 0; the_arrays[i].arrstrs != NULL; ++i) {
free(the_arrays[i].arrstrs);
}
free(the_arrays);
}
void store_strings_in_array_of_strings_in_array_of_array_of_strings_in_a_struct(
const char * const * const strings_to_copy[], size_t strings_to_copy_len)
{
struct string_s {
char *str;
};
struct array_of_strings_s {
struct string_s *strs;
size_t strscnt;
};
struct array_of_arrays_of_strings_s {
struct array_of_strings_s *arrstrs;
size_t arrstrscnt;
};
struct array_of_arrays_of_strings_s the_arrays;
// fill array
the_arrays.arrstrscnt = strings_to_copy_len;
the_arrays.arrstrs = malloc(sizeof(the_arrays.arrstrs[0]) * the_arrays.arrstrscnt);
if (the_arrays.arrstrs == NULL) { perror("malloc failed\n"); abort(); }
for (size_t i = 0; i < the_arrays.arrstrscnt; ++i) {
struct array_of_strings_s * const array_of_strings = &the_arrays.arrstrs[i];
size_t cnt = 0;
for (size_t j = 0; strings_to_copy[i][j] != NULL; ++j) {
++cnt;
}
array_of_strings->strscnt = cnt;
array_of_strings->strs = malloc(sizeof(array_of_strings->strs[0]) * array_of_strings->strscnt);
if (array_of_strings->strs == NULL) { perror("AA"); abort(); }
for (size_t k = 0; k < array_of_strings->strscnt; ++k) {
struct string_s * const string = &array_of_strings->strs[k];
string->str = strdup(strings_to_copy[i][k]);
if (string->str == NULL) { perror("AA"); abort(); }
}
}
// print
for (size_t i = 0; i < the_arrays.arrstrscnt; ++i) {
for (size_t j = 0; j < the_arrays.arrstrs[i].strscnt; ++j) {
printf("%s: %zu %zu %s\n", __func__, i, j, the_arrays.arrstrs[i].strs[j].str);
}
}
// free
for (size_t i = 0; i < the_arrays.arrstrscnt; ++i) {
struct array_of_strings_s * const array_of_strings = &the_arrays.arrstrs[i];
for (size_t j = 0; j < array_of_strings->strscnt; ++j) {
struct string_s * const string = &array_of_strings->strs[i];
free(string->str);
}
free(array_of_strings->strs);
}
free(the_arrays.arrstrs);
}
int main()
{
// "blabla" is a string literal - it's a immutable sting
const char * const str_arr1[] = { "sdfddsf", "foo1", NULL };
const char * const str_arr2[] = { "sdsosdfrt", "foo2", NULL };
const char * const str_arr3[] = { "grsdsfdep", "foo3", NULL };
// or char `str_arr1[][] = { .... };`
// string literal are immutable, read-only
// so `const char *var = "abc";` or string initialization like `char var[] = "abc";`
// just an array of strings to copy
const char * const * const strings_to_copy[] = { str_arr1, str_arr2, str_arr3 };
const size_t strings_to_copy_len = sizeof(strings_to_copy)/sizeof(strings_to_copy[0]);
store_pointers_to_arrys_of_strings_null_delimeterd(
strings_to_copy, strings_to_copy_len);
store_strings_themselves_as_arrays_of_strings_null_delimeterd(
strings_to_copy, strings_to_copy_len);
store_strings_in_array_of_strings_in_array_of_array_of_strings_null_delimeterd(
strings_to_copy, strings_to_copy_len);
store_pointers_to_arrays_of_strings_in_a_struct(
strings_to_copy, strings_to_copy_len);
store_strings_in_an_array_of_structs_delimeterd_by_null_of_arrays_of_strings_delimeterd_by_null(
strings_to_copy, strings_to_copy_len);
store_pointers_to_strings_in_array_of_structs(
strings_to_copy, strings_to_copy_len);
return 0;
}
Will output:
store_pointers_to_arrys_of_strings_null_delimeterd: 0 0 sdfddsf
store_pointers_to_arrys_of_strings_null_delimeterd: 0 1 foo1
store_pointers_to_arrys_of_strings_null_delimeterd: 1 0 sdsosdfrt
store_pointers_to_arrys_of_strings_null_delimeterd: 1 1 foo2
store_pointers_to_arrys_of_strings_null_delimeterd: 2 0 grsdsfdep
store_pointers_to_arrys_of_strings_null_delimeterd: 2 1 foo3
store_strings_themselves_as_arrays_of_strings_null_delimeterd: 0 0 sdfddsf
store_strings_themselves_as_arrays_of_strings_null_delimeterd: 0 1 foo1
store_strings_themselves_as_arrays_of_strings_null_delimeterd: 1 0 sdsosdfrt
store_strings_themselves_as_arrays_of_strings_null_delimeterd: 1 1 foo2
store_strings_themselves_as_arrays_of_strings_null_delimeterd: 2 0 grsdsfdep
store_strings_themselves_as_arrays_of_strings_null_delimeterd: 2 1 foo3
store_strings_in_array_of_strings_in_array_of_array_of_strings_null_delimeterd: 0 0 sdfddsf
store_strings_in_array_of_strings_in_array_of_array_of_strings_null_delimeterd: 0 1 foo1
store_strings_in_array_of_strings_in_array_of_array_of_strings_null_delimeterd: 1 0 sdsosdfrt
store_strings_in_array_of_strings_in_array_of_array_of_strings_null_delimeterd: 1 1 foo2
store_strings_in_array_of_strings_in_array_of_array_of_strings_null_delimeterd: 2 0 grsdsfdep
store_strings_in_array_of_strings_in_array_of_array_of_strings_null_delimeterd: 2 1 foo3
store_pointers_to_arrays_of_strings_in_a_struct: 0 0 sdfddsf
store_pointers_to_arrays_of_strings_in_a_struct: 0 1 foo1
store_pointers_to_arrays_of_strings_in_a_struct: 1 0 sdsosdfrt
store_pointers_to_arrays_of_strings_in_a_struct: 1 1 foo2
store_pointers_to_arrays_of_strings_in_a_struct: 2 0 grsdsfdep
store_pointers_to_arrays_of_strings_in_a_struct: 2 1 foo3
store_strings_in_an_array_of_structs_delimeterd_by_null_of_arrays_of_strings_delimeterd_by_null: 0 0 sdfddsf
store_strings_in_an_array_of_structs_delimeterd_by_null_of_arrays_of_strings_delimeterd_by_null: 0 1 foo1
store_strings_in_an_array_of_structs_delimeterd_by_null_of_arrays_of_strings_delimeterd_by_null: 1 0 sdsosdfrt
store_strings_in_an_array_of_structs_delimeterd_by_null_of_arrays_of_strings_delimeterd_by_null: 1 1 foo2
store_strings_in_an_array_of_structs_delimeterd_by_null_of_arrays_of_strings_delimeterd_by_null: 2 0 grsdsfdep
store_strings_in_an_array_of_structs_delimeterd_by_null_of_arrays_of_strings_delimeterd_by_null: 2 1 foo3
store_pointers_to_strings_in_array_of_structs: 0 0 sdfddsf
store_pointers_to_strings_in_array_of_structs: 0 1 foo1
store_pointers_to_strings_in_array_of_structs: 1 0 sdsosdfrt
store_pointers_to_strings_in_array_of_structs: 1 1 foo2
store_pointers_to_strings_in_array_of_structs: 2 0 grsdsfdep
store_pointers_to_strings_in_array_of_structs: 2 1 foo3
Live version available at onlinegdb.