7

I want to remove a particular substring from a string for example my main string is "ababccdabce" and I want to remove "abc" from it so it will become "abcde".

I just wanted to know if there is a predefined function in C to do that, and if not, how to do it?

Mohit Singh
  • 125
  • 1
  • 1
  • 7

1 Answers1

11

There is no predefined function in C to remove a given substring from a C string, but you can write one using strstr and memmove. Note that if you remove the substring in place, you cannot use memcpy nor strcpy because these have undefined behavior if the source and destination arrays overlap.

Here is the code:

#include <string.h>

char *strremove(char *str, const char *sub) {
    size_t len = strlen(sub);
    if (len > 0) {
        char *p = str;
        while ((p = strstr(p, sub)) != NULL) {
            memmove(p, p + len, strlen(p + len) + 1);
        }
    }
    return str;
}

Note that the resulting string may contain the substring as is the case in your example.

Netherwire suggested an optimisation:

char *strremove(char *str, const char *sub) {
    size_t len = strlen(sub);
    if (len > 0) {
        char *p = str;
        size_t size = 0;
        while ((p = strstr(p, sub)) != NULL) {
            size = (size == 0) ? (p - str) + strlen(p + len) + 1 : size - len;
            memmove(p, p + len, size - (p - str));
        }
    }
    return str;
}

Further honing the code, I came up with an even more efficient version using the 2 finger-method: only copying the fragments between matches starting after the first match:

char *strremove(char *str, const char *sub) {
    char *p, *q, *r;
    if (*sub && (q = r = strstr(str, sub)) != NULL) {
        size_t len = strlen(sub);
        while ((r = strstr(p = r + len, sub)) != NULL) {
            memmove(q, p, r - p);
            q += r - p;
        }
        memmove(q, p, strlen(p) + 1);
    }
    return str;
}

Here is the same method without any calls to memmove:

char *strremove(char *str, const char *sub) {
    char *p, *q, *r;
    if (*sub && (q = r = strstr(str, sub)) != NULL) {
        size_t len = strlen(sub);
        while ((r = strstr(p = r + len, sub)) != NULL) {
            while (p < r)
                *q++ = *p++;
        }
        while ((*q++ = *p++) != '\0')
            continue;
    }
    return str;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 1
    You may decrease the number of `strlen` calls by caching `str` length, decreasing it each time the `sub` has been removed – Netherwire May 05 '19 at 09:42
  • @Netherwire: Good point, but it makes the code more cumbersome, especially if one wants to avoid computing `strlen(str)` if there is no match. Thanks for teasing me... I found an even better solution :) – chqrlie May 05 '19 at 10:11
  • `Signal: SIGSEGV (Segmentation fault)` :) – r1v3n Jul 13 '21 at 14:55
  • @r1v3n: I fixed the special case where `sub` is an empty string. There might be other bugs, can you be more specific and tell me what arguments are causing the segfault? – chqrlie Jul 13 '21 at 20:45