初始化链表数组时写入无效
Invalid write when initializing an array of linked lists
所以我有这个函数分配和初始化 NULL
将是一个链表数组。我实际上想要这个函数 return 一个 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: %zu\n", size);
toks_groups[size] = NULL;
size--;
}
return (toks_groups);
}
它工作正常,但是当我 运行 我的程序(这是一个极简主义 shell)进入 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()
。
此外,根据经验:
- 使用有意义的名称。当它显然不是一个大小,而只是一些元素时,调用
size
是令人困惑的。
- 使用正确的代码结构。使用
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;
}
我仍然不确定你是否真的需要额外的元素,但你应该知道这一点。
所以我有这个函数分配和初始化 NULL
将是一个链表数组。我实际上想要这个函数 return 一个 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: %zu\n", size);
toks_groups[size] = NULL;
size--;
}
return (toks_groups);
}
它工作正常,但是当我 运行 我的程序(这是一个极简主义 shell)进入 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()
。
此外,根据经验:
- 使用有意义的名称。当它显然不是一个大小,而只是一些元素时,调用
size
是令人困惑的。 - 使用正确的代码结构。使用
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;
}
我仍然不确定你是否真的需要额外的元素,但你应该知道这一点。