10

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.

pevik
  • 4,523
  • 3
  • 33
  • 44
Erik Blenert
  • 103
  • 1
  • 1
  • 6
  • 2
    @GerardvanHelden Probably because they are not in the C standard library? (Are you thinking PHP?) – user12205 Sep 05 '15 at 13:40
  • How did you saw the result? with a debugger? – yeyo Sep 05 '15 at 13:44
  • @ace fair point, comment deleted. Thought the PHP functions internally mapped to C stdlib (which they do a lot of the time) but not this case. – Gerard van Helden Sep 05 '15 at 13:45
  • This function is a little risky in that you don't know for sure whether the input string can hold 100 bytes. But that aside, your `while` loop only increments `p` by 1 each time through the loop. I would assume it needs to bump by the length of the replacement string. – lurker Sep 05 '15 at 13:48
  • 1
    Also, what are `strcat(buffer, p+strlen(search));` and `strcpy(string, buffer);` are for? You don't really need the first line, and you can move the second one out of the loop… – The Paramagnetic Croissant Sep 05 '15 at 13:51

5 Answers5

19

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");
  • The algorithm you described in words is what i was trying to achieve. I know I can make it better, but it's just a school assignment. Thanks for the input :) – Erik Blenert Sep 05 '15 at 14:15
4

For starters:

This line

strncpy(buffer, string, p-string);

not necessarily appends a 0-terminator to what had been copied to buffer.

The following line

strcat(buffer, replace);

however relies on buffer being 0-terminated.

As buffer had not been initialised and though the 0-terminator most likely misses the latter line may very well read beyond buffer's memory and with this invoke the infamous Undefined Behaviour.

alk
  • 69,737
  • 10
  • 105
  • 255
4
char *replace_str(char *str, char *orig, char *rep)
{
static char buffer[4096];
char *p;
int i=0;

while(str[i]){
    if (!(p=strstr(str+i,orig)))  return str;
    strncpy(buffer+strlen(buffer),str+i,(p-str)-i);
    buffer[p-str] = '\0';
    strcat(buffer,rep);
    printf("STR:%s\n",buffer);
    i=(p-str)+strlen(orig);
}

return buffer;
}

int main(void)
{
  char str[100],str1[50],str2[50];
  printf("Enter a one line string..\n");
  gets(str);
  printf("Enter the sub string to be replaced..\n");
  gets(str1);
  printf("Enter the replacing string....\n");
  gets(str2);
  puts(replace_str(str, str1, str2));

  return 0;
}

Input: marie has apples has

Output: marie blabla apples blabla

StackUser
  • 255
  • 2
  • 8
  • This is succinct but did not work for an input string of "123 4" and wanting to replace the blank with a comma. This works, but may not be the best and did not thoroughly test: if (!(p=strstr(str+i,orig))) { strcat(buffer, (str+i)); return buffer; } – cniggeler Jun 13 '23 at 15:41
0
int replace_str(char* i_str, char* i_orig, char* i_rep)
{
   char l_before[2024];
   char l_after[2024];
   char* l_p;
   int l_origLen;

   l_origLen = strlen(i_orig);
   while (l_p = strstr(i_str, i_orig)) {
      sprintf(l_before ,"%.*s" ,l_p - i_str ,i_str);
      sprintf(l_after ,"%s" ,l_p + l_origLen);
      sprintf(i_str ,"%s%s%s" ,l_before ,i_rep ,l_after);
   }
   return(strlen(i_str));
}
-1

i find some needful corrections to be made in function.. here is new function

char *replace_str(char *str, char *orig, char *rep)
{
    static char buffer[1024];
    char *p;
    int i = 0;

    if (!(p = strstr(str + i, orig)))
    {
        return str;
    }

    while (str[i])
    {
        if (!(p = strstr(str + i, orig)))
        {
            strcat(buffer, str + i);
            break; //return str;
        }
        strncpy(buffer + strlen(buffer), str + i, (p - str) - i);
        buffer[p - str] = '\0';
        strcat(buffer, rep);
        //printf("STR:%s\n", buffer);
        i = (p - str) + strlen(orig);
    }

    return buffer;
}
  • 2
    please don't just give a block of code, but explain the changes and why they matter. Also; does this solve the problem? – Chris Maes Feb 07 '17 at 11:43