C Primer Plus 第八章“字符输入输出和输入验证”学习笔记

小结

许多程序使用 getchar()逐字符读取输入。通常,系统使用行缓冲输入(用户输入的字符被收集并储存在一个被称为缓冲区(buffer)的临时存储区,按下Enter键后,程序才可使用用户输入的字符)。按下Enter键也传送了一个换行符,编程时要注意处理这个换行符。ANSI C把缓冲输入作为标准。

为什么要有缓冲区?

首先,把若干字符作为一个进行传输比逐个发送这些字符节约时间。其次,如果用户打错字符,可以直接通过键盘修正错误。当最后按下Enter键时,传输的是正确的输入。

C 是一门强大、灵活的语言,有许多用于打开、读取、写入和关闭文件的库函数。

无论操作系统实际使用何种方法检测文件结尾,在C语言中,用getchar()读取文件检测到文件结尾时将返回一个特殊的值,即EOF(end offile的缩写)。scanf()函数检测到文件结尾时也返EOF。通常, EOF定义在stdio.h文件中:
#define EOF (-1)

使用该程序进行键盘输入,要设法输入EOF字符。正确的方法是,必须找出当前系统的要求。例如,在大多数UNIX和Linux系统中,在一行开始处按下Ctrl+D会传输文件结尾信号。许多微型计算机系统都把一行开始处的Ctrl+Z识别为文件结尾信号,一些系统把任意位置的Ctrl+Z解释成文件结尾信号。

可以用程序直接打开文件,待读取的文件应该与可执行文件位于同一目录。程序如下:

// file_eof.c --打开一个文件并显示该文件
#include<stdio.h>
#include<stdlib.h>       // 为了使用exit()
int main()
{
	int ch;
	FILE * fp;
	char fname[50];// 储存文件名
	printf("Enter the name of the file: ");
	scanf("%s", fname);
	fp=fopen(fname, "r");
	if(fp == NULL)	//如果失败 
	{
		printf("Failed to open file. Bye\n");
		exit(1);	// 退出程序
	}
	// getc(fp)从打开的文件中获取一个字符
	while((ch = getc(fp)) != EOF)
		putchar(ch);
	fclose(fp);	//关闭文件 
	return 0;
}


程序通常接受特殊形式的输入。可以在设计程序时考虑用户在输入时可能犯的错误,在输入验证部分处理这些错误情况,让程序更强健更友好。对于一个小型程序,输入验证可能是代码中最复杂的部分。处理这类问题有多种方案。例如,如果用户输入错误类型的信息,可以终止程序,也可以给用户提供有限次或无限次机会重新输入。

程序遵循模块化的编程思想,使用独立函数(模块)来验证输入和管理显示。程序越大,使用模块化编程就越重要。

复习题

复习题的参考答案在附录A中。

1.putchar(getchar())是一个有效表达式,它实现什么功能?
getchar(putchar())是否也是有效表达式?

表达式 putchar(getchar())使程序读取下一个输入字符并打印出来。getchar()的返回值是putchar()的参数。

但 getchar(putchar())是无效的表达式,因为getchar()不需要参数,而putchar()需要一个参数。

2.下面的语句分别完成什么任务?
a.putchar('H');
b.putchar('\007');
c.putchar('\n');
d.putchar('\b');

a.显示字符 H。
b.如果系统使用ASCII,则发出一声警报。
c.把光标移至下一行的开始。
d.退后一格。

3.假设有一个名为 count 的可执行程序,用于统计输入的字符数。设计一个使用 count 程序统计essay文件中字符数的命令行,并把统计结果保存在essayct文件中。

 count<essay >essayct或者count >essayct<essay

4.给定复习题3中的程序和文件,下面哪一条是有效的命令?
a.essayct <essay
b.count essay
c.essay >count

都不是有效的命令。

5.EOF是什么?
EOF是由getchar()和scanf()返回的信号(一个特殊值),表明函数检测到文件结尾。

7.C如何处理不同计算机系统中的不同文件和换行约定?

C的标准 I/0库把不同的文件映射为统一的流来统一处理。

8.在使用缓冲输入的系统中,把数值和字符混合输入会遇到什么潜在的问题?

数值输入会跳过空格和换行符,但是字符输入不会。

编程练习

1.设计一个程序,统计在读到文件结尾之前读取的字符数。

/* Programming Exercise 8-1 */
#include <stdio.h>
int main(void)
{
	int ch;
	int ct = 0;
	while ((ch = getchar()) != EOF)
		ct++;
	printf("%d characters read\n", ct);
	return 0;
}

3.编写一个程序,在遇到 EOF 之前,把输入作为字符流读取。该程序要报告输入中的大写字母和小写字母的个数。假设大小写字母数值是连续的。或者使用ctype.h库中合适的分类函数更方便。

