SyntaxStudy
Sign Up
C void Pointers and Pointer Casting
C Beginner 1 min read

void Pointers and Pointer Casting

A `void *` pointer (void pointer) holds an address without specifying what type of data lives there. It is C's generic pointer type — any pointer can be implicitly converted to and from `void *` without a cast. The standard library uses `void *` extensively: `malloc` returns `void *`, `memcpy` and `memset` accept `void *`, and `qsort`'s comparison callback receives `const void *` arguments. To use the data a `void *` points to, you must cast it to a concrete pointer type first. The cast tells the compiler how to interpret the bytes at that address. Incorrect casts — such as treating a `float *` as an `int *` — violate the strict-aliasing rule and produce undefined behaviour. The only safe way to reinterpret bytes is through a union or `memcpy`. The functions `memcpy()`, `memmove()`, and `memset()` in `` operate on raw bytes through `void *` pointers. `memcpy` is the fastest way to copy a block of memory when source and destination do not overlap. `memmove` is safe even when they do overlap. `memset` fills a block with a repeated byte value — most commonly used to zero out a struct or array.
Example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Generic swap using void pointers and memcpy */
void generic_swap(void *a, void *b, size_t size)
{
    unsigned char tmp[size];   /* variable-length array (C99) */
    memcpy(tmp, a,   size);
    memcpy(a,   b,   size);
    memcpy(b,   tmp, size);
}

int main(void)
{
    /* void * implicit conversion */
    int   x = 10, y = 20;
    generic_swap(&x, &y, sizeof(int));
    printf("After swap: x=%d y=%d\n", x, y);   /* 20 10 */

    double da = 1.5, db = 9.9;
    generic_swap(&da, &db, sizeof(double));
    printf("After swap: da=%.1f db=%.1f\n", da, db);

    /* memset: zero-initialise an array */
    int arr[8];
    memset(arr, 0, sizeof(arr));
    printf("zeroed: ");
    for (int i = 0; i < 8; i++) printf("%d ", arr[i]);
    printf("\n");

    /* memcpy vs memmove (overlapping regions) */
    char buf[] = "Hello, World!";
    memmove(buf + 7, buf, 5);   /* safe for overlap */
    buf[12] = '\0';
    printf("memmove result: \"%s\"\n", buf);

    /* Casting void * from malloc */
    void *raw = malloc(sizeof(double) * 3);
    double *dp = (double *)raw;   /* explicit cast for clarity */
    dp[0] = 1.1; dp[1] = 2.2; dp[2] = 3.3;
    printf("dp: %.1f %.1f %.1f\n", dp[0], dp[1], dp[2]);
    free(raw);

    return 0;
}