Replace all occurrences of a substring in a string in C

Erik Blenert picture Erik Blenert · Sep 5, 2015 · Viewed 32.7k times · Source

I'm trying to make a function in C to replace all occurrences of a substring in a string. I made my function, but it only works on the first occurrence of the substring in the bigger string.

Here is the code so far:

void strreplace(char string[], char search[], char replace[]){
    char buffer[100];
    char*p = string;
    while((p=strstr(p, search))){
        strncpy(buffer, string, p-string);
        buffer[p-string] = '\0'; //EDIT: THIS WAS MISSING
        strcat(buffer, replace);
        strcat(buffer, p+strlen(search));
        strcpy(string, buffer);
        p++;
    }
} 

I'm not new to C programming, but I'm missing something here.

Example: for input string "marie has apples has", searching for "has" and replace with "blabla"

In the first "has" is replaced correctly, but the second one is not. The final output is "marie blabla apples hasblabla". Notice the second "has" is still there.

What am I doing wrong? :)

EDIT Is is working now. Adding the null terminating character fixed the problem. I know the resulting string can be bigger than 100. It's a school homework so I won't have strings longer than 20 or so.

Answer

It doesn't seem clear to me what algorithm you are trying to follow, it all looks fishy to me. What's probably the simplest approach is:

  • search for first occurrence of the "needle" (searched-for substring)
  • copy the part before the first occurrence to the result buffer
  • append the replacement string to the result buffer
  • increment the p pointer so it points just after the needle
  • GOTO 10
void str_replace(char *target, const char *needle, const char *replacement)
{
    char buffer[1024] = { 0 };
    char *insert_point = &buffer[0];
    const char *tmp = target;
    size_t needle_len = strlen(needle);
    size_t repl_len = strlen(replacement);

    while (1) {
        const char *p = strstr(tmp, needle);

        // walked past last occurrence of needle; copy remaining part
        if (p == NULL) {
            strcpy(insert_point, tmp);
            break;
        }

        // copy part before needle
        memcpy(insert_point, tmp, p - tmp);
        insert_point += p - tmp;

        // copy replacement string
        memcpy(insert_point, replacement, repl_len);
        insert_point += repl_len;

        // adjust pointers, move on
        tmp = p + needle_len;
    }

    // write altered string back to target
    strcpy(target, buffer);
}

Warning: You also have to be careful about how you call your function. If the replacement string is larger than the needle, your modified string will be longer than the original one, so you have to make sure your original buffer is long enough to contain the modified string. E.g.:

char s[1024] = "marie has apples has";                         
str_replace(s, "has", "blabla");