一、循环简介
二、基本运算符
2.1 赋值运算符:=
2.2 加法运算符:+
2.3 减法运算符:-
2.4 符号运算符:-和+
2.5 乘法运算符:*
2.6 除法运算符:/
2.7 运算符优先级
2.8 优先级和求值顺序
三、其他运算符
3.1 sizeof运算符和size_t类型
3.2 求模运算符:%
3.3 递增运算符:++
3.4 递减运算符:--
3.5 优先级
3.6 不要自作聪明
四、表达式和语句
4.1 表达式
4.2 语句
副作用和序列点
4.3 复合语句
提示 风格提示
总结 表达式和语句
五、类型转换
5.1 强制类型转换运算符
六、带参数的函数
程序示例:
/* shoes1.c -- 把鞋码转换成英寸 */
#include
#define ADJUST 7.31 // 字符常量
int main(void)
{
const double SCALE = 0.333;// const变量
double shoe, foot;
shoe = 9.0;
foot = SCALE * shoe + ADJUST;
printf("Shoe size (men's) foot length\n");
printf("%10.1f %15.2f inches\n", shoe, foot);
getchar();
return 0;
}
运行结果:
Shoe size (men's) foot length
9.0 10.31 inches
运用循环解决重复运算的问题,原程序可改为:
/* shoes2.c -- 计算多个不同鞋码对应的脚长 */
#include
#define ADJUST 7.31 // 字符常量
int main(void)
{
const double SCALE = 0.333;// const变量
double shoe, foot;
printf("Shoe size (men's) foot length\n");
shoe = 3.0;
while (shoe < 18.5) /* while循环开始 */
{ /* 块开始 */
foot = SCALE * shoe + ADJUST;
printf("%10.1f %15.2f inches\n", shoe, foot);
shoe = shoe + 1.0;
} /* 块结束 */
printf("If the shoe fits, wear it.\n");
getchar();
return 0;
}
运行结果:
Shoe size (men's) foot length
3.0 8.31 inches
4.0 8.64 inches
5.0 8.97 inches
6.0 9.31 inches
7.0 9.64 inches
8.0 9.97 inches
9.0 10.31 inches
10.0 10.64 inches
11.0 10.97 inches
12.0 11.31 inches
13.0 11.64 inches
14.0 11.97 inches
15.0 12.30 inches
16.0 12.64 inches
17.0 12.97 inches
18.0 13.30 inches
If the shoe fits, wear it.
C用运算符(operator)表示算术运算。
用于基本算术运算的运算符:=、+、-、*和/(C没有指数运算符。C 的标准数学库提供了一个pow()函数用于指数运算。例如,pow(3.5, 2.2)返回3.5的2.2次幂)
赋值表达式语句的目的是把值储存到内存位置上。用于储存值的数据存储区域统称为数据对象(data object)。使用变量名是标识对象的一种方法。
左值(lvalue)是 C 语言的术语,用于标识特定数据对象的名称或表达式。因此,对象指的是实际的数据存储,而左值是用于标识或定位存储位置的标签。
可修改的左值( modifiable lvalue),用于标识可修改的对象。当前标准建议,使用术语对象定位值(object locatorvalue)更好。
注:对于早期的C语言,提到左值意味着:
1.它指定一个对象,所以引用内存中的地址;
2.它可用在赋值运算符的左侧,左值(lvalue)中的l源自left
一方面C继续把标识对象的表达式定义为左值,一方面某些左值却不能放在赋值运算符的左侧。有些左值不能用于赋值运算符的左侧。标准对左值的定义已经不能满足当前的状况,因此引入了新的术语。
右值(rvalue)指的是能赋值给可修改左值的量,且本身不是左值。右值可以是常量、变量或其他可求值的表达式(如,函数调用)。实际上,当前标准在描述这一概念时使用的是表达式的值(value of an expression),而不是右值。
补充:
加法运算符(addition operator)用于加法运算,使其两侧的值相加。
相加的值(运算对象)可以是变量,也可以是常量。
减法运算符(subtraction operator)用于减法运算,使其左侧的数减去右侧的数。
+和-运算符都被称为二元运算符(binary operator),即这些运算符需要两个运算对象才能完成操作。
减号还可用于标明或改变一个值的代数符号。
smokey = –rocky;以这种方式使用的负号被称为一元运算符(unary operator)。一元运算符只需要一个运算对象。
符号*表示乘法。C没有平方函数,可以使用乘法来计算平方。
/* squares.c -- 计算1~20的平方 */
#include
int main(void)
{
int num = 1;
while (num < 21)
{
printf("%4d %6d\n", num, num * num);
num = num + 1;
}
getchar();
return 0;
}
运行结果:
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
10 100
11 121
12 144
13 169
14 196
15 225
16 256
17 289
18 324
19 361
20 400
一个指数增长的例子:在棋盘的第1个方格里放1粒小麦、第2个方格里放2粒小麦、第3个方格里放4粒小麦,第4个方格里放 8 粒小麦,以此类推。
/* wheat.c -- 指数增长 */#include
#define SQUARES 64 // 棋盘中的方格数
int main(void)
{
const double CROP = 2E16; // 世界小麦年产谷粒数
double current, total;
int count = 1;
printf(" num");
printf(" added grains ");
printf("world total");
printf(" fraction\n");
total = current = 1.0; /* 从1颗谷粒开始 */
printf("%4d %13.2e %12.2e %12.2e\n", count, current,
total, total / CROP);
while (count < SQUARES)
{
count = count + 1;
current = 2.0 * current; /* 下一个方格谷粒翻倍 */
total = total + current; /* 更新总数 */
printf("%4d %13.2e %12.2e %12.2e\n", count, current,
total, total / CROP);
}
printf("That's all.\n");
getchar();
return 0;
}
运行结果:
num added grains world total fraction
1 1.00e+00 1.00e+00 5.00e-17
2 2.00e+00 3.00e+00 1.50e-16
3 4.00e+00 7.00e+00 3.50e-16
4 8.00e+00 1.50e+01 7.50e-16
5 1.60e+01 3.10e+01 1.55e-15
6 3.20e+01 6.30e+01 3.15e-15
7 6.40e+01 1.27e+02 6.35e-15
8 1.28e+02 2.55e+02 1.27e-14
9 2.56e+02 5.11e+02 2.55e-14
10 5.12e+02 1.02e+03 5.12e-14
11 1.02e+03 2.05e+03 1.02e-13
12 2.05e+03 4.10e+03 2.05e-13
13 4.10e+03 8.19e+03 4.10e-13
14 8.19e+03 1.64e+04 8.19e-13
15 1.64e+04 3.28e+04 1.64e-12
16 3.28e+04 6.55e+04 3.28e-12
17 6.55e+04 1.31e+05 6.55e-12
18 1.31e+05 2.62e+05 1.31e-11
19 2.62e+05 5.24e+05 2.62e-11
20 5.24e+05 1.05e+06 5.24e-11
21 1.05e+06 2.10e+06 1.05e-10
22 2.10e+06 4.19e+06 2.10e-10
23 4.19e+06 8.39e+06 4.19e-10
24 8.39e+06 1.68e+07 8.39e-10
25 1.68e+07 3.36e+07 1.68e-09
26 3.36e+07 6.71e+07 3.36e-09
27 6.71e+07 1.34e+08 6.71e-09
28 1.34e+08 2.68e+08 1.34e-08
29 2.68e+08 5.37e+08 2.68e-08
30 5.37e+08 1.07e+09 5.37e-08
31 1.07e+09 2.15e+09 1.07e-07
32 2.15e+09 4.29e+09 2.15e-07
33 4.29e+09 8.59e+09 4.29e-07
34 8.59e+09 1.72e+10 8.59e-07
35 1.72e+10 3.44e+10 1.72e-06
36 3.44e+10 6.87e+10 3.44e-06
37 6.87e+10 1.37e+11 6.87e-06
38 1.37e+11 2.75e+11 1.37e-05
39 2.75e+11 5.50e+11 2.75e-05
40 5.50e+11 1.10e+12 5.50e-05
41 1.10e+12 2.20e+12 1.10e-04
42 2.20e+12 4.40e+12 2.20e-04
43 4.40e+12 8.80e+12 4.40e-04
44 8.80e+12 1.76e+13 8.80e-04
45 1.76e+13 3.52e+13 1.76e-03
46 3.52e+13 7.04e+13 3.52e-03
47 7.04e+13 1.41e+14 7.04e-03
48 1.41e+14 2.81e+14 1.41e-02
49 2.81e+14 5.63e+14 2.81e-02
50 5.63e+14 1.13e+15 5.63e-02
51 1.13e+15 2.25e+15 1.13e-01
52 2.25e+15 4.50e+15 2.25e-01
53 4.50e+15 9.01e+15 4.50e-01
54 9.01e+15 1.80e+16 9.01e-01
55 1.80e+16 3.60e+16 1.80e+00
56 3.60e+16 7.21e+16 3.60e+00
57 7.21e+16 1.44e+17 7.21e+00
58 1.44e+17 2.88e+17 1.44e+01
59 2.88e+17 5.76e+17 2.88e+01
60 5.76e+17 1.15e+18 5.76e+01
61 1.15e+18 2.31e+18 1.15e+02
62 2.31e+18 4.61e+18 2.31e+02
63 4.61e+18 9.22e+18 4.61e+02
64 9.22e+18 1.84e+19 9.22e+02
That's all.
C使用符号/来表示除法。/左侧的值是被除数,右侧的值是除数。
浮点数除法的结果是浮点数,而整数除法的结果是整数。在C语言中,整数除法结果的小数
部分被丢弃,这一过程被称为截断(truncation)。
/* divide.c -- 演示除法 */
#include
int main(void)
{
printf("integer division: 5/4 is %d \n", 5 / 4);
printf("integer division: 6/3 is %d \n", 6 / 3);
printf("integer division: 7/4 is %d \n", 7 / 4);
printf("floating division: 7./4. is %1.2f \n", 7. / 4.);
printf("mixed division: 7./4 is %1.2f \n", 7. / 4);
printf("floating division: -3.8/3 is %1.2f \n", -3.8 / 3.);
printf("mixed division: -7/4 is %d \n", -7 / 4);
getchar();
return 0;
}
运行结果:
integer division: 5/4 is 1
integer division: 6/3 is 2
integer division: 7/4 is 1
floating division: 7./4. is 1.75
mixed division: 7./4 is 1.75
floating division: -3.8/3 is -1.27
mixed division: -7/4 is -1
混合整数和浮点数计算的结果是浮点数。实际上,计算机不能真正用浮点数除以整数,编译器会把两个运算对象转换成相同的类型。本例中,在进行除法运算前,整数会被转换成浮点数。
C99标准以前,C语言给语言的实现者留有一些空间,让他们来决定如何进行负数的整数除法。
C99规定使用趋零截断。
C 语言有明确的规定,通过运算符优先级来解决操作顺序的问题。乘法和除法的优先级比加法和减法高。
如果两个运算符的优先级相同怎么办?
如果它们处理同一个运算对象,则根据它们在语句中出现的顺序来执行。对大多数运算符而言,这种情况都是按从左到右的顺序进行(=运算符除外)。
最先执行圆括号中的部分。圆括号内部按正常的规则执行。
运算符优先级为表达式中的求值顺序提供重要的依据,但是并没有规定所有的顺序。C 给语言的实现者留出选择的余地。
y = 6 * 12 + 5 * 20;
优先级并未规定到底先进行哪一个乘法。C 语言把主动权留给语言的实现者,根据不同的硬件来决定先计算前者还是后者。
结合律只适用于共享同一运算对象运算符。在该例中,两个*运算符并没有共享同一个运算对象,因此从左往右的结合律不适用于这种情况。
/* rules.c -- 优先级测试 */
#include
int main(void)
{
int top, score;
top = score = -(2 + 5) * 6 + (4 + 3 * (2 + 3));
printf("top = %d, score = %d\n", top, score);
getchar();
return 0;
}
运行结果:
top = -23, score = -23
圆括号的优先级最高。先计算-(2 + 5) * 6中的圆括号部分,还是先计算(4 + 3 * (2 + 3))中的圆括号部分取决于具体的实现。
运算对象可以是具体的数据对象(如,变量名)或类型。如果运算对象是类型(如,float),则必须用圆括号将其括起来。
#include
int main(void)
{
int n = 0;
size_t intsize;
intsize = sizeof(int);
printf("n = %d, n has %zd bytes; all ints have\
%zd bytes.\n",n, sizeof n, intsize);
getchar();
return 0;
}
运行结果:
n = 0, n has 4 bytes; all ints have 4 bytes.
C 语言规定,sizeof 返回 size_t 类型的值。这是一个无符号整数类型,但它不是新类型。
解释:
C有一个typedef机制
例如:typedef double real; 这样,real就是double的别名。
类似地,C 头文件系统可以使用 typedef 把 size_t 作为 unsigned int 或unsigned long的别名。这样,在使用size_t类型时,编译器会根据不同的系统替换标准类型。
C99 做了进一步调整,新增了%zd 转换说明用于 printf()显示 size_t类型的值。如果系统不支持%zd,可使用%u或%lu代替%zd
求模运算符(modulus operator)用于整数运算。求模运算符给出其左侧整数除以右侧整数的余数(remainder)。
求模运算符只能用于整数,不能用于浮点数。
// min_sec.c -- 把秒数转换成分和秒
#include
#define SEC_PER_MIN 60 // 1分钟60秒
int main(void)
{
int sec, min, left;
printf("Convert seconds to minutes and seconds!\n");
printf("Enter the number of seconds (<=0 to quit):\n");
scanf("%d", &sec); // 读取秒数
while (sec > 0)
{
min = sec / SEC_PER_MIN; // 截断分钟数
left = sec % SEC_PER_MIN; // 剩下的秒数
printf("%d seconds is %d minutes, %d seconds.\n",
sec,min, left);
printf("Enter next value (<=0 to quit):\n");
scanf("%d", &sec);
}
printf("Done!\n");
getchar();
getchar();
return 0;
}
运行结果:
Convert seconds to minutes and seconds!
Enter the number of seconds (<=0 to quit):
80
80 seconds is 1 minutes, 20 seconds.
Enter next value (<=0 to quit):
1200
1200 seconds is 20 minutes, 0 seconds.
Enter next value (<=0 to quit):
-3
Done!
该程序中,使用scanf()为变量sec获取一个新值,并通过SEC新值的情况来决定循环是否进行,相比与使用计数器来控制while循环,这又是一种新的控制循环的方法。这两种情况设计的要点是,每次循环都会修改被测试的变量值。
C99规定“趋零截断”之后,如果第1个运算对象是负数,那么求模的结果为负数;如果第1个运算对象是正数,那么求模的结果也是正数。
如果当前系统不支持C99标准,会显示不同的结果。实际上,标准规定:无论何种情况,只要a和b都是整数值,便可通过a - (a/b)*b来计算a%b。
递增运算符(increment operator)执行简单的任务,将其运算对象递增1。该运算符以两种方式出现。
两种模式的区别在于递增行为发生的时间不同。
两种模式的相同之处:
/* add_one.c -- 递增:前缀和后缀 */
#include
int main(void)
{
int ultra = 0, super = 0;
while (super < 5)
{
super++;
++ultra;
printf("super = %d, ultra = %d \n", super, ultra);
}
getchar();
return 0;
}
运行结果:
super = 1, ultra = 1
super = 2, ultra = 2
super = 3, ultra = 3
super = 4, ultra = 4
super = 5, ultra = 5
缩写形式的优点是:1、紧凑结构的代码让程序更为简洁,可读性更高。2、递增运算符通常生成的机器语言代码效率更高,因为它和实际的机器语言指令很相似。尽管如此,随着商家推出的C编译器越来越智能,这一优势可能会消失。
下面是一个代码缩短的例子:
///* 缩短代码 */
//#include
//#define ADJUST 7.31 // 字符常量
//int main(void)
//{
// const double SCALE = 0.333;// const变量
// double shoe, foot;
// printf("Shoe size (men's) foot length\n");
// shoe = 3.0;
// while (shoe < 18.5) /* while循环开始 */
// { /* 块开始 */
// foot = SCALE * shoe + ADJUST;
// printf("%10.1f %15.2f inches\n", shoe, foot);
// shoe = shoe + 1.0;
// } /* 块结束 */
// printf("If the shoe fits, wear it.\n");
// getchar();
// return 0;
//}
//将上面的代码缩短
#include
#define ADJUST 7.31 // 字符常量
int main(void)
{
const double SCALE = 0.333;// const变量
double shoe, foot;
printf("Shoe size (men's) foot length\n");
shoe = 2.0;
while (++shoe < 18.5)
{
foot = SCALE*shoe + ADJUST;
printf("%10.1f %20.2f inches\n", shoe, foot);
}
printf("If the shoe fits, wear it.\n");
getchar();
return 0;
}
两种模式的不同之处:
/* post_pre.c -- 前缀和后缀 */
#include
int main(void)
{
int a = 1, b = 1;
int a_post, pre_b;
a_post = a++; // 后缀递增
pre_b = ++b; // 前缀递增
printf("a a_post b pre_b \n");
printf("%1d %4d %4d %4d\n", a, a_post, b, pre_b);
getchar();
return 0;
}
运行结果:
a a_post b pre_b
2 1 2 2
单独使用递增运算符时(如,ego++;),使用哪种形式都没关系。但是,当运算符和运算对象是更复杂表达式的一部分时(如上面的示例),使用前缀或后缀的效果不同。
例如上面提到过的的代码:
while (++shoe < 18.5)
该测试条件相当于提供了一个鞋子尺码到18的表。如果使用shoe++而不是++shoes,尺码表会增至19。因为shoe会在与18.5进行比较之后才递增,而不是先递增再比较。
每种形式的递增运算符都有一个递减运算符(decrement operator)与之对应,用--代替++即可。
#include
#define MAX 100
int main(void)
{
int count = MAX + 1;
while (--count > 0)
{
printf("%d bottles of spring water on the wall, ""%d bottles of spring water!\n", count, count);
printf("Take one down and pass it around,\n");
printf("%d bottles of spring water!\n\n", count - 1);
}
getchar();
return 0;
}
运行结果:
100 bottles of spring water on the wall, 100 bottles of spring water!
Take one down and pass it around,
99 bottles of spring water!
. . .
1 bottles of spring water on the wall, 1 bottles of spring water!
Take one down and pass it around,
0 bottles of spring water!
注:>运算符表示“大于”,<运算符表示“小于”,它们都是关系运算符(relational operator)。
递增运算符和递减运算符都有很高的结合优先级,只有圆括号的优先级比它们高。因此,x*y++表示的是(x)*(y++),而不是(x+y)++。不过后者无效,因为递增和递减运算符只能影响一个变量(或者,更普遍地说,只能影响一个可修改的左值),而组合x*y本身不是可修改的左值。
不要混淆这两个运算符的优先级和它们的求值顺序。例如:nextnum = (y + n++)*6; 根据优先级可以判断何时使用n的值对表达式求值,而递增运算符的性质决定了何时递增n的值。
如果n++是表达式的一部分,可将其视为“先使用n,再递增”;而++n则表示“先递增n,再使用”。
#include
int main(void)
{
int num=5;
while (num < 6)
{
printf("%10d %10d\n", num, num*num++);
}
getchar();
return 0;
}
运行结果:
6 25
该程序的问题是:当 printf()获取待打印的值时,可能先对最后一个参数( )求值,这样在获取其他参数的值之前就递增了num。在C语言中,编译器可以自行选择先对函数中的哪个参数求值。
#include
int main(void)
{
float ans;
int num = 4;
ans = num / 2 + 5 * (1 + num++);
printf("%.2f", ans);
getchar();
return 0;
}
运行结果:
27.00
该程序的问题是:
编译器可能不会按预想的顺序来执行。你可能认为,先计算第1项(num/2),接着计算第2项(5*(1 +num++))。但是,编译器可能先计算第2项,递增num,然后在num/2中使用num递增后的新值。因此,无法保证编译器到底先计算哪一项。
同理,下面的情况也不确定:
n = 3;
y = n++ + n++;
在使用递增递减运算符须遵循以下规则:
表达式(expression)由运算符和运算对象组成。最简单的表达式是一个单独的运算对象。
运算对象可以是常量、变量或二者的组合。一些表达式由子表达式(subexpression)组成。
C 表达式的一个最重要的特性是,每个表达式都有一个值。
语句(statement)是C程序的基本构建块。一条语句相当于一条完整的计算机指令。在C中,大部分语句都以分号结尾。
最简单的语句是空语句。
C把末尾加上一个分号的表达式都看作是一条语句(即,表达式语句)。
语句可以改变值或调用函数。
并不是所有的指令都是语句。例如:x = 6 + (y = 5);y = 5是一条完整的指令,但是它只是语句的
一部分。
/* addemup.c -- 几种常见的语句 */#include
int main(void) /* 计算前20个整数的和 */
{
int count, sum; /* 声明 */
count = 0; /* 表达式语句 */
sum = 0; /* 表达式语句 */
while (count++ < 20) /* 迭代语句 */
sum = sum + count;
printf("sum = %d\n", sum); /* 表达式语句 */
getchar();
return 0; /* 跳转语句 */
}
运行结果:
sum = 210
术语副作用(side effect):副作用是对数据对象或文件的修改。
例如:表达式states = 50,C会对其求值得50。对该表达式求值的副作用是把变量states的值改为50。类似地,调用 printf()函数时,它显示的信息其实是副作用(printf()的返回值是待显示字符的个数)。
序列点(sequence point)是程序执行的点,在该点上,所有的副作用都在进入下一步之前发生。
在 C语言中,语句中的分号标记了一个序列点。一些运算符也有序列点。
任何一个完整表达式的结束也是一个序列点。完整表达式(full expression)是指这个表达式不是另一个更大表达式的子表达式。
复合语句(compound statement)是用花括号括起来的一条或多条语句,复合语句也称为块(block)。
缩进对编译器不起作用,编译器通过花括号和while循环的结构来识别和解释指令。
表达式:表达式由运算符和运算对象组成。最简单的表达式是不带运算符的一个常量或变量。
语句:简单语句以一个分号结尾。复合语句(或块)由花括号括起来的一条或多条语句组成。
在语句和表达式中应使用类型相同的变量和常量。如果使用混合类型,C会采用一套规则进行自动类型转换。一些基本的类型转换规则:
待赋值的值与目标类型不匹配时,规则如下:
/* convert.c -- 自动类型转换 */
#include
int main(void)
{
char ch;
int i;
float fl;
fl = i = ch = 'C'; /* 第9行 */
printf("ch = %c, i = %d, fl = %2.2f\n", ch, i, fl); /* 第10行 */
ch = ch + 1; /* 第11行 */
i = fl + 2 * ch; /* 第12行 */
fl = 2.0 * ch + i; /* 第13行*/
printf("ch = %c, i = %d, fl = %2.2f\n", ch, i, fl); /* 第14行 */
ch = 1107; /* 第15行 */ //1107%265=83
printf("Now ch = %c\n", ch); /* 第16行 */
ch = 80.89; /* 第17行 */ //截断为83
printf("Now ch = %c\n", ch); /* 第18行 */
getchar();
return 0;
}
运行结果:
ch = C, i = 67, fl = 67.00
ch = D, i = 203, fl = 339.00
Now ch = S
Now ch = P
强制类型转换(cast):在某个量的前面放置用圆括号括起来的类型名,该类型名即是希望转换成的目标类型。
圆括号和它括起来的类型名构成了强制类型转换运算符(castoperator)。
/* pound.c -- 定义一个带一个参数的函数 */
#include
void pound(int n);// ANSI函数原型声明
int main(void)
{
int times = 5;
char ch = '!'; // ASCII码是33
float f = 6.0f;
pound(times); // int类型的参数
pound(ch); // 和pound((int)ch);相同
pound(f); // 和pound((int)f);相同
getchar();
return 0;
}
void pound(int n) // ANSI风格函数头
{ // 表明该函数接受一个int类型的参数
while (n-- > 0)
printf("#");
printf("\n");
}
运行结果:
#####
#################################
######
声明参数就创建了被称为形式参数(formal parameter,简称形参)的变量。n
函数调用传递的值为实际参数(actual argument),简称实参。10
变量名是函数私有的,即在函数中定义的函数名不会和别处的相同名称发生冲突。
注:在ANSI C之前,C使用的是函数声明,而不是函数原型。函数声明只指明了函数名和返回类型,没有指明参数类型。为了向下兼容,C现在仍然允许这样的形式:
void pound(); /* ANSI C之前的函数声明 */
示例程序:
// running.c -- A useful program for runners
#include
const int S_PER_M = 60; // 1分钟的秒数
const int S_PER_H = 3600; // 1小时的秒数
const double M_PER_K = 0.62137; // 1公里的英里数
int main(void)
{
double distk, distm; // 跑过的距离(分别以公里和英里为单位)
double rate; // 平均速度(以英里/小时为单位)
int min, sec; // 跑步用时(以分钟和秒为单位)
int time; // 跑步用时(以秒为单位)
double mtime; // 跑1英里需要的时间,以秒为单位
int mmin, msec; // 跑1英里需要的时间,以分钟和秒为单位
printf("This program converts your time for a metricrace\n");
printf("to a time for running a mile and to your average\n");
printf("speed in miles per hour.\n");
printf("Please enter, in kilometers, the distance run.\n");
scanf("%lf", &distk); // %lf表示读取一个double类型的值
printf("Next enter the time in minutes and seconds.\n");
printf("Begin by entering the minutes.\n");
scanf("%d", &min);
printf("Now enter the seconds.\n");
scanf("%d", &sec);
time = S_PER_M * min + sec; // 把时间转换成秒
distm = M_PER_K * distk; // 把公里转换成英里
rate = distm / time * S_PER_H; // 英里/秒×秒/小时 = 英里/小时
mtime = (double)time / distm; // 时间/距离 = 跑1英里所用的时间
mmin = (int)mtime / S_PER_M; // 求出分钟数
msec = (int)mtime % S_PER_M; // 求出剩余的秒数
printf("You ran %1.2f km (%1.2f miles) in %d min,%d sec.\n",
distk, distm, min, sec);
printf("That pace corresponds to running a mile in%d min, ",
mmin);
printf("%d sec.\nYour average speed was %1.2f mph.\n",
msec,rate);
getchar();
getchar();
return 0;
}
运行结果:
This program converts your time for a metricrace
to a time for running a mile and to your average
speed in miles per hour.
Please enter, in kilometers, the distance run.
5.5
Next enter the time in minutes and seconds.
Begin by entering the minutes.
20
Now enter the seconds.
20
You ran 5.50 km (3.42 miles) in 20 min,20 sec.
That pace corresponds to running a mile in5 min, 56 sec.
Your average speed was 10.08 mph.