我认为这在我之前发生过。这是A3.txt
:
%INSERT
MARK 29
DAVID 21
JOHN 44
JOHN 51
LARRY 39
MARK 21
DAVID 18
JOHN 28
MARK 35
DONALD 41
PHIL 26
即使我在循环结束时使用sourcefile >> reader
,程序也会继续输出"reader: MARK"
,这意味着sourcefile >> reader;
语句不起作用(即,它会保持相同的输入一遍又一遍,或者它没有得到任何输入)。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct data
{
string name;
int id;
data* link;
};
data* start;
data* node;
ifstream sourcefile;
int main()
{
data* start = new data;
start -> link = NULL;
string input;
string reader;
sourcefile.open("A3.txt");
bool firstnode = true;
sourcefile >> input;
node = start;
cout << "Recieved command: " << input << endl;
if(input == "%INSERT")
{
// unlike the other ones, this function keeps reading until it hits another command
sourcefile >> reader;
cout << "Insert name: " << reader << endl;
// iterates through the link list until it hits the final node
while(node -> link != NULL)
node = node -> link;
while(reader[0] != '%')
{
if(firstnode)
start -> link = new data;
else
node -> link = new data;
sourcefile >> node -> name;
sourcefile >> node -> id;
node -> link = NULL;
sourcefile >> reader;
cout << "reader: " << reader << endl;
}
}
else
return 0;
}
另外...... offtopic。编译器说switch语句不能用于字符串,这是真的,还是我做错了什么?
答案 0 :(得分:2)
sourcefile >> node -> id;
失败,之后sourcefile
的所有输入操作都没有成功,因为failbit
流中设置了sourcefile
。 sourcefile >> node -> id;
失败,因为它尝试读取整数但在流中遇到“DAVID”。这是因为sourcefile >> reader;
消耗“MARK”,sourcefile >> node -> name;
消耗“29”,因此sourcefile >> node -> id;
会留下“DAVID”。尝试将sourcefile >> node -> name;
替换为node -> name = reader
。
是的,您不能在switch
中使用字符串,只能使用整数和枚举表达式。
在另一个offtopic note上,你似乎没有释放为节点分配的内存(简单的解决方案:只使用std::list
)。
编辑:如果你使用std::list
:
#include <iostream>
#include <fstream>
#include <string>
#include <list>
using namespace std;
struct data
{
string name;
int id;
};
ifstream sourcefile;
int main()
{
list< data > datalist;
string input;
string reader;
sourcefile.open("A3.txt");
sourcefile >> input;
cout << "Received command: " << input << endl;
if(input == "%INSERT")
{
// unlike the other ones, this function keeps reading until it hits another command
sourcefile >> reader;
cout << "Insert name: " << reader << endl;
while(reader[0] != '%')
{
data d;
d.name = reader;
sourcefile >> d.id;
datalist.push_back( d );
sourcefile >> reader;
cout << "reader: " << reader << endl;
}
}
}
答案 1 :(得分:2)
现在你的代码太多了。程序解决了一系列子问题,试图解决更大的问题。这会导致Single Responsibility Principle。
这意味着一个对象(类,函数等)应该只解决一个问题 。但是现在还没有发生。例如,main
通常不止一件事:它管理列表的节点(也不正确!没有任何东西被删除!),并从用户那里获得输入。这太过分了。
相反,分开了。您应该创建一个管理节点的list
类,然后main
应该使用它。请注意这里的区别:main
不再解决这个问题,它会利用一些功能。
因此,考虑到这一点,它会迅速跟随我们分解的越多,正确,修复和维护就越容易。采取代码并将其拆分的行为是“重构”。我们这样做。
首先,我们需要一个链表来使用。通常我们有std::vector
(注意:链接列表通常是更糟糕的容器)或std::list
,但由于你的老师 dumb 被误导,他让你自己编写。您的作业应 编写列表容器或使用列表容器并读取输入,而不是两者。 (同样,在现实世界中,我们将事情分开;为什么要教人们混合它们?)
你已经掌握了基础知识,只需要封装它。 (如果你还不上课,请告诉我,我也会扩展到那里;当我们在那里时,如果你还没有,你可能想要good book来教你自己老师不是):
// normally this should be a template so it can store anything,
// and yadda yadda (more features), but let's just make it basic
// this data class is what the linked list holds
struct data
{
std::string name;
int id;
};
class linked_list
{
public:
linked_list() :
mHead(0)
{}
// the magic: the destructor will always run
// on objects that aren't dynamically allocated,
// so we're guaranteed our resources will be
// released properly
~linked_list()
{
// walk through the list, free each node
while (mHead)
{
node* toDelete = mHead; // store current head
mHead = mHead->next; // move to next node
delete toDelete; // delete old head
}
}
void push_back(const data& pData)
{
// allocate the new node
node* newNode = new node(pData, mHead);
// insert
mHead = newNode;
}
data pop_back()
{
// remove
node* oldNode = mHead;
mHead = mHead->next;
// deallocate
data d = oldNode->data;
delete oldNode;
return d;
/*
the above is *not* safe. if copying the data throws
an exception, we will leak the node. better would be
to use auto_ptr like this:
// now the node will be deleted when the function ends, always
std::auto_ptr<node> n(oldNode);
// copy and return, or copy and throw; either way is safe
return n->data;
but who knows if your <strike>dumb</strike>misguided
would allow it. so for now, make it unsafe. i doubt
he'd notice anyway.
*/
}
private:
// any class that manages memory (i.e., has a destructor) also needs to
// properly handle copying and assignment.
// this is known as The Rule of Three; for now we just make the class
// noncopyable, so we don't deal with those issues.
linked_list(const linked_list&); // private and not defined means it
linked_list& operator=(const linked_list&); // cannot be copied or assigned
struct node
{
// for convenience, give it a constructor
node(const data& pData, node* pNext) :
d(pData),
next(pNext)
{}
data d; // data we store
node* next; // and the next node
};
node* mHead; // head of list
};
现在您有一个要使用的列表。 main
将不再对此类事情感到困扰:
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
using namespace std; // should generally be avoided
// your linked_list code
int main()
{
// don't declare variables until you need them,
// and avoid globals. (the previous rule helps)
ifstream sourcefile("A3.txt");
// check that it opened
if (!sourceFile.is_open())
{
cerr << "could not open file" << endl;
// EXIT_FAILURE is inside <cstdlib>
return EXIT_FAILURE;
}
string input;
sourcefile >> input;
cout << "Received command: " << input << endl;
linked_list datalist;
if (input == "%INSERT")
{
string reader;
sourcefile >> reader;
cout << "Insert name: " << reader << endl;
while (reader[0] != '%')
{
data d;
d.name = reader;
sourcefile >> d.id;
datalist.push_back(d);
sourcefile >> reader;
cout << "reader: " << reader << endl;
}
}
}
请注意阅读更容易。您不再管理列表,而只是使用它。列表管理自己,所以你永远不会泄漏任何东西。
这是您想要采取的路线:将事物包装成正确解决一个问题的工作对象,并将它们一起使用。