0

編集

簡単にするために、私は、リストを単純に通過する最も基本的なカーソルを作成したいと思っています。これは、方法や形状を変更したり、「開始」を形成したりすることはありません。私はまだ何かを返すときに変更され始めたいと思っていますが、直前ではありません。それで、新しいノードを追加したいときを除いて、何も変更せずにリストを調べて開始するためのポインターを作成することは可能ですか?

また、「ノード」ではない単純なポインタを使用してリストをたどることはできますか?

/編集

宿題の一部として作成する簡単な(単一の)リンクリストがあります。もちろん、それ以外にもやることはたくさんありますが、リストを邪魔にならないようにした後は、すべてを順調に進める必要がありますが、C ++をしばらく使用している間(ボーランドC ++でした)、私は多くのことをしました知っていたのは、半分忘れられているか、時代遅れです。私はしばらくの間Pythonでプログラミングしましたが、それはつまり、C++でのポインターの動作に不満を感じ続けるということです。

私の問題は、リストに新しいノードを追加しようとすると、カーソルが異常な方法で動作することです。以下で説明します。

編集:わかりました、私は変更しました:

Node *cursor;
cursor = new Node
cursor = begin;

大失敗ですが、宣言カーソルの後の結果は同じで、両方が同じメモリ位置(0x32ce8のようなもの)で始まります。

/編集

