释放结构体中unsigned char二维矩阵时程序随机无报错退出问题
问题分析与修复方案
核心崩溃原因:栈缓冲区溢出
代码中char buf[] = "";定义的buf是长度仅为1的字符数组,但后续调用fgets(buf, MAX_LEN, ptr);尝试读取最多10000个字符,直接触发栈缓冲区溢出,破坏程序栈的完整性,导致后续内存分配、释放操作的行为完全不可预测——这就是程序偶尔崩溃的根本原因。
全量修复后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> struct imagem{ unsigned char ** matrix; char* file_path; int height; int width; int max_cinza; int histograma[256]; char* location; }; struct imagem* lerImagem(char file_path[]) { // 初始化结构体并检查内存分配 struct imagem* imagem = malloc(sizeof(struct imagem)); if (imagem == NULL) { fprintf(stderr, "Falha ao alocar memória para estrutura\n"); return NULL; } memset(imagem, 0, sizeof(struct imagem)); // 初始化结构体成员为0,避免野指针 // 复制文件路径,避免指针悬空 imagem->file_path = strdup(file_path); if (imagem->file_path == NULL) { fprintf(stderr, "Falha ao alocar memória para caminho do arquivo\n"); free(imagem); return NULL; } FILE* ptr = fopen(file_path, "r"); if (NULL == ptr) { fprintf(stderr, "A imagem não está no file_path selecionado\n"); free(imagem->file_path); free(imagem); return NULL; } const int MAX_LEN = 10000; char buf[MAX_LEN]; // 定义足够大的缓冲区 // 读取第一行(跳过P2等标识) if (fgets(buf, MAX_LEN, ptr) == NULL) { fprintf(stderr, "Falha ao ler cabeçalho do arquivo\n"); fclose(ptr); free(imagem->file_path); free(imagem); return NULL; } // 读取宽高 int int_largura, int_altura; if (fscanf(ptr, "%d %d", &int_largura, &int_altura) != 2) { fprintf(stderr, "Falha ao ler dimensões da imagem\n"); fclose(ptr); free(imagem->file_path); free(imagem); return NULL; } imagem->height = int_altura; imagem->width = int_largura; // 分配二维数组内存并检查 imagem->matrix = malloc(imagem->height * sizeof(unsigned char*)); if (imagem->matrix == NULL) { fprintf(stderr, "Falha ao alocar memória para linhas da matriz\n"); fclose(ptr); free(imagem->file_path); free(imagem); return NULL; } for (int i = 0; i < imagem->height; i++) { imagem->matrix[i] = malloc(imagem->width * sizeof(unsigned char)); if (imagem->matrix[i] == NULL) { fprintf(stderr, "Falha ao alocar memória para coluna %d\n", i); // 已分配的内存要提前释放 for (int j = 0; j < i; j++) { free(imagem->matrix[j]); } free(imagem->matrix); fclose(ptr); free(imagem->file_path); free(imagem); return NULL; } } // 读取max_cinza,用%d匹配int类型 if (fscanf(ptr, "%d", &imagem->max_cinza) != 1) { fprintf(stderr, "Falha ao ler valor máximo de cinza\n"); // 清理已分配资源 for (int i = 0; i < imagem->height; i++) { free(imagem->matrix[i]); } free(imagem->matrix); fclose(ptr); free(imagem->file_path); free(imagem); return NULL; } // 读取像素数据 for(int row = 0; row < imagem->height; row++){ for(int column = 0; column < imagem->width; column++){ // 用%hhu匹配unsigned char类型,避免类型不匹配 if (fscanf(ptr, "%hhu", &(imagem->matrix[row][column])) != 1) { fprintf(stderr, "Falha ao ler pixel na posição (%d,%d)\n", row, column); // 清理资源 for (int i = 0; i < imagem->height; i++) { free(imagem->matrix[i]); } free(imagem->matrix); fclose(ptr); free(imagem->file_path); free(imagem); return NULL; } } } fclose(ptr); return imagem; } void freeImagem(struct imagem* imagem_input){ if (imagem_input == NULL) { return; } if (imagem_input->matrix != NULL) { for(int i=0; i < imagem_input->height; i++){ free(imagem_input->matrix[i]); } free(imagem_input->matrix); } free(imagem_input->file_path); free(imagem_input); }
关键修复点说明
- 修复缓冲区溢出:将
char buf[] = "";改为char buf[MAX_LEN];,确保缓冲区足够容纳第一行内容。 - 避免指针悬空:用
strdup复制传入的文件路径字符串,确保结构体持有独立的内存空间。 - 完善内存分配检查:每次
malloc后都检查返回值,分配失败时及时清理已分配的所有资源,避免内存泄漏和崩溃。 - 修正类型匹配问题:读取
max_cinza用%d(匹配int类型),读取像素用%hhu(匹配unsigned char类型),避免类型不匹配导致的未定义行为。 - 增强错误处理:文件读取的每一步都检查返回值,出错时清理所有已分配资源后返回;
freeImagem增加NULL检查,避免传入空指针时崩溃。
内容的提问来源于stack exchange,提问作者Vinicius Caetano
相关产品推荐
相关产品推荐

