在c中分配内存时写入、读取无效



我有一个函数split_text,它接收char数组text,并尝试使用token作为拆分值将其拆分为子数组,res是指向每个子字符串的指针数组

int split_text(char * text, char * token, char ** res)
{
int x =0;
char * tmp = strtok(text , token);
while (tmp != NULL)
{
res[x] = malloc(1024);
strcpy(res[x], tmp);
x++;
*res = realloc(*res, sizeof(char*)*(x+1));
tmp = strtok(NULL , token);
}
return x;
}
int main()
{
char text[] = "Hello world this is elliot";
char ** ptr = (char**)malloc(sizeof(char*));
int x = split_text(text, " ", ptr);

for (int i =0; i< x; i++)
printf("%sn", ptr[i]);

return 0;
}

当编译这个代码时,它可以很好地工作,就像在中一样,它在新行中显示每个子字符串,但当使用valgrind运行时,我会得到许多Invalid write of size 8Invalid read of size 8

这是完整的valgrind输出

==74210== Memcheck, a memory error detector
==74210== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==74210== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==74210== Command: ./a.out
==74210== 
==74210== Invalid write of size 8
==74210==    at 0x1091D0: split_text (split.c:23)
==74210==    by 0x1092B2: main (split.c:38)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
==74210== Invalid read of size 8
==74210==    at 0x1091E7: split_text (split.c:24)
==74210==    by 0x1092B2: main (split.c:38)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
Hello
==74210== Invalid read of size 8
==74210==    at 0x1092D3: main (split.c:42)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
world
this
is
elliot
==74210== 
==74210== HEAP SUMMARY:
==74210==     in use at exit: 4,152 bytes in 6 blocks
==74210==   total heap usage: 12 allocs, 6 frees, 6,312 bytes allocated
==74210== 
==74210== LEAK SUMMARY:
==74210==    definitely lost: 4,104 bytes in 5 blocks
==74210==    indirectly lost: 48 bytes in 1 blocks
==74210==      possibly lost: 0 bytes in 0 blocks
==74210==    still reachable: 0 bytes in 0 blocks
==74210==         suppressed: 0 bytes in 0 blocks
==74210== Rerun with --leak-check=full to see details of leaked memory
==74210== 
==74210== ERROR SUMMARY: 12 errors from 3 contexts (suppressed: 0 from 0)
==74210== 
==74210== 4 errors in context 1 of 3:
==74210== Invalid read of size 8
==74210==    at 0x1092D3: main (split.c:42)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
==74210== 
==74210== 4 errors in context 2 of 3:
==74210== Invalid read of size 8
==74210==    at 0x1091E7: split_text (split.c:24)
==74210==    by 0x1092B2: main (split.c:38)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
==74210== 
==74210== 4 errors in context 3 of 3:
==74210== Invalid write of size 8
==74210==    at 0x1091D0: split_text (split.c:23)
==74210==    by 0x1092B2: main (split.c:38)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
==74210== ERROR SUMMARY: 12 errors from 3 contexts (suppressed: 0 from 0)

我知道它是从无效的内存位置读取和写入的,但它仍然将分割后的文本作为子字符串输出

为什么会出现这些错误,以及如何修复这些错误?

至少这个语句

*res = realloc(*res, sizeof(char*)*(x+1))

相当于

res[0] = realloc(res[0], sizeof(char*)*(x+1))

没有道理。

它总是重新分配指针res所指向的指针数组的第一个元素。

结果,指针res所指向的数组在main中仅分配了一个元素。

所以这个调用strcpy

strcpy(res[x], tmp);

至少当CCD_ 12不等于CCD_ 13时调用未定义的行为。

请注意,如果要更改函数split_text中main中声明的指针ptr,则需要通过引用将其传递给函数。这是函数的第三个参数,应该像一样声明

int split_text(char * text, char * token, char *** res);

至于函数定义,则需要为每个新元素的指针分配内存,还需要分配指针指向的字符数组,其中将复制子字符串。

最新更新