2013-02-14 212 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的約定。當然,使用不同參數名稱的建議也適用。