最近在写人工智能作业的时候遇到了一点问题,就是在循环语句中对指针类型赋值出现错误,导致所有的结点的前驱指针最终指向自身。

问题描述

以下使用一个简单的示例来模拟当时出现的问题。

MyStruct 为一个自定义结构体类型,包含数据成员 val 和前驱结点 pre。首先将初始结点(0,nullptr)加入队列 Q,随后在每次循环中,用变量 fs 接收队列 Q 的队首元素并将其出队,并根据该结点生成一个新结点,该新结点 val = fs.val + 1,且将其前驱结点设为 fs 并加入到队列 Q 中。直到 fs.val >= 5 时退出循环。

struct MyStruct
{
	int val;
	MyStruct* pre;
	MyStruct(int v = 0, MyStruct* p = nullptr) : val(v), pre(p) {}
};

int main()
{
	std::queue<MyStruct> Q;
	Q.emplace(0, nullptr);
	MyStruct target;
	while (!Q.empty()) {
		MyStruct fs = Q.front();
		Q.pop();
		if (fs.val >= 5) {
			target = fs;
			break;
		}
		Q.emplace(fs.val + 1, &fs);
	}
	std::cin.get();
}

如果代码运行如我们预期,最终将会得到一个 val 为 5 的结点,并且其前驱为一个 val 为 4 的结点,以此类推,形成一个 val 从 5 到 0 的链表。但事实上,最终结点之间并没有彼此相连,结点 target 的 pre 为自身。

问题原因

如果仔细观察,变量 fs 在整个循环过程中都占用同一片内存空间,而子节点的前驱结点 pre 直接指定为了 fs 的地址,那么如果 fs 的值遭到改变,即该地址的数据被改变,那么结点的前驱结点 pre 也会被改变。即下次循环执行 MyStruct fs = Q.front(); 后结点的前驱结点就遭到了改变,且指向了自身。

解放方法

由于 fs 的始终占用一片内存空间,为了防止因 fs 的数据被改变而使得结点前驱结点数据遭到改变,可以为结点的前驱结点重新开辟一片内存空间并赋予当前 fs 的数据。