《C Primer Plus》(第六版)第十三章:文件输入\输出|复习题与编程练习答案参考

目录

复习题

1.下面的程序有什么问题?

2.下面的程序完成什么任务?(假设在命令行环境中运行)

3.假设程序中有下列语句:

4.编写一个程序,不接受任何命令行参数或接受一个命令行参数。如果有一个参数,将其解释为文件名;如果没有参数,使用标准输入(stdin)作为输入。假设输入完全是浮点数。该程序要计算和报告输入数字的算术平均值。

5.编写一个程序,接受两个命令行参数。第1个参数是字符,第2个参数是文件名。要求该程序只打印文件中包含给定字符的那些行。

6.二进制文件和文本文件有何区别?二进制流和文本流有何区别?

7.

8.下面语句的区别是什么?

9."a+"、"r+"和"w+"模式打开的文件都是可读写的。哪种模式更适合用来更改文件中已有的内容?


复习题



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;
}
根据文件定义,应包含 #include <stdio.h> 。应该把 fp 声明为文件指针: FILE *fp;
要给 fopen() 函数提供一种模式: fopen("gelatin","w") ,或者 "a" 模式。
fputs() 函数的参数顺序应该反过来。
输出字符串应该有一个换行符,提高可读性。
fclose() 函数需要一个文件指针,而不是一个文件名:fclose(fp);
下面是修改后的版本:
#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;
}
如果可以打开的话,会打开与命令行第 1 个参数名相同名称的文件,并在屏幕上显示文件中的每个数字字符。

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.ch=getc(fp1)
b.fprint(fp2,"%c\n",ch);
c.putc(ch,fp2);
d.fclose(fp1);
注意
fp1用于输入操作,因为它识别以读模式打开的文件。与此类似, fp2 以写模式打开文件,所以常用于输出操作。

4.编写一个程序,不接受任何命令行参数或接受一个命令行参数。如果有一个参数,将其解释为文件名;如果没有参数,使用标准输入(stdin)作为输入。假设输入完全是浮点数。该程序要计算和报告输入数字的算术平均值。

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv [])
{
FILE * fp;
double n;
double sum = 0.0;
int ct = 0;
if (argc == 1)
fp = stdin;
else if (argc == 2)
{
if ((fp = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
}
}
else
{
fprintf(stderr, "Usage: %s [filename]\n", argv[0]);
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%lf", &n) == 1)
{
sum += n;
++ct;
}
if (ct > 0)
printf("Average of %d values = %f\n", ct, sum / ct);
else
printf("No valid data.\n");
return 0;
}

5.编写一个程序,接受两个命令行参数。第1个参数是字符,第2个参数是文件名。要求该程序只打印文件中包含给定字符的那些行。

注意
C 程序根据 '\n' 识别文件中的行。假设所有行都不超过 256 个字符,你可能会想到用fgets()
#include <stdio.h>
#include <stdlib.h>
#define BUF 256
int has_ch(char ch, const char * line);
int main(int argc, char * argv [])
{
FILE * fp;
char ch;
char line[BUF];
if (argc != 3)
{
printf("Usage: %s character filename\n", argv[0]);
exit(EXIT_FAILURE);
}
ch = argv[1][0];
if ((fp = fopen(argv[2], "r")) == NULL)
{
printf("Can't open %s\n", argv[2]);
exit(EXIT_FAILURE);
}
while (fgets(line, BUF, fp) != NULL)
{
if (has_ch(ch, line))
fputs(line, stdout);
}
fclose(fp);
return 0;
}
int has_ch(char ch, const char * line)
{
while (*line)
if (ch == *line++)
return(1);
return 0;
}
fgets() fputs() 函数要一起使用,因为 fgets() 会把按下 Enter 键的 \n 留在字符串中, fputs() puts() 不一样,不会添加一个换行符。

6.二进制文件和文本文件有何区别?二进制流和文本流有何区别?

二进制文件与文本文件的区别是,这两种文件格式对系统的依赖性不同。二进制流和文本流的区别包括是在读写流时程序执行的转换(二进制流不转换,而文本流可能要转换换行符和其他字符)。

7.

a. 分别用 fprintf() fwrite() 储存 8238201 有何区别?
b. 分别用 putc() fwrite() 储存字符 S 有何区别?
a. fprintf() 储存 8238201 时,将其视为 7 个字符,保存在 7 字节中。用fwrite()储存时,使用该数的二进制表示,将其储存为一个 4 字节的整数。
b.没有区别。两个函数都将其储存为一个单字节的二进制码。

8.下面语句的区别是什么?

printf("Hello, %s\n", name);
fprintf(stdout, "Hello, %s\n", name);
fprintf(stderr, "Hello, %s\n", name);
1 条语句是第 2 条语句的速记表示。第 3 条语句把消息写到标准错误上。通常,标准错误被定向到与标准输出相同的位置。但是标准错误不受标准输出重定向的影响。

9."a+"、"r+""w+"模式打开的文件都是可读写的。哪种模式更适合用来更改文件中已有的内容?

可以在以 "r+" 模式打开的文件中读写,所以该模式最合适。 "a+" 只允许在文件的末尾添加内容。"w+" 模式提供一个空文件,丢弃文件原来的内容。
编程题
暂时先放着
1. 修改程序清单 13.1 中的程序,要求提示用户输入文件名,并读取用户输入的信息,不使用命令行参数。
2. 编写一个文件拷贝程序,该程序通过命令行获取原始文件名和拷贝文件名。尽量使用标准I/O 和二进制模式。
3. 编写一个文件拷贝程序,提示用户输入文本文件名,并以该文件名作为原始文件名和输出文件名。该程序要使用 ctype.h 中的 toupper() 函数,在写入到输出文件时把所有文本转换成大写。使用标准I/O 和文本模式。
4. 编写一个程序,按顺序在屏幕上显示命令行中列出的所有文件。使用argc控制循环。
5. 修改程序清单 13.5 中的程序,用命令行界面代替交互式界面。
6. 使用命令行参数的程序依赖于用户的内存如何正确地使用它们。重写程序清单 13.2 中的程序,不使用命令行参数,而是提示用户输入所需信息。
7. 编写一个程序打开两个文件。可以使用命令行参数或提示用户输入文件名。
a. 该程序以这样的顺序打印:打印第 1 个文件的第 1 行,第 2 个文件的第 1行,第1 个文件的第 2 行,第 2 个文件的第 2 行,以此类推,打印到行数较多文件的最后一行。
b. 修改该程序,把行号相同的行打印成一行。
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 个字符串。最后,程序显示最终的图片(即,打印所有的字符串),并将结果储存在文本文件中。例如,下面是开
始的数据:
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
1003 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
根据以上描述选择特定的输出字符,最终输出如下:
13. 用变长数组( VLA )代替标准数组,完成编程练习 12
14. 数字图像,尤其是从宇宙飞船发回的数字图像,可能会包含一些失真。为编程练习12 添加消除失真的函数。该函数把每个值与它上下左右相邻的值作比较,如果该值与其周围相邻值的差都大于1 ,则用所有相邻值的平均值(四舍五入为整数)代替该值。注意,与边界上的点相邻的点少于4
个,所以做特殊处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值