I have this function split_text
that takes in a char
array text
and attempts to split it into sub-arrays using the token
as the split value, res
is an array of pointers to each of the sub-strings
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("%s\n", ptr[i]);
return 0;
}
when compiling this code it works fine as in it displays the sub-strings each on a new line but when ran with valgrind
, I get many Invalid write of size 8
and Invalid read of size 8
Here is the full valgrind
output
==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)
I know that it is reading and writing from invalid memory places but it still outputs the split-ed text as sub-strings
Why do I get these errors and how do I fix them?
CodePudding user response:
At least this statement
*res = realloc(*res, sizeof(char*)*(x 1))
that is equivalent to
res[0] = realloc(res[0], sizeof(char*)*(x 1))
does not make a sense.
It always reallocates the first element of the array of pointers pointed to by the pointer res
.
As a result the array pointed to by the pointer res
has only one element allocated in main.
So this call strcpy
strcpy(res[x], tmp);
invokes undefined behavior at least when x
is not equal to 0
.
Pay attention to that if you want to change the pointer ptr
declared in main within the function split_text
then you need to pass it to the function by reference. That is the third parameter of the function should be declared like
int split_text(char * text, char * token, char *** res);
As for the function definition then you need to allocate memory for a pointer for each new element and also to allocate a character array pointed to by the pointer where a substring will be copied.