Menu
Coddy logo textTech

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.

challenge icon

Desafio

Fácil

Vamos 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 struct Product com três membros: char name[50], double price e int quantity. Também declare duas funções:
    • display_by_value — recebe um Product por valor e imprime suas informações
    • display_by_pointer — recebe um const Product * e imprime as mesmas informações
    Use include guards com o símbolo 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: 5

Folha 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 const com 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;
}
quiz iconTeste seus conhecimentos

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