Search code examples
csplitc-stringsfunction-definition

Is there any way to split a CONST char * with a delimiter into an array?


I'm trying to split a given string (input) into an array of elements. Here is my code:

char *buff = save_to_buff(); // save the input
int token_count = 1;
for(int i = 0; buff[i] != '\0';i++)
{
    if(buff[i] == ' ')
    {
        token_count++;
    }
}
char *token = strtok(buff, " ");
char *arr[token_count];

for(int i = 0;token != NULL;i++)
{
    arr[i] = token;
    token = strtok(NULL, " ");
}
for(int i = 0; i < token_count;i++)
{
    printf("%s ", arr[i]);
}

It works, however I need to make a function char **parse_cmdline(const char *cmdline) which splits the buff(cmdline) in this case into an array, but how can I do that if it is even possible? I either get a warning that the 'const' qualifier is discared or an error. Is there any way?


Solution

  • You can split the function into two functions.

    The first one will return the number of tokens in a given string. Using the return value of the function you can allocate an array of pointers the number of elements of which is equal to the number of tokens in the given string plus one. That is the array of tokens will end with a null pointer.

    The second function will fill the provided array with tokens of the given string.

    Here is a demonstration program.

    #include <stdio.h>
    #include <string.h>
    
    size_t count_tokens( const char *s1, const char *s2 )
    {
        size_t n = 0;
    
        while (*s1)
        {
            s1 += strspn( s1, s2 );
    
            if (*s1)
            {
                ++n;
                s1 += strcspn( s1, s2 );
            }
        }
    
        return n;
    }
    
    size_t get_tokens( char **s1, const char *s2, const char *s3 )
    {
        size_t n = 0;
    
        while (*s2)
        {
            s2 += strspn( s2, s3 );
            
            if (*s2)
            {
                ++n;
    
                const char *p = s2;
                s2 += strcspn( s2, s3 );
    
                size_t len = s2 - p;
                *s1 = malloc( len + 1 );
    
                if (*s1)
                {
                    memcpy( *s1, p, len );
                    ( *s1 )[len] = '\0';
                }
    
                ++s1;
            }
        }
    
        *s1 = NULL;
    
        return n;
    }
    
    
    int main( void )
    {
        const char *s1 = "Hello World!";
    
        size_t n = count_tokens( s1, " " );
    
        printf( "%zu\n", n );
    
        char **p = malloc( ( n + 1 ) * sizeof( char * ) );
    
        get_tokens( p, s1, " " );
    
        for ( size_t i = 0; i < n; i++ )
        {
            if ( p[i] ) puts( p[i] );
        }
    
        for (size_t i = 0; i < n; i++)
        {
            free( p[i] );
        }
    
        free( p );
    }
    

    The program output is

    2
    Hello
    World!
    

    As a delimiter of tokens you can pass any string to the functions as for example " \t\n'.