Непонятная ошибка в программе Game Of Life

У меня есть рабочий код Game of Life. Он сохраняет каждую популяцию в виде растрового изображения. Вот как выглядит результат (обрезанный):

желаемый результат

При очистке кода я обнаружил, что если я закомментирую или иным образом удалю строку 60:

cout << "Survivor: " << x << ", " << y << "\n";

Это полностью портит программу, и вместо того, чтобы создать планер, как должен, он выдает это:

ошибочный вывод

Я ковырялся, пытаясь выяснить, что может быть причиной этого, но пока безуспешно. Это мой текущий код:

//Bitmap Library from http://partow.net/programming/bitmap/
#include "bitmap_image.hpp"
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

using namespace std;

#define WIDTH 160
#define HEIGHT 128

bool population[WIDTH][HEIGHT];
bool survivors[WIDTH][HEIGHT];

int check_survivors();
int check_neighbors(int x, int y);
int write_population(char* file);

int main() {
    int i, populations;

    cout << "Enter number of populations: ";
    cin >> populations;

    //Glider
    survivors[28][100] = true;
    survivors[29][100] = true;
    survivors[29][101] = true;
    survivors[30][101] = true;
    survivors[28][102] = true;

    //Initial image generation
    write_population("population0.bmp");

    //populations
    for (i = 0; i < populations; i++) {
        char filename[17] = "population";
        char ii[3];
        sprintf(ii, "%d", i+1);

        strcat(filename, ii);
        strcat(filename, ".bmp");

        check_survivors();
        write_population(filename);
    }

    return 0;
}

int check_survivors() {
    //set x and y variables
    int x, y;

    for (x = 0; x < WIDTH; x++) {
        for (y = 0; y < HEIGHT; y++) {
            if (check_neighbors(x, y)) {
                survivors[x][y] = true;
                cout << "Survivor: " << x << ", " << y << "\n";
            } else {
                survivors[x][y] = false;
            }
        }
    }
    return 0;
}

int check_neighbors(int x, int y) {
    int neighbors = 0, survives;

    //I really need to rewrite this mess

    //Neighbors above
    if (population[x-1][y-1] == true && x != 0 && y != 0) {
        neighbors++;
    }
    if (population[x][y-1] == true && y != 0) {
        neighbors++;
    }
    if (population[x+1][y-1] == true && x != WIDTH-1 && y != 0) {
        neighbors++;
    }

    //Neighbors next to
    if (population[x-1][y] == true && x != 0 ) {
        neighbors++;
    }
    if (population[x+1][y] == true && x != WIDTH-1) {
        neighbors++;
    }

    //Neighbors below
    if (population[x-1][y+1] == true && x != 0  && y != HEIGHT-1) {
        neighbors++;
    }
    if (population[x][y+1] == true && y != HEIGHT-1) {
        neighbors++;
    }
    if (population[x+1][y+1] == true && x != WIDTH-1 && y != HEIGHT-1) {
        neighbors++;
    }

    //Determining life or death
    if (neighbors < 2 || neighbors > 3) {
        //Neighbors less than 2 or more than 3 is dead cell
        survives = 0; 
    } else if (neighbors == 3 && population[x][y] == false) {
        //Exactly 3 neighbors re-animates a cell
        survives = 1;
    } else if (population[x][y] == true) {
        //2 or 3 neighbors is survivor
        survives = 1;
    }

    return survives;
}

int write_population(char* file) {
    //Create Image
    bitmap_image image(WIDTH, HEIGHT);

    //Set background to white
    image_drawer draw(image);
    image.set_all_channels(255,255,255);

    //set x and y variables
    int x, y;

    //For every array point, check to see if it survives,
    //and transfer survivors to population
    for (x = 0; x < WIDTH; x++) {
        for (y = 0; y < HEIGHT; y++) {
            if (survivors[x][y] == true) {
                draw.pen_width(1);
                draw.pen_color(0,0,0);
                draw.plot_pixel(x, y);
            }
            population[x][y] = survivors[x][y];
        }
    }

    //Save image
    image.save_image(file);

    //return
    return 1;
}

person Quicksilver    schedule 01.11.2014    source источник
comment
sprintf(ii, "%d", i+1); может вызвать переполнение буфера, а также последующие вызовы strcat. Перепишите этот код.   -  person M.M    schedule 01.11.2014


Ответы (2)


Такие вещи:

if (population[x-1][y-1] == true && x != 0 && y != 0)

нужно переписать так:

if ( x > 0 && y > 0 && population[x-1][y-1] == true )

в противном случае вы попадете прямо на территорию неопределенного поведения, когда x или y будут 0 (как это будет несколько раз, когда вы вызовете check_neighbors() из check_survivors()), и вы можете ожидать странных, необъяснимых ошибок, подобных этой. Вам необходимо проверить наличие недопустимых индексов массива перед попыткой доступа к этим элементам.

Также здесь:

if (neighbors < 2 || neighbors > 3) {
    //Neighbors less than 2 or more than 3 is dead cell
    survives = 0; 
} else if (neighbors == 3 && population[x][y] == false) {
    //Exactly 3 neighbors re-animates a cell
    survives = 1;
} else if (population[x][y] == true) {
    //2 or 3 neighbors is survivor
    survives = 1;
}

похоже, что survives можно оставить с неопределенным значением, если neighbors == 2 и population[x][y] == false, что также приведет к неопределенному поведению, если вы получите доступ к этому значению. Из вашего кода не сразу ясно, может ли такое сочетание обстоятельств когда-либо быть правдой, но если вы все еще находитесь на этапе отладки, то, как минимум, стоит добавить проверку условия, чтобы проверить, так это или нет.

Если ваша программа демонстрирует неопределенное поведение, как это, то практически невозможно рассуждать об этом до тех пор, пока эти проблемы не будут устранены.

person Crowman    schedule 01.11.2014
comment
@Quicksilver обязательно прочитайте, что на самом деле означает неопределенное поведение, если вы еще не знаете. Это технический термин, и он не обязательно знаком тем, кто пришел из других языков. - person HostileFork says dont trust SE; 01.11.2014
comment
Также стоит добавить, что современные IDE, такие как VisualStudio, значительно упрощают предотвращение подобных ошибок. - person Tymoteusz Paul; 01.11.2014

Вы не всегда присваиваете значение переменной survives, например. если population[x][y] равно false, а neighbors равно 2. Это оставляет survives со значением того, что находится в памяти в данный момент. Когда вы добавляете вызов cout, вероятно, происходит установка этого бита памяти стека в 0, маскируя ошибку вашей программы.

Добавьте начальное значение к survives при его объявлении.

person The Dark    schedule 01.11.2014