1.修改程序清单13.1中的程序,使之不采用命令行参数,而是请求用户输入文件名并读入用户的响应。
(程序清单13.1示范了如何使用标准I/O读取文件和统计文件中的字符个数)
#include<stdio.h>
#include<stdlib.h> //ANSIC 的exit()原型
int main(void)
{
int ch;
FILE *fp;
long count = 0;
char name[41];
printf("Input the file's name: ");
scanf("%s",name);
if((fp=fopen(name,"r"))==NULL)
{
printf ("Can't open %s\n", name);
exit(1);
}
while((ch=getc(fp))!=EOF)
{
putc(ch,stdout);
count++;
}
fclose(fp);
printf("\nFile %s has %ld characters\n",name,count);
return 0;
}
2、编写一个文件复制程序。程序需要从命令行获得源文件名和目的文件名。尽可能使用标准I/O和二进制模式。
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
int ch;
FILE *source,*destination;
if((source=fopen(argv[1],"rb"))==NULL)
{
printf ("Can't open %s\n", argv[1]);
exit(1);
}
if((destination=fopen(argv[2],"wb"))==NULL)
{
printf ("Can't open %s\n", argv[2]);
exit(1);
}
while((ch=getc(source))!=EOF)
putc(ch,destination);
fclose(source);
fclose(destination);
printf("copy finished\n");
return 0;
}
3.编写一个文件复制程序,提示用户输名入源文件名和输出文件。在向输出文件写入时,程序应当使用ctype.h中定义的toupper()函数将所有的文本转换成大写。使用标准I/O和文本模式。
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(void)
{
int ch;
FILE *source,*destination;
char source_name[41],destination_name[41];
printf("Input the source file's name:");
if((source=fopen(gets(source_name),"r"))==NULL)
{
printf("Can't open %s\n", source_name);
exit(1);
}
printf("Input the destination file's name:");
if((destination=fopen(gets(destination_name),"w"))==NULL)
{
printf("Can't open %s\n", destination_name);
exit(1);
}
while((ch=getc(source))!=EOF)
putc(toupper(ch),destination);
fclose(source);
fclose(destination);
printf("Copy finished!\n");
return 0;
}
4、编写一段程序,依次在屏幕上显示命令行中列出的全部文件。使用argc控制循环。
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
int i,n=argc;
char str[100];
FILE *fp;
for(i=1;i<4;i++)
{
printf("\nFILE %d -- %s:\n",i,argv[i]);
if((fp=fopen(argv[i],"r"))==NULL)
{
printf("Can't open %s\n",argv[i]);
exit(1);
}
while(fscanf(fp,"%s",str)!=EOF)
fprintf(stdout,"%s",str);
fclose(fp);
}
return 0;
}
5.修改程序清单13.6中的程序,使用命令行参数(而不是交互式界面)获得文件名。
(把多个文件的内容追加到一个文件)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFSIZE 1024
#define SLEN 81
void append(FILE *source, FILE *dest);
int main(int argc,char *argv[])
{
FILE *fa,*fs; //fa for append file, fs for source file
int file=0;i; // number of files appended
if((fa=fopen(argv[1],"a"))==NULL)
{
fprintf(stderr,"Can't open %s\n", argv[1]);
exit(2);
}
if(setvbuf(fa,NULL,_IOFBF,BUFSIZE)!=0)
{
fputs("Can't create output buffer\n",stderr);
exit(3);
}
for(i=2;i<argc;i++)
{
if(strcmp(argv[i],argv[1])==0)
fputs("Can't append file to itself\n",stderr);
else if ((fs=fopen(argv[i],"r"))==NULL)
fprintf(stderr,"Can't open file %s\n",argv[i]);
else
{
if(setvbuf(fs,NULL,_IOFBF,BUFSIZE)!=0)
{
fputs("Can't create input buffer\n",stderr);
coutinue;
}
append(fs,fa);
if(ferror(fs)!=0)
fprintf(stderr,"Error in reading file %s.\n",argv[i]);
if(ferror(fa)!=0)
fprintf(stderr,"Error in writing file %s.\n",argv[1]);
fclose(fs);
file++;
printf("File %s appended.\n",argv[i]);
}
printf("Done.%d files appended.\n",files);
fclose(fa);
return 0;
}
void append(FILE *source,File *dest)
{
size_t bytes;
static char temp[BUFSIZE]; //allocate once
while((bytes=fread(temp,sizeof(char),BUFSIZE,source))>0)
fwrite(temp,sizeof(char),bytes,dest);
}
6.使用命令行参数的程序要求用户记住正确的使用方法。重写程序清单13.2中的程序,不使用命令行参数,而是提示用户键入所需的信息。
#include<stdio.h>
#include<stdlib.h> //for exit()
#include<string.h> //for strcopy(),strcat()
#define LEN 40
int main(void)
{
FILE *in, *out; //declare two FILE pointers
int ch;
char name[LEN]; //storage for output filename
int count = 0;
//set up input
puts("Enter the name of the file to be reduce");
gets(name);
if((in=fopen(name,"r"))==NULL)
{
fprintf(stderr,"I could't open the file \"%s\"\n",name);
exit(2);
}
//set up output
name[LEN-5]='\0';
strcat(name,".red"); //append.red
if((out=fopen(name,"w"))==NULL)
{
fprintf(stderr,"Can't create output file.\n");
exit(3);
}
//copy date
while((ch=getc(in))!=EOF)
if(count++ % 3 == 0)
putc(ch,out); //print every 3rd char
//clean up
if(fclose(in)!=0 or fclose(out)!=0)
fprintf(stderr,"Error in closing files\n");
return 0;
}
7.编写一个打开两个文件的程序。可以使用命令行参数或者请求用户输入来获得文件名。
a.让程序打印第一个文件的第一行、第二个文件的第一行、第一个文件的第二行、第二个文件的第二行,依此类推,直到打印完行数较多的文件的最后一行。
#include<stdio.h>
#include<stdlib.h>
#define M 100
int main(int argc,char *argv[])
{
FILE *fp1,*fp2;
char str1[M],str2[M];
int E1,E2;
if((fp1=fopen(argv[1],"r"))==NULL)
{
printf("Can't open %s",argv[1]);
exit(1);
}
if((fp2=fopen(argv[2],"r"))==NULL)
{
printf("Can't open %s",argv[2]);
exit(1);
}
while(1)
{
if((E1=fscanf(fp1,"%s",str1))==1) puts(str1);
if((E2=fscanf(fp2,"%s",str2))==1) puts(str2);
if(E1!=1 && E2!=1) break;
}
fclose(fp1);
fclose(fp2);
return 0;
}
b.修改程序,把行号相同的行打印到同一行上。(输出由Puts( )换成printf( ))
#include<stdio.h>
#include<stdlib.h>
#define M 100
int main(int argc,char *argv[])
{
FILE *fp1,*fp2;
char str1[M],str2[M];
int E1,E2;
if((fp1=fopen(argv[1],"r"))==NULL)
{
printf("Can't open %s",argv[1]);
exit(1);
}
if((fp2=fopen(argv[2],"r"))==NULL)
{
printf("Can't open %s",argv[2]);
exit(1);
}
while(1)
{
if((E1=fscanf(fp1,"%s",str1))==1) printf("%s",str1);
if((E2=fscanf(fp2,"%s",str2))==1) printf("%s",str2);
if(E1!=1 && E2!=1) break;
printf("\n");
}
fclose(fp1);
fclose(fp2);
return 0;
}
8.编写一段程序,将一个字符、零个或多个文件名作为命令行参数。如果字符后没有参数跟随,程序读取标准输入文件。否则,程序依次打开每个文件,然后报告每个文件中该字符的出现次数。文件名和字符本身也与计数值一起报告。程序中包括错误检查,以确定参数数目是否正确和是否能打开文件。如果不能打开文件,程序要报告这一情况然后继续处理下一文件。
#include<stdio.h>
#include<stdlib.h>
int count(char ch,FILE *fp);
int main(int argc,char *argv[])
{
int i;
char ch;
FILE *fp;
if(argc<2)
{
printf("no char?\n");
exit(1);
}
ch=argv[1][0];
if(argc==2)
{
printf("Input a article:");
printf("In your input: %c has been appeared %d times.\n",ch,count(ch,stdin));
}
else
for(i=2;i<argc;i++)
{
if((fp=fopen(argv[i],"r"))==NULL)
printf("Can't open %s\n",argv[i]);
else
{
printf("In %s: %c has been appeared %d times.\n",argv[i],ch,count(ch,fp));
fclose(fp);
}
}
return 0;
}
int count(char ch,FILE *fp)
{
int n=0;
char ch2;
while((ch2=getc(fp))!=EOF)
if(ch==ch2) n++;
return n;
}
9.修改程序清单13.3中的程序,从l开始,根据加入列表的顺序为每个单词编号。当再次运行程序时,确保新的单词编号接着前面的编号开始。
#include<stdio.h>
#include<stdlib.h>
#define MAX 40
int main(void)
{
FILE *fp;
char words[MAX];
int count = 0;
if((fp=fopen("wordy","a+"))==NULL)
{
fprintf(stdout,"Can't open \"wordy\" file.\n");
exit(1);
}
rewind(fp);
while(fgets(words,MAX-1,fp)!=NULL) count++;
puts("Enter words to add to the file;press the enter");
puts("key at the beginning of a line to terminate.");
while(gets(words)!=NULL && words[0]!='\0')
fprintf(fp,"%d:%s\n",count++,words);
puts("File counts:");
rewind(fp);
while(fscanf(fp,"%s",words)==1)
puts(words);
if(fclose(fp)!=0)
fprintf(stderr,"Error closing file\n");
return 0;
}
10.编写一个程序,打开一个文本文件,文件名通过交互方式获得。建立一个循环,请求用户输入一个文件位置。然后程序打印文件中从该位置开始到下一换行符之间的部分。用户通过输入非数字字符来终止输入循环。
#include<stdio.h>
#include<stdlib.h>
#define MAX 81
int main(void)
{
char name[30],content[MAX];
int row,column;
FILE *fp;
printf("Input the name of file:");
gets(name);
if((fp=fopen(name,"r"))==NULL)
{
printf("Can't open %s",name);
exit(1);
}
printf("Input the row and column to output:");
while(scanf("%d%d",&row,&column)==2)
{
row--,column--;
fseek(fp,0,SEEK_SET);
while(row--) fgets(content,MAX,fp);
fseek(fp,column,SEEK_CUR);
fgets(content,MAX,fp);
printf(content);
printf("Input the start position to output:");
}
printf("Quit\n");
return 0;
}
11.编写一个程序,接受两个命令行参数。第一个参数为一个字符串;第二个为文件名。程序打印文件中包含该字符串的所有行。因为这一任务是面向行而不是面向字符的,所以要使用fgets()而不是getc()。使用标准C库函数strstr()(在第II章的练习7中简要描述过)在每一行中搜索这一字符串。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 201
int main(int argc,char *argv[])
{
FILE *fp;
char str[MAX];
if((fp=fopen(argv[2],"r"))==NULL)
{
printf("Can't open %s",argv[2]);
exit(1);
}
while(fgets(str,MAX,fp)!=NULL)
if(strstr(str,argv[1])!=NULL)
printf(str);
return 0;
}
12.创建一个包含20行,每行30个整数的文本文件。整数在O到9之间,用空格分开。该文件是一个图片的数字表示,从0到9的值代表逐渐增加的灰度。编写一个程序,将文件的内容读入到一个20*30的int数组中。一种将这种数字表示转化成图片的粗略方法就是让程序使用数组中的数值来初始化一个20*31的字符阵列。0对应空格字符,l对应句号字符,依此类推,较大的值对应占用空间较多的字符。比如,可以使用#代表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<stdio.h>
#include<stdlib.h>
int main(void)
{
FILE *fp;
char name[30],photo[20][31],table[]=" .':~*=&%@";
int num[20][30],row,column,i=0;
printf("Input the name of source file:");
gets(name);
if((fp=fopen(name,"r"))==NULL)
{
printf("Can't open %s",name);
exit(1);
}
for(row=0;row<20;row++)
for(column=0;column<30;column++)
fscanf(fp,"%d",&num[row][column]);
for(row=0;row<20;row++)
{
for(column=0;column<30;column++)
photo[row][column]=table[num[row][column]];
photo[row][column]='\0';
}
for(row=0;row<20;row++)
puts(photo[row]);
printf("Input the name of destination file:");
gets(name);
if((fp=fopen(name,"w"))==NULL)
{
printf("Can't open %s",name);
exit(1);
}
for(row=0;row<20;row++)
fprintf(fp,"%s\n",photo[row]);
return 0;
}
13.数字图像,尤其是从宇宙飞船发回的数字图像可能会包含尖峰脉冲。为第12道编程练习题添加消除尖峰脉冲的函数。该函数应该将每一个值和它上下左右的相邻值比较,如果该值与它周围每个值的差都大于1,就用所有相邻值的平均值(取与其最接近的整数)取代这个值。注意到边界上的点的相邻点少于4个,所以它们需要特殊处理。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char name[30],photo[20][31],table[] = " .':~*=&%@";
int num[20][30],row,column,i=0;
printf("input the name of source file:");
gets(name);
if ( ( fp=fopen(name,"r") ) == NULL )
{
printf("Can't open %s",name);
exit(1);
}
for (row=0; row<20; row++)
for (column=0; column<30; column++)
fscanf(fp,"%d",&num[row][column]);
for (row=0; row<20; row++)
for (column=0; column<30; column++)
{
if(row==0&&column==0) //处理第1行第1个数
{
if( (num[row][column] - num[row][column+1])>1 && (num[row][column] - num[row+1][column])>1 )
num[row][column] = ( num[row][column+1] + num[row+1][column] ) / 2 + 0.5;//加0.5是为了四舍五入
}
else if(row==0&&column==29) //处理第1行最后1个数
{
if( (num[row][column] - num[row][column-1])>1 && (num[row][column] - num[row+1][column])>1 )
num[row][column] = ( num[row][column-1] + num[row+1][column] ) / 2 + 0.5;
}
else if(row==19&&column==0) //处理最后1行第1个数
{
if( (num[row][column] - num[row-1][column])>1 && (num[row][column] - num[row][column+1])>1 )
num[row][column] = ( num[row-1][column] + num[row][column+1] ) / 2 + 0.5;
}
else if(row==19&&column==29) //处理最后1行最后1个数
{
if( (num[row][column] - num[row-1][column])>1 && (num[row][column] - num[row][column-1])>1 )
num[row][column] = ( num[row-1][column] + num[row][column-1] ) / 2 + 0.5;
}
else if(row==0) //处理第1行中间的数
{
if( (num[row][column] - num[row][column-1])>1 && (num[row][column] - num[row+1][column])>1 && (num[row][column] - num[row][column+1])>1 )
num[row][column] = ( num[row][column-1] + num[row+1][column] + num[row][column+1]) / 3 + 0.5;
}
else if(column==0) //处理第1列中间的数
{
if( (num[row][column] - num[row-1][column])>1 && (num[row][column] - num[row+1][column])>1 && (num[row][column] - num[row][column+1])>1 )
num[row][column] = ( num[row-1][column] + num[row+1][column] + num[row][column+1]) / 3 + 0.5;
}
else if(row==19) //处理最后1行中间的数
{
if( (num[row][column] - num[row-1][column])>1 && (num[row][column] - num[row][column-1])>1 && (num[row][column] - num[row][column+1])>1 )
num[row][column] = ( num[row-1][column] + num[row][column-1] + num[row][column+1]) / 3 + 0.5;
}
else if(column==29) //处理最后1列中间的数
{
if( (num[row][column] - num[row-1][column])>1 && (num[row][column] - num[row+1][column])>1 && (num[row][column] - num[row][column-1])>1 )
num[row][column] = ( num[row-1][column] + num[row+1][column] + num[row][column-1]) / 3 + 0.5;
}
else //处理中间的数
{
if( (num[row][column] - num[row-1][column])>1 && (num[row][column] - num[row+1][column])>1 && (num[row][column] - num[row][column-1])>1 && (num[row][column] - num[row][column+1])>1 )
num[row][column] = ( num[row-1][column] + num[row+1][column] + num[row][column-1]) + num[row][column+1]/ 4 + 0.5;
}
}
for (row=0; row<20; row++) //数字与图形转换
{
for (column=0; column<30; column++)
photo[row][column] = table[ num[row][column] ];
photo[row][column] = '\0';
}
for (row=0; row<20; row++)
puts(photo[row]);
printf("input the name of destination file:");
gets(name);
if ( ( fp=fopen(name,"w") ) == NULL )
{
printf("Can't open %s",name);
exit(1);
}
for (row=0; row<20; row++)
fprintf(fp,"%s\n",photo[row]);
return 0;
}