x_array[i]
должен указывать на динамически размещенный массив char
, а x_array
должен указывать на динамически размещенный массив char *
, поэтому x_array
следует объявить как char **x_array
.
Вы передаете указатель на x_array
в качестве параметра arr
функции get_string_array
, поэтому параметр arr
должен быть объявлен как char ***arr
.
The * Функция 1016 * игнорирует переданное значение параметра arr
, поэтому переменная x_array
в main
остается неизменной функцией.
При сбое malloc
функция get_string_array
может быть использование освобожденного указателя в следующей итерации l oop после вызова free(arr)
. Кроме того, main
в настоящее время не может определить, успешно ли get_string_array
выделена память или нет. Один из способов сделать это - установить *arr_len = 0
и *arr = NULL
при сбое.
Вот исправленная версия кода:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int NB_ELEMENTS = 2;
const int MAX_STRING = 50;
void get_string_array(char ***arr, size_t *arr_len) {
int i;
*arr_len = 0; /* in case of failure */
*arr = malloc(sizeof(char *) * NB_ELEMENTS);
if (!*arr) {
printf("the memory could not be allocated for the array\n");
return;
}
for (i = 0; i < NB_ELEMENTS; i++) {
(*arr)[i] = malloc(sizeof(char) * (MAX_STRING + 1));
if (!(*arr)[i]) {
printf("the memory could not be allocated for element [%d]\n", i);
break;
}
}
if (i < NB_ELEMENTS) {
/* Failed to allocate an element. Clean up. */
while (i > 0) {
i--;
free((*arr)[i]);
}
free(*arr);
*arr = NULL;
return;
}
strcpy((*arr)[0], "hello");
strcpy((*arr)[1], "world");
printf("[inside the function] %s %s\n", (*arr)[0], (*arr)[1]);
*arr_len = NB_ELEMENTS;
}
int main(void)
{
char **x_array;
size_t x_length;
get_string_array(&x_array, &x_length);
for (int i=0; (size_t)i < x_length; i++) {
printf("%s\n", x_array[i]);
free(x_array[i]);
}
free(x_array);
return 0;
}
Функция get_string_array
может быть упрощается благодаря использованию локальной переменной, чтобы уменьшить количество разыменований указателя и сделать код более читабельным:
void get_string_array(char ***arr, size_t *arr_len) {
int i;
char **a;
/* In case of failure... */
*arr = NULL;
*arr_len = 0;
a = malloc(sizeof(char *) * NB_ELEMENTS);
if (!a) {
printf("the memory could not be allocated for the array\n");
return;
}
for (i = 0; i < NB_ELEMENTS; i++) {
a[i] = malloc(sizeof(char) * (MAX_STRING + 1));
if (!a[i]) {
printf("the memory could not be allocated for element [%d]\n", i);
break;
}
}
if (i < NB_ELEMENTS) {
/* Failed to allocate an element. Clean up. */
while (i > 0) {
i--;
free(a[i]);
}
free(a);
return;
}
strcpy(a[0], "hello");
strcpy(a[1], "world");
printf("[inside the function] %s %s\n", a[0], a[1]);
*arr = a;
*arr_len = NB_ELEMENTS;
}
В качестве альтернативы можно изменить функцию get_string_array
, чтобы она возвращала указатель на выделенный массив (или NULL
при ошибке), пропуская первый параметр:
char **get_string_array(size_t *arr_len) {
int i;
char **a;
/* In case of failure... */
*arr_len = 0;
a = malloc(sizeof(char *) * NB_ELEMENTS);
if (!a) {
printf("the memory could not be allocated for the array\n");
return NULL;
}
for (i = 0; i < NB_ELEMENTS; i++) {
a[i] = malloc(sizeof(char) * (MAX_STRING + 1));
if (!a[i]) {
printf("the memory could not be allocated for element [%d]\n", i);
break;
}
}
if (i < NB_ELEMENTS) {
/* Failed to allocate an element. Clean up. */
while (i > 0) {
i--;
free(a[i]);
}
free(a);
return NULL;
}
strcpy(a[0], "hello");
strcpy(a[1], "world");
printf("[inside the function] %s %s\n", a[0], a[1]);
*arr_len = NB_ELEMENTS;
return a;
}
Затем вызов функции get_string_array
в main
должен будет соответственно измениться:
int main(void)
{
char **x_array;
size_t x_length;
x_array = get_string_array(&x_length);
for (int i=0; (size_t)i < x_length; i++) {
printf("%s\n", x_array[i]);
free(x_array[i]);
}
free(x_array);
return 0;
}