C++: 实战:指针与引用综合
最后更新:2026-08-26
前面的课程我们分开了讲指针和引用,但真实程序里它们是混在一起用的。
这一课,我们通过几个综合实例,练习如何让指针和引用协同工作。
1. 实例一:用指针实现字符串反转*
▶ 示例 1:字符串反转(难度⭐⭐)
#include <iostream>
#include <cstring>
void reverseString(char* str) {
int len = std::strlen(str);
char* left = str;
char* right = str + len - 1;
while (left < right) {
// 交换 left 和 right 指向的字符
char temp = *left;
*left = *right;
*right = temp;
left++;
right--;
}
}
int main() {
char str = "Hello, World!";
std::cout << "反转前:" << str << std::endl;
reverseString(str);
std::cout << "反转后:" << str << std::endl;
return 0;
}
输出:
反转前:
反转后:
2. 实例二:动态结构体数组*
▶ 示例 2:动态分配学生数组(难度⭐⭐⭐)
#include <iostream>
#include <string>
struct Student {
std::string name;
int age;
double score;
};
int main() {
int n;
std::cout << "请输入学生数量:";
std::cin >> n;
// 动态分配 Student 数组
Student* students = new Student[n];
// 输入学生信息
for (int i = 0; i < n; i++) {
std::cout << "请输入第 " << i + 1 << " 个学生的姓名:";
std::cin.ignore();
std::getline(std::cin, students[i].name);
std::cout << "请输入年龄:";
std::cin >> students[i].age;
std::cout << "请输入成绩:";
std::cin >> students[i].score;
}
// 输出所有学生信息
std::cout << "\n========== 学生列表 ==========\n";
for (int i = 0; i < n; i++) {
std::cout << i + 1 << ". " << students[i].name
<< ",年龄:" << students[i].age
<< ",成绩:" << students[i].score << std::endl;
}
// 释放内存
delete students;
return 0;
}
输出:
请输入学生数量:
请输入第 个学生的姓名:
请输入年龄:
请输入成绩:
========== 学生列表 ==========
.
3. 实例三:链表基础(选学)*
(1) 3.1 什么是链表?
链表是一种动态数据结构——每个元素(节点)存数据和指向下一个节点的指针。
| 生活场景 | 程序中的对应 |
|---|---|
| 寻宝游戏(每张纸条指向下一张纸条的位置) | 链表 |
▶ 示例 3:简单的链表(难度⭐⭐⭐)
#include <iostream>
struct Node {
int data;
Node* next;
};
int main() {
// 创建节点
Node* head = new Node{1, nullptr};
Node* second = new Node{2, nullptr};
Node* third = new Node{3, nullptr};
// 连接节点
head->next = second;
second->next = third;
// 遍历链表
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
// 释放内存
delete head;
delete second;
delete third;
return 0;
}
输出:
💡 提示: 链表是数据结构的重要内容,这里只是简单介绍。后面会学更多数据结构。
4. 实战练习:通讯录(动态内存版)*
▶ 示例 4:动态通讯录(难度⭐⭐⭐)
#include <iostream>
#include <string>
#include <cstring>
struct Contact {
char name[50];
char phone[20];
Contact* next; // 链表指针
};
Contact* head = nullptr; // 链表头指针
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; // 新节点指向原头节点
head = newContact; // 更新头节点
}
void printContacts() {
if (head == nullptr) {
std::cout << "通讯录为空!" << std::endl;
return;
}
std::cout << "\n========== 通讯录 ==========\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();
// 释放内存(选做)
// ...
return 0;
}
输出:
通讯录为空!
========== 通讯录 ==========
.
❓ 常见问题
Q:什么时候用指针,什么时候用引用? A:> - 如果参数可能被修改,且需要表示"没有"(如查找失败)→ 指针(
nullptr) > - 如果参数可能被修改,但一定有值 → 引用 > - 如果参数不需要被修改 → const 引用(推荐) > - 如果需要动态分配内存 → 指针(new) Q:为什么链表比数组好? A:> - 数组:大小固定,插入/删除元素要移动后面的所有元素(慢) > - 链表:大小动态,插入/删除元素只要改指针(快)但链表也有缺点:不能随机访问(要找第 i 个元素,必须从头遍历)。
Q:怎么避免内存泄漏? A:> 1. 确保
new和delete成对出现 > 2. 释放后立即设为nullptr> 3. 用智能指针(std::unique_ptr、std::shared_ptr,后面会学)
Q:关于practice pointers最重要的是什么? A:先理解核心概念,再通过实践例子来巩固。
📖 小节
- 指针和引用可以混用——引用让代码简洁,指针处理动态内存
- 用指针可以实现动态数据结构(如链表、树、图)
- 动态分配内存后,一定要记得释放(
delete) - 链表是动态数据结构的基础
📝 作业
-
基础题 (Difficulty ⭐): 写一个函数
void swap(int* a, int* b),用指针交换两个变量的值。 -
进阶题 (Difficulty ⭐⭐): 写一个程序,用动态内存分配一个
int数组,让用户输入数组大小和内容,然后反转数组并输出。 -
挑战题 (Difficulty ⭐⭐⭐): 扩展"动态通讯录"程序:
-
添加"删除联系人"功能
-
添加"查找联系人"功能
-
程序结束时释放所有动态分配的内存
- 指针函数参数:修改外部变量的值
- 动态数组:运行时确定大小,用完释放
- 函数返回指针需确保内存不被释放
- 引用传递比指针语法更简洁
- nullptr 检查避免解引用空指针
5. 🚀 下一步*
恭喜你!Phase 4(指针与引用)的所有课程都学完了。 接下来我们进入 Phase 5(面向对象编程)——学习 C++ 最核心的特性,理解类、对象、继承、多态!