双指针分割故障

时间:2014-04-02 08:08:42

标签: c++

class abc ;
void getdata(abc **input=NULL);

class abc {
    int x ;

    public :
    void setX(int in) { x = in ; }
    int  getX()  { return x ; }
};

void getdata(abc **input){
    abc *ap = new abc;
    cout<< "ap ="<<ap <<endl;
    ap->setX(10);
    input = new abc*;
    *input = ap ;
}

int main() {
    abc *a1 ;
    cout << a1 <<endl ;
    getdata(&a1);
    cout<< a1 <<endl;

    cout<< a1->getX()<<endl;
    return 0;
}

它给出了分段错误,意味着a1将变为空 如果我删除 input = new abc * ;它工作正常。
我不明白这个逻辑。

4 个答案:

答案 0 :(得分:3)

在第

getdata(&a1);

您要将a1的地址发送至getdata
它需要该地址才能访问a1

然后在

input = new abc*;

您覆盖该指针。函数getdata不再“记住”a1

的地址

然后在

*input = ap
你正在写那个新的(无用的)地址。 程序到达时

a1->getX()

a1从未被写入,并且未定义。

答案 1 :(得分:2)

通过添加行input = new abc*;,您要更改input的值,而不是input指向的值,除非您删除该行,否则该值仍为未定义。

答案 2 :(得分:0)

首先input指向a1。但是当你input = new abc*;时,它停止指向a1。所以删除该行。

void getdata(abc **input) // here input points to a1
{
    abc *ap = new abc;
    cout<< "ap ="<<ap <<endl;
    ap->setX(10);

    *input = ap ; // input still points to a1, but value of a1 is changed
                  // you may think this as a1=ap;
}

答案 3 :(得分:0)

@ user657267是对的,但让我详细说明一下。

abc,在main中声明为abc *a1 ;,是一个像任何其他变量一样的变量(比如像int)。它定义了一个内存位置,可能是4个字节,它恰好位于函数main的堆栈中。该内存适用于某些数据,在这种情况下恰好是一个地址。

与任何变量一样,变量存储其数据的内存位置也有一个地址。乍一看这可能会让人感到困惑,但它没有什么神奇之处 - 地址也是值,与其他任何地方一样,并且可以存储在变量中,这些变量占据了某个具有自己地址的内存。

将a1的地址传递给要更改变量所持数据的函数是正确的。正确地说,你应用运算符&amp;将地址传递给函数时变量名称为getdata(&a1);

getdata()现在知道a1在哪里保存其数据,即在复制到形式参数&#34;输入&#34;的地址。当getdata想要更改该数据时,它需要写入该位置。这是使用运算符*(解除引用运算符)完成的。

现在,a1中的数据恰好是abc对象的(当前可能是无效的)地址。分配给a1的合适数据将是abc对象的地址。例如,使用abc *ap = new abc;创建的新abc对象的指针ap对于这样的赋值是非常好的值。我们可以在getdata中访问a1,因为我们碰巧在输入中有地址。与通过地址进行的任何分配一样,我们需要使用解除引用运算符*来访问&#34;输入&#34;中的地址 location 。在描述。 (据我们所知,该位置是a1数据所在的位置)。

现在input = new abc*;做了什么?右侧&#34;新的abc *&#34;,在堆上创建一个可以容纳地址的位置,可能是4字节。它的类型是&#34; abc *&#34;。

运营商&#34; new&#34;返回新创建的对象的地址(即可以将地址保存到abc的4个字节的地址),并将该地址分配给输入。 Oy vey - 我们丢失了主要数据a1存储数据的信息!这就是&#34;输入&#34;一直持续到现在。 &#34;输入&#34;现在指向一个不同的,完全有效的内存位置,它可以保存abc的地址。 *input = ap ;将在getdata()开头创建的abc的地址写入该内存位置。数据主要人物a1持有的无赖完全没有改变。因为没有任何东西被分配给它,它包含的随机字节很可能继续是一个完全无效的地址。

因此,虽然*input = ap ;非常好,但它会在错误的位置更改数据。省略覆盖输入所持有的a1数据的完全有效位置,一切都会正常工作。 a1的内容将由getdata()更改,它将新创建的abc对象的地址写入其中,以便取消引用指针,例如,通过a1->getX(),将是一个有效的操作。

为了避免意外覆盖只读参数,可以将它们声明为const。在这种情况下,getdata(abc **const input)表示您不想更改值&#34;输入&#34;包含的内容。 (但您仍然可以使用该值来访问a1的数据!)因此,赋值input = new abc*;会引发编译时错误。