【问题标题】:Invalid write after allocating memory for struct member in array of structs为结构数组中的结构成员分配内存后写入无效
【发布时间】:2019-03-05 11:02:37
【问题描述】:

我需要将一个结构数组传递给一个函数,我的理解是我必须为整个结构数组以及数组内每个结构中的每个单独的结构成员分配内存。

我这样做的方式导致来自 valgrind 的无效写入错误(在函数 read_file 内的第二行引起)。怎么了?

typedef struct test
{
    char *string1; 
    int num1; 
    int num2;
    char *string2;
} Test;

static void read_file(Test *test)
{
    test = (Test *)calloc(16, sizeof(test));
    test[0].string1 = (char *)calloc(strlen("hello") + 1, sizeof(char));
}

int main(void)
{
    int i = 0;
    Test test[16];

    for (i = 0; i < 16; i++)
    {
        memset(&test[i], 0, sizeof(test[i]));
        test[i] = (Test) { "", 0, 0, "" };
    }

    read_file(test);
    return 0;
}

PS:我知道我必须释放分配的内存,但首先我想让上面的代码工作。

【问题讨论】:

  • 不要忘记参数是按传递的,即它们是复制的。副本的修改(即对局部参数变量的赋值)不会改变原始的。当您在 read_file 函数中对 test 进行赋值时,请考虑这一点。
  • 另外,test 已经指向(第一个元素)一个现有数组,为什么还要分配新内存?

标签: c struct dynamic-memory-allocation calloc


【解决方案1】:

main 中的 test 数组已经为其分配了内存。

然后您将其传递给read_file 函数,因此您无需再次为其分配内存。删除这个:

test = (Test *)calloc(16, sizeof(test));

顺便说一句,您可能打算在那里使用sizeof(Test)(或sizeof(*test))。 sizeof(test)sizeof(Test*) 相同,几乎可以肯定小于sizeof(Test)

【讨论】:

  • 您也可以使用sizeof(*test) 代替sizeof(Test)。 (两者都有效)
  • 如果没有该行 (test = (Test *)calloc(16, sizeof(test));),程序会以错误“Aborted (core dumped)”终止。所以我想我确实需要它?!
  • @ci7i2en4:您确定您在谈论您在问题中发布的代码吗?还是你做得比展示的更多?
  • 我原始帖子中的 sn-p 是更长代码的一部分。但是,我确信未显示的部分没有错误,因为我已经测试了数周而没有遇到任何问题。直到今天早些时候,在添加显示的内容后,才会出现“无效写入”错误。或者“中止(核心转储)”,如果我删除你提到的那一行。
  • @ci7i2en4 这表明您的其他代码有 undefined behavior 并且它很幸运。 Valgrind 应该会告诉你你的其他代码哪里出错了。
【解决方案2】:
Test *test

read_file 函数中的 test 变量是 Test 结构的 pointer

sizeof(test)

这等于 指针的大小

test = (Test *)calloc(16, sizeof(test));

这为Test 结构的16 个指针 分配内存。这不会为 16 个结构分配内存,只为指向它们的指针分配内存。

test[0].string1 = 

无效并且发生未定义的行为。由于sizeof(test)sizeof(Test) 小得多,因此没有足够的内存来访问test0[].string1。因此,这会“越界”访问内存,并且会访问无效/未分配的内存区域。当您尝试写入它(您正在执行分配)时,表达式无效并且会发生未定义的行为。 Valgrind 正确地将其检测为“写入错误”——您尝试写入不属于您的内存。

【讨论】:

  • 即使在将 sizeof(test) 更改为 sizeof(Test) 之后,test[0].string1 = ... 仍然出现相同的错误
  • 我想通了:我正在读取一个包含 16 行数据的 CSV 文件(进入结构数组)。这就是我(c)为其分配内存的 16 个结构。但是,CSV 文件中也有“标题行”(描述列),我完全忘记了!现在,在将其更正为 test = (Test *)calloc(17, sizeof(Test));我的代码运行良好。
猜你喜欢
  • 2021-12-09
  • 2021-06-04
  • 1970-01-01
  • 2022-11-07
  • 1970-01-01
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多