

連結リストを勉強しているのですがうまく機能しません。  
わかる方がいれば、どこが間違っているか教えてください。

Activity::appendの目的は、headがNULLの場合は連結リストの最初のnodeを作成し、もし先にnodeがあった場合は、その後にnodeを生成するといったものです。

しかし、実行して連結リストを表示したところ、一番最後に入力したnodeの情報しか表示されませんでした。

改善すべき点があれば、お願いします。

[code]

    #include <iostream>
    #include <cctype>
    #include <cstring>
    using namespace std;
    
    const int SIZE = 20;
    const int SIZE2 = 130;
    const int SIZE3 = 100;
    
    struct node
    {
      char name [SIZE];
      char explain [SIZE2];
      char reason [SIZE3];
      int times;
      node *next;
    };
    
    class Activity
    {
      public:
        Activity();
        ~Activity();
        void read();
        void append(char name[], char explain[], char reason[], int times);
        void display();
      
      private:
        node *head;
    };
    
    Activity::Activity()
    {
      head = NULL;
    }
    
    Activity::~Activity()
    {
      while(head != NULL)
      {
        node *temp;
        temp = head -> next;
        delete head;
        head = temp;
      }
    
      delete head;
      
    }
    
    
    void Activity::append(char name[], char explain[], char reason[], int times)
    {
        if(NULL == head)  
        {  
        cout << endl;
        head = new node;
        strcpy(head->name,name);
        strcpy(head->explain,explain);
        strcpy(head->reason, reason); 
        head->times = times;  
        head->next = NULL;
        }
        else
        {
          node *current = head;
          while(current->next!= NULL)
          {
            current = current ->next;
          }
          current->next = new node;
          current = current->next;
          strcpy(head->name,name);
          strcpy(head->explain,explain);
          strcpy(head->reason, reason); 
          head->times = times;  
          head->next = NULL;
          current->next = NULL;
        }
    
    }
    
    void Activity::display()
    {
      if(head == NULL)
      return;
      node *current = head;
      while(current != NULL)
      {
        cout <<current->name <<endl;
        cout <<current->explain << endl;
        cout <<current->reason << endl;
        cout <<current->times << endl;
        cout << endl;
        current = current->next;
      }
    }
    
    int main()
    {
      Activity my_activity;
      char response ='y';
      do
      {
        char name [SIZE];
        char explain [SIZE2];
        char reason [SIZE3];
        int times;
        cout <<"Please enter name of activity"  << endl;
        cin.get(name, SIZE, '\n');  cin.ignore(100, '\n');
        cout <<"Please explain detail of it" << endl;
        cin.get(explain, SIZE2, '\n');  cin.ignore(100, '\n');
        cout <<"please explain why do you want to do" << endl;
        cin.get(reason, SIZE3, '\n');  cin.ignore(100, '\n');
        cout <<"How many times does it take?" << endl;
        cin >> times;  cin.ignore(100, '\n');
    
        my_activity.append(name, explain, reason, times);
    
        cout <<"Do you want to continue to append?" << endl;
        cin >> response; cin.ignore(100,'\n');
      }while(response=='y');
      my_activity.display();
    }
    
[/code]


CC BY-SA 4.0
2021-03-11T20:42:04.373
74601
2021-03-16T00:27:53.757
2021-03-16T00:27:53.757
3060
44009
question
c++
連結リストの表示


「うまく機能しません」ではあなたが期待している動作とプログラムの実際の動作が違うことしかわかりません。オイラたち読者が勝手な解釈で「こうなってほしいに違いない」と思って回答しても、実はあなたの期待通りでない：なんてことはよくありますし、そうなると回答は無駄になってしまいます。

* * *

というわけでオイラの勝手な解釈で  
期待：入力した要素が全部、入力した順に表示されてほしい  
現実：最後の要素だけが表示されている  
であるものとして（希望に沿わない場合は他の人の回答をお待ちあれ）

表示ルーチン `Activity::display()` は誤っていないように思われます。誤っているのは `Activity::append()`
のほうでしょう。んで、どう直すかは「何が正しいのか」で全く異なりますので先の苦言のようなことになります。

`Activity::append()` に期待されている動作を妄想するに

  * 名前からして `head` は連結リストの先頭を示したいのであろう
  * 連結リストが無い場合は先頭の要素を作成 (`head` を更新)
  * 連結リストがある場合は連結リストの末尾に１つ要素を追加 (`head` を更新してはならない)

`head` は「先頭の要素」を表す (表したい) のであれば、これを更新してよいのは最初の要素を作ったときのみで、既に要素がある場合には `head`
自体を書き換えてはならないわけです。その辺を修正すると良さそうです（オイラからは今すぐ修正例を提示しないことにしますので、うまく修正できたら自己回答していただけると幸い）

* * *

回答がないのは SO 的にはカッコよくないのでコードサンプルを提示してみる。前後を略すが当然ながら `Activity::append()`
の中身ということでよろしく

Level 1 な回答 : 既にリストがある場合には `head` を更新しないを素直に実装

[code]

    node* self=new node; // strcpy 等は省略
    self->next=NULL;     // 次がない、とは要するに末尾のこと
    if (head==NULL) {    // リストが無い、つまり今回作ったやつが先頭
        head=self;       // 先頭ありにして終了
        return;
    }
    // 既にリストがある場合、今回作ったやつを末尾に追加
    // このときは head を更新してはいけない
    node* p=head;
    for (; p->next!=NULL; p=p->next); // 末尾を探す
    // 今ここで p は有効な末尾ノードのはずだから
    p->next=self; // self->next は既に NULL だからこれだけでよい
    
[/code]

Level 2 な回答 : なんだか `if` が格好悪いのでこれを除去したくなる

[code]

    // 前略：何をどうしているのか敢えて解説しないので読解よろしく
    node** p = &head;
    for (; *p != NULL; p = &(*p)->next);
    *p = self;
    
[/code]

Level 3 な回答 : これら「追加処理」は `Activity` のメンバーですべきでないし、おそらく `node`
でもすべきではないので、もう１つリストクラスを作るべきかもしれない。


CC BY-SA 4.0
2021-03-12T05:08:58.100
74614
2021-03-15T01:03:14.673
2021-03-15T01:03:14.673
8589
8589
74601
answer