将一个指针分配给另一个时的段错误

Posted

技术标签:

【中文标题】将一个指针分配给另一个时的段错误【英文标题】:Segfault when assigning one pointer to another 【发布时间】:2009-12-09 21:00:39 【问题描述】:

我的大脑从来没有真正理解过链表和指针的细微之处,但我正在尝试帮助一位朋友完成一些 C++ 作业。 (在我走得更远之前,是的,有 std::list 但我正在寻找一个学术答案,也许能让他和我更容易理解链表)。

我们需要做的是根据用户输入生成一个对象链表(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;
        

我确定我做错了什么。

【问题讨论】:

次要的挑剔,不是答案:getEmployee() 应该返回 Employee& 而不是 Employee。前者是引用,后者将Employee 复制到堆栈中。 getNext() 有同样的问题;它会复制下一个 LinkedListContainer 对象,如果您必须处理复制构造函数,这可能会造成混乱。 【参考方案1】:

查看您的类,似乎没有将指针 emp 设置为指向实际对象的地方。

这一行:

*emp = *newEmp;

newEmp指向的对象的值赋给emp指向的对象。除非两个指针都指向有效对象,否则代码将具有未定义的行为。

emp 作为Employee 对象而不是作为需要手动管理指向对象生命周期的对象的指针可能会更好。

这假设您的LinkedListContainer 类是一个拥有Employee 的节点。

另一方面,当你这样做时:

*next = *newContainer;

根据命名我假设您只想将下一个指针指向另一个您可能想要做的LinkedListContainer

next = newContainer;

因为这会将指针的值分配给变量next

在设计类和使用指针时,需要明确哪些对象拥有哪些其他对象,并确保适当地管理它们的生命周期。

【讨论】:

不应该是:“如果任一指​​针指向无效对象...” 很好,虽然我选择了不同的措辞。【参考方案2】:
*emp = *newEmp;

应该是:

emp = newEmp;

这样你分配的是指针而不是指针指向的对象。

【讨论】:

【参考方案3】:

您的emp 指针未初始化,因此当您尝试在setEmployee() 中取消引用它(*emp)时,您会尝试访问不属于您的内存(因此出现段错误)。

您最好按值保存 Employee(假设它不是多态的)并通过 const 引用传递 setEmployee 一个 Employee 对象:

class LinkedListContainer 
  Employee emp;

  // ...

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

  // ...
;

当然,您还需要调整其他成员函数以反映使用值与指针。

祝你好运!

【讨论】:

【参考方案4】:
*emp = *newEmp

您不想这样做 - 事实上,您根本不想在这里取消引用任何指针。

emp = newEmp

【讨论】:

【参考方案5】:

默认情况下,emp 是一个不指向任何地方的指针。通过写作

*emp = *newEmp;

您尝试将 newEmp 的内容分配给 emp 指向的任何内存位置。如前所述,emp 没有指向任何地方,因此您在此处取消引用 NULL 指针,这导致了分段错误。

如果您的容器要包含一个完整的 Employee,您最好将 emp 声明为 Employee 类型(而不是像现在那样指向 Employee 的指针)。那么

emp = *newEmp;

会起作用,虽然我不太确定这是否就是你需要解决的关于 LinkedListContainer 的全部问题。

【讨论】:

【参考方案6】:

您遇到的一个问题是因为在您访问指针时前导 *。 * 在访问指针时告诉编译器的是,不是读取指针指向的地址,而是读取指针指向的位置的值。

一个例子是变量就像持有价值的房子。指针就像房子上的地址。通常,当编译器读取指针时,它只会看到地址。当您将 * 放在指针前面时,它会告诉编译器查看“房屋”内部以提取其中的值。当您为指针分配新地址时,您不想使用 *,否则您复制的是值而不是地址。

所以你想要做的是在 setNext 例如:

next = newContainer;

【讨论】:

【参考方案7】:

以前的答案解释了分段错误的原因。无论如何,如果您需要该示例用于学术用途,那么恕我直言,您忘记了班级成员的初始化。第二个问题是内存管理——谁来分配/释放这些对象?在您的示例中没有构造函数,也没有析构函数:)

您的班级可能如下所示:

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;    

;

【讨论】:

以上是关于将一个指针分配给另一个时的段错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 std::string.c_str() 作为另一个方法的参数时的段错误

OpenCL 多 GPU 积分 - 将全局大小从 32 更改为 64 时的段错误

调用 glDrawElements 时的段错误

推送到成员向量时的段错误

GCC 生成的程序集 - C 函数调用时的段错误

并行测试与地理相交时的段错误