Search code examples
cstring-concatenationstrcat

Dynamic string concatenation with strcat in C


I have experienced an issue while using strcat, using realloc however, strcat overwrites destination string

char *splitStr(char *line) {
        char *str_;
        str_ = (char *) malloc(1);
        char *ptr = strtok(line,"\n");
        int a;
        while (ptr != NULL) {
              if (ptr[0] != '$') {
                        printf("oncesi %s\n", str_);
                        a = strlen(ptr) + strlen(str_) + 1;
                        str_ = realloc(str_, a);
                        strcat(str_, ptr);
                        str_[a] = '\0';
                        printf("sontasi:%s\n", str_);
              }
              ptr = strtok(NULL, "\n");
        }
        printf("splitStr %d\n", strlen(str_));
        printf("%s", str_);
        return str_;
}

and my input value is ;

*4
$3
200
$4
4814
$7
SUCCESS
$4
3204

so I want to split this input value via strtok; strtok(line,'\n');

and concat all line without start "$" char to new char. However, this code give following output;

line: *4
oncesi 
sontasi:*4
oncesi *4
200tasi:*4
200esi *4
4814asi:*4
4814si *4
SUCCESS:*4
SUCCESS*4
3204ESS:*4
splitStr 25

seems to overwrite source string. do you have any idea why this issue could be happening ?


Solution

  • the following proposed code:

    1. cleanly compiles
    2. performs the indicated functionality
    3. is slightly reformated for readability of output
    4. checks for errors from malloc() and realloc()
    5. shows how to initialize the str[] array, which is the problem in the OPs posted code.
    6. the function: strlen() returns a size_t, not an int. so the proper output format conversion specifier is: %zu
    7. does not use trailing underscores on variable names

    and now, the proposed code:

    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    
    char *splitStr( char *line ) 
    {
        printf("original line: %s\n", line);
    
        char *str = malloc(1);
        if( !str )
        {
            perror( "malloc failed" );
            exit( EXIT_FAILURE );
        }
    
        str[0] = '\0';   // critical statement
        char *token = strtok(line,"\n");
    
    
        while( token ) 
        {
            if( token[0] != '$') 
            {
                char* temp = realloc( str, strlen( token ) + strlen( str ) + 1 );
                if( ! temp )
                {
                    perror( "realloc failed" );
                    free( str );
                    exit( EXIT_FAILURE );
                }
    
                str = temp;   // update pointer
    
                strcat(str, token);
                printf( "concat result: %s\n", str );
            }
            token = strtok(NULL, "\n");
        }
    
        printf("splitStr %zu\n", strlen(str));
        return str;
    }
    
    
    int main( void )
    {
        char  firstStr[] = "$abcd\n$defg\nhijk\n";
        char *firstNewStr = splitStr( firstStr );
        printf( "returned: %s\n\n\n\n", firstNewStr );
        free( firstNewStr );
    
        char  secondStr[] = "abcd\ndefg\nhijk\n";
        char *secondNewStr = splitStr( secondStr );
        printf( "returned: %s\n\n\n\n", secondNewStr );
        free( secondNewStr );
    }
    

    a run of the proposed code results in:

    original line: $abcd
    $defg
    hijk
    
    concat result: hijk
    splitStr 4
    returned: hijk
    
    
    
    original line: abcd
    defg
    hijk
    
    concat result: abcd
    concat result: abcddefg
    concat result: abcddefghijk
    splitStr 12
    returned: abcddefghijk