0

我一直在尝试创建一个将数组转换为链表的函数。它创建一个与数组长度相同的节点数组,并将数组中的每个值存储到每个节点的数据字段中,并类似地设置指针。我很快意识到它不起作用,因为 print() 在打印第一个节点的数据值后给出了未定义的结果。我使用了一些 cout 调用来查看发生了什么,发现 main 中的两个 cout 调用,即使完全相同,在 MSVC2019 编译器上也会产生不同的结果。第一个产生 2 (应该如此),第二个产生未定义的结果。以下是完整的程序:

#include <iostream>

struct Node {
    int data;
    Node* next;
};

void print(Node n);
Node toNode(int ar[], int size);

int main(void) {
    int ar[] = { 1, 2, 3, 4, 5 };
    Node n = toNode(ar, 5);
    std::cout << (*(n.next)).data << std::endl;
    std::cout << (*(n.next)).data << std::endl;
    // print(n);
}

Node toNode(int ar[], int size) {
    Node nodes[100];
    for (int i = 0; i < size; i++) {
        Node n;
        n.data = ar[i];
        nodes[i] = n;
    }
    for (int i = 1; i < size; i++) {
        nodes[i-1].next = &nodes[i];
    }
    nodes[size-1].next = NULL;
    for (int i = 0; i < size; i++) {
        Node n = nodes[i];
    }
    return nodes[0];
}

void print(Node n) {
    std::cout << n.data << std::endl;
    if (n.next != NULL)
        print(*n.next);
}

这是 MSVC 2019 的输出:

msvc 结果

我在在线编译器上尝试了相同的代码,每次都给出一致的 2:

在线 gdb 结果

这是我在 MSVC2019 上调用 print(n) 时得到的:

msvc print() 结果

toNode() 函数有问题吗?我尝试打印出节点 [] 数组中每个节点的值,它们是 1、2、3、4 和 5。我还尝试打印出节点 [] 中每个节点所指向的节点的值数组,结果如预期的那样分别为 2、3、4 和 5。

还要注意在线上有警告

nodes[size-1].next = NULL;

在 toNode() 函数中。警告信息是:

C6386:写入“节点”时缓冲区溢出:可写大小为“552”字节,但可能写入“-8”字节。

4

1 回答 1

2

这是一个非常普遍的问题。

问题是您的代码正在使用指向已被破坏的对象的指针。看看你的toNode功能(带评论)

Node toNode(int ar[], int size) {
    Node nodes[100];
    ...
    for (int i = 1; i < size; i++) {
        nodes[i-1].next = &nodes[i]; // pointers to 'nodes' being saved here
    }
    ...
    return nodes[0]; // object containing  pointers to 'nodes' returned here
}

问题是nodes数组在toNode退出时被破坏。因此,您保存的所有这些指针都指向已被销毁的对象。这解释了不一致的行为。它还解释了为什么当您仍在toNode函数内部时可以成功打印出所有值,此时nodes数组尚未被破坏。

当你使用指针时,你要确保被指向的对象在指针之前没有被破坏。C++ 不会为您执行此操作。确保这一点的常用方法是使用动态内存分配(即使用new)。这是创建链表的常规技术。

于 2020-12-22T07:43:48.430 回答