Troca Genérica
Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 51 de 61.
Uma operação comum na programação é trocar dois valores. Normalmente, você escreveria uma função swap 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 duas variáveis quaisquer.
A principal ideia é que a troca consiste apenas em mover bytes. Se você souber o tamanho dos dados, poderá copiar bytes sem conhecer o tipo real. A assinatura da função é assim:
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 reorganizar 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 essa ú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 de C implementa funções genéricas como qsort e bsearch.
Desafio
FácilVamos criar um utilitário genérico de troca que possa trocar os valores de quaisquer duas variáveis, independentemente do tipo delas: usando o poder dos ponteiros void* e de memcpy.
Você organizará seu código em três arquivos:
swap.h: declare sua funçãogeneric_swap, que recebe dois ponteirosvoid*e um parâmetrosize_tindicando o tamanho dos dados a serem trocados. Não se esqueça dos protetores de inclusão!swap.c: implemente a funçãogeneric_swap. Use um buffer temporário ememcpypara mover bytes entre as duas localizações de memória. Lembre-se do padrão de troca em três etapas: copie o primeiro valor para o temporário, copie o segundo para o primeiro e copie o temporário para o segundo.main.c: demonstre o funcionamento da sua troca genérica com diferentes tipos de dados. Leia um indicador de tipo (ipara inteiros,dpara números de ponto flutuante do tipo double), seguido por dois valores. Crie duas variáveis do tipo apropriado, troque-as usando sua funçãogeneric_swape, em seguida, imprima os dois 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 os dois 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 dessa abordagem é que sua função generic_swap não faz ideia de quais tipos 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 usar memcpy e <stddef.h> ou <stdlib.h> para usar 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 Programação Orientada a Objetos
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írculoImplementação do RetânguloUso PolimórficoContainer de FormasPratique por conta própria: Compilador de C online