未定义的引用和分段错误
Undefined References and Segmentation Faults
好的,我正在编写一个程序,它使用几个不同的类,包括一个链排序列表和一个二叉搜索树/节点类。当我在Visual Studio中编译时,它运行没有任何抱怨,100%流畅,并且我已经在那里完全调试了它,没有错误。但是,当我把它放到Unix中时,我必须打开它,然后用g++去测试它,一切都会变得地狱。如果我尝试访问比二叉树的根目录更多的内容,则会出现"分段错误"。
当我使用命令"g++ main.cpp"时,我看到数十个对其他类的成员函数的"未定义引用"。现在,我确实拥有所有必要的 #include 语句,以及使用"#ifndef/#define/#endif"语句。给我带来问题的仅有的两个类是Employee和SearchTreeNode类。以下是这两个以及主要:
#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)nsertn(F)ind Employee from IDn(D)elete Employee from IDn(L)ast Name Searchn(S)ave to filen(R)ead from filen(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 Addedn----------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
您遇到的问题有很多可能的原因。 我想到的一个问题是,当你在Visual Studio中编译时,你已经设置了包含路径 - 搜索头文件的路径。 也可能您没有在 Visual Studio 中设置它,但在您创建项目并将文件从各个目录添加到项目时,VS 会为您静默设置它。
使用 g++,您必须自己提供包含目录。 (如果您在 Linux 下使用了类似于 Visual Studio 的 IDE,那么这些包含目录将为您设置。 因此,问题不在于Windows和Linux之间的区别,而在于IDE中的开发与使用命令行进行编译之间的区别。
查看 g++ 的手册页。 查看用于添加包含目录的 -I 选项和用于在链接期间搜索库的 -l。 (您很可能需要 -I 选项。
鉴于您在Windows上取得了成功,我怀疑您的源代码有问题。 唯一的另一种可能性是你使用了 Visual Studio 特有的库函数,而 g++ 中没有。
每当您尝试读取或写入无效的内存地址时,都会出现分段错误。这可能有很多原因 - 查看此处的一些示例。
当您无法链接所需的库和/或对象文件时,会发生未定义的引用错误。通过简单地使用g++ main.cpp
您既不指定其他源文件,也不指定任何链接所需的库。
就像上面@Ray说的,直接在命令行上编译时,您必须自己提供包含和链接目录,这就是为什么我们通常有一个 Makefile 的原因。使用正确制作的 Makefile 比直接调用编译器更好,因为检查哪些源文件发生了更改,调用编译器来重建所需的文件而不是所有文件(当您的项目很大时,这会有很大的不同!
如果你对Makefiles没有太多经验,我建议你使用CMake。它是一个构建系统,可以为您制作生成文件。好消息是它甚至是多平台的,因此使用相同的CMakeLists.txt文件,您可以为Windows或Linux生成makefile,并且语法非常简单。
如果你告诉我你拥有的所有源文件和你可能使用的最终库,我可以给你一个确切的CMakeLists.txt示例,它应该为你编译所有内容,但它可以是像下面这样简单的东西(基于你的包含,我假设你的源文件将是main.cpp,LinkedSortedList.cpp,LinkedNode.cpp,Employee.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})
您应该在源代码目录中创建此文件。要将编译输出与源代码分开,您可以创建一个构建目录,在那里运行 CMake,参考父目录上的 CMakeLists.txt 文件,它将为您构建生成文件。从那里,你只需要调用常规的make来构建你的程序:
mkdir build
cd build
cmake ..
make
这将为您提供employee_manager构建目录的可执行文件。
- 在某些循环内使用vector.push_back时出现分段错误
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 当我的阵列太大时出现分段错误
- 分段错误当我试图运行程序时出错
- 在c++中初始化矩阵时出现分段错误(核心转储)
- 尝试使用集合函数时出现分段错误
- 我无法缩小此分段错误的原因
- g++的分段错误(在NaN上使用to_string两次时)
- 我是如何在这段代码中出现分段错误的
- 创建结构的数组时遇到分段错误
- 在c++中键入向量中的所有值后,得到分段错误(核心转储)
- 在 c++ 中实现 Trie 时出现分段错误
- 为什么 fstream 在打开带有格式的文件时会导致分段错误?
- 为什么我遇到分段错误?
- 动态类的分段错误(家庭作业问题)
- 分段错误 - 读取初始化指针的数组
- 如何摆脱C ++中的分段错误错误?
- 使用 CTYPE 时出现分段错误
- 为什么代码给出分段错误?