Passagem de Ponteiros para Structs
Parte da seção Logic & Flow do Journey de C da Coddy — lição 47 de 63.
Embora a passagem de structs por valor funcione bem para a leitura de dados, ela se torna ineficiente com structs grandes porque toda a estrutura é copiada. Mais importante ainda, você não pode modificar a struct original de dentro da função. É aqui que a passagem de ponteiros para structs se torna essencial.
Quando você passa um ponteiro para uma struct em vez da própria struct, a função recebe o endereço de memória da struct original. Essa abordagem oferece duas vantagens principais: é mais eficiente (sem cópia) e permite que a função modifique os dados originais.
A sintaxe para uma função que aceita um ponteiro para uma struct é:
void functionName(struct StructureName *ptr) {
// Corpo da função usando ptr->member
}Dentro da função, você usa o operador de seta para acessar e modificar os membros da struct. Quaisquer alterações feitas através do ponteiro afetarão diretamente a struct original na função chamadora, tornando esta abordagem perfeita para funções que precisam atualizar ou transformar dados da struct.
Esta técnica é fundamental para a construção de programas em C eficientes que trabalham com estruturas de dados complexas, pois combina o poder dos ponteiros com a organização de structs.
Desafio
FácilCrie um programa em C que demonstre a passagem de ponteiros para structs para funções para modificação eficiente de dados. Seu programa deve:
- Definir uma
structchamadaBankAccountcom os seguintes membros:- Um inteiro
accountNumberpara armazenar o número da conta - Um array de caracteres
ownerNamecom tamanho 30 para armazenar o nome do proprietário da conta - Um float
balancepara armazenar o saldo da conta - Um inteiro
transactionCountpara armazenar o número de transações
- Um inteiro
- Escrever uma função chamada
depositMoneyque:- Recebe um ponteiro para uma struct
BankAccounte um valor float como parâmetros - Adiciona o valor ao saldo da conta usando o operador de seta (arrow operator)
- Incrementa o contador de transações em 1
- Imprime
Deposit successful. New balance: [balance]
- Recebe um ponteiro para uma struct
- Escrever uma função chamada
withdrawMoneyque:- Recebe um ponteiro para uma struct
BankAccounte um valor float como parâmetros - Verifica se o valor do saque é maior que o saldo atual
- Se houver fundos insuficientes, imprime
Insufficient funds. Current balance: [balance] - Se houver fundos suficientes, subtrai o valor do saldo, incrementa o contador de transações e imprime
Withdrawal successful. New balance: [balance]
- Recebe um ponteiro para uma struct
- Escrever uma função chamada
displayAccountque:- Recebe um ponteiro para uma struct
BankAccountcomo parâmetro - Imprime as informações da conta neste formato exato:
Account Information:Account Number: [accountNumber]Owner: [ownerName]Balance: [balance]Transactions: [transactionCount]
- Recebe um ponteiro para uma struct
- Na função main:
- Cria uma variável
BankAccountchamadaaccount - Lê o número da conta, o nome do proprietário e o saldo inicial da entrada
- Define o contador de transações como 0
- Chama
displayAccountpara mostrar o estado inicial da conta - Lê um valor de depósito e chama
depositMoney - Lê um valor de saque e chama
withdrawMoney - Chama
displayAccountpara mostrar o estado final da conta
- Cria uma variável
Este desafio demonstra o poder de passar ponteiros para structs para funções. Ao contrário da passagem por valor, as funções recebem o endereço de memória da struct original, permitindo que modifiquem diretamente os dados originais. Essa abordagem é mais eficiente (sem cópia) e permite que as funções alterem permanentemente os valores da struct na função que as chamou.
Folha de consulta
Ao passar structs por valor, toda a estrutura é copiada, o que é ineficiente para structs grandes e impede a modificação dos dados originais. Passar ponteiros para structs resolve ambos os problemas ao passar o endereço de memória em vez disso.
Sintaxe da função para aceitar um ponteiro para uma struct:
void functionName(struct StructureName *ptr) {
// Corpo da função usando ptr->member
}Dentro da função, use o operador de seta (->) para acessar e modificar os membros da struct através do ponteiro. Quaisquer alterações feitas afetarão diretamente a struct original na função chamadora.
Esta abordagem oferece duas vantagens principais:
- Mais eficiente (sem cópia de toda a struct)
- Permite que as funções modifiquem os dados da struct original
Experimente você mesmo
#include <stdio.h>
#include <string.h>
// TODO: Defina a struct BankAccount aqui
// TODO: Escreva a função depositMoney aqui
// TODO: Escreva a função withdrawMoney aqui
// TODO: Escreva a função displayAccount aqui
int main() {
// Ler entrada
int accountNum;
char ownerName[30];
float initialBalance;
float depositAmount;
float withdrawAmount;
scanf("%d", &accountNum);
scanf("%s", ownerName);
scanf("%f", &initialBalance);
scanf("%f", &depositAmount);
scanf("%f", &withdrawAmount);
// TODO: Criar a variável BankAccount e inicializá-la
// TODO: Chamar displayAccount para mostrar o estado inicial
// TODO: Chamar depositMoney com o valor do depósito
// TODO: Chamar withdrawMoney com o valor do saque
// TODO: Chamar displayAccount para mostrar o estado final
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 Logic & Flow
1Fundamentos de Ponteiros
O que é um Ponteiro?Declarando PonteirosO Operador de Endereço (&)O Operador de Desreferência (*)Ponteiros NULLRecapitulação: Fundamentos de Ponteiros4Projeto: Utilitário de Texto Simples
Visão Geral do ProjetoContando Caracteres2Ponteiros e Arrays
Nomes de Arrays como PonteirosElementos de Array - PonteirosAritmética de PonteirosComparando PonteirosRecapitulação: Percorrendo Arrays com Ponteiros5Ponteiros e Funções
Passagem por ValorPassando Ponteiros para FunçõesModificando Variáveis via PonteirosUm Exemplo Clássico: SwapPassando Arrays para FunçõesRecapitulação: Ponteiros como Argumentos8Structs e Ponteiros
Ponteiros para StructsO Operador Seta (->)Passagem de Structs por ValorPassagem de Ponteiros para StructsAlocação Dinâmica de StructsRecapitulação: Modificando Struct - Ptr3Arrays de Caracteres e Strings
Strings como Arrays de charO Terminador NuloEntrada de Strings com scanfUsando strlen()Usando strcpy()Usando strcat()Usando strcmp()Recapitulação: Funções Básicas de Strings6Gerenciamento de Memória
Memória Stack vs. HeapAlocação Dinâmica - malloc()Usando sizeof() para AlocaçãoVerificando Falhas de AlocaçãoLiberando Memória com free()Alocando com calloc()Recapitulação: Array Dinâmico9Projeto: Cadastro Simples de Contatos
Projeto: Definir a Struct de ContatoFunção para Criar um Contato