【问题标题】:Pass array of strings to function and use malloc将字符串数组传递给函数并使用 malloc
【发布时间】:2020-03-18 16:35:16
【问题描述】:


在 C 语言中,我尝试在一个带有 malloc 的函数中创建一个字符串数组。
我没有返回数组,而是传递了它的地址和一个 size_t 变量地址。
我想保持数组动态,这意味着数组的大小由函数决定。
这个想法与以下链接相同,但这次使用字符串而不是整数:
https://stackoverflow.com/a/8437818/5036990

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

代码不起作用,我认为问题出在我声明指针并将其传递给函数的方式上。数组的构建方式应该没问题。

这是来自 gcc 的堆栈跟踪:

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;
                   ~~~~~~^~~~~

【问题讨论】:

  • 函数的第一行丢弃了参数。也许你的意思是*arr = malloc ...

标签: c malloc


【解决方案1】:

x_array[i]应该指向char的动态分配数组,x_array应该指向char *的动态分配数组,所以x_array应该声明为char **x_array

您将一个指向x_array 的指针作为get_string_array 函数的arr 参数传递,因此arr 参数应声明为char ***arr

get_string_array函数忽略了arr参数传入的值,所以main中的x_array变量保持不变。

如果malloc 失败,则get_string_array 函数可能在调用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;
}

然后,main 中对 get_string_array 函数的调用需要相应地更改:

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

【讨论】:

  • 非常感谢,伊恩,这对您有帮助
【解决方案2】:

x_array[i] 的类型为 char,它被提升为 int

您需要将其声明为 char ** 并在函数中声明为 char ***

【讨论】:

    猜你喜欢
    • 2016-12-08
    • 2015-09-09
    • 1970-01-01
    • 2018-02-13
    • 1970-01-01
    • 2013-06-27
    • 2015-05-27
    相关资源
    最近更新 更多