这是我的康威人生游戏C代码。
函数newgen检查相邻的单元格,所有八个单元格,即使单元格位于矩阵的边缘。如何更改它而不会导致访问超出绑定的数据和未定义的行为?
我也有这个错误:
1 IntelliSense: a value of type "void *" cannot be assigned to an entity of type "int *"
代码为:
void copy() {
int i, j;
for (i = j = 0; i < HEIGHT; i++) {
for (; j < WIDTH; j++) {
gb2[i][j] = gb[i][j];
}
}
}
void init() {
int i, j;
for (i = 0; i < HEIGHT; i++) {
gb [i] = malloc(sizeof(int)*WIDTH);
gb2[i] = malloc(sizeof(int)*WIDTH);
}
for (i = 0 ; i < HEIGHT; i++) {
for (j = 0 ; j < WIDTH; j++) {
gb [i][j] = 0;
}
}
gb[0][0] = 1;
gb[0][1] = 1;
gb[1][0] = 1;
gb[1][1] = 1;
copy();
}
int main(){int i;init();newgen();printg();对于(i=0;i<HEIGHT;i++){免费(gb[i]);自由(gb2[i]);}}
在newgen()
中,行从1循环到HEIGHT-2,这避免了越界访问,但列从0循环到WIDTH-2,所以当您在第一列时,访问j-1的每一行都有越界访问。即
for (j = 0; j < WIDTH-1; j++) {
if (gb[i][j+1]) n++;
if (gb[i+1][j]) n++;
if (gb[i+1][j+1]) n++;
if (gb[i-1][j-1]) n++; // <- Here,
if (gb[i][j-1]) n++; // <- here,
if (gb[i-1][j]) n++;
if (gb[i+1][j-1]) n++; // <- ...and here.
if (gb[i-1][j+1]) n++;
当您开始在列上循环时,以j等于1而不是0开始:
for (j = 1; j < WIDTH-1; j++) {
我还没有测试下面的代码(无论如何它都是不完整的),但您应该循环遍历数组中的所有元素并更新邻居计数。您可以使用在所有相邻单元格上运行的几个循环,并在执行过程中执行边界检查。
当您开始处理每个单元格时,还应该重置相邻单元格的计数。
void newgen()
{
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
int n = 0;
for (int test_y = i - 1; test_y <= (i + 1); ++test_y)
{
for (int test_x = j - 1; test_x <= (j + 1); ++test_x)
{
if ((test_x != test_y) &&
(test_x >= 0) && (test_x < WIDTH) &&
(test_y >= 0) && (test_y < HEIGHT))
{
if (gb[test_y][test_x])
{
n++;
}
}
}
}
/* Process the n value here */
}
}
}
您可能只使用静态数组,而不是沿一个维度分配,或者沿两个维度分配。目前,它是静态和动态大小的混合,这不是问题,只是看起来不一致。
您的Intellisense错误听起来像Intellisense只处理C++代码,而不是C代码,但这只是猜测。您可以将编译器(我在这里假设是MSVC)配置为编译为C或C++,但Intellisense可能没有这个选项,或者它是单独配置的。
IntelliSense警告是因为您正在使用Visual C++,并且该警告在C++中是合适的。(当你使用C时,它不是那么"intelli"。你可以通过将malloc
的返回值强制转换为(int *)
来避免警告,尽管在C中不建议强制转换malloc
的返回值。
至于避免越界访问:不要访问越界。一些可能的解决方案包括:
-
创建一个函数来返回单个单元格的有效/无效值,并检查那里的边界,如果超出边界,则返回0。(或者,你可以将网格包裹到另一边;如果你想制作动画,例如,在小网格上的滑翔机,这很好。)
-
不要将第一行或最后一行或列包含在循环中,而是将其视为特殊情况,不要访问超出边界的内容。
-
分配两个额外的行和列,将它们初始化为零,然后不迭代最后一行或列(即,将活动网格视为[1.w][1..h],但分配w+2列和h+2行)。然后,边缘不需要特殊的情况,而是使用少量的额外内存。