Passagem de parâmetros
Nesta aula, exploramos as duas formas de passagem de parâmetros em C: por valor e por referência. Discutimos como a passagem por valor cria cópias das variáveis, impedindo alterações no original, e introduzimos o conceito de ponteiros para modificar variáveis fora da função. Exemplos práticos ilustram cada abordagem.
Em C, a forma como passamos argumentos para funções determina se as modificações dentro da função afetam as variáveis originais. A linguagem oferece duas maneiras: passagem por valor (padrão) e passagem por referência (simulada com ponteiros). Compreender essa diferença é essencial para escrever código correto e eficiente.
Nesta aula, vamos detalhar cada método, mostrar suas limitações e apresentar exemplos práticos. Ao final, você saberá quando usar cada abordagem e como implementar a passagem por referência em C.
Por valor
Na passagem por valor, o valor da variável é copiado para o parâmetro da função. Dentro da função, trabalhamos com uma cópia independente; alterações no parâmetro não afetam a variável original. Esse é o comportamento padrão em C para todos os tipos de dados (int, float, char, etc.).
Exemplo: uma função que tenta trocar dois números usando passagem por valor não consegue alterar os valores originais.
#include <stdio.h>
void trocar(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
printf("Antes: x = %d, y = %d\n", x, y);
trocar(x, y);
printf("Depois: x = %d, y = %d\n", x, y);
return 0;
}A saída será: Antes: x = 10, y = 20 e Depois: x = 10, y = 20. A troca não ocorreu porque as variáveis a e b são cópias locais.
Limitação (não altera o original)
A principal limitação da passagem por valor é que funções não podem modificar variáveis do escopo chamador. Isso é intencional: protege os dados originais de alterações acidentais. Porém, quando precisamos que a função altere o valor original (por exemplo, em funções de troca, incremento ou leitura de dados), a passagem por valor se torna insuficiente.
Outra limitação: para tipos grandes (como structs grandes), copiar todo o valor pode ser ineficiente em termos de tempo e memória. Nesses casos, passar um ponteiro (referência) é mais eficiente.
Introdução a passar por referência
C não possui passagem por referência como C++ ou Java. Em vez disso, usamos ponteiros para simular esse comportamento. Passamos o endereço da variável (usando o operador &) e a função recebe um ponteiro. Dentro da função, desreferenciamos o ponteiro (com *) para acessar e modificar o valor original.
Exemplo: a função trocar agora recebe ponteiros para inteiros.
#include <stdio.h>
void trocar(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
printf("Antes: x = %d, y = %d\n", x, y);
trocar(&x, &y);
printf("Depois: x = %d, y = %d\n", x, y);
return 0;
}Agora a saída será: Depois: x = 20, y = 10. A função alterou as variáveis originais porque trabalhou com seus endereços.
Exemplos
Vamos ver mais exemplos práticos de passagem por referência.
Exemplo 1: Função que dobra o valor de uma variável
#include <stdio.h>
void dobrar(int *n) {
*n *= 2;
}
int main() {
int valor = 5;
printf("Antes: %d\n", valor);
dobrar(&valor);
printf("Depois: %d\n", valor);
return 0;
}Saída: Antes: 5 e Depois: 10.
Exemplo 2: Função que retorna múltiplos valores via parâmetros
#include <stdio.h>
void dividir(int dividendo, int divisor, int *quociente, int *resto) {
*quociente = dividendo / divisor;
*resto = dividendo % divisor;
}
int main() {
int a = 17, b = 5;
int q, r;
dividir(a, b, &q, &r);
printf("%d dividido por %d: quociente = %d, resto = %d\n", a, b, q, r);
return 0;
}Saída: 17 dividido por 5: quociente = 3, resto = 2.
Exemplo 3: Passagem de arrays (sempre por referência)
Em C, arrays são passados por referência automaticamente (o nome do array é um ponteiro).
#include <stdio.h>
void preencher(int arr[], int tamanho) {
for (int i = 0; i < tamanho; i++) {
arr[i] = i * 10;
}
}
int main() {
int vetor[5];
preencher(vetor, 5);
for (int i = 0; i < 5; i++) {
printf("%d ", vetor[i]);
}
return 0;
}Saída: 0 10 20 30 40.
Boas práticas
Use passagem por valor para tipos simples quando a função não precisa modificar o original. Use ponteiros (passagem por referência) quando precisar alterar o valor ou quando o tipo for grande. Sempre documente se um parâmetro ponteiro é usado para modificar o valor ou apenas para leitura (use const quando apropriado).
Referências
- cppreference: Function call
- Learn-C.org: Functions
- GNU C Manual: Function Calls
- Tutorialspoint: C Functions
- Wikipedia: Evaluation strategy
Exercícios
Crie uma função que recebe um inteiro por valor e tenta somar 10 a ele. Mostre que o valor original não é alterado.
✓ Resposta:#include <stdio.h> void somar10(int n) { n += 10; } int main() { int x = 5; printf("Antes: %d\n", x); somar10(x); printf("Depois: %d\n", x); return 0; }Saída: Antes: 5, Depois: 5.
Escreva uma função que recebe um ponteiro para inteiro e dobra o valor da variável apontada. Teste com um exemplo.
✓ Resposta:#include <stdio.h> void dobrar(int *p) { *p *= 2; } int main() { int v = 7; printf("Antes: %d\n", v); dobrar(&v); printf("Depois: %d\n", v); return 0; }Implemente uma função que recebe dois ponteiros para inteiros e troca seus valores.
✓ Resposta:#include <stdio.h> void trocar(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int main() { int x = 3, y = 8; printf("Antes: x=%d, y=%d\n", x, y); trocar(&x, &y); printf("Depois: x=%d, y=%d\n", x, y); return 0; }Crie uma função que recebe um array de inteiros e seu tamanho, e preenche o array com números pares (0, 2, 4, ...). Use passagem por referência.
✓ Resposta:#include <stdio.h> void preencherPares(int arr[], int n) { for (int i = 0; i < n; i++) { arr[i] = i * 2; } } int main() { int vetor[5]; preencherPares(vetor, 5); for (int i = 0; i < 5; i++) { printf("%d ", vetor[i]); } return 0; }Escreva uma função que recebe um ponteiro para um float e o eleva ao quadrado. Teste com um valor.
✓ Resposta:#include <stdio.h> void quadrado(float *p) { *p = (*p) * (*p); } int main() { float x = 2.5; printf("Antes: %.2f\n", x); quadrado(&x); printf("Depois: %.2f\n", x); return 0; }