1.2. 变量与算术表达式
用℃=(5/9)(℉-32)打印华氏与摄氏温度的对应关系:
1 -17
20 -6
40 4
60 15
80 26
100 37
120 48
140 60
160 71
180 82
200 93
220 104
240 115
260 126
280 137
300 148
程序仍只含一个名为main的函数定义。比helloworld长,并不复杂。程序引入了新概念,含注释、声明变量、算术表达式、循环以及格式化输出。
#include <stdio.h>
/*当fahr=0,20,…,300时,分别打印华氏温度与摄氏温度对照表*/
main()
{
int fahr, celsius;
int lower, upper,step;
lower = 0;
upper = 300;
step = 20;
fahr = lower;
while (fahr<=upper){
celsius = 5*(fahr-32)/9;
printf("%d\t,%d\n",fahr,celsius);
fahr=fahr+step;
}
}
其中/*……*/称为注释,解释该程序的作用。/**/之间内容被编译器忽略。注释自由,使程序易懂。程序中允许出现空格、制表符或换行符的位置都可以用注释。
C语言中,所有变量都要先声明后使用。声明常放在函数起始处,在任何可执行语句之前。声明用于说明变量的属性,由一个类型名和一个变量表组成。如:
int fahr, celsius;
int lower, upper, step;
类型int表示其后所列变量为整数,相应地,float表所列变量为浮点数(可带有小数部分的数)。int与float的取值范围取决于具体的机器。int类型通常为16位,范围在-32768~32767之间,也有用32位表示的int类型。
除int和float外,C语言还有其它基本数据类型:
char 字符——一个字节
short 短整型
long 长整形
double 双精度浮点型
数据类型对象的大小也取决于具体机器。 另外,还存在这些基本数据类型的数组、结构、联合、指向这些数据类型的指针以及返回这些数据类型的函数。在后续相应章节介绍。
程序中最开始执行的计算是下列4个赋值语句:
lower = 0;
upper = 300;
step = 20;
fahr = lower;
它们为变量设置初值。各语句均以分号结束。
温度转换表中的各行计算方式相同,因此可用循环语句重复输出各行。这是while循环的用途:
while(fahr<=upper){
……
}
while循环执行:先测试圆括号里的条件;条件为真(fahr<=upper),则循环体(括在花括号中的3条语句);再重新测试圆括号中的条件,如果为真,再次执行循环;当圆括号中的测试条件结果为假(fahr>upper)时,循环结束,并继续执行跟在while循环语句后的下一条语句。没有语句则停止。 while循环体可以是花括号括起来的一或多条语句,也可以是不用花括号包括的单条语句,如:
while(i<j)
i=2*j;
这两种情况下,总把由while控制语句缩进一个制表位,可容易地看出循环语句中包含哪些语句。这缩进方式突出程序逻辑结构。尽管C编译器并不关心程序的外观形式,但正确的缩进以及保留适当空格的设计风格对程序的易读性很重要。建议每行只写一条语句,并在运算符两边各加上一个空格字符,使得运算的结合关系更明了。
相比而言,花括号的位置不那么重要。从比较流行的风格中选一种,读者可自选风格,并一直使用,习惯。
该程序中,绝大部分工作都在while循环里完成。赋值语句
celsius = 5*(fahr - 32) / 9;
用于计算与指定华氏温度相对应的摄氏温度值,并将结果赋值给变量celsius。句中,把表达式写成先乘5再除以9而不是直接写成5 / 9,原因是在C语言及许多其他语言中,整数除法操作将执行舍位,结果中的任何小数部分都会被舍弃。由于5和9都是整数,5 / 9相除后经截取所得的结果为0,因此这样求得的所有摄氏温度都将为0。
从例子中可看到printf函数的一些功能。printf是个通用输出格式化函数,第七章将详讲。该函数第一个参数是待打印的字符串,其中每个百分号表示其它的参数之一进行替换的位置,并指定打印格式。如,%d指定一个整形参数,因此语句
printf("%d\t%d\n", fahr, celsius);
用于打印两个整数fahr与celsius的值,并在两者之间留一个制表符的空间(\t)。
printf函数的第一个参数中各个%分别对应于第二、第三个、……参数,在数目和类型上都必须匹配,否则将有错误结果。
顺便,printf函数并不是C语言本身的一部分,C语言本身并没有定义输入/输出功能。它仅是标准库函数中一个有用的函数,这些标准库函数在C语言程序中通常都可以使用。但ANSI标准定义了printf函数的行为,因此,对每个符合该标准的编译器和库来说,该函数的属性都是相同的。
为将重点放在讲述C语言本身上 ,在第七章之前的各章中不再对输入输出作更多介绍,而且,特别将格式化输入推后到第七章讲解。如读者想了解数据输入,可以先读7.4节中对scanf函数的讨论部分,scanf类似于printf,但用于读输入数据而不是写输出数据。
上述程序有两个问题。简单问题是,由于输出的数不是右对齐,所以输出的结果不是很美观。易解决:如果在printf语句的第一个参数的%d中指明打印宽度,则打印的数字会在打印区域内右对齐。例如,用语句:
printf("%3d %6d\n", fahr, celsius);
打印fahr与celsius的值,这样,fahr占3个数字宽,celsius的值占6个数字宽,输出的结果如下:
0 -17
20 -6
40 4
60 15
80 26
100 37
……
另一个较严重问题,使用的整形算术运算,计算得到的摄氏温度不太精准,如,与0℉对应的精确的摄氏温度应该是-17.8℃,而不是-17℃。这需要对程序修改。
#include <stdio.h>
/* print Fahrenheit-Celsius table
for fahr = 0, 20, ..., 300; floating-point version */
main()
{
float fahr, celsius;
float lower, upper, step;
lower = 0; /* lower limit of temperatuire scale */
upper = 300; /* upper limit */
step = 20; /* step size */
fahr = lower;
while (fahr <= upper) {
celsius = (5.0/9.0) * (fahr-32.0);
printf("%3.0f %6.1f\n", fahr, celsius);
fahr = fahr + step;
}
}
不同之处在于把fahr与celsius声明为float类型,转换公式的表述方式也更自然一些。在前程序中,不能用5 / 9的形式是因为按整形除法的计算规则,相除并舍位后得到的结果为0。但常数中的小数点表明该常数是个浮点数,因此,5.0 / 9.0 是两个浮点数相除,结果不会被舍位。
如果某个算术运算符的所有操作数均为整形,则执行整形运算。但如果某个算术运算符有一个浮点型操作数和一个整型操作数,则在开始运算之前整形操作数将会被转换成浮点型。例如,fahr - 32中,32在运算过程中将被自动转换为浮点数在参与运算。不过,即使浮点常量取的是整型值,在书写时最好还是为它加上一个显式小数点,可以强调其浮点性质,便于阅读。
第 2 章将详细介绍把整型数转换为浮点型数的规则。在这里需要注意,赋值语句
fahr = lower;
与条件测试语句
while(fahr <= upper)
也都是按这种方式执行,即运算之前把int操作数转为float型。
printf中的转换说明%3.0f表明待打印的浮点数(即fahr)至少占3个字符宽,且不
带小数点和小数部分;%6.1f表明另一个待打印的数(celsius)至少占6个字符宽,且小
数点后面有1位数字。其输出如下所示:
0 -17.8
20 -6.7
40 4.4
……
格式说明可以省略宽度与精度,例如,%6f表示待打印的浮点数至少有6个字符宽;%.2f
指定待打印的浮点数的小数点后有两位小数,但宽度没有限制;%f 则仅仅要求按照浮点数打
印该数。
%d //按照十进制整型数打印
%6d //按照十进制整型数打印,至少6个字符宽
%f //按照浮点数打印
%6f //按照浮点数打印,至少6个字符宽
%.2f //按照浮点数打印,小数点后有两位小数
%6.2f //按照浮点数打印,至少6个字符宽,小数点后有两位小数
此外,printf 函数还支持下列格式说明:%o 表示八进制数;%x 表示十六进制数;%c
表示字符;%s表示字符串;%%表示百分号(%)本身。
练习 1-3 修改温度转换程序,使之能在转换表的顶部打印一个标题。
练习 1-4 编写一个程序打印摄氏温度转换为相应华氏温度的转换表。