使用 new/delete 手動管理堆內存,實現學生信息單向鏈表的創建、輸入、打印、銷毀,體現 RAII 前時代的資源管理邏輯。
struct Student {
char name[20];
int age;
int sex; // 1 男, 0 女
Student* next;
};
採用尾插法保持輸入順序。傳遞 Student** headRef 以便修改主調用者的頭指針。
void createList(int n, Student** headRef) {
Student *tail = nullptr;
for (int i = 1; i <= n; ++i) {
Student* node = new Student();
cout << "第 " << i << " 位學生 (姓名 年齡 性別[1男/0女]):";
cin >> node->name >> node->age >> node->sex;
node->next = nullptr;
if (*headRef == nullptr) {
*headRef = node;
} else {
tail->next = node;
}
tail = node;
}
}
void printList(const Student* head) {
cout << "\n學生信息:\n";
for (const Student* p = head; p; p = p->next) {
cout << p->name << '\t' << p->age << '\t' << (p->sex ? "男" : "女") << '\n';
}
}
void destroyList(Student* head) {
while (head) {
Student* next = head->next;
delete head;
head = next;
}
}
int main() {
int n;
cout << "請輸入學生人數:";
cin >> n;
Student* head = nullptr;
createList(n, &head);
printList(head);
destroyList(head); // 歸還所有堆內存
head = nullptr; // 防止懸空指針
return 0;
}
| 操作 | 說明 |
|---|---|
new Student() | 分配堆內存,調用默認構造函數(POD 類型不初始化成員)。 |
delete ptr | 釋放單個節點內存,調用析構函數(此處無析構函數)。 |
| 遍歷釋放 | 必須先保存 next 再 delete current,否則訪問已釋放內存。 |
| 置空指針 | 釋放後將頭指針/遍歷指針置 nullptr,防止二次釋放/懸空訪問。 |
#include
struct Student {
string name;
int age, sex;
unique_ptr next; // 獨擁所有權,自動遞歸釋放
};
void createList(int n, unique_ptr& head) {
Student* tail = nullptr;
for (int i=1;i<=n;++i) {
auto node = make_unique();
cin >> node->name >> node->age >> node->sex;
if (!head) head = move(node);
else tail->next = move(node);
tail = head.get(); // 找到尾節點(簡化版,實際需循環到尾)
}
}
// 無需手動 destroyList,unique_ptr 析構時遞歸釋放整條鏈
優勢:異常安全、無內存洩漏、無懸空指針、所有權語義清晰。生產代碼首選智能指針。
手動實現鏈表是理解指針、堆內存、所有權轉移的經典練習。掌握 new/delete 配對、雙指針遍歷、頭指針引用傳遞、銷毀順序,為後續學習智能指針、容器底層實現、系統編程打下堅實基礎。