Swap genérico
Parte de la sección Programación Orientada a Objetos 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 independiente para cada tipo: una para int, otra para double, y así sucesivamente. Pero con void* y memcpy, podemos escribir una sola función que intercambie dos variables cualesquiera.
La idea clave es que intercambiar consiste simplemente en mover bytes. Si conoces el tamaño de los datos, puedes copiar bytes sin conocer el tipo real. La signatura de la función tiene este aspecto:
void generic_swap(void* a, void* b, size_t size);El parámetro size indica a la función cuántos bytes mover. Dentro, usamos un búfer temporal y memcpy de <string.h> para intercambiar 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, que utiliza void* con size_t, es la forma en que la biblioteca estándar de C implementa funciones genéricas como qsort y bsearch.
Desafío
FácilConstruyamos una utilidad de intercambio genérica que pueda intercambiar los valores de dos variables cualesquiera, independientemente de su tipo: usando el poder de los punteros void* y memcpy.
Organizarás tu código en tres archivos:
swap.h: Declara tu funcióngeneric_swap, que recibe dos punterosvoid*y un parámetrosize_tque indica el tamaño de los datos que se intercambiarán. ¡No olvides las protecciones de inclusión!swap.c: Implementa la funcióngeneric_swap. Usa 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 que tu intercambio genérico funciona con distintos tipos de datos. Lee un indicador de tipo (ipara enteros,dpara números de doble precisión) seguido de dos valores. Crea dos variables del tipo apropiado, intercámbialas usando tu funcióngeneric_swapy, después, imprime ambos valores tras el intercambio.
Tu programa recibirá tres entradas:
- Un indicador de tipo:
ipara entero odpara número de doble precisión - El primer valor
- El segundo valor
Después del intercambio, imprime ambos valores en líneas separadas. Para los números de doble precisión, usa 2 decimales.
Salida de ejemplo cuando las entradas son i, 5 y 10:
10
5Salida de ejemplo cuando las entradas son d, 3.14 y 2.71:
2.71
3.14Salida de ejemplo cuando las entradas son i, -7 y 42:
42
-7Salida de ejemplo 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 funciona con enteros, números de doble precisión, estructuras o cualquier otro tipo de datos. Tendrás que incluir <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: Llama a generic_swap para intercambiar a y b
// Hint: 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: Llama a generic_swap para intercambiar a y b
// Hint: 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 Programación Orientada a Objetos
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írculoImplementación del rectánguloUso polimórficoContenedor de figurasPractica por tu cuenta: Compilador de C online