Конвей в игре Life Buffer Underflow - PullRequest
       27

Конвей в игре Life Buffer Underflow

0 голосов
/ 07 октября 2018

Я довольно новичок в C, и раньше я слышал о переполнении буфера, но никогда не слышал о переполнении буфера стека.Я пытался прочитать об этом, и, насколько я понимаю, я выделяю слишком много памяти?Я просто хочу быть уверен, что правильно понимаю проблему.Поэтому мой вопрос связан со следующим кодом, который обновляет данный файл для игры жизни Конвея через несколько поколений.Если кто-нибудь может объяснить, где я что-то неправильно понимаю, я был бы очень благодарен.Входные данные должны быть следующими:В первой строке board.txt также содержится количество строк и столбцов.Странно то, что код иногда работает для небольших плат, но создает переполнение буфера для больших плат.

#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;
}

1 Ответ

0 голосов
/ 07 октября 2018

Когда i или j равен нулю, original[i-1][j-1] пытается получить доступ к элементу вне массива original.

Стандарт C не определяет результирующее поведение.Во многих реализациях C это часто будет пытаться получить доступ к памяти вне массива.Чем больше строк массива (чем больше столбцов), тем дальше будет находиться массив вне массива original[i-1], и тем более вероятно, что он попытается получить доступ к памяти, которая не отображается, что приведет к ошибке.

Вы должны написать код, который не обращается к элементам вне массива.

В случае алгоритмов, которые должны проверять соседние элементы массиваСуществуют общие подходы к этому:

  • Поскольку каждый элемент рассматривается, используйте операторы if, чтобы проверить, есть ли у него соседи внутри массива.Для любых направлений, в которых соседи не существуют, не пытайтесь исследовать элементы там.Этот код приводит к многократному тестированию границ массива для каждого элемента.
  • Разделение обработки массива на основной цикл (или набор вложенных циклов, по одному для каждого измерения) для внутренних элементов, все из которыхиметь соседей во всех направлениях и отдельные циклы для краев массива (например, «левый» край, где i равен нулю, а элементы не имеют соседей слева. Тогда отдельное тестирование для каждого элемента не требуется; каждый цикл обрабатывает случаи, когда соседи для элементов, обрабатываемых в этом цикле, известны. Углы также должны обрабатываться отдельно.
  • Дополните массив фиктивными строками и столбцами по краям, которые содержат нейтральную информацию. Таким образом, дляжелаемый размер массива R строк и C столбцов, фактический размер массива R+2 строк и C+2 столбцов будет использоваться. Цикл для обработки элементов будет проходить через строки от 1 до R-2 и через столбцыОт 1 до C-2.
...