简体   繁体   中英

Undefined References and Segmentation Faults

Ok, I'm writing a program which uses several different classes, including a Linked Sorted List, and a Binary Search Tree/Node class. When I compile in Visual Studio, it runs with no complaints at all, 100% smooth, and I have completely debugged it there, getting no errors. However, when I put it into Unix, which I have to turn it in on, and go to test it with g++, everything goes to hell. If I try to access more than the root of the binary tree, I get a "segmentation fault".

When I use the command "g++ main.cpp", I see dozens of "undefined references" to the member functions of the other classes. Now, I do have all of the necessary #include statements, as well as using "#ifndef/#define/#endif" statements. The only two classes which give me the issues are the Employee and SearchTreeNode classes. Here are those two as well as the main:

    #include "LinkedSortedList.h"
    #include "LinkedNode.h"
    #include "Employee.h"
    #include "SearchTreeNode.h"
    #include <string>
    #include <ostream>
    #include <iostream>
    #include <fstream>

    using namespace std;

    int main() {

LinkedSortedList<Employee> mylist;  //create the LSL
SearchTree mytree;                  //create the BST

int searchCount = 0; //occasionally used to count recursive calls to function
bool _continue = true;
char command;

do{

    cout << "\nEnter your command: \n" << endl;
    cout << "(I)nsert\n(F)ind Employee from ID\n(D)elete Employee from ID\n(L)ast Name Search\n(S)ave to file\n(R)ead from file\n(Q)uit" << endl;

    cin >> command;

    if(command == 'I' || command == 'i'){
        //insert
        Employee* newEmployee = new Employee();
        newEmployee->create();
        mylist.insert(*newEmployee);
        mytree.insert(newEmployee);
        cout << "Employee Added\n----------\n" << endl;
        newEmployee->print();
        cout << "\n----------\n" << endl;
    }
    else if(command == 'L' || command == 'l'){
        //arbitrary pointer to undefined matches to be used in fetchAllMatches()
        LinkedSortedList<Employee>* matches;
        string name;
        cout << "Last Name to Search for: " << endl;
        cin >> name;
        Employee* search = new Employee();
        search->setLastName(name);

        int matchCount = mylist.fetchAllMatches(*search, matches, matchCount);
        cout << mylist.size() << " Records Searched.\n"<< matchCount << " Matches Found:" << endl;
        //Make sure that there is something to print to avoid errors
        if(matchCount > 0)
            matches->print();

    }
    else if(command == 'D' || command == 'd'){
        int IDnumber;
        cout << "Enter Employee ID to delete: " << endl;
        cin >> IDnumber;

        if(mytree.getRoot() != NULL) { // make sure there is a tree to search through
            Employee *x = mytree.find(IDnumber, searchCount, mytree.getRoot());

            if(x->getAddress() != "null"){
                mylist.remove(*x);
                mytree.remove(x->getId());
                cout << "\n" << x << "\n---------\n" << "File Deleted" << endl;
            }

        } else {
            cout << "Tree is empty" << endl;
        }
    }
    else if(command == 'F' || command == 'f'){
        int IDnumber;
        cout << "Enter Employee ID to find: " << endl;
        cin >> IDnumber;
        searchCount = 0;
        if(mytree.getRoot() != NULL) { // make sure there is a tree to search through
            Employee* x = mytree.find(IDnumber, searchCount, mytree.getRoot());

            if(x->getAddress() != "null"){
                    cout << "\n" << *x << "\n" << endl;
            } else {
                cout << "Employee not found!" << endl;
            }

        } else {
            cout << "Tree is empty" << endl;
        }
    }
    else if(command == 'S' || command == 's'){
        string file;
        cout << "Write Database to File Name: " << endl;
        cin >> file;
        mylist.printToFile(file, mylist);
    }
    else if(command == 'T' || command == 't'){
        mytree.print(mytree.getRoot());
    }
    else if(command == 'R' || command == 'r'){
        //read
        if(mylist.size() > 0) {
            mylist.clear();
            mytree.clearTree(mytree);
        }
        string line;
        string file;
        int intLine;
        cout << "File Name: " << endl;
        cin >> file;
        ifstream myfile(file.c_str());
        if (myfile.is_open())
        {
            getline (myfile,line);
            if(line != "<Records>"){
                cout << "Not a database file." << endl;
            }
            //make sure it's still ok
            while ( myfile.good() )
            {

                getline(myfile, line);
                if(line != "<END>"){

                    Employee* newEmployee = new Employee();

                    for(int i = 0; i < 10; i++){
                        switch (i){

                        case 0:

                            newEmployee->setLastName(line);
                            break;
                        case 1:
                            getline(myfile, line);
                            newEmployee->setFirstName(line);
                            break;
                        case 2:
                            myfile >> intLine;
                            newEmployee->setId(intLine);
                            break;
                        case 3:
                            myfile >> intLine;
                            myfile.get();
                            newEmployee->setSalary(intLine);
                            break;
                        case 4:
                            getline(myfile, line);
                            newEmployee->setDept(line);
                            break;
                        case 5:
                            getline(myfile, line);
                            newEmployee->setPhone(line);
                            break;
                        case 6:
                            getline(myfile, line);
                            newEmployee->setAddress(line);
                            break;
                        case 7:
                            getline(myfile, line);
                            newEmployee->setHireDate(line);
                            break;
                        case 8:
                            getline(myfile, line);
                            newEmployee->setEmail(line);
                            break;
                        case 9:
                            getline(myfile, line);//eat the dashes
                            break;
                        }

                    }
                    mylist.insert(*newEmployee);
                    mytree.insert(newEmployee);
                }
                else {
                    myfile.close();
                }
            }

        }
        else cout << "Unable to open file";     
    }
    else if(command == 'Q' || command == 'q'){
        return 0;
    }
    else if(command == 'P' || command == 'p'){
        mylist.print();
    }
}
while(_continue);

return 0;
}






    #include <iostream>
    using namespace std;



    #ifndef _EmployeeClass_
    #define _EmployeeClass_


    class Employee {

    public:

Employee(){
    firstName;
    lastName;
    department;
    email;
    dateHired;
    phoneNumber;
    homeAddress;
    employeeID = 0;
    salary = 0;

    //this->create();
}

Employee(string last, string first, int ID, int _salary, string dept, string phone, 
    string address, string hireDate, string _email){

        lastName = last;
        firstName = first;
        employeeID = ID;
        salary = _salary;
        department = dept;
        phoneNumber = phone;
        homeAddress = address;
        dateHired = hireDate;
        email = _email;

        employeeCount++;
}

void create();
//list of getter functions to return private variables, preventing direct access.
int getId();
int getSalary();
string getFirstName();
string getLastName();
string getDept();
string getHireDate();
string getEmail();
string getAddress();
string getPhone();

friend bool operator!= (Employee &x, Employee &y);
friend bool operator== (Employee &x, Employee &y);  
friend bool operator<= (Employee &x, Employee &y);
friend bool operator>= (Employee &x, Employee &y);
friend bool operator< (Employee &x, Employee &y);
friend bool operator> (Employee &x, Employee &y);

friend ostream& operator<<(ostream& output, Employee& x);
void print();

//list of setter functions to set values for the private variables, without allowing direct access.
void setPhone(string phone);
void setId(int ID);
void setSalary(int salary);
void setFirstName(string name);
void setLastName(string surname);
void setDept(string dept);
void setHireDate(string hireDate);
void setEmail(string email);
void setAddress(string address);

    private:

//private member variables dependant on input for each individual object
string firstName;
string lastName;
string department;
string email;
string dateHired;
string homeAddress;
string phoneNumber;
int employeeID;
int salary;

int employeeCount;

    };

    #endif

