Deleting n characters from a given position in a string is a common string manipulation task used in text editors, parsers, and data cleaning. The approach: shift all characters after the deleted region one step to the left, overwriting the deleted characters, then terminate the string with a null byte.
The original post used gets() (removed in C11, unsafe buffer overflow) and a strcpy()-based approach. This rewrite uses a manual shift loop — no library functions beyond strlen() — and supports 1-based position input.
Algorithm
- Convert the 1-based
posto a 0-based index:start = pos - 1. - Clamp
nif deleting past the end:n = min(n, len - start). - Shift all characters at index
start+nand beyond one position to the left. - Add a null terminator at the new end.
C Program to Delete n Characters from a String
/* Delete n characters from a given position in a string
* position is 1-based (position 1 = first character)
* Compile: gcc -ansi -Wall -Wextra delchars.c -o delchars */
#include <stdio.h>
#include <string.h>
void delete_chars(char *str, int pos, int n)
{
int len = (int)strlen(str);
int start, i;
if (pos < 1 || pos > len || n < 1) return; /* nothing to delete */
start = pos - 1; /* convert 1-based pos to 0-based index */
if (start + n > len)
n = len - start; /* clamp: don't delete past end of string */
/* shift characters left: overwrite the deleted region */
for (i = start; str[i + n] != '\0'; i++)
str[i] = str[i + n];
str[i] = '\0'; /* terminate */
}
int main(void)
{
char s1[100] = "Hello, World!";
char s2[100] = "abcdefghij";
char s3[100] = "Programming";
printf("Original: \"%s\"\n", s1);
delete_chars(s1, 8, 5); /* delete "World" (pos 8, 5 chars) */
printf("After delete_chars(s, 8, 5): \"%s\"\n\n", s1);
printf("Original: \"%s\"\n", s2);
delete_chars(s2, 3, 4); /* delete "cdef" (pos 3, 4 chars) */
printf("After delete_chars(s, 3, 4): \"%s\"\n\n", s2);
printf("Original: \"%s\"\n", s3);
delete_chars(s3, 1, 3); /* delete "Pro" (pos 1, 3 chars) */
printf("After delete_chars(s, 1, 3): \"%s\"\n", s3);
return 0;
}
How to Compile and Run
gcc -ansi -Wall -Wextra delchars.c -o delchars
./delchars
Sample Output
Original: "Hello, World!" After delete_chars(s, 8, 5): "Hello, !" Original: "abcdefghij" After delete_chars(s, 3, 4): "abghij" Original: "Programming" After delete_chars(s, 1, 3): "gramming"
Step-by-Step Trace: “Hello, World!”, delete 5 at pos 8
Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 '\0'
Char: H e l l o , ! W o r l d ! [before: indices shifted]
Wait — let me verify:
"Hello, World!"
H=0 e=1 l=2 l=3 o=4 ,=5 =6 W=7 o=8 r=9 l=10 d=11 !=12
pos=8 → start = 7 (0-based) → char at index 7 is 'W'
Delete 5 from index 7: W=7, o=8, r=9, l=10, d=11
Shift index 12 ('!') → index 7, then '\0' → index 8
| Step | String state | What happened |
|---|---|---|
| Before | “Hello, World!” | len=13, start=7, n=5 |
| Shift ‘!’ | “Hello, !orld!” | str[7]=’!’ (was str[12]) |
| Terminate | “Hello, !” | str[8]=’\0′ |
Code Explanation
- 1-based position — text editors and most human descriptions count characters starting from 1. The function converts to 0-based index internally:
start = pos - 1. If the user says “position 8”, we delete from array index 7. - Clamping n — if pos=9 and n=10 in a 13-character string, we can only delete 4 characters (not 10). The clamp prevents the shift loop from reading uninitialized memory:
n = len - startlimits n to the remaining characters. - The shift loop:
str[i] = str[i + n]— each iteration moves a character n positions to the left, overwriting the deleted region. The loop runs whilestr[i+n] != '\0', which copies the null terminator exactly once at the end via thestr[i] = '\0'after the loop. - No memmove needed — since we are always moving data to lower indices (left shift), a simple left-to-right copy loop is safe.
memmove()would be needed if the source and destination regions could overlap in either direction. Here they do overlap (the destination starts inside the source range), but left-to-right iteration handles it correctly. - Modify in-place — the function takes
char *str(a pointer to a modifiable buffer), notconst char *. Passing a string literal likedelete_chars("hello", 1, 2)would invoke undefined behavior — string literals are read-only.
What This Program Teaches
- In-place string modification — shifting characters left is the fundamental technique behind text deletion in any language. The same shift pattern appears in array deletion, circular buffer management, and parser token consumption.
- Null terminator management — after the shift, the string must be manually terminated with
'\0'. Missing the terminator is a classic C string bug: subsequent operations would read garbage data past the intended end. - Input validation before array access — checking
pos < 1 || pos > lenbefore computingstartprevents out-of-bounds reads. The clampn = len - startprevents out-of-bounds shifts. Together they make the function safe for any integer inputs. - Why not strcpy here —
strcpy(str + start, str + start + n)would also work but relies on undefined behavior when source and destination overlap (which they do here — same buffer, overlapping regions).memmove()is the safe library call for overlapping copies; the manual loop is also correct for left shifts.
Related Programs
- Delete Vowels from String in C
- Replace Substring in C
- Find Position of Substring in C
- String Copy and Concatenation in C
- Sort a String in C
Recommended book:
The C Programming Language — Kernighan & Ritchie (India) |
(US)
|
C Programming: A Modern Approach — K.N. King (India) |
(US)
Practice what you learned: C Aptitude Questions — or try our C Programming Quiz App on Android.