/* Programming Exercise 8-3 */
/* Using ctype.h eliminates need to assume consecutive coding */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
	int ch;
	unsigned long uct = 0;
	unsigned long lct = 0;
	unsigned long oct = 0;
	while ((ch = getchar()) != EOF)
		if (isupper(ch))
			uct++;
		else if (islower(ch))
			lct++;
		else
			oct++;
	printf("%lu uppercase characters read\n", uct);
	printf("%lu lowercase characters read\n", lct);
	printf("%lu other characters read\n", oct);
	return 0;
}
/*
or you could use
if (ch >= 'A' && ch <= 'Z')
	uct++;
else if (ch >= 'a' && ch <= 'z')
	lct++;
else
	oct++;
*/

5.修改程序清单8.4的猜数字程序,使用更智能的猜测策略。例如,程序最初猜50,询问用户是猜大了、猜小了还是猜对了。如果猜小了,那么下一次猜测的值应是50和100中值,也就是75。如果这次猜大了,那么下一次猜测的值应是50和75的中值,等等。使用二分查找(binary search)策略,如果用户没有欺骗程序,那么程序很快就会猜到正确的答案。

/* Programming Exercise 8-5 */
/* binaryguess.c -- an improved number-guesser */
/* but relies upon truthful, correct responses */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
	int high = 100;
	int low = 1;
	int guess = (high + low) / 2;
	char response;
	printf("Pick an integer from 1 to 100. I will try to guess ");
	printf("it.\nRespond with a y if my guess is right, with");
	printf("\na h if it is high, and with an l if it is low.\n");
	printf("Uh...is your number %d?\n", guess);
	while ((response = getchar()) != 'y') /* get response */
	{
		if (response == '\n')
			continue;
		if (response != 'h' && response != 'l')
		{
			printf("I don't understand that response. Please enter h for\n");
			printf("high, l for low, or y for correct.\n");
			continue;
		}
		if (response == 'h')
			high = guess - 1;
		else if (response == 'l')
			low = guess + 1;
		guess = (high + low) / 2;
		printf("Well, then, is it %d?\n", guess);
	}
	printf("I knew I could do it!\n");
	return 0;
}

7.修改第7章的编程练习8,用字符代替数字标记菜单的选项。用q代替5作为结束输入的标记。

/* Programming Exercise 8-7 */
#include <stdio.h>
#include <ctype.h>
#include <stdio.h>
#define BASEPAY1 8.75 // $8.75 per hour
#define BASEPAY2 9.33 // $9.33 per hour
#define BASEPAY3 10.00 // $10.00 per hour
#define BASEPAY4 11.20 // $11.20 per hour
#define BASEHRS 40 // hours at basepay
#define OVERTIME 1.5 // 1.5 time
#define AMT1 300 // 1st rate tier
#define AMT2 150 // 2st rate tier
#define RATE1 0.15 // rate for 1st tier
#define RATE2 0.20 // rate for 2nd tier
#define RATE3 0.25 // rate for 3rd tier
int getfirst(void);
void menu(void);
int main(void)
{
	double hours;
	double gross;
	double net;
	double taxes;
	double pay;
	char response;
	menu();
	while ((response = getfirst()) != 'q')
	{
		if (response == '\n') /* skip over newlines */
			continue;
		response = tolower(response); /* accept A as a, etc. */
		switch (response)
		{
			case 'a': pay = BASEPAY1; break;
			case 'b': pay = BASEPAY2; break;
			case 'c': pay = BASEPAY3; break;
			case 'd': pay = BASEPAY4; break;
			default : printf("Please enter a, b, c, d, or q.\n");	
				menu();
				continue; // go to beginning of loop
		}
		printf("Enter the number of hours worked this week: ");
	scanf("%lf", &hours);
	if (hours <= BASEHRS)
	gross = hours * pay;
	else
	gross = BASEHRS * pay + (hours - BASEHRS) * pay * OVERTIME;
	if (gross <= AMT1)
	taxes = gross * RATE1;
	else if (gross <= AMT1 + AMT2)
	taxes = AMT1 * RATE1 + (gross - AMT1) * RATE2;
	else
	taxes = AMT1 * RATE1 + AMT2 * RATE2 + (gross - AMT1 - AMT2) * RATE3;
	net = gross - taxes;
	printf("gross: $%.2f; taxes: $%.2f; net: $%.2f\n", gross, taxes,net);
	menu();
}
	printf("Done.\n");
	return 0;
}
void menu(void)
{
	printf("********************************************************""*********\n");
	printf("Enter the letter corresponding to the desired pay rate"" or action:\n");
	printf("a) $%4.2f/hr b) $%4.2f/hr\n", BASEPAY1,BASEPAY2);
	printf("c) $%5.2f/hr d) $%5.2f/hr\n", BASEPAY3,
	BASEPAY4);
	printf("q) quit\n");
	printf("********************************************************""*********\n");
}
int getfirst(void)
{
	int ch;
	ch = getchar();
	while (isspace(ch))
	ch = getchar();
	while (getchar() != '\n')
	continue;
	return ch;
}

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值