1.修改程序清单13.1中的程序,要求提示用户输入文件名,并读取用户输入的信息,不使用命令行参数。
#include#include #define SIZE 40 int main(void) { char filename[SIZE]; int ch; FILE *fp; unsigned long count=0; puts("Enter the filename: "); if(scanf("%s",filename)!=1) { puts("Filename intput error."); exit(EXIT_FAILURE); } if((fp=fopen(filename,"r"))==NULL) { printf("Can't open file:%s.n",filename); exit(EXIT_FAILURE); } while((ch=getc(fp))!=EOF) { putchar(ch); // putc(ch,stdout); count++; } putchar('n'); fclose(fp); printf("File %s has %lu characters.n",filename,count); return 0; }
2.编写一个文件拷贝程序,该程序通过命令行获取原始文件名和拷贝文件名。尽量使用标准I/O 和二进制模式。
#include#include int main(int argc,char * argv[]) { int ch; FILE * fp1; FILE * fp2; if(argc!=3) { printf("%s:Usage filename.n",argv[1]); exit(EXIT_FAILURE); } if((fp1=fopen(argv[1],"rb"))==NULL) { printf("Couldn't open file:%sn",argv[1]); exit(EXIT_FAILURE); } if((fp2=fopen(argv[2],"wb"))==NULL) { printf("Couldn't open file:%sn",argv[2]); exit(EXIT_FAILURE); } printf("Originally file:%sn",argv[1]); while((ch=getc(fp1))!=EOF) putc(ch,stdout); putchar('n'); fseek(fp1,0L,SEEK_SET); // 定位到文件开头 while((ch=getc(fp1))!=EOF) // 把第一个文件的内容复制到第二个文件 putc(ch,fp2); fclose(fp1); fclose(fp2); if((fp2=fopen(argv[2],"rb"))==NULL) { printf("couldn't open file:%sn",argv[2]); exit(EXIT_FAILURE); } printf("Now,file:%sn",argv[2]); // 显示第二个文件的内容 while((ch=getc(fp2))!=EOF) putc(ch,stdout); fclose(fp2); return 0; }
3.编写一个文件拷贝程序,提示用户输入文本文件名,并以该文件名作为原始文件名和输出文件名。该程序要使用ctype.h中的toupper()函数,在写入到输出文件时把所有文本转换成大写,使用标准I/O和文本模式。
#include#include #include int main(void) { char filename[40]; char ch; FILE * fp; printf("Enter the filename:n"); if(scanf("%s",filename)!=1) { printf("Filename input error.n"); exit(EXIT_FAILURE); } if((fp=fopen(filename,"r+"))==NULL) { printf("Couldn't open file:%sn",filename); exit(EXIT_FAILURE); } getchar(); printf("Enter the characters:n"); while((ch=getchar())!=EOF) 从标准I/0中写入,并转换为大写后,写入文件 { ch=toupper(ch); putc(ch,fp); } fseek(fp,0,SEEK_SET); printf("Now,file %s:n",filename); while((ch=getc(fp))!=EOF) //显示文件内容 putc(ch,stdout); fclose(fp); return 0; }
4.编写一个程序,按顺序在屏幕上显示命令行中列出的所有文件。使用argc控制循环。
#include#include int main(int argc,char * argv[]) { char ch; FILE * fp; int i; for(i=0;i
5.修改程序清单13.5中的程序,用命令行界面代替交互式界面。
#include#include #include #define BUFFSIZE 4096 void append(FILE * fs,FILE * fa); int main(int argc, char * argv[]) { char ch; int i; FILE * fs,* fa; if(argc<3) { printf("Need at least 2 file.n"); exit(EXIT_FAILURE); } if((fa=fopen(argv[1],"a+"))==NULL) // 以更新模式打开文件,在末尾添加 { fprintf(stderr,"error in open file %sn",argv[1]); exit(EXIT_FAILURE); } if(setvbuf(fa,NULL,_IOFBF,BUFFSIZE)!=0) // 为写设置缓冲区 { fprintf(stderr,"error in set buffer for input.n"); exit(EXIT_FAILURE); } for(i=0;i0) fwrite(temp,sizeof(char),bytes,fa); }
6.使用命令行参数的程序依赖于用户的内存如何正确地使用它们。重写程序清单13.2中的程序, 不使用命令行参数,而是提示用户输入所需信息。
#include#include #include #define LEN 40 char * s_gets(char * st,int n); int main(void) { FILE * in,* out; char file_src[LEN]; char file_app[LEN]; char ch; int count=0; printf("Enter the source file:n"); while(s_gets(file_src,LEN)==NULL||file_src[0]==' ') { fprintf(stderr,"File name input error.n"); printf("Try again:n"); } if((in=fopen(file_src,"r"))==NULL) { fprintf(stderr,"Can't open file:%s.n",file_src); exit(EXIT_FAILURE); } strncpy(file_app,file_src,LEN-5); file_app[LEN-5]=' '; strcat(file_app,".red"); if((out=fopen(file_app,"w"))==NULL) { fprintf(stderr,"Can't open file:%s.n",file_app); exit(EXIT_FAILURE); } while((ch=getc(in))!=EOF) // 压缩文件到输出 { if(count++%3==0) putc(ch,out); } if(fclose(in)!=0||fclose(out)!=0) fprintf(stderr,"Error in closing file.n"); return 0; } char * s_gets(char * st,int n) { char * ret_val; int i=0; ret_val=fgets(st,n,stdin); while(st[i]!='/0'&&st[i]!='n') i++; if(st[i]=='n') st[i]=' '; else while(getchar()!='n') continue; return ret_val; }
7.编写一个程序打开两个文件。可以使用命令行参数或提示用户输入文件名。
a.该程序以这样的顺序打印:打印第1个文件的第1行,第2个文件的第1行,第1个文件的第2 行,第2个文件的第2行,以此类推,打印到行数较多文件的最后一行。
b.修改该程序,把行号相同的行打印成 一行。
#include#include void fun_a(FILE * fp1,FILE * fp2); // 按a的方式打印 void fun_b(FILE * fp1,FILE * fp2); // 按b的方式打印 int main(int argc,char * argv[]) { FILE * fp1,* fp2; if(argc<3) { fprintf(stderr,"Hasn't enough arc.n"); exit(EXIT_FAILURE); } if((fp1=fopen(argv[1],"r"))==NULL) { fprintf(stderr,"Can't open file:%sn",argv[1]); exit(EXIT_FAILURE); } if((fp2=fopen(argv[2],"r"))==NULL) { fprintf(stderr,"Can't open file:%sn",argv[2]); exit(EXIT_FAILURE); } fun_a(fp1,fp2); printf("n"); rewind(fp1); rewind(fp2); fun_b(fp1,fp2); if(fclose(fp1)!=0||fclose(fp2)!=0) fprintf(stderr,"Error in closing file.n"); return 0; } void fun_a(FILE * fp1,FILE * fp2) { char ch1,ch2; do { while((ch1=getc(fp1))!='n'&&ch1!=EOF) putc(ch1,stdout); putchar('n'); while((ch2=getc(fp2))!='n'&&ch2!=EOF) putc(ch2,stdout); putchar('n'); }while(ch1!=EOF||ch2!=EOF); } void fun_b(FILE * fp1,FILE * fp2) { char ch1,ch2; do { while((ch1=getc(fp1))!='n'&&ch1!=EOF) putc(ch1,stdout); while((ch2=getc(fp2))!='n'&&ch2!=EOF) putc(ch2,stdout); putchar('n'); }while(ch1!=EOF||ch2!=EOF); }
8.编写一个程序,以一个字符和任意文件名作为命令行参数。如果字符后面没有参数,该程序读取标准输入;否则,程序依次打开每个文件并报告每个文件中该字符出现的次数。文件名和字符 本身也要一同报告。程序应包含错误检查,以确定参数数量是否正确和是否能打开文件。如果无法 打开文件,程序应报告这一情况,然后继续处理下一个文件。
#include#include #include #define MAXSIZE 81 int main(int argc,char * argv[]) { FILE * fp; char temp[MAXSIZE]; int i=0,count=0; char ch; if(argc<2) { fprintf(stderr,"Usage filename:%sn",argv[0]); exit(EXIT_FAILURE); } if(argc==2) //标准输入 { if(fgets(temp,MAXSIZE,stdin)!=NULL) { while(temp[i]!=' ') { if(temp[i]==*argv[1]) count++; i++; } printf("Character %c appeared %d times in the input stream.n",*argv[1],count); } else printf("Input NULL.n"); } count=0; if(argc>2) // .txt文件输入 { for(i=2;i
9.修改程序清单13.3中的程序,从1开始,根据加入列表的顺序为每个单词编号。当程序下次运行时,确保新的单词编号接着上次的编号开始。
#include#include #include #define SIZE 40 int main(void) { FILE * fp; char words[SIZE]; int i=0; // i为单词编号 if((fp=fopen("file.txt","a+"))==NULL) { fprintf(stderr,"Can't open file.txt.n"); exit(EXIT_FAILURE); } puts("Enter the words,press "); puts("# at the beginning of a line to terminate:"); while(fscanf(fp,"%s",words)==1) // 统计原有的单词数 i++; while(fscanf(stdin,"%40s",words)==1&&words[0]!='#') // 遇到空白字符,输入单词结束 fprintf(fp,"%d%sn",++i,words); // 读入新单词,并为其编号 rewind(fp); puts("File content:"); while(fscanf(fp,"%s",words)==1) puts(words); while(fclose(fp)!=0) fprintf(stderr,"Error in closing file.n"); return 0; }
10.编写一个程序打开一个文本文件,通过交互方式获得文件名。通过一个循环,提示用户输入 一个文件位置。然后该程序打印从该位置开始到下一个换行符之前的内容。用户输入负数或非数值 字符可以结束输入循环。
#include#include #include #define MAXSIZE 81 int main(void) { char temp[MAXSIZE]; FILE * fp; long pos; if((fp=fopen("file.txt","r"))==NULL) { fprintf(stderr,"Can't open file.txt.n"); exit(EXIT_FAILURE); } puts("Enter the position:"); while(scanf("%ld",&pos)==1&&pos>0) { fseek(fp,pos-1,SEEK_SET); // 定位文件位置 if(fgets(temp,MAXSIZE,fp)!=NULL) // 输出该位置到下一个换行符的内容 fputs(temp,stdout); rewind(fp); } if(fclose(fp)!=0) fprintf(stderr,"Error in closing file.n"); return 0; }
11.编写一个程序,接受两个命令行参数。第1个参数是一个字符串,第2个参数是一个文件名。 然后该程序查找该文件,打印文件中包含该字符串的所有行。因为该任务是面向行而不是面向字符 的,所以要使用fgets()而不是getc()。使用标准C库函数strstr()(11. 5. 7 节简要介绍过) 在每一行中查找指定字符串。假设文件中的所有行都不超过255个字符。
#include#include #include #define MAXSIZE 255 int main(int argc,char * argv[]) { char temp[MAXSIZE]; FILE * fp; int count=0; if(argc<3) { fprintf(stderr,"Usage filename:%sn",argv[2]); exit(EXIT_FAILURE); } if((fp=fopen(argv[2],"r"))==NULL) { fprintf(stderr,"Can't open file:%sn",argv[2]); exit(EXIT_FAILURE); } while(fgets(temp,MAXSIZE,fp)!=NULL) // 每一行输入到临时数组中,并与字符串做比较 { if(strstr(temp,argv[1])!=0) { fputs(temp,stdout); count++; } } if(count==0) printf("No line include string:%sn",argv[1]); if(fclose(fp)!=0) printf("Error in closing file:%sn",argv[2]); return 0; }
12.创建一个文本文件,内含20行,每行30个整数。这些整数都在0~9 之间,用空格分开。该文件是用数字表示一张图片,0~9表示逐渐增加的灰度。编写一个程序,把文件中的内容读入一个 20×30的int数组中。一种把这些数字转换为图片的粗略方法是:该程序使用数组中的值初始化一个 20×31的字符数组,用值0对应空格字符,1对应点字符,以此类推。数字越大表示字符所占的空间 越大。例如,用#表示9。每行的最后一个字符(第31个) 是空字符,这样该数组包含了20个字符串。最后,程序显示最终的图片(即,打印所有的字符串),并将结果储存在文本文件中。例如, 下面是开始的数据:
0 0 9 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 2 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 9 0 0 0 0 0 0 0 5 8 9 9 8 5 5 2 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 5 8 1 9 8 5 4 5 2 0 0 0 0 0 0 0 0 0
0 0 0 0 9 0 0 0 0 0 0 0 5 8 9 9 8 5 0 4 5 2 0 0 0 0 0 0 0 0
0 0 9 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 4 5 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 1 8 5 0 0 0 4 5 2 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 4 5 2 0 0 0 0 0
5 5 5 5 5 5 5 5 5 5 5 5 5 8 9 9 8 5 5 5 5 5 5 5 5 5 5 5 5 5
8 8 8 8 8 8 8 8 8 8 8 8 5 8 9 9 8 5 8 8 8 8 8 8 8 8 8 8 8 8
9 9 9 9 0 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 3 9 9 9 9 9 9 9
8 8 8 8 8 8 8 8 8 8 8 8 5 8 9 9 8 5 8 8 8 8 8 8 8 8 8 8 8 8
5 5 5 5 5 5 5 5 5 5 5 5 5 8 9 9 8 5 5 5 5 5 5 5 5 5 5 5 5 5
0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 6 6 0 0 0 0 0 0
0 0 0 0 2 2 0 0 0 0 0 0 5 8 9 9 8 5 0 0 5 6 0 0 6 5 0 0 0 0
0 0 0 0 3 3 0 0 0 0 0 0 5 8 9 9 8 5 0 5 6 1 1 1 1 6 5 0 0 0
0 0 0 0 4 4 0 0 0 0 0 0 5 8 9 9 8 5 0 0 5 6 0 0 6 5 0 0 0 0
0 0 0 0 5 5 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 6 6 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 5 8 9 9 8 5 0 0 0 0 0 0 0 0 0 0 0 0
根据以上描述选择特定的输出字符,最终输出如下:
#include#include #include #include int main(void) { FILE * fp1,* fp2; int arr1[20][30]; // 保存数字的数组 int arr2[20][31]; // 保存字符的数组 int i,j; char ch; if((fp1=fopen("1.txt","r"))==NULL) { fprintf(stderr,"Can't open file:1.txtn"); exit(EXIT_FAILURE); } for(i=0;i<20;i++) // 从文件读入数字到数组 for(j=0;j<60;j++) { if((ch=getc(fp1))!=EOF&&isdigit(ch)) arr1[i][j/2]=(int)ch-48; } if(fclose(fp1)!=0) fprintf(stderr,"Error in closing file 1.txtn"); for(i=0;i<20;i++) // 把数字转换为字符,并存入到arr2数组中 for(j=0;j<30;j++) { switch(arr1[i][j]) { case 0:arr2[i][j]=' '; break; case 1:arr2[i][j]='.'; break; case 2:arr2[i][j]='''; break; case 3:arr2[i][j]=':'; break; case 4:arr2[i][j]='~'; break; case 5:arr2[i][j]='*'; break; case 6:arr2[i][j]='='; break; case 7:arr2[i][j]='^'; break; case 8:arr2[i][j]='%'; break; case 9:arr2[i][j]='#'; break; default: break; } } for(i=0;i<20;i++) arr2[i][30]=' '; if((fp2=fopen("2.txt","a+"))==NULL) { fprintf(stderr,"Can't open file:2.txtn"); exit(EXIT_FAILURE); } for(i=0;i<20;i++) // 把arr2数组的字符,读入到文件中 { for(j=0;j<31;j++) putc(arr2[i][j],fp2); putc('n',fp2); } rewind(fp2); puts("Content output:"); while((ch=getc(fp2))!=EOF) //输出文件的内容 putc(ch,stdout); if(fclose(fp2)!=0) fprintf(stderr,"Error in closing file 2.txtn"); return 0; }
13.用变长数组(VLA)代替标准数组,完成编程练习12。
#include#include #include #include int main(void) { FILE * fp1,* fp2; int a=20; int b=30; int arr1[a][b]; // 声明变长数组 int i,j; char ch; if((fp1=fopen("1.txt","r"))==NULL) { fprintf(stderr,"Can't open file:1.txtn"); exit(EXIT_FAILURE); } if((fp2=fopen("2.txt","a+"))==NULL) { fprintf(stderr,"Can't open file:2.txtn"); exit(EXIT_FAILURE); } for(i=0;i
14.数字图像,尤其是从宇宙飞船发回的数字图像,可能会包含一些失真。为编程练习12添加消除失真的函数。该函数把每个值与它上下左右相邻的值作比较,如果该值与其周围相邻值的差都 大于1,则用所有相邻值的平均值(四舍五入为整数)代替该值。注意,与边界上的点相邻的点少于4个,所以做特殊处理。
#include#include #include #include void func(int a,int b,int arr[a][b]); // 消除失真的函数 int main(void) { FILE * fp1,* fp2; int a=20; int b=30; int arr1[a][b]; int i,j; char ch; if((fp1=fopen("1.txt","r"))==NULL) { fprintf(stderr,"Can't open file:1.txtn"); exit(EXIT_FAILURE); } if((fp2=fopen("2.txt","a+"))==NULL) { fprintf(stderr,"Can't open file:2.txtn"); exit(EXIT_FAILURE); } for(i=0;i1&& // 与上下左右做比较 abs(arr[i][j]-arr[i+1][j]>1)&& abs(arr[i][j]-arr[i][j-1]>1)&& abs(arr[i][j]-arr[i][j+1]>1)) { arr[i][j]=(arr[i-1][j]+arr[i+1][j]+arr[i][j-1]+arr[i][j+1])/4; temp=((arr[i-1][j]+arr[i+1][j]+arr[i][j-1]+arr[i][j+1])/4.0-arr[i][j])>=0.5?1:0; //四舍五入 arr[i][j]+=temp; } } }
因笔者水平有限,边界未作特殊处理。请见谅。
史蒂芬·普拉达(Stephen Prata). C Primer Plus(第6版)中文版(异步图书) (Kindle位置17210). 人民邮电出版社. Kindle 版本.



