从C ++中的文件加载数据时出现分段错误

布赖恩·林赛

我的问题的标题可能是该网站上其他许多问题的标题,但是,我遇到的问题可能是我一生中必须面对的最奇怪的事情。

我被分配去binary search tree为数据库设计一个,该数据库包含一长串公司的员工记录。我已经成功实施了该项目,并且一切正常,直到收到教授的电子邮件,要求班上的每个人都通过SSH登录到基于Linux的服务器,并验证项目在该处的编译和运行情况符合预期。

源代码编译的很好,但是,当我运行该应用程序并告诉它加载文件的3000条记录列表时,我遇到了segmentation fault第543条记录(文件中的行)。

我的问题是:考虑到我的计算机上的代码运行正常,是什么可能导致此问题?

对于项目的大小,给我分配多少内存有关系吗?加载数据时是否可能内存不足?

即使我100%确信问题不在我的代码中,但我仍然认为方便您查看一段代码并尝试找出问题。

这是我的employee课:

class employee
{
public:

    employee(){}

    employee(std::string first_name, std::string last_name, unsigned int ID)
    {
        this->first_name = first_name;
        this->last_name = last_name;
        this->ID = ID;
    }

    std::string first_name;
    std::string last_name;
    unsigned int ID;
    employee * left, * right;
};//*root;

这是我用来将文件加载到数据库中的功能:

void createBST(bstree & tree)
{
    string file_name;

    cout << "Enter database file path: ";
    cin >> file_name;

    ifstream file_reader (file_name.c_str());

  //  if (file_reader == NULL)
  //  {
   //     error("\nError: Invalid file path provided!\n\n");
   ///     return;
   // }

    string line;
    for (;;)
    {
        if (!getline(file_reader, line))
            break;

        string tokens[3];
        split(line, tokens);

        string first_name, last_name;
        unsigned int ID;

        last_name = tokens[0];
        first_name = tokens[1];
        ID = std::atoi(tokens[2].c_str());

    //    cout << "INSERTING: " << tokens[2] << "\t" << tokens[0] << "\t" << tokens[1] << endl;

        // insert a new employee object into bstree
        tree.Insert(new employee(first_name, last_name, ID));
    }

    cout << endl << endl << "All employee records have been inserted to database successfully." << endl << endl;

    // close file
    file_reader.close();
}

这是我的binary search tree(bstree):

#include <iomanip>
#include <iostream>
#include "bstree.h"

//--------------------------------------------
// Function: bstree()
// Purpose: Class constructor.
//--------------------------------------------
bstree::bstree()
{
    count = 0;
    root = NULL;
}

//--------------------------------------------
// Function: ~bstree()
// Purpose: Class destructor.
//--------------------------------------------
bstree::~bstree()
{
    ClearTree(root);
    return;
}

//--------------------------------------------
// Function: ClearTree()
// Purpose: Perform a recursive traversal of
//        a tree destroying all nodes.
//--------------------------------------------
void bstree::ClearTree(employee *T)
{
    if(T==NULL) return;  // Nothing to clear
    if(T->left != NULL) ClearTree(T->left); // Clear left sub-tree
    if(T->right != NULL) ClearTree(T->right); // Clear right sub-tree
    delete T;    // Destroy this node
    return;
}

//--------------------------------------------
// Function: isEmpty()
// Purpose: Return TRUE if tree is empty.
//--------------------------------------------
bool bstree::isEmpty()
{
    return(root == NULL);
}


//--------------------------------------------
// Function: DupNode()
// Purpose: Duplicate a node in the tree.  This
//        is used to allow returning a complete
//        structure from the tree without giving
//        access into the tree through the pointers.
// Preconditions: None
// Returns: Pointer to a duplicate of the node arg
//--------------------------------------------
employee *bstree::DupNode(employee * T)
{
    employee *dupNode;

    dupNode = new employee();
    *dupNode = *T;    // Copy the data structure
    dupNode->left = NULL;    // Set the pointers to NULL
    dupNode->right = NULL;
    return dupNode;
}


