727文件操作-文件操作_例题(1)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
【例题一】
1、实验目的
〔1〕掌握文本文件的格式化读写方法。
〔2〕掌握文件程序典型编译出错信息,掌握常用跟踪调试方法。
2、实验任务
〔1〕实验内容:将文本文件中所有整数相加,并把累加和写入该文件的末尾。
给出有错误的源程序,请调试程序并改正。
〔2〕实验要求:建立一个文本文件Int_Data.dat,事先在其中存放假设干个整数,以空格或换行间隔。
编写程序,将此文件中所有整数相加,并把累加和写入该文件的末尾。
/* 1 */ #include <stdio.h>
/* 2 */ #include <stdlib.h>
/* 3 */ int main(void)
/* 4 */ { FILE *fp; /*定义文件指针*/
/* 5 */ int n,sum;
/* 6 */ if(fp = fopen("Int_Data.dat", "r")==NULL){ /*翻开文件*/
/* 7 */ printf("Can't Open File!");
/* 8 */ exit(0);
/* 9 */ }
/* 10 */ sum=0;
/* 11 */ while(fscanf(fp, "%d", &n)==EOF) /*断点*/ /*从文件读数*/
/* 12 */ sum = sum + n;
/* 13 */ fprintf(fp, " %d", sum); /*累加和写入文件*/
/* 14 */ fclose(fp);
/* 15 */ return 0;
/* 16 */ }
3、实验分析
〔1 〕程序分析:该程序先定义文件指针fp ,用fopen() 以读方式翻开文本文件Int_Data.dat,遍历文件中每个数,每读一个数就计算一次累加和,最后用fprintf()将和写入文件,关闭文件。
〔2〕调试要点
具体调试步骤如下:
1〕在运行程序前,先建立文本文件Int_Data.dat,并写入例如中的初始数据。
2〕编译程序,出现编译错误,出错提示信息指出,第6 行代码中的赋值表达式左右两边的类型不匹配。
分析错误原因,是由于运算符“=〞与“==〞的优先级不同造成的,应该先执行赋值运算,再执行关系运算,所以改为:
if((fp = fopen("Int_Data.dat", "r"))==NULL){ /*加上一对括号*/
3〕重新编译和连接,未出现错误信息。
运行程序后,查看文件Int_Data.dat 的内容,发现没有发生变化。
故程序存在逻辑错误。
4〕设置断点,调试程序,程序运行到断点,继续单步运行,发现已读出文件中的第一个值10,但并没有累加到变量sum 中,且while 循环已结束,说明while 循环条件出错。
这是因为当fscanf()执行失败时返回值才为EOF,因此第11 行应改为:
while(fscanf(fp, "%d", &n)!=EOF) /*使用!=*/
5 〕重新调试程序,文件数据能够正常读取并累加,运行结束后,翻开文件Int_Data.dat,发现文件内容仍然没有变化。
说明sum 数据未写入,但第13 行语句并没有错误。
结合前文分析,原来是翻开文件时没有设置写权限,因此,将第
6 行改为:if((fp = fopen("Int_Data.dat", "r+"))==NULL){ /*使用"r+"方式*/
6〕重新运行程序,运行结果与预期一致。
4、参考代码〔更正局部〕
本案例共修改了3 处错误,涉及两行代码。
更正代码如下:
/* 6 */ if((fp = fopen("Int_Data.dat", "r+"))==NULL){/*翻开文件。
修改了两处/
/* 11 */ while(fscanf(fp, "%d", &n)!=EOF) /*从文件中读数。
修改1 处*/
5、思考题
读者可以尝试一下,如果以"w+"或"a+"的方式翻开文件,程序其他局部一样,结果会
怎么样?为什么?
【例题二】
1.实验目的
〔1〕掌握二进制文件的根本处理方法。
〔2〕掌握随机文件的处理方法。
〔3〕掌握排序算法的实现,掌握函数定义、参数传递、调用。
2.实验任务
〔1〕实验内容:编写一个程序,将二进制文件student.dat 中的数据,按成绩从高到低排序并输出。
其中,文件中的数据包含了众多学生的信息,包括:学号、姓名、成绩,其结构如下:struct student{
char id[11];
char name[21];
int score;
};
〔2〕实验要求:读者实验时需要事先生成包含学生成绩的二进制文件,可以单独编写相应的程序,或利用本章实验工程9-7 的结果。
要求输出排序后的数据如下形式:
……
3.实验分析
〔1〕问题分析:本实验题涉及两个关键问题,一是二进制数据的读入,二是数据排序。
从文件中读入结构化的二进制数据,可以采用fread()函数。
对数据排序,可以将所有数据存储在数组里,并采用读者熟悉的排序算法进行排序。
但这里关键的问题是:之前并不知道文件中的数据个数,所以,事先无法决定数组的大小。
我们可以采用动态分配空间的方式使用动态数组。
但还是需要计算文件中数据的个数。
这里采用两种方法来统计个数,方法一是先将所有数据读出,以统计出个数;方法二是利用函数fseek()和ftell()计算得出个数。
〔2〕实验要点:
1〕二进制文件数据的读写与处理
本案例采用了二进制文件,按记录存放,所以先以二进制文件读方式"rb"翻开文件。
由
于需要知道记录的个数并申请动态数组空间,可以采用以下两种方法。
方法一:循环中用 fread()读出每一条记录统计人数,再根据人数精确地分配存储数据 的存储空间,然后使用 rewind()函数〔或关闭文件后再重新翻开〕将文件指针移到文件首, 再次读出数据放入动态分配的存储空间内。
最后,对这批读出的数据进行处理。
方法二:先使用 fseek()控制文件指针到文件尾,再利用 ftell()获得相对于文件开头的字节数,然后通过计算获得文件内储存的人数。
接下去的操作方法与方法一一样。
2〕排序函数的定义、参数传递、调用
可定义函数 ,实现以 p 为首地址的连续 n 条记录〔结构体变量〕,按结构分量 score 排序。
在主函数中,调用 sort(p,n),将存储空间首地址实参 p 和人数实参 n 传给对应的形参。
3〕根本算法
主函数算法如错误:引用源未找到所示:
将文件中的成绩排序流程图 4.
参考代码
/* 3 */ struct student{
/* 定义结构体 */ /* 4 */ char id[11];
/* 5 */ char name[21];
/* 6 */ int score;
/* 7 */ };
/* 8 */ void main()
/* 9 */ { struct student st,*p;
/* 10 */ FILE *fp;int n=0,i;
/* 11 */ void sort(struct student *,int);
/* 12 */ if((fp=fopen("c:\\student.dat","rb"))==NULL){ /* 文件翻开*/
/* 13 */ printf("Cannot open file!\n");
/* 14 */ exit(0);
/* 15 */ }
/* 16 */ while(!feof(fp)){ /* 读出数据,以统计人数*/
/* 17 */ fread(&st,sizeof(struct student),1,fp);
/* 18 */ n++;
/* 19 */ }
/* 20 */ n--; /* C 程序自动将最后一个学生的数据重复读出一次*/
/* 21 */ p=(struct student*)malloc(n*sizeof(struct student)); /*根据人数动态分配存储单元*/
/* 22 */ rewind(fp); /* 将文件指针移到文件首*/
/* 23 */ fread(p,sizeof(struct student),n,fp); /*将n 个学生数据存储在p 为首地址的存储单元*/ /* 24 */ fclose(fp); /* 文件关闭*/
/* 25 */ sort(p,n); /* 以存储数据的首地址和人数为参数,调用排序函数*/
/* 26 */ printf("%6s%13s%15s\n","id","name","score"); /* 输出表头*/
/* 27 */ for(i=0;i<n;i++) /* 输出排序后的结果*/
/* 28 */ printf("%-12s%-20s%d\n",p[i].id,p[i].name,p[i].score);
/* 29 */ }
/* 30 */ void sort(struct student *p,int n) /* 排序函数〔使用选择分类算法〕*/
/* 31 */ {int i,j,index;
/* 32 */ struct student stu;
/* 33 */ for(i=0;i<n-1;i++){
/* 34 */ index=i;
/* 35 */ for(j=i+1;j<n;j++)
/* 36 */ if(p[j].score>p[index].score)index=j;
/* 37 */ stu=p[index];p[index]=p[i];p[i]=stu;
/* 38 */ }
/* 39 */ }
方法二的程序片断为〔将方法一的16 至20 行替换成如下程序段〕:
fseek(fp,0l,2); /* 将指针移到文件末尾*/
n=ftell(fp)/sizeof(struct student); /* 通过当前指针相对于文件首的字节数计算人数*/ 5.思考题
如果要求采用链表存储数据,并将sort()函数改成链表插入函数insert(),且从文件中只读出一遍数据,那么程序如何修改?。