The memcpy function is used to copy a block of data from a source address to a destination address. It assumes the memory regions do not overlap.
void * memcpy(void * destination, const void * source, size_t num);
The idea is to simply typecast given addresses to char *(char takes 1 byte). Then one by one copy data from source to destination.
#include<iostream>
void* myMemCpy(void* dest, const void* src, size_t n) {
char* d = (char*)dest;
const char* s = (const char*)src;
for (size_t i = 0; i < n; i++) {
d[i] = s[i]; // Simple forward copy
}
return dest;
}
// Driver program
int main() {
char csrc[] = "GeeksforGeeks";
char cdest[100];
myMemCpy(cdest, csrc, strlen(csrc)+1);
printf("Copied string is %s", cdest);
int isrc[] = {10, 20, 30, 40, 50};
int n = sizeof(isrc)/sizeof(isrc[0]);
int idest[n], i;
myMemCpy(idest, isrc, sizeof(isrc));
printf("\nCopied array is ");
for (i=0; i<n; i++)
printf("%d ", idest[i]);
return 0;
}
Output
Copied string is GeeksforGeeks Copied array is 10 20 30 40 50
What is memmove()
memmove() is similar to memcpy() as it also copies data from a source to destination. memcpy() leads to problems when source and destination addresses overlap as memcpy() simply copies data one by one from one location to another.
Example of Failure:
- Source: "Geeksfor"
- Action: memcpy(src + 5, src, 8)
- Result: "GeeksGeeksGeek" (Data loss due to overwriting)
// Sample program to show that memcpy() can lose data.
#include <stdio.h>
#include <string.h>
int main()
{
char csrc[100] = "Geeksfor";
memcpy(csrc+5, csrc, strlen(csrc)+1);
printf("%s", csrc);
return 0;
}
Output:
GeeksGeeksGeek
Since the input addresses are overlapping, the above program overwrites the original string and causes data loss.
// Sample program to show that memmove() is better than memcpy()
// when addresses overlap.
#include <stdio.h>
#include <string.h>
int main()
{
char csrc[100] = "Geeksfor";
memmove(csrc+5, csrc, strlen(csrc)+1);
printf("%s", csrc);
return 0;
}
Output:
GeeksGeeksfor
Implementing memmove()
While a common trick is to use a temp array instead of directly copying from src to dest to handle overlapping addresses, this is inefficient. A professional implementation avoids double copies by picking the direction of the copy based on the relative positions of src and dest.
- Forward Copy: If the destination is before the source, start from the beginning.
- Backward Copy: If the destination is after the source, start from the end to avoid overwriting the source data.
#include<iostream>
void* myMemMove(void* dest, const void* src, size_t n) {
char* d = (char*)dest;
const char* s = (const char*)src;
if (d == s || n == 0) return dest;
if (d < s) {
// Safe to copy forward
for (size_t i = 0; i < n; i++) {
d[i] = s[i];
}
} else {
// Copy backward to prevent overwriting source
for (size_t i = n; i > 0; i--) {
d[i - 1] = s[i - 1];
}
}
return dest;
}
int main() {
char csrc[100] = "Geeksfor";
myMemMove(csrc+5, csrc, strlen(csrc)+1);
printf("%s", csrc);
return 0;
}
Output
GeeksGeeksfor
Note: Further speed can be achieved by copying by word size (e.g., 4 or 8 bytes at a time) or using vector instructions for contiguous memory blocks.