//--------------------------------------------
// Function: SearchTree()
// Purpose: Perform an iterative search of the tree and
//        return a pointer to a treenode containing the
//        search key or NULL if not found.
// Preconditions: None
// Returns: Pointer to a duplicate of the node found
//--------------------------------------------
employee *bstree::SearchTree(unsigned int Key)
{
    employee *temp;

    temp = root;
    while((temp != NULL) && (temp->ID != Key))
    {
        if(Key < temp->ID)
            temp = temp->left;  // Search key comes before this node.
        else
            temp = temp->right; // Search key comes after this node
    }

    if(temp == NULL)
        return temp;    // Search key not found
    else
        return(DupNode(temp));    // Found it so return a duplicate
}



//--------------------------------------------
// Function: Insert()
// Insert a new node into the tree.
// Preconditions: None
// Returns: int (TRUE if successful, FALSE otherwise)
//--------------------------------------------
bool bstree::Insert(employee *newNode)
{
    employee *temp;
    employee *back;

    temp = root;
    back = NULL;

    while(temp != NULL) // Loop till temp falls out of the tree
    {
        back = temp;
        if(newNode->ID < temp->ID)
            temp = temp->left;
        else if (newNode->ID > temp->ID)
            temp = temp->right;
        else
            return false;
    }

    // Now attach the new node to the node that back points to
    if(back == NULL) // Attach as root node in a new tree
        root = newNode;

    else
    {
        if(newNode->ID < back->ID)
            back->left = newNode;
        else if (newNode->ID > back->ID)
            back->right = newNode;
        else
            return false;
    }

   return true;
}


//--------------------------------------------
// Function: Insert()
// Insert a new node into the tree.
// Preconditions: None
// Returns: int (TRUE if successful, FALSE otherwise)
//--------------------------------------------
bool bstree::Insert(unsigned int Key, string first_name, string last_name)
{
     employee *newNode;

    // Create the new node and copy data into it
    newNode = new employee();
    newNode->ID = Key;
    newNode->first_name = first_name;
    newNode->last_name = last_name;
    newNode->left = newNode->right = NULL;

    // Call other Insert() to do the actual insertion
    return(Insert(newNode));
}

//--------------------------------------------
// Function: Delete()
// Purpose: Delete a node from the tree.
// Preconditions: Tree contains the node to delete
// Returns: int (TRUE if successful, FALSE otherwise)
//--------------------------------------------
bool bstree::Delete(unsigned int Key)
{
    employee *back;
    employee *temp;
    employee *delParent;    // Parent of node to delete
    employee *delNode;      // Node to delete

    temp = root;
    back = NULL;

    // Find the node to delete
    while((temp != NULL) && (Key != temp->ID))
    {
        back = temp;
        if(Key < temp->ID)
            temp = temp->left;
        else
            temp = temp->right;
    }

    if(temp == NULL) // Didn't find the one to delete
        return false;

    else
    {
        if(temp == root) // Deleting the root
        {
            delNode = root;
            delParent = NULL;
        }
        else
        {
            delNode = temp;
            delParent = back;
        }
    }

    // Case 1: Deleting node with no children or one child
    if(delNode->right == NULL)
    {
        if(delParent == NULL)    // If deleting the root
        {
            root = delNode->left;
            delete delNode;
            return true;
        }
        else
        {
            if(delParent->left == delNode)
                delParent->left = delNode->left;
            else
                delParent->right = delNode->left;
                delete delNode;
            return true;
        }
    }
    else // There is at least one child
    {
        if(delNode->left == NULL)    // Only 1 child and it is on the right
        {
            if(delParent == NULL)    // If deleting the root
            {
                root = delNode->right;
                delete delNode;
                return true;
            }
            else
            {
                if(delParent->left == delNode)
                    delParent->left = delNode->right;
                else
                    delParent->right = delNode->right;
                delete delNode;
                return true;
            }
        }
        else // Case 2: Deleting node with two children
        {
            // Find the replacement value.  Locate the node
            // containing the largest value smaller than the
            // key of the node being deleted.
            temp = delNode->left;
            back = delNode;
            while(temp->right != NULL)
            {
                back = temp;
                temp = temp->right;
            }
            // Copy the replacement values into the node to be deleted
            delNode->ID = temp->ID;
            delNode->first_name = temp->first_name;
            delNode->last_name = temp->last_name;

            // Remove the replacement node from the tree
            if(back == delNode)
                back->left = temp->left;
            else
                back->right = temp->left;
            delete temp;
            return true;
        }
    }
}


