segmentation fault while loading data from a file in C++ -
the title of question might have been title many other questions on site, however, experiencing strangest thing i've ever had deal in whole academic life.
i assigned design binary search tree
database contains long list of company's employee records. have implemented project , worked fine, until received email professor asking in class log linux-powered server via ssh , verify project compiles , behaves expected on there.
the source code compiled fine, however, when run application , tell load list of 3000 records of file, run segmentation fault
@ 543th record (line in file).
my question is: causing problem, considering code worked fine on own machine?
does matter, size of project, how memory assigned me? possible running out of memory while loading data?
even though 100% sure problem not in code, still think convenient @ piece of code , try spot problem.
here's employee
class:
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;
this function using load file database:
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; (;;) { 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 new employee object bstree tree.insert(new employee(first_name, last_name, id)); } cout << endl << endl << "all employee records have been inserted database successfully." << endl << endl; // close file file_reader.close(); }
and here 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 recursive traversal of // tree destroying nodes. //-------------------------------------------- void bstree::cleartree(employee *t) { if(t==null) return; // nothing 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 node return; } //-------------------------------------------- // function: isempty() // purpose: return true if tree empty. //-------------------------------------------- bool bstree::isempty() { return(root == null); } //-------------------------------------------- // function: dupnode() // purpose: duplicate node in tree. // used allow returning complete // structure tree without giving // access tree through pointers. // preconditions: none // returns: pointer duplicate of node arg //-------------------------------------------- employee *bstree::dupnode(employee * t) { employee *dupnode; dupnode = new employee(); *dupnode = *t; // copy data structure dupnode->left = null; // set pointers null dupnode->right = null; return dupnode; } //-------------------------------------------- // function: searchtree() // purpose: perform iterative search of tree , // return pointer treenode containing // search key or null if not found. // preconditions: none // returns: pointer duplicate of 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 node. else temp = temp->right; // search key comes after node } if(temp == null) return temp; // search key not found else return(dupnode(temp)); // found return duplicate } //-------------------------------------------- // function: insert() // insert new node tree. // preconditions: none // returns: int (true if successful, false otherwise) //-------------------------------------------- bool bstree::insert(employee *newnode) { employee *temp; employee *back; temp = root; = null; while(temp != null) // loop till temp falls out of tree { = temp; if(newnode->id < temp->id) temp = temp->left; else if (newnode->id > temp->id) temp = temp->right; else return false; } // attach new node node points if(back == null) // attach root node in 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 new node 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 new node , copy data newnode = new employee(); newnode->id = key; newnode->first_name = first_name; newnode->last_name = last_name; newnode->left = newnode->right = null; // call other insert() actual insertion return(insert(newnode)); } //-------------------------------------------- // function: delete() // purpose: delete node tree. // preconditions: tree contains node delete // returns: int (true if successful, false otherwise) //-------------------------------------------- bool bstree::delete(unsigned int key) { employee *back; employee *temp; employee *delparent; // parent of node delete employee *delnode; // node delete temp = root; = null; // find node delete while((temp != null) && (key != temp->id)) { = temp; if(key < temp->id) temp = temp->left; else temp = temp->right; } if(temp == null) // didn't find 1 delete return false; else { if(temp == root) // deleting root { delnode = root; delparent = null; } else { delnode = temp; delparent = back; } } // case 1: deleting node no children or 1 child if(delnode->right == null) { if(delparent == null) // if deleting 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 @ least 1 child { if(delnode->left == null) // 1 child , on right { if(delparent == null) // if deleting 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 2 children { // find replacement value. locate node // containing largest value smaller // key of node being deleted. temp = delnode->left; = delnode; while(temp->right != null) { = temp; temp = temp->right; } // copy replacement values node deleted delnode->id = temp->id; delnode->first_name = temp->first_name; delnode->last_name = temp->last_name; // remove replacement node tree if(back == delnode) back->left = temp->left; else back->right = temp->left; delete temp; return true; } } } //-------------------------------------------- // function: printone() // purpose: print data in 1 node of 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 tree using 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 tree using recursive // traversal. gives user access // printall() without giving access // root of 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); } }
neither of employee
constructors initialize either left or right pointers null. particularly worrisome copy-constructor, parameterized constructor pain show through:
when loading file this:
tree.insert(new employee(first_name, last_name, id));
which fires constructor:
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; }
nowhere in above left , right member pointers assigned anything. indeterminate , therefore garbage. when this:
bool bstree::insert(employee *newnode) { employee *temp; employee *back; temp = root; = null; while(temp != null) // loop till temp falls out of tree { = temp; if(newnode->id < temp->id) temp = temp->left; else if (newnode->id > temp->id) temp = temp->right; else return false; } // attach new node node points if(back == null) // attach root node in 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; }
you're chasing pointers not valid, , indeed cannot evaluated less dereferenced without invoking undefined behavior.
this not going turn online debugging session. need initialize all members of object class, ideally in initializer list:
class employee { public: // note: shouldn't *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 null employee(const employee& obj) : first_name(obj.first_name) , last_name(obj.last_name) , id(obj.id) , left(), right() { } // assignment operator. 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; };
normally code assignment operator use copy-constructor implementing copy/swap idiom. in case overkill, since object has no actual dynamic-managed members ( i.e. members object responsible creating/destroying).
anyway, above big issue, , did not take time dissect actual tree management code beyond insertion logic. wouldn't surprised if there defect lurking in delete operation, tedious binary trees. should enough further down road.
Comments
Post a Comment