C++: Practice: Pointers and References Comprehensive
Last updated: 2026-08-26
Previous lessons covered pointers and references separately, but in real programs they are used together.
In this lesson, we'll practice making pointers and references work together through several comprehensive examples.
1. Example 1: String Reversal Using Pointers*
▶ Example 1: String Reversal (Difficulty ⭐⭐)
#include <iostream>
#include <cstring>
void reverseString(char* str) {
int len = std::strlen(str);
char* left = str;
char* right = str + len - 1;
while (left < right) {
// Swap characters pointed to by left and 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;
}
Output:
Before reversal:
After reversal:
2. Example 2: Dynamic Struct Array*
▶ Example 2: Dynamically Allocating Student Array (Difficulty ⭐⭐⭐)
#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;
// Dynamically allocate Student array
Student* students = new Student[n];
// Input student information
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;
}
// Output all student information
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;
}
// Free memory
delete[] students;
return 0;
}
Output:
Enter number of students:
Enter name for student :
Enter age:
Enter score:
========== Student List ==========
.
3. Example 3: Linked List Basics (Optional)*
(1) 3.1 What is a Linked List?
A linked list is a dynamic data structure — each element (node) stores data and a pointer to the next node.
| Real-life Analogy | Programming Equivalent |
|---|---|
| Treasure hunt (each clue points to the next clue's location) | Linked list |
▶ Example 3: Simple Linked List (Difficulty ⭐⭐⭐)
#include <iostream>
struct Node {
int data;
Node* next;
};
int main() {
// Create nodes
Node* head = new Node{1, nullptr};
Node* second = new Node{2, nullptr};
Node* third = new Node{3, nullptr};
// Link nodes
head->next = second;
second->next = third;
// Traverse linked list
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
// Free memory
delete head;
delete second;
delete third;
return 0;
}
Output:
💡 Tip: Linked lists are an important topic in data structures — this is just a brief introduction. You'll learn more data structures later.
4. Practice Exercise: Address Book (Dynamic Memory Version)*
▶ Example 4: Dynamic Address Book (Difficulty ⭐⭐⭐)
#include <iostream>
#include <string>
#include <cstring>
struct Contact {
char name[50];
char phone[20];
Contact* next; // Linked list pointer
};
Contact* head = nullptr; // Linked list head pointer
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; // New node points to original head
head = newContact; // Update head
}
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();
// Free memory (optional)
// ...
return 0;
}
Output:
Address book is empty!
========== Address Book ==========
.
❓ FAQ
Q: When should I use pointers vs references? A:> - If a parameter may be modified and needs to represent "nothing" (e.g., search failure) → pointer (
nullptr) > - If a parameter may be modified but always has a value → reference > - If a parameter doesn't need to be modified → const reference (recommended) > - If dynamic memory allocation is needed → pointer (new) Q: Why are linked lists better than arrays? A:> - Array: fixed size, inserting/deleting requires shifting all subsequent elements (slow) > - Linked list: dynamic size, inserting/deleting only requires changing pointers (fast)But linked lists also have disadvantages: no random access (to find the ith element, you must traverse from the head).
Q: How to avoid memory leaks? A:> 1. Ensure
newanddeleteare paired > 2. Set pointer tonullptrimmediately after freeing > 3. Use smart pointers (std::unique_ptr,std::shared_ptr, covered later)
Q: What's most important about practice with pointers? A: Understand the core concepts first, then solidify them through practical examples.
📖 Summary
- Pointers and references can be mixed — references make code concise, pointers handle dynamic memory
- Pointers can implement dynamic data structures (e.g., linked lists, trees, graphs)
- After dynamically allocating memory, always remember to free it (
delete) - Linked lists are the foundation of dynamic data structures
📝 Exercises
-
Basic (Difficulty ⭐): Write a function
void swap(int* a, int* b)that swaps two variables' values using pointers. -
Intermediate (Difficulty ⭐⭐): Write a program that dynamically allocates an
intarray, lets the user input the array size and contents, then reverses the array and outputs it. -
Challenge (Difficulty ⭐⭐⭐): Extend the "Dynamic Address Book" program:
- Add a "delete contact" feature
- Add a "search contact" feature
- Free all dynamically allocated memory when the program ends
- Pointer function parameters: modify external variable values
- Dynamic arrays: determine size at runtime, free when done
- Functions returning pointers must ensure memory isn't freed prematurely
- Pass-by-reference syntax is more concise than pointers
- nullptr checks prevent dereferencing null pointers
5. 🚀 Next Steps*
Congratulations! You've completed all lessons in Phase 4 (Pointers and References). Next, we enter Phase 5 (Object-Oriented Programming) — learning C++'s most core feature, understanding classes, objects, inheritance, and polymorphism!