Hey all,
I'm writing a program that is an address book using an AVL Node structure (which was provided). I defined the contact class as the ItemType of the data to be inserted in each node. Initially I encountered a Segmentation fault that occured during the assignment from the AVLClass object returned from Read_DB() to the AVLClass object AVLTreeContacts. AVLClass has an overloaded assignment operator that copies all the nodes of the tree.

// Original screen output at runtime before writing overloaded = operator for contact class
Database successfully read
DEBUG: AVLClass overloaded = operator called
DEBUG: AVLClass CopyTree called
Segmentation fault

I figured this was because I needed an overloaded assignment operator for the contact class so I wrote one. Now i'm getting a compile error that i can't figure out. I've tried adding the "#include" and "using namespace ..." statements to make sure it can see it, but still can't figure it out. 2 Questions:

1) Is there a problem with my overloaded assignment operator? Can you copy a vector of vectors with the statement I have for the Vec_affs.
2) Any ideas on the compiler error? If I comment out my overloaded operator, the program compiles, but then i get the segmentation fault when the program tries to copy one node containing a contact class object to another node containing a contact class object

bstnode.o(.text+0x10c): In function `BSTNodeClass::GetInfo(ns_1::contact&) const':
bstnode.cpp:25: undefined reference to `ns_1::contact::operator=(ns_1::contact const&)'
collect2: ld returned 1 exit status

// FROM main.cpp

int main ()
{
   // DECLARE OBJECTS & VARIABLES
   AVLClass AVLTreeContacts;

   // INITIAL READ OF DB FILE
   //Read_DB( );
   AVLTreeContacts = Read_DB( );
   //AVLTreeContacts.Print();

   Main_Menu();

   return 0;
}

// FROM contact.h/.cpp

#include <cstdlib>      // provides size_t
#include <string>
#include <vector>
#include <fstream>

using namespace std;

namespace ns_1
{
   class contact
   {
   public:
        // TYPEDEFS & MEMBER CONSTANTS
        std::vector<string> fields;  // only works if "using namespace std" exists, what's the problem?
        std::vector<vector<string> > Vec_affs;  // affiliate = name, phone, email

        // CONSTRUCTOR
        contact( ) {   ; };

        // MODIFICATION MEMBER FUNCTIONS

        // CONSTANT MEMBER FUNCTIONS
        contact& contact::operator=(const contact& record);
        // NONMEMBER FUNCTIONS
   };
}

namespace ns_1 
{
   contact& contact::operator=(const contact& record)
   {
        #ifdef DEBUG
           cout << "DEBUG: Contact class overloaded = operator called " << endl;
        #endif

        if (this != &record) {

           // Clear memory for all variables in Contact class
           fields.clear();
           Vec_affs.clear();

           // copy vector (primary contact info) field values
           fields(record.fields);
           Vec_affs(record.Vec_affs);

           //for (int i = 0; i < record.fields.size() ; ++i)
           //   this->fields.at(i) = record->fields.at(i); //- incorrect - need push_back
           // copy 2D vector (affiliate) field values
           //for (int a = 0; a < record.Vec_affs.size(); ++a) {   // incorrect - need push_back
           //   this->Vec_aff
           //   for (int b = 0; a < record.Vec_affs.at(a).size(); ++b)
           //      this->Vec
        }
        return *this;
   }

}

//FROM bstnode.h/cpp

class BSTNodeClass
   {
   protected:
      ItemType Info;
      BSTNodeClass * Left, * Right;
   public:
      BSTNodeClass(const ItemType & Item, BSTNodeClass * LeftPtr = NULL,
         BSTNodeClass * RightPtr = NULL):
         Info(Item), Left(LeftPtr), Right(RightPtr)
         {
         };
      void GetInfo(ItemType & TheInfo) const;
   friend class BSTClass;
   friend class AVLClass;
   };

typedef BSTNodeClass * BSTNodePtr;

void BSTNodeClass::GetInfo(ItemType & TheInfo) const   //ItemType
   {
   TheInfo = Info;   // assumes assignment works on this type
   }

NOTE - The AVLClass calls functions in the bstnode and bstree files to do some of the heavy lifting.

Thanks for any and all help!!