This is the Employee Class:

    #include <iostream>
    #include "Employee.h"


    #ifndef _SearchTreeNodeClass_
    #define _SearchTreeNodeClass_




    //this class makes a binary search tree of "search tree nodes" which contain 3                         pointers:
    //left: points to left child (value always less than node)
    //right: points to right child (value always greater than node)
    //data: points to an Employee object in memory.
    using namespace std;

    class SearchTreeNode
    {
    private:
SearchTreeNode( Employee* D,SearchTreeNode* L = NULL, SearchTreeNode* R = NULL )    // constructor
{ 
    data = D;
    left = L;  
    right = R; 
};
int         count;
Employee*   data;                           // node data
SearchTreeNode* left;                       // pointer to the left subSearchTree
SearchTreeNode* right;                      // pointer to the right subSearchTree

friend class SearchTree;                // give SearchTree complete access
    };
    #endif

    #ifndef _SearchTreeClass_
    #define _SearchTreeClass_


    using namespace std;

    class SearchTree
    {        
    public:
SearchTree();                           
virtual ~SearchTree();                  
SearchTree( const SearchTree& );        
SearchTree& operator=( SearchTree& );   
SearchTreeNode* getRoot();
SearchTreeNode* find(int, SearchTreeNode*);
Employee* find(int, int, SearchTreeNode* ); 
void insert( Employee* );               
void print();   
void destroy( SearchTreeNode* );        
void print( SearchTreeNode* );
void clearTree( SearchTree& );
void inorder( SearchTreeNode* );
void remove( int x );
    private:
SearchTreeNode* root;                       // pointer to the root of the search SearchTree                     
SearchTreeNode* copy( SearchTreeNode* );
void insert( SearchTreeNode*& root, Employee* );

    };
    #endif

