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");
Answer from The Paramagnetic Croissant on Stack Overflow
Top answer
1 of 5
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");
2 of 5
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.

Top answer
1 of 2
5

The interface

  1. There are a number of useful things to return. Let's list them in order of which is least surprising:

    • The pointer to the start of the destination. This follows the standard library, but is least useful.
    • The pointer to the end of the destination. This follows an alternative convention embodies in the stpcpy() function and similar added to POSIX in 2008.
    • Number of characters produced / to produce. Generally only used if the sink can accept any number of characters, or the destinations size is also passed. countOccurrences() seems your flawed attempt to begin implementing the alternative approach to sizing the buffer.
    • Return a count of replacements done. Degenerates to boolean if maximum number of replacements is 1.
    • Try to combine bool (not count) with one of the other options. strstr() does it, arguable returning a pointer to the terminator might have been better.

    None of those options reflects your choice.

  2. Provide some way to properly size the destination buffer. As a bonus, replaceNAndAllocate() becomes fairly trivial.

The algorithm

  1. replaceN()'s use of replace() results in a standard Shlemiel The Painter-algorithm. It should be linear, but ends up quadratic.

  2. countOccurrences() can fail if some proper suffix (neither empty nor the full string) is a prefix of the needle, specifically if the resultant string is found. Skip over the full match found, not the first character.

Implementation

  1. Yes, strncpy() (which is not actually a string-function) will behave identically to memcpy() if the first n - 1 bytes are non-null. It is still inefficient and false advertisement though.

  2. &pointer[offset_calculation] might not be longer than pointer + offset_calculation, but it is a bit less idiomatic. You decide whether it should be changed.

  3. replaceN() should be the one to implement directly, replace() being a convenience-function. The overhead is trivial for the latter, and fixes the current problem with its runtime.

  4. Most of the time, you use pointer directly, but sometimes you use pointer != NULL. Fix the inconsistency, preferably in favor of the former, which is more idiomatic and shorter.

  5. countOccurrences() and allocateBuffer() seem to be internal helpers. Mark them static so they are not exported.

  6. Your test-program fails to free the buffer replaceAllAndAllocate() allocates.

2 of 2
2

First impression is pretty good - care taken with exception conditions and thought to the interface.

Headers: I find it helpful to have a consistent order for headers, to quickly see if the header I need is already included. For this, I group the Standard Library headers in alphabetical order. You might find that helpful too.

char *ptr = strstr(src, orig); // First match

I'd write const *ptr there, to avoid accidents.

strncpy(dest, src, offset); // Copy everything before match

Probably memcpy is more appropriate here, given we know that src doesn't end before src + offset.

strcpy(&dest[offset], new); // Copy replacement
strcpy(&dest[offset + strlen(new)], &src[offset + origlen]); // Copy rest

It's strange to index an array, only to extract a pointer. I'd write those as:

strcpy(dest + offset, new); // Copy replacement
strcpy(dest + offset + strlen(new), src + offset + origlen); // Copy rest

Arguably, we could measure strlen(new) first, then use memcpy for the first of those.

If countOccurrences() and allocateBuffer() aren't intended to be part of the public interface, declare them with internal linkage (static).

The test program is an optimist. If you've taken the care to safely return a null pointer from the function, the caller ought to have the decency to set a good example by testing the value rather than blindly passing it on!

🌐
YouTube
youtube.com › watch
Replace All Occurrences Of A Substring In A String With Another Substring | C Programming Example - YouTube
How to replace all occurrences of a substring in a string with another substring in C, for example to replace a word with another word, or to replace a phras...
Published   January 6, 2022
🌐
YouTube
youtube.com › watch
Replaces all occurrences of a substring in a string in C/C++ - YouTube
Build a replace_all() function that replace all occurrences of the substring in a string
Published   August 14, 2017
🌐
Creativeandcritical
creativeandcritical.net › str-replace-c
Portable C string and wide string replacement functions: repl_str and repl_wcs
The purpose of this function is to replace in the input string all occurrences of a source/search ("from") substring with a target/replace ("to") substring, and to then return a post-replacement string, doing all this as efficiently as is possible without specific knowledge of the nature of ...
🌐
GeeksforGeeks
geeksforgeeks.org › dsa › find-and-replace-all-occurrence-of-a-substring-in-the-given-string
Replace a Word - GeeksforGeeks
June 29, 2026 - Return the modified string. ... Input: s = "xxforxx xx for xx", s1 = "xx", s2 = "Geeks" Output: "GeeksforGeeks Geeks for Geeks" Explanation: Every occurrence of "xx" is replaced with "Geeks". Input: s = "India is the xx country", s1 = "xx", s2 = "best" Output: "India is the best country" Explanation: The occurrence of "xx" is replaced with "best". ... The idea is to traverse s and check at every index whether substring s1 starts from there.
🌐
Stack Overflow
stackoverflow.com › questions › 39401070 › find-and-replace-all-occurrences-of-a-substring-in-c
string - Find and replace all occurrences of a substring in C - Stack Overflow
If have a lot of printf in there just so I can see where everything is for debugging. ... If I am running it against the string what4is4this with searchStr = 4 and replaceStr = !!! this is the output in the console...
🌐
TutorialsPoint
tutorialspoint.com › article › c-program-to-replace-all-occurrence-of-a-character-in-a-string
C program to replace all occurrence of a character in a string
for(i = 0; string[i] != '\0'; i++) { if(string[i] == old_char) { string[i] = new_char; } } This method replaces every occurrence of a character in the string −
Top answer
1 of 16
118

