Revisão de Ponteiros Void
Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 49 de 61.
Um void* é a maneira que C usa para dizer "um ponteiro para alguma coisa, mas não vou dizer o quê". Ele pode armazenar o endereço de qualquer tipo de dado: um int, um float, uma struct ou qualquer outra coisa. Isso faz dele a base para escrever código genérico em C.
O problema é que você não pode desreferenciar um void* diretamente. O compilador não sabe quantos bytes deve ler nem como interpretá-los. Para usar os dados, você precisa convertê-los de volta para o tipo correto:
void print_int(void* data) {
int* p = (int*)data;
printf("%d\n", *p);
}
int main() {
int x = 42;
print_int(&x);
return 0;
}Essa flexibilidade vem acompanhada de responsabilidade. Se você converter para o tipo errado, o compilador não vai impedir, mas seu programa produzirá lixo ou travará. É por isso que funções genéricas frequentemente associam um void* a um indicador de tipo (como um enum ou uma flag), para que a função saiba como interpretar os dados corretamente.
Nas próximas lições, você usará void* para construir contêineres que podem armazenar qualquer tipo de dado, permitindo estruturas de dados realmente reutilizáveis.
Desafio
FácilEscreva uma função chamada print_value que aceite dois parâmetros: um ponteiro void* para os dados e um sinalizador de tipo int. A função deve interpretar e imprimir os dados com base no sinalizador de tipo:
- Se o sinalizador de tipo for
0, converta o ponteiro paraint*e imprima o valor inteiro - Se o sinalizador de tipo for
1, converta o ponteiro parafloat*e imprima o valor de ponto flutuante com 2 casas decimais
Seu programa receberá duas entradas:
- Um sinalizador de tipo (
0para inteiro,1para ponto flutuante) - Um valor numérico
Com base no sinalizador de tipo, armazene o valor no tipo de variável apropriado e, em seguida, chame print_value com um ponteiro para essa variável e o sinalizador de tipo.
Exemplo de saída quando as entradas são 0 e 42:
42Exemplo de saída quando as entradas são 1 e 3.14:
3.14Exemplo de saída quando as entradas são 0 e -17:
-17Exemplo de saída quando as entradas são 1 e 99.5:
99.50Experimente você mesmo
#include <stdio.h>
// TODO: Escreva sua função print_value aqui
int main() {
int type_flag;
scanf("%d", &type_flag);
if (type_flag == 0) {
int int_value;
scanf("%d", &int_value);
// TODO: Chame print_value com um ponteiro para int_value e a flag de tipo
} else if (type_flag == 1) {
float float_value;
scanf("%f", &float_value);
// TODO: Chame print_value com um ponteiro para float_value e a flag de tipo
}
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