我有一个文本文件,它有很多记录(大约20k行),编写如下:
00000000090020120200728012
00000010520020120200729012
00000002740020120200729012
00000002710020120200736012
00000001601020120200755012
00000002870020120200758012
00000010690020120200753013
00000001760020120200800013
00000008480020120200800013
00000009370020120200733014
00000001500020120200739014
00000012400020120200743014
00000008720020120200715015
00009100570020120200734017
00000002060020120200734017
00000002050020120200734017
00000003670020120200734017这些记录包含2020年访问办公室的数据信息,每个记录都可以用这种结构读取(我将以第一行为例):
按字符读取字符串时,记录按以下方式拆分:
h 1100728(索引19-23 ->小时和访问的分钟)h 211H 112012(索引24-26 -> )h 213f 214
我编写了以下代码,用于计算指定门上指定的徽章ID的记录(在我的例子中,我只需要读取001,002,003门):
#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,因为我需要在办公室的入口数一次,而不是出口。你能帮帮我吗?例如,如果你数ID徽章002341,它会计算342次访问,但它只需要计算一半。请救救我!
发布于 2022-10-18 13:22:30
问题是缓冲区太小,fgets无法在一次调用中读取所有数字和换行符。fgets最多只读取NUMLEN - 1字符。#define NUMLEN 27允许fgets在一次呼叫中读取数字,但没有空间读取换行符。换行符在第二个fgets调用中读取。使用#define NUMLEN 30将提供足够大的缓冲区,以便在一个fgets调用中读取数字和换行符。
使用!feof(fp)作为while条件可能是一个问题。当读取最后一行时,没有错误,所以循环再次迭代。相反,使用fgets作为while条件。
考虑使用sscanf提取字段。%2s将扫描最多两个字符。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define NUMLEN 30
int main () {
printf("\n-- 32bit version\n");
int entriesCounter = 0;
char const *filename = "Storico2020.txt";
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 = NULL;
fp = fopen( filename, "r");
if (fp == NULL) {
perror ( filename);
exit(1);
}
printf("\nInsert ID badge for counting accesses: ");
scanf("%6s", requiredBadge);
while( fgets(buff, NUMLEN, fp)) {
// example -> init:0000 | badge:000352 | entry:1 | data:01012019 | time:0030 | gate:023
if ( 8 != sscanf ( buff + 4, "%6s%1s%2s%2s%4s%2s%2s%3s"
, badge
, entry
, day
, month
, year
, hours
, minutes
, gate)) {
fprintf ( stderr, "bad record %s\n", buff);
continue;
}
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;
}发布于 2022-10-18 13:25:07
您需要更加小心地验证输入。总是(总是)检查扫描返回的值。而且,虽然下面的代码不是我如何做到的,但看到您任意地复制所有这些数据,我感到很痛苦。你不需要这么做。如果您复制数据仅仅是因为您想拥有以空结尾的字符串,但不想破坏缓冲区,则应该重新考虑。例:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void
show(const char *header, const char *str, size_t len)
{
fputs(header, stdout);
fwrite(str, 1, len, stdout);
}
int
main(int argc, char **argv)
{
char buff[1024];
unsigned line = 0;
unsigned entriesCounter = 0;
const char * const badge = buff + 4;
const char * const entry = buff + 10;
const char * const day = buff + 11;
const char * const month = buff + 13;
const char * const year = buff + 15;
const char * const hours = buff + 19;
const char * const minutes = buff + 21;
const char * const gate = buff + 23;
char * const end = buff + 26;
if( argc < 2 ){
fprintf(stderr, "missing badge argument\n");
exit(EXIT_FAILURE);
}
const char *requiredBadge = argv[1];
const char *path = argc > 2 ? argv[2] : "stdin";
FILE *fp = argc > 2 ? fopen(argv[2], "r") : stdin;
if( fp == NULL ){
perror(path);
exit(1);
}
while( *end = '\0', fgets(buff, sizeof buff, fp) != NULL ){
line += 1;
if( *end != '\n' ){
fprintf(stderr, "Unexpected input in line %u\n", line);
continue;
}
if( strncmp(requiredBadge, badge, entry - badge) == 0
&& *entry == '1'
) {
printf("%5d: ", ++entriesCounter);
show("Badge: ", badge, entry - badge);
show(" | in date: ", day, month - day);
show("/", month, year - month);
show("/", year, hours - year);
show(" | gate: ", gate, end - gate);
show(" | hour: ", hours, minutes - hours);
show(":", minutes, gate - minutes);
putchar('\n');
}
}
}
/* Sample input:
00000010520020120200729012
00000002740020120200729012
00000002711020120200736012
00000002710020120200736012
00000002711020120200736012
00000001601020120200755012
00000002870020120200758012
00000010690020120200753013
00000001760020120200800013
00000008480020120200800013
00000009370020120200733014
*/请注意,这会稍微调整接口,并将所需的徽章读入命令行参数,而不是从输入流中获取它。
https://stackoverflow.com/questions/74110214
复制相似问题