0

私はC++でのリンクリストの実装に取り​​組んでいます。過去にJavaでこれを行ったことがありますが、コードがコンパイルされるため、C ++でポインターを使用してこれを行う方法がわかりませんが、実行するとセグメンテーション違反が発生します。私は何が間違っているのですか?

私のnode.hファイル

#ifndef NODE_H
#define NODE_H

#include <string>
using namespace std;

class Node
{
public:

    Node(const string, const int) ;
    ~Node() { }
    void setNext(Node *); // setter for the next variable
    Node * getNext();     // getter for the next variable
    string getKey();      // getter for the key variable
    int getDistance();    // getter for the dist variable

private:
   Node *next;
   int dist;
   string key;
};

#endif

私のNode.cppファイル

#include "node.h"
#include <string>

Node::Node(string key, int dist){
    key = key;
    dist = dist;
}

void Node::setNext(Node * next){
    next->next;
}

Node * Node::getNext(){
    return this->next;
}

string Node::getKey(){
    return key;
}

int Node::getDistance(){
    return dist;
}

そして私のmain.cppファイル

#include "node.h"
#include <iostream>

using namespace std;

int main(){
    Node* nptr1 = new Node("Test1", 2);
    Node* nptr2 = new Node("Test2", 2);
    Node* temp;

    nptr1->setNext(nptr2);
    temp = nptr1->getNext();
    cout << temp->getKey() << "-" << temp->getDistance() << endl;
}

どんな助けでも大歓迎です。ありがとう。

4

2 に答える 2

2

すべてのメンバーを定義済みの値に初期化する必要があります。パラメータとメンバーに同じ名前を付けるべきではありません。これはほとんどの場合、混乱やバグの原因となります。

Node::Node(string key_val, int distance)
    : next(0)
{
    key = key_val;
    dist = distance;
}

さらに良いことに、メンバーの初期化を使用します

Node::Node(string key_val, int distance)
    : next(0),
      key(key_val),
      dist(distance)
{
}

コメンターがすでに指摘しているように、指定されたパラメーターにnextポインターを設定する必要があり、パラメーターを変更するのではなく、メンバーを変更する必要がありますsetNext()this->next

void Node::setNext(Node * next_ptr){
    next = next_ptr;
}
于 2013-02-14T18:49:25.447 に答える
0

ポインタ/動的メモリ割り当てを備えた言語のリンクリストおよびその他のデータ構造の鍵は、各操作で考えられるすべての状態(ケース)をマップすることです。いずれの場合も、コードがポインタとメモリを正しく処理することを確認する必要があります。これがおそらく、それを実装するように求められている理由です。発生する落とし穴について考える方法を教えるためです。したがって、私は単に直接的な解決策を提供するのではなく、この機会を利用して、この問題や将来の問題についてあなたや他の人を助ける基本的な概念を理解する方法を概説します。

テール挿入のあるstage1(非常に基本的な)リンクリストのように見える場合でも、ある種のマッピングスキームを開発する必要があります。main()私の個人的な経験は、 :内の各行についてです。

  1. オブジェクトごとにボックスを描画します
  2. ボックス内のすべてのデータ変数を一覧表示します
  3. 非ポインタ変数の横に初期化/割り当てられた値をリストします
  4. ポインタ変数からポイントされていることがわかっているオブジェクトに矢印を描画します
  5. ポインタ変数から割り当てられていないポインタの空白領域に矢印を描画します

知っておくべき重要なことの1つは、初期化されていないデータとポインターは、OS /コンパイラーによって異なる未定義のプロパティを示すため、適切な初期値を使用してそれらのほとんどを定義することが重要な場合がよくあります。宣言時に常に安全なデフォルトに初期化することが私に役立つことがわかりました(それが不可能であるか、パフォーマンスの問題が発生する場合がありますが、それらは必要に応じて処理できます-たとえば、レイジー初期化)。Javaとは異なり、基本的なC ++は、デフォルトでnullポインター例外を発生させたり、初期値を提供したり、ガベージコレクションを実行したりしません(コンパイラー/ライブラリーと渡されたオプションに大きく依存します)。せいぜい、プログラムはセグメンテーション違反(通常は想定外のメモリにアクセスしたことを意味するより一般的な例外)になります。最悪の場合、プログラムは引き続き機能しますが、予期しない動作をするか、フィードバックなしでクラッシュします。したがって、マッピングスキームを使用して、オブジェクトへのポインタNULLまたはオブジェクトに対して実行されたfree/delete実行されたオブジェクトへのポインタに対して操作を実行していないことを確認する必要があります。さらに、それらが指している場所が理にかなっていることを確認する必要があります。他のリンクスキームと同様に、ノードをそれ自体にリンクしたり、循環リンクを作成したりするなどのパラドックスが発生する可能性があります。

したがって、前述のように、各操作で発生する可能性のあるすべてのケースを追跡することも重要です。このプログラムがデータ構造またはポインターを学習する手段である場合、私が思うに、間違いなく、より高度なリストを実装するように求められます。より高度なリストは扱いにくい場合があるため、特定の操作を実行するために特別な注意が必要になる可能性があるかどうかを判断するために、早い段階で習慣を身に付ける必要があります(コーナーケース)。リストの場合、リストが空、1つの要素、2つの要素、または2+の要素がある場合を考慮する必要があります。また、要素が開始、終了、またはその中間のどこから挿入/削除されているかを考慮する必要がある場合もあります。繰り返しになりますが、これらのケースがどのように実行されるかを理解するために、マッピングを広範囲に使用してください。あなたは本当に前述の方法を使ってこれを考えようとするべきですが、あなたはチェックすることもできます詳細については、ウィキペディアまたはデータ構造の教科書を参照してください。

ところで、レイモンドが述べたように、デバッガーを使用して問題を確認することができます。実際、これまでC / C ++デバッガーを使用したことがない場合は、これが学習に最適な時期です。これが機能したら、プラットフォームのC /C++デバッガーに関するドキュメントを調べてください。これを使用して、機能していないコードをステップ実行しmain()、データ値がマッピングの期待値と一致するかどうかを確認してください。この種のスキルは、後で非常に貴重であることがわかります。

また、これthisは通常C ++でのポインタであるため、Java / Pythonでの使用方法と混同しないでください。メンバーデータには、一部の人が示唆しているようにthis->somedata NOTを使用してアクセスします。 そうは言っても、わかりやすくするために、メンバー変数と同じパラメーター名がある場所ではthis.somedataの規則を使用することをお勧めします。this->somedata = somedataもちろん、異なるパラメータ名を使用するというアドバイスも機能します。

于 2013-02-16T17:57:42.790 に答える