2013-02-14 208 views
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; 
} 

任何帮助将不胜感激。 谢谢。

+0

你的'setNext'函数不会做任何事情...... – Mat 2013-02-14 18:42:36

+0

'this.next = next;'? – Kevin 2013-02-14 18:43:31

+0

list <>或slist <>是在C++中使用它的正确方法。只有在C,你必须像这样弄脏你的双手...... – 2013-02-14 18:44:16

回答

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) 
{ 
} 

为评论者所指出的,你必须在setNext()设置next指向给定的参数,你应该修改参数,但this->next成员

void Node::setNext(Node * next_ptr){ 
    next = next_ptr; 
} 
0

带指针/动态内存分配的语言中链接列表和其他数据结构的关键是映射出每个操作的所有可能状态(情况)。您必须确保您的代码在每种情况下都能正确处理指针和内存。这可能是你被要求实施它的原因:教你如何思考出现的陷阱。因此,我不会简单地给你一个直接的解决方案,而是概述如何抓住这个机会来理解那些能够帮助你和其他人解决这个问题和未来问题的基本概念。

即使在似乎是一个stage1(非常基本的)带尾部插入的链表中,你也应该开发某种映射方案。我个人的经验是,在各行中main()内:

  1. 在框中画一个框为每个对象
  2. 列表中的所有数据变量
  3. 列表中的非指针变量旁边的任何初始化/分配的值从指针变量
  4. 绘制箭头对象,你知道被指出从指针变量
  5. 画箭头的空白区域用于未分配的指针

要知道的一件事是,未初始化的数据和指针表现出未定义的属性,这些属性因操作系统/编译器而异,因此使用合适的初始值定义大多数属性通常是至关重要的。我发现总是初始化为一个安全的默认声明已经很好地运行了(有些情况下它是不可能的或者会产生性能问题,但是这些可以根据需要进行处理 - 例如,延迟初始化)。与Java不同,基本的C++在缺省情况下不会引发空指针异常,提供初始值或垃圾收集(它高度依赖编译器/库并传递选项)。充其量,你的程序最好是segfault(通常意味着你已经访问过你不应该访问的内存的更一般的异常),在更糟糕的情况下,它会继续工作但行为不可预测或崩溃而没有反馈。因此,您应该使用映射方案来验证您没有对指向NULL的指针执行操作,或者指向已对其执行free/delete的对象的指针。此外,你会想确保他们指向的地方有意义。像任何链接方案一样,您可能会有一些悖论,如将节点链接到自身或创建循环链接。

因此,如前所述,跟踪每个操作的所有可能情况也很重要。如果这个程序是一种学习数据结构或指针的手段,正如我猜想的那样,毫无疑问,您会被要求实现更高级的列表。更高级的列表可能会比较棘手,所以您应该早点尝试确定如何执行特定操作可能需要额外关注(角落案例)。对于列表,您应该考虑列表为空,有1个元素,有2个元素或2+元素的情况。您可能还需要考虑是否从开始,结束或中间的某个位置插入/移除某个元素。再次,大量使用映射来了解这些情况将如何发挥。您应该尝试通过使用上述方法来思考,但您也可以检查wikipedia或数据结构教科书以获取更多信息。

顺便说一句,正如Raymond所说,您可以使用调试器来帮助您查看问题。事实上,如果您之前没有使用C/C++调试器,那么这是学习的最佳时机。完成此工作后,查找适用于您的平台的C/C++调试器的文档。尝试使用它来遍历非工作代码的main(),并查看数据值是否与映射中的期望值相符。这种技能将在以后证明是非常宝贵的。

另外,还要注意this通常是在C++ a pointer,所以不要用它是如何在Java/Python中混淆:成员数据使用this->somedatathis.somedata访问一些建议。据说,为了更加清晰,您可能希望在参数名称与成员变量相同的地方使用this->somedata = somedata的约定。当然,使用不同参数名称的建议也适用。