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
相关产品推荐
相关产品推荐

