2014-04-02 120 views
1
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 *;它工作正常。
我不明白这个逻辑。双指针分段错误

回答

2

通过包含行input = new abc*;您正在更改input的值,而不是input指向的值,除非您删除该行,否则它仍未定义。

3

在行

getdata(&a1); 

你要发送的A1地址getdata
它需要一个地址,访问a1

然后在

input = new abc*; 

您覆盖该指针。功能getdata不再“记住”的a1

那么地址在

*input = ap 

你正在编写新的(无用)地址。 当程序到达

a1->getX() 

a1从来没有写入,和是不确定的。

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; 
} 
0

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

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

与任何变量一样,变量存储的内存位置其数据也具有地址。这可能让人第一眼就感到困惑,但它并没有什么魔力 - 地址和其他值一样,并且可以存储在变量中,变量占据某处具有自己地址的某个内存。

将a1的地址传递给一个函数是正确的,该函数将更改变量所保存的数据。正确地,当您将其地址传递给函数getdata(&a1);时,将运算符&应用于变量名称。

getdata()现在知道a1保存其数据的地方,即在复制到形式参数“input”的地址处。当getdata想要更改该数据时,需要写入该位置。这是使用运算符*,即解引用运算符完成的。

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

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

运算符“new”返回新创建的对象的地址(即,可以容纳地址的abc的4个字节的地址),并将该地址分配给输入。 Oy vey - 我们已经失去了main的a1存储其数据的信息!这是“投入”持续到现在的价值。 “输入”现在指向一个不同的,完全有效的内存位置,它可以保存abc的地址。 *input = ap ;将在getdata()开头创建的abc的地址写入该内存位置。 Bummer,数据主的a1所持有的根本不变。因为没有分配给它,所以它包含的随机字节很可能仍然是一个完全无效的地址。

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

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