Why do I keep getting segmentation fault?

65 Views Asked by At

I am trying to make a sudoku validator as a multi-threading example on C, in which 3 concurrent threads checks the rows, cols and grids in the sudoku and tells if the sudoku is valid, but I seem to be getting the segmentation fault everytime I run it.

#include <stdio.h>
#include <pthread.h>
#include <stdbool.h>
#include <unistd.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>

#define MAX_ROWS_COLS 100

int rows;
int cols;

typedef struct {
    int (*array)[MAX_ROWS_COLS];
    int rows;
    int cols;
} ThreadArgs;


bool checkRows(void* arg){
    ThreadArgs* threadArgs = (ThreadArgs*)arg;
    int (*array)[threadArgs->cols] = threadArgs->array;
    int rows = threadArgs->rows;
    int cols = threadArgs->cols;
    
    bool used[rows];
    for(int i = 0; i < rows; i++){
        used[i] = false;
    } 
    
    for(int i = 0; i < rows; i++){
        for(int j = 0; j < cols; j++){
            int num = array[i][j];
            if(num < 1 || num > rows || used[num-1]){
                return false;
            }
            used[num-1] = true;
        }
        for(int k = 0 ; k < rows; k++){
            used[k] = false;
        }
    }
    return true;
}

bool checkCols(void* arg){
    ThreadArgs* threadArgs = (ThreadArgs*)arg;
    int (*array)[threadArgs->cols] = threadArgs->array;
    int rows = threadArgs->rows;
    int cols = threadArgs->cols;

    bool used[rows];
    for(int i = 0; i < rows; i++){
        used[i] = false;
    } 
    
    for(int i = 0; i < rows; i++){
        for(int j = 0; j < cols; j++){
            int num = array[j][i];
            if(num < 1 || num > rows || used[num-1]){
                return false;
            }
            used[num-1] = true;
        }
        for(int k = 0 ; k < rows; k++){
            used[k] = false;
        }
    }
    return true;
}

int checkGrid(void* arg){
    ThreadArgs* threadArgs = (ThreadArgs*)arg;
    int (*array)[threadArgs->cols] = threadArgs->array;
    int rows = threadArgs->rows;
    int cols = threadArgs->cols;
    
    bool used[rows];
    for(int i = 0; i < rows; i++){
        used[i] = false;
    }
    //Check grid
    int grid = sqrt(rows);
    int count = 0;
    for(int i = 0; i < rows; i=i+grid){
        for(int j = 0; j < rows; j = j+grid){
            for(int k = 0; k < grid; k++){
                for(int l = 0; l < grid; l++){
                    //printf("%d,%d\n",i+k,j+l);
                    int num = array[i+k][j+l];
                    if(num < 1 || num > rows || used[num-1]){
                        return false;
                    }
                    used[num-1] = true;
                }
                for(int m = 0; m < rows; m++){
                    used[m] = false;
                }
            }
        }
    }
    return true;
}

bool checkSudoku(int array[rows][cols]){
    pthread_t p1,p2,p3;
    int rowResult, colResult, gridResult;

    ThreadArgs args = {array, rows, cols};

    pthread_create(&p1, NULL, checkRows, (void*)&args);
    pthread_create(&p2, NULL, checkCols, (void*)&args);
    pthread_create(&p3, NULL, checkGrid, (void*)&args);

    pthread_join(p1, (void**)&rowResult);
    pthread_join(p2, (void**)&colResult);
    pthread_join(p3, (void**)&gridResult);

    if(rowResult == 0 || colResult == 0 || gridResult == 0){
        return false;
    }
    return true;
}


int main() {
    clock_t start, end;
    double cpu_time_used;

    start = clock();
    FILE *file;
    char line[1000];

    // Open the LaTeX file
    file = fopen("input.tex", "r");
    if (file == NULL) {
        printf("Error opening file.\n");
        return 1;
    }

    if (fgets(line, sizeof(line), file)) {
        sscanf(line, "%d %d", &rows, &cols);
    } else {
        printf("Error reading dimensions.\n");
        fclose(file);
        return 1;
    }

    int **array = (int **)malloc(rows * sizeof(int *));
    if (array == NULL) {
        printf("Error allocating memory for array.\n");
        return 1;
    }
    for (int i = 0; i < rows; i++) {
        array[i] = (int *)malloc(cols * sizeof(int));
        if (array[i] == NULL) {
            printf("Error allocating memory for array.\n");
            return 1;
        }
    }

    for (int i = 0; i < rows; i++) {
        if (fgets(line, sizeof(line), file)) {
            char *token = strtok(line, " ");
            for (int j = 0; j < cols && token != NULL; j++) {
            array[i][j] = atoi(token);
            token = strtok(NULL, " ");
        }
        } else {
            printf("Error reading array values.\n");
            fclose(file);
            return 1;
        }
    }

    fclose(file);

    printf("Populated 2D array:\n");
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                printf("%d ", array[i][j]);
            }
        printf("\n");
    }
    
    if(checkSudoku(array)){
        printf("Sudoku valid\n");
    } else {
        printf("Invalid\n");
    }
    
    end = clock();
    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
    double microseconds = cpu_time_used * 1000000;

        printf("Execution time: %.2f microseconds\n", microseconds);

    // Free dynamically allocated memory
    for (int i = 0; i < rows; i++) {
        free(array[i]);
    }
    free(array);
    
    return 0;
}

