Ошибка сегментации Game of Life в C

Я новичок в C, Linux и т. Д., Мой код компилируется и запускается, но как только я ввожу свои первые пользовательские данные, я получаю ошибку сегментации. Если бы кто-то мог указать, что не так с моим кодом, это было бы очень полезно. Я думаю, что это либо в «вычислить ()», либо в «основной ()», потому что я пытался выделить память, используя «malloc ()» в обоих из те места.

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

#define LIFE_YES 'X'
#define LIFE_NO 'O'

int HEIGHT, WIDTH;
typedef int **TableType;

void printTable(TableType table) {
    int height, width;

        for (height = 0; height < HEIGHT; height++) {
            for (width = 0; width < WIDTH; width++) {
                    if (table[height][width] == LIFE_YES) {
                        printf("X");
                    } 
            else {
                    printf("-");
                    }
            }
            printf("\n");
        }
        printf("\n");
}

void clearTable(TableType table) {
    int height, width;

        for (height = 0; height < HEIGHT; height++) {
            for (width = 0; width < WIDTH; width++) {
                    table[height][width] = LIFE_NO;
            }
        }
}

void askUser(TableType tableA) {
    int i;
        int n;
        int height, width;

        printf("Enter the amount of initial organisms: ");
        scanf("%d", &n);

        for (i = 0; i < n; i++) {
            printf("Enter dimensions (x y) where organism %d will live: ", i + 1);
            scanf("%d %d", &height, &width);

            tableA[height][width] = LIFE_YES;
        }

        printTable(tableA);
        printf("Generation 0");
}

int getNeighborValue(TableType table, int row, int col) {
        if (row < 0 || row >= HEIGHT || col < 0 || col >= WIDTH || table[row][col] != LIFE_YES ) {
            return 0;
        } 
    else {
            return 1;
        }
}

int getNeighborCount(TableType table, int row, int col) {
        int neighbor = 0;

        neighbor += getNeighborValue(table, row - 1, col - 1);
        neighbor += getNeighborValue(table, row - 1, col);
        neighbor += getNeighborValue(table, row - 1, col + 1);
        neighbor += getNeighborValue(table, row, col - 1);
        neighbor += getNeighborValue(table, row, col + 1);
        neighbor += getNeighborValue(table, row + 1, col - 1);
        neighbor += getNeighborValue(table, row + 1, col);
        neighbor += getNeighborValue(table, row + 1, col + 1);

        return neighbor;
}

void calculate(TableType tableA) {
        TableType tableB;
        int neighbor, height, width, i;
    tableB= malloc(HEIGHT * sizeof(int*));

    for (i = 0; i < HEIGHT; i++) {
            tableB[i] = malloc(WIDTH * sizeof(int));
    }

        for (height = 0; height < HEIGHT; height++) {
            for (width = 0; width < WIDTH; width++) {
                    neighbor = getNeighborCount(tableA, height, width);
                    if (neighbor==3) {
                        tableB[height][width] = LIFE_YES;
                    } 
            else if (neighbor == 2 && tableA[height][width] == LIFE_YES) {
                        tableB[height][width] = LIFE_YES;
                    } 
            else {
                        tableB[height][width] = LIFE_NO;
                    }
            }
        }

        for (height = 0; height < HEIGHT; height++) {
            for (width = 0; width < WIDTH; width++) {
                    tableA[height][width] = tableB[height][width];
            }
    }
    free(tableB);
}

/* test data
void loadTestData(TableType table) {
        table[3][4] = LIFE_YES;
        table[3][5] = LIFE_YES;
        table[3][6] = LIFE_YES;

        table[10][4] = LIFE_YES;
        table[10][5] = LIFE_YES;
        table[10][6] = LIFE_YES;
        table[11][6] = LIFE_YES;
        table[12][5] = LIFE_YES;
}
*/

int main(void) {
    int i;
        char end;
        int generation = 0;

    printf("Enter the amount of rows and columns you want in the grid: ");
    scanf("%i %i\n", &HEIGHT, &WIDTH);

        TableType table = malloc(HEIGHT * sizeof(int*));

    for (i = 0; i < HEIGHT; i++) {
            table[i] = malloc(WIDTH * sizeof(int));
    }

        clearTable(table);
        askUser(table);
        /*loadTestData(table);*/
        printTable(table);

        while (end != 'q') {
            calculate(table);
            printTable(table);
            printf("Generation %d\n", ++generation);
            printf("Press q to quit or 1 to continue: ");
            scanf(" %c", &end);
        }

        return 0;
}

