打印链接列表 - 访问冲突 C++
Printing A linked List - Access Violation C++
我有一个链表,它接受几个输入文件,然后将它们放入一个链表中,以便稍后打印。
我实现了打印功能,但效果不佳,并出现访问冲突错误。我尝试调试,不幸的是我找不到问题的根源。
函数中的错误行:
cout << ptr2->command + " ";
运行-时间错误:
First-chance exception at 0x00DAC616 in the file.exe: 0xC0000005: Access violation reading location 0xCDCDCDE1.
代码如下:
#include <iostream>
#include <fstream>
#include <string>
#include "strutils.h"
using namespace std;
struct Commands;
struct Functions
{
string fname;
Functions *right;
Commands *down;
};
struct Commands
{
string command;
Commands *next;
};
Functions *head;
Functions *temp;
Commands *temp2;
void StreamToLinkedList(ifstream &inputfile)
{
string s;
getline(inputfile, s);
temp = new Functions();
temp->fname = s.substr(0, s.length());
temp2 = temp->down;
while (!inputfile.eof())
{
getline(inputfile, s);
temp2 = new Commands();
temp2->command = s.substr(0, s.length()-1) + ",";
temp2 = temp2->next;
}
inputfile.clear();
inputfile.seekg(0);
}
void printLinkedList()
{
Functions *ptr = head;
Commands *ptr2;
while (ptr != nullptr)
{
cout << ptr->fname << endl;
ptr2 = ptr->down;
while (ptr2 != nullptr)
{
cout << ptr2->command + " ";
ptr2 = ptr2->next;
}
cout << endl;
ptr = ptr->right;
}
}
int main()
{
string file, key, s;
ifstream input;
cout <<"If you want to open a service (function) defining the file," << endl
<<"then press (Y/y) for 'yes', otherwise press any single key" << endl;
cin >> key;
ToLower(key);
if (key == "y")
{
cout << "Enter file the input file name: ";
cin >> file;
input.open(file.c_str());
if (input.fail())
{
cout << "Cannot open the file." << endl
<< "Program terminated." << endl;
cin.get();
cin.ignore();
return 0;
}
else
{
StreamToLinkedList(input);
head = temp;
temp = temp->right;
}
}
else
{
cout << "Cannot found any input file to process" <<endl
<< "Program terminated."<< endl;
cin.get();
cin.ignore();
return 0;
}
do
{
cout<< "Do you want to open another service defining file?"<<endl
<< "Press (Y/y) for 'yes', otherwise press any key" <<endl;
cin >> key;
ToLower(key);
if (key == "y")
{
cout << "Enter file the input file name: ";
cin >> file;
input.open(file.c_str());
if (input.fail())
{
cout << "Cannot open the file." << endl
<< "Program terminated." << endl;
cin.get();
cin.ignore();
return 0;
}
else
{
StreamToLinkedList(input);
temp = temp->right;
}
}
} while ( key == "y");
cout << "-------------------------------------------------------------------" << endl
<< "PRINTING AVAILABLE SERVICES (FUNCTIONS) TO BE CHOSEN FROM THE USERS" << endl
<< "-------------------------------------------------------------------" << endl << endl;
printLinkedList();
cin.get();
cin.ignore();
return 0;
}
错误代码可能是什么?
您的访问冲突问题是 new 默认情况下不会将其分配的内存归零,
所以最后一个结构中的指针指向一个随机值。
temp2 = new Commands; // this memory is not initilized to zero
temp2 = new Commands(); // this memory is initialized to zero, (all elements is set to 0)
回答
你的打印功能没问题。您创建和管理列表的方式出了问题,可能是因为 您从未初始化 您的 Functions.right
和 Functions.down
字段,所以您的 linked 列表 linking 到无效内存。好吧,你实际上 link 你的列表。
您的某些分配,例如 temp2 = temp->down
和 temp = temp->right
没有任何意义,因为这些字段未初始化并且您正在覆盖这些变量(temp
和 temp2
) 之后添加新对象。
此外,您有重复的代码。您正在以完全相同的方式在两个不同的地方读取文件。问题是你的代码是错误的,所以你有双倍的错误要修复。此处代码重复的唯一明显原因是您希望在用户第一次输入和第 n 次输入时显示不同的消息。
我建议将这段代码放在它自己的函数中。否则找到一个更有效的方法来使用 conditionals/loops 这样你就没有那么多重复代码了。
注释
我有 "few" 关于您的代码的注意事项。 LinkedList 在两个 class 中实现,称为 Functions
和 Commands
。我知道你想要一个函数列表并且每个函数都有一个命令列表,但是你必须学会将程序的域分开来自其他功能。
IE: A LinkedList
是对象(任何种类)的容器。 Function
和 Command
是您为程序所做的特定内容,与 linked 列表本身无关。从概念的角度来看,Function
包含 Command
,但不一定通过 LinkedList
,或 map
,或 array
,等等
你的代码需要概念分离,看看它能有多清晰
// Linked list of functions
Functions list;
// No need to comment this one
LinkedList functions;
(我们不要争论缺少模板类型)
此外,除非使用复数来命名 class 有意义,否则您应该几乎总是使用单数(Functions
与 Function
)。这是因为当您实例化一个 class 时,您将拥有 一个 object/instance,因此使用复数形式表示该类型可能会产生误导。考虑以下声明,
Function someFunction; // This is a single function
Functions someFunction; // Is this one function or multiple functions??
List< Function > functions; // This is a list of functions
List< Functions > functions; // Is this a list of lists of functions???
您应该创建一个名为 LinkedList 的 class(提示:如果可以,请使用模板以提高其可重用性)。然后,如果您要将函数和命令的实现与 linked 列表分开,您可以制作类似
template <class T>
struct LinkedList {
T* obj;
LinkedList<T>* next;
LinkedList() : obj( nullptr ), next( nullptr ) {}
};
struct Command {
string cname;
};
struct Function {
string fname;
LinkedList<Command> commands;
};
现在您可以像这样声明您的函数列表,
LinkedList<Function> functions;
因为每个 Function
都有自己的 Command
列表,所以您有一个列表列表,您不必像在当前实施中那样独立管理每个列表。当然,你的列表仍然需要一个接口(和内存管理)但这不在这个问题的范围内。
编辑:
当 nullptr 不指向任何东西时初始化你的指针。
temp = new Functions;
temp->right = nullptr;
temp->down = nullptr;
或者使用默认构造函数,
struct Functions {
...
Functions() : right( nullptr ), down( nullptr ){}
};
然后像这样初始化,
temp = new Functions();
我有一个链表,它接受几个输入文件,然后将它们放入一个链表中,以便稍后打印。
我实现了打印功能,但效果不佳,并出现访问冲突错误。我尝试调试,不幸的是我找不到问题的根源。
函数中的错误行:
cout << ptr2->command + " ";
运行-时间错误:
First-chance exception at 0x00DAC616 in the file.exe: 0xC0000005: Access violation reading location 0xCDCDCDE1.
代码如下:
#include <iostream>
#include <fstream>
#include <string>
#include "strutils.h"
using namespace std;
struct Commands;
struct Functions
{
string fname;
Functions *right;
Commands *down;
};
struct Commands
{
string command;
Commands *next;
};
Functions *head;
Functions *temp;
Commands *temp2;
void StreamToLinkedList(ifstream &inputfile)
{
string s;
getline(inputfile, s);
temp = new Functions();
temp->fname = s.substr(0, s.length());
temp2 = temp->down;
while (!inputfile.eof())
{
getline(inputfile, s);
temp2 = new Commands();
temp2->command = s.substr(0, s.length()-1) + ",";
temp2 = temp2->next;
}
inputfile.clear();
inputfile.seekg(0);
}
void printLinkedList()
{
Functions *ptr = head;
Commands *ptr2;
while (ptr != nullptr)
{
cout << ptr->fname << endl;
ptr2 = ptr->down;
while (ptr2 != nullptr)
{
cout << ptr2->command + " ";
ptr2 = ptr2->next;
}
cout << endl;
ptr = ptr->right;
}
}
int main()
{
string file, key, s;
ifstream input;
cout <<"If you want to open a service (function) defining the file," << endl
<<"then press (Y/y) for 'yes', otherwise press any single key" << endl;
cin >> key;
ToLower(key);
if (key == "y")
{
cout << "Enter file the input file name: ";
cin >> file;
input.open(file.c_str());
if (input.fail())
{
cout << "Cannot open the file." << endl
<< "Program terminated." << endl;
cin.get();
cin.ignore();
return 0;
}
else
{
StreamToLinkedList(input);
head = temp;
temp = temp->right;
}
}
else
{
cout << "Cannot found any input file to process" <<endl
<< "Program terminated."<< endl;
cin.get();
cin.ignore();
return 0;
}
do
{
cout<< "Do you want to open another service defining file?"<<endl
<< "Press (Y/y) for 'yes', otherwise press any key" <<endl;
cin >> key;
ToLower(key);
if (key == "y")
{
cout << "Enter file the input file name: ";
cin >> file;
input.open(file.c_str());
if (input.fail())
{
cout << "Cannot open the file." << endl
<< "Program terminated." << endl;
cin.get();
cin.ignore();
return 0;
}
else
{
StreamToLinkedList(input);
temp = temp->right;
}
}
} while ( key == "y");
cout << "-------------------------------------------------------------------" << endl
<< "PRINTING AVAILABLE SERVICES (FUNCTIONS) TO BE CHOSEN FROM THE USERS" << endl
<< "-------------------------------------------------------------------" << endl << endl;
printLinkedList();
cin.get();
cin.ignore();
return 0;
}
错误代码可能是什么?
您的访问冲突问题是 new 默认情况下不会将其分配的内存归零, 所以最后一个结构中的指针指向一个随机值。
temp2 = new Commands; // this memory is not initilized to zero
temp2 = new Commands(); // this memory is initialized to zero, (all elements is set to 0)
回答
你的打印功能没问题。您创建和管理列表的方式出了问题,可能是因为 您从未初始化 您的 Functions.right
和 Functions.down
字段,所以您的 linked 列表 linking 到无效内存。好吧,你实际上 link 你的列表。
您的某些分配,例如 temp2 = temp->down
和 temp = temp->right
没有任何意义,因为这些字段未初始化并且您正在覆盖这些变量(temp
和 temp2
) 之后添加新对象。
此外,您有重复的代码。您正在以完全相同的方式在两个不同的地方读取文件。问题是你的代码是错误的,所以你有双倍的错误要修复。此处代码重复的唯一明显原因是您希望在用户第一次输入和第 n 次输入时显示不同的消息。
我建议将这段代码放在它自己的函数中。否则找到一个更有效的方法来使用 conditionals/loops 这样你就没有那么多重复代码了。
注释
我有 "few" 关于您的代码的注意事项。 LinkedList 在两个 class 中实现,称为 Functions
和 Commands
。我知道你想要一个函数列表并且每个函数都有一个命令列表,但是你必须学会将程序的域分开来自其他功能。
IE: A LinkedList
是对象(任何种类)的容器。 Function
和 Command
是您为程序所做的特定内容,与 linked 列表本身无关。从概念的角度来看,Function
包含 Command
,但不一定通过 LinkedList
,或 map
,或 array
,等等
你的代码需要概念分离,看看它能有多清晰
// Linked list of functions
Functions list;
// No need to comment this one
LinkedList functions;
(我们不要争论缺少模板类型)
此外,除非使用复数来命名 class 有意义,否则您应该几乎总是使用单数(Functions
与 Function
)。这是因为当您实例化一个 class 时,您将拥有 一个 object/instance,因此使用复数形式表示该类型可能会产生误导。考虑以下声明,
Function someFunction; // This is a single function
Functions someFunction; // Is this one function or multiple functions??
List< Function > functions; // This is a list of functions
List< Functions > functions; // Is this a list of lists of functions???
您应该创建一个名为 LinkedList 的 class(提示:如果可以,请使用模板以提高其可重用性)。然后,如果您要将函数和命令的实现与 linked 列表分开,您可以制作类似
template <class T>
struct LinkedList {
T* obj;
LinkedList<T>* next;
LinkedList() : obj( nullptr ), next( nullptr ) {}
};
struct Command {
string cname;
};
struct Function {
string fname;
LinkedList<Command> commands;
};
现在您可以像这样声明您的函数列表,
LinkedList<Function> functions;
因为每个 Function
都有自己的 Command
列表,所以您有一个列表列表,您不必像在当前实施中那样独立管理每个列表。当然,你的列表仍然需要一个接口(和内存管理)但这不在这个问题的范围内。
编辑:
当 nullptr 不指向任何东西时初始化你的指针。
temp = new Functions;
temp->right = nullptr;
temp->down = nullptr;
或者使用默认构造函数,
struct Functions {
...
Functions() : right( nullptr ), down( nullptr ){}
};
然后像这样初始化,
temp = new Functions();