2

Possible Duplicate:
Split string with delimiters in C

I'm searching a good way to "explode" a char* into other char* using a delimiter.

My delimiter will be #

Community
  • 1
  • 1
Math
  • 666
  • 8
  • 26
  • 1
    Are you looking for something like [strtok](http://www.elook.org/programming/c/strtok.html)? – Mihai Oct 08 '12 at 21:44
  • Nothing at this time, just searching for a good way to do it. Here is what i'm thinking; Loop trough the char array, and copy each char into the other char*, and this until the current char is my delimiter. – Math Oct 08 '12 at 21:45
  • see [examples how to split a sentence into words](http://stackoverflow.com/q/47402/4279) – jfs Oct 08 '12 at 21:47
  • "explode" is a function name that [I'm hardly surprised to find is common in PHP](http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/) – HostileFork says dont trust SE Oct 08 '12 at 21:50

2 Answers2

11

You can use strtok like CrazyCasta said but his/hers code is wrong.

char *tok;
char *src = malloc(strlen(srcStr) + 1);
memcpy(src, srcStr);

tok = strtok(src, "#");
if(tok == NULL)
{
    printf("no tokens found");
    free(src);
    return ???;
}
printf("%s ; ", tok);
while((tok = strtok(NULL, "#")))
    printf("%s ; ", tok);
printf("\n");
free(str);

Be aware that strtok has to be called the first time with the source pointer, after that you have to use NULL. Also src must be writeable because strtok writes \0 to terminate the found strings. Hence, depending on how you read the string (and whether you are going to use it afterwards or not), you should do a copy of it. But as I said, this is not always necessary.

EDIT:

an explode function could look like this:

char *strdup(const char *src)
{
    char *tmp = malloc(strlen(src) + 1);
    if(tmp)
        strcpy(tmp, src);
    return tmp;
}

void explode(const char *src, const char *tokens, char ***list, size_t *len)
{   
    if(src == NULL || list == NULL || len == NULL)
        return;

    char *str, *copy, **_list = NULL, **tmp;
    *list = NULL;
    *len  = 0;

    copy = strdup(src);
    if(copy == NULL)
        return;

    str = strtok(copy, tokens);
    if(str == NULL)
        goto free_and_exit;

    _list = realloc(NULL, sizeof *_list);
    if(_list == NULL)
        goto free_and_exit;

    _list[*len] = strdup(str);
    if(_list[*len] == NULL)
        goto free_and_exit;
    (*len)++;


    while((str = strtok(NULL, tokens)))
    {   
        tmp = realloc(_list, (sizeof *_list) * (*len + 1));
        if(tmp == NULL)
            goto free_and_exit;

        _list = tmp;

        _list[*len] = strdup(str);
        if(_list[*len] == NULL)
            goto free_and_exit;
        (*len)++;
    }


free_and_exit:
    *list = _list;
    free(copy);
}

then you have to call it:

char **list;
size_t i, len;
explode("this;is;a;string", ";", &list, &len);
for(i = 0; i < len; ++i)
    printf("%d: %s\n", i+1, list[i]);

/* free list */
for(i = 0; i < len; ++i)
    free(list[i]);
free(list);

this is an example running with valgrind:

valgrind ./a 
==18675== Memcheck, a memory error detector
==18675== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. 
==18675== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==18675== Command: ./a 
==18675== 
1: this
2: is
3: a
4: string
==18675== 
==18675== HEAP SUMMARY:
==18675==     in use at exit: 0 bytes in 0 blocks
==18675==   total heap usage: 9 allocs, 9 frees, 114 bytes allocated
==18675== 
==18675== All heap blocks were freed -- no leaks are possible
==18675== 
==18675== For counts of detected and suppressed errors, rerun with: -v
==18675== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
Pablo
  • 13,271
  • 4
  • 39
  • 59
  • Works great, thanks! Apparently my compiler is a bit picky so I had to specify the return types for malloc and realloc. `char *tmp = (char*)malloc(strlen(src) + 1);` and `tmp = (char**)realloc(_list, (sizeof * _list) * (*len + 1));` and `_list = (char**)realloc(NULL, sizeof * _list);` ... hope that bit helps someone. – Vince K Jan 23 '20 at 02:33
  • 1
    @VinceK you are probably using a C++ compiler, a C compiler should not require you to cast a `void*` to another pointer. – Pablo Jan 23 '20 at 17:20
  • You are correct @Pablo – Vince K Jan 24 '20 at 01:18
  • 1
    @VinceK be aware of compiling C code with a C++ compiler. There are some differences and you might end up with strange results. See https://stackoverflow.com/questions/1201593/where-is-c-not-a-subset-of-c – Pablo Jan 24 '20 at 09:33
1

Generally this is what the strtok function is for:

char* tok;
tok = strtok(srcStr, "#");

while(tok != NULL)
{
    // Do stuff with tok
    tok = strtok(NULL, "#");
}
CrazyCasta
  • 26,917
  • 4
  • 45
  • 72