C++有序链表实现学生名册时触发string下标越界断言错误求助
有序链表实现学生名册问题排查
作业要求
本次作业需基于有序链表(sorted linked list)实现学生名册,每个学生记录包含name、SSN和grade,使用链表数据结构存储所有学生数据。测试程序需从输入文件读取数据,按SSN顺序插入链表,支持删除指定学生,每次增删操作后打印完整链表。
当前实现代码
StudentLinkedList.h
#include <ostream> #include <iostream> using namespace std; struct StudentData { string name; int ssn; char grade; }; struct StudentNode { StudentData student; StudentNode* next; }; class StudentLinkedList { public: StudentLinkedList(); void addStudent(StudentData student); void deleteStudent(int); void printList(ostream&); private: StudentNode* head; int length; }; StudentLinkedList::StudentLinkedList() { head = NULL; } void StudentLinkedList::addStudent(StudentData student) { StudentNode* temp = new StudentNode();//Creating new node temp->student = student; temp->next = NULL; if (length == 0) { head = temp; } else { int i; StudentNode* p = head; StudentNode* p2 = head; for (i = 0; i < length; i++) { if (student.ssn < p->student.ssn) break; else if (p->next != NULL) { if (i == 0) p = p->next; else { p = p->next; p2 = p2->next;//Making p2 stay before p } } } if (i == 0) {//If SSN is lesser than head SSN temp->next = head; head = temp; } else { int i; StudentNode* p = head; StudentNode* p2 = head; for (i = 0; i < length; i++) { if (student.ssn < p->student.ssn) break; else if (p->next != NULL) { if (i == 0) p = p->next; else { p = p->next; p2 = p2->next;//Making p2 stay before p } } } if (i == 0) {//If SSN is lesser than head SSN temp->next = head; head = temp; } else if (p->next == NULL && p->student.ssn < student.ssn) {//Adding student at the end p->next = temp; } else {//Inserting student in the middle temp->next = p; p2->next = temp; } } length++; } } void StudentLinkedList::deleteStudent(int ssn) { StudentNode* p = head; while (1) { if (p->student.ssn == ssn)//Deleting head { head = p->next; break; } else if (p->next == NULL)//If student not found when there is only 1 node { std::cout << "Student not found!" << std::endl; break; } else { if (p->next->next == NULL) { if (p->next->student.ssn == ssn)//Deleting last node p->next = NULL; else std::cout << "Student not found!" << std::endl; break; } else { if (p->next->student.ssn == ssn) {//Deleting node in the middle p->next = p->next->next; break; } else { p = p->next;//Looping until node is found } } } } length--; } void StudentLinkedList::printList(ostream&) { StudentNode* p = head; while (p != NULL) { cout << p->student.name << " " << p->student.ssn << " " << p->student.grade << std::endl; p = p->next; } }
Driver.cpp
#include "StudentLinkedList.h" #include <fstream> #include <string> int main() { StudentLinkedList slist; StudentData student; fstream infile; infile.open("Student.txt"); int ssn; string str; //Read each student from the file and insert into linked list using while loop while (!infile.eof()) { getline(infile, str); int i = 0; char c = str[i++]; std::string word = ""; while (c != '\t') { word += c; c = str[i++]; } student.name = word; word = ""; c = str[i++]; while (c != '\t')//Extracting student SSN { word += c; c = str[i++]; } student.ssn = std::stoi(word);//Converting string to integer word = ""; c = str[i++]; student.grade = c;//Student Grade //add a student to the student list slist.addStudent(student); } slist.printList(cout); cout << "-----------------------------------------------------" << endl; //Deleting one student from the student linked list!!! cout << "Enter SSN to be deleted : "; int sno; cin >> sno; slist.deleteStudent(sno); slist.printList(cout); return 0; }
问题分析与修复
触发Debug Assertion Failed (string subscript out of range)的核心原因是字符串访问时下标超出范围,结合代码来看,具体问题及修复方案如下:
1. 文件读取逻辑错误(直接导致越界)
- 问题:使用
while (!infile.eof())循环读取文件,会导致最后一次循环读取空字符串(因为eof标志在读取失败后才会触发),此时访问str[i++](i=0)会直接越界。同时,读取字符时没有检查i是否超出字符串长度,若文件行格式错误(缺少制表符),循环会持续i++直到越界。 - 修复:
- 把循环改为
while (getline(infile, str)),仅当成功读取一行时进入循环。 - 读取字符时添加
i < str.size()的判断,防止下标越界。 - 跳过空行,避免处理无效数据。
修改后的读取代码:
while (getline(infile, str)) { if (str.empty()) continue; // 跳过空行 int i = 0; std::string word = ""; // 读取name while (i < str.size() && str[i] != '\t') { word += str[i++]; } if (i >= str.size()) continue; // 格式错误跳过 student.name = word; i++; // 跳过制表符 word = ""; // 读取SSN while (i < str.size() && str[i] != '\t') { word += str[i++]; } if (i >= str.size()) continue; // 格式错误跳过 student.ssn = std::stoi(word); i++; // 跳过制表符 // 读取grade if (i >= str.size()) continue; // 格式错误跳过 student.grade = str[i]; slist.addStudent(student); } - 把循环改为
2. 链表类初始化遗漏
- 问题:
StudentLinkedList构造函数中未初始化length成员变量,初始值为随机垃圾值,导致addStudent中if (length == 0)判断逻辑错误,可能引发后续链表操作异常。 - 修复:在构造函数中初始化
length为0:StudentLinkedList::StudentLinkedList() { head = NULL; length = 0; }
3. deleteStudent函数的潜在问题
- 问题:
- 若链表为空(head为NULL),直接访问
p->student.ssn会崩溃。 - 无论是否找到并删除学生,都会执行
length--,导致length值与实际链表长度不符。
- 若链表为空(head为NULL),直接访问
- 修复:
void StudentLinkedList::deleteStudent(int ssn) { if (head == NULL) { std::cout << "Student not found!" << std::endl; return; } StudentNode* p = head; StudentNode* prev = NULL; bool found = false; while (p != NULL) { if (p->student.ssn == ssn) { found = true; if (prev == NULL) // 删除头节点 { head = p->next; } else // 删除中间或尾节点 { prev->next = p->next; } delete p; // 释放内存,避免内存泄漏 break; } prev = p; p = p->next; } if (found) { length--; } else { std::cout << "Student not found!" << std::endl; } }
4. addStudent函数冗余代码
- 问题:函数内的else块重复执行了一遍for循环,属于冗余代码,不仅浪费资源还容易引发逻辑不一致。
- 修复:删除重复的for循环,直接复用第一次循环的p、p2、i值:
void StudentLinkedList::addStudent(StudentData student) { StudentNode* temp = new StudentNode(); temp->student = student; temp->next = NULL; if (length == 0) { head = temp; } else { int i = 0; StudentNode* p = head; StudentNode* p2 = head; for (; i < length; i++) { if (student.ssn < p->student.ssn) break; if (p->next != NULL) { if (i != 0) { p2 = p2->next; } p = p->next; } else { break; // 已到链表末尾 } } if (i == 0) { // 插入到头部 temp->next = head; head = temp; } else if (p->next == NULL && p->student.ssn < student.ssn) { // 插入到尾部 p->next = temp; } else { // 插入到中间 temp->next = p; p2->next = temp; } } length++; }
5. printList函数参数未使用
- 问题:函数声明了
ostream&参数,但实际直接使用cout,不符合设计意图。 - 修复:使用传入的ostream对象输出:
void StudentLinkedList::printList(ostream& os) { StudentNode* p = head; while (p != NULL) { os << p->student.name << " " << p->student.ssn << " " << p->student.grade << std::endl; p = p->next; } }
内容的提问来源于stack exchange,提问作者oStarZ
相关产品推荐
相关产品推荐

