Memory Functions (memcpy/memset)
The <string.h> header (despite its name) also declares a set of low-level functions that operate on raw bytes of memory rather than null-terminated strings. These "mem" functions — memcpy, memmove, memset, and memcmp — are the workhorses behind copying structs, zeroing buffers, and comparing binary data efficiently.
memcpy: Fast, Non-Overlapping Copy
memcpy(dest, src, n) copies exactly n bytes from src to dest. It's typically the fastest way to duplicate a block of memory because it can copy in large chunks without worrying about byte order or string terminators.
#include <stdio.h>
#include <string.h>
int main(void) {
int source[5] = { 1, 2, 3, 4, 5 };
int destination[5];
memcpy(destination, source, sizeof(source));
for (int i = 0; i < 5; i++) {
printf("%d ", destination[i]);
}
printf("\n");
return 0;
}memmove: The Overlap-Safe Alternative
memmove(dest, src, n) has the exact same signature as memcpy, but it guarantees correct behavior even when the source and destination overlap — typically by copying through a temporary buffer or by detecting the overlap direction and copying in the safe order.
#include <stdio.h>
#include <string.h>
int main(void) {
int arr[6] = { 1, 2, 3, 4, 5, 6 };
/* Shift elements [1..5] one position to the left, into an
overlapping region -- this requires memmove, not memcpy. */
memmove(&arr[0], &arr[1], 5 * sizeof(int));
arr[5] = 0; /* the vacated last slot */
for (int i = 0; i < 6; i++) {
printf("%d ", arr[i]);
}
printf("\n"); /* prints: 2 3 4 5 6 0 */
return 0;
}memset: Filling Memory with a Value
memset(ptr, value, n) sets each of the first n bytes at ptr to value (interpreted as an unsigned char). It's most commonly used to zero out a buffer or struct before use, ensuring there is no leftover garbage from previously-used memory.
#include <stdio.h>
#include <string.h>
typedef struct {
char name[32];
int age;
} Person;
int main(void) {
Person p;
memset(&p, 0, sizeof(p)); /* zero out the whole struct */
printf("Name is empty: \"%s\"\n", p.name);
printf("Age defaults to: %d\n", p.age);
return 0;
}memcmp: Comparing Raw Bytes
memcmp(a, b, n) compares the first n bytes of two memory regions and returns zero if they are identical, or a nonzero value (negative or positive) indicating which region has the smaller byte at the first point of difference — similar in spirit to strcmp, but for arbitrary binary data rather than C strings.
#include <stdio.h>
#include <string.h>
int main(void) {
int a[3] = { 1, 2, 3 };
int b[3] = { 1, 2, 3 };
int c[3] = { 1, 2, 4 };
printf("a vs b: %d\n", memcmp(a, b, sizeof(a))); /* 0 -- identical */
printf("a vs c: %s\n", memcmp(a, c, sizeof(a)) == 0 ? "equal" : "different");
return 0;
}Worked Example: Combining memset and memcpy on a Struct
#include <stdio.h>
#include <string.h>
typedef struct {
char label[16];
int values[4];
} Record;
int main(void) {
Record original;
memset(&original, 0, sizeof(original)); /* start from a clean slate */
strcpy(original.label, "sample");
original.values[0] = 10;
original.values[1] = 20;
original.values[2] = 30;
original.values[3] = 40;
Record backup;
memcpy(&backup, &original, sizeof(Record)); /* deep-ish copy: whole struct, byte for byte */
/* Mutate the original; the backup remains untouched. */
original.values[0] = 999;
printf("original.values[0] = %d\n", original.values[0]); /* 999 */
printf("backup.values[0] = %d\n", backup.values[0]); /* 10 */
printf("Structs identical? %s\n",
memcmp(&original, &backup, sizeof(Record)) == 0 ? "yes" : "no");
return 0;
}At a Glance
Function | Purpose | Overlap-safe? |
|---|---|---|
memcpy | Copy n bytes from src to dest | No — undefined behavior if regions overlap |
memmove | Copy n bytes, safe even if regions overlap | Yes |
memset | Fill n bytes with a single byte value | N/A |
memcmp | Compare n bytes of two regions | N/A |