Void Pointers Recap
Part of the Object Oriented Programming section of Coddy's C journey — lesson 49 of 61.
A void* is C's way of saying "a pointer to something, but I'm not telling you what." It can hold the address of any data type — an int, a float, a struct, or anything else. This makes it the foundation for writing generic code in C.
The catch is that you cannot dereference a void* directly. The compiler doesn't know how many bytes to read or how to interpret them. To use the data, you must cast it back to the correct type:
void print_int(void* data) {
int* p = (int*)data;
printf("%d\n", *p);
}
int main() {
int x = 42;
print_int(&x);
return 0;
}This flexibility comes with responsibility. If you cast to the wrong type, the compiler won't stop you — but your program will produce garbage or crash. That's why generic functions often pair a void* with a type indicator (like an enum or flag) so the function knows how to interpret the data correctly.
In the upcoming lessons, you'll use void* to build containers that can store any type of data, enabling truly reusable data structures.
Challenge
EasyWrite a function called print_value that accepts two parameters: a void* pointer to data and an int type flag. The function should interpret and print the data based on the type flag:
- If the type flag is
0, cast the pointer toint*and print the integer value - If the type flag is
1, cast the pointer tofloat*and print the float value with 2 decimal places
Your program will receive two inputs:
- A type flag (
0for integer,1for float) - A numeric value
Based on the type flag, store the value in the appropriate variable type, then call print_value with a pointer to that variable and the type flag.
Example output when the inputs are 0 and 42:
42Example output when the inputs are 1 and 3.14:
3.14Example output when the inputs are 0 and -17:
-17Example output when the inputs are 1 and 99.5:
99.50Cheat sheet
A void* is a generic pointer that can hold the address of any data type. It provides flexibility for writing generic code in C.
You cannot dereference a void* directly — you must cast it to the correct type first:
void print_int(void* data) {
int* p = (int*)data;
printf("%d\n", *p);
}
int main() {
int x = 42;
print_int(&x);
return 0;
}Generic functions often pair a void* with a type indicator (like an enum or flag) to know how to interpret the data correctly. Casting to the wrong type can cause undefined behavior or crashes.
Try it yourself
#include <stdio.h>
// TODO: Write your print_value function here
int main() {
int type_flag;
scanf("%d", &type_flag);
if (type_flag == 0) {
int int_value;
scanf("%d", &int_value);
// TODO: Call print_value with a pointer to int_value and the type flag
} else if (type_flag == 1) {
float float_value;
scanf("%f", &float_value);
// TODO: Call print_value with a pointer to float_value and the type flag
}
return 0;
}This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Modular Programming Basics
Header FilesInclude GuardsSource FilesStatic FunctionsRecap: Modular Calculator4Encapsulation
Opaque Pointers ConceptDefining Opaque StructsGetters and SettersValidation in SettersRecap: Secret Box7Function Pointers
Declaring Function PointersCalling Function PointersTypedef for Function PointersPassing Functions as ArgumentsRecap: Calculator Dispatch10Generic Containers
Void Pointers RecapGeneric WrapperGeneric SwapGeneric CompareRecap: Generic Array2Objects and Methods
Structs as ObjectsThe 'Self' PointerConst CorrectnessPointer vs ValueHelper MethodsRecap: Point Manager5Project: Simple Bank Account
Project SetupImplementation of Account3Object Lifecycle
Constructor PatternDestructor PatternStack InitializationDeep CopyRecap: String Wrapper6Inheritance via Composition
Struct EmbeddingThe First Member RuleAccessing Parent MembersUpcastingRecap: Shape Hierarchy