Node *add_node (Node *begin,string type, int sum, int ap_nr) // begin is the first node in the list
{
    // if first node is dummy node

    if (begin->ap_nr == -1)
        {
            begin->type = type;
            begin->ap_nr = ap_nr;
            begin->sum = sum;
            begin->next = 0;
            return begin;
        }

    // else create new node and insert it in sorted position

   else
    {
        // EDIT:
        Node *cursor = begin; // Same problem

        //if node should be inserted before first node (begin)

        if (ap_nr <begin->ap_nr)
        {
            cursor->ap_nr = ap_nr;
            cursor->type = type;
            cursor->sum = sum;
            cursor->next = begin;
            return cursor;
        }

常にデバッグするとき、beginは同様の形式です:0x32ce02、「カーソル」を作成するとき、それは大きく異なる形式(より長い)ですが、これを行うと:cursor = begin、カーソルはこの0x32df02のようになります。

ただし、問題は、「if(ap_nr ap_nr)」に到達したときに、実行可能な理由がまったくないため、カーソルが0x32ce02になり、「cursor-> next=begin」が無限ループを保証することです。また、ノードをいくつ追加しても、これは常に発生するため、リストを印刷するたびに、最後に追加されたノードの無限のストリームになります。

私は何か間違ったことをしていますか?それは宣言ですか、それとも割り当て、作成ですか?なにか ?

また、ポインタが*別のモジュールのどこかで始まり、この関数を使用して新しいbeginを返す場合...それは機能するはずですよね?

PS私はまた簡単なカウンターソリューションをいただければ幸いです(私のものがちょうど良くない場合にこれを行う別の方法)

また、私がどのようにリストを作成したかを指摘する必要があります。これは、ノードの単純なリンクです。

struct Node {
    string type;
    int ap_nr;
    int sum;
    Node *next;
};
4

3 に答える 3

2

このコード:

cursor = new Node;
cursor = begin;

次のことを行います。

  • スタックに新しいNodeオブジェクトを作成します
  • そのオブジェクトのアドレスを変数に入れますcurrent
  • そのアドレスを次のアドレスをbegin含むアドレスですぐに上書きします

つまり、新しいものをリークするだけNodeです。cursorその後、begin同じことを指さします。

したがって、行:

cursor->next = begin;

ループを作ります。cursor->next == begin == cursor

行を削除してcursor = begin;カーソルを戻すと、必要な処理が実行されます。で作成されたノードnew Nodeがリストの新しい先頭になりbegin、関数の先頭でポイントされたノードがそのリストの2番目のノードになります。

これで、そのリストをトラバース(追加ではなく)する場合、次のようなことができます。

 Node *cursor = begin; // assuming begin is the head of your list
 while (cursor != 0) {
    // process this node
    cursor = cursor->next;
 }

そして、それはあなたがそれを正しく構築したと仮定して、あなたのリストの各ノードを訪問します。

いくつかの注意:

  • この関数を呼び出すコードは、おそらく次のようになります。

    list = add_node(list, ...);
    

    あなたがそれを持っていない場合、あなたはあなたが望むものを手に入れることができません。

  • に表示されるアドレスが、によって返されるアドレスと大きく異なる場合は、何か問題が発生している可能性があります。つまりbegin、スタックアドレスを指している可能性があります。スタックのオブジェクトをリストに追加しないでください。すべてのオブジェクトに。を割り当ててください。(グローバル静的変数を指している場合、それは問題ありませんが、そうでないことを確認してください)。newbeginnewbegindelete

  • 実際にダミーノードが必要add_nodeでない限り、それも削除することをお勧めします。これにより、関数が必要以上に複雑になります。

これは、その特別なダミーノード(不完全なコード)なしでそれを行う方法のスケルトンです:

Node *add_node(Node *list, ...)
{
  Node *new_node = new Node;
  new_node->next = list;
  // fill in other properties
  return new_node;
}

そしてこれを使用するには:

int foo()
{
    Node *list = 0; // or nullptr for C++11
    list = add_node(list, ...); // add item 1
    list = add_node(list, ...); // add item 2
    list = add_node(list, ...); // add item 3
    ...
于 2012-03-31T08:47:29.500 に答える
1

明示的にそう言うので、ポインタcursorとは同じメモリ位置を指します。文字通り、「と同じ位置を指すという名前のポインタ変数を作成する」と言います。ですから、そうなるのは当然のことです。beginNode* cursor = begin; cursorbegin

編集:コードが何を意図しているのか間違った推測に基づいてアドバイスを削除し、より適切なアドバイスに変更しました

コメントから、元々増加していると仮定して、結果のリストでフィールドが増加するような位置にノードを挿入する必要があることがわかりましたap_nr(それでも正しくない場合は、必要なものを明確に記述してください) 。

その場合、の初期化cursorはもちろん正しくなりました。ただし、オブジェクトポイントを次のように変更することは正しくありません。そのノードの前に新しいノードを挿入したい。ただし、そのためにはいくつかの変更を加える必要があります。cursor

まず、新しく作成されたノードへのポインタを保持する別のポインタ変数が必要です。

Node* new_node = new Node;

次に、そのノードをリストに挿入する必要があります。つまり、etcの代わりにcursor->ap_nr=ap_nr;etcを使用する必要がありますnew_node->ap_nr=ap_nr;。また、それに続くノードはもちろんリストの最初のノード(によって示されるfirst)ではなく、見つけたばかりのノード(によって示されるcurrent)です。

ただし、ここで問題が発生します。その新しいノードをリストに挿入する必要があります。つまり、のノードのnextポインターを変更する必要があります(ただし、ではなく、新しく作成されたノードを指すようにします)。ただし、リストが単一にリンクされているため、つまり、見つかった要素から前の要素へのポインターがないため、前のノードへのポインターはもうありません。ただし、要素を挿入するには、を変更する必要あります。beginnext

ただし、持っているのは次のノードへのポインタです。したがって、より良い戦略は、cursorのノードをポイントにして、代わりに一貫して使用することです(もちろん、移動する場合を除く)。そうすれば、設定した後、次のように書くことができますcursor->nextcursorcursornew_node->nextcursor->next = new_node;

コードに欠けている他のことcurrentは、nullではないチェック(リストの最後にあります)と、実際に前進するコード(内部の一部にcursor属する)です。elseif

実際、ブロックが閉じられていないことに気付いたので、実際のコードに前進コードが含まれている可能性があります。

最後に、いくつかの一般的なアドバイス:関数のコードをモジュール化すると、おそらくそのコードを書くのが簡単になります。特定のノードの後に​​新しいノードを挿入する関数を1つ用意します(ポインターのみを変更しnext、ポインターを新しく挿入されたコード)、新しいノードが挿入されるノードを見つけるための別のadd_node関数があり、関数でそれらの他の関数のみを呼び出すようにします。そうすれば、各機能でサブ問題の1つに集中できます。

于 2012-03-31T09:27:43.917 に答える
1
    Node *cursor;
    cursor = new Node;
    cursor = begin;

ここでこれらの3行で何をしているのかを正確に理解してください。実際に理解しているよりも、さらに多くのことが起こっている可能性があります。

  • 最初の行で、 cursorという新しい変数を宣言します。この変数は、Node*タイプのポインターオブジェクトの名前です。(平易な英語では、 Node *は「ノードへのポインタ」を意味します)。
    ポインタオブジェクトに格納されるデータのタイプは、メモリ内のアドレスを表す単なる数値の整数データです。ポインタオブジェクトは、実際には他の種類の整数オブジェクトと何ら変わりはありません。
    (「変数」と「オブジェクト」の違いに注意してください。オブジェクトは、数値/文字/メモリアドレスなど、メモリに格納されているものであり、変数はオブジェクトの名前です)

  • 2行目では、2つのことが起こります。まず、Nodeオブジェクトにメモリを割り当て、割り当てられたメモリに新しいNodeオブジェクトを作成ます。このメモリには変数名がなく、単なるフリーストアオブジェクトです(これは、新しいノードのしくみ)次に、=演算子(代入演算子)を使用して、新しく割り当てられたNodeオブジェクトのアドレス値(数値)をカーソル変数に格納します。 新しいNodeオブジェクトのアドレス値を保存した後、新しく割り当てられたNodeオブジェクトにアクセスする唯一の方法は、カーソル変数名を使用することです。

  • 3行目では、カーソル変数に格納されている値をすぐに上書きします。新しいノードのアドレスデータを格納する代わりに、別のオブジェクトのアドレス(beginと呼ばれる別のポインタ変数からコピーされた他のオブジェクトのアドレス)を格納します。これは、新しく割り当てられたノードを「リーク」させるという即時の効果があります。

私が伝えようとしているポイント(あなたが気付いていないかもしれないと思います)は、これらの3行のコードで考慮すべき4つの異なるオブジェクト(つまり「メモリ内のアイテム」)が潜在的に存在するということです。それらのうちの2つは、 cursor and beginと呼ばれるポインターオブジェクト(整数)であり、他の2つは、名前はありませんが、ポインターオブジェクトによって格納されたアドレス値を使用してアクセスできるフリーストアオブジェクト(ノード)です。

あなたがここで読む価値があると思うかもしれないたくさんのリンクがあります:

于 2012-03-31T09:13:04.073 に答える