If it matters I am running this on a Kali Linux VM with 4 threads allocated to it.

It should wait for the 3 threads to terminate and then return if the sudoku is valid.

1

There are 1 best solutions below

1
Flori On BEST ANSWER

There are mutiple problems with this code:

  • a function overgiven to a thread can only return void* and not bool (but you can use pthread_exit((void*)true))
  • int** array and int *array[MAX_ROWS_COLS] are not the same, therefore you cannot overgive int** array to a function that accepts int *array[MAX_ROWS_COLS]
  • another problem is that you are using the variables cols and rows in the global, but also in the local scope (in this case it is ok, but you should avoid it)
  • missing headerfile string.h
#include <math.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define MAX_ROWS_COLS 100

int rows;
int cols;

typedef struct {
    int** array;
    int rows;
    int cols;
} ThreadArgs;

void* checkRows(void* arg) {
    ThreadArgs* threadArgs = (ThreadArgs*)arg;
    int** array = threadArgs->array;
    int rows = threadArgs->rows;
    int cols = threadArgs->cols;

    bool used[rows];
    for (int i = 0; i < rows; i++) {
        used[i] = false;
    }

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            int num = array[i][j];
            if (num < 1 || num > rows || used[num - 1]) {
                pthread_exit((void*)false);
            }
            used[num - 1] = true;
        }
        for (int k = 0; k < rows; k++) {
            used[k] = false;
        }
    }
    pthread_exit((void*)true);
}

void* checkCols(void* arg) {
    ThreadArgs* threadArgs = (ThreadArgs*)arg;
    int** array = threadArgs->array;
    int rows = threadArgs->rows;
    int cols = threadArgs->cols;

    bool used[rows];
    for (int i = 0; i < rows; i++) {
        used[i] = false;
    }

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            int num = array[j][i];
            if (num < 1 || num > rows || used[num - 1]) {
                pthread_exit((void*)false);
            }
            used[num - 1] = true;
        }
        for (int k = 0; k < rows; k++) {
            used[k] = false;
        }
    }
    pthread_exit((void*)true);
}

void* checkGrid(void* arg) {
    ThreadArgs* threadArgs = (ThreadArgs*)arg;
    int** array = threadArgs->array;
    int rows = threadArgs->rows;
    int cols = threadArgs->cols;

    bool used[rows];
    for (int i = 0; i < rows; i++) {
        used[i] = false;
    }

    // Check grid
    int grid = sqrt(rows);
    int count = 0;
    for (int i = 0; i < rows; i = i + grid) {
        for (int j = 0; j < rows; j = j + grid) {
            for (int k = 0; k < grid; k++) {
                for (int l = 0; l < grid; l++) {
                    // printf("%d,%d\n",i+k,j+l);
                    int num = array[i + k][j + l];
                    if (num < 1 || num > rows || used[num - 1]) {
                        pthread_exit((void*)false);
                    }
                    used[num - 1] = true;
                }
                for (int m = 0; m < rows; m++) {
                    used[m] = false;
                }
            }
        }
    }
    pthread_exit((void*)true);
}

bool checkSudoku(int** array) {
    pthread_t p1, p2, p3;
    void *rowResult, *colResult, *gridResult;

    ThreadArgs args = {array, rows, cols};

    pthread_create(&p1, NULL, checkRows, (void*)&args);
    pthread_create(&p2, NULL, checkCols, (void*)&args);
    pthread_create(&p3, NULL, checkGrid, (void*)&args);

    pthread_join(p1, &rowResult);
    pthread_join(p2, &colResult);
    pthread_join(p3, &gridResult);

    if ((bool)rowResult == 0 || (bool)colResult == 0 || (bool)gridResult == 0) {
        return false;
    }

    return true;
}

int main() {
    clock_t start, end;
    double cpu_time_used;

    start = clock();
    FILE* file;
    char line[1000];

    // Open the LaTeX file
    file = fopen("input.tex", "r");
    if (file == NULL) {
        printf("Error opening file.\n");
        return 1;
    }

    if (fgets(line, sizeof(line), file)) {
        sscanf(line, "%d %d", &rows, &cols);
    } else {
        printf("Error reading dimensions.\n");
        fclose(file);
        return 1;
    }

    int** array = (int**)malloc(rows * sizeof(int*));
    if (array == NULL) {
        printf("Error allocating memory for array.\n");
        return 1;
    }
    for (int i = 0; i < rows; i++) {
        array[i] = (int*)malloc(cols * sizeof(int));
        if (array[i] == NULL) {
            printf("Error allocating memory for array.\n");
            return 1;
        }
    }

    for (int i = 0; i < rows; i++) {
        if (fgets(line, sizeof(line), file)) {
            char* token = strtok(line, " ");
            for (int j = 0; j < cols && token != NULL; j++) {
                array[i][j] = atoi(token);
                token = strtok(NULL, " ");
            }
        } else {
            printf("Error reading array values.\n");
            fclose(file);
            return 1;
        }
    }

    fclose(file);

    printf("Populated 2D array:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }

    if (checkSudoku(array)) {
        printf("Sudoku valid\n");
    } else {
        printf("Invalid\n");
    }

    end = clock();
    cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
    double microseconds = cpu_time_used * 1000000;

    printf("Execution time: %.2f microseconds\n", microseconds);

    // Free dynamically allocated memory
    for (int i = 0; i < rows; i++) {
        free(array[i]);
    }
    free(array);

    return 0;
}