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

C语言文件行读取函数异常排查:乱码、空文件行数统计错误

问题排查与修复

以下是你的代码中存在的核心问题及对应的修复方案:

1. 文件指针位置未重置

调用count_number_of_lines后,文件指针会移动到文件末尾(EOF)。后续调用getLineFromFile时,fgets无法读取任何内容,导致字符串内存未初始化,输出乱码。

修复:在统计行数后调用rewind(fp)将文件指针重置到文件开头。

2. 空行统计逻辑错误

原count_number_of_lines函数会将仅包含换行符的空行计入统计(因为fgets会读取换行符,strlen(line)结果为1),不符合"统计非空行"的需求;虽空文件返回0是正确的,但非空文件中的空行统计有误。

修复:读取每行后先去掉换行符,再检查是否包含非空白字符。

3. getLineFromFile函数边界处理不当

  • 当指定行号超过文件实际行数时,fgets会返回NULL,此时直接修改字符串会导致未定义行为。
  • 若行末尾无换行符(如文件最后一行),str[strlen(str)-1] = '\0'会错误修改有效字符。

修复:跟踪最后一次成功读取的行,仅当行末尾存在换行符时才移除它;若未读取到任何行,释放内存并返回NULL。

4. 内存泄漏

  • main和compiled函数中初始malloc的指针被getLineFromFile的返回值覆盖,导致内存泄漏。
  • getLineFromFile返回的字符串未被释放,多次调用会累积内存泄漏。

修复:不再提前malloc指针,每次使用getLineFromFile返回的字符串后立即释放。


修复后的完整代码

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

char* getLineFromFile(FILE *fp, int lineNumber) // 若行号超出总行数,返回最后一行
{
    char *str = malloc(sizeof(char) * 80);
    if (!str) return NULL; // 处理内存分配失败

    int i;
    int has_read = 0;
    for (i = 1 ; i <= lineNumber; i++) {
        if (fgets(str, 80, fp) == NULL) {
            break; // 到达文件末尾,停止读取
        }
        has_read = 1;
    }

    if (has_read) {
        // 仅当行末尾存在换行符时移除
        size_t len = strlen(str);
        if (len > 0 && str[len-1] == '\n') {
            str[len-1] = '\0';
        }
        return str;
    } else {
        // 未读取到任何内容,释放内存并返回NULL
        free(str);
        return NULL;
    }
}

/// 统计文件中的非空行(不含仅空白字符的行)
int count_number_of_lines(FILE *fp) {
    int count = 0;
    char line[256];

    while (fgets(line, sizeof(line), fp) != NULL) {
        size_t len = strlen(line);
        // 移除换行符
        if (len > 0 && line[len-1] == '\n') {
            line[--len] = '\0';
        }
        // 检查是否包含非空白字符
        int is_empty = 1;
        for (size_t j = 0; j < len; j++) {
            if (!isspace((unsigned char)line[j])) {
                is_empty = 0;
                break;
            }
        }
        if (!is_empty) {
            count++;
        }
    }

    return count;
}

int compiled(FILE* fp){
    int nb_lines = count_number_of_lines(fp);
    rewind(fp); // 重置文件指针到开头
    printf("number of lines : %d \n", nb_lines);
    
    for (int j=1; j<=nb_lines; j++){
        char *line = getLineFromFile(fp, j);
        if (line) {
            printf("%s \n", line);
            free(line); // 释放内存
        }
    }
    return 0;
}

int main()
{
    FILE *fichier = fopen("CodeSource.txt", "r");
    if (!fichier) {
        perror("无法打开文件");
        return 1;
    }

    int nb_lines = count_number_of_lines(fichier);
    rewind(fichier); // 重置文件指针到开头
    
    for (int j=1; j<=nb_lines; j++){
        char *str = getLineFromFile(fichier, j);
        if (str) {
            printf("%s \n", str);
            free(str); // 释放内存
        }
    }

    fclose(fichier); // 关闭文件
    return 0;
}

额外说明

  • 代码中增加了fclose(fichier)以确保文件资源被正确释放。
  • 添加了内存分配失败的处理逻辑,避免程序崩溃。
  • 若需要支持超过79字符的行,需修改getLineFromFile的内存分配逻辑(如动态扩容),当前代码假设每行不超过79字符。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 22:45:38