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 em programação é trocar 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 principal percepção é que trocar significa apenas 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. Dentro dela, usamos um buffer temporário e memcpy de <string.h> para trocar 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 com 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.14Esse padrão, que usa void* com size_t, é como a biblioteca padrão de C implementa funções genéricas como qsort e bsearch.
Desafio
FácilVamos criar uma utilidade genérica de troca que pode trocar os valores de quaisquer duas variáveis, independentemente do tipo delas: usando o poder dos ponteiros void* e de memcpy.
Você vai organizar seu código em três arquivos:
swap.h: Declare sua funçãogeneric_swap, que recebe dois ponteirosvoid*e um parâmetrosize_tque indica 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 os dois locais de memória. Lembre-se do padrão de troca em três etapas: copie o primeiro valor para temp, copie o segundo para o primeiro e copie temp para o segundo.main.c: Demonstre sua troca genérica funcionando com diferentes tipos de dados. Leia um indicador de tipo (ipara inteiros,dpara números de ponto flutuante) 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 número de ponto flutuante - O primeiro valor
- O segundo valor
Após a troca, imprima os dois valores em linhas separadas. Para números de ponto flutuante, 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 vantagem dessa abordagem é que sua função generic_swap não sabe quais tipos está trocando. Ela apenas move bytes. A mesma função funciona com inteiros, números de ponto flutuante, 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 os valores de 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 os valores de 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çalhoProteções de inclusãoArquivos-fonteFunções estáticasRevisão: calculadora modular4Encapsulamento
Conceito de ponteiros opacosDefinindo structs opacasGetters e settersValidação em settersRevisão: caixa secreta7Ponteiros para Funções
Declarando Ponteiros para FunçõesChamando Ponteiros para FunçõesTypedef para Ponteiros para FunçõesPassando Funções como ArgumentosRevisão: Despacho da Calculadora10Contêineres Genéricos
Revisão de ponteiros voidInvólucro genéricoTroca genéricaComparação genéricaRevisão: array genérico2Objetos e métodos
Structs como objetosO ponteiro 'Self'Correção de constPonteiro vs. valorMétodos auxiliaresRevisão: Gerenciador de pontos5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta3Ciclo de vida do objeto
Padrão de construtorPadrão de destrutorInicialização da pilhaCópia profundaRevisão: wrapper de String6Herança por composição
Incorporação de structRegra do primeiro membroAcessando membros do tipo paiUpcastingRevisão: hierarquia de formas9Projeto: Desenhador de Formas
Visão geral do projetoImplementação do círculoImplementação do retânguloUso polimórficoContêiner de formasPratique por conta própria: Compilador de C online