C++: Passagem de Parâmetros de Função
Última atualização: 2026-08-26
Na Aula 10 aprendemos fundamentos de funções e como funções podem receber parâmetros.
Mas como exatamente os parâmetros são passados para as funções? Se um parâmetro é modificado dentro da função, a variável externa muda?
É isso que esta aula cobre — métodos de passagem de parâmetros.
1. Passagem por Valor
(1) 1.1 Uso Básico
Passagem por valor é o método padrão de passagem de parâmetros em C++ — o valor do argumento é copiado para o parâmetro.
#include <iostream>
void modifyValue(int x) { // x é um parâmetro (cópia)
x = 100; // Modifica a cópia, não afeta a variável original
std::cout << "x in function = " << x << std::endl;
}
int main() {
int a = 5;
modifyValue(a); // Passagem por valor: o valor de a é copiado para x
std::cout << "a in main = " << a << std::endl; // a ainda é 5
return 0;
}
💡 Ponto-chave: Com passagem por valor, modificar o parâmetro dentro da função não afeta o argumento.
(2) 1.2 Prós e Contras da Passagem por Valor
| Prós | Contras |
|---|---|
| Seguro (a função não pode modificar o argumento) | Objetos grandes são caros para copiar (ex: arrays grandes, structs grandes) |
| Lógica clara | Não permite que a função "retorne" múltiplos valores |
2. Passagem por Ponteiro
Se você quer que uma função modifique uma variável externa, pode passar seu endereço (ponteiro).
(1) 2.1 Uso Básico
#include <iostream>
void modifyValue(int* x) { // x é um ponteiro
*x = 100; // Desreferência: modifica o valor que o ponteiro aponta
std::cout << "*x in function = " << *x << std::endl;
}
int main() {
int a = 5;
modifyValue(&a); // Passa endereço: passa o endereço de a para a função
std::cout << "a in main = " << a << std::endl; // a agora é 100
return 0;
}
💡 Ponto-chave: Com passagem por ponteiro, a função pode modificar o valor do argumento através do ponteiro.
(2) 2.2 Por Que Pode Modificar?
| Passo | Explicação |
|---|---|
| 1 | int a = 5; — Aloca espaço na memória e armazena 5 |
| 2 | modifyValue(&a); — Passa o endereço de a para a função |
| 3 | int* x recebe o endereço, apontando para o espaço de memória de a |
| 4 | *x = 100; — Modifica o valor de a através do ponteiro |
3. Passagem por Referência
C++ introduziu referências — elas são "apelidos" para variáveis, mais seguras e fáceis de usar que ponteiros.
(1) 3.1 Uso Básico
#include <iostream>
void modifyValue(int& x) { // x é uma referência (apelido)
x = 100; // Modificar x modifica a variável original
std::cout << "x in function = " << x << std::endl;
}
int main() {
int a = 5;
modifyValue(a); // Passagem por referência: não precisa de &, parece passagem por valor
std::cout << "a in main = " << a << std::endl; // a agora é 100
return 0;
}
💡 Ponto-chave: Com passagem por referência, o parâmetro é um apelido do argumento — modificar o parâmetro modifica o argumento.
(2) 3.2 Referência vs Ponteiro
| Comparação | Referência | Ponteiro |
|---|---|---|
| Sintaxe | int& x = a; |
int* x = &a; |
| Pode ser nulo | ❌ Não (deve ser inicializado) | ✅ Sim (pode ser nullptr) |
| Precisa desreferenciar | ❌ Não (usa diretamente) | ✅ Sim (usa *x) |
| Pode religar | ❌ Não (uma vez vinculado, não pode mudar) | ✅ Sim (pode apontar para outra variável) |
| Recomendação | ⭐⭐⭐⭐⭐ (preferir) | ⭐⭐⭐ (usar quando necessário) |
4. Comparação dos Três Métodos de Passagem
▶ Exemplo 1: Trocar Duas Variáveis (Dificuldade ⭐⭐)
Método 1: Passagem por Valor (Falha)
#include <iostream>
void swapFailed(int a, int b) { // ❌ Passagem por valor: modifica cópias
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 3, y = 5;
swapFailed(x, y);
std::cout << "x = " << x << ", y = " << y << std::endl; // x=3, y=5 (não trocados)
return 0;
}
Saída:
x = 5, y = 3
Método 2: Passagem por Ponteiro (Funciona)
#include <iostream>
void swapPointer(int* a, int* b) { // ✅ Passagem por ponteiro
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 3, y = 5;
swapPointer(&x, &y);
std::cout << "x = " << x << ", y = " << y << std::endl; // x=5, y=3 (trocados)
return 0;
}
Método 3: Passagem por Referência (Funciona, Recomendado)
#include <iostream>
void swapReference(int& a, int& b) { // ✅ Passagem por referência (recomendado)
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 3, y = 5;
swapReference(x, y); // Parece passagem por valor, mas é passagem por referência
std::cout << "x = " << x << ", y = " << y << std::endl; // x=5, y=3 (trocados)
return 0;
}
5. Quando Usar Qual Método de Passagem?
| Cenário | Método Recomendado | Razão |
|---|---|---|
| Função não precisa modificar o parâmetro | Passagem por valor ou passagem por referência const | Seguro e claro |
| Função precisa modificar o parâmetro | Passagem por referência | Sintaxe concisa, segura |
| Precisa "retornar" múltiplos valores | Passagem por referência | A função pode modificar múltiplos parâmetros de referência |
| Parâmetro é um objeto grande (array, struct) | Passagem por referência const | Evita custo de cópia |
| Precisa representar "nada" (ex: busca falhou) | Passagem por ponteiro | Ponteiro pode ser nullptr |
💡 Regra de ouro: Prefira passagem por referência, use passagem por ponteiro quando necessário, e passagem por valor para objetos pequenos.
6. Referência const
Se você não quer que a função modifique o parâmetro mas quer evitar o custo de cópia, use uma referência const.
#include <iostream>
#include <string>
void printName(const std::string& name) { // referência const: não pode modificar name
std::cout << "Name: " << name << std::endl;
// name = "Alice"; // ❌ Erro: não pode modificar uma referência const
}
int main() {
std::string myName = "MOTO";
printName(myName); // Não precisa copiar a string inteira — eficiente
return 0;
}
💡 Ponto-chave: referência const é um dos métodos de passagem de parâmetros mais usados em C++, equilibrando segurança e eficiência.
7. Arrays como Parâmetros
Quando um array é passado como parâmetro, ele decai para um ponteiro (coberto em detalhes mais tarde).
#include <iostream>
// Array como parâmetro, precisa passar o comprimento
void printArray(int arr, int length) {
for (int i = 0; i < length; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
int main() {
int myArray[5] = {1, 2, 3, 4, 5};
printArray(myArray, 5); // Passa nome do array (que é o endereço do primeiro elemento)
return 0;
}
💡 Dica: Quando um array é passado como parâmetro, a função não sabe o comprimento do array — você precisa passar um parâmetro de comprimento adicional.
8. Prática: Múltiplos Valores de Retorno
▶ Exemplo 2: Calcular Quociente e Resto (Dificuldade ⭐⭐)
#include <iostream>
// Usa parâmetros de referência para "retornar" múltiplos valores
void divide(int a, int b, int& quotient, int& remainder) {
quotient = a / b;
remainder = a % b;
}
int main() {
int a = 17, b = 5;
int q, r;
divide(a, b, q, r); // q e r serão modificados
std::cout << a << " / " << b << " = " << q << " ... " << r << std::endl;
// Saída: 17 / 5 = 3 ... 2
return 0;
}
Saída:
17 / 5 = 3 ... 2
▶ Exemplo 3: Parâmetros Padrão (Dificuldade ⭐)
#include <iostream>
#include <string>
// Função com parâmetros padrão
void greet(const std::string& name, const std::string& greeting = "Hello") {
std::cout << greeting << "," << name << "!" << std::endl;
}
int main() {
greet("Zhang San"); // Usa parâmetro padrão
greet("Li Si", "Good morning"); // Especifica parâmetro
greet("Wang Wu", "Good evening"); // Especifica parâmetro
return 0;
}
Saída:
Hello,Zhang San!
Good morning,Li Si!
Good evening,Wang Wu!
Saída esperada:
Hello,Zhang San!
Good morning,Li Si!
Good evening,Wang Wu!
❓ Perguntas Frequentes
P: Qual a diferença real entre referências e ponteiros? R: - Uma referência é um apelido para uma variável; um ponteiro é uma variável que armazena um endereço - Uma referência deve ser inicializada; um ponteiro pode ser
nullptr- Uma referência não pode ser religada; um ponteiro pode - Prefira referências a menos que precise representar "nada" (então use ponteiro) P: Por que não preciso especificar o comprimento ao passar um array como parâmetro? R: Porque arrays decaem para ponteiros.void foo(int arr)é equivalente avoid foo(int* arr)— arr é na verdade um ponteiro, não um array. P: Qual é mais eficiente: passagem por valor, por referência ou por ponteiro? R: - Objetos pequenos (comoint): passagem por valor é mais eficiente (pequeno custo de cópia) - Objetos grandes (como arrays grandes, structs grandes): passagem por referência const é mais eficiente (evita cópia) - Quando precisa modificar um parâmetro: passagem por referência é melhor (sintaxe concisa)
P: O que é mais importante sobre parâmetros de função? R: Entenda os conceitos centrais primeiro, depois reforce-os através de exemplos práticos.
P: Como praticar parâmetros de função de forma eficiente? R: Comece com exemplos simples, aumente a dificuldade gradualmente, e sempre teste seu código.
📖 Resumo
- Passagem por valor: Faz uma cópia; modificações dentro da função não afetam o exterior
- Passagem por ponteiro: Passa um endereço; a função pode modificar o exterior através do ponteiro
- Passagem por referência: Passa um apelido; modificações dentro da função afetam o exterior (recomendado)
- Referência const: Não pode modificar, mas evita custo de cópia (mais usada)
- Arrays decaem para ponteiros quando passados como parâmetros; um parâmetro de comprimento adicional é necessário
📝 Exercícios
-
Básico (Dificuldade ⭐): Escreva uma função
void addTen(int& x)que adiciona 10 à variável passada. Teste-a emmain. -
Intermediário (Dificuldade ⭐⭐): Escreva uma função
void minMax(int arr, int length, int& min, int& max)que encontre os valores mínimo e máximo em um array (usando parâmetros de referência para "retorná-los"). -
Desafio (Dificuldade ⭐⭐⭐): Escreva um programa que implemente "ordenar três números":
-
Escreva uma função
void sortThree(int& a, int& b, int& c)que ordene três números do menor para o maior -
Em
main, deixe o usuário digitar três números, chamesortThree, depois exiba o resultado ordenado
- Passagem por valor: copia o parâmetro; modificações dentro da função não afetam o exterior
- Passagem por referência: compartilha memória; modificações dentro da função afetam o exterior
- Parâmetros padrão vão da direita para esquerda; podem ser omitidos ao chamar
- Sobrecarga de funções: mesmo nome com parâmetros diferentes; determinada em tempo de compilação
- Referência const protege parâmetros de modificação enquanto evita cópia
9. 🚀 Próximo Passo
Agora que você aprendeu passagem de parâmetros, a seguir vamos aprender recursão (Aula 12) — a técnica incrível de uma função chamar a si mesma!