Recommended Answers

All 4 Replies

1->// only works if "using namespace std" exists, what's the problem?

Because you have not scoped 'string'. If you don't specify, using namespace std, then you have to scope all namespace types with std:: .

2-> I don't see a problem with copying of vectors of strings bu why have you declared it like

contact& contact::operator=(const contact& record);

instead of

contact& operator=(const contact& record);

in the header file?

3-> The GetInfo function according to me should be defined like

const ItemType& GetInfo()

and should return Info. Why are you passing it a reference, which should be passing to some object, and then actually overwriting that object by the value of Info ?

Good point. I fixed 1 & 2. Looking closer at the GetInfo function, the author of the class never actually implemented it anywhere - so I just commented it out.

Now I'm just left with the Seg Fault error that occurs when i do the below assignment. I know where the problem occurs, but do not know what the cause is. I'm new at using the gdb debugger so still figuring that out.

// FROM Main
AVLTreeContacts = Read_DB( );

// Last few lines of output when program is run

DEBUG: AVLClass ClearTree called
DEBUG: AVLClass ClearSubTree called
DEBUG: AVLClass ClearSubTree called
DEBUG: AVLClass ClearSubTree called
DEBUG: AVLClass ClearSubTree called
DEBUG: AVLClass ClearSubTree called
DEBUG: AVLClass overloaded = operator called
DEBUG: AVLClass ClearTree called
DEBUG: AVLClass ClearSubTree called
DEBUG: AVLClass CopyTree called

Program received signal SIGSEGV, Segmentation fault.
0x0804cfd4 in AVLClass::CopyTree (this=0xbffa25a0, Tree=@0x10) at avltree.cpp:113
113 Root = CopySubtree(reinterpret_cast <AVLNodePtr> (Tree.Root));
(gdb) print Root
$1 = 0x0
(gdb) print Tree.Root
Cannot access memory at address 0x10

// avltree.cpp:113 corresponds to line 41 of the second code snippet below


// Read_DB function which returns an AVL Tree - seems to work fine as long as i don't do the assignment.

AVLClass& Read_DB( )
{
   int i, a;
   ifstream contactDB;
   string line;
   string affil_val;
   contact new_person;
   AVLClass AVLTreeInitial;

   // OPEN ADDRESS BOOK DATABASE FILE
   contactDB.open("data.txt");
   assert(contactDB);

   while(contactDB) {
        for (i=0 ; i < 13; ++i) {
           getline(contactDB, line);
           cout << "Retrieved field: " << line << endl;
           new_person.fields.push_back(line);
           cout << "Entered: " << new_person.fields.at(i) << " at position " << i << endl;

        }
        getline(contactDB, line);
        int row = 0;
        while (line != "|" && (!contactDB.eof())) {
           //if (contactDB.eof( ))
           cout << "Entering affiliate parsing sub-loop" << endl;
           int row_begin = 0;
           for (int k=0 ; k < line.length() ; ++k) {
                if (line[k] == ';') {
                   cout << "encounted semicolon, write " << affil_val << " to vec, break" << endl;
                   if (row_begin == 0) {
                        new_person.Vec_affs.push_back( vector<string>(1, affil_val) );
                        affil_val = "";
                        ++row;
                   }
                   else {
                        new_person.Vec_affs.at(row).push_back(affil_val);
                        affil_val = "";
                        ++row;
                   }
                }
                else if (line[k] == ',') {
                   // write field to affil vector
                   cout << "encountered comma, write " << affil_val << " to vec, zero out affil_val" << endl;
                   if (row_begin == 0) {
                        new_person.Vec_affs.push_back( vector<string>(1, affil_val) );
                        ++row_begin;
                        affil_val = "";
                   }
                   else {
                        new_person.Vec_affs.at(row).push_back(affil_val);
                        affil_val = "";
                   }
                }
                else
                   affil_val += line[k];
           }
           // if contactDB == eof - insert node, return.
           affil_val = "";   // make sure affil_val is empty and the start of each line
           getline(contactDB, line);
        }
        if (line == "|") {
           cout << "encountered a pipe, record complete" << endl;
        }
        // 2D vector traversal using size() function
        for (a=0; a< new_person.Vec_affs.size() ; ++a) {
           cout << endl << "Vec_affs entry: " << a << "   ";
           for (int b=0; b< new_person.Vec_affs.at(a).size(); ++b)
                cout << new_person.Vec_affs.at(a).at(b) << " ";
        }
        // AVL Insert
        AVLTreeInitial.Insert(new_person);

        // Clear new_person contact in preparation for possible next entry.
        new_person.fields.clear( );
        new_person.Vec_affs.clear( );
        cout << "CLEARING contact for new entry" << endl;
   }
   cout << "Database successfully read"  << endl;
   contactDB.close();
}

