Search code examples
cdynamic-memory-allocation

Concatenating two strings : C


Consider Below code for concatenating two char arrays with a delimiter:

void addStrings(char* str1,char* str2,char del)
{
//str1=str1+str2
int len1=strlen(str1);
int len2=strlen(str2);
int i=0;
//char* temp=(char*) malloc((len1+1)*sizeof(char));
//strcpy(temp,str1);
str1=(char*) realloc(str1,(len1+len2+1)*sizeof(char));
printf("Here--%d\n",strlen(str1));
*(str1+len1)=del; //adding delimiter
for(i=0;i<=len2;i++)
    *(str1+len1+i+1)=*(str2+i);
printf("Concatenated String: %s\n",str1);
i=0;
    while( *(str1+i) != '\0')
    {
            printf("~~%d:%c\n",i,*(str1+i));
        i++;
    }

}

When running this function with addStrings("A","test",'@');; The code crashes as realloc below is gdb output

Breakpoint 3, addStrings (str1=0x40212f <_data_start__+303> "A", str2=0x40212a <_data_start__+298> "test",
    del=64 '@') at string.c:34
34      int len1=strlen(str1);
(gdb) s
35      int len2=strlen(str2);
(gdb) s
36      int i=0;
(gdb) s
39      str1=(char*) realloc(str1,(len1+len2+1)*sizeof(char));
(gdb)

Program received signal SIGABRT, Aborted.
0x004012f2 in addStrings (str1=0xc0 <Address 0xc0 out of bounds>,
    str2=0xea60 <Address 0xea60 out of bounds>, del=0 '\000') at string.c:39
39      str1=(char*) realloc(str1,(len1+len2+1)*sizeof(char));

Not able to figure out why it is crashing? Is it because I am passing str1 as auto variable rather than creating it on heap?

If this is the case ? How do I modify my code to accept auto as well as heap variables?


Solution

  • You need to pass your target string pointer by address, and it must hold either the address of a previously allocate string, or NULL (if coded correctly). The size allocation must be both lengths + 2 (one for the deli separator, one for the terminator). The result can look something like this:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void addStrings(char** str1, const char* str2,char del)
    {
        size_t len1 = *str1 ? strlen(*str1) : 0;
        size_t len2 = str2 ? strlen(str2) : 0;
        char *res = realloc(*str1, len1 + len2 + 2);
        if (res)
        {
            res[len1] = del;
            memcpy(res + len1 + 1, str2, len2);
            res[len1 + 1 + len2] = 0;
            *str1 = res;
        }
    }
    
    int main()
    {
        char *p = NULL;
        const char test[] = "test";
        int i=0;
    
        // prove it works with no input whatsoever
        addStrings(&p, NULL, 'X');
        printf("p = %p, %s\n", p, p);
    
        // loop on some input for awhile
        for (;i<10;++i)
        {
            addStrings(&p, test, '@');
            printf("p = %p, %s\n", p, p);
        }
        free(p);
        return 0;
    }
    

    Output

    p = 0x128610, X
    p = 0x128610, X@test
    p = 0x128610, X@test@test
    p = 0x128620, X@test@test@test
    p = 0x128620, X@test@test@test@test
    p = 0x128620, X@test@test@test@test@test
    p = 0x128620, X@test@test@test@test@test@test
    p = 0x128640, X@test@test@test@test@test@test@test
    p = 0x128640, X@test@test@test@test@test@test@test@test
    p = 0x128640, X@test@test@test@test@test@test@test@test@test
    p = 0x128670, X@test@test@test@test@test@test@test@test@test@test
    

    Compiled with: Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn) Target: i386-apple-darwin13.2.0 Thread model: posix

    Note the change in resulting address on some of the passes. I leave the checking for valid parameter input as an exercise for you.