文件提取似乎没有前进到文件中的下一个单词

发布于 2024-09-27 08:07:36 字数 1590 浏览 0 评论 0原文

我想这种事以前也发生在我身上。这是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;

}

还有……题外话。编译器说 switch 语句不能与字符串一起使用,这是真的吗,还是我做错了什么?

I think this has happened to me before. This isA3.txt:

%INSERT
MARK 29 
DAVID 21
JOHN 44
JOHN 51
LARRY 39
MARK 21
DAVID 18
JOHN 28
MARK 35
DONALD 41
PHIL 26

Even though I use sourcefile >> reader at the end of the loop, the program keeps outputting "reader: MARK", meaning the sourcefile >> reader; statement isn't working (i.e., it keeps getting the same input over and over again, or it's not getting any input).

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

}

Also... offtopic. The compiler said that switch statements can't be used with strings, is that really true, or was I doing something else wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

妄想挽回 2024-10-04 08:07:36

源文件>>节点-> id; 失败,此后来自 sourcefile 的输入操作都不会成功,因为 failbitsourcefile 流中设置。 源文件>>节点-> id; 失败,因为它尝试读取整数但在流中遇到“DAVID”。发生这种情况是因为 sourcefile >> reader; 消耗“MARK”,sourcefile>>节点-> name; 消耗“29”,因此 sourcefile >>>节点-> id; 然后留下“DAVID”。尝试替换sourcefile>>节点-> name;node ->名称=读者

是的,您不能在 switch 中使用字符串,只能使用整数和枚举表达式。

在另一个题外话中,您似乎没有释放为节点分配的内存(简单的解决方案:只需使用 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;
  }
 }
}

sourcefile >> node -> id; fails, and after that none of the input operations from sourcefile succeed, as failbit becomes set in the sourcefile stream. sourcefile >> node -> id; fails because it tries to read an integer but encounters "DAVID" in the stream. That happens because sourcefile >> reader; consumes "MARK", sourcefile >> node -> name; consumes "29", so sourcefile >> node -> id; is then left with "DAVID". Try replacing sourcefile >> node -> name; with node -> name = reader.

And yes, you can't use strings in switch, only integral and enumeration expressions.

On another offtopic note, you don't seem to release the memory allocated for nodes (easy solution: just use std::list).

EDIT: Here's how your program might look like when if you used 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;
  }
 }
}
蓝色星空 2024-10-04 08:07:36

现在你的代码做了太多事情。程序解决一系列子问题以试图解决更大的问题。这就引出了单一责任原则

这意味着一个对象(类、函数等)应该解决一个问题。但现在这并没有发生。例如,main 简单地做了不止一件事:它管理列表的节点(也是错误的!没有任何内容被删除!),并从用户获取输入。这太过分了。

相反,把事情分开。您应该创建一个管理节点的 list 类,然后 main 应该使用它。请注意这里的区别:main 不再解决这个问题,它利用了可以解决这个问题的东西。

因此,考虑到这一点,我们很快就会发现,我们把事情分解得越多,纠正、修复和维护就越容易。获取代码并将其拆分的行为就是“重构”。让我们这样做吧。

首先,我们需要一个链表来使用。通常我们有 std::vector (注意:链表通常是最糟糕的容器)或 std::list,但由于你的老师是愚蠢< /strike>误导了,他让你自己写。您的作业应该是编写列表容器或使用列表容器并读取输入,而不是两者兼而有之。 (同样,在现实世界中,我们将事物分开;为什么教人们混合它们?)

您已经掌握了基础知识,只需要封装即可。 (如果您还不知道类,请告诉我,我也会在那里进行扩展;当我们这样做时,如果您还不知道,您可能想要获得 一本好书,教你自己,你的老师不会):

// 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;
        }
    }
}

注意它的阅读变得多么容易。您不再管理列表,而只是使用它。而且该列表会自行管理,因此您永远不会泄漏任何内容。

这是您要采取的路线:将事物包装到正确解决一个问题的工作对象中,然后将它们一起使用。

Right now your code does too much. Programs solve a collection of sub-problems in an attempt to solve a larger problem. This leads to the Single Responsibility Principle.

What that means is that one object (class, function, etc.) should solve one problem only. But right now that's not happening. For example, main trivially does more than one thing: it manages nodes for the list (incorrectly, too! Nothing is ever deleted!), and gets input from the user. This is too much.

Rather, split things up. You should make a list class that manages nodes, and then main should use it. Note the difference here: main no longer solves that problem, it utilizes something that does.

So with this in mind, it quickly follows the more we split things up, the easier it is to be correct, fix, and maintain. The act of taking code and splitting it up is "refactoring". Let's do that.

First, we need a linked list to use. Normally we have std::vector (note: linked lists are generally the worse container there is) or std::list, but since your teacher is dumbmisguided, he's making you write your own. Your assignment should be either write a list container or use a list container and read input, not both. (Again, in the real world we split things up; why teach people to mix them?)

You already have the basics down, it just needs to be encapsulated. (If you don't know classes yet, let me know and I'll expand there too; while we're at it, if you don't already you might want to get a good book to teach yourself what your teacher isn't):

// 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
};

Now you have a list to use. main will no longer be troubled with such things:

#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;
        }
    }
}

Note how much easier it is to read. You no longer manage a list, but simply use it. And the list manages itself, so you never leak anything.

This is the route you'll want to take: wrap things into working objects that solve one problem correctly, and use them together.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文