I wrote this code as an answer to a question. But I'd like you to have a look at it. This post is basically a copy of [the answer](https://stackoverflow.com/a/68237099/6699433) I posted The code does no error checking. It assumes that the output buffer exists and is big enough and that src, orig and new are valid strings. The headers needed: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stddef.h> #include <stdint.h> The main replace function // Replace the first occurrence of orig in src with new and write result to dest // Return pointer to first character after the end of first match in src and // NULL if no match const char *replace(char *dest, const char *src, const char *orig, const char *new) { char *ptr = strstr(src, orig); // First match // If no match, we want dest to contain a copy of src if(!ptr) { strcpy(dest, src); return NULL; } const ptrdiff_t offset = ptr - src; // Calculate offset const int origlen = strlen(orig); strncpy(dest, src, offset); // Copy everything before match strcpy(&dest[offset], new); // Copy replacement strcpy(&dest[offset + strlen(new)], &src[offset + origlen]); // Copy rest return src + offset + origlen; } Then we just add a function to handle N occurrences // Replace maximum n occurrences. Stops when no more matches. // Returns number of replacements size_t replaceN(char *dest, const char *src, const char *orig, const char *new, size_t n) { size_t ret = 0; // Maybe an unnecessary optimization to avoid multiple calls in // loop, but it also adds clarity const int newlen = strlen(new); const int origlen = strlen(orig); do { const char *ptr = replace(dest, src, orig, new); // Replace if(!ptr) return ret; // Quit if no more matches // Length of the part of src before first match const ptrdiff_t offset = ptr - src; src = ptr; // Move src past what we have already copied. ret++; dest += offset - origlen + newlen; // Advance pointer to dest to the end } while(n > ret); return ret; } And a simple wrapper for all occurrences. Note that it's safe to use `SIZE_MAX` here, because there will never be more occurrences than that. // Replace all. Returns the number of replacements, because why not? size_t replaceAll(char *dest, const char *src, const char *orig, const char *new) { return replaceN(dest, src, orig, new, SIZE_MAX); } It's easy to write a wrapper for the allocation. We borrow some code from https://stackoverflow.com/q/9052490/6699433 size_t countOccurrences(const char *str, const char *substr) { size_t count = 0; while((str = strstr(str, substr)) != NULL) { count++; str++; // We're standing at the match, so we need to advance } return count; } Then some code to calculate size and allocate a buffer // Allocate a buffer big enough to hold src with n replacements // of orig to new char *allocateBuffer(const char *src, const char *orig, const char *new, size_t n) { return malloc(strlen(src) + n * (strlen(new) - strlen(orig)) + 1 // Remember the zero terminator ); } And the two final functions // Allocates a buffer and replaces max n occurrences of orig with new and // writes it to the allocated buffer. // Returns the buffer and NULL if allocation failed char *replaceNAndAllocate(const char *src, const char *orig, const char *new, size_t n) { const size_t count = countOccurrences(src, orig); n = n < count ? n : count; // Min of n and count char *buf = allocateBuffer(src, orig, new, n); if(!buf) return NULL; replaceN(buf, src, orig, new, n); return buf; } // Allocates a buffer and replaces all occurrences of orig with new and // writes it to the allocated buffer. // Returns the buffer and NULL if allocation failed char *replaceAllAndAllocate(const char *src, const char *orig, const char *new) { return replaceNAndAllocate(src, orig, new, SIZE_MAX); } And finally, a simple `main` with a test with multiple occurrences and with original string being a substring of replacement string: int main(void) { char src[] = "!!!asdf!!!asdf!!!asdf!!!asdf!!!"; char orig[] = "asdf"; char new[] = "asdfaaaaaaaaasdf"; puts(replaceAllAndAllocate(src, orig, new)); } No warnings with `-Wall -Wextra -pedantic` and the output is: $ ./a.out !!!asdfaaaaaaaaasdf!!!asdfaaaaaaaaasdf!!!asdfaaaaaaaaasdf!!!asdfaaaaaaaaasdf!!!