学习C语言第三天
1.3 for语句
对于特定任务我们可以采用多种方法来编写程序。下面用for循环实现温度转换程序的功能。
#include <stdio.h>
/* 打印华氏温度-摄氏温度对照表 */
main() {
int fahr;
for (fahr = 0; fahr <= 300; fahr = fahr + 20)
printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr -32));
}
while循环和for循环执行结果相同,但程序本身有所不同。做主要的改进是去掉了大部分变量,而值使用了一个int类型的变量fahr。温度的下限、上限和步长都是常量,而计算摄氏温度的表达式现在变成了printf函数的第三个参数,不再是一个单独的赋值语句。
C语言中一个通用规则:在允许使用某种类型变量值的任何场合,都可以使用该类型的更复杂的表达式。
for语句是对while语句的推广,更直观一些。圆括号中包含3个部分,各部分之间用分号隔开。第一部分
fahr = 0
是初始化部分,仅在进入循环前执行一次。第二部分
fahr <= 300
是控制循环的测试或条件部分。循环控制将对条件求值,如果结果为真,则执行循环体。此后将执行第三个部分
fahr = fahr + 20
以将循环变量fahr增加一个步长,并再次对条件求值。如果计算得到的条件值为假,循环将终止执行。3部分内容都可以是任何表达式。
练习1-5 修改温度转换程序,要求以逆序(即按照从300度到0度的顺序)打印温度转换表。
#include <stdio.h>
/* 逆序打印华氏温度-摄氏温度表 */
main() {
int fahr;
for(fahr = 300; fahr >= 0; fahr = fahr - 20)
printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr -32));
}
______________________________________________________________________________
1.4 符号常量
在程序中使用300、20等类似的“幻数”并不是一个好习惯,他们几乎无法想以后阅读改程序的人提供什么信息,而且使程序的修改变得更加困难。处理这种幻数的一种方法是赋予它们有意义的名字。#define指令可以把符号名(或称为符号常量)定义为一个特定的字符串:
#define 名字 替换文本
在该定义后,程序中出现的所有在#define中定义的名字(既没有用引号引起来,也不是其它名字的一部分)都将用相应的替换文本替换。替换文本可以是任何字符序列,而不仅限于数字。
#include <stdio.h>
#define LOWER 0 /* 表的下限 */
#define UPPER 300 /* 表的上限 */
#define STEP 20 /* 步长*/
/* 打印华氏温度-摄氏温度对照表 */
main() {
int fahr;
for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr - 32));
}
其中,LOWER、UPPER与STEP都是符号常量,而非变量,因此不需要出现在声明中。符号常量名通常用大写字母拼写,这样可以很容易与用小写字母拼写的变量名相区别。注意,#define指令行的末尾没有分号。
1.5 字符输入/输出
接下来看一组与字符型数据处理有关的程序。许多程序只不过是这里讨论的程序原型的扩充版本而已。
标准库提供的输入/输出模型非常简单。无论文本从何处输入,输出到何处,其输入/输出都是按照字符流的方式处理。文本流是有多行字符构成的字符序列,而每行字符则由0个或者多个字符组成,行末是一个换行符。标准库负责使每个输入/输出六都能遵守这一模型。使用标准库的C语言程序员不必关心程序外这些行是如何表示的。
标准库提供了一次读/写一个字符的函数,其中最简单的是getchar和putchar两个函数。每次调用是,getchar函数从文本流中读入下一个输入字符,并将其作为结果值返回。也就是说,在执行语句
c = getchar()
之后,变量c中将包含输入流中的下一个字符。这种字符通常是通过键盘输入的。每次调用putchar函数时将打印一个字符。例如:
putchar(c)
将把整型变量c的内容以字符的形式打印出来,通常是显示在屏幕上。
1.5.1 文件复制
借助于getchar和putchar函数,可以在不了解其他输入/输出知识的情况下编写出数量惊人的有用代码。最简单的例子就是把输入 一次一个字符地复制到输出,其基本思想如下:
读一个字符
while(该字符不是文件结束符)
输出刚读入的字符
读入下一个字符
将上述基本思想转换为C语言程序为:
#include <stdio.h>
/* 将输入复制到输出:版本1*/
main() {
int c;
c = getchar();
while (c != EOF)
{
putchar(c);
c = getchar();
}
}
其中,关系运算符!=表示“不等于”。
字符在键盘、屏幕或其他任何地方无论以什么形式表现,它在机器内部都是以位模式存储的。char类型专门用于存储这种字符型数据,当然任何整型(int)也可以用于存储字符型数据。
这里需要解决如何区分文件中有效数据与输入结束符的问题。C语言采取的解决方法是:在没有输入时,getchar函数将返回一个特殊值,这个特殊值与任何实际字符都不同。这个值称为EOF(end of file,文件结束)。这里之所以不把c声明成char类型,是因为它必须足够大,除了能存储任何可能的字符外还要能存储文件结束符EOF。
EOF定义在文件<stdio.h>中,是一个整型数。其具体数值是什么并不重要,只要它与任何char类型的值都不相同即可。
在C语言中,类似于
c = getchar()
之类的赋值操作是一个表达式,并且具有一个值,即赋值后左边变量保存的值。也就是说,赋值可以作为更大的表达式的一部分出现。改写程序如下:
#include <stdio.h>
/* 将输入复制到输出:版本2*/
main() {
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
以上这段程序将输入集中化,getchar函数在程序中只出现了一次,这样就缩短了程序,整个程序看起来更紧凑。习惯这种风格后,读之就会发现按照这种方式编写的程序更易阅读。我们经常会看到这种风格。(不过,如果过多的使用这种类型的复杂语句,编写的程序可能会难以理解,应该尽量避免这种情况)。
不等于运算符!=的优先级必赋值运算符=的优先级高,这样在不使用圆括号的情况下关系测试!=将在赋值=操作之前执行。因此语句
c = getchar() != EOF
等价于语句
c = (getchar() != EOF)
该语句执行后,c的值将被置为0或1,这并不是我们希望的结果。
练习1-6 验证表达式getchar() != EOF 的值是0还是1.
练习1-7 编写一个打印EOF值的程序。
#include <stdio.h>
main() {
printf("练习1-6\n");
printf("%d\n", (getchar() != EOF)); // 正常情况下是1
printf("练习1-7\n");
printf("%d\n", EOF); // -1
}