简体   繁体   中英

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 ?

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

Your input contains Windows/DOS end-of-line codings "\\r\\n" .

Since strtok() just replaces '\\n' with '\\0' , the '\\r' stays in the string. On output it moves the cursor to the left and additional characters overwrite old characters, at least visually.

Your concatenated string should be OK, however. Count the characters, and don't forget to include a '\\r' for each line: "*4\\r200\\r4814\\rSUCCESS\\r3204\\r" are 25 characters as the output splitStr 25 shows.


Additional notes:

  • As others already said, str_ = (char *) malloc(1); does not initialize the space str_ points to. You need to do this yourself, in example by str_[0] = '\\0'; .
  • Don't use underscores that way.
  • You don't need to cast the result of malloc() , it is a void* that is compatible to char* (and any other).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM