I have this code here that is tokenizing a string. This line check if a string have quotes and returns the string without quotes. If I get something from the user, for example Hello "nice" day
, it will return hello nice day
:
char* str = take_quotes(line, stderr);
The function take_quotes
is allocating space so I need to deallocate space in my tokenize function.
I thought that after I use the line I could free the space before returning my tokens, but when I do that I lose whatever is in my tokens. How should I free the space that was returned from take_quotes
?
char** tokenize(char* line){
if(line == NULL)
return NULL;
char* str = take_quotes(line, stderr); //free space
char **tokens = malloc( sizeof( char * ) );
*tokens = NULL;
size_t n = 1;
const char *delim = " \t \n";
char *p = strtok( str, delim );
int success = p != NULL;
while ( success )
{
char **tmp = realloc( tokens, ( n 1 ) * sizeof( char * ) );
if ( tmp == NULL )
{
free( tokens );
tokens = NULL;
success = 0;
}
else
{
tokens = tmp;
tokens[n - 1] = p;
tokens[n] = NULL;
n;
p = strtok( NULL, delim );
success = p != NULL;
}
}
free(str);
str = NULL;
return tokens;
}
When I change my line
tokens[n - 1] = p;
to
tokens[n - 1] = strdup(p);
I get many errros in Valgrind
==8175== LEAK SUMMARY:
==8175== definitely lost: 12 bytes in 3 blocks
==8175== indirectly lost: 0 bytes in 0 blocks
==8175== possibly lost: 6 bytes in 1 blocks
==8175== still reachable: 0 bytes in 0 blocks
==8175== suppressed: 0 bytes in 0 blocks
==8175==
==8175== For lists of detected and suppressed errors, rerun with: -s
==8175== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
CodePudding user response:
strtok
tokenizes the given string in-place, by inserting NUL terminating bytes into the string at the delimiters. No additional memory is allocated. When you free str
, you are destroying the memory that contains these tokens.
One approach is to make copies of your tokens, allocating memory for each along the way.
strdup
can be used for this purpose:
tokens[n - 1] = strdup(p);
If strdup
is not available on your system, then you will have to rewrite its functionality (hint: strlen
malloc
strcpy
, and don't forget additional space for the NUL terminating byte!).
When it is time to free tokens
, you will have to free each of the individual elements it contains first.
A contrived example of freeing each element of a jagged array:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void free_tokens(char **tokens) {
for (char **t = tokens; *t != NULL; t )
free(*t);
free(tokens);
}
int main(void) {
char **tokens = malloc(3 * sizeof *tokens);
tokens[0] = strdup("hello");
tokens[1] = strdup("world");
tokens[2] = NULL;
for (char **t = tokens; *t != NULL; t )
printf("token:[%s]\n", *t);
free_tokens(tokens);
}