CMemory Functions (memcpy/memset)

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.

C
#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;
}
Warning
`memcpy` has **undefined behavior** if the source and destination regions overlap. The function is free to copy forward, backward, or in chunks — if the regions overlap, it may read bytes that have already been overwritten, silently corrupting the result. If there's any chance the regions overlap, use `memmove` instead.
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.

C
#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.

C
#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;
}
Note
Because `memset` fills with a single **byte** value, it's only reliable for setting to `0` (or `-1` for all-bits-set patterns) when working with multi-byte types like `int`. `memset(arr, 1, n)` on an `int` array does **not** set every int to `1` — it sets every individual byte to `1`, producing large garbage integers.
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.

C
#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

C
#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

Tip
If you're not sure whether two buffers might overlap, `memmove` is always safe to use in place of `memcpy` — the small potential performance cost is rarely worth risking silent data corruption.