2016-07-19 15 views
1

まず、重複した質問の場合は、お詫び申し上げます。私はちょうどC + +を学んでいると私はおそらく、私はすでに尋ねられていることを見つけるために正しい検索条件を知らない。ポインタと静的オブジェクトと新しいオブジェクト

とにかく、私はHackerRankの30日間のコードを使ってC++を教えています。しかし、私は、LinkedListのメソッドinsertを実装するように頼まれたときに解決できないようなロードブロッキングを打ちました。概念的には、何をする必要があるかを知っていますが、構文的に私は問題にぶつかっています。

以下は私のコードで、デバッグ用の印刷物が含まれています。何が起こっているように見えるのは、ループ反復に関係なく、new_nodeがメモリ内の同じ場所に置かれ続けることです。これが確実にメモリ内の新しい場所になるようにしますか? new_nodestaticとして宣言しても、同じ動作をするようです。

ここでは、コードです:

#include <iostream> 
#include <cstddef> 
using namespace std;  
class Node 
{ 
    public: 
     int data; 
     Node *next; 
     Node(int d){ 
      data=d; 
      next=NULL; 
     } 
}; 
class Solution{ 
    public: 
    /// ----- MY CODE BEGINS HERE: 
     Node* insert(Node *head,int data) 
     { 
      cout << "----------" << endl; 
      cout << data << endl; 
      int i = 0; 

      if (head){ 
       Node *curr = head; 
       Node *next = curr->next; 

       while(next){ 
        cout << data << "," << i << ": " << curr << "," << curr->next 
        << "," << curr->data << endl; 
        i++; 
        curr = curr->next; 
        next = curr->next; 
       } 
       cout << data << "," << i << ": " << curr << "," << curr->next 
        << "," << curr->data << endl; 
       static Node new_node = Node(data); 
       curr->next = &new_node; 
       cout << " *** Adding " << data << " at " << curr->next 
        << " and next points to: " << (curr->next)->next << endl; 
       return head; 
      } 
      else{ 
       static Node new_head = Node(data); 
       cout << " *** Adding " << data << " at " << &new_head 
        << " and next points to: " << new_head.next << endl; 
       return &new_head; 
      } 
     } 
     // ------- MY CODE ENDS HERE 
     void display(Node *head) 
     { 
      Node *start=head; 
      while(start) 
      { 
       cout<<start->data<<" "; 
       start=start->next; 
      } 
     } 
}; 
int main() 
{ 
    Node* head=NULL; 
    Solution mylist; 
    int T,data; 
    cin>>T; 
    while(T-->0){ 
     cin>>data; 
     head=mylist.insert(head,data); 
    } 
    mylist.display(head); 

} 

私がのサンプル入力でこれを実行すると(4、2、3、4、1)、私は次を得る:

---------- 
2 
*** Adding 2 at 0x6022e0 and next points to: 0 
---------- 
3 
3,0: 0x6022e0,0,2 
*** Adding 3 at 0x7fff3ddc1d80 and next points to: 0 
---------- 
4 
4,0: 0x6022e0,0x7fff3ddc1d80,2 
4,1: 0x7fff3ddc1d80,0,3 
*** Adding 4 at 0x7fff3ddc1d80 and next points to: 0x7fff3ddc1d80 
---------- 
1 
1,0: 0x6022e0,0x7fff3ddc1d80,2 
1,1: 0x7fff3ddc1d80,0x7fff3ddc1d80,4 
1,2: 0x7fff3ddc1d80,0x7fff3ddc1d80,4 
1,3: 0x7fff3ddc1d80,0x7fff3ddc1d80,4 
1,4: 0x7fff3ddc1d80,0x7fff3ddc1d80,4 
1,5: 0x7fff3ddc1d80,0x7fff3ddc1d80,4 

と、これはセグメンテーションフォールトが無限ループに巻き込まれるまで続きます。

new_nodeが同じメモリロケーション(staticありまたはなし)に配置され続ける理由はありますか。これは主要な問題ではないのですか?私は完全にその点を見逃していますか?前もって感謝します!

- C++新生児。


編集:提案されたduplicateは、ここでの質問にはあまり関係しません。私の悩みは、ポインタと参照の違いを理解するのではなく、違いはなかった(!明らかに)私は質問を書いている時点でnewオペレータを知らなかったとして

Node node_1 = Node(data); 
static node_2 = Node(data); 
node_3 = new Node(data); 

