《C Primer Plus》第13章复习题与编程练习
- 复习题
- 1. 下面的程序有什么问题?
- 2. 下面的程序完成什么任务?(假设在命令行环境中运行)
- 3. 假设程序中有下列语句:
- 4. 编写一个程序,不接受任何命令行参数或接受一个命令行参数。如果有一个参数,将其解释为文件名;如果没有参数,使用标准输入(stdin)作为输入。假设输入完全是浮点数。该程序要计算和报告输入数字的算术平均值。
- 5. 编写一个程序,接受两个命令行参数。第1个参数是字符,第2个参数是文件名。要求该程序只打印文件中包含给定字符的那些行。
- 6. 二进制文件和文本文件有何区别?二进制流和文本流有何区别?
- 7.
- 8.下面语句的区别是什么?
- 9."a+"、"r+"和"w+"模式打开的文件都是可读写的。哪种模式更适合用来更改文件中已有的内容?
- 编程练习
- 1. 修改程序清单13.1中的程序,要求提示用户输入文件名,并读取用户输入的信息,不使用命令行参数。
- 2. 编写一个文件拷贝程序,该程序通过命令行获取原始文件名和拷贝文件名。尽量使用标准I/O和二进制模式。
- 3. 编写一个文件拷贝程序,提示用户输入文本文件名,并以该文件名作为原始文件名和输出文件名。该程序要使用 ctype.h 中的 toupper()函数,在写入到输出文件时把所有文本转换成大写。使用标准I/O和文本模式。
- 4. 编写一个程序,按顺序在屏幕上显示命令行中列出的所有文件。使用argc控制循环。
- 5. 修改程序清单13.5中的程序,用命令行界面代替交互式界面。
- 6. 使用命令行参数的程序依赖于用户的内存如何正确地使用它们。重写程序清单 13.2 中的程序,不使用命令行参数,而是提示用户输入所需信息。
- 7. 编写一个程序打开两个文件。可以使用命令行参数或提示用户输入文件名。
- 8. 编写一个程序,以一个字符和任意文件名作为命令行参数。如果字符后面没有参数,该程序读取标准输入;否则,程序依次打开每个文件并报告每个文件中该字符出现的次数。文件名和字符本身也要一同报告。程序应包含错误检查,以确定参数数量是否正确和是否能打开文件。如果无法打开文件,程序应报告这一情况,然后继续处理下一个文件。
- 9. 修改程序清单 13.3 中的程序,从 1 开始,根据加入列表的顺序为每个单词编号。当程序下次运行时,确保新的单词编号接着上次的编号开始。
- 10. 编写一个程序打开一个文本文件,通过交互方式获得文件名。通过一个循环,提示用户输入一个文件位置。然后该程序打印从该位置开始到下一个换行符之前的内容。用户输入负数或非数值字符可以结束输入循环。
- 11. 编写一个程序,接受两个命令行参数。第1个参数是一个字符串,第2个参数是一个文件名。然后该程序查找该文件,打印文件中包含该字符串的所有行。因为该任务是面向行而不是面向字符的,所以要使用fgets()而不是getc()。使用标准C库函数strstr()(11.5.7节简要介绍过)在每一行中查找指定字符串。假设文件中的所有行都不超过255个字符。
- 12. 创建一个文本文件,内含20行,每行30个整数。这些整数都在0~9之间,用空格分开。该文件是用数字表示一张图片,0~9表示逐渐增加的灰度。编写一个程序,把文件中的内容读入一个20×30的int数组中。一种把这些数字转换为图片的粗略方法是:该程序使用数组中的值初始化一个20×31的字符数组,用值0 对应空格字符,1 对应点字符,以此类推。数字越大表示字符所占的空间越大。例如,用#表示9。每行的最后一个字符(第31个)是空字符,这样该数组包含了20个字符串。最后,程序显示最终的图片(即,打印所有的字符串),并将结果储存在文本文件中。例如,下面是开始的数据:
- 13. 用变长数组(VLA)代替标准数组,完成编程练习12。
- 14. 数字图像,尤其是从宇宙飞船发回的数字图像,可能会包含一些失真。为编程练习12添加消除失真的函数。该函数把每个值与它上下左右相邻的值作比较,如果该值与其周围相邻值的差都大于1,则用所有相邻值的平均值(四舍五入为整数)代替该值。注意,与边界上的点相邻的点少于4个,所以做特殊处理。
复习题
1. 下面的程序有什么问题?
int main(void)
{
int * fp;
int k;
fp = fopen("gelatin");
for (k = 0; k < 30; k++)
fputs(fp, "Nanette eats gelatin.");
fclose("gelatin");
return 0;
}
缺少头文件,fopen()和fclose()函数错误。
修改后的代码如下:
#include <stdio.h>
int main(void)
{
FILE *fp;
int k;
fp = fopen("gelatin", "w");
for (k = 0; k < 30; k++)
fputs("Nanette eats gelatin.\n", fp);
fclose(fp);
return 0;
}
2. 下面的程序完成什么任务?(假设在命令行环境中运行)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv [])
{
int ch;
FILE *fp;
if (argc < 2)
exit(EXIT_FAILURE);
if ((fp = fopen(argv[1], "r")) == NULL)
exit(EXIT_FAILURE);
while ((ch = getc(fp)) != EOF)
if (isdigit(ch))
putchar(ch);
fclose(fp);
return 0;
}
如果有第二个参数,尝试打开一个和该参数名同名的文件,如果该文件可以打开,在屏幕上输出一个其中的所有数字。
运行结果:
3. 假设程序中有下列语句:
#include <stdio.h>
FILE * fp1,* fp2;
char ch;
fp1 = fopen("terky", "r");
fp2 = fopen("jerky", "w");
另外,假设成功打开了两个文件。补全下面函数调用中缺少的参数:
a.ch = getc();
b.fprintf( ,“%c\n”, );
c.putc( , );
d.fclose(); /* 关闭terky文件 */
a. fp1
b. fp2 ch
c. ch fp2
d. fp1
4. 编写一个程序,不接受任何命令行参数或接受一个命令行参数。如果有一个参数,将其解释为文件名;如果没有参数,使用标准输入(stdin)作为输入。假设输入完全是浮点数。该程序要计算和报告输入数字的算术平均值。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void makeFile()
{
srand((unsigned long)time(0));
FILE *fp;
fp = fopen("file.txt", "w");
//生成100个浮点数,小数点前有3位,小数点后有4位
for (int j = 0; j < 100; ++j)
{
for (int i = 0; i < 7; ++i)
{
if (i == 3)
{
putc('.', fp);
}
putc(rand() % 10 + '0', fp);
}
putc('\n', fp);
}
fclose(fp);
}
int main(int argc, char **argv)
{
makeFile();
FILE *fp;
double n, sum = 0.0;
int num = 0;
if (argc == 1)
{
fp = stdin;
}
else if (argc == 2)
{
if ((fp = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Open %s failed\n", argv[1]);
exit(EXIT_FAILURE);
}
}
else
{
fprintf(stderr, "Usage:%s [filename]\n", argv[0]);
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%lf", &n) == 1)
{
num++;
sum += n;
}
if (num)
{
printf("%lf\n", sum / n);
}
else
{
puts("There is no number");
}
system("pause");
return 0;
}
运行结果:
使用文件输入:
使用键盘输入:
5. 编写一个程序,接受两个命令行参数。第1个参数是字符,第2个参数是文件名。要求该程序只打印文件中包含给定字符的那些行。
注意
C程序根据’\n’识别文件中的行。假设所有行都不超过256个字符,你可能会想到用fgets()。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void makeFile()
{
srand((unsigned long)time(0));
FILE *fp;
fp = fopen("file.txt", "w");
// 随机生成100条字符串
for (int j = 0; j < 100; ++j)
{
int n = rand() % 256;
for (int i = 0; i < n; ++i)
{
putc(32 + rand() % 95, fp);
}
putc('\n', fp);
}
fclose(fp);
}
int main(int argc, char **argv)
{
makeFile();
FILE *fp;
char ch;
if (argc != 3)
{
fprintf(stderr, "Usage:%s [character] [filename]\n", argv[0]);
exit(EXIT_FAILURE);
}
else
{
if (strlen(argv[1]) != 1)
{
fprintf(stderr, "The second parameter should be a character\n");
exit(EXIT_FAILURE);
}
if ((fp = fopen(argv[2], "r")) == NULL)
{
fprintf(stderr, "Open %s failed\n", argv[1]);
exit(EXIT_FAILURE);
}
}
ch = argv[1][0];
char a[256];
while (fgets(a, 256, fp) != NULL)
{
if (strchr(a, ch))
;
{
puts(a);
}
}
system("pause");
return 0;
}
运行结果:
6. 二进制文件和文本文件有何区别?二进制流和文本流有何区别?
这两种文件格式对系统的依赖性不同。
二进制流和文本流的区别包括是在读写流时程序执行的转换(二进制流不转换,文本流可能要转换换行符和其他字符)。
7.
a.分别用fprintf()和fwrite()储存8238201有何区别?
b.分别用putc()和fwrite()储存字符S有何区别?
a. 用fprintf()时把8238201当做7个字符存储,用fwrite()时把8238201当做一个4字节整形存储
b. 没有区别,都将其视为一个单字节二进制码
8.下面语句的区别是什么?
printf(“Hello, %s\n”, name);
fprintf(stdout, “Hello, %s\n”, name);
fprintf(stderr, “Hello, %s\n”, name);
第一句和第二句没有区别,第三条语句把消息写到标准错误上。
通常,标准错误被定向到与标准输出相同的位置。但标准错误不受标准输出重定向的影响
9.“a+”、"r+"和"w+"模式打开的文件都是可读写的。哪种模式更适合用来更改文件中已有的内容?
r+
a+只允许在文件的末尾添加,w+会丢弃文件原有内容
编程练习
1. 修改程序清单13.1中的程序,要求提示用户输入文件名,并读取用户输入的信息,不使用命令行参数。
代码:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ch;
FILE *fp;
unsigned count = 0;
char fileName[50];
printf("Please input the filename: ");
gets(fileName);
if ((fp = fopen(fileName, "r")) == NULL)
{
printf("Can't open %s\n", fileName);
exit(EXIT_FAILURE);
}
while ((ch = getc(fp)) != EOF)
{
putc(ch, stdout);
count++;
}
fclose(fp);
printf("\nFile %s has %lu characters\n", fileName, count);
system("pause");
return 0;
}
运行结果:
2. 编写一个文件拷贝程序,该程序通过命令行获取原始文件名和拷贝文件名。尽量使用标准I/O和二进制模式。
代码:
在这里插入代码片
运行结果:
3. 编写一个文件拷贝程序,提示用户输入文本文件名,并以该文件名作为原始文件名和输出文件名。该程序要使用 ctype.h 中的 toupper()函数,在写入到输出文件时把所有文本转换成大写。使用标准I/O和文本模式。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char ch;
FILE *fp1, *fp2;
unsigned count = 0;
if (argc != 3)
{
fprintf(stderr, "Usage:%s [filename] [filename]\n", argv[0]);
exit(EXIT_FAILURE);
}
else
{
if ((fp1 = fopen(argv[1], "rb")) == NULL)
{
fprintf(stderr, "Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
}
if ((fp2 = fopen(argv[2], "wb")) == NULL)
{
fprintf(stderr, "Can't open %s\n", argv[2]);
exit(EXIT_FAILURE);
}
}
// 拷贝
while ((ch = getc(fp1)) != EOF)
{
if (islower(ch))
ch = toupper(ch);
putc(ch, fp2);
count++;
}
fclose(fp1);
fclose(fp2);
printf("文件%s的内容已经拷贝到%s,共复制%lu个字符。\n", argv[1], argv[2], count);
system("pause");
return 0;
}
运行结果:
4. 编写一个程序,按顺序在屏幕上显示命令行中列出的所有文件。使用argc控制循环。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
int main(int argc, char **argv)
{
FILE *fp;
char ch;
for (int i = 1; i < argc; i++)
{
if ((fp = fopen(argv[i], "r")) != NULL)
{
printf("File %d:%s\n", i, argv[i]);
while ((ch = getc(fp)) != EOF)
{
putchar(ch);
}
putchar('\n');
fclose(fp);
}
else
{
fprintf(stderr, "Open %s failed\n", argv[i]);
exit(EXIT_FAILURE);
}
}
printf("Done\n");
system("pause");
return 0;
}
运行结果:
5. 修改程序清单13.5中的程序,用命令行界面代替交互式界面。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 4096
#define SLEN 81
void append(FILE *source, FILE *dest);
char *s_gets(char *st, int n);
int main(int argc, char **argv)
{
FILE *fa, *fs; // fa 指向目标文件,fs 指向源文件
int files = 0; // 附加的文件数量
char file_app[SLEN]; // 目标文件名
char file_src[SLEN]; // 源文件名
int ch;
if (argc < 2)
{
fprintf(stderr, "Usage:%s [filename]\n", argv[0]);
exit(EXIT_FAILURE);
}
if ((fa = fopen(argv[1], "a+")) == NULL)
{
fprintf(stderr, "Can't open %s\n", argv[2]);
exit(EXIT_FAILURE);
}
if (setvbuf(fa, NULL, _IOFBF, BUFSIZE) != 0)
{
fputs("Can't create output buffer\n", stderr);
exit(EXIT_FAILURE);
}
puts("Enter name of first source file (empty line to quit):");
while (s_gets(file_src, SLEN) && file_src[0] != '\0')
{
if (strcmp(argv[1], file_src) == 0)
fputs("Can't append file to itself\n", stderr);
else if ((fs = fopen(file_src, "r")) == NULL)
fprintf(stderr, "Can't open %s\n", file_src);
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", file_src);
if (ferror(fa) != 0)
fprintf(stderr, "Error in writing file %s.\n", file_app);
fclose(fs);
files++;
printf("File %s appended.\n", file_src);
puts("Next file (empty line to quit):");
}
}
printf("Done appending.%d files appended.\n", files);
rewind(fa);
printf("%s contents:\n", file_app);
while ((ch = getc(fa)) != EOF)
putchar(ch);
puts("Done displaying.");
fclose(fa);
system("pause");
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);
}
char *s_gets(char *st, int n)
{
char *ret_val;
char *find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n'); // 查找换行符
if (find) // 如果地址不是NULL,
*find = '\0'; // 在此处放置一个空字符
else
while (getchar() != '\n')
continue;
}
return ret_val;
}
6. 使用命令行参数的程序依赖于用户的内存如何正确地使用它们。重写程序清单 13.2 中的程序,不使用命令行参数,而是提示用户输入所需信息。
代码:
在这里插入代码片
运行结果:
7. 编写一个程序打开两个文件。可以使用命令行参数或提示用户输入文件名。
a.该程序以这样的顺序打印:打印第1个文件的第1行,第2个文件的第1行,第1个文件的第2行,第2个文件的第2行,以此类推,打印到行数较多文件的最后一行。
b.修改该程序,把行号相同的行打印成一行。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_LEN 256
void aFunc(FILE *fp1, FILE *fp2)
{
char file1[LINE_LEN], file2[LINE_LEN];
while (fgets(file1, LINE_LEN, fp1) && fgets(file2, LINE_LEN, fp2))
{
printf("%s\n", file1);
printf("%s\n", file2);
}
while (fgets(file1, LINE_LEN, fp1))
{
printf("%s\n", file1);
}
while (fgets(file2, LINE_LEN, fp2))
{
printf("%s\n", file2);
}
}
void bFunc(FILE *fp1, FILE *fp2)
{
char file1[LINE_LEN], file2[LINE_LEN];
while (fgets(file1, LINE_LEN, fp1) && fgets(file2, LINE_LEN, fp2))
{
printf("%s%s\n", file1, file2);
}
while (fgets(file1, LINE_LEN, fp1))
{
puts(file1);
}
while (fgets(file2, LINE_LEN, fp2))
{
puts(file2);
}
}
int main(int argc, char **argv)
{
FILE *fp1, *fp2;
if (argc != 3)
{
fprintf(stderr, "Usage:%s [filename] [filename]", argv[0]);
exit(EXIT_FAILURE);
}
if ((fp1 = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
}
if ((fp2 = fopen(argv[2], "r")) == NULL)
{
fprintf(stderr, "Can't open %s\n", argv[2]);
exit(EXIT_FAILURE);
}
aFunc(fp1, fp2); // 或bFunc()
system("pause");
return 0;
}
运行结果:
8. 编写一个程序,以一个字符和任意文件名作为命令行参数。如果字符后面没有参数,该程序读取标准输入;否则,程序依次打开每个文件并报告每个文件中该字符出现的次数。文件名和字符本身也要一同报告。程序应包含错误检查,以确定参数数量是否正确和是否能打开文件。如果无法打开文件,程序应报告这一情况,然后继续处理下一个文件。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define LINE_LEN 256
int main(int argc, char **argv)
{
FILE *fp;
int count;
char ch;
if (argc < 2)
{
fprintf(stderr, "Usage:%s [character] / [character] [filename] ... \n", argv[0]);
exit(EXIT_FAILURE);
}
if (strlen(argv[1]) != 1)
{
fprintf(stderr, "The second parameter should be a character.\n");
exit(EXIT_FAILURE);
}
if (argc == 2)
{
count = 0;
char a[LINE_LEN];
for (int j = 0; j < LINE_LEN; ++j)
{
a[j] = getchar();
}
for (int i = 0; i < LINE_LEN; ++i)
{
if (a[i] == argv[1][0])
count++;
}
printf("There are %d \'%c\' in the input.\n", count, argv[1][0]);
}
else
{
for (int i = 2; i < argc; ++i)
{
count = 0;
if ((fp = fopen(argv[i], "r")) == NULL)
{
fprintf(stderr, "Can't open %s\n", argv[i]);
continue;
}
while ((ch = getc(fp)) != EOF)
{
if (ch == argv[1][0])
count++;
}
printf("There are %d \'%c\' in %s.\n", count, argv[1][0], argv[i]);
}
}
system("pause");
return 0;
}
运行结果:
9. 修改程序清单 13.3 中的程序,从 1 开始,根据加入列表的顺序为每个单词编号。当程序下次运行时,确保新的单词编号接着上次的编号开始。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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%s\n", ++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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 41
int main(void)
{
FILE *fp;
char name[40];
long pos;
char ch;
printf("Please input the filename: ");
scanf("%s", name);
if ((fp = fopen(name, "r")) == NULL)
{
fprintf(stderr, "Can't open %s\n", name);
exit(EXIT_FAILURE);
}
printf("Input the index(q or -1 to quit):");
while (scanf("%ld", &pos) == 1 && pos > 0)
{
fseek(fp, pos, SEEK_SET);
while ((ch = getc(fp)) != EOF && ch != '\n')
{
putchar(ch);
}
putchar('\n');
printf("Input the index(q or -1 to quit):");
}
system("pause");
return 0;
}
运行结果:
11. 编写一个程序,接受两个命令行参数。第1个参数是一个字符串,第2个参数是一个文件名。然后该程序查找该文件,打印文件中包含该字符串的所有行。因为该任务是面向行而不是面向字符的,所以要使用fgets()而不是getc()。使用标准C库函数strstr()(11.5.7节简要介绍过)在每一行中查找指定字符串。假设文件中的所有行都不超过255个字符。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 41
int main(void)
{
FILE *fp;
char name[40];
char c[256];
char s[256];
printf("Please input the filename: ");
scanf("%s", name);
if ((fp = fopen(name, "r")) == NULL)
{
fprintf(stderr, "Can't open %s\n", name);
exit(EXIT_FAILURE);
}
printf("Please input a string: ");
scanf("%s", c);
while (fgets(s, 256, fp))
{
if (strstr(s, c))
{
puts(s);
}
}
system("pause");
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 <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
FILE *fp1, *fp2;
int number[20][30]; // 保存数字的数组
int character[20][31]; // 保存字符的数组
int i, j;
char ch;
if ((fp1 = fopen("number.txt", "r")) == NULL)
{
fprintf(stderr, "Can't open file:%s\n", "number.txt");
exit(EXIT_FAILURE);
}
for (i = 0; i < 20; i++) // 从文件读入数字到数组
for (j = 0; j < 60; j++)
{
if ((ch = getc(fp1)) != EOF && isdigit(ch))
number[i][j / 2] = (int)ch - 48;
}
if (fclose(fp1) != 0)
fprintf(stderr, "Error in closing file number.txt\n");
for (i = 0; i < 20; i++) // 把数字转换为字符,并存入到character数组中
for (j = 0; j < 30; j++)
{
switch (number[i][j])
{
case 0:
character[i][j] = ' ';
break;
case 1:
character[i][j] = '.';
break;
case 2:
character[i][j] = '\'';
break;
case 3:
character[i][j] = ':';
break;
case 4:
character[i][j] = '~';
break;
case 5:
character[i][j] = '*';
break;
case 6:
character[i][j] = '=';
break;
case 7:
character[i][j] = '^';
break;
case 8:
character[i][j] = '%';
break;
case 9:
character[i][j] = '#';
break;
default:
break;
}
}
for (i = 0; i < 20; i++)
character[i][30] = '\0';
if ((fp2 = fopen("result.txt", "a+")) == NULL)
{
fprintf(stderr, "Can't open file:%s\n", "result.txt");
exit(EXIT_FAILURE);
}
for (i = 0; i < 20; i++) // 把character数组的字符,读入到文件中
{
for (j = 0; j < 31; j++)
putc(character[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 result.txt\n");
system("pause");
return 0;
}
运行结果:
13. 用变长数组(VLA)代替标准数组,完成编程练习12。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
FILE *fp1, *fp2;
int a = 20;
int b = 30;
int arr1[a][b]; // 声明变长数组
int i, j;
char ch;
if ((fp1 = fopen("number.txt", "r")) == NULL)
{
fprintf(stderr, "Can't open file:number.txt\n");
exit(EXIT_FAILURE);
}
if ((fp2 = fopen("result.txt", "a+")) == NULL)
{
fprintf(stderr, "Can't open file:result.txt\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < a; i++) // 从文件读入数字到数组
{
for (j = 0; j < 2 * b; 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:number.txt\b");
for (i = 0; i < 20; i++) // 按数组中的元素,转换为相应的字符,并输出到文件
{
for (j = 0; j < 30; j++)
{
switch (arr1[i][j])
{
case 0:
putc(' ', fp2);
break;
case 1:
putc('.', fp2);
break;
case 2:
putc('\'', fp2);
break;
case 3:
putc(':', fp2);
break;
case 4:
putc('~', fp2);
break;
case 5:
putc('*', fp2);
break;
case 6:
putc('=', fp2);
break;
case 7:
putc('^', fp2);
break;
case 8:
putc('%', fp2);
break;
case 9:
putc('#', fp2);
break;
default:
break;
}
}
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:result.txt\n");
system("pause");
return 0;
}
14. 数字图像,尤其是从宇宙飞船发回的数字图像,可能会包含一些失真。为编程练习12添加消除失真的函数。该函数把每个值与它上下左右相邻的值作比较,如果该值与其周围相邻值的差都大于1,则用所有相邻值的平均值(四舍五入为整数)代替该值。注意,与边界上的点相邻的点少于4个,所以做特殊处理。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void func(int a, int b, int arr[][])
{
float temp;
int i, j;
for (i = 1; i < a - 1; i++)
for (j = 1; j < b - 1; j++)
{
if (abs(arr[i][j] - arr[i - 1][j]) > 1 && // 与上下左右做比较
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;
}
}
}
int main(void)
{
FILE *fp1, *fp2;
int a = 20;
int b = 30;
int arr1[a][b];
int i, j;
char ch;
if ((fp1 = fopen("number.txt", "r")) == NULL)
{
fprintf(stderr, "Can't open file:number.txt\n");
exit(EXIT_FAILURE);
}
if ((fp2 = fopen("result.txt", "a+")) == NULL)
{
fprintf(stderr, "Can't open file:result.txt\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < a; i++) // 把文件中的数字保存到数组中
for (j = 0; j < 2 * b; j++)
if ((ch = getc(fp1)) != EOF && isdigit(ch))
arr1[i][j / 2] = (int)ch - 48;
func(a, b, arr1); // 消除失真
if (fclose(fp1) != 0)
fprintf(stderr, "Error in closing file number.txt\n");
for (i = 0; i < a; i++) // 按照数组中的数字,转换为相应的字符,并输入到文件中
{
for (j = 0; j < b; j++)
{
switch (arr1[i][j])
{
case 0:
putc(' ', fp2);
break;
case 1:
putc('.', fp2);
break;
case 2:
putc('\'', fp2);
break;
case 3:
putc(':', fp2);
break;
case 4:
putc('~', fp2);
break;
case 5:
putc('*', fp2);
break;
case 6:
putc('=', fp2);
break;
case 7:
putc('^', fp2);
break;
case 8:
putc('%', fp2);
break;
case 9:
putc('#', fp2);
break;
default:
break;
}
}
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 result.txt\n");
system("pause");
return 0;
}