C Basics: Move Overlapping Text Within One Buffer
Inserting or removing text shifts bytes through overlapping parts of the same array. Use memmove for those shifts and reserve memcpy for disjoint storage.
Prepare a scratch directory
Tested on Linux x86-64 with GCC 14.2.0. You need GCC, the C development headers, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. This example uses the C standard library and no external package.
Keep the same terminal open. Stop if setup fails, before saving the source:
start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1Run the example
Save this as memmove-overlap-demo.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char text[16] = "draft";
const char prefix[] = "OK: ";
size_t text_length = strlen(text);
size_t prefix_length = strlen(prefix);
if (prefix_length > sizeof text - 1 - text_length) {
fputs("Insufficient capacity\n", stderr);
return EXIT_FAILURE;
}
memmove(text + prefix_length, text, text_length + 1);
memcpy(text, prefix, prefix_length);
printf("Inserted: %s\n", text);
memmove(text, text + prefix_length, strlen(text + prefix_length) + 1);
printf("Removed: %s\n", text);
return EXIT_SUCCESS;
}Compile and run it. The && prevents running an old executable if compilation fails:
gcc -std=c17 -Wall -Wextra -Werror -pedantic memmove-overlap-demo.c -o memmove-overlap-demo &&
./memmove-overlap-demoObserved output:
Inserted: OK: draft
Removed: draftRead the result
The first move shifts draft and its terminating null byte to the right. The separate prefix array does not overlap the destination, so memcpy can fill the gap. Removing the prefix shifts the remaining string and terminator back to the start.
Apply it carefully
Both ranges must be valid for the requested byte count; memmove does not check capacity. The subtraction check is safe because text is already a terminated string inside the fixed array. This edits bytes, not Unicode grapheme boundaries. Do not demonstrate the overlapping operation with memcpy: its behavior would be undefined, even if a particular run appeared to work.
The library reference describes the relevant behavior.
Clean up
Remove only the source and executable created here, then remove the empty scratch directory:
rm -- memmove-overlap-demo.c memmove-overlap-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directoryIf the directory is not empty, inspect what remains before removing anything else.
Acknowledgements
This post was created with assistance from AI.