【问题标题】:Function to modify dynamically allocated two dimensional array of char*用于修改动态分配的 char* 二维数组的函数
【发布时间】:2017-10-04 06:02:59
【问题描述】:

所以,这是我的逻辑:

这是一些文字:

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

【问题讨论】:

  • 您需要 4 个指针的假设是不正确的。没错,要更改字符串数组的内存参数,您需要传递该内存块的地址,但您不需要 4 个星号。
  • @ryyker 我有点迷路了。所以在主函数中我需要通过地址传递,而接收函数只需要3星?
  • 是的,这是真的。请参阅下面的说明。
  • 虽然“那么这是文本数组:”似乎适用于char **arr;",但arr 不是数组。它是一个指针。这是一个pointer to a pointer of char。对于char *b[10]barray。我发现保持这种差异清晰有助于解决编码问题,例如张贴在这里。

标签: c arrays multidimensional-array char malloc


【解决方案1】:

您只需要 3 个*** 来执行您描述的操作,而不是 4 个****。请注意,有一些方法可以让您避免在字符串数组方面过度深入。还有很好的理由来避免数组的过深顺序,尤其是需要free(.) 分配的所有内容。这意味着每次调用[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 数组,那么为先前分配的 array 字符串分配新内存的原型可能如下所示:

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

【讨论】:

  • 唯一的评论是如果在realloc失败的情况下希望保留buf的原始内容,您可以删除free,视情况而定。此外,不需要if { ... return NULL; } else { buf = tmp; ... }。如果发生故障,您已经返回,所以一个简单的if { ... return NULL; } buf = tmp; ... 就足够了。这些只是尼特,干得好。 tmp = (char *)realloc... 也是已知的Do I cast the result of malloc? nit...
  • @DavidC.Rankin - 感谢您的详细回复! - 关于铸造......直到今年,当我的环境更新到它的最新版本(ANSI C99 的实现)时,我从来没有遇到过不铸造 [m][c][re]alloc( .)。现在我收到了令人讨厌的编译器警告。我还没有联系生产这个编译器的公司并提交错误报告,但这让我想知道他们是否让一些 C++'esk 行为进入我宝贵的C99 系统。
  • @DavidC.Rankin - 关于释放原始缓冲区 - 确实不是绝对必要的。但是我把它放进去是因为如果调用函数发出请求,那是因为需要更多的内存。如果未授予该内存,则当尝试将更多内容写入同一 buf 溢出时,调用者将失败,从而导致访问冲突或 UB。我宁愿返回一个明确的NUL,让调用者知道避免这些失败模式。另一方面,我同意。我将简化声明。再次感谢。
  • size_t numStrings ... int i; ... i&lt;numStringssigned intunsigned size_t 的比较。这会产生“警告:有符号和无符号整数表达式之间的比较 [-Wsign-compare]”。对于非常棒的numStrings,它也是错误的功能,因为size_t 的范围很可能超过int。使用size_t i;size_t numStrings 可以解决警告和功能问题。
  • @chux - 这很可能是产生警告的场景。感谢您的澄清。
【解决方案2】:

我只是偶然发现了我的这个老问题,并立即发现了问题。答案如下:

星号的个数其实是对的,问题是算子评估。具体来说,这种形式的所有代码行:

*table[0]

应该写成:

(*table)[0]

【讨论】:

    猜你喜欢
    • 2010-12-27
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    • 2021-01-26
    • 2015-02-10
    相关资源
    最近更新 更多