Swap genérico
Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 51 de 61.
Una operación común en programación es intercambiar dos valores. Normalmente, escribirías una función de intercambio separada para cada tipo — una para int, otra para double, y así sucesivamente. Pero con void* and memcpy, podemos escribir una única función que intercambie dos variables cualesquiera.
La idea clave es que el intercambio consiste simplemente en mover bytes. Si conoces el tamaño de los datos, puedes copiar bytes sin conocer el tipo real. La firma de la función se ve así:
void generic_swap(void* a, void* b, size_t size);El parámetro size le indica a la función cuántos bytes mover. En el interior, utilizamos un búfer temporal y memcpy de <string.h> para reorganizar los bytes:
void generic_swap(void* a, void* b, size_t size) {
char temp[size]; // búfer temporal
memcpy(temp, a, size); // temp = a
memcpy(a, b, size); // a = b
memcpy(b, temp, size); // b = temp
}Ahora esta única función funciona para cualquier tipo:
int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x ahora es 10, y ahora es 5double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p es ahora 2.71, q es ahora 3.14Este patrón —usando void* con size_t— es como la biblioteca estándar de C implementa funciones genéricas como qsort y bsearch.
Desafío
FácilVamos a construir una utilidad de intercambio genérica que pueda intercambiar los valores de cualquier par de variables, independientemente de su tipo — utilizando el poder de los punteros void* y memcpy.
Organizarás tu código en tres archivos:
swap.h: Declara tu funcióngeneric_swapque recibe dos punterosvoid*y un parámetrosize_tque indica el tamaño de los datos a intercambiar. ¡No olvides los include guards!swap.c: Implementa la funcióngeneric_swap. Utiliza un búfer temporal ymemcpypara mover bytes entre las dos ubicaciones de memoria. Recuerda el patrón de intercambio de tres pasos: copiar el primer valor al temporal, copiar el segundo al primero, y copiar el temporal al segundo.main.c: Demuestra tu intercambio genérico funcionando con diferentes tipos de datos. Lee un indicador de tipo ('i'para enteros,'d'para doubles) seguido de dos valores. Crea dos variables del tipo apropiado, intercámbialas usando tu funcióngeneric_swap, y luego imprime ambos valores después del intercambio.
Tu programa recibirá tres entradas:
- Un indicador de tipo:
'i'para entero o'd'para double - El primer valor
- El segundo valor
Después del intercambio, imprime ambos valores en líneas separadas. Para los doubles, utiliza 2 decimales.
Ejemplo de salida cuando las entradas son 'i', 5, y 10:
10
5Ejemplo de salida cuando las entradas son 'd', 3.14, y 2.71:
2.71
3.14Ejemplo de salida cuando las entradas son 'i', -7, y 42:
42
-7Ejemplo de salida cuando las entradas son 'd', 99.99, y 0.01:
0.01
99.99La belleza de este enfoque es que tu función generic_swap no tiene idea de qué tipos está intercambiando — simplemente mueve bytes. La misma función sirve para enteros, doubles, structs o cualquier otro tipo de dato. Necesitarás incluir <string.h> para memcpy y <stddef.h> o <stdlib.h> para size_t.
Hoja de referencia
Una función de intercambio genérica utiliza punteros void* y memcpy para intercambiar valores de cualquier tipo moviendo bytes sin conocer el tipo real.
Firma de la función:
void generic_swap(void* a, void* b, size_t size);Implementación utilizando un búfer temporal y memcpy:
void generic_swap(void* a, void* b, size_t size) {
char temp[size]; // búfer temporal
memcpy(temp, a, size); // temp = a
memcpy(a, b, size); // a = b
memcpy(b, temp, size); // b = temp
}Uso con diferentes tipos:
int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x ahora es 10, y ahora es 5
double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p ahora es 2.71, q ahora es 3.14Cabeceras requeridas: <string.h> para memcpy y <stddef.h> o <stdlib.h> para size_t.
Pruébalo tú mismo
#include <stdio.h>
#include "swap.h"
int main() {
char type;
scanf("%c", &type);
if (type == 'i') {
int a, b;
scanf("%d", &a);
scanf("%d", &b);
// TODO: Llamar a generic_swap para intercambiar a y b
// Pista: Usa &a, &b y sizeof(int)
printf("%d\n", a);
printf("%d\n", b);
} else if (type == 'd') {
double a, b;
scanf("%lf", &a);
scanf("%lf", &b);
// TODO: Llamar a generic_swap para intercambiar a y b
// Pista: Usa &a, &b y sizeof(double)
printf("%.2f\n", a);
printf("%.2f\n", b);
}
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