person Mel Moore    schedule 14.09.2013    source источник
comment
Скомпилируйте свою программу с параметром -g, откройте ее внутри gdb (gdb myprogramname), запустите ее (run) и распечатайте трассировку после получения segfault (bt).   -  person Nemanja Boric    schedule 14.09.2013
comment
@NemanjaBoric, как именно мне поместить это в терминал, я обычно делаю gcc -Wall ProjectName.c, а затем запускаю его с помощью ./a.out   -  person Mel Moore    schedule 14.09.2013
comment
Если я прав, после того, как вы ввели свою ВЫСОТУ и ШИРИНУ, возникают ошибки сегментации?   -  person xQuare    schedule 14.09.2013
comment
gcc -Wall -g "ProjectName.c" и вместо ./a.out запустить gdb: gdb ./a.out   -  person Nemanja Boric    schedule 14.09.2013
comment
@NemanjaBoric Я запустил это, и все, что там написано, это «Нет стека».   -  person Mel Moore    schedule 14.09.2013
comment
@xQuare, какой метод и как от него избавиться.   -  person Mel Moore    schedule 14.09.2013
comment
@MelMoore Вы скомпилировали его с помощью -g? Альтернативой является просто шаг за шагом с помощью команды next.   -  person Nemanja Boric    schedule 14.09.2013
comment
@MelMoore Нет, я просто пытался спросить, какая строка кода была последней, которую вы наверняка выполнили перед segfault.   -  person xQuare    schedule 14.09.2013
comment
@NemanjaBoric да, я сделал gcc -Wall -g PA2.c, затем сделал gdb ./a.out, а затем bt   -  person Mel Moore    schedule 14.09.2013
comment
@xQuare Да, сразу после того, как я ввожу ВЫСОТУ и ВЕС   -  person Mel Moore    schedule 14.09.2013
comment
@MelMoore Вы забыли запустить программу с командой run в gdb. Запустите bt после получения segfault.   -  person Nemanja Boric    schedule 14.09.2013
comment
Изменить scanf("%i %i\n", &HEIGHT, &WIDTH); -> scanf("%i%i", &HEIGHT, &WIDTH). Функции scanf автоматически пропускают пробелы для всего, кроме %c, а новая строка только испортит ситуацию.   -  person CodeClown42    schedule 14.09.2013


Ответы (2)


В основном

scanf("%i %i\n", &HEIGHT, &WIDTH);  ==>    scanf("%i %i", &HEIGHT, &WIDTH);
             ^

из-за этого \n вам нужно ввести еще один ввод. Избегайте этого

и ошибка сегментации в askUser

tableA[height][width] = LIFE_YES;

Program received signal SIGSEGV, Segmentation fault.
0x00000000004007c1 in askUser (tableA=0x603010) at seg3.c:49
49                  tableA[height][width] = LIFE_YES;
(gdb) bt
#0  0x00000000004007c1 in askUser (tableA=0x603010) at seg3.c:49
#1  0x0000000000400bf3 in main () at seg3.c:142
(gdb)  

и здесь вы не выделили память, но вы сначала получаете доступ к памяти.

person Gangadhar    schedule 14.09.2013
comment
Простой способ исправления @MelMoore объявляется глобально. static int table[max][max]; и избегайте передачи массива в качестве аргумента. если вы не хотите объявлять глобально, вы должны играть с указателями.... - person Gangadhar; 14.09.2013
comment
Я пытался использовать указатели, но теперь я просто получаю ошибки seg. - person Mel Moore; 14.09.2013
comment
@MelMoore, я всегда поощряю использование указателей ... сначала завершите свою программу массивом, а затем преобразуйте в указатели, см. это cppforschool.com/tutorial/array2.html - person Gangadhar; 14.09.2013

Это ошибка сегментации из-за:

for (i = 0; i < n; i++) 
{
   printf("Enter dimensions (x y) where organism %d will live: ", i + 1);
   scanf("%d %d", &height, &width);
    tableA[height][width] = LIFE_YES;  <--- Here 
}

Что делать, если указанный пользователем размер выходит за пределы размеров «ВЫСОТА» и «ВЕС», которые вы изначально динамически выделили в main.

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

Второе:
Кроме того, ваша переменная end в main не инициализирована, возможно, вы пропустили эту end = getchar() в условии if.
Если она не инициализирована, это также может вызвать сбой сегментации.

Третье:
\n в scanf действительно требуется? Если это присутствует, он примет 3-й ввод в качестве ввода для следующего scanf и не будет запрашивать ввод для этого сканирования.
т. е. здесь в настоящее время 3-й ввод войдет в нет. организмов без запроса.

person Uchia Itachi    schedule 14.09.2013
comment
\n хуже, чем не требуется, потребует ввести строку ДВАЖДЫ, хотя используется только первая. - person CodeClown42; 14.09.2013
comment
Итак, я должен поместить оператор if в этот цикл for, чтобы выполнять table[][] = life только в том случае, если высота и ширина > 0, но ‹ HEIGHT и WIDTH? - person Mel Moore; 14.09.2013
comment
Вы также должны считать равным 0 :) - person Uchia Itachi; 14.09.2013
comment
Я поставил «if ((высота ›= 0 && высота =‹ ВЫСОТА) && (ширина ›= 0 && ширина =‹ ШИРИНА))» в верхней части таблицы. - person Mel Moore; 14.09.2013