指针是如何工作的

时间:2015-04-03 19:31:58

标签: c++ pointers

这是一个简单的代码,我在问我的问题。

struct Class{
public:
    int key;
    Class*next;
};

int main(){
Class c;
    c.key = 1;
    Class* p = &c;
    for (int i = 2; i < 5; i++){
        Class next;
        next.key = i;
        p->next = &next;
        p = p->next;
    }
    p = &c;
    for (int i = 1; i < 5; i++){
        std::cout << p->key;
        p = p->next;
    }
}

我期待的输出:1234

输出我得到:1444

请你告诉我我的代码有什么问题,以及如何获得1234。

4 个答案:

答案 0 :(得分:2)

for (int i = 2; i < 5; i++){
    Class next;
    next.key = 2;
    p->next = &next;
    p = p->next;
}

next对象的生命周期在每次迭代结束时结束。由于您将此对象的地址分配给p->next,因此当迭代结束时,此指针将保持悬空状态。在下一次迭代中,当您尝试使用p时,您将调用未定义的行为。

答案 1 :(得分:1)

你的逻辑似乎是正确的,但正如其他评论员所指出的那样,在循环中创建的变量是该循环的本地变量,因此一旦你离开循环就会过期。你需要做一个小修改。

替代解决方案:只需用以下代码替换您的第一个循环:

for (int i = 2; i < 5; i++){                    
    p->next = new Class;
    p->next->key = i;           
    p = p->next;
}

这将分配所需的内存并在每次迭代时创建一个新条目。

希望有所帮助!

答案 2 :(得分:0)

问题是在这个循环中

for (int i = 2; i < 5; i++){
    Class next;
    next.key = 2;
    p->next = &next;
    p = p->next;
}

对于每次迭代,您使用相同的局部变量。因此,对于循环p->next的第二次迭代,指向同一本地对象。 因此,您的porgram具有未定义的行为,因为退出循环后此本地对象不活动。通常情况下,可以覆盖局部变量占用的内存。

结果似乎是节点。一个是c,它指向已经“死亡”的节点,而死亡节点next指向自身,并保留存储在数据成员key中的最后一个值为4. / p>

您应该动态分配每个节点或使用列表中的节点数组。

这是一个演示程序,展示了如何通过数组使用simialr方法。

#include <iostream>

struct Class
{
public:
    int key;
    Class *next;
};

int main() 
{
    const size_t N = 4;
    Class c[N];

    c[0].key = 1;
    Class *p = &c[0];

    for ( size_t i = 1; i < N; i++ )
    {
        c[i].key = i + 1;
        p->next = &c[i];
        p = p->next;
    }

    p = &c[0];

    for ( int i = 0; i < N; i++ )
    {
        std::cout << p->key;
        p = p->next;
    }

    std::cout << std::endl;

    return 0;
}

输出

1234

答案 3 :(得分:0)

解释Chris的评论 - 访问其范围之外的变量是未定义的行为。你的next变量的范围是for循环的一次迭代,一旦你达到了循环的结束}(并且i++已经运行了,我认为),这取决于编译器处理释放next的内存,然后在下次运行时重新初始化它。您的编译器似乎正在做出合理的决定,将next保留在同一块内存中,并在每次迭代时再次运行构造函数,这就是为什么您的内存访问不会引发分段错误(IE,尝试访问内存)程序未被授予访问权限)。退出next循环后,您的编译器也可能决定取消分配for,但似乎也没有这样做,这就是您可以访问其内存进行打印的原因。

长话短说,不要过于担心弄清楚你的程序为什么会这样做,而是使用kvorobiev所示的堆内存,这将持续到for循环范围的末尾。作为良好的做法,一旦你完成了记忆,你也应该delete