There are many possible reasons for the problems that you are having. One that comes to mind is when you compile in Visual Studio, you have set the include path -- the path where header files are searched for. It is also possible that you didn't set it in Visual Studio, but VS set it for you silently when you created a project and added files to the project from various directories.

With g++, you have to provide the include directories yourself. (If you had used an IDE under Linux that is similar to Visual Studio, then these include directories would have been set for you. So, the problem is not the difference between Windows and Linux, but between development within an IDE that does many things behind the scenes and compiling using the command line.)

Look at the man pages for g++. Take a look at the -I option for adding include directories and the -l for library search during linking. (Most likely you will need the -I option.)

Given that you were successful with Windows, I doubt you have a problem with your source code. The only other possibility is that you used a library function that is Visual Studio specific that is absent in g++.

Segmentation fault errors come up whenever you try to read or write to an invalid memory address. This can have many causes - check here for some examples.

Undefined reference errors happen when you fail to link required libraries and/or object files. From simply using g++ main.cpp you are not specifying neither the other source files nor any required libraries for linking.

Like @Ray said above, when compiling directly on the command line you have to supply the include and linking directories by yourself, which is why we usually have a Makefile for. Using a properly crafted Makefile is better than calling the compiler directly because make checks which source files changed, calling the compiler to rebuild just the needed files instead of everything (this makes a hell of a difference when your project is big!).

If you don't have much experience with Makefiles, I would suggest you use CMake . It is a build system which makes the makefiles for you. The good thing it is even multiplatform, so with the same CMakeLists.txt file you can generate makefiles for Windows or Linux, and the syntax is really simple.

If you tell me all the source files you have and eventual libraries you might use I can give you an exact CMakeLists.txt sample that should compile everything for you, but it can be something as simple as the following (based on your includes, I assumed your source files would be main.cpp , LinkedSortedList.cpp , LinkedNode.cpp , Employee.cpp and SearchTreeNode.cpp ):

cmake_minimum_required (VERSION 2.6)

project (employee_manager CXX)

set (SOURCES
  main.cpp
  LinkedSortedList.cpp
  LinkedNode.cpp
  Employee.cpp
  SearchTreeNode.cpp
  )

add_executable (employee_manager ${SOURCES})

You should create this file at your source code dir. To separate the compilation output from the source you can then create a build dir, run CMake there referring to the CMakeLists.txt file at the parent dir and it will build the Makefile for you. From there, you just need to invoke the regular make to build your program:

mkdir build
cd build
cmake ..
make

That will give you the executable file employee_manager into the build dir.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM