C语言读取记事本数据时最后一行数据被重复读出?怎么回事?

我写了一个函数如下,目的是将记事本中的数据显示在屏幕中,记事本中的数据一行一条。但是在编译运行时发现最后一条记录被重复显示了?但我找不出什么问题?那么熟悉C语言的帮我看看吧!感激不尽。
void display()
{
struct record rec;
int i=0;
fp=fopen("record.txt","r"); //以只读方式打开record.txt
if(fp==NULL)
{ printf("打开文件错误!\n"); exit(0); }
system("cls"); //清屏
for(i=0;i<150;i++)
printf("*");
printf("\n");
printf("\t|流水号| 日期 |\t工资\t| 奖金 | 补贴 | 总收入 |食品消费|日用品费|房租| 水电费 |通讯费|交通费| 教育费 | 医疗费 |总支出|\n");
while(feof(fp)==0)
{//如果不是文件尾
fscanf(fp,"%d%d%d%d",&rec.id,&rec.dtime.y,&rec.dtime.m,&rec.dtime.d);
for(i=0;i<13;i++)
fscanf(fp,"%f",&rec.cost[i]);
printf("\t%d\t%d%d%d",rec.id,rec.dtime.y,rec.dtime.m,rec.dtime.d);//输出流水号和日期
for(i=0;i<13;i++)
printf("\t %.2f",rec.cost[i]); //输出各项费用
printf("\n");
}
fclose(fp); //关闭文件
}
记事本中的数据如下所示:
1 2011-6-12 10.00 10.00 10.00 30.00 10.00 10.00 10.00 10.00 101.00 10.00 10.00 10.00 171.00
2 2011-6-13 20.00 20.00 20.00 60.00 20.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.00
3 2011-6-14 100.00 100.00 100.00 300.00 100.00 100.00 100.00 100.00 100.00 100.00 100.00 100.00 800.0

第1个回答  2011-06-26
用feof,但必须记住:当文件刚刚读到文件尾时,feof不会返回true。只有在文件尾部再次进行一次读操作,feof才会返回真。
这与底层系统调用相关。因为只有read返回一次0值,进程才能知道文件结束了。

你可以将代码读取做如下修改
while(fscanf(fp,"%d%d%d%d",&rec.id,&rec.dtime.y,&rec.dtime.m,&rec.dtime.d))
{//如果不是文件尾
for(i=0;i<13;i++)
fscanf(fp,"%f",&rec.cost[i]);
printf("\t%d\t%d%d%d",rec.id,rec.dtime.y,rec.dtime.m,rec.dtime.d);//输出流水号和日期
for(i=0;i<13;i++)
printf("\t %.2f",rec.cost[i]); //输出各项费用
printf("\n");
}

你再试试。追问

试过,不行。而且我没条记录最后的数据项是
for(i=0;i<13;i++)
printf("\t %.2f",rec.cost[i]);
有无read()函数可用判断文件尾的?

追答

这样,你将fscanf(fp,"%f",&rec.cost[i]);
这里作一下判断,也就是
if(!fscanf(fp,"%f",&rec.cost[i]))
说明读到文件末尾了,此时你就跳出循环,下面不用再输出原来已经填充的了。

追问

你说的跳出循环是for那个吗?我试过还是不行。是不是我在while前没有先读入数据呢?

追答

是跳出for后,根据i的值确定没有读取内容,然后跳出while循环。两个是一起跳的。

第2个回答  2011-06-27
#include <stdio.h>

typedef struct node
{
int value;
int weight;
struct node *next;
}linklist;

void Insert(linklist *head, int value, int weight)
{
linklist *rear, *s;

rear = head;
while (rear->value != value &&
rear->next)
{
rear = rear->next;
}

if (rear->value == value)
{
rear->weight += weight;
return;
}

s = new linklist();
s->value = value;
s->weight = weight;
s->next = rear->next;
rear->next = s;
}

void main()
{
linklist *head, *rear;
int value, weight;
FILE *fpIn, *fpOut;
char inFile[FILENAME_MAX], outFile[FILENAME_MAX];

printf("请输入原始数据文件路径:");
scanf("%s", inFile);
fpIn = fopen(inFile, "rt");
if (fpIn == NULL)
{
printf("打开文件'%s'失败,请检查文件是否存在", inFile);
getchar();
return;
}

printf("请输入新文件的名字:");
scanf("%s", outFile);
fpOut = fopen(outFile, "wt");

head = new linklist();
head->value = -1;
head->weight = -1;
head->next = NULL;
while (fscanf(fpIn, "(%d,%d)\n", &value, &weight) > 0)
{
Insert(head, value, weight);
}

fclose(fpIn);

rear = head->next;
while (rear)
{
fprintf(fpOut, "(%d,%d)\n", rear->value, rear->weight);
rear = rear->next;
}
fclose(fpOut);

printf("处理完毕!");
getchar();
}
本回答被提问者采纳
第3个回答  2011-06-26
你把 fscanf(fp,"%d%d%d%d",&rec.id,&rec.dtime.y,&rec.dtime.m,&rec.dtime.d);这句位置改成下面这样试试:

fscanf(fp,"%d%d%d%d",&rec.id,&rec.dtime.y,&rec.dtime.m,&rec.dtime.d);
while(feof(fp)==0)
{//如果不是文件尾
for(i=0;i<13;i++)
fscanf(fp,"%f",&rec.cost[i]);
printf("\t%d\t%d%d%d",rec.id,rec.dtime.y,rec.dtime.m,rec.dtime.d);//输出流水号和日期
for(i=0;i<13;i++)
printf("\t %.2f",rec.cost[i]); //输出各项费用
printf("\n");
fscanf(fp,"%d%d%d%d",&rec.id,&rec.dtime.y,&rec.dtime.m,&rec.dtime.d);
}

或者用 while(fgets(buffer,size,fp))
第4个回答  2011-06-26
先读一次,然后判断是否文件尾又读一次追问

你的思路跟用do-while有区别吗?我试过用do-while来实现,但结果还是最后一条记录重复了