Repaso de punteros void
Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 49 de 61.
Un void* es la forma que tiene C de decir "un puntero a algo, pero no te diré a qué". Puede contener la dirección de cualquier tipo de dato — un int, un float, un struct o cualquier otra cosa. Esto lo convierte en la base para escribir código genérico en C.
El inconveniente es que no puedes desreferenciar un void* directamente. El compilador no sabe cuántos bytes leer ni cómo interpretarlos. Para usar los datos, debes realizar un cast (conversión) de vuelta al tipo correcto:
void print_int(void* data) {
int* p = (int*)data;
printf("%d\n", *p);
}
int main() {
int x = 42;
print_int(&x);
return 0;
}Esta flexibilidad conlleva una responsabilidad. Si realizas un cast al tipo incorrecto, el compilador no te detendrá, pero tu programa producirá basura o fallará. Es por eso que las funciones genéricas a menudo emparejan un void* con un indicador de tipo (como un enum o un flag) para que la función sepa cómo interpretar los datos correctamente.
En las próximas lecciones, usarás void* para construir contenedores que pueden almacenar cualquier tipo de datos, permitiendo estructuras de datos verdaderamente reutilizables.
Desafío
FácilEscribe una función llamada print_value que acepte dos parámetros: un puntero void* a datos y una bandera de tipo int. La función debe interpretar e imprimir los datos basándose en la bandera de tipo:
- Si la bandera de tipo es
0, convierte el puntero aint*e imprime el valor entero - Si la bandera de tipo es
1, convierte el puntero afloat*e imprime el valor flotante con 2 decimales
Tu programa recibirá dos entradas:
- Una bandera de tipo (
0para entero,1para flotante) - Un valor numérico
Basándote en la bandera de tipo, almacena el valor en el tipo de variable apropiado, luego llama a print_value con un puntero a esa variable y la bandera de tipo.
Ejemplo de salida cuando las entradas son 0 y 42:
42Ejemplo de salida cuando las entradas son 1 y 3.14:
3.14Ejemplo de salida cuando las entradas son 0 y -17:
-17Ejemplo de salida cuando las entradas son 1 y 99.5:
99.50Hoja de referencia
Un void* es un puntero genérico que puede contener la dirección de cualquier tipo de dato. Proporciona flexibilidad para escribir código genérico en C.
No se puede desreferenciar un void* directamente; primero debe convertirse al tipo correcto:
void print_int(void* data) {
int* p = (int*)data;
printf("%d\n", *p);
}
int main() {
int x = 42;
print_int(&x);
return 0;
}Las funciones genéricas a menudo emparejan un void* con un indicador de tipo (como un enum o una bandera) para saber cómo interpretar los datos correctamente. Realizar una conversión al tipo incorrecto puede causar un comportamiento indefinido o bloqueos del programa.
Pruébalo tú mismo
#include <stdio.h>
// TODO: Escribe tu función print_value aquí
int main() {
int type_flag;
scanf("%d", &type_flag);
if (type_flag == 0) {
int int_value;
scanf("%d", &int_value);
// TODO: Llama a print_value con un puntero a int_value y el flag de tipo
} else if (type_flag == 1) {
float float_value;
scanf("%f", &float_value);
// TODO: Llama a print_value con un puntero a float_value y el flag de tipo
}
return 0;
}Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Fundamentos de programación modular
Archivos de cabeceraGuardas de inclusiónArchivos fuenteFunciones estáticasRepaso: Calculadora modular4Encapsulamiento
Concepto de punteros opacosDefinición de structs opacosGetters y SettersValidación en settersResumen: Caja secreta7Punteros a funciones
Declaración de punteros a funcionesLlamada a punteros a funcionesTypedef para punteros a funcionesPasar funciones como argumentosRepaso: Dispatch de calculadora10Contenedores genéricos
Repaso de punteros voidWrapper genéricoSwap genéricoComparación genéricaRepaso: Array genérico2Objetos y métodos
Structs como objetosEl puntero 'Self'Const CorrectnessPuntero vs. ValorMétodos auxiliaresResumen: Point Manager5Proyecto: Cuenta bancaria simple
Configuración del proyectoImplementación de la cuenta3Ciclo de vida de los objetos
Patrón ConstructorPatrón DestructorInicialización en StackCopia profundaResumen: String Wrapper6Herencia mediante composición
Incrustación de StructsLa regla del primer miembroAcceso a miembros padreUpcastingResumen: Jerarquía de formas9Proyecto: Dibujador de figuras
Descripción general del proyectoImplementación del círculo