资源描述
单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,单击此处编辑母版标题样式,#,Visual C+,模块,7,位运算与文件,任务,1,位运算,学习目标,掌握六种位运算的运算符与格式、运算规则。,7.1.1,案例讲解,案例,1,二进制的循环移位,1,问题描述,实现二进制的循环移位。设待移位的数为,a,,移位情况如图,7-1,,设系统中,2,个字节存放一个整数。,2,编程分析,n,位图,7-1,二进制的循环移位图解,该问题的要求在于将待移位数,a,分成两部分,然后交换这两部分的位置。从而可知,需要增加两个变量存储变量,a,的两部分的值,而这些操作都需要求助于位运算。程序描述如下:,main ( ),定义无符号整型变量,a,b,c,定义整型变量,n,输入待移位数,a,和所移动位数,n,对数,a,左移,16-n,位后的结果给变量,b,对数,a,右移,n,位后的结果给变量,c,对变量,b,c,做按位或运算,计算结果给变量,c,输出变量,a,和,c,n,位,n,位,图,7-1,二进制的循环移位图解,3,编写源程序,/* EX7_1.C */,#include ,main( ),unsigned short unsignedA, unsignedB, unsignedC;,int intN;,printf(,请输入一个无符号整型变量,unsignedA,的值:,);,scanf(%u,printf(,请输入移位位数,intN,的值:,);,scanf(%d,unsignedB = unsignedA intN;,unsignedC = unsignedC | unsignedB;,printf(unsignedA,的值:,%on, unsignedA);,printf(unsignedC,的值:,%on, unsignedC);,4,运行结果,图,7-2,案例,1,运行结果,5,归纳分析,在本案例中,使用了左移位运算、右移位运算和按位或运算相配合,实现二进制的循环移位。,该程序运行的一个实例,输入,unsignedA,的值为,174,,移动位数,intN,的值为,2,,则运行结果如图。其中:十进制数,174,(即为八进制数,256,)的二进制数为,0000000010101110,(按题设要求为,2,个字节),循环移动,2,位,则循环移位后的二进制结果为,1000000000101011,(即为八进制数,100053,)。,7.1.2,基础理论,C,语言中提供给开发人员一种位的运算,这种位的运算常用在检测和控制领域中,这和,C,语言的特性关系非常大,因为,C,语言是具有高级语言的特点和低级语言的功能,能完成一些汇编语言所能完成的功能。给开发人员提供了一定的简便。,C,语言提供了六种位运算,下面分别介绍。,1,按位与运算,(&),(1),格式:,x&y,(2),规则:按位与运算符,“,&,”,是双目运算符。其功能是参加运算的两数各对应的二进位相与。只有对应的两个二进位均为,1,时,结果位才为,1,,,否则为,0,。参加运算的数以补码方式出现。,例如:,9&5,可写算式如下,00001001,& 00000101,00000001,结果为:,9&5=1,。,(3),主要用途:用来对某些位清,0,或保留某些位。,例如:把,a,的高八位清,0,,保留低八位,可作,a&255,运算,(255,的二进制数为,0000000011111111),。,2,按位或运算符,(|),(1),格式:,x|y,(2),规则:按位或运算符,“,|,”,是双目运算符。其功能是参加运算的两数各对应的二进位相或。只要对应的二个二进位有一个为,1,时,结果位就为,1,。参加运算的两个数均以补码出现。,例如:,9|5,可写算式如下,00001001,| 00000101,00001101,结果为:,9|5=13,(3),主要用途:常用来将源操作数某些位置,1,,其他位不变。,例如:把,a,的低八位置,1,,保留高八位,可作,a|255,运算,(255,的二进制数为,0000000011111111),。,3,按位异或运算,(),(1),格式:,xy,(2),规则:按位异或运算符,“,”,是双目运算符。其功能是参加运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为,1,。参加运算数仍以补码出现。,例如:,95,可写成算式如下,00001001, 00000101,00001100,结果为:,95=12,(3),主要用途:常用来将源操作数某些特定位的值取反,其他位不变。,例如:把,a,的低八位取反,保留高八位,可作,a255,运算,(255,的二进制数为,0000000011111111),。,4,求反运算,(),(1),格式:, x,(2),规则:求反运算符,为单目运算符,具备右结合性。 其功能是对参加运算的数的各二进位按位求反。,例如:,9,可写成算式如下, 0000000000001001,1111111111110110,结果为:,9=-10,5,左移运算(,),(1),格式:,x,位数,(2),规则:左移运算符,“,”,是双目运算符。其功能是把,“,”,左边的运算数的各二进位全部左移若干位,,“,”,右边的数指定移动的位数。低位补,0,,高位溢出。,例如: 设,a=15,,,a,),(1),格式:,x,位数,(2),规则:使操作数的各位右移,高位补,0,,低位溢出。,例如:,52=1,00000101,右移两位,00000001,任务,2,文件,学习目标,掌握标准设备输入、输出函数的使用;掌握缓冲文件系统的使用。,7.2.1,案例讲解,案例,1,读取指定文件内容,1,问题描述:,已知一文本文件,“,c: text.txt”,的内容如下:,#include,void main( ),printf(hello world);,编写程序读取指定该文本文件的内容,并在屏幕上输出。,2,编程分析:,程序描述如下:,main( ),定义文件指针 *,fp,,定义字符变量,ch,打开指定的文本文件,判断指定的文本文件是否能打开,假如不能打开,显示提示信息,并结束程序,使用循环读取该文本文件的每个字符,并依次在屏幕上输出,关闭指定的文本文件,3.,编写源程序,/* EX7_8.C */,#include ,#include ,/*,控制台输入输出 *,/,#include ,/*,最常用的系统函数*,/,void main( ),FILE *fileP;,char charC;,if(fileP =fopen(c:text.txt,r)=NULL),printf(,不能打开文件,按任意键退出,!);,getch( );,exit(1);,while (charC =fgetc(fileP)!=EOF),putchar(charC);,fclose(fileP);,4,运行结果,图,7-9,案例,1,运行结果,5,归纳分析,本例程序的功能是从文件中逐个读取字符,在屏幕上显示。程序定义了文件指针,fileP,,以读文本文件方式打开文件“,text.txt”,,并使,fileP,指向该文件。如打开文件出错,给出提示并退出程序。,While,循环中每次读出一个字符,只要读出的字符不是文件结束标志(每个文件末有一结束标志,EOF,)就把该字符显示在屏幕上,然后再读入下一字符。每读一次,文件内部的位置指针向后移动一个字符,文件结束时,该指针指向,EOF,。,7.2.2,基础理论,1,文件的概念,文件是指存储在外部介质上的数据集合体,是操作系统数据管理的单位。使用数据文件的目的:,(1),数据文件的改动不引起程序的改动,程序与数据分离;,(2),不同程序可以访问同一数据文件中的数据,数据共享;,(3),能长期保存程序运行的中间数据或结果数据。,2,文件的分类,根据文件存储的内容的不同,文件可以分为,程序文件,和,数据文件,两种。程序文件是程序代码的集合体,而数据文件是指专门用来保存数据的文件。,根据文件存储介质的不同,文件又可以分为,磁盘文件,和,设备文件,两种。磁盘文件是指保存在磁盘或其他外部存储介质上的一个有序数据集,可以是,C,语言的源文件、目标文件、可执行程序,也可以是一组待输入处理的原始数据,或者是一组输出的结果。对于源文件、目标文件、可执行,程序可以称为程序文件,对于输入输出数据可称为数据文件。设备文件是指与主机相联的各种外部设备,如显示器、打印机、磁盘等。,C,语言把外部设备也看作是,一个文件来进行管理,把他们的输入、输出等同于对磁盘文件的读和写。通常把显示器定义为标准输出文件,键盘指定为标准的输入文件。,根据文件的组织形式不同,文件又可以分为,ASCII,码文件(也称为文本文件),和,二进制码文件两种。,ASCII,码文件,每个字节存放一个字符的,ASCII,码。二进制码文件,数据按,其在内存中的,存储形式原样存放。例如:,int,型数,10000,,在内存中存储占用两个字节,其中,1,的,ASCII,为,00110001,,,0,的,ASCII,为,00110000,,,10000,的二进制表示为,10011100010000,。如果分别存储到文本文件和二进制码文件中,其形式如下:,图,7-10,数据存储示意图,从图中可以看出来,,ASCII,码文件输入与字符一一对应,便于对字符进行逐个处理,也便于字符的输出,但一般占存储空间较多,而且花费二进制代码和,ASCII,代码之间的转换时间。,用,二进制文件则可以节省外部存储空间和转换的时间,但处理过程比较复杂。,因此,文本文件特点:存储量大、速度慢、便于对字符操作;二进制码文件特点:存储量小、速度快、便于存放中间结果。,3,文件的处理,在,C,语言中,对文件的输入输出都是通过文件,系统完成的,并不区分类型,都看成是字符或者是二进制流,按字节进行处理。输入输出数据流的开始和结束只由程序控制而不受物理符号(如回车换行符)的控制。因此我们也把这种文件称作“,流式文件,”。,文件系统又分为,缓冲文件系统,和,非缓冲文件系统,。所谓缓冲文件系统是高级文件系统,系统自动地在内存区为每一个正在使用的文件名开辟一个缓冲区,数据的输入输出都是以这个缓冲区为中介。所谓非缓冲文件系统是低级文件系统,指系统不自动开辟确定大小的缓冲区,而由程序,为每个文件设定缓冲区。图,7-11,和图,7-12,分别是缓冲文件系统和非缓冲文件系统。,标准,C,只采用缓冲文件系统,,也就是既用缓冲文件系统处理文本文件,也用它来处理二进制文件。在,C,语言中没有输入输出语句,对文件的读写操作都是用标准的输入输出库函数来实现的。,4,缓冲文件系统,(,1,),FILE,类型和文件指针,在缓冲文件系统中,使用最多的概念就是“文件指针”。缓冲文件系统为每个使用的文件在内存中开辟一个缓冲区,用来存放文件的相关信息,这些信息被保存在,FILE,类型的变量中。在,stdio.h,文件中有,FILE,类型的定义:,typedef struct,short level; /*,缓冲区空或满的程度*,/,unsigned flags; /*,文件状态标志*,/,char fd; /*,文件描述符*,/,unsigned char hold; /*,如无缓冲区则不读取字符*,/,short bsize; /*,缓冲区的大小*,/,unsigned char *buffer; /*,数据缓冲区的位置*,/,unsigned ar *curp; /*,指针,当前的指向*,/,unsigned istemp; /*,临时文件*,/,short token; /*,用于有效性检查*,/,FILE;,对于普通用户而言,不必了解,FILE,类型的结构内容,只要知道,,每个文件都对应一个唯一的文件型指针变量,通过文件指针我们可以对它所指的文件进行各种操作。,定义文件型指针变量的一般形式为:,FILE *,指针变量名,;,例如:,FILE *fileP; fileP,是指向,FILE,类型结构体的指针变量,通过,fileP,即可找存放某个文件信息的结构变量,然后按结构变量提供的信息,可以访问该文件,实施对文件的操作。习惯上也,笼统地把,fileP,称为指向一个文件的指针。,5,文件的操作,对文件的基本操作有两种,一种是输入操作,一种是输出操作。在访问文件之前,要先打开文件,然后才能访问该文件,对文件操作结束后,还要关闭该文件。因此对文件的操作,必须遵守“先打开,再读写,后关闭”的规则,也就是说在进行读写操作之前要先打开文件,使用完毕后要关闭。,(1),文件的打开函数,fopen,fopen,函数用来实现打开一个文件,其调用的一般形式为:,FILE * fileP;,fileP =fopen,(,文件名,使用文件方式,),;,其中,“文件名”是被打开文件的文件名,包括文件的存储路径,“使用文件方式”是指文件的类型和操作要求。,例如:,fileP =fopen(“file1”,“r”),;,它表示在当前目录下打开文件,file1,,使用文件方式为“读”操作,并使,fileP,指向该文件。,使用文件的方式共有,12,种,如表,7-1,所示,.,表,7-1,文件使用方式表,文件使用方式,含义,“,r”,(只读),打开一个文本文件,只允许读数据,“,w”,( 只写),打开或建立一个文本文件,只允许写数据,“,a”,( 追加),打开一个文本文件,并在文件末尾增加数据,“,rb”,(只读),打开一个二进制文件,只允许读数据,“,wb”,( 只写),打开或建立一个二进制文件,只允许写数据,“,ab”,( 追加),打开一个二进制文件,并在文件末尾写数据,“,r+”,( 读写),打开一个文本文件,允许读和写,“,w+”,( 读写),建立一个文本文件,允许读写,“,a+”,( 读写),打开一个文本文件,允许读,或在文件末追加数据,“,rb+”,( 读写),打开一个二进制文件,允许读和写,“,wb+”,( 读写),建立一个二进制文件,允许读和写,“,ab+”,( 读写),打开一个二进制文件,允许读,或在文件末追加数据,说明:,用“,r”,方式打开的文件,,该文件必须已经存在,且只能从该文件读出数据。,用“,w”,方式打开的文件只能向该文件写入数据。,若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。,如果想向一个已存在的文件末尾添加新的信息(不删除原来的数据),则应该用“,a ”,方式打开。,但此时该文件必须是存在的,否则将会出错。,用“,r+”,、“,w+”,、“,a+”,方式打开的文件,既可以用来写入数据,也可以用来读出文件中的数据。,如果不能打开一个文件时,,fopen,将返回一个空指针值,NULL,。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。因此常用以下程序段打开文件:,if(fileP =fopen(file1,r)= =NULL),printf(n,不能打开文件,file1n);,exit(0);,(2),文件关闭函数,fclose,文件一旦使用完毕,应该用关闭文件函数把文件关闭,以避免文件的数据丢失等错误。,所谓关闭文件就是使文件指针变量不再指向该文件。,调用的一般形式是:,fclose(,文件指针,),;,例如:,fclose(fileP);,顺利完成关闭文件操作时,,fclose,函数返回值为,0,,否则返回,EOF,(,-1,)。,6,文件的读写和建立,文件打开以后,就可以对它进行读写操作了。,在语言中提供了多种文件读写的函数:,字符读写函数 :,fgetc,和,fputc,字符串读写函数:,fgets,和,fputs,数据块读写函数:,fread,和,fwrite,格式化读写函数:,fscanf,和,fprinf,使用以上函数都要求包含头文件,stdio.h,。,(1),读字符函数,fgetc,fgetc,函数的功能是从指定的文件中读一个字符,,读取的文件必须是以读或读写方式打开的。调用的形式为:,ch=fgetc(fileP),;,fileP,为文件型指针变量,,ch,为字符变量。其意义是从打开的文件,fileP,中读取一个字符并送入,ch,中。读字符时遇到文件结束符,函数返回一个文件结束标志,EOF,(,-1,)。,EOF,是在,stdio.h,文件中定义的符号常量,值为,-1,。,(2),写字符函数,fputc,fputc,函数的功能是把一个字符写入指定的文件中。,调用的形式为:,fputc(ch, fileP),;,ch,是要输出的字符,它可以是字符常量或者是字符变量。,fileP,为文件型指针变量。其意义是把字符,ch,写入到,fileP,所指向的文件中。如果写入成功则返回写入的字符, 如果写入失败则返回一个,EOF,(,-1,)。,(3),读字符串函数,fgets,fgets,函数的功能是从指定的文件中读一个字符串到字符数组中。,函数调用的形式为:,fgets(str,n, fileP),;,n,是一个正整数,为要求得到的字符数,但从文件中读出的字符串只有,n-1,个字符,然后在最后一个字符后加上串结束标志,0,,,因此得到的字符串共有,n,个字符。把得到的字符串放在字符数组,str,里面。,fileP,为文件型指针变量。如果在读完,n-1,个字符之前遇到换行符或,EOF,,读操作即结束。函数返回值为,str,的首地址。,(4),写字符串函数,fputs,fputs,函数的功能是向指定的文件写入一个字符串。,函数的调用形式为:,fputs(s, fileP),s,可以是字符串常量,也可以是字符数组名,或字符型指针变量。,fileP,为文件型指针变量。字符串末尾的,0,不输出,若输出成功,函数值返回为,0,,失败则为,EOF,。,7,数据块读写函数,fread,和,fwrite,有时候需要读写一组数据,如一个数组的元素,一个结构变量的值等。这时候可以使用读写数据块函数,用来读写一个数据块。函数调用的一般形式为:,fread(buffer,size,count, fileP);,fwrite(buffer,size,count, fileP);,其中:,buffer,是一个指针,在,fread,函数中,它表示存放输入数据的首地址,在,fwrite,函数中,它表示存放输出数据的首地址。,size,表示要读写的字节数。,count,表示要读写的数据块块数(即,count,个,size,大的数据块)。,fileP,表示文件指针。,8,格式化读写函数,fscanf,和,fprintf,fscanf,函数,,fprintf,函数与前面使用的,scanf,和,printf,函数的功能相似,都是格式化读写函数。 不同之处在于,fscanf,函数和,fprintf,函数的读写对象不是键盘和显示器,而是磁盘文件。函数的调用格式为:,fscanf,(,文件指针,格式字符串,输入表列,),;,fprintf,(,文件指针,格式字符串,输出表列,),;,要注意的是,当在内存和磁盘频繁交换数据的情况下,最好不使用这两个函数,而使用,fread,和,fwrite,函数。,9,文件的定位和测试,(1),文件的定位,上一节介绍的对文件的读写方式都是,顺序读写,,即读写文件只能从头开始,顺序读写各个数据。但在实际问题中常要求只读写文件中某一指定的部分,也就是移动文件指针到需要读写的位置,再进行读写,这种读写称为随机读写,。 实现随机读写的关键是按要求移动文件指针,这称为文件的定位。,rewind,函数,:,调用形式为,rewind(,文件指针,),;,它的功能是把文件指针重新移到文件的开头。此函数没有返回值。,fseek,函数,:fseek,函数用来移动文件指针, 其调用形式为:,fseek(,文件指针,位移量,起始点,),;,其中:“文件指针”指向被移动的文件。 “位移量”是指以“起始点”为基点,向前移动的字节数。要求位移量是,long,型数据,以便在文件的长度大于,64K,时不会出问题。当,用常量表示,位移量时,直接在末尾加后缀“,L”,。“起始点”表示从文件的什么位置开始计算位移量,规定的起始点有三种:文件首,当前位置和文件尾。其表示方法如表,7-2,所示。,表,7-2,文件指针三种起始点,起始点,表示符号,数字表示,文件首,SEEK_SET,0,当前位置,SEEK_CUR,1,文件末尾,SEEK_END,2,fseek,函数一般用于二进制文件,这是因为文本文件要进行转换,在计算位置的时候会出现错误,。,(2),文件检测函数,语言中常用的文件检测函数有以下几个:,文件结束检测函数,feof,(),调用格式:,feof(,文件指针,),;,功能:,判断文件是否处于文件结束位置,如文件结束,则返回值为,1,,否则为,0,。,读写文件出错检测函数,ferror,(),调用格式:,ferror(,文件指针,),;,功能:,检查文件在用各种输入输出函数进行读写时是否出错。 如,ferror,返回值为,0,表示未出错,否则表示有错。,文件出错标志和文件结束标志置,0,函数,clearerr,(),调用格式:,clearerr(,文件指针,);,功能:,用于清除出错标志和文件结束标志,使它们为,0,值。,7.2.3,技能训练,【,实验,7.2.1】,编写程序,从键盘上输入一系列字符,写到磁盘文件,file,中,以,#,作为输入的结束标志,然后把文件中的内容在屏幕上输出。,【,指导,】,本实验的功能是执行了两次磁盘文件操作:先用,fputc,函数把输入的字符放在,fileP,指向的文件中,然后把文件中的内容用,fgetc,函数逐个读取,在屏幕上显示。,程序定义了文件指针,fileP,先以写方式打开文本文件,file,,并使,fileP,指向该文件。如打开文件出错,给出提示并退出程序。输入字符到文件中的循环是以输入“,#”,作为循环结束的标志;,然后再以读方式打开文本文件,file,,循环读取文本文件的每一个字符,并显示在屏幕上,并以,EOF,作为循环的结束标志,也就是判断是否读到文件的结尾。每次文件操作结束后,都要用,fclose,函数关闭文件。,/*EX7_9.C*/,# include,#include ,#include ,void main( )( ),FILE *fileP;,char charC;,if(fileP =fopen(file,w)=NULL),printf(,不能打开文件,n);,exit(0);,printf(“,请输入字符,:n”);,while (charC =getchar( )!=#),fputc(charC, fileP);,fclose(fileP);,if (fileP =fopen(file,r)=NULL),printf(,不能打开文件,n);,exit(0);,printf(,文件内容为,:n);,charC =fgetc(fileP);,while(charC!=EOF),putchar(charC);,charC =fgetc(fileP);,fclose(fileP);,该程序首先打开当前目录中文件名为,file,的文件,然后从键盘上输入字符并存储到文件,file,中,输入完成后关闭文件,file,,最后再次打开文件,file,,并输出文件,file,中的字符。图,7-13,为该程序的一次运行实例,.,图,7-13,程序,EX7_9,运行结果,【,实验,7.2.2】,有两个磁盘文件,a1.txt,和,a2.txt,,各存放若干行字母,今要求把这两个文件中的信息按行交叉合并(即先是,a1.txt,的的第一行,接着是,a2.txt,中的第一行,然后是,a1.txt,的第二行,跟着是,a2.txt,的第二行,,),输出到一个新文件,a3.txt,中去。,【,指导,】,以读方式打开磁盘文件,a1.txt,和,a2.txt,,然后依次读取,a1.txt,和,a2.txt,的一行,交叉存入新文件,a3.txt,,因此可以通过,3,个循环语句实现。具体做法为:通过,fgets,函数分别获得文件,a1.txt,和,a2.txt,中的每一行字符,分别赋值给字符数组,str1,和,str2,,然后将字符数组,str1,和,str2,中的内容依次写入文件,a3.txt,。假如其中某个文件读取完成,则将另一文件剩余行写人文件,a3.txt,后部。,/*EX7_10.C*/,#include,#include ,#include ,void main( )( ),FILE *fp1,*fp2,*fp3;,char str1255,str2255;,if(fp1=fopen(a1.txt,r)=NULL),printf(file a1 cannot be openedn);exit(0);,if(fp2=fopen(a2.txt,r)=NULL),printf(file a2 cannot be openedn);exit(0);,if(fp3=fopen(a3.txt,w+)=NULL),printf(file a3 cannot be openedn);exit(0);,while(fgets(str1,255,fp1)!=NULL&fgets(str2,255,fp2)!=NULL),fputs(str1,fp3);,fputs(str2,fp3);,while(fgets(str1,255,fp1)!=NULL),fputs(str1,fp3);,while(fgets(str2,255,fp2)!=NULL),fputs(str2,fp3);,/*char charC; /,以下注释掉的代码,为查看文件,a1,、,a2,、,a3,的内容,以检查运行效果,rewind(fp1);,rewind(fp2);,rewind(fp3);,printf(a1,文件内容为,:n);,charC =fgetc(fp1);,while(charC!=EOF),putchar(charC);,charC =fgetc(fp1);,printf(a2,文件内容为,:n);,charC =fgetc(fp2);,while(charC!=EOF),putchar(charC);,charC =fgetc(fp2);,printf(a3,文件内容为,:n);,charC =fgetc(fp3);,while(charC!=EOF),putchar(charC);,charC =fgetc(fp3);,*/,fclose(fp1); fclose(fp2); fclose(fp3);,去掉上述代码中的注释符号,该程序的一次运行实例如下图,7-14,。,图,7-14,程序,EX7_10,运行结果,【,实验,7.2.3】,从键盘输入两个学生数据,写入一个文件中,再读出这两个学生的数据显示在屏幕上。,【,指导,】,该实验需要一个数据结构来存储学生信息,因此需要定义一个学生结构体。并将输入后的学生信息写入文件,再读出该文件的内容,显示在屏幕上。每个学生的信息包含一组数据,因此使用数据块读写函数,fread,和,fwrite,来完成对文件的读写,程序如下。,/*EX7_11.C*/,# include,#include ,#include ,struct stu,char name10;,int num;,int age;,char addr20;,stu_12,stu_22,*p,*q;,main( )( ),FILE *fp;,p=stu_1;,q=stu_2;,int i;,if(fp=fopen(stu_list,wb+)=NULL),printf(Cannot open file strike any key exit!);,exit(0);,printf(input datan);,for(i=0;iname,p=stu_1;,fwrite(p,sizeof(struct stu),2,fp);,rewind(fp);,fread(q,sizeof(struct stu),2,fp);,printf(NAMEtNUMBERt AGEt ADDRn);,for(i=0;iname,q-num,q-age,q-addr);,fclose(fp);,本例程序定义了一个结构,stu,说明了两个结构数组,stu_1,和,stu_2,以及两个结构指针变量,p,和,q,。,p,指向,stu_1,q,指向,stu_2,。程序以读写方式打开二进制文件“,stu_list”,,输入二个学生数据之后,写入该文件中,然后用,rewind,函数把文件内部位置指针重新移到文件首,读出两个学生数据后,在屏幕上显示,。,图,7-15,程序,EX7_11,运行结果,【,实验,7.2.4】,用,fscanf,和,fprintf,函数完成实验,7.2.3,的问题。,【,指导,】,与函数,fread,和,fwrite,相比,,fscanf,和,fprintf,函数每次只能读写一个结构数组元素,因此采用了循环语句来,读写全部数组元素,程序,如下。,/*EX7_12.C*/,# include,#include ,#include ,struct stu,char name10;,int num;,int age;,char addr20;,stu_12,stu_22,*p,*q;,main( )( ),FILE *fp;,p=stu_1;,q=stu_2;,int i;,if(fp=fopen(stu_list,wb+)=NULL),printf(Cannot open file strike any key exit!);,exit(0);,printf(input datan);,for(i=0;iname,p=stu_1;,for(i=0;iname,p-num,p-age,p-addr);,rewind(fp);,for(i=0;iname,printf(NAMEtNUMBERt AGEt ADDRn);,q= stu_2;,for(i=0;iname,q-num,q-age,q-addr);,fclose(fp);,本程序中,fscanf,和,fprintf,函数每次只能读写一个结构数组元素,因此采用了循环语句来读写全部数组元素。还要注意指针变量,p,q,由于循环改变了它们的值,因此在程序中分别对它们重新赋予了数组的首地址。,图,7-16,程序,EX7_12,运行结果,【,实验,7.2.5】,在学生文件,stu_ list,中读出第二个学生的数据。,【,指导,】,前两个实验对文件的读取都是顺序读出,而该实验只读写文件,stu_ list,中某一指定部分的内容。因此用函数,fseek,先将文件内部的位置,指针移动到需要读写的位置,然后再使用函数,fread,读取指定数据。,/*EX7_13.C*/,#include,#include ,#include ,struct stu,char name10;,int num;,int age;,char addr20;,student,*p;,main( )( ),FILE *fp;,int i=1;,p=,if(fp=fopen(stu_list,rb)=NULL),printf(Cannot open file strike any key exit!);,getch( )( );,exit(1);,rewind(fp);,fseek(fp,i*sizeof(struct stu),0);,fread(p,sizeof(struct stu),1,fp);,printf(nametnumbert age addrn);,printf(%st%5d %7d %sn,p-name,p-num,p-age,p-addr);,该程序的一次运行实例如下图,7-17,。,图,7-17,程序,EX7_13,运行结果,7.2.4,拓展与练习,【,练习,】,利用本章的学习内容实现简单的文件加密。,【,指导,】,每次对原文中的一个字符进行加密,再将加密后的这个字符存储到密文,直到将原文中的每个字符做如上处理后,才结束该加密程序。具体做法为:首先通过键盘输入加密密钥,然后读取原文中的每一个字符,与加密密钥进行异或操作,得到该字符的加密密文,然后将该加密密文存入密文中,直到处理完原文中的每个字符,程序如下。,/*EX7_14.C*/,#include ,#include ,#include ,void main( ),FILE *originalfile,*Cipherfile;,char charC;,int intCipher;,int intN;,printf(,请输入密钥,intN,的值:,);,scanf(%d,if (originalfile =fopen(test,rb)=NULL),printf(,不能打开文件,n);,exit(0);,if (Cipherfile =fopen(Ciphertext,wb)=NULL),printf(,不能打开文件,n);,exit(0);,charC =fgetc(originalfile);,while(charC!=EOF),intCipher=(int)(charC)intN;,fputc(char)(intCipher), Cipherfile);,charC =fgetc(originalfile);,fclose(Cipherfile);,fclose(originalfile);,该程序实现了较简单对称加密的一种算法。在语言中,一个,int,型数据占,2,个字节,因此该程序可以有,65536,个加密密钥。现假设输入加密密钥,1234,,其执行效果如图,7-18,至图,7-20,。,图,7-18,程,序,EX7_14,运行结果,图,7-19,程,序,EX7_14,加密前原文内容,图,7-20,程,序,EX7_14,加密后密文内容,此外,该实例只是为了说明通过,C,语言中的位运算与文件处理解决问题的方法。在实际中,加密算法要复杂得多,对它的处理相对也比较复杂。例如该程序可以使用不同的加密密钥进行多次加密,或者配合使用其他位运算,对原文实现非对称加密等方法,都可以增加密文的破解难度,以达到文件传输过程中的安全性。解密为加密的逆过程,因此解密程序可以作为课后练习,由自己编程运行。,7.2.5,编程规范与常见错误,1.,使用文件时忘记打开文件;,2.,用只读方式打开,却企图向该文件输出数据;,3.,文件使用完,忘记关闭文件等错误。,因此文件打开前,应做到对文件的状态进行检查。,7.2.6,贯通案例之八,1.,问题描述:,在贯通案例七的基础上实现学生成绩管理系统的加载文件,保存文件两个功能。,2.,编写程序,/*,函数功能:保存学生记录文件,函数参数:结构体指针,head,,指向存储学生信息的结构体数组的首地址,整型变量,n,,表示学生人数,整型变量,m,,表示考试科目,函数返回值:无,*,/,/*EX7_15.C*/,void SaveScoreFile(STU *head, const int n, const int m ),FILE *fp ;,int i ;,STU *p = head;,if(fp=fopen(record,wb)=NULL),printf(can not open filen);,exit(1);,printf(nSaving filen);,fwrite( ,fwrite( ,for (i=0; in; i+),fwrite( head+i , sizeof(struct student), 1, fp ) ;,fclose(fp) ;,return;,/*,函数功能:加载学生记录文件,函数参数:结构体指针,head,,指向存储学生信息的结构体数组的首地址,整型变量,n,,表示学生人数,整型变量,m,,表示考试科目,函数返回值:结构体指针,head,,指向存储学生信息的结构体数组的首地址,*,/,/*EX7_16.C*/,STU *LoadScoreFile(STU *head, int *n, int *m ),FILE *fp ;,int i ;,if ( ( fp=fopen(record, rb) = NULL ),printf (open failuren) ;,exit(-1) ;,fread( n, sizeof(int), 1, fp) ; /*,先读出学生数 *,/,fread( m, sizeof(int), 1, fp) ; /*,先读出课程数 *,/,printf(M:%d N:%dn, *m, *n ) ;,for( i=0; i= *n; i+),fread( head + i , sizeof( struct student), 1, fp ) ;,fclose ( fp) ;,return head ;,3.,运行结果,图,7-21,保存文件,图,7-22,加载,显示学生成绩,自测题,1.,以下程序的输出结果是,main( )( ), char x=040;,printf(%on,x1);,100B) 80 C) 64 D) 32,2.,有以下程序,main( )( ),unsigned char a,b,c;,a=0x3; b=a|0x8; c=b1;,printf(%d%dn,b,c);,程序运行后的输出结果是,_,。,A) -1112 B) -6-13 C) 1224 D) 1122,3.,下列关于,C,语言数据文件的叙述中正确的是,A,)文件由,ASCII,码字符序列组成,,C,语言只能读写文本文件,B,)文件由二进制数据序列组成,,C,语言只能读写二进制文件,C,)文件由记录序列组成,可按数据的存放形式分为二进制文件和文本文件,D,)文件由数据流形式组成,可按数据的存放形式分为二进制文件和文本文件,4.,下面的程序执行后,文件,test.txt,中的内容是,#include ,void fun(char *fname ,char *st), FILE *myf; int i;,myf=fopen(fname,w );,for(i=0;istrlen(st); i+)fputc(sti,myf);,fclose(myf);,main( )( ),fun(test,new world); fun(test,hello,);,A,),hello,,,B,),new worldhello,,,C,),new world D,),hello, rld,5,下面的程序用于统计文件中字符的个数,请填空。,# include ,main( )( ),FILE *fp;,long num=0;,if(fp=fopen(file.dat,r)=NULL),printf(Open file error!n);,_;,while_,fgetc(fp);,num+;,printf(number=%dn,number);,_;,6,下面的程序是从一个二进制文件中读入结构体数据,并把结构体数据显示在终端屏幕上,请填空。,# include ,struct data,int num;,float total;,;,main( )( ),FILE *fp;,fp=fopen(file.dat,r);,print(fp);,_;,print(_),struct data rb;,while(!feof(fp),fread(,printf(%d,%f,_,_);,Visual C+,结束,
展开阅读全文