The optimizer should eliminate most of the local variables. The tmp pointer is there to make sure strcpy doesn't have to walk the string to find the null. tmp points to the end of result after each call. (See Shlemiel the painter's algorithm for why strcpy can be annoying.)

// You must free the result if result is non-NULL.
char *str_replace(char *orig, char *rep, char *with) {
    char *result; // the return string
    char *ins;    // the next insert point
    char *tmp;    // varies
    int len_rep;  // length of rep (the string to remove)
    int len_with; // length of with (the string to replace rep with)
    int len_front; // distance between rep and end of last rep
    int count;    // number of replacements

    // sanity checks and initialization
    if (!orig || !rep)
        return NULL;
    len_rep = strlen(rep);
    if (len_rep == 0)
        return NULL; // empty rep causes infinite loop during count
    if (!with)
        with = "";
    len_with = strlen(with);

    // count the number of replacements needed
    ins = orig;
    for (count = 0; (tmp = strstr(ins, rep)); ++count) {
        ins = tmp + len_rep;
    }

    tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);

    if (!result)
        return NULL;

    // first time through the loop, all the variable are set correctly
    // from here on,
    //    tmp points to the end of the result string
    //    ins points to the next occurrence of rep in orig
    //    orig points to the remainder of orig after "end of rep"
    while (count--) {
        ins = strstr(orig, rep);
        len_front = ins - orig;
        tmp = strncpy(tmp, orig, len_front) + len_front;
        tmp = strcpy(tmp, with) + len_with;
        orig += len_front + len_rep; // move to next "end of rep"
    }
    strcpy(tmp, orig);
    return result;
}
2 of 16
21

This is not provided in the standard C library because, given only a char* you can't increase the memory allocated to the string if the replacement string is longer than the string being replaced.

