Troca Genérica
Parte da seção Object Oriented Programming do Journey de C da Coddy — lição 51 de 61.
Uma operação comum na programação é a troca de dois valores. Normalmente, você escreveria uma função de troca separada para cada tipo — uma para int, outra para double, e assim por diante. Mas com void* e memcpy, podemos escrever uma única função que troca quaisquer duas variáveis.
A percepção fundamental é que a troca (swapping) consiste apenas em mover bytes de um lugar para outro. Se você souber o tamanho dos dados, poderá copiar os bytes sem conhecer o tipo real. A assinatura da função se parece com isto:
void generic_swap(void* a, void* b, size_t size);O parâmetro size informa à função quantos bytes mover. Internamente, usamos um buffer temporário e memcpy de <string.h> para embaralhar os bytes:
void generic_swap(void* a, void* b, size_t size) {
char temp[size]; // buffer temporário
memcpy(temp, a, size); // temp = a
memcpy(a, b, size); // a = b
memcpy(b, temp, size); // b = temp
}Agora esta única função funciona para qualquer tipo:
int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x agora é 10, y agora é 5double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p agora é 2.71, q agora é 3.14Este padrão — usando void* com size_t — é como a biblioteca padrão do C implementa funções genéricas como qsort e bsearch.
Desafio
FácilVamos construir um utilitário de troca genérico que pode permutar os valores de quaisquer duas variáveis, independentemente de seu tipo — usando o poder dos ponteiros void* e do memcpy.
Você organizará seu código em três arquivos:
swap.h: Declare sua funçãogeneric_swapque recebe dois ponteirosvoid*e um parâmetrosize_tindicando o tamanho dos dados a serem trocados. Não se esqueça dos include guards!swap.c: Implemente a funçãogeneric_swap. Use um buffer temporário ememcpypara mover bytes entre os dois locais de memória. Lembre-se do padrão de troca de três etapas: copiar o primeiro valor para o temporário, copiar o segundo para o primeiro, copiar o temporário para o segundo.main.c: Demonstre sua troca genérica funcionando com diferentes tipos de dados. Leia um indicador de tipo (ipara inteiros,dpara doubles) seguido por dois valores. Crie duas variáveis do tipo apropriado, troque-as usando sua funçãogeneric_swape, em seguida, imprima ambos os valores após a troca.
Seu programa receberá três entradas:
- Um indicador de tipo:
ipara inteiro oudpara double - O primeiro valor
- O segundo valor
Após a troca, imprima ambos os valores em linhas separadas. Para doubles, use 2 casas decimais.
Exemplo de saída quando as entradas são i, 5 e 10:
10
5Exemplo de saída quando as entradas são d, 3.14 e 2.71:
2.71
3.14Exemplo de saída quando as entradas são i, -7 e 42:
42
-7Exemplo de saída quando as entradas são d, 99.99 e 0.01:
0.01
99.99A beleza desta abordagem é que sua função generic_swap não tem ideia de quais tipos ela está trocando — ela apenas move bytes. A mesma função funciona para inteiros, doubles, structs ou qualquer outro tipo de dado. Você precisará incluir <string.h> para memcpy e <stddef.h> ou <stdlib.h> para size_t.
Folha de consulta
Uma função swap genérica usa ponteiros void* e memcpy para trocar valores de qualquer tipo, movendo bytes sem conhecer o tipo real.
Assinatura da função:
void generic_swap(void* a, void* b, size_t size);Implementação usando um buffer temporário e memcpy:
void generic_swap(void* a, void* b, size_t size) {
char temp[size]; // buffer temporário
memcpy(temp, a, size); // temp = a
memcpy(a, b, size); // a = b
memcpy(b, temp, size); // b = temp
}Uso com diferentes tipos:
int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x agora é 10, y agora é 5
double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p agora é 2.71, q agora é 3.14Cabeçalhos necessários: <string.h> para memcpy e <stddef.h> ou <stdlib.h> para size_t.
Experimente você mesmo
#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: Chame generic_swap para trocar a e b
// Dica: Use &a, &b e sizeof(int)
printf("%d\n", a);
printf("%d\n", b);
} else if (type == 'd') {
double a, b;
scanf("%lf", &a);
scanf("%lf", &b);
// TODO: Chame generic_swap para trocar a e b
// Dica: Use &a, &b e sizeof(double)
printf("%.2f\n", a);
printf("%.2f\n", b);
}
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Fundamentos da Programação Modular
Arquivos de CabeçalhoInclude GuardsArquivos-FonteFunções EstáticasRecapitulação: Calculadora Modular4Encapsulamento
Conceito de Ponteiros OpacosDefinindo Structs OpacasGetters e SettersValidação em SettersRecapitulação: Caixa Secreta7Ponteiros para Funções
Declarando Ponteiros para FunçõesChamando Ponteiros para FunçõesTypedef para Ponteiros para FunçõesPassando Funções como ArgumentosRecapitulação: Dispatch de Calculadora10Contêineres Genéricos
Revisão de Ponteiros VoidWrapper GenéricoTroca GenéricaComparação GenéricaRevisão: Array Genérico2Objetos e Métodos
Structs como ObjetosO Ponteiro 'Self'Const CorrectnessPonteiro vs ValorMétodos AuxiliaresRecapitulação: Point Manager5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta3Ciclo de Vida de Objetos
Padrão de ConstrutorPadrão de DestrutorInicialização na StackCópia ProfundaRecapitulação: String Wrapper6Herança via Composição
Incorporação de StructsA Regra do Primeiro MembroAcessando Membros PaiUpcastingRecapitulação: Hierarquia de Formas9Projeto: Desenhador de Formas
Visão Geral do ProjetoImplementação do Círculo