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 ステートメントは文字列では使用できないと言いましたが、それは本当ですか、それとも何か間違ったことをしたのでしょうか?

4

2 に答える 2

2

今、あなたのコードはやりすぎです。プログラムは、より大きな問題を解決するために、一連のサブ問題を解決します。これは、単一責任の原則につながります。

つまり、1つのオブジェクト(クラス、関数など)は1つの問題のみを解決する必要があります。しかし、今はそれは起こっていません。たとえば、main自明に複数のことを行います。リストのノードを管理し(誤って、何も削除されません!)、ユーザーからの入力を取得します。これは、やりすぎ。

むしろ、物事を分割します。ノードを管理するlistクラスを作成してから、それmain使用する必要があります。ここでの違いに注意してください。mainもはやその問題を解決するのではなく、解決する何かを利用します。

したがって、これを念頭に置いて、物事を分割すればするほど、修正、修正、および保守が容易になります。コードを取得して分割するという行為は「リファクタリング」です。そうしよう。

まず、使用するリンクリストが必要です。通常、私たちはstd::vector(注:リンクリストは一般的に悪いコンテナです)またはstd::listを持っていますが、あなたの先生はばかげているので、あなたにあなた自身を書かせています。割り当ては、リストコンテナーを作成する、リストコンテナーを使用して入力を読み取るか、両方ではない必要があります。(繰り返しますが、現実の世界では物事を分割します。なぜ人々にそれらを混ぜるように教えるのですか?)

あなたはすでに基本を理解しています、それはただカプセル化される必要があります。(クラスをまだ知らない場合は、私に知らせてください。私もそこで展開します。私たちがそれをしている間、まだ知らない場合は、先生が何であるかを自分自身に教えるための良い本を手に入れたいと思うかもしれません。 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
};

これで、使用するリストができました。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;
        }
    }
}

読みやすいことに注意してください。リストを管理するのではなく、単にそれを使用します。そして、リストはそれ自体を管理するので、何もリークすることはありません。

これがあなたがたどりたいルートです:1つの問題を正しく解決する作業オブジェクトに物事を包み、それらを一緒に使用します。

于 2010-10-15T20:49:12.443 に答える
2

sourcefile >> node -> id;失敗し、その後、ストリームで設定されるように、からの入力操作はどれもsourcefile成功しません。整数を読み込もうとしたが、ストリームで「DAVID」に遭遇したため失敗しました。これは、「MARK」を消費し、「29」を消費するため、「DAVID」が残るためです。に置き換えてみてください。failbitsourcefilesourcefile >> node -> id;sourcefile >> reader;sourcefile >> node -> name;sourcefile >> node -> id;sourcefile >> node -> name;node -> name = reader

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;
  }
 }
}
于 2010-10-15T19:45:40.177 に答える