0

わかりました。リンクされた並べ替えリストや、バイナリ検索ツリー/ノードクラスなど、いくつかの異なるクラスを使用するプログラムを作成しています。Visual Studioでコンパイルすると、文句なしで100%スムーズに実行され、そこで完全にデバッグされ、エラーは発生しません。しかし、それをUnixに入れて、それをオンにして、g ++でテストしに行くと、すべてが地獄に落ちます。バイナリツリーのルート以外にアクセスしようとすると、「セグメンテーション違反」が発生します。

コマンド「g++main.cpp」を使用すると、他のクラスのメンバー関数への「未定義の参照」が数十個表示されます。これで、必要なすべての#includeステートメントと、「#ifndef /#define /#endif」ステートメントを使用できるようになりました。問題が発生するのは、EmployeeクラスとSearchTreeNodeクラスの2つだけです。これらの2つとメインは次のとおりです。

    #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

これは従業員クラスです:

    #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
4

2 に答える 2

0

あなたが抱えている問題には多くの理由が考えられます。頭に浮かぶのは、Visual Studio でコンパイルするときに、インクルード パス (ヘッダー ファイルが検索されるパス) を設定したことです。Visual Studio で設定しなかった可能性もありますが、プロジェクトを作成し、さまざまなディレクトリからプロジェクトにファイルを追加したときに、VS が自動的に設定します。

g++ では、インクルード ディレクトリを自分で提供する必要があります。(Linux で Visual Studio に似た IDE を使用していた場合、これらのインクルード ディレクトリは自動的に設定されているはずです。したがって、問題は Windows と Linux の違いではなく、多くのことを行う IDE 内での開発の違いにあります。舞台裏でコマンドラインを使用してコンパイルします。)

g++ の man ページを見てください。インクルード ディレクトリを追加するための -I オプションと、リンク中にライブラリを検索するための -l オプションを見てください。(ほとんどの場合、-I オプションが必要になります。)

あなたが Windows で成功したことを考えると、ソース コードに問題があるとは思えません。他の唯一の可能性は、g++ にはない Visual Studio 固有のライブラリ関数を使用したことです。

于 2012-05-18T03:00:16.407 に答える
0

無効なメモリ アドレスを読み書きしようとすると、セグメンテーション違反エラーが発生します。これには多くの原因が考えられます -ここでいくつかの例を確認してください。

必要なライブラリやオブジェクト ファイルのリンクに失敗すると、未定義の参照エラーが発生します。単純に使用g++ main.cppすると、他のソースファイルもリンクに必要なライブラリも指定しません。

@Ray が上で述べたように、コマンド ラインで直接コンパイルする場合は、インクルード ディレクトリとリンク ディレクトリを自分で指定する必要があります。これが、通常 Makefile がある理由です。適切に作成された Makefile を使用することは、コンパイラを直接呼び出すよりも優れています。なぜなら、makeはどのソース ファイルが変更されたかをチェックし、コンパイラを呼び出してすべてではなく必要なファイルだけを再構築するからです (プロジェクトが大きい場合、これは大きな違いになります!)。

Makefile の経験があまりない場合は、CMakeを使用することをお勧めします。これは、makefile を作成するビルド システムです。良いことに、マルチプラットフォームであるため、同じCMakeLists.txtファイルを使用して、Windows または Linux 用のメイクファイルを生成でき、構文は非常に単純です。

あなたが持っているすべてのソース ファイルと、最終的に使用する可能性のあるライブラリを教えていただければ、すべてをコンパイルする正確なCMakeLists.txtサンプルを提供できますが、次のように単純なものにすることができます (インクルードに基づいて、私はソースファイルがmain.cppLinkedSortedList.cppLinkedNode.cppEmployee.cppおよび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})

このファイルは、ソース コード ディレクトリに作成する必要があります。コンパイル出力をソースから分離するには、ビルド ディレクトリを作成し、そこで親ディレクトリのCMakeLists.txtファイルを参照して CMake を実行すると、Makefile がビルドされます。そこから、通常のmakeを呼び出してプログラムをビルドするだけです。

mkdir build
cd build
cmake ..
make

これにより、実行可能ファイルemployee_managerビルドディレクトリに作成されます。

于 2012-05-18T13:06:36.570 に答える