You can do this using std::string more easily, but even there, no single function will do it for you.

Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › dsa › replace-occurrences-string-ab-c-without-using-extra-space
Replace all occurrences of string AB with C without using extra space - GeeksforGeeks
April 30, 2024 - <script> // Efficient javascript program to replace // all occurrences of "AB" with "C" function translate(str) { var len = str.length; if (len < 2) return; // Index in modified string var i = 0; // Index in original string var j = 0; // Traverse string while (j < len - 1) { // Replace occurrence of "AB" with "C" if (str[j] == 'A' && str[j + 1] == 'B') { // Increment j by 2 j = j + 2; let firstPart = str.substr(0, i); let lastPart = str.substr(i + 1); str = firstPart + 'C' + lastPart; i += 1; continue; } let firstPart = str.substr(0, i); let lastPart = str.substr(i + 1); str = firstPart + str[
🌐
Tutorial Gateway
tutorialgateway.org › c-program-to-replace-all-occurrence-of-a-character-in-a-string
C Program to Replace All Occurrence of a Character in a String
January 26, 2025 - Please Enter any String : tutorial gateway Please Enter the Character that you want to Search for : t Please Enter the New Character : $ The Final String after Replacing All Occurrences of 't' with '$' = $u$orial ga$eway
🌐
Codeforwin
codeforwin.org › home › c program to replace all occurrences of a character in a string
C program to replace all occurrences of a character in a string - Codeforwin
July 20, 2025 - Input string: I_love_learning_at_Codeforwin. Input character to replace: _ Input character to replace with: - ... Below is the step by step descriptive logic to replace all occurrence of a character in a given string.
🌐
Quora
quora.com › How-do-I-replace-all-occurrences-of-a-string-in-C
How to replace all occurrences of a string in C++ - Quora
Quora is a place to gain and share knowledge. It's a platform to ask questions and connect with people who contribute unique insights and quality answers.
🌐
Stack Overflow
stackoverflow.com › questions › 68236790 › how-to-find-and-replace-multiple-or-all-occurences-in-c-strings
How to find and replace multiple or all occurences in C strings - Stack Overflow
July 3, 2021 - This uses fixed size buffers, you must make sure they are big enough to hold the string after replacement is done. ... This code was tested with MSVC 2019. void replaceN(char* line,const char* orig,const char* new, int times){ char* buf; if(times==0) return; //sem tempo irmao if((times==-1||--times>0) && (buf = strstr(line,orig))!=NULL){ //find orig for(const char *c=orig;*c;c++) buf++; //advance buf replaceN(buf,orig,new,times); //repeat until the last occurrence } //this will run first for the last match if((buf = strstr(line,orig))!=NULL){ char tmp[LINE_LEN]; int i = buf-line; //pointer dif
🌐
Stack Overflow
stackoverflow.com › questions › 22433706 › c-function-to-replace-in-a-string-all-occurrences-of-a-given-substring
C++ function to replace in a string all occurrences of a given substring - Stack Overflow
I want a function that takes a string and replaces all occurrences of a given word with asterisks in place of its letters. I want to do this elegantly, like a real C++ programmer. As an example, ...
🌐
YouTube
youtube.com › shorts › Inltl8m7HV0
How to replace all occurrences of a character in string c++ - YouTube
AboutPressCopyrightContact usCreatorsAdvertiseDevelopersTermsPrivacyPolicy & SafetyHow YouTube worksTest new features · © 2026 Google LLC
Published   December 6, 2022
🌐
PREP INSTA
prepinsta.com › home › c program › c program to replace a substring in a string
Replace a Substring in a String C program | PrepInsta
March 20, 2025 - #include<stdio.h> #include<string.h> int main() { char str[256] = "prepinsta", substr[128] = "insta", replace[128] = "ster ", output[256]; int i = 0, j = 0, flag = 0, start = 0; str[strlen(str) - 1] = '\0'; substr[strlen(substr) - 1] = '\0'; replace[strlen(replace) - 1] = '\0'; // check whether the substring to be replaced is present while (str[i] != '\0') { if (str[i] == substr[j]) { if (!flag) start = i; j++; if (substr[j] == '\0') break; flag = 1; } else { flag = start = j = 0; } i++; } if (substr[j] == '\0' && flag) { for (i = 0; i < start; i++) output[i] = str[i]; // replace substring wit
Top answer
1 of 1
1

If there's a chance of the data changing, you'll probably want to use some kind of map (e.g. a hashtable or a trie). Covering the theory of these seems unnecessary here, especially given that this option wasn't mentioned in the question... I just thought I'd mention some food for thought.

Otherwise, there's no chance of the data changing and I would highly recommend using a sorted lookup table, which is an optimised version of your first option so you can use binary searches instead of searching from the start of your array to the end. For example:

struct replacement {
    char original[4];
    char replacement[4];
};

int compare_replacement(void const *x, void const *y) {
    struct replacement const *fu = x, *ba = y;
    return memcmp(x->original, y->original, 4);
}

int main(void) {
    struct replacement table[] = {
        { .original = " </3" , .replacement = "\xf0\x9f\x92\x94" },
        { .original = " <3 " , .replacement = "\xf0\x9f\x92\x97" },
        { .original = " 8-D" , .replacement = "\xf0\x9f\x98\x81" },
        { .original = " 8D " , .replacement = "\xf0\x9f\x98\x81" },
        { .original = " x-D" , .replacement = "\xf0\x9f\x98\x81" },
        { .original = " xD " , .replacement = "\xf0\x9f\x98\x81" },
        { .original = " :')" , .replacement = "\xf0\x9f\x98\x82" },
        { .original = ":'-)" , .replacement = "\xf0\x9f\x98\x82" },
        { .original = ":-))" , .replacement = "\xf0\x9f\x98\x83" },
        { .original = " 8) " , .replacement = "\xf0\x9f\x98\x84" },
        { .original = " :) " , .replacement = "\xf0\x9f\x98\x84" },
        { .original = " :-)" , .replacement = "\xf0\x9f\x98\x84" },
        { .original = " =) " , .replacement = "\xf0\x9f\x98\x84" },
        { .original = " =] " , .replacement = "\xf0\x9f\x98\x84" },
        { .original = " 0:)" , .replacement = "\xf0\x9f\x98\x87" },
        { .original = "0:-)" , .replacement = "\xf0\x9f\x98\x87" }
    };

    qsort(table, sizeof table / sizeof *table, sizeof *table, compare_replacement);
}

Then you should be able to iterate from the start of the string to the end of the string, using bsearch to test each successive four bytes, like this for example:

void replace_emotes(char *str, struct replacement *rep, size_t rep_size) {
    while (*str) {
        struct replacement query = { 0 };
        strncpy(query.original, rep, sizeof query.original);

        struct replacement *response = bsearch(&query, rep, rep_size, sizeof *rep, compare_replacement);
        if (response) {
            strncpy(str, response->replacement, sizeof response->replacement);
        }
    }
}

If you intend to support insertions, you need to work with realloc for a start... and either figure out where to insert to keep the array sorted before the insertion, or resort the array after each insertion. Either of these will work fine for modifications (insertions and removals) to small sets, but if you intend to support larger sets you'll probably want to use something like a trie or hashtable.