使用 realloc 和 calloc 增加函数内二维数组的大小

Posted

技术标签:

【中文标题】使用 realloc 和 calloc 增加函数内二维数组的大小【英文标题】:Increase the size of a 2D-Array inside a function with realloc and calloc 【发布时间】:2021-12-25 04:32:15 【问题描述】:

我想在一个数组中存储多个字符串(也就是字符数组)。因此,我想使用二维数组。由于我不知道确切的大小(单个字符串的长度和字符串的数量),我需要动态增加大小。

为了更好的结构,我想把这个放在一个单独的函数里面。但是,如果我在调整数组大小后访问我的数组,显然大小没有改变,我会遇到分段错误。

我是 C 的新手(来自 C++ 背景)

#include<stdio.h>
#include <stdlib.h>

//I want to increase my array from [1][5] to [2][5]
void increase(char*** data)

    *data = realloc(*data, 2 * sizeof (char*));
    *data[1] = calloc(5, sizeof(char));


int main(void)

    char** data  = calloc(1, sizeof(char*));
    data[0] = calloc(5, sizeof(char));

    increase(&data);

    data[1][3] = 'a'; //<-- When I access the array I get an segmentation fault

    free(data);
  
  return 0;

我使用char*** 的方法是否正确?我可以直接在主函数中的测试环境中实现它并且它有效。但是,一旦将它封装在一个函数中,我就得到了一个 seg。故障。

我认为这与我将数组传递给函数的方式有关,但我无法弄清楚这是什么原因以及如何解决它。有没有人有一些想法或解决方案?

【问题讨论】:

@AdrianMole 你是对的。刚刚修复了这个例子。 请注意*data[1] 被解析为*(data[1]),而不是(*data)[1]。而data[1] 不存在 【参考方案1】:

错误(这是微妙的灾难性)在于您如何尝试分配传递的指针数组的第二个元素,并且与operator precedence 有关。请注意,数组下标运算符[] 的优先级高于间接运算符*

因此,您的线路:

*data[1] = calloc(5, sizeof(char));

其实有这样的效果:

*(data[1]) = calloc(5, sizeof(char));

正如您希望看到的那样,这确实是不是您想要做的。

相反,您需要:

(*data)[1] = calloc(5, sizeof(char));

另一个问题(虽然不是错误,本身)是您没有对分配进行任何错误检查;这在使用realloc 时尤其重要,因为就您的代码而言,如果调用失败,您将丢失“原始”指针。最好将来自realloc 的返回值存储在一个临时文件中,然后仅当该临时文件不是NULL 时才覆盖原始值。

这是您的代码可能的重新工作(不过,您可以/应该在 calloc 调用上添加更多错误检查):

#include <stdio.h>
#include <stdlib.h>

int increase(char*** data)

    char** temp = realloc(*data, 2 * sizeof(char*));
    if (temp != NULL) 
        *data = temp;   // Only overwrite the original if we succeed!
        (*data)[1] = calloc(5, sizeof(char));
        return 1;
    
    else 
        printf("Allocation error!"); // But we still have our original "data" pointer
        return 0;
    


int main(void)

    char** data = calloc(1, sizeof(char*));
    data[0] = calloc(5, sizeof(char));
    if (increase(&data)) 
        data[1][3] = 'a';
        printf("%c\n", data[1][3]); // Just to do some testing!
        free(data[1]); // Free the second (added) block
    
    free(data[0]) // Free the first (original) block
    free(data); // "data" will be valid whether or not our call to "increase" works
    return 0;

【讨论】:

问题是您的代码中没有二维数组。问题是关于二维数组。指针数组不是二维数组 (*data)[1] = calloc(5, sizeof(char)); - 不,这是错误的 (*data)[1] 是指向单个元素字符数组的指针 - 在问题的上下文中这根本没有意义 @0___________ (*data)[1] 是一个 char* 指针。返回的值为calloc(5, sizeof(char)) @0___________ 不确定您的实际意思,但 (*data)[1] 实际上是指针数组的单个元素(在我的代码中相当于 temp[1]);我真的很困惑你是如何得到 is a pointer to single element char array. @0___________ 当然,除非感到困惑:char (*data)[1]; 声明指向单元素字符数组的指针...但是我的代码中 nowhere 有这样的声明。【参考方案2】:
    您的代码中没有任何二维数组,只有指针数组。您的问题是关于二维数组的。

琐碎代码(列数不变)

void *alloc2D(const size_t rows, const size_t cols, char (*arr)[cols])

    arr = realloc(arr, rows * sizeof(*arr));
    return arr;

不那么琐碎的代码 - 两者都在变化。

void *alloc2D(const size_t rows, const size_t cols, const size_t oldrows, const size_t oldcols, char (*arr)[oldcols])

    char (*newarr)[cols] = malloc(rows * sizeof(*newarr));

    if(arr && newarr)
    
        for(size_t r = 0; r < rows && r < oldrows; r++)
        
            memcpy(newarr[r], arr[r], sizeof(*arr) > sizeof(*newarr) ? sizeof(*newarr) : sizeof(*arr));p
        
       
    if(newarr) free(arr);
    return newarr;

还有一些用法:

void *increase(const size_t oldrows, const size_t oldcols, char (*arr)[oldcols])

    return alloc2D(oldrows+1, oldcols, arr);


int main(void)

    size_t rows;
    size_t cols;

    if(scanf("%zu", &rows) != 1)  /* error handling*/
    if(scanf("%zu", &cols) != 1)  /* error handling*/

    char (*arr)[cols] = alloc2D(rows, cols, NULL);
    char (*narr)[cols];

    narr = increase(rows, cols, arr);
    if(narr) arr = narr;

    free(narr);
  
  return 0;

【讨论】:

你在哪里为你的列分配新内存? @David9472 阅读代码 - 一切都在那里

以上是关于使用 realloc 和 calloc 增加函数内二维数组的大小的主要内容,如果未能解决你的问题,请参考以下文章

动态内存分配的补充 realloc和calloc函数

C中堆管理——浅谈malloc,calloc,realloc函数之间的区别

C中堆管理——浅谈malloc,calloc,realloc函数之间的区别

realloc,malloc,calloc函数的区别

动态内存函数+经典笔试题@动态内存管理---malloc +free + calloc + realloc

alloc()malloc()calloc()realloc()区别及用法