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

释放结构体中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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 03:07:22