//Class Header and functions where Seg Fault occurs

#include "bstnode.h"


class BSTClass
   {
   private:
      BSTNodePtr GetNode(const ItemType & Item,
         BSTNodePtr LeftPtr = NULL, BSTNodePtr RightPtr = NULL);
      void FreeNode(BSTNodePtr NodePtr);
      void ClearTree(void);
      void ClearSubtree(BSTNodePtr Current);
      BSTNodePtr SubtreeFind(BSTNodePtr Current,
         const ItemType & Item) const;
      void PrintSubtree(BSTNodePtr NodePtr, int Level) const;
      // The following data fields could be made protected instead of
      // private.  This would make them accessible to the derived AVLClass
      // without making AVLClass a friend of BSTClass.
      BSTNodePtr Root;
      int Count;
   public:
      BSTClass(void);
      ~BSTClass(void);
      int NumItems(void) const;
      bool Empty(void) const;
      void Insert(const ItemType & Item);
      //  Some sort of Remove method could also be added, but
      //  it would require effort to remake the binary search tree
      //  after the deletion of a node.
      BSTNodePtr Find(const ItemType & Item) const;
      void Print(void) const;
   friend class AVLClass;
   };


void AVLClass::CopyTree(const AVLClass & Tree)
   {
   #ifdef DEBUG
      cout << "DEBUG: AVLClass CopyTree called" << endl;
   #endif

   Root = CopySubtree(reinterpret_cast <AVLNodePtr> (Tree.Root));
   cout << "creation of Root successful" << endl;
   Count = Tree.Count;
   }

AVLNodePtr AVLClass::CopySubtree(const AVLNodePtr Current)
   {
   AVLNodePtr NewLeftPtr, NewRightPtr, NewParentPtr;
   // Once this section works, leave this out as it gives too much output:
   #ifdef DEBUG
    cout << "DEBUG: AVLClass CopySubtree called" << endl;
   #endif

   if (Current == NULL)
      return NULL;

   if (Current->Left == NULL)
      NewLeftPtr = NULL;
   else
      NewLeftPtr = CopySubtree(reinterpret_cast <AVLNodePtr> (Current->Left));

   if (Current->Right == NULL)
      NewRightPtr = NULL;
   else
      NewRightPtr = CopySubtree(reinterpret_cast <AVLNodePtr> (Current->Right));

   NewParentPtr = GetNode(Current->Info, NewLeftPtr, NewRightPtr,
      Current->Balance);

   return NewParentPtr;
   }

I can't really pin-point the error from this much code but you can try some general tips first to improve your code so that the problem can be easily identified.

For all classes with pointers define a copy-ctor, assignment operator and destructor to properly manage copying of pointers, freeing of memory etc.

If you are returning NULL from CopySubtree and assigning it to Root, it is possible that somewhere you use it without checking. So make sure you are not doing that.

Don't use reinterpret_cast unless you totally know that you cannot do without it. It usually means that the design is flawed and you should try and improve that. I don't really understand reinterpret_cast and stay away from it.

Once you do all this it might be easier to locate the error. If possible you can create a smaller compilable version of the code which reproduces the error and then people here will be able to execute it and provide better inputs.

Thanks for the advice Agni. I will take it to heart. I finally found the issue. First of all, my Read_DB function was not returning anything. I added a return statement at the end of the function. Secondly I was returning the address of a local variable rather than the variable itself. I still mix that up sometimes.

Appreciate your insight!

The reinterpret_cast was not me, but I figured it must be working because everyone else in my class is using the same libraries i am.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.