C语言基于malloc数组实现康威生命游戏网格更新错误排查
康威生命游戏更新逻辑错误排查
你的代码有两个核心逻辑错误,和你观察到的输出畸变完全对应:
- 浅拷贝导致遍历过程中原网格被串改
你写的copyGrid = grid;不是创建独立的副本网格,只是让copyGrid指针和原grid指向了同一块内存地址。康威生命游戏的核心要求是:所有细胞的新状态必须完全基于上一轮的原始网格状态计算,不能边计算边修改原网格。你现在遍历过程中修改copyGrid的值等价于直接修改原grid,后面的细胞统计邻居时读到的是已经被修改过的本轮新值,不是上一轮的初始值,结果必然出错。这个错误和你给出的3*3测试用例异常完全匹配:当你遍历到(0,1)位置判断它应该存活,直接把原网格该位置设为1,后续遍历(0,2)统计邻居时,会把这个刚改的1额外算进去,导致邻居计数比实际多1,本来应该死亡的(0,2)被误判为存活,正好对应你实际输出第一行末尾多出来的1。
- 指针赋值无效
C语言函数参数是值传递,你在函数末尾写的grid = copyGrid;只是修改了函数内部形参的指针值,不会改变函数外部传入的实参指针指向,就算你做了正确的内存拷贝,这行代码也没法把新网格传回调用处。
另外你伪代码里存在变量名拼写错误(neigbour漏写字母h),不过你测试时countN返回值正确,应该是写伪代码时的手滑,不属于运行时错误。
修复步骤
- 给副本网格申请独立内存,不要直接指针赋值,参考初始化代码:
int** copyGrid = (int**)malloc(r * sizeof(int*)); for (int i = 0; i < r; i++) { copyGrid[i] = (int*)malloc(c * sizeof(int)); } - 遍历计算状态时,所有存活判断、邻居计数全部读取原grid的值,计算得到的新状态只写入copyGrid,全程不要修改原grid的任何值,保证整轮计算的数据源都是上一轮的未修改状态。
- 整轮计算完成后,先逐行释放原grid的已申请内存,再把copyGrid的地址传回调用处。你可以把函数返回值从
void改成int**,最后return copyGrid,调用方用原网格指针接收返回值即可;如果要保留传参修改的写法,需要把grid参数改成int***类型,传入外部二维指针的地址才能修改实参指向。 - 修复后测试3*3闪烁器用例:横条初始状态迭代一轮后会正确变成竖条,和你预期输出一致。
内容的提问来源于stack exchange,提问作者Mumer
相关产品推荐
相关产品推荐

