C++: Prática: Ponteiros e Referências Abrangente
Última atualização: 2026-08-26
Aulas anteriores cobriram ponteiros e referências separadamente, mas em programas reais eles são usados juntos.
Nesta aula, vamos praticar fazer ponteiros e referências trabalharem juntos através de vários exemplos abrangentes.
1. Exemplo 1: Inversão de String Usando Ponteiros*
▶ Exemplo 1: Inversão de String (Dificuldade ⭐⭐)
#include <iostream>
#include <cstring>
void reverseString(char* str) {
int len = std::strlen(str);
char* left = str;
char* right = str + len - 1;
while (left < right) {
// Trocar caracteres apontados por left e right
char temp = *left;
*left = *right;
*right = temp;
left++;
right--;
}
}
int main() {
char str[] = "Hello, World!";
std::cout << "Before reversal: " << str << std::endl;
reverseString(str);
std::cout << "After reversal: " << str << std::endl;
return 0;
}
Saída:
Before reversal:
After reversal:
2. Exemplo 2: Array Dinâmico de Structs*
▶ Exemplo 2: Alocando Dinamicamente Array de Alunos (Dificuldade ⭐⭐⭐)
#include <iostream>
#include <string>
struct Student {
std::string name;
int age;
double score;
};
int main() {
int n;
std::cout << "Enter number of students: ";
std::cin >> n;
// Alocar dinamicamente array de Student
Student* students = new Student[n];
// Inserir informações dos alunos
for (int i = 0; i < n; i++) {
std::cout << "Enter name for student " << i + 1 << ": ";
std::cin.ignore();
std::getline(std::cin, students[i].name);
std::cout << "Enter age: ";
std::cin >> students[i].age;
std::cout << "Enter score: ";
std::cin >> students[i].score;
}
// Exibir todas as informações dos alunos
std::cout << "\n========== Student List ==========\n";
for (int i = 0; i < n; i++) {
std::cout << i + 1 << ". " << students[i].name
<< ", Age: " << students[i].age
<< ", Score: " << students[i].score << std::endl;
}
// Liberar memória
delete[] students;
return 0;
}
Saída:
Enter number of students:
Enter name for student :
Enter age:
Enter score:
========== Student List ==========
.
3. Exemplo 3: Noções Básicas de Lista Ligada (Opcional)*
(1) 3.1 O Que É uma Lista Ligada?
Uma lista ligada é uma estrutura de dados dinâmica — cada elemento (nó) armazena dados e um ponteiro para o próximo nó.
| Analogia do Mundo Real | Equivalente na Programação |
|---|---|
| Caça ao tesouro (cada pista aponta para a localização da próxima) | Lista ligada |
▶ Exemplo 3: Lista Ligada Simples (Dificuldade ⭐⭐⭐)
#include <iostream>
struct Node {
int data;
Node* next;
};
int main() {
// Criar nós
Node* head = new Node{1, nullptr};
Node* second = new Node{2, nullptr};
Node* third = new Node{3, nullptr};
// Conectar nós
head->next = second;
second->next = third;
// Percorrer lista ligada
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
// Liberar memória
delete head;
delete second;
delete third;
return 0;
}
Saída:
💡 Dica: Listas ligadas são um tópico importante em estruturas de dados — esta é apenas uma breve introdução. Você aprenderá mais estruturas de dados depois.
4. Exercício Prático: Agenda (Versão com Memória Dinâmica)*
▶ Exemplo 4: Agenda Dinâmica (Dificuldade ⭐⭐⭐)
#include <iostream>
#include <string>
#include <cstring>
struct Contact {
char name[50];
char phone[20];
Contact* next; // Ponteiro da lista ligada
};
Contact* head = nullptr; // Ponteiro cabeça da lista ligada
void addContact(const std::string& name, const std::string& phone) {
Contact* newContact = new Contact;
std::strcpy(newContact->name, name.c_str());
std::strcpy(newContact->phone, phone.c_str());
newContact->next = head; // Novo nó aponta para a cabeça original
head = newContact; // Atualizar cabeça
}
void printContacts() {
if (head == nullptr) {
std::cout << "Address book is empty!" << std::endl;
return;
}
std::cout << "\n========== Address Book ==========\n";
Contact* current = head;
int index = 1;
while (current != nullptr) {
std::cout << index << ". " << current->name
<< " - " << current->phone << std::endl;
current = current->next;
index++;
}
}
int main() {
addContact("MOTO", "13800138000");
addContact("Alice", "13900139000");
addContact("Bob", "13700137000");
printContacts();
// Liberar memória (opcional)
// ...
return 0;
}
Saída:
Address book is empty!
========== Address Book ==========
.
❓ Perguntas Frequentes
P: Quando devo usar ponteiros vs referências? R:> - Se um parâmetro pode ser modificado e precisa representar "nada" (ex.: falha na busca) → ponteiro (
nullptr) > - Se um parâmetro pode ser modificado mas sempre tem um valor → referência > - Se um parâmetro não precisa ser modificado → referência const (recomendado) > - Se alocação dinâmica de memória é necessária → ponteiro (new) P: Por que listas ligadas são melhores que arrays? R:> - Array: tamanho fixo, inserir/excluir requer deslocar todos os elementos subsequentes (lento) > - Lista ligada: tamanho dinâmico, inserir/excluir requer apenas mudar ponteiros (rápido)Mas listas ligadas também têm desvantagens: sem acesso aleatório (para encontrar o i-ésimo elemento, você deve percorrer desde o início).
P: Como evitar vazamentos de memória? R:> 1. Garantir que
newedeleteestejam emparelhados > 2. Definir ponteiro paranullptrimediatamente após liberar > 3. Usar smart pointers (std::unique_ptr,std::shared_ptr, cobertos mais tarde)
P: O que é mais importante na prática com ponteiros? R: Entenda os conceitos centrais primeiro, depois solidifique com exemplos práticos.
📖 Resumo
- Ponteiros e referências podem ser misturados — referências tornam o código conciso, ponteiros lidam com memória dinâmica
- Ponteiros podem implementar estruturas de dados dinâmicas (ex.: listas ligadas, árvores, grafos)
- Após alocar memória dinamicamente, sempre lembre-se de liberá-la (
delete) - Listas ligadas são a base das estruturas de dados dinâmicas
📝 Exercícios
-
Básico (Dificuldade ⭐): Escreva uma função
void swap(int* a, int* b)que troque os valores de duas variáveis usando ponteiros. -
Intermediário (Dificuldade ⭐⭐): Escreva um programa que aloque dinamicamente um array de
int, permita que o usuário insira o tamanho e conteúdo do array, depois inverta o array e exiba-o. -
Desafio (Dificuldade ⭐⭐⭐): Estenda o programa "Agenda Dinâmica":
- Adicione um recurso de "excluir contato"
- Adicione um recurso de "buscar contato"
- Libere toda a memória alocada dinamicamente quando o programa terminar
- Parâmetros de função com ponteiro: modificar valores de variáveis externas
- Arrays dinâmicos: determinar tamanho em tempo de execução, liberar quando terminar
- Funções que retornam ponteiros devem garantir que a memória não seja liberada prematuramente
- Sintaxe de passagem por referência é mais concisa que ponteiros
- Verificações de nullptr impedem desreferenciação de ponteiros nulos
5. 🚀 Próximos Passos*
Parabéns! Você completou todas as aulas da Fase 4 (Ponteiros e Referências). A seguir, entramos na Fase 5 (Programação Orientada a Objetos) — aprendendo o recurso mais central do C++, entendendo classes, objetos, herança e polimorfismo!