Usage of void and void* Pointers in C Programming

<span>void</span> and <span>void*</span> are fundamental yet very useful types in C programming, especially when dealing with generic pointers (such as <span>malloc</span>, callback functions, etc.), where <span>void*</span> is crucial.

1. What are <span>void</span> and <span>void*</span>

Syntax Meaning
<span>void</span> Indicates “no type” or “no return value”, commonly used for function return types
<span>void*</span> Generic pointer type, can point to any type of data

2. Usage of <span>void</span>

1. Indicates a function with “no return value”

void say_hello() {
    printf("Hello!\n");
}

2. Indicates a function that “takes no parameters” (old style)

void do_nothing(void) {
    // Function takes 0 parameters (explicitly stated)
}

3. Usage of <span>void*</span>: Generic pointer type

✨ 1. <span>malloc</span> returns a <span>void*</span>

int* p = (int*)malloc(sizeof(int) * 5);
  • <span>malloc</span> returns a <span>void*</span>, you need to manually cast it to the target type pointer
  • In C++, casting is mandatory, while in C it can be omitted, but it’s recommended to be explicit

✨ 2. Function parameter passing (generic parameters)

void print_value(void* data, char type) {
    if (type == 'i') {
        printf("int: %d\n", *(int*)data);
    } else if (type == 'f') {
        printf("float: %f\n", *(float*)data);
    }
}

Call:

int x = 10;
float y = 3.14;
print_value(&x, 'i');
print_value(&y, 'f');

✨ 3. Used with thread libraries (e.g., <span>pthread</span>)

void* thread_func(void* arg) {
    int* p = (int*)arg;
    printf("Thread got: %d\n", *p);
    return NULL;
}

✨ 4. Implementing generic containers (e.g., linked lists, stacks, queues)

typedef struct Node {
    void* data;
    struct Node* next;
} Node;

You can store any type of data, as long as you correctly cast the type when accessing it.

4. void* requires explicit type casting

Because <span>void*</span> has no type information, it cannot be dereferenced directly.

void* p;
int x = 10;
p = &x;

printf("%d\n", *(int*)p);  // ✅ OK
// printf("%d\n", *p);      // ❌ Error: cannot dereference void*

5. Limitations of void*

Limitation Explanation
Cannot directly dereference <span>*p</span> Because <span>void</span> is an incomplete type, size is unknown
Cannot perform <span>p++</span> operation Same reason: cannot know how many bytes to skip
Must explicitly cast back to target type pointer Otherwise, the compiler does not know what type of data you are operating on

6. Complete example

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

void print_any(void* data, char type) {
    switch (type) {
        case'i':
            printf("int: %d\n", *(int*)data);
            break;
        case'd':
            printf("double: %f\n", *(double*)data);
            break;
        case's':
            printf("string: %s\n", (char*)data);
            break;
    }
}

int main() {
    int x = 42;
    double y = 3.14;
    char* msg = "hello";

    print_any(&x, 'i');
    print_any(&y, 'd');
    print_any(msg, 's');

    return 0;
}

7. Summary Comparison

Type Meaning Example
<span>void</span> No return value/parameters <span>void func(void)</span>
<span>void*</span> Pointer to any type <span>void* ptr = malloc(10);</span>

Review of Uses

  • <span>malloc/free</span> and other memory function return values
  • Generic parameter passing (e.g., callback functions)
  • Implementing data structures (linked lists/queues, etc.)
  • Used with <span>pthread</span>, <span>qsort</span> and other library functions

Leave a Comment