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

C语言feof+fgets循环重复计数门禁记录问题求助

门禁记录重复计数问题排查与解决

我有一份2020年办公室门禁记录文本文件,约2万行,每条记录格式固定:

  • 索引[0-3]:无效数据
  • 索引[4-9]:Badge ID
  • 索引[10]:进出标识(0进1出)
  • 索引[11-18]:日期
  • 索引[19-22]:时分
  • 索引[23-26]:Gate ID

编写了C语言代码统计指定Badge ID的出门(entry=1)次数,但结果出现重复计数——比如统计Badge ID 002341时得到342次,实际应为171次。原代码如下:

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

#define NUMLEN 27

int main () {
    printf("\n-- 32bit version\n");
    int entriesCounter = 0;
    char buff[NUMLEN];
    char requiredBadge[7];
    char badge[7];
    char entry[2];
    char day[3];
    char month[3];
    char year[5];
    char hours[3];
    char minutes[3];
    char gate[4];
    FILE *fp;
    fp = fopen("Storico2020.txt", "r");
    if (fp == NULL) {
        printf("Error open");
        exit(1);
    }
    printf("\nInsert ID badge for counting accesses: ");
    scanf("%s", requiredBadge);
    while(!feof(fp)) {
        fgets(buff, NUMLEN, fp);    // example -> init:0000 | badge:000352 | entry:1 | data:01012019 | time:0030 | gate:023
        strncpy(badge, buff+4, 6);
        badge[6] = '\0';
        strncpy(entry, buff+10, 1);
        entry[1] = '\0';
        strncpy(day, buff+11, 2);
        day[2] = '\0';
        strncpy(month, buff+13, 2);
        month[2] = '\0';
        strncpy(year, buff+15, 4);
        year[4] = '\0';
        strncpy(hours, buff+19, 2);
        hours[2] = '\0';
        strncpy(minutes, buff+21, 2);
        minutes[2] = '\0';
        strncpy(gate, buff+23, 3);
        gate[3] = '\0';
        if (strcmp(requiredBadge, badge) == 0 && strcmp(entry, "1") == 0) {
            printf("\nBadge: %s | in date: %s/%s/%s | gate: %s | hour: %s:%s", badge, day, month, year, gate, hours, minutes);
            entriesCounter++;
        }
        
    }
    fclose(fp);
    printf("\n********** TOTAL ACCESSES OF BADGE ID %s: %d ***************\n" ,requiredBadge, entriesCounter);
    
    system("PAUSE");

    return 0;
}

问题根源

  1. while(!feof(fp))循环条件错误:feof()仅在尝试读取并到达文件末尾时返回真,导致最后一行有效数据读取完成后,循环会额外执行一次。此时fgets()读取失败,buff保留上一次的内容,最后一条符合条件的记录会被重复统计。
  2. 缓冲区长度不足:代码中NUMLEN定义为27,但注释里的示例行长度远超过27。fgets()每次只能读取26个字符(需预留1位给终止符\0),剩余内容留在输入缓冲区,下一次循环继续读取同一行的剩余部分,同一条记录被拆分成多次处理,最终计数翻倍。

解决步骤

  • 修正循环条件:将while(!feof(fp))改为while(fgets(buff, sizeof(buff), fp) != NULL),当fgets()读取失败(到达末尾或出错)时直接退出循环,避免重复处理。
  • 增大缓冲区:将NUMLEN调整为足够容纳完整行的数值,比如#define NUMLEN 100,确保能读取整条记录。
  • 可选验证:检查buff最后一个字符是否为\n,若不是则说明该行被截断,可添加跳过或报错逻辑。

修正后的代码

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

#define NUMLEN 100  // 增大缓冲区以容纳完整记录行

int main () {
    printf("\n-- 32bit version\n");
    int entriesCounter = 0;
    char buff[NUMLEN];
    char requiredBadge[7];
    char badge[7];
    char entry[2];
    char day[3];
    char month[3];
    char year[5];
    char hours[3];
    char minutes[3];
    char gate[4];
    FILE *fp;
    fp = fopen("Storico2020.txt", "r");
    if (fp == NULL) {
        printf("Error open");
        exit(1);
    }
    printf("\nInsert ID badge for counting accesses: ");
    scanf("%s", requiredBadge);
    
    // 用fgets返回值判断读取是否成功,替代feof循环
    while(fgets(buff, NUMLEN, fp) != NULL) {    
        strncpy(badge, buff+4, 6);
        badge[6] = '\0';
        strncpy(entry, buff+10, 1);
        entry[1] = '\0';
        strncpy(day, buff+11, 2);
        day[2] = '\0';
        strncpy(month, buff+13, 2);
        month[2] = '\0';
        strncpy(year, buff+15, 4);
        year[4] = '\0';
        strncpy(hours, buff+19, 2);
        hours[2] = '\0';
        strncpy(minutes, buff+21, 2);
        minutes[2] = '\0';
        strncpy(gate, buff+23, 3);
        gate[3] = '\0';
        
        if (strcmp(requiredBadge, badge) == 0 && strcmp(entry, "1") == 0) {
            printf("\nBadge: %s | in date: %s/%s/%s | gate: %s | hour: %s:%s", badge, day, month, year, gate, hours, minutes);
            entriesCounter++;
        }
    }
    fclose(fp);
    printf("\n********** TOTAL ACCESSES OF BADGE ID %s: %d ***************\n" ,requiredBadge, entriesCounter);
    
    system("PAUSE");

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:01:00