You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言多线程数独验证器持续出现Segmentation Fault问题求助

多线程数独验证器段错误问题修复

核心问题分析

1. 线程函数返回值不符合pthread规范

pthread_create要求线程函数签名为void* (*start_routine)(void*),但你的checkRows、checkCols返回bool,checkGrid返回int,返回值大小与void*不匹配(64位系统下void*为8字节,bool为1字节),会破坏调用栈结构,直接引发段错误。

2. 二维数组类型不兼容

main中动态分配的是int**(指针数组),但ThreadArgs中定义的是int (*array)[MAX_ROWS_COLS](固定列数的二维数组指针),两种类型完全不兼容。线程函数中强制转换后访问array[i][j]会导致内存访问错误。

3. 宫格检查逻辑错误

checkGrid中在遍历宫格的每一行后就重置used数组,导致每个宫格的行内检查失效;同时若rows不是完全平方数,会引发数组越界访问。

4. 可变长度数组(VLA)栈溢出风险

bool used[rows]属于可变长度数组,当rows较大时会耗尽栈空间,引发段错误。

修复方案

1. 修正线程函数签名和返回值

将线程函数改为返回void*,用malloc分配返回值,主线程中释放返回的内存,保证类型匹配。

2. 统一二维数组类型

将ThreadArgs中的数组指针改为int**,与main中动态分配的数组类型一致。

3. 修复宫格检查逻辑

每个宫格遍历完成后再重置used数组,同时先验证rows是否为完全平方数,避免无效遍历。

4. 替换可变长度数组为动态分配

用malloc分配used数组,避免栈溢出,使用完后释放内存。

修复后的完整代码

#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;
    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 = malloc(rows * sizeof(bool));
    if (!used) {
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    
    bool *result = malloc(sizeof(bool));
    *result = true;
    
    for(int i = 0; i < rows; i++){
        for(int k = 0 ; k < rows; k++){
            used[k] = false;
        }
        for(int j = 0; j < cols; j++){
            int num = array[i][j];
            if(num < 1 || num > rows || used[num-1]){
                *result = false;
                break;
            }
            used[num-1] = true;
        }
        if (!*result) break;
    }
    
    free(used);
    return (void*)result;
}

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

    bool *used = malloc(rows * sizeof(bool));
    if (!used) {
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    
    bool *result = malloc(sizeof(bool));
    *result = true;
    
    for(int i = 0; i < cols; i++){
        for(int k = 0 ; k < rows; k++){
            used[k] = false;
        }
        for(int j = 0; j < rows; j++){
            int num = array[j][i];
            if(num < 1 || num > rows || used[num-1]){
                *result = false;
                break;
            }
            used[num-1] = true;
        }
        if (!*result) break;
    }
    
    free(used);
    return (void*)result;
}

void* checkGrid(void* arg){
    ThreadArgs* threadArgs = (ThreadArgs*)arg;
    int **array = threadArgs->array;
    int rows = threadArgs->rows;
    int cols = threadArgs->cols;
    
    bool *result = malloc(sizeof(bool));
    *result = true;
    
    int grid = sqrt(rows);
    // 检查rows是否是完全平方数
    if (grid * grid != rows) {
        *result = false;
        return (void*)result;
    }
    
    bool *used = malloc(rows * sizeof(bool));
    if (!used) {
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    
    for(int i = 0; i < rows; i += grid){
        for(int j = 0; j < cols; j += grid){
            // 重置used数组,准备检查当前宫格
            for(int m = 0; m < rows; m++){
                used[m] = false;
            }
            for(int k = 0; k < grid; k++){
                for(int l = 0; l < grid; l++){
                    int num = array[i+k][j+l];
                    if(num < 1 || num > rows || used[num-1]){
                        *result = false;
                        goto cleanup;
                    }
                    used[num-1] = true;
                }
            }
        }
    }

cleanup:
    free(used);
    return (void*)result;
}

bool checkSudoku(int **array){
    pthread_t p1,p2,p3;
    bool *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);

    bool isValid = *rowResult && *colResult && *gridResult;
    
    // 释放线程返回的内存
    free(rowResult);
    free(colResult);
    free(gridResult);

    return isValid;
}


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

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

    // 打开输入文件
    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);
        // 数独必须是方阵
        if (rows != cols) {
            printf("Sudoku must be a square matrix.\n");
            fclose(file);
            return 1;
        }
    } 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");
            // 释放已分配的内存
            for (int j = 0; j < i; j++) free(array[j]);
            free(array);
            return 1;
        }
    }

    for (int i = 0; i < rows; i++) {
        if (fgets(line, sizeof(line), file)) {
            char *token = strtok(line, " \n"); // 加入换行符作为分隔符,避免读取空行
            for (int j = 0; j < cols && token != NULL; j++) {
                array[i][j] = atoi(token);
                token = strtok(NULL, " \n");
            }
        } else {
            printf("Error reading array values.\n");
            // 释放已分配的内存
            for (int j = 0; j < rows; j++) free(array[j]);
            free(array);
            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);

    // 释放动态分配的内存
    for (int i = 0; i < rows; i++) {
        free(array[i]);
    }
    free(array);
    
    return 0;
}

额外优化点

  • 增加数独必须是方阵的检查(rows == cols),符合数独定义;
  • 内存分配失败时,增加已分配内存的释放逻辑,避免内存泄漏;
  • 修正strtok分隔符,加入换行符,避免读取空行时出错;
  • 宫格检查前先验证rows是否为完全平方数,避免无效遍历。

内容的提问来源于stack exchange,提问作者Rachit Anand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 12:42:33