Ponteiro vs Valor
Parte da seção Object Oriented Programming do Journey de C da Coddy — lição 9 de 61.
Quando você passa uma struct para uma função, o C oferece duas opções: passá-la por valor (copiar a struct inteira) ou passá-la por ponteiro (copiar apenas o endereço). A escolha é significativamente importante para o desempenho.
A passagem por valor cria uma cópia completa da struct na stack. Para uma struct pequena com alguns inteiros, isso não tem problema. Mas imagine uma struct com centenas de bytes — cada chamada de função copia todos esses dados:
typedef struct {
char name[100];
int scores[50];
double average;
} Student;
// Por valor: copia ~608 bytes a cada chamada
void print_by_value(Student s) {
printf("%s: %.2f\n", s.name, s.average);
}
// Por ponteiro: copia apenas 8 bytes (o endereço)
void print_by_pointer(const Student *s) {
printf("%s: %.2f\n", s->name, s->average);
}
A sintaxe também difere. Com um parâmetro de valor, você usa o operador de ponto (s.name). Com um ponteiro, você usa o operador de seta (s->name).
A versão com ponteiro é mais eficiente porque ela apenas passa um endereço de memória — tipicamente 8 bytes, independentemente do tamanho da struct.
É por isso que programadores C quase sempre passam structs por ponteiro. Use const quando a função não deve modificar os dados, e um ponteiro comum quando deve. Você obtém tanto eficiência quanto uma intenção clara.
Desafio
FácilVamos construir um módulo Product que demonstra a diferença entre passar structs por valor e por ponteiro. Você criará duas funções de exibição — uma que recebe a struct inteira como uma cópia e outra que recebe apenas um ponteiro para ela.
Você criará três arquivos:
product.h: Declare uma structProductcom três membros:char name[50],double priceeint quantity. Também declare duas funções:display_by_value— recebe umProductpor valor e imprime suas informaçõesdisplay_by_pointer— recebe umconst Product *e imprime as mesmas informações
PRODUCT_H.product.c: Implemente ambas as funções. Observe a diferença de sintaxe: a versão por valor usa o operador ponto (p.name), enquanto a versão por ponteiro usa o operador seta (p->name). Ambas as funções devem imprimir no mesmo formato.main.c: Crie um Product, então chame ambas as funções de exibição para mostrar que elas produzem uma saída idêntica, apesar de usarem estilos de parâmetros diferentes.
Você receberá três entradas: o nome do produto (uma string), o preço (um double) e a quantidade (um inteiro).
Em seu arquivo principal, inicialize um Product com esses valores, então chame display_by_value seguido por display_by_pointer.
Ambas as funções devem imprimir neste formato:
Product: {name}, Price: {price}, Qty: {quantity}Use %.2f para o preço para exibir duas casas decimais.
Por exemplo, com as entradas Laptop, 999.99 e 5, a saída seria:
Product: Laptop, Price: 999.99, Qty: 5
Product: Laptop, Price: 999.99, Qty: 5Folha de consulta
Ao passar structs para funções, você pode escolher entre passagem por valor (copiando a struct inteira) ou passagem por ponteiro (copiando apenas o endereço).
A passagem por valor cria uma cópia completa da struct:
void print_by_value(Student s) {
printf("%s: %.2f\n", s.name, s.average); // Use dot operator
}
A passagem por ponteiro passa apenas o endereço de memória:
void print_by_pointer(const Student *s) {
printf("%s: %.2f\n", s->name, s->average); // Use arrow operator
}
Principais diferenças:
- Por valor utiliza o operador ponto (
s.member) - Por ponteiro utiliza o operador seta (
s->member) - Ponteiros são mais eficientes para structs grandes (apenas 8 bytes vs. o tamanho total da struct)
- Use
constcom ponteiros quando a função não deve modificar os dados
Programadores C normalmente preferem passar structs por ponteiro para obter melhor desempenho.
Experimente você mesmo
#include <stdio.h>
#include <string.h>
#include "product.h"
int main() {
char name[50];
double price;
int quantity;
// Ler as entradas
scanf("%s", name);
scanf("%lf", &price);
scanf("%d", &quantity);
// TODO: Crie uma variável Product e inicialize-a com os valores de entrada
// Dica: Use strcpy para copiar o nome para o campo name da struct
// TODO: Chame display_by_value com o Product
// TODO: Chame display_by_pointer com um ponteiro para o Product
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 Secreta2Objetos 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