Передайте массив строк для работы и используйте malloc - PullRequest
0 голосов
/ 18 марта 2020

В C Language я пытаюсь создать массив строк в функции с mallo c. Вместо того, чтобы возвращать массив, я передаю его адрес и адрес переменной size_t. Я хотел бы сохранить динамический массив c, что означает, что размер массива определяется функцией. Идея та же, что и у следующей ссылки, но на этот раз со строками вместо целых: { ссылка }

#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) {

    arr = malloc(sizeof(char *) * NB_ELEMENTS);
    if (!arr) {
        printf("the memory could not be allocated for the array\n");
        return;
    }


    for (int i = 0; i < NB_ELEMENTS; i++) {
        arr[i] = malloc(sizeof(char) * (MAX_STRING + 1));
        if (!arr[i]) {
            free(arr);
            printf("the memory could not be allocated for element [%d]\n", i);
        }
    }

    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;
}

Код не работает, я думаю, что проблема заключается в том, как я объявляю указатель и передаю его функции. Способ построения массива должен быть в порядке.

Вот трассировка стека от g cc:

test-array-str.c:39:15: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
      printf("%s\n", x_array[i]);
              ~^     ~~~~~~~~~~
              %d
test-array-str.c:40:21: warning: passing argument 1 of ‘free’ makes pointer from integer without a cast [-Wint-conversion]
         free(x_array[i]);
              ~~~~~~~^~~
In file included from test-array-str.c:2:
/usr/include/stdlib.h:563:25: note: expected ‘void *’ but argument is of type ‘char’
 extern void free (void *__ptr) __THROW;
                   ~~~~~~^~~~~

Ответы [ 2 ]

0 голосов
/ 18 марта 2020

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;
}
0 голосов
/ 18 марта 2020

x_array[i] имеет тип char, который повышается до int.

, вам нужно объявить его как char ** и в функции как char ***

...