、私はに知りませんでした(a)これを検索するか、(b)タイトルにこの用語を含める。タイトルは明確にするために編集されています。この編集は、今後の読者にも含まれています。

+1

リンクリストは、不快の1ポインタを学ぶためにそれらを強制的にプログラミング言語を学ぶ人たちの上に落ちています。ここで重要なことは、ポインタの所有権(誰がもはや必要でないときに指し示されたメモリを維持し、解放する責任を負う)と指し示すメモリの寿命(いつそれが削除されるか)である。リンクされたリストに関して、リストを動作させることは、紙に必要な接続への接続と変更を描画してから、描画を使用して実行する必要のある動作を確立することに勝るものはありません。 – user4581301

+0

*えええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええ、 "* ###実装されているように私は少しバロックすぎているようです。本当にあなたは' 'curr''と' 'next''ポインタの両方を必要としません。あなたは 'curr-> next == NULL'を見つけるまで反復する必要があります。その時点で、 'next'ポインタが' NULL'である新しいノードを割り当て、 'curr-> next'に割り当てます。あなたの "法的なパッドと数字の2つの鉛筆"が表示されます。 –

+0

@MikeRobinsonフィードバックをありがとう - しかし、あなたはどちらも実際にはアルゴリズムに関するものではなく、C++の構文と詳細に関する私の質問に答えています(受け入れられた答えがそうでした)。 – brettb

答えて

5

変数staticを宣言すると、その変数のコピーは1つのみです。宣言を初めて実行するときに作成され、将来関数を呼び出すと同じデータが再利用されます。したがって、new_nodeを使用するたびに、同じノードになります。

new演算子を使用して動的データを割り当てる必要があります。演算子の名前が示すように、これは使用するたびに新しいオブジェクトを作成します。 remove()操作をクラスに追加すると、deleteを使用してメモリが解放されます。

Node* insert(Node *head,int data) 
    { 
     cout << "----------" << endl; 
     cout << data << endl; 
     int i = 0; 

     if (head){ 
      Node *curr = head; 
      Node *next = curr->next; 

      while(next){ 
       cout << data << "," << i << ": " << curr << "," << curr->next 
       << "," << curr->data << endl; 
       i++; 
       curr = curr->next; 
       next = curr->next; 
      } 
      cout << data << "," << i << ": " << curr << "," << curr->next 
       << "," << curr->data << endl; 
      Node *new_node = new Node(data); 
      curr->next = new_node; 
      cout << " *** Adding " << data << " at " << curr->next 
       << " and next points to: " << (curr->next)->next << endl; 
      return head; 
     } 
     else{ 
      Node *new_head = new Node(data); 
      cout << " *** Adding " << data << " at " << &new_head 
       << " and next points to: " << new_head->next << endl; 
      return new_head; 
     } 
    } 
1

静的変数を使用します。これらは一度だけ作成され、すべての関数呼び出しで同じです! あなたの意図は常に新しいノードを作成することです、これらの変数は静的ではありません!

は、関数が終了したときにそうでない場合は、クリーンアップを取得、すべてのノードは、(新しいと)無料ストアに作成する必要があります

Node* new_head = new Node(data); 
return new_head; 
// as well as 
Node* new_node = new Node(data); 
curr->next = new_node; 

でそれを試してみてください。 これは、常にメモリ破損である既存の変数を参照していないことを意味します。新しいノードを削除するデストラクタも用意する必要があります。 詳細については、変数の有効期間についてを参照してください。

さらに注記:

  • 使用nullptr
  • のstd ::リスト、またはSTD :: linked_listリストのためのコンテナを(私はあなたが学びたい、知っているが、それらを見てみましょう)している
  • あなたのクラスはすべてパブリックです - 構造体を使用することはできますが、それはアクセス指定子には同じですがデフォルトのパブリックなので、使用できます。
  • 所有権の利用unique_ptrを(これはちょっと高度ですが、早期にそれを使用)
+0

私の意見では、このようなアルゴリズムでは何も「静的」なものを指定する必要はありません。そのような理由はないので、IMHO変数は 'static'宣言すべきではありません。 –

+0

が一致します。とにかく静的変数は非常に余分に使われるべきです。通常はスタック変数が必要です(コンテナを使用した動的メモリ管理など)。フリーストア変数の必要性さえめったにありません。スマートポインタがスタック変数としても修飾されていると仮定すると、 –

+0

ありがとう@jonas_toth - この回答も役に立ちました! – brettb

関連する問題