0

这是我的康威生命游戏 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; 在里面(); 新根();打印();for (i = 0; i < HEIGHT; i++) { free(gb[i]); 免费(gb2[i]);} }

4

3 回答 3

1

newgen()您从 1 循环到 HEIGHT - 2 的行中,这避免了越界访问,但是对于从 0 循环到 WIDTH - 2 的列,因此您在访问 j - 1 的每一行中都有越界访问,当你在第一列。IE,

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++) { 
于 2012-01-21T14:11:45.360 回答
0

我还没有测试过下面的代码(无论如何它都不完整),但是您应该遍历数组中的所有元素并更新邻居计数。您可以使用几个循环遍历所有相邻单元格并在执行过程中执行边界检查。

当您开始处理每个单元格时,您还应该重置相邻单元格计数。

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 要么没有该选项,要么单独配置。

于 2012-01-21T14:32:28.090 回答
0

IntelliSense 警告是因为您使用的是 Visual C++,并且该警告适用于 C++。(当您使用 C 时,它不是那么“智能”。)您可以通过将返回值转换为mallocto来避免警告(int *),尽管在 C 中不建议转换malloc返回值。

至于避免越界访问:不要越界访问。一些可能的解决方案包括:

  • 创建一个函数来返回单个单元格的活/死值,并检查那里的边界,如果超出边界则返回 0。(或者您可以将网格环绕到另一侧;如果您想制作动画,例如小网格上的滑翔机,这很好。)

  • 不要在循环中包含第一行或最后一行或列,而是将它们视为特殊情况并且不要越界访问。

  • 分配两个额外的行和列,将它们初始化为零,然后不要遍历最后一行或列(即,将您的活动网格视为 [1..w][1..h] 但分配 w+2 列和 h+2 行)。那么你不需要边缘的特殊情况,但使用少量的额外内存。

于 2012-01-21T14:33:12.623 回答