//--------------------------------------------
// Function: PrintOne()
// Purpose: Print data in one node of a tree.
// Preconditions: None
// Returns: void
//--------------------------------------------
void bstree::PrintOne(employee *T)
{
    cout << T->ID << "\t\t" << T->first_name << "\t\t" << T->last_name << endl;
}



//--------------------------------------------
// Function: PrintAll()
// Purpose: Print the tree using a recursive
//        traversal
// Preconditions: None
// Returns: void
//--------------------------------------------
void bstree::PrintAll(employee *T)
{
    if(T != NULL)
    {
        PrintAll(T->left);
        PrintOne(T);
        PrintAll(T->right);
    }
}


//--------------------------------------------
// Function: PrintTree()
// Purpose: Print the tree using a recursive
//        traversal.  This gives the user access
//        to PrintAll() without giving access to
//        the root of the tree.
// Preconditions: None
// Returns: void
//--------------------------------------------
void bstree::PrintTree()
{
    PrintAll(root);
}


void bstree::saveToFile(const char * fileName)
{
    ofstream file_writer;
    file_writer.open(fileName);
    saveToFile(file_writer, root);
    file_writer.close();
}

void bstree::saveToFile(ofstream & file_writer, employee * T)
{
    if (T != NULL)
    {
        saveToFile(file_writer, T->left);
        file_writer << T->last_name;
        file_writer << "\t";
        file_writer << T->first_name;
        file_writer << "\t";
        file_writer << T->ID;
        file_writer << "\n";
        saveToFile(file_writer, T->right);
    }

}
WhozCraig

employee构造函数均未将左指针或右指针初始化为NULL。对于复制构造函数而言,这尤其令人担忧,但是参数化构造函数真正可以显示痛苦的地方:

从文件加载时,请执行以下操作:

tree.Insert(new employee(first_name, last_name, ID));

触发此构造函数:

employee(std::string first_name, std::string last_name, unsigned int ID)
{
    this->first_name = first_name;
    this->last_name = last_name;
    this->ID = ID;
}

上面没有任何地方分配给任何对象的左右成员指针。因此它们是不确定的,因此是垃圾。所以当你这样做时:

bool bstree::Insert(employee *newNode)
{
    employee *temp;
    employee *back;

    temp = root;
    back = NULL;

    while(temp != NULL) // Loop till temp falls out of the tree
    {
        back = temp;
        if(newNode->ID < temp->ID)
            temp = temp->left;
        else if (newNode->ID > temp->ID)
            temp = temp->right;
        else
            return false;
    }

    // Now attach the new node to the node that back points to
    if(back == NULL) // Attach as root node in a new tree
        root = newNode;

    else
    {
        if(newNode->ID < back->ID)
            back->left = newNode;
        else if (newNode->ID > back->ID)
            back->right = newNode;
        else
            return false;
    }

   return true;
}

您正在追逐无效的指针,并且实际上,如果不调用未定义的行为,甚至无法对其进行更小的解引用评估

不会变成在线调试会话。您需要正确地初始化对象类的所有成员,最好在初始化器列表中:

class employee
{
public:

    // note: this shouldn't even be *needed*
    employee() : ID(), left(), right() {}

    // parameterized constructor
    employee(const std::string& first, const std::string& last, unsigned int id)
        : first_name(first)
        , last_name(last)
        , ID(id)
        , left(), right()
    {
    }

     // copy-ctor. retains values; child pointers set as null
    employee(const employee& obj)
        : first_name(obj.first_name)
        , last_name(obj.last_name)
        , ID(obj.id)
        , left(), right()
    {
    }

    // assignment operator. does NOT copy child pointers
    employee& operator =(const employee& obj)
    {
        first_name = obj.first_name;
        last_name = obj.last_name;
        ID = obj.ID;
    }

    std::string first_name;
    std::string last_name;
    unsigned int ID;
    employee * left, * right;
};

通常,我会通过实现copy / swap习惯用法,对赋值运算符进行编码,以使用copy-constructor 但是在这种情况下,这将是多余的,因为您的对象没有实际的动态管理成员(即,对象本身实际上是负责创建/销毁的成员)。

