1.2 变量及其输入
1.1节的程序虽好,但有一个遗憾:计算的数据是事先确定的。为了计算1+2和2+3,下面不得不编写两个程序。可不可以让程序读取键盘输入,并根据输入内容计算结果呢?答案是肯定的。程序如下:
程序1-4 a+b问题
#include<stdio.h>
int main()
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", a+b);
return 0;
}
该程序比1.1节的复杂了许多。简单地说,第一条语句“int a, b”声明了两个整型(即整数类型)变量a和b,然后读取键盘输入,并放到a和b中。注意a和b前面的“&”符号——千万不要漏掉,不信可以试试(2)。
现在,你的程序已经读入了两个整数,可以在表达式中自由使用它们,就好比使用12、597这样的常数。这样,表达式a+b就不难理解了。
提示1-3:scanf中的占位符和变量的数据类型应一一对应,且每个变量前需要加“&”符号。
可以暂时把变量理解成“存放值的场所”,或者形象地认为每个变量都是一个盒子、瓶子或箱子。在C语言中,变量有自己的数据类型,例如,int型变量存放整数值,而double型变量存放浮点数值(专业的说法是“双精度”浮点数)。如果一定要把浮点数值存放在一个int型变量中,将会丢失部分信息——我们不推荐这样做。
下面来看一个复杂一点的例子。
例题1-1 圆柱体的表面积
输入底面半径r和高h,输出圆柱体的表面积,保留3位小数,格式见样例。
样例输入:
3.5 9
样例输出:
Area = 274.889
【分析】
圆柱体的表面积由3部分组成:上底面积、下底面积和侧面积。由于上下底面积相等,完整的公式可以写成:表面积=底面积×2+侧面积。根据几何知识,底面积=πr2,侧面积=2πrh。不难写出完整程序:
程序1-5 圆柱体的表面积
#include<stdio.h>
#include<math.h>
int main()
{
const double pi = acos(-1.0);
double r, h, s1, s2, s;
scanf("%lf%lf", &r, &h);
s1 = pi*r*r;
s2 = 2*pi*r*h;
s = s1*2.0 + s2;
printf("Area = %.3f\n", s)
return 0;
}
这是本书中第一个完整的“竞赛题目”,因为和正规比赛一样,题目中包含着输入输出格式规定,还有样例数据。大多数的算法竞赛包含如下一些相同的“游戏规则”。
首先,选手程序的执行是自动完成的,没有人工干预。不要在用户输入之前打印提示信息(例如“Please input n:”),这不仅不会为程序赢得更高的“界面友好分”,反而会让程序丢掉大量的(甚至所有的)分数——这些提示信息会被当作输出数据的一部分。例如,刚才的程序如果加上了“友好提示”,输出信息将变成:
Please input n:
Area = 274.889
比标准答案多了整整一行!
其次,不要让程序“按任意键退出”(例如,调用system("pause"),或者添加一个多余的getchar()),因为不会有人来“按任意键”的。不少早期的C语言教材会建议在程序的最后添加这样一条语句来“观察输出结果”,但注意千万不要在算法竞赛中这样做。
提示1-4:在算法竞赛中,输入前不要打印提示信息。输出完毕后应立即终止程序,不要等待用户按键,因为输入输出过程都是自动的,没有人工干预。
在一般情况下,你的程序不能直接读取键盘和控制屏幕:不要在算法竞赛中使用getch()、getche()、gotoxy()和clrscr()函数(早期的教材中可能会介绍这些函数)。
提示1-5:在算法竞赛中不要使用头文件conio.h,包括getch()、clrscr()等函数。
最后,最容易忽略的是输出的格式:在很多情况下,输出格式是非常严格的,多一个或者少一个字符都是不可以的!
提示1-6:在算法竞赛中,每行输出均应以回车符结束,包括最后一行。除非特别说明,每行的行首不应有空格,但行末通常可以有多余空格。另外,输出的每两个数或者字符串之间应以单个空格隔开。
总结一下,算法竞赛的程序应当只做3件事情:读入数据、计算结果、打印输出。不要打印提示信息,不要在打印输出后“暂停程序”,更不要尝试画图、访问网络等与算法无关的任务。
回到刚才的程序,它多了几个新内容。首先是“const double pi = acos(-1.0);”。这里也声明了一个叫pi的“符号”,但是const关键字表明它的值是不可以改变的——pi是一个真正的数学常数(3)。
提示1-7:尽量用const关键字声明常数。
接下来是s1 = pi * r * r。这条语句应该如何理解呢?“s1等于pi*r*r”吗?并不是这样的。若把它换成“pi * r * r = s1”,编译器会给出错误信息:invalid value in assignment。如果这条语句真的是“二者相等”的意思,为何不允许反着写呢?
事实上,这条语句的学术说法是赋值(assignment),它不是一个描述,而是一个动作。其确切含义是:先把“等号”右边的值算出来,然后赋于左边的变量中。注意,变量是“喜新厌旧”的,即新的值将覆盖原来的值,一旦被赋了新的值,变量中原来的值就丢失了。
提示1-8:赋值是个动作,先计算右边的值,再赋给左边的变量,覆盖它原来的值。
最后是“Area = %.3f\n”,该语句的用法很容易被猜到:只有以“%”开头的部分才会被后面的值替换掉,其他部分原样输出。
提示1-9:printf的格式字符串中可以包含其他可打印符号,打印时原样输出。
这里还有一个非常容易忽略的细节:输入采用的是"%lf"而不是"%f"。关于这一点,本章的末尾会继续讨论,现在先跳过。