Replace a Substring in C – Safe Replace-All Implementation

Replacing a substring means finding every occurrence of one piece of text inside a string and swapping it for another — for example, turning “the cat sat on the mat” into “the cog sog on the mog” by replacing “at” with “og”. C has no built-in function for this (unlike Python’s str.replace()), so it’s a common exercise for practicing manual string manipulation with pointers and indices.

This page builds a complete, safe replace-all implementation in C, walks through how it works, and covers the buffer-overflow trap that naive versions of this program fall into.

How It Works — Step by Step

  1. Scan the main string one position at a time.
  2. At each position, check whether the substring to replace starts there (using strncmp).
  3. If it matches, copy the replacement text into the result and skip past the matched substring.
  4. If it doesn’t match, copy just the current character into the result and move one position forward.
  5. Repeat until the entire input string has been scanned, then terminate the result with '\0'.

Step-by-step trace

Replacing "an" with "XY" in "banana bread":

b            -> no match at index 0, copy 'b'
an           -> match at index 1, write "XY", skip 2
an           -> match at index 3, write "XY", skip 2
a            -> no match, copy 'a'
" bread"     -> no more matches, copy the rest as-is

Result: bXYXYa bread

C Program to Replace All Occurrences of a Substring

/* Replace All Occurrences of a Substring in C
 * Compile: gcc -ansi -Wall -Wextra replacesub.c -o replacesub */
#include <stdio.h>
#include <string.h>

#define MAXLEN 500

void replace_all(const char *str, const char *old_sub, const char *new_sub, char *result)
{
    int str_len = (int)strlen(str);
    int old_len = (int)strlen(old_sub);
    int new_len = (int)strlen(new_sub);
    int i = 0, j = 0, k;

    if (old_len == 0) {
        strcpy(result, str);
        return;
    }

    while (i < str_len && j < MAXLEN - 1) {
        if (i <= str_len - old_len && strncmp(&str[i], old_sub, old_len) == 0) {
            for (k = 0; k < new_len && j < MAXLEN - 1; k++)
                result[j++] = new_sub[k];
            i += old_len;
        } else {
            result[j++] = str[i++];
        }
    }
    result[j] = '\0';
}

int main(void)
{
    char str[MAXLEN], old_sub[100], new_sub[100], result[MAXLEN];

    printf("Enter the main string: ");
    fgets(str, sizeof(str), stdin);
    str[strcspn(str, "\n")] = '\0';

    printf("Enter substring to replace: ");
    fgets(old_sub, sizeof(old_sub), stdin);
    old_sub[strcspn(old_sub, "\n")] = '\0';

    printf("Enter replacement string: ");
    fgets(new_sub, sizeof(new_sub), stdin);
    new_sub[strcspn(new_sub, "\n")] = '\0';

    replace_all(str, old_sub, new_sub, result);

    printf("Result: %s\n", result);

    return 0;
}

How to Compile and Run

gcc -ansi -Wall -Wextra replacesub.c -o replacesub
./replacesub

Sample Input and Output — Test 1

Enter the main string: the cat sat on the mat
Enter substring to replace: at
Enter replacement string: ATX
Result: the cATX sATX on the mATX

Sample Input and Output — Test 2

Enter the main string: banana bread
Enter substring to replace: an
Enter replacement string: XY
Result: bXYXYa bread

Code Explanation

  • The overflow guard: j < MAXLEN - 1 — if the replacement text is longer than the text it replaces, and there are many matches, the result can grow larger than the input. Checking j against MAXLEN - 1 on every write (in both the outer loop and the copy loop) stops the function from writing past the end of the buffer, at the cost of silently truncating extremely long results.
  • i <= str_len - old_len guard before strncmp — without this, near the end of the string, strncmp could read past the null terminator while checking for a match that can’t possibly fit.
  • Empty old_sub edge case — replacing every occurrence of an empty string is undefined behavior in most implementations, so this program explicitly checks for it and just copies the string unchanged.
  • Why not modify the string in place — when the replacement text is a different length than the original, shifting the remaining characters correctly in place is error-prone; building a separate result buffer is simpler and safer.

Time and Space Complexity

Case Time Space
Matching O(n × m) worst case O(n) for the result buffer

n = length of the main string, m = length of the substring being replaced. In practice, matches are rare, so the actual comparisons done are close to O(n).

What This Program Teaches

  • Building a result in a separate buffer — the standard, safe pattern whenever the output size differs from the input size.
  • Defensive buffer bounds-checking — writing loop conditions that can never overflow the destination array, regardless of the input.
  • strncmp for substring matching — comparing only a fixed number of characters instead of the whole string.

Related Programs

Recommended Books

Practice C string handling with the C Programming Quiz App — 500+ MCQs covering strings, pointers, sorting, and more.
Download on Google Play →

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>