You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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++直到越界。
  • 修复:
    1. 把循环改为while (getline(infile, str)),仅当成功读取一行时进入循环。
    2. 读取字符时添加i < str.size()的判断,防止下标越界。
    3. 跳过空行,避免处理无效数据。
      修改后的读取代码:
    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函数的潜在问题

  • 问题:
    1. 若链表为空(head为NULL),直接访问p->student.ssn会崩溃。
    2. 无论是否找到并删除学生,都会执行length--,导致length值与实际链表长度不符。
  • 修复:
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 17:52:02