函数修改动态分配字符的二维数组*

问题描述:

所以,这里是我的逻辑:函数修改动态分配字符的二维数组*

这是一些文本:

char *text; 

然后,这是课文的数组:

char **arr; 

然后这些阵列的阵列是:

char ***arr2d; 

如果我想一个函数来修改它,它需要接受它:

char ****arr2d; 

和函数中使用它:

*arr2d = (e.g. allocate); 

所以,如果我想创建二维数组一样这并使第一行,第一列只包含一个字母'a',那么为什么这不起作用?

#define COLUMNS 7 

    void loadTable(char ****table) 
    { 
      *table = (char ***) malloc(sizeof(char**)); 

      if (!*table) { 
       printf("Allocation error for table rows."); 
       return; 
      } 

      *table[0] = (char**) malloc(COLUMNS * sizeof(char*)); 

      if (!*table[0]) { 
       printf("Allocation error for table columns."); 
       return; 
      } 

      *table[0][0] = (char*) malloc(2 * sizeof(char)); 

     *table[0][0][0] = (char)(97); 
     *table[0][0][1] = '\0'; 
    } 


    int main() 
    { 

     char ***table; 

     loadTable(&table); 

     return 0; 
    } 
+1

假设你需要4个指针是不正确的,如果你的愿望实现第二架原型机这必须扩大。确实,要更改字符串数组的内存参数,您需要传递该内存块的地址,但不需要4个星号即可完成此操作。 – ryyker

+0

@ryyker我迷路了一下。所以在主函数中我需要通过地址来传递它,但接收函数只需要3颗星? – Bondy

+0

是的,那是真的。请参阅下面的解释。 – ryyker

您将只需要3 ***做你的描述,而不是4 ****。请注意,有些方法可以让您避免使用字符串数组的数组。还有很好的理由来避免数组的过度深入,而不仅仅是需要你分配的所有东西。这意味着对[m][c][re]alloc(.)的每次调用只需拨打free(.)

但是,为了解决您的问题...

一般情况下,创建新的内存为阵列以前分配的内存,你可以使用一个函数原型为:

char * ReSizeBuffer(char **str, size_t origSize); 

如果说以前分配的缓冲区创建为:

char *buf = calloc(origSize, 1); 

...使用情况如下所示:

char *tmp = {0}; 

tmp = ReSizeBuffer(&buf, newSize); //see implementation below 
if(!tmp) 
{ 
    free(buf); 
    return NULL; 
} 
buf = tmp; 
///use new buf 
... 

那么,如果这种方式更适合焦炭的单一阵列,然后原型为字符串之前分配阵列分配新的内存可能是这样的:

char ** ReSizeBuffer(char ***str, size_t numArrays, size_t strLens); 

哪里,如果说以前分配2D缓冲创建为:

char **buf = Create2DStr(size_t numStrings, size_t maxStrLen); //see implementation below 

...的使用可能看起来像:

char **tmp = {0}; 

tmp = ReSizeBuffer(&buf, numStrings, maxStrLen); 
if(!tmp) 
{ 
    free(buf); 
    return NULL; 
} 
buf = tmp; 
///use new buf 
... 

实现:

ReSizeBuffer实现。

char * ReSizeBuffer(char **str, size_t size) 
{ 
    char *tmp={0}; 

    if(!(*str)) return NULL; 

    if(size == 0) 
    { 
     free(*str); 
     return NULL; 
    } 

    tmp = (char *)realloc((char *)(*str), size); 
    if(!tmp) 
    { 
     free(*str); 
     return NULL; 
    } 
    *str = tmp; 

    return *str; 
} 

Create2DStr实现可能是这样的:

char ** Create2DStr(size_t numStrings, size_t maxStrLen) 
{ 
    int i; 
    char **a = {0}; 
    a = calloc(numStrings, sizeof(char *)); 
    for(i=0;i<numStrings; i++) 
    { 
     a[i] = calloc(maxStrLen + 1, 1); 
    } 
    return a; 
} 
+0

唯一的评论将是,如果有一个愿望,保留'buf'的原始内容在'realloc'失败,你可以取消'free',取决于情况。另外,不需要'if {... return NULL;} else {buf = tmp; ...}'。如果失败发生,你已经*返回*,所以一个简单的'if {... return NULL;} buf = tmp; ...'就足够了,这些只是nits,所以'tmp =(char *)realloc ...'也是已知的[**我是否施放了malloc **的结果](http://*.com/q/605845/995714)nit ... –

+0

@ DavidC.Rankin - 感谢您的详细回复! - 关于铸造...直到今年,当我的环境更新到它的最新版本(ANSI C99的实现)时,我从来没有任何问题没有施放[m] [c] [re] alloc返回)。现在我得到了一个令人讨厌的编译器警告。我还没有联系用bug报告生成这个编译器的公司,但是这让我怀疑他们是否让一些C++的esk行为进入我的珍贵'C99'系统。 – ryyker

+0

@ DavidC.Rankin - 关于释放原始缓冲区 - 确实不是绝对必要的。但我把它放进去,因为如果一个请求是由一个调用函数完成的,那是因为需要更多的内存。如果该内存未被授予,则当尝试向同一buf写入更多内容时,调用者将失败,导致访问冲突或UB。我宁愿让返回成为一个明确的'NUL',以允许调用者知道避免这些失败模式。另一方面,我同意。我将简化陈述。再次感谢。 – ryyker