简体   繁体   English

康威的生命游戏缓冲下溢

[英]Conway's Game of Life Buffer Underflow

I'm pretty new to C and I've heard of Buffer Overflow before but I've never heard of a stack buffer underflow. 我是C语言的新手,以前也听说过Buffer Overflow,但是我从未听说过堆栈缓冲区下溢。 I've been trying to read up on it and from what I understand, I'm allocating too much memory? 我一直在尝试阅读,据我了解,我分配的内存过多吗? I just want to be sure I understand the issue properly. 我只是想确保我正确理解了这个问题。 So my question is related to the following code which takes an a number of generations to update the given file for Conway's Game of Life. 因此,我的问题与以下代码有关,该代码需要花费几代人的时间才能更新Conway的《人生游戏》的给定文件。 If anyone can explain where I'm misunderstanding something, I'd be very grateful. 如果有人能解释我误会了什么地方,我将不胜感激。 The input should be along the lines of "./life.c # board.txt" where # is the number of generations and board.txt is the board constructed of "."'s and "*"'s. 输入应沿“ ./life.c#board.txt”行,其中#是世代数,而board.txt是由“。”和“ *”构成的电路板。 The first line of board.txt also holds the number of rows and columns. board.txt的第一行还包含行数和列数。 The odd thing is that the code works sometimes for smaller board but creates a buffer underflow for bigger boards. 奇怪的是,该代码有时适用于较小的电路板,但会为较大的电路板造成缓冲区下溢。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

void futureGens(int numRows, int numCols, int original[numRows][numCols], int generations){
    int future[numRows][numCols];
    int i, j;

    for(i = 0; i < numRows; i++){
        for(j = 0; j < numCols; j++){
            int live = 0;

            if(original[i-1][j-1] == 1){
                live++;
            }
            if(original[i-1][j] == 1){
                live++;
            }
            if(original[i-1][j+1] == 1){
                live++;
            }
            if(original[i][j-1] == 1){
                live++;
            }
            if(original[i][j] == 1){
                live++;
            }
            if(original[i][j+1] == 1){
                live++;
            }
            if(original[i+1][j-1] == 1){
                live++;
            }   
            if(original[i+1][j] == 1){
                live++;
            }
            if(original[i+1][j+1] == 1){
                live++;
            }

            live -= original[i][j];

            switch(live){
                case 0:
                case 1: 
                    future[i][j] = 0;
                    break;
                case 2:
                    future[i][j] = original[i][j];
                    break;
                case 3:
                    future[i][j] = 1;
                    break;
                default:
                    future[i][j] = 0;
            }   
        }
    }

    if(generations == 1){           
        //printf("\nFuture: \n");
        for(i = 0; i < numRows; i++){
            for(j = 0; j < numCols; j++){
                if(future[i][j] == 1){
                    printf("*");
                } else {
                    printf(".");
                } 

                //printf("%d", future[i][j]);
            }
            printf("\n");
        }
    }   
     else {
        futureGens(numRows, numCols, future, generations-1);
    } 
}

int main(int argc, char **argv){
    if(argc != 3) {
        return EXIT_FAILURE;
    }

    int generations = atoi(argv[1]);

    FILE *fp = fopen(argv[2], "r");
    if(fp == NULL){
        printf("error: nothing in file\n");
        return EXIT_FAILURE;
    }

    int numRows = 0, numCols = 0;
    char line[256];

    if(fgets(line, sizeof(line), fp)){
        char c[256];
        int p;

        for(p = 0; p < 256; p++){
            if(isdigit(line[p]) != 0){
                c[p] = line[p];
            } else {
                break;
            }

        }

        numRows = atoi(c);
        numCols = atoi(c);
        printf("row: %d, col: %d\n", numRows, numCols);
    }

    //initialize the original array
    int original[numRows][numCols];
    int i, j;

    for(i = 0; i < numRows; i++){
        fgets(line, sizeof(line), fp);
        for(j = 0; j < numCols; j++){
            char c = line[j];
            if(c == '.'){
                original[i][j] = 0;
            } else if(c == '*'){
                original[i][j] = 1;
            }
        }   
    }

    futureGens(numRows, numCols, original, generations);

    return EXIT_SUCCESS;
}

When i or j is zero, then original[i-1][j-1] attempts to access an element outside of the array original . ij为零时, original[i-1][j-1]尝试访问original数组之外的元素。

The C standard does not define the resulting behavior. C标准没有定义结果行为。 In many C implementations, this will often attempt to access memory outside the array. 在许多C实现中,这通常会尝试访问阵列外部的内存。 The bigger the array rows are (the more columns there are), the further outside the array original[i-1] will be, and the more likely it is to attempt to access memory that is not mapped, which will cause a fault. 数组行越大(列越多),数组original[i-1]越远,尝试访问未映射的内存的可能性就越大,这将导致故障。

You must write code that does not access elements outside of an array. 必须编写访问数组外部元素的代码。

In the case of algorithms that must examine the neighbors of elements of an array, there are common approaches to this: 对于必须检查数组元素的邻居的算法,有一些通用的方法:

  • As each element is considered, use if statements to test whether it has neighbors inside the array. 考虑到每个元素后,请使用if语句测试其在数组内是否具有邻居。 For any directions in which neighbors do not exist, do not attempt to examine elements there. 对于不存在邻居的任何方向,请勿尝试检查那里的元素。 This code results in testing the array boundaries repeatedly, for each element. 此代码导致对每个元素重复测试数组边界。
  • Separate the processing of the array into a main loop (or set of nested loops, one for each dimension) for the interior elements, all of which have neighbors in all directions and separate loops for the edges of the array (such as the “left” edge, where i is zero, and the elements do not have neighbors on the left. Then no separate testing for each element is needed; each loop handles cases where the neighbors for elements processed in that loop are known. The corners must also be handled separately. 将数组的处理分为内部元素的主循环(或一组嵌套循环,每个维度一个),所有内部元素在各个方向上都具有相邻元素,并为数组的边缘提供单独的循环(例如“左”边,其中i为零,并且元素在左侧没有相邻元素。因此,无需对每个元素进行单独测试;每个循环都处理已知该循环中要处理的元素的相邻元素的情况。分开处理。
  • Pad the array with dummy rows and columns at the edges that contain neutral information. 在包含中性信息的边缘用虚拟行和列填充阵列。 Thus, for a desired array size of R rows and C columns, an actual array size of R+2 rows and C+2 columns would be used. 因此,对于R行和C列的期望阵列大小,将使用R+2行和C+2列的实际阵列大小。 The loop to process elements would iterate through rows 1 to R-2 and through columns 1 to C-2 . 处理元素的循环将遍历第1到R-2行以及第1到C-2列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM