c-初始化链表数组时写入无效



所以我有一个函数,它将为NULL分配并初始化一个链表数组。实际上,我希望这个函数返回一个NULL指针数组,以便以后可以用链表填充它。

static t_tokens **init_tokens_groups(size_t size)
{
t_tokens **toks_groups;
if (!(toks_groups = malloc(sizeof(toks_groups) * size + 1)))
exit(EXIT_FAILURE);
while (size + 1)
{
printf("size: %zun", size);
toks_groups[size] = NULL;
size--;
}
return (toks_groups);
}

它工作得很好,但当我在Valgrind中运行我的程序(这是一个极简主义的外壳(时,

valgrind --track-origins=yes ./mysh

我遇到了这个:

==4914== Invalid write of size 8
==4914==    at 0x10AD6B: init_tokens_groups (tokens_split.c:39)
==4914==    by 0x10AE06: split_tokens (tokens_split.c:68)
==4914==    by 0x1093D9: prompt_loop (sh21.c:38)
==4914==    by 0x10944A: main (sh21.c:57)
==4914==  Address 0x4a508f8 is 8 bytes inside a block of size 9 alloc'd
==4914==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4914==    by 0x10AD42: init_tokens_groups (tokens_split.c:35)
==4914==    by 0x10AE06: split_tokens (tokens_split.c:68)
==4914==    by 0x1093D9: prompt_loop (sh21.c:38)
==4914==    by 0x10944A: main (sh21.c:57)
==4914== 
==4914== Invalid write of size 8
==4914==    at 0x10AD6B: init_tokens_groups (tokens_split.c:39)
==4914==    by 0x10AE06: split_tokens (tokens_split.c:68)
==4914==    by 0x109369: dispatch (sh21.c:19)
==4914==    by 0x1093F6: prompt_loop (sh21.c:42)
==4914==    by 0x10944A: main (sh21.c:57)
==4914==  Address 0x4a509f8 is 8 bytes inside a block of size 9 alloc'd
==4914==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4914==    by 0x10AD42: init_tokens_groups (tokens_split.c:35)
==4914==    by 0x10AE06: split_tokens (tokens_split.c:68)
==4914==    by 0x109369: dispatch (sh21.c:19)
==4914==    by 0x1093F6: prompt_loop (sh21.c:42)
==4914==    by 0x10944A: main (sh21.c:57)

我真的不明白它是从哪里来的,因为我只是在这个阶段初始化指向NULL的指针,在填充、操作和读取程序中的链表数组时,我没有遇到任何问题或错误(好吧,我没有检测到(。我想我是在用记忆做一些奇怪的事情,但我不知道在哪里。

这:

toks_groups = malloc(sizeof(toks_groups) * size + 1))

是错误的,并在以后第一次执行toks_groups[size] = NULL;(位于分配的区域之外(时导致问题。Valgrind告诉您无效写入为8字节,因为系统上的指针大小为8字节。

如果要分配size + 1元素,则应将表达式放在括号中。你在做sizeof(toks_groups)这个事实也很奇怪,没有多大意义。你可能想做的是:

toks_groups = malloc(sizeof(*toks_groups) * (size + 1)))

如果只想分配size元素(而不是size + 1(,则从malloc()中删除+ 1并更改while (...)条件。您也根本不需要while,如果您想将所有内容初始化为NULL,您可以使用calloc()而不是malloc()

此外,作为经验法则:

  1. 使用有意义的名称。当某个东西显然不是一个大小,而只是一些元素时,调用size是令人困惑的
  2. 使用正确的代码构造。使用while循环对一系列值进行迭代实际上是违反直觉的,很容易导致错误

上述代码的更好版本如下:

static t_tokens **init_tokens_groups(size_t n)
{
t_tokens **toks_groups;
if (!(toks_groups = calloc(sizeof(*toks_groups) * (n + 1))))
exit(EXIT_FAILURE);
return toks_groups;
}

我仍然不确定你是否真的需要额外的元素,但你应该知道。

最新更新