【问题标题】:Dynamically allocate an array of strings动态分配字符串数组
【发布时间】:2020-12-09 03:49:36
【问题描述】:

如何修复此代码以打印数组中的单词?此外,这是为 n 最大大小为 40 的字动态分配内存的正确方法吗?

int main() {

    int n;
    char *arr;
    int i;

    printf("Give me a number:");
    scanf("%d", &n);

    arr = malloc(n * 40);

    for (i = 0; i < n; i++)
    {
        printf("Give me a word: ");
        scanf("%s", &arr[i]);
    }

    for (i = 0; i < n; i++)
    {
        printf("%s", arr[i]); //< --problem here
    }

    return 0;
}

【问题讨论】:

  • 不,chars 和字符串不一样。
  • 尝试例如typedef char BUF[40]; 然后BUF *arr = malloc(n * sizeof(BUF));

标签: arrays c string dynamic-memory-allocation


【解决方案1】:

您的分配不是最好的,printf 参数 arr[i] 期望 char* 但您将其传递给 int(如果您愿意,可以使用 char)。

下面是你应该如何使用 cmets:

Live demo

#include <stdio.h>
#include <stdlib.h> //for malloc

int main(){
    int n;
    int i;
    
    printf("Give me a number:");
    scanf("%d", &n);

    //declare a variable of pointer to pointer to char
    //allocate memory for the array of pointers to char, 
    //each one capable of pointing to a char array
    char **arr = malloc(n * sizeof *arr);

    if(arr == NULL){ //check for allocation errors
        perror("malloc");
        return EXIT_FAILURE;
    }

    //allocate memory for each individual char array
    for(i = 0; i < n; i++){
        arr[i] = malloc(40); //char size is always 1 byte

        if(arr == NULL){ //check for allocation errors
            perror("malloc");
            return EXIT_FAILURE;
        }
    }

    for (i = 0; i < n; i++){
        printf("Give me a word: ");
        //limit the size of read input to 39 charaters to avoid overflow, 
        //a nul character will be added by scanf
        scanf("%39s", arr[i]);
    }

    for (i = 0; i < n; i++){
        printf("%s\n", arr[i]);
       
    }
     
    for(int i = 0; i < n; i++){ //free the memory for each char array
        free(arr[i]);
    }
    free(arr); //free array of pointers

    return 0;
}

您也可以使用指向 40 个字符数组的指针以更少的代码来完成此操作,这将简化内存分配和释放:

cmets 示例:

Live demo

#include <stdio.h>
#include <stdlib.h> //for malloc

int main(){
    int n;    
    int i;

    printf("Give me a number:");
    scanf("%d", &n);

    //declare a pointer to array of chars and
    //allocate memory for all the char arrays
    char (*arr)[40] = malloc(n * sizeof *arr);

    if(arr == NULL){ //check for allocation errors
        perror("malloc");
        return EXIT_FAILURE;
    }

    for (i = 0; i < n; i++){
        printf("Give me a word: ");
        scanf("%39s", arr[i]);
    }

    for (i = 0; i < n; i++){
        printf("%s\n", arr[i]);
    }

    free(arr); //free allocated memory

    return 0;
}

【讨论】:

  • 在他的代码中,&amp;arr[i]char*,因为 arrchar*arr[i] 将是 char,并且添加一个 & 符号会成为一个指向值的指针。跨度>
  • Nitpick:由于分配给每个字符串 40 个字符,我更喜欢更简单的分配:char (*a)[40]; a = malloc(n * sizeof *a); 然后mallocfree 都是单行的。
  • @cajomar,是的,你说得对,我斜着看没注意。
  • 谢谢,但为什么我也可以像@4386427 所说的那样分配?这样分配不只是一个字符串?我对第一个代码的理解更好,你能更好地解释一下第二个如何为所有 n 个单词分配内存,而不是像我想的那样只为一个单词分配内存吗?我如何阅读:“char (*arr)[40]”?和“char *arr [40]”有什么区别?
  • @Boninissimo,它有点神秘,但它很容易理解,arr 是一个指向 40 个字符数组的指针,例如 sizeof *arr(取消引用的指针)是 40 个字节大小,乘以n 将为您提供所需的内存块,现在arr 是指向 40 个字符的指针,递增它将使其指向下一个 40 个字符块。例如,如果n 为 2,您将拥有一个 40 * 2 字节的块,arr[0] 指向块的开头第一个字节,如果您愿意,arr[1] 会跳转 40 个字节并指向第二个“ line",字节 41。这是以线性方式存储在内存中的。
【解决方案2】:

这个:

for(i=0;i<n;i++){
    printf("Give me a word: ");
    scanf("%s",&arr[i]);
}

可能不是你想要的。
你可能想要这个:

for(i=0; i<n; i++){
    printf("Give me a word: ");
    scanf("%s", arr + i*40);
}

然后:

for(i=0; i<n; i++){
    printf("%s", arr + i*40);
}

请记住,C 中的字符串只是一个字符数组。 因此,在定义char *arr 时,您正在创建一个单个字符串。如果您完成了char **arr,它将是一个字符串数组,这就是您想要的。
但是,我发现在堆上分配/释放数组数组相当不方便,并且更喜欢将它们“展平”为单个数组。
这正是您对 arr = malloc(n*40) 所做的事情,但后来您在执行此操作时将此 characters 数组视为 strings 数组:

for(i=0; i<n; i++){
    printf("Give me a word: ");
    scanf("%s", &arr[i]);
}

请注意,这实际上是完全合法的(scanf 想要 char* 而你给了它),但这是一个逻辑错误,因为你给它的是 n-th 字符当你想给它n-th array.

哦,是的,以后别忘了free(arr)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-21
    • 2013-03-09
    • 2017-10-23
    • 1970-01-01
    • 2015-07-14
    • 2017-10-03
    相关资源
    最近更新 更多