无论如何,以上是一个问题,我没有花时间去分析除插入逻辑之外的实际树管理代码。如果Delete操作中潜伏着缺陷,对于二进制树总是很乏味的,我不会感到惊讶。但这足以使您走得更远。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

从C ++中的文件加载数据时出现分段错误

来自分类Dev

扫描文件并计算c中的值时出现分段错误

来自分类Dev

在 C 中创建新文件时出现分段错误

来自分类Dev

写入文件时出现C分段错误

来自分类Dev

尝试在C中获取文件扩展名时出现分段错误错误

来自分类Dev

即使我尝试在C中创建文件也找不到文件时出现分段错误

来自分类Dev

在 C、Linux 中递归列出目录和文件时出现分段错误(核心转储)

来自分类Dev

c-打开文件时出现分段错误

来自分类Dev

从文件读取大数组时出现分段错误。C ++ / gcc

来自分类Dev

c-打开文件时出现分段错误

来自分类Dev

在C ++中操作向量时出现分段错误

来自分类Dev

在C中实现反向功能时出现分段错误

来自分类Dev

尝试克隆函数时出现分段错误(在C中)

来自分类Dev

在C中初始化数组时出现分段错误

来自分类Dev

使用链表中的指针结构时出现C分段错误

来自分类Dev

尝试克隆函数时出现分段错误(在C中)

来自分类Dev

在C中实现链表时出现分段错误

来自分类Dev

使用链表中的指针结构时出现C分段错误

来自分类Dev

exe C时出现分段错误错误

来自分类Dev

文件中C的分段错误

来自分类Dev

调用c函数时出现分段错误

来自分类Dev

从向量擦除时出现C ++分段错误

来自分类Dev

C - 使用 strlen 时出现分段错误?

来自分类Dev

创建树时出现分段错误 (C)

来自分类Dev

将 unicode 替换为 C++ 字符串中的空格时出现分段错误错误

来自分类Dev

尝试导入头文件并使用它时在C中出现分段错误

来自分类Dev

尝试导入头文件并使用它时在C中出现分段错误

来自分类Dev

尝试在C中创建动态分配的字符串数组时出现分段错误

来自分类Dev

在C ++ 4.8.1中使用strlen的打印输出时出现分段错误

Related 相关文章

  1. 1

    从C ++中的文件加载数据时出现分段错误

  2. 2

    扫描文件并计算c中的值时出现分段错误

  3. 3

    在 C 中创建新文件时出现分段错误

  4. 4

    写入文件时出现C分段错误

  5. 5

    尝试在C中获取文件扩展名时出现分段错误错误

  6. 6

    即使我尝试在C中创建文件也找不到文件时出现分段错误

  7. 7

    在 C、Linux 中递归列出目录和文件时出现分段错误(核心转储)

  8. 8

    c-打开文件时出现分段错误

  9. 9

    从文件读取大数组时出现分段错误。C ++ / gcc

  10. 10

    c-打开文件时出现分段错误

  11. 11

    在C ++中操作向量时出现分段错误

  12. 12

    在C中实现反向功能时出现分段错误

  13. 13

    尝试克隆函数时出现分段错误(在C中)

  14. 14

    在C中初始化数组时出现分段错误

  15. 15

    使用链表中的指针结构时出现C分段错误

  16. 16

    尝试克隆函数时出现分段错误(在C中)

  17. 17

    在C中实现链表时出现分段错误

  18. 18

    使用链表中的指针结构时出现C分段错误

  19. 19

    exe C时出现分段错误错误

  20. 20

    文件中C的分段错误

  21. 21

    调用c函数时出现分段错误

  22. 22

    从向量擦除时出现C ++分段错误

  23. 23

    C - 使用 strlen 时出现分段错误?

  24. 24

    创建树时出现分段错误 (C)

  25. 25

    将 unicode 替换为 C++ 字符串中的空格时出现分段错误错误

  26. 26

    尝试导入头文件并使用它时在C中出现分段错误

  27. 27

    尝试导入头文件并使用它时在C中出现分段错误

  28. 28

    尝试在C中创建动态分配的字符串数组时出现分段错误

  29. 29

    在C ++ 4.8.1中使用strlen的打印输出时出现分段错误

热门标签

归档