Your use of strtok() is correct. The problem is your use of the uninitialized argv. You need to make sure that all destination strings have been allocated sufficient memory. Compare and contrast:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *copy_str(const char *s)
{
char *copy = malloc(strlen(s) + 1);
if (copy != NULL)
strcpy(copy, s);
return copy;
}
char **split_str(const char *s, const char *delim)
{
/*
Error handling omitted for brevity
*/
char **dst = malloc(sizeof *dst);
char *src = copy_str(s);
char *tok = strtok(src, delim);
size_t n = 0;
while (tok != NULL) {
dst = realloc(dst, ++n);
dst[n - 1] = copy_str(tok);
tok = strtok(NULL, delim);
}
dst[n] = NULL;
free(src);
return dst;
}
int main(void)
{
char **s = split_str("this|is|a|test", "|");
size_t i;
for (i = 0; s[i] != NULL; i++) {
printf("'%s'\n", s[i]);
free(s[i]);
}
free(s);
return 0;
}
Narue
Bad Cop
15,460 posts since Sep 2004
Reputation Points: 6,483
Solved Threads: 1,407
Skill Endorsements: 54
dst = realloc(dst, ++n);
It should be this:
dst = realloc(dst, ++n * sizeof *dst);
And that, my friend, is proof that regardless of your experience or ability, stupid mistakes happen. Especially if you work with higher level language too often and then drop down to a low level language that doesn't hold your hand. ;)
Narue
Bad Cop
15,460 posts since Sep 2004
Reputation Points: 6,483
Solved Threads: 1,407
Skill Endorsements: 54
Please post a complete main() function that exhibits the problem. The snippets you posted are clearly not the code you're trying to execute because they won't compile.
Narue
Bad Cop
15,460 posts since Sep 2004
Reputation Points: 6,483
Solved Threads: 1,407
Skill Endorsements: 54
That code still doesn't compile (which suggests that you're not showing me your actual code), and when I fix the syntax error on your fgets() call, it doesn't fault on my system.
Narue
Bad Cop
15,460 posts since Sep 2004
Reputation Points: 6,483
Solved Threads: 1,407
Skill Endorsements: 54
I suspect that it was trying to free a pointer that doesn't exist which kind of doesn't make sense.
This is a case where I don't see an immediate problem. It would probably take some debugging, but as I cannot reproduce the error, I can't help too much. It's a shame, because I'd be interested to know exactly what's causing your error.
I know it's important to free buffers we don't need anymore from the memory but do we need to free(src)?
Unless the process lives for a long time, it's not technically necessary. On modern operating systems the memory allocated dynamically will be freed when the process terminates. However, one can't determine conclusively how library functions such as split_str() might be called, so it's an excellent idea to clean up after yourself.
You can get rid of the allocation entirely (and thus the need for free()) by assuming that s is modifiable. This puts the onus on the caller to refrain from calling split_str() with something like a string literal. The reason for that is strtok() modifies the source string, and string literals are read-only:
char **split_str(char *s, const char *delim)
{
/*
Error handling omitted for brevity
*/
char **dst = malloc(sizeof *dst);
char *tok = strtok(s, delim);
size_t n = 0;
while (tok != NULL) {
dst = realloc(dst, ++n * sizeof *dst);
dst[n - 1] = copy_str(tok);
tok = strtok(NULL, delim);
}
dst[n] = NULL;
return dst;
}
Narue
Bad Cop
15,460 posts since Sep 2004
Reputation Points: 6,483
Solved Threads: 1,407
Skill Endorsements: 54
Question Answered as of 1 Year Ago by
Narue