Passagem de parâmetros
Esta aula explica os mecanismos de passagem de parâmetros em C: por valor, que cria uma cópia local e não altera o original, e por referência (simulada com ponteiros), que permite modificar as variáveis originais. São apresentados exemplos práticos e exercícios para fixação.
A passagem de parâmetros é a forma como funções recebem dados para processamento. Em C, existem duas maneiras principais: por valor e por referência (simulada com ponteiros). Compreender a diferença é essencial para evitar erros e escrever código eficiente.
Nesta aula, veremos como cada método funciona, suas vantagens e limitações, e exemplos práticos que ilustram o comportamento na prática.
Por valor
Na passagem por valor, o argumento passado para a função é copiado para o parâmetro formal. A função trabalha com essa cópia, e qualquer modificação feita nela não afeta a variável original. Isso é o padrão em C para tipos básicos como int, float, char etc.
Exemplo: considere uma função que tenta trocar dois valores. Usando passagem por valor, a troca só ocorre dentro da função.
#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. As variáveis originais não são alteradas.
Limitação (não altera o original)
A principal limitação da passagem por valor é a impossibilidade de modificar variáveis do escopo chamador. Isso é útil quando queremos proteger os dados originais, mas problemático quando precisamos que a função altere o estado externo (como em trocas, leitura de dados, etc.).
Outra limitação é a cópia de grandes estruturas (structs, arrays), que pode ser ineficiente. Arrays, na verdade, são passados como ponteiros (decaindo para ponteiro), mas o conteúdo não é copiado — veremos isso mais adiante.
Introdução a passar por referência
C não possui passagem por referência nativa como C++ ou Java. No entanto, podemos simular esse comportamento usando ponteiros. Passamos o endereço da variável (&var) e a função recebe um ponteiro. Assim, a função pode alterar o valor original através do operador de dereferência (*).
Exemplo: a função trocar reescrita com ponteiros.
#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;
}Saída: Antes: x=10, y=20 e Depois: x=20, y=10. Agora a troca é efetiva.
É importante lembrar que, mesmo usando ponteiros, a passagem ainda é por valor (o valor do ponteiro é copiado), mas o efeito é de referência porque podemos alterar o dado apontado.
Exemplos
Vejamos mais exemplos práticos para consolidar.
Exemplo 1: Função que dobra um valor
#include <stdio.h>
void dobrar(int *num) {
*num *= 2;
}
int main() {
int a = 5;
dobrar(&a);
printf("a = %d\n", a); // 10
return 0;
}Exemplo 2: Lendo múltiplos valores via função
#include <stdio.h>
void ler_valores(int *x, int *y) {
printf("Digite dois inteiros: ");
scanf("%d %d", x, y); // x e y já são endereços
}
int main() {
int a, b;
ler_valores(&a, &b);
printf("Você digitou: %d e %d\n", a, b);
return 0;
}Exemplo 3: Passagem de array (decai para ponteiro)
#include <stdio.h>
void modificar_array(int arr[], int n) {
for (int i = 0; i < n; i++)
arr[i] *= 2;
}
int main() {
int v[] = {1, 2, 3, 4};
modificar_array(v, 4);
for (int i = 0; i < 4; i++)
printf("%d ", v[i]); // 2 4 6 8
return 0;
}Aqui, o array é passado como ponteiro, então as alterações afetam o original.
Boas práticas
Use passagem por valor para tipos pequenos quando não precisar modificar o original. Use ponteiros (referência simulada) quando precisar alterar ou para evitar cópias de grandes estruturas. Sempre documente se a função modifica os parâmetros.
Referências
- cppreference: Functions in C
- GNU C Manual: Function Calls
- TutorialsPoint: Call by Value
- TutorialsPoint: Call by Reference
- Wikipedia: Call by value
Exercícios
- Escreva uma função que receba dois inteiros por valor e retorne a soma. Teste no main.
- Crie uma função que receba um float por referência e o eleve ao quadrado.
- Implemente uma função que troque três variáveis inteiras de forma circular (a recebe b, b recebe c, c recebe a). Use ponteiros.
- Explique por que o código abaixo não funciona como esperado e corrija-o usando passagem por referência: void inc(int x) { x++; }
- Crie uma função que receba um array de inteiros e seu tamanho, e retorne a média (como double). Use passagem por referência (ponteiro) para o array.
#include <stdio.h>
int soma(int a, int b) {
return a + b;
}
int main() {
int x = 3, y = 7;
printf("%d\n", soma(x, y)); // 10
return 0;
}#include <stdio.h>
void quadrado(float *p) {
*p = (*p) * (*p);
}
int main() {
float val = 4.5;
quadrado(&val);
printf("%.2f\n", val); // 20.25
return 0;
}#include <stdio.h>
void trocar_circular(int *a, int *b, int *c) {
int temp = *a;
*a = *b;
*b = *c;
*c = temp;
}
int main() {
int x=1, y=2, z=3;
trocar_circular(&x, &y, &z);
printf("%d %d %d\n", x, y, z); // 2 3 1
return 0;
}O código usa passagem por valor, então x++ incrementa a cópia local, não a original. Correção:
void inc(int *x) {
(*x)++;
}
int main() {
int a = 5;
inc(&a);
printf("%d\n", a); // 6
return 0;
}#include <stdio.h>
double media(int *arr, int n) {
int soma = 0;
for (int i = 0; i < n; i++)
soma += arr[i];
return (double)soma / n;
}
int main() {
int v[] = {10, 20, 30};
printf("%.2f\n", media(v, 3)); // 20.00
return 0;
}