C primer plus(第五版)编程练习第十三章

来源:互联网 发布:python中raise的用法 编辑:程序博客网 时间:2024/05/22 07:49
第一题:修改程序清单13.1中的程序,使之不采用命令行参数,而是请求用户输入文件名并读入用户的响应。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int ch;
    char filename[41];
    FILE * fp;
    long count = 0;

    fputs("Input your filename:\n",stdout);
    scanf("%s",filename);
    if((fp = fopen(filename,"r")) == NULL)
    {
        printf("Can't open %s.\n",filename);
        exit(1);
    }
    while((ch = getc(fp)) != EOF)
    {
        putc(ch,stdout);
        count++;
    }
    fclose(fp);
    printf("File %s has %ld characters\n",filename,count);
    return 0;
}
———————————————分割线—————————————————
第二题:编写一个文件复制程序。程序要从命令行获得源文件名和目的文件名。尽可能使用标准I/O和二进制模式。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char * argv[])
{
    char ch;
    FILE * sfp,*dfp;

    if(argc != 3)
    {
        fputs("Usage:command sourcefile destinationfile\n",stderr);
        exit(1);
    }
    if((sfp = fopen(argv[1],"rb")) == NULL)
    {
        fputs("Can't open sourcefile\n",stderr);
        exit(2);
    }
    if((dfp = fopen(argv[2],"wb")) == NULL)
    {
        fputs("Can't open destinationfile\n",stderr);
        exit(3);
    }
    while((ch = getc(sfp)) != EOF)
        putc(ch,dfp);
    return 0;
}
———————————————分割线—————————————————
第三题:编写一个文件复制程序,提示用户输入源文件名和输出文件名。在向输出文件写入时,程序应当使用ctype.h中定义的toupper()函数将所有文本转换成大写。使用标准I/O和文本模式。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
    char ch;
    FILE * sfp,* dfp;
    char sfile[40],dfile[40];
    
    fputs("Input your sourcefile:\n",stdout);
    scanf("%s",sfile);
    fputs("Input your destinationfile:\n",stdout);
    scanf("%s",dfile);
    if((sfp = fopen(sfile,"r")) == NULL)
    {
        fputs("Can't open sourcefile\n",stderr);
        exit(1);
    }
    if((dfp = fopen(dfile,"w")) == NULL)
    {
        fputs("Can't open destinationfile\n",stderr);
        exit(2);
    }
    while((ch = getc(sfp)) != EOF)
        putc(toupper(ch),dfp);
    return 0;
}
———————————————分割线—————————————————
第四题:编写一个程序,依次在屏幕上显示命令行中列出的全部文件。使用argc控制循环。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char * argv[])
{
    int i;
    char ch;
    FILE * fp;

    if(argc < 2)
    {
        fputs("Usage:at leat one argument\n",stderr);
        exit(1);
    }
    for(i = 1;i < argc;i++)
    {
        if((fp = fopen(argv[i],"r")) == NULL)
        {
            fputs("Can't open the file\n",stderr);
            exit(2);
        }
        fprintf(stdout,"File %s:\n",argv[i]);
        while((ch = getc(fp)) != EOF)
            putc(ch,stdout);
    }
    return 0;
}
———————————————分割线—————————————————
第五题:修改程序清单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;
    int files = 0;
    int i;
    if(argc < 3)
    {
        fputs("Usage:command destinationfile sourcefile1 sourcefile2,...\n",stderr);
        exit(1);
    }
    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)
    {
        fprintf(stderr,"Can't create output buffer\n");
        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 %s\n",argv[i]);
        else
        {
            if(setvbuf(fs,NULL,_IOFBF,BUFSIZE) != 0)
            {
                fputs("Can't create input buffer\n",stderr);
                continue;
            }
            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);
            files++;
            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];
 
    while((bytes = fread(temp,sizeof(char),BUFSIZE,source)) > 0)
        fwrite(temp,sizeof(char),bytes,dest);
}
———————————————分割线—————————————————
第六题:使用命令行参数的程序要求用户记住正确的使用方法。重写程序清单13.2中的程序,不使用命令行参数,而是提示用户键入所需的信息。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 40
int main(void)
{
    FILE *in,*out;
    int ch;
    char name1[LEN],name2[LEN];
    int count = 0;

    puts("Input your sourcefile");
    scanf("%s",name1);
    if((in = fopen(name1,"r")) == NULL)
    {
        fprintf(stderr,"Can't open the file \"%s\"\n",name1);
        exit(2);
    }
    strcpy(name2,name1);
    strcat(name2,".red");
    if((out = fopen(name2,"w")) == NULL)
    {
        fprintf(stderr,"Can't create the output file \"%s\"\n",name2);
        exit(3);
    }
    while((ch = getc(in)) != EOF)
        if(count++ % 3 == 0)
            putc(ch,out);
    if(fclose(in) != 0 || fclose(out) != 0)
        fprintf(stderr,"Error in closing files\n");
    return 0;
}
———————————————分割线—————————————————
第七题:编写一个打开两个文件的程序。可以使用命令行参数或者请求用户输入来获得文件名。
a.让程序打印第一个文件的第一行、第二个文件的第一行、第一个文件的第二行、第二个文件的第二行,以此类推,直到打印完行数较多的文件的最后一行。
b.修改程序,把行号相同的行打印到同一行上。
解:设计不同选项,让程序可以完成a,b两个需求。
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LEN 41
#define A 'a'
#define B 'b'
void aout(FILE * fp1,FILE * fp2);
void bout(FILE * fp1,FILE * fp2);
int main(int argc,char * argv[])
{
    char ch;
    FILE * fp1,* fp2;

    if(argc != 3)
    {
        fputs("Usage:command file1 file2",stderr);
        exit(1);
    }
    if((fp1 = fopen(argv[1],"r")) == NULL || (fp2 = fopen(argv[2],"r")) == NULL)
    {
        fputs("Can't open files",stderr);
        exit(2);
    }
    fputs("chose mode:\na.one by one\nb.one line\n",stdout);
    scanf("%c",&ch);
    while(getchar() != '\n');
    if(ch == A)
        aout(fp1,fp2);
    else if(ch == B)
        bout(fp1,fp2);
    else
    {
        fputs("Bad choice",stderr);
        exit(3);
    }
    return 0;
}
void aout(FILE * fp1,FILE * fp2)
{
    char ch1 = ' ';
    char ch2 = ' ';

    while(!(ch1 == EOF && ch2 == EOF))
    {
        while((ch1 = getc(fp1)) != '\n' && ch1 != EOF)
        {
            putc(ch1,stdout);
        }
        if(ch1 == '\n')
            putc('\n',stdout);
        while((ch2 = getc(fp2)) != '\n' && ch2 != EOF)
        {
            putc(ch2,stdout);
        }
        if(ch2 == '\n')
            putc('\n',stdout);
    }
}
void bout(FILE * fp1,FILE * fp2)
{
    char ch1 = ' ';
    char ch2 = ' ';

    while(!(ch1 == EOF && ch2 == EOF))
    {
        while((ch1 = getc(fp1)) != '\n' && ch1 != EOF)
        {
            putc(ch1,stdout);
        }
        while((ch2 = getc(fp2)) != '\n' && ch2 != EOF)
        {
            putc(ch2,stdout);
        }
        if(ch2 == '\n')
            putc('\n',stdout);
    }
}
———————————————分割线—————————————————
第八题:编写一段程序,将一个字符、零个或多个文件名作为命令行参数。如果字符后没有参数跟随,程序读取标准输入文件。否则,程序依次打开每个文件,然后报告每个文件中该字符的出现次数。文件名和字符本身也与计数值一起报告。程序中包括错误检查,以确定参数数目是否正确和是否能打开文件。如果不能打开文件,程序要报告这一情况然后继续处理下一文件。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char * argv[])
{
    FILE * fp;
    int count;
    int i;
    char mch,ch;

    if(argc < 2 || strlen(argv[1]) > 1)
    {
        fputs("Usage:command char file1,file2...\n",stderr);
        exit(1);
    }
    mch = argv[1][0];
    if(argc == 2)
    {
        count = 0;
        while((ch = getc(stdin)) != EOF)
            if(ch == mch)
                count++;
        printf("You Inputed %d %c\n",count,mch);
    }
    else
    {
        for(i = 2;i < argc;i++)
        {
            if((fp = fopen(argv[i],"r")) == NULL)
            {
                fprintf(stderr,"Can't open files %s\n",argv[i]);
                continue;
            }
            count = 0;
            while((ch = getc(fp)) != EOF)
                if(ch == mch)
                    count++;
            fprintf(stdout,"File %s have %d %c\n",argv[i],count,mch);
        }
    }
    return 0;
}
———————————————分割线—————————————————
第九题:修改程序清单13.3中的程序,从1开始,根据加入列表的顺序为每个单词编号。当再次运行程序时,确保新的单词编号接着前面的编号开始。
解:接着前面的编号,意思就是,得先读取并计算,然后再添加。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 40
int main(void)
{
    FILE * fp;
    char words[MAX];
    char num_words[MAX + 10];
    int count = 0;

    if((fp = fopen("words","a+")) == NULL)
    {
        fprintf(stderr,"Can't open \"words\" file.\n");
        exit(1);
    }
    puts("Enter words to add to the file;press the Enter");
    puts("key at the beginning of a line to terminate.");
    while(fscanf(fp,"%s",words) == 1)
        count++;
    while(gets(words) != NULL && words[0] != '\0')
    {
        sprintf(num_words,"%d:",++count);
        strcat(num_words,words);
        fprintf(fp,"%s ",num_words);
    }
    puts("File contents:");
    rewind(fp);
    while(fscanf(fp,"%s",words) == 1)
        puts(words);
    if(fclose(fp) != 0)
        fprintf(stderr,"Error closing file\n");
    return 0;
}
———————————————分割线—————————————————
第十题:编写一个程序,打开一个文本文件,文件名通过交互方式获得。建立一个循环,请求用户输入一个文件位置。然后程序打印文件中从该位置开始到下一换行符之间的部分。用户通过输入非数组字符来终止输入循环。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    char ch;
    FILE * fp;
    long pos;
    char file[40];
    
    puts("Input which file to open:");
    scanf("%s",file);
    if((fp = fopen(file,"r")) == NULL)
    {
        fprintf(stderr,"Can't open file.\n");
        exit(1);
    }
    printf("Input the location(q to quit):");
    while(scanf("%ld",&pos))
    {
        fseek(fp,pos,SEEK_SET);
        while((ch = getc(fp)) != '\n' && ch != EOF)
            putc(ch,stdout);
        putc('\n',stdout);
        printf("Input the location(q to quit):");
    }
    return 0;
}
———————————————分割线—————————————————
第十一题:编写一个程序,接收两个命令行参数。第一个参数为一个字符串;第二个参数为文件名。程序打印文件中包含该字符串的所有行。因为这一任务是面向行而不是面向字符的,所以要使用fgets()而不是getc()。使用标准C库函数strstr()在每一行中搜索这一字符串。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char * argv[])
{
    FILE * fp;
    char line[1024];
    
    if(argc != 3)
    {
        fprintf(stderr,"Usage:command line filename\n");
        exit(1);
    }
    if((fp = fopen(argv[2],"r")) == NULL)
    {
        fprintf(stderr,"Can't open file.\n");
        exit(2);
    }
    while(fgets(line,1024,fp))
        if(strstr(line,argv[1]))
            fputs(line,stdout);
    return 0;
}
———————————————分割线—————————————————
第十二题:创建一个包含20行,每行30个整数的文本文件。整数在0到9之间,用空格分开。该文件是一个图片的数字表示,从0到9的值代表逐渐增加的灰度。编写一个程序,将文件的内容读入到一个20*30的int数组中。一个将这种数字表示转化成图片的粗略方法就是让程序使用数组中的数值来初始化一个20*31的字符阵列。0对应空格字符,1对应句号字符,以此类推,较大的值对应占用空间较多的字符。比如,可以使用#代表9.每行的最后一个字符(第31个)为空字符,这样数组将包含20个字符串。然后程序显示图片结果(即打印这些字符串),并将结果诚如一个文本文件中。例如(太耗费篇幅,略)。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#define N0 ' '
#define N1 '.'
#define N2 ':'
#define N3 '!'
#define N4 '|'
#define N5 '+'
#define N6 '?'
#define N7 'T'
#define N8 'H'
#define N9 '#'
#define NAME "picture"
void createfile(char * ptr);
int main()
{
    FILE * fp;
    char txt[20][31];
    char n[5];
    int i,j;

    createfile(NAME);
    if((fp = fopen(NAME,"r")) == NULL)
    {
        fprintf(stderr,"Can't open file.\n");
        exit(1);
    }
    for(i = 0;i < 20;i ++)
    {
        for(j = 0;j < 30;j++)
        {
            if(fscanf(fp,"%s",n))
            switch(n[0])
            {
                case '0':txt[i][j] = N0;
                             break;
                case '1':txt[i][j] = N1;
                             break;
                case '2':txt[i][j] = N2;
                             break;
                case '3':txt[i][j] = N3;
                             break;
                case '4':txt[i][j] = N4;
                             break;
                case '5':txt[i][j] = N5;
                             break;
                case '6':txt[i][j] = N6;
                             break;
                case '7':txt[i][j] = N7;
                             break;
                case '8':txt[i][j] = N8;
                             break;
                case '9':txt[i][j] = N9;
            }
        }
        txt[i][30] = '\0';
    }
    fclose(fp);
    for(i = 0;i < 20;i++)
        puts(txt[i]);
    return 0;
}
void createfile(char * ptr)
{
    int i,j;
    FILE * fp;

    if((fp = fopen(ptr,"w")) == NULL)
    {
        fprintf(stderr,"Can't open file.\n");
        exit(1);
    }
    for(i = 0;i < 20;i++)
    {
        for(j = 0;j < 30;j++)
            fprintf(fp,"%d ",rand() % 10);
        putc('\n',fp);
    }
    fclose(fp);
}
———————————————分割线—————————————————
第十三题:数字图像,尤其是从宇宙飞船发挥的数字图像可能会包含尖峰脉冲。为第十二题添加消除尖峰冒充的函数。该函数应该将每一个值和它的上下左右的相邻值比较,如果该值与它周围每个值的差都大于1,就用所有相邻值的平均值(取与其最接近的整数)取代这取代这个值。注意到边界上的点的相邻点少于4个,所以他们需要特殊处理。
解:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#define N0 ' '
#define N1 '.'
#define N2 ':'
#define N3 '!'
#define N4 '|'
#define N5 '+'
#define N6 '?'
#define N7 'T'
#define N8 'H'
#define N9 '#'
#define NAME "picture"
void createfile(char * ptr);
void filter(char * ptr);
int main()
{
    FILE * fp;
    char txt[20][31];
    char n[5];
    int i,j;

    createfile(NAME);
    filter(NAME);
    if((fp = fopen(NAME,"r")) == NULL)
    {
        fprintf(stderr,"Can't open file.\n");
        exit(1);
    }
    for(i = 0;i < 20;i ++)
    {
        for(j = 0;j < 30;j++)
        {
            if(fscanf(fp,"%s",n))
            switch(n[0])
            {
                case '0':txt[i][j] = N0;
                             break;
                case '1':txt[i][j] = N1;
                             break;
                case '2':txt[i][j] = N2;
                             break;
                case '3':txt[i][j] = N3;
                             break;
                case '4':txt[i][j] = N4;
                             break;
                case '5':txt[i][j] = N5;
                             break;
                case '6':txt[i][j] = N6;
                             break;
                case '7':txt[i][j] = N7;
                             break;
                case '8':txt[i][j] = N8;
                             break;
                case '9':txt[i][j] = N9;
            }
        }
        txt[i][30] = '\0';
    }
    fclose(fp);
    for(i = 0;i < 20;i++)
        puts(txt[i]);
    return 0;
}
void createfile(char * ptr)
{
    int i,j;
    FILE * fp;

    if((fp = fopen(ptr,"w")) == NULL)
    {
        fprintf(stderr,"Can't open file.\n");
        exit(1);
    }
    for(i = 0;i < 20;i++)
    {
        for(j = 0;j < 30;j++)
            fprintf(fp,"%d ",rand() % 10);
        putc('\n',fp);
    }
    fclose(fp);
}
void filter(char * ptr)
{
    int i,j;
    FILE * fp;
    char txt[20][30];
    char n[5];

    if((fp = fopen(ptr,"r")) == NULL)
    {
        fprintf(stderr,"Can't open file.\n");
        exit(1);
    }
    for(i = 0;i < 20;i ++)
    {
        for(j = 0;j < 30;j++)
        {
            if(fscanf(fp,"%s",n))
                txt[i][j] = n[0];
        }
    }
    fclose(fp);
    if((fp = fopen(ptr,"w")) == NULL)
    {
        fprintf(stderr,"Can't open file.\n");
        exit(1);
    }
    for(i = 0;i < 20;i ++)
    {
        for(j = 0;j < 30;j++)
        {
        if(i == 0 && j == 0 && txt[i][j] - txt[i + 1][j] > 1 && txt[i][j] - txt[i][j + 1] > 1)
            txt[i][j] = (txt[i + 1][j] + txt[i][j + 1]) / 2 + (txt[i + 1][j] + txt[i][j + 1]) % 2;
        else if(i == 0 && j == 29 && txt[i][j] - txt[i + 1][j] > 1 && txt[i][j] - txt[i][j - 1] > 1)
            txt[i][j] = (txt[i + 1][j] + txt[i][j - 1]) / 2 + (txt[i + 1][j] + txt[i][j - 1]) % 2;
        else if(i == 19 && j == 0 && txt[i][j] - txt[i - 1][j] > 1 && txt[i][j] - txt[i][j + 1] > 1)
            txt[i][j] = (txt[i - 1][j] + txt[i][j + 1]) / 2 + (txt[i - 1][j] + txt[i][j + 1]) % 2;
        else if(i == 19 && j == 29 && txt[i][j] - txt[i - 1][j] > 1 && txt[i][j] - txt[i][j - 1] > 1)
            txt[i][j] = (txt[i - 1][j] + txt[i][j - 1]) / 2 + (txt[i - 1][j] + txt[i][j - 1]) % 2;
        else if(i == 0 && txt[i][j] - txt[i][j - 1] > 1 && txt[i][j] - txt[i + 1][j] > 1 && txt[i][j] - txt[i][j + 1] > 1)
            txt[i][j] = (txt[i][j - 1] + txt[i + 1][j] + txt[i][j + 1]) / 3 + ((txt[i][j - 1] + txt[i + 1][j] + txt[i][j + 1]) % 3 != 0);
        else if(i == 19 && txt[i][j] - txt[i][j - 1] > 1 && txt[i][j] - txt[i - 1][j] > 1 && txt[i][j] - txt[i][j + 1] > 1)
            txt[i][j] = (txt[i][j - 1] + txt[i - 1][j] + txt[i][j + 1]) / 3 + ((txt[i][j - 1] + txt[i - 1][j] + txt[i][j + 1]) % 3 != 0);
        else if(j == 0 && txt[i][j] - txt[i - 1][j] > 1 && txt[i][j] - txt[i][j + 1] > 1 && txt[i][j] - txt[i + 1][j] > 1)
            txt[i][j] = (txt[i - 1][j] + txt[i][j + 1] + txt[i + 1][j]) / 3 + ((txt[i - 1][j] + txt[i][j + 1] + txt[i + 1][j]) % 3 != 0);
        else if(j == 29 && txt[i][j] - txt[i - 1][j] > 1 && txt[i][j] - txt[i][j - 1] > 1 && txt[i][j] - txt[i + 1][j] > 1)
            txt[i][j] = (txt[i - 1][j] + txt[i][j - 1] + txt[i + 1][j]) / 3 + ((txt[i - 1][j] + txt[i][j - 1] + txt[i + 1][j]) % 3 != 0);
        else if(txt[i][j] - txt[i - 1][j] > 1 && txt[i][j] - txt[i][j - 1] > 1 && txt[i][j] - txt[i + 1][j] > 1 && txt[i][j] - txt[i][j + 1] > 1) 
            txt[i][j] = (txt[i - 1][j] + txt[i][j - 1] + txt[i + 1][j] + txt[i][j + 1]) / 4 + ((txt[i - 1][j] + txt[i][j - 1] + txt[i + 1][j] + txt[i][j + 1]) % 4 != 0);
        fprintf(fp,"%c ",txt[i][j]);
        }
        putc('\n',fp);
    }
    fclose(fp);
}
运行说明:也可以自定义文件而不是用创建函数。
PS:差点放弃这道题,太繁杂了。

















0 0