题目描述
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:
1、 记录最多8条错误记录,循环记录,对相同的错误记录(净文件名称和行号完全匹配)只记录一条,错误计数增加;
2、 超过16个字符的文件名称,只记录文件的最后有效16个字符;
3、 输入的文件可能带路径,记录文件名称不能带路径。
输入描述:
一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。
输出描述:
将所有的记录统计并将结果输出,格式:文件名 代码行数 数目,一个空格隔开,如:
输入
E:\V1R2\product\fpgadrive.c 1325
输出
fpgadrive.c 1325 1
这道题目拿到手之后,想法不少,然后首先用了结构体,后来考虑数字字符串的时候字符串数字要不要存成数字?然后舍弃结构体用了二位数组,结果依旧写着写着一团乱麻,其实就是拿到题目后没想清楚就开始写导致的。最后还是选择结构体,读取字符串的时候,连着读两个:一个字符串一个数字(scanf),之前用gets的时候很麻烦啊。
后来提交后又遇到一个问题,我写的代码,在连续遇到多个一样的文件记录且后面不再输入这种情况的时候输出有问题(flag比其他情况多1),老想不明白为什么会有这样的问题,后来想明白了,但是怎么解决嘞?其实加一个变量记录一下到底插入了多少条记录就好了,而不是用设置的flag,用flag导致的问题就是输出的时候最后一个为0,0 其他情况没遇到是因为紧接着后面又读入的时候,其实不会影响结果,只有连续遇到多个与之前文件记录相同的记录且不再输入其他新的错误记录的时候才会出现这样的问题,人家测试用例设计的很好啊!为什么我想不到呢,是怎么考虑到这种特殊情况的!要我设计测试用例的话我会怎么设计?
---------------------------------c代码--------------------------------------
算法思想:类似于二叉排序树(二叉排序树的插入是基于查找的,只有查找失败的时候才进行插入操作,查找成功的时候不做任何改变),所以本题,边查找看是否有文件名和行数一样的记录,如果有,则修改数量;如果没有,则插入;继续读入下一条记录。做这道题目还有一点小技巧就是scanf用来获取输入比gets好,所以要具体问题具体分析,明确两者之间的差异。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node{
char fname[100];
int num;
int line;
};
int main()
{
struct node a[100];
char temp[100];
int t_num,flag,i=0;
int count=0;
while(scanf("%s %d",&temp,&t_num)!=EOF)
{
char *p,*q,stemp[100];
flag=i;
int len=strlen(temp);
p=strrchr(temp,'\\');
q=&temp[len-1];
//文件名处理
if(q-p<=16)
{memcpy(stemp,p+1,q-p);stemp[q-p]='\0';}
else
{memcpy(stemp,q-16+1,16);stemp[16]='\0';}
//开始查找不到一样的则插入,否则修改数量继续读入文件名
int isput=0;
for(int k=0;k<flag;k++)
{
if(strcmp(a[k].fname,stemp)==0&&a[k].line==t_num)
{
a[k].num=a[k].num+1;//找到一样的,改变数量
isput=1;
i--;break;
}
}
//找到一样的记录就不插入,否则插入
if(isput==0)
{
//插入
strcpy(a[i].fname,stemp);
a[i].line=t_num;
a[i].num=1;
count=count+1;//标记到底记录了多少错误信息
}
i++;
}
//输出,如果输入记录少于8条或大于等于8条分别考虑
if(flag<8)
{
for(int k=0;k<count;k++)
{printf("%s %d %d\n",a[k].fname,a[k].line,a[k].num);}
}
else
{
for(int k=count-8;k<count;k++)
{
printf("%s %d %d\n",a[k].fname,a[k].line,a[k].num);
}
}
}