2009-12-09 110 views
0

我的大腦從來沒有真正理解鏈表和指針的更精細的點,但我試圖用一些C++任務來幫助朋友。 (在我進一步討論之前,是的,有std :: list,但我正在尋找學術答案,也許會讓鏈接列表對他和我自己更容易理解)。將指針分配給另一個指針時發生Segfault

我們需要做的是根據用戶輸入生成一個對象的鏈表(Employee對象),然後將該信息顯示給用戶。每當我嘗試將對象分配到鏈接列表容器時,它都會發生段錯誤。

我有以下鏈接列表對象:

class LinkedListContainer { 
    private: 
     Employee *emp; 
     LinkedListContainer *next; 

    public: 
     Employee getEmployee() { return *emp; } 

     void setEmployee(Employee *newEmp) { 
      *emp = *newEmp // This is what is causing the segfault 
     } 

     LinkedListContainer getNext() { return *next; } 

     void setNext(LinkedListContainer *newContainer) { 
      *next = *newContainer; 
     } 
} 

我敢肯定,我在做什麼可怕的錯誤。

+1

Minor nitpick,不是答案:'getEmployee()'應該返回一個'Employee'而不是'Employee'。前者是一個參考,後者將'Employee'複製到堆棧中。 'getNext()'有同樣的問題;它會創建下一個LinkedListContainer對象的副本,如果必須處理複製構造函數,可能會造成混亂。 – 2009-12-09 21:30:09

回答

5

看看你的班級,看起來並不像指針emp設置爲指向實際對象的地方。

這條線:

*emp = *newEmp; 

分配對象的值指向newEmp到對象通過emp指向。除非這兩個指針指向有效的對象,否則代碼將具有未定義的行爲。

您可能會更好地將emp作爲Employee對象,而不是指向需要手動管理指向對象的生命週期的對象的指針。

這假設您的LinkedListContainer類是一個節點,它將擁有Employee

在當你這樣做的另一方面:

*next = *newContainer; 

從命名我會認爲你只是想指向另一個LinkedListContainer下一個指針,而您可能會想這樣做:

next = newContainer; 

,因爲這會將指針的值賦給變量next

當你設計你的類並使用指針時,你需要清楚它指向哪個對象擁有哪些其他對象,並確保你適當地管理它們的生命週期。

+0

不應該是:「如果其中一個指針指向無效對象...「 – 2009-12-09 21:11:37

+0

好,但我選擇了不同的措辭。 – 2009-12-09 21:16:43

0
*emp = *newEmp 

你不想這樣做 - 事實上,你不想在這裏解除引用任何指針。

emp = newEmp 
0

默認情況下,emp是一個無處指向的指針。通過編寫

*emp = *newEmp; 

您嘗試將newEmp的內容分配給emp所指向的任何內存位置。如上所述,emp指向無處,因此您在這裏取消了一個NULL指針,這導致了分段錯誤。

如果您的容器包含完整的Employee,則最好將emp聲明爲Employee類型(而不是指向Employee的指針)。然後

emp = *newEmp; 

會工作,雖然我不太確定這是否將是所有你需要解決你的LinkedListContainer。

2
*emp = *newEmp; 

應該是:

emp = newEmp; 

所以,你要指定的指針而不是對象由指針指向。

1

emp指針未初始化,所以當你試圖取消對它的引用(*emp)在setEmployee()您嘗試訪問內存,它不屬於你(因此段錯誤)。

你可能會更好持有價值的員工(假設它不是多態),並通過const引用傳遞setEmployee Employee對象:

class LinkedListContainer { 
    Employee emp; 

    // ... 

    void setEmployee(const Employee& newEmp) { 
    emp = newEmp; 
    } 

    // ... 
}; 

當然,你需要調整你的其他成員函數以及反映使用值與指針。

祝你好運!

0

您遇到的問題之一是因爲您訪問指針時的前導*。什麼*告訴編譯器訪問一個指針時,不是讀指針指向的地址,而是讀指針指向的位置的值。

一個例子是變量就像擁有價值的房屋。指針就像房子的地址。通常,當編譯器讀取指針時,它只能看到地址。當你把指針的前面指向它時,它會告訴編譯器查看「房子」內部以提取其中的值。當你分配指針新地址時,你不想使用*,否則你正在複製值而不是地址。

所以,你想要做什麼,而不是在setNext例如:

next = newContainer; 
0

以前的答案解釋分割故障的原因。無論如何,如果你需要這個樣本用於學術用途,那麼恕我直言,你忘記了班級成員的初始化。第二個問題是內存管理 - 誰會分配/釋放這些對象?在您的樣品有也不構造函數,析構函數都不:)

你的類可能看起來像下面這樣:

class LinkedListContainer 
{  
    public:   
     LinkedListContainer() 
      : d_emp(0) 
      , d_next(0) 
     { 
     } 

     bool isValid() const 
     { 
      const bool result = (d_emp != 0); 
      return result; 
     } 

     const Employee& getEmployee() const 
     { 
      assert(isValid()); 
      return *d_emp; 
     }   

     void setEmployee(Employee* emp) 
     {    
      d_emp = emp; 
     }   

     LinkedListContainer* getNext() 
     { 
      return d_next; 
     }   

     void setNext(LinkedListContainer* next) 
     {    
      d_next = next;   
     } 

    private:   
     Employee* d_emp;   
     LinkedListContainer* d_next;  

}; 

如果你不想與內存管理Employee對象打擾,那麼就使用來自boost庫的shared_ptr。

typedef boost::shared_ptr<Employee> SmartEmployee; 

class LinkedListContainer 
{  
    public:   
     LinkedListContainer() 
      : d_next(0) 
     { 
     } 

     bool isValid() const 
     { 
      return d_emp; 
     } 

     const Employee& getEmployee() const 
     { 
      assert(isValid()); 
      return *d_emp; 
     }   

     void setEmployee(SmartEmployee emp) 
     {    
      d_emp = emp; 
     }   

     LinkedListContainer* getNext() 
     { 
      return d_next; 
     }   

     void setNext(LinkedListContainer* next) 
     {    
      d_next = next;   
     } 

    private:   
     SmartEmployee d_emp;   
     LinkedListContainer* d_next;  

}; 
相關問題