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

C语言程序内存泄漏修复及数组越界无警告问题咨询

C代码内存泄漏与数组越界问题修复

一、原解析代码

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<ctype.h>
#include<limits.h>
#include<uchar.h>
#include<assert.h>
#define MAXW    128
#define MAXC    112
int main(int argc,char **argv)
{
    int readdef = 0;            /* flag for reading definition */
    size_t offset = 0            /* offset for each part of definition */
        ,len = 0;             /* length of each line */
    char buf[MAXC] = "";      /* read (line) buffer */
    char word[MAXW] = "";     /* buffer storing word */
    char defn[MAXC] = "";     /* buffer storing definition */

    /* open filename given as 1st argument, (or read stdin by default) */
    FILE *fp = argc > 1 ? fopen(argv[1],"r") : stdin;

    if(!fp){     /* validate file open for reading */
        fprintf(stderr,"error: file '%s' open failed\n",argv[1]);
        exit(EXIT_FAILURE);
    }

    while(fgets(buf,MAXC,fp))
    {
        char *p = buf;   /* pointer to parse word & 1st part of defn */

        if(*buf == '\n') {
            defn[offset-1] = 0;
            printf("defn:%s\n\n",defn);
            readdef = 0;
            offset= 0;
        }
        else if(readdef == 0)
        {
            while(*p && *p != '.') p++;
            if(p-buf+1 > MAXW){
                fprintf(stderr,"error: word exceeds %d chars.\n",MAXW-1);
                exit(EXIT_FAILURE);
            }
            snprintf(word,p-buf+1,"%s",buf);     /* copy to word */
            printf("word=%s|\n",word);
            
            while(ispunct(*p) || isspace(*p))
                p++;
            
            len = strlen(p);

            if(len && p[len-1] == '\n')
                p[len-1] = ' ';

            strcpy(defn,p);
            offset +=len;
            readdef = 1;
        }
        else{
            len = strlen(buf);              /*get the line length */
            if(len && buf[len-1] == '\n')   /* chk \n, overwrite w/' ' */
                buf[len-1] = ' ';
            
            if(offset + len + 1 > MAXC){
                fprintf(stderr,"error: definition exceed %d chars\n",MAXC-1);
                // free(buf);
                exit(EXIT_FAILURE);
            }

            snprintf(defn+offset,len+1,"%s",buf);   /* append to defn */
            offset += len;                          /*update offset*/
        }
    }

    if(fp != stdin) fclose(fp);

    defn[offset - 1] = 0;
    printf("defn: %s\n\n",defn);

    exit(EXIT_SUCCESS);
}

二、MAXC不足时的内存泄漏问题

泄漏现象

当MAXC取值较小时,valgrind检测到仍有内存未释放:

error: definition exceed 111 chars
==28017==
==28017== HEAP SUMMARY:
==28017==     in use at exit: 472 bytes in 1 blocks
==28017==   total heap usage: 3 allocs, 2 frees, 5,592 bytes allocated
==28017==
==28017== 472 bytes in 1 blocks are still reachable in loss record 1 of 1
==28017==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==28017==    by 0x48ED6CD: __fopen_internal (iofopen.c:65)
==28017==    by 0x48ED6CD: fopen@@GLIBC_2.2.5 (iofopen.c:86)
==28017==    by 0x109285: main (in /home/jian/helloc/a.out)
==28017==
==28017== LEAK SUMMARY:
==28017==    definitely lost: 0 bytes in 0 blocks
==28017==    indirectly lost: 0 bytes in 0 blocks
==28017==      possibly lost: 0 bytes in 0 blocks
==28017==    still reachable: 472 bytes in 1 blocks
==28017==         suppressed: 0 bytes in 0 blocks
==28017==
==28017== For lists of detected and suppressed errors, rerun with: -s
==28017== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

原因分析

程序检测到定义长度超限后直接调用exit退出,但如果是通过命令行参数打开的文件(fp != stdin),文件指针未被关闭,导致文件关联的内存资源未释放。

修复方案

在所有触发exit的分支前,先关闭已打开的文件指针:

// 单词长度超限分支修改
if(p-buf+1 > MAXW){
    fprintf(stderr,"error: word exceeds %d chars.\n",MAXW-1);
    if(fp != stdin) fclose(fp); // 新增关闭文件操作
    exit(EXIT_FAILURE);
}

// 定义长度超限分支修改
if(offset + len + 1 > MAXC){
    fprintf(stderr,"error: definition exceed %d chars\n",MAXC-1);
    if(fp != stdin) fclose(fp); // 新增关闭文件操作
    exit(EXIT_FAILURE);
}

三、首行空换行时的数组越界问题

问题场景

当输入文件dat/definitions.txt首行为空换行时,代码执行defn[offset-1] = 0,此时offset值为0。由于offset是无符号的size_t类型,offset-1会溢出为极大值,导致访问defn数组的越界位置,触发未定义行为。

GCC未警告的原因

GCC默认静态分析不会检测这种仅在运行时触发的动态越界,尤其是涉及无符号整数溢出的场景。需要开启更高等级的编译警告才能触发提示,比如添加编译选项:-Wall -Wextra -Warray-bounds,其中-Warray-bounds会对数组越界做更严格的检查。

修复方案

在执行数组操作前,先判断offset是否大于0,避免越界:

// 空行处理分支修改
if(*buf == '\n') {
    if(offset > 0) { // 新增判断
        defn[offset-1] = 0;
        printf("defn:%s\n\n",defn);
    }
    readdef = 0;
    offset= 0;
}

// 文件末尾处理修改
if(offset > 0) { // 新增判断
    defn[offset - 1] = 0;
    printf("defn: %s\n\n",defn);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 19:15:50