C - Generic Programming Techniques Using void * in C
Generic programming is a programming approach that allows developers to write code that works with multiple data types without duplicating the same logic for each type. Unlike languages such as C++ that support templates or Java that provides generics, the C programming language achieves generic programming primarily through the use of void * pointers. A void * pointer, also called a generic pointer, can store the address of any data type. This capability makes it possible to create flexible and reusable functions that work with integers, floating-point numbers, structures, arrays, and user-defined data types.
What is a void * Pointer?
A void * pointer is a special type of pointer that does not have an associated data type. Since it does not know the type of data it points to, it cannot directly access or manipulate the value. Before dereferencing a void * pointer, it must first be converted into the appropriate pointer type.
Syntax
void *ptr;
Example:
#include <stdio.h>
int main()
{
int num = 50;
void *ptr = #
printf("%d", *(int *)ptr);
return 0;
}
Output
50
In this example, the generic pointer stores the address of an integer. Before accessing the value, the pointer is typecast to int *.
Why Generic Programming is Needed
Suppose you want to create a function that swaps two values.
Without generic programming, separate functions are needed.
void swapInt(int *a, int *b);
void swapFloat(float *a, float *b);
void swapChar(char *a, char *b);
Although the logic remains identical, each function must be written separately.
Using void *, a single function can swap values of any data type.
This reduces:
-
Code duplication
-
Development time
-
Maintenance effort
-
Testing complexity
Generic Swap Function
#include <stdio.h>
#include <string.h>
void swap(void *a, void *b, size_t size)
{
char temp[size];
memcpy(temp, a, size);
memcpy(a, b, size);
memcpy(b, temp, size);
}
int main()
{
int x = 10, y = 20;
swap(&x, &y, sizeof(int));
printf("%d %d", x, y);
return 0;
}
Output
20 10
The function works for integers without knowing the data type in advance.
Swapping Floating-Point Numbers
#include <stdio.h>
#include <string.h>
void swap(void *a, void *b, size_t size)
{
char temp[size];
memcpy(temp, a, size);
memcpy(a, b, size);
memcpy(b, temp, size);
}
int main()
{
float a = 5.5;
float b = 9.8;
swap(&a, &b, sizeof(float));
printf("%.1f %.1f", a, b);
return 0;
}
Output
9.8 5.5
The same function now works for floating-point numbers.
Swapping Structures
#include <stdio.h>
#include <string.h>
struct Student
{
int id;
char name[20];
};
void swap(void *a, void *b, size_t size)
{
char temp[size];
memcpy(temp, a, size);
memcpy(a, b, size);
memcpy(b, temp, size);
}
int main()
{
struct Student s1 = {1, "Rahul"};
struct Student s2 = {2, "Anita"};
swap(&s1, &s2, sizeof(struct Student));
printf("%d %s\n", s1.id, s1.name);
printf("%d %s", s2.id, s2.name);
return 0;
}
Output
2 Anita
1 Rahul
A single function successfully swaps complete structures.
Generic Search Function
A generic search function can search different types of arrays.
#include <stdio.h>
#include <string.h>
int search(void *array, void *key, int n, int size)
{
char *ptr = (char *)array;
for(int i = 0; i < n; i++)
{
if(memcmp(ptr + i * size, key, size) == 0)
return i;
}
return -1;
}
int main()
{
int numbers[] = {10,20,30,40};
int key = 30;
int index = search(numbers, &key, 4, sizeof(int));
printf("%d", index);
return 0;
}
Output
2
The function can search arrays of integers, characters, structures, or floating-point numbers by changing only the arguments.
Generic Sorting Using qsort()
The C Standard Library provides a generic sorting function.
Syntax
qsort(array, number_of_elements, element_size, comparison_function);
Example
#include <stdio.h>
#include <stdlib.h>
int compare(const void *a, const void *b)
{
return (*(int *)a - *(int *)b);
}
int main()
{
int arr[] = {8,4,2,9,1};
qsort(arr, 5, sizeof(int), compare);
for(int i = 0; i < 5; i++)
printf("%d ", arr[i]);
return 0;
}
Output
1 2 4 8 9
qsort() internally uses void * pointers, making it capable of sorting any data type.
Generic Binary Search Using bsearch()
Another standard library function that uses generic programming is bsearch().
Example
#include <stdio.h>
#include <stdlib.h>
int compare(const void *a, const void *b)
{
return (*(int *)a - *(int *)b);
}
int main()
{
int arr[] = {10,20,30,40,50};
int key = 40;
int *result = bsearch(&key, arr, 5, sizeof(int), compare);
if(result != NULL)
printf("%d found", *result);
else
printf("Not found");
return 0;
}
Output
40 found
Generic Printing Function
A function can print different data types by receiving an additional parameter indicating the data type.
#include <stdio.h>
void printValue(void *data, char type)
{
if(type == 'i')
printf("%d\n", *(int *)data);
else if(type == 'f')
printf("%.2f\n", *(float *)data);
else if(type == 'c')
printf("%c\n", *(char *)data);
}
int main()
{
int a = 50;
float b = 4.75;
char c = 'A';
printValue(&a,'i');
printValue(&b,'f');
printValue(&c,'c');
return 0;
}
Output
50
4.75
A
Type Casting in Generic Programming
Since void * has no type information, explicit type conversion is mandatory.
Example
int num = 100;
void *ptr = #
int value = *(int *)ptr;
Without type casting, the compiler cannot determine the size or format of the data.
Advantages of Generic Programming with void *
-
Reduces duplicate code by using one function for multiple data types.
-
Makes programs easier to maintain and update.
-
Improves code reusability across projects.
-
Supports user-defined data types such as structures.
-
Forms the basis of many standard library functions like
qsort(),bsearch(), andmemcpy(). -
Enables the development of flexible libraries and reusable APIs.
Limitations
-
Requires explicit type casting before accessing data.
-
No compile-time type checking, increasing the possibility of programming errors.
-
Can make debugging more difficult if incorrect pointer types are used.
-
Slightly more complex than writing type-specific functions.
-
Improper casting may lead to undefined behavior or memory access violations.
Real-World Applications
Generic programming using void * is widely used in many software systems, including:
-
Standard C library functions such as
qsort(),bsearch(),memcpy(), andmemmove(). -
Generic data structures including linked lists, queues, stacks, trees, and hash tables.
-
Operating systems where kernel components manage different object types.
-
Embedded systems that require reusable and memory-efficient code.
-
Device drivers that process hardware data of varying formats.
-
Database engines that store and manipulate records of different structures.
-
Networking applications that handle packets with diverse data layouts.
-
Reusable software libraries designed to support multiple applications.
Conclusion
Generic programming with void * is one of the most powerful techniques available in C for writing flexible and reusable code. By allowing a single function to operate on different data types, it minimizes code duplication and simplifies maintenance. Many functions in the C Standard Library rely on this concept, demonstrating its importance in professional software development. Although developers must use explicit type casting and carefully manage pointer types, mastering void * enables the creation of efficient, reusable, and scalable C programs suitable for a wide range of real-world applications.