1、计算增长率
假如我国国民生产总值的年增长率为7%,计算 10 年后我国国民生产总值与现在相比增长多少百分比。计算公式为
r 为年增长率,n 为年数,p 为与现在相比的倍数。
解题思路:由公式可知,就是一个幂函数求解过程。
#include <stdio.h>
#include <math.h>
int main() {
float p, r = 0.07;
int n = 10;
p = pow(1 + r, (double)n); // 建议强制转换下,因会隐式转换
printf("p=%f\n", p);
return 0;
}
暴力循环:注意初始化 p = 1.0
即可。
#include <stdio.h>
#include <math.h>
int main() {
float p = 1.0, r = 0.07;
int n = 10;
// p = pow(1 + r, (double)n);
for (int i = 0; i < n; i++) {
p = p * (1 + r);
}
printf("p=%f\n", p);
return 0;
}
编译运行:编译需要链接 <math.h>
需要添加 -lm
选项。
:::success
b12@PC:~/chapter3$ gcc -Wall ./src/increaseRate.c -o ./bin/increaseRate -lm
b12@PC:~/chapter3$ ./bin/increaseRate
p=1.967152
:::
2、存款利息的计算
有1000元,想存5年,可按以下5种办法存:
- 一次存 5 年期。
- 先存 2 年期,到期后将本息再存 3 年期。
- 先存 3 年期,到期后将本息再存 2 年期。
- 存 1 年期,到期后将本息再存 1 年期,连续存 5 次。
- 存活期存款。活期利息每一季度结算一次。
2017 年的银行存款利息如下:
- 1 年期定期存款利息为 1.5%;
- 2 年期定期存款利息为 2.1%;
- 3 年期定期存款利息为 2.75%;
- 5 年期定期存款利息为 3%;
- 活期存款利息为 0.35%(活期存款每一季度结算一次利息)。
如果 r 为年利率,n 为存款年数,则计算本息和的公式如下:
- 1 年期本息和:
;
- n 年期本息和:
;
- 存 n 次 1 年期的本息和:
;
- 活期存款本息和:
,其中
表示一个季度(4 个月)的本息和
解题思路:题目已经规定好很多,浅显易懂,直接编码即可。重点就是活期存款问题。
#include <stdio.h>
#include <math.h>
int main() {
float r5, r3, r2, r1, r0, p, p1, p2, p3, p4, p5;
p = 1000;
r5 = 0.03;
r3 = 0.0275;
r2 = 0.0468;
r1 = 0.021;
r0 = 0.0035;
p1 = p * (1 + r5 * 5); // 5年
p2 = p * (1 + 2 * r2) * (1 + 3 * r3); // 先2年,到期本息和再存3年
p3 = p * (1 + 3 * r3) * (1 + 2 * r2); // 先3年,到期本息和再存2年
p4 = p * pow(1 + r1, 5); // 先1年,到期本息和再存1年,如此重复5次
p5 = p * pow(1 + r0 / 4, 4 * 5); // 活期,4个月结算一次
printf("p1 = %f\n", p1);
printf("p2 = %f\n", p2);
printf("p3 = %f\n", p3);
printf("p4 = %f\n", p4);
printf("p5 = %f\n", p5);
return 0;
}
编译运行:
:::success
b12@PC:~/chapter3$ gcc -Wall ./src/calInterests.c -o ./bin/calInerests -lm
b12@PC:~/chapter3$ ./bin/calInerests
p1 = 1150.000000
p2 = 1183.821899
p3 = 1183.822021
p4 = 1109.503784
p5 = 1017.646179
:::
书中讨论:
:::info
- gcc 对上面实数默认
double
转换为float
变量不会给予 warning,也不需要担心。除非给出警告,那么将上述变量全部定义为double
即可。 保留两位小数输出:正常生活中钱最精确只能到分和角,因此四舍五入(PS:这种四舍五入在实际中恐怕不行)保留两位小数,只需要将程序格式化输出
%.2f
即可。书中外加%5.2f
只为输出数字。下面对其格式化输出进行拓展。 :::#include <stdio.h>
#include <math.h>
int main() {
double r5, r3, r2, r1, r0, p, p1, p2, p3, p4, p5; // 此处更改为double
p = 1000;
r5 = 0.03;
r3 = 0.0275;
r2 = 0.0468;
r1 = 0.021;
r0 = 0.0035;
int n = 5;
p1 = p * (1 + r5 * 5); // 5年
p2 = p * (1 + 2 * r2) * (1 + 3 * r3); // 先2年,到期本息和再存3年
p3 = p * (1 + 3 * r3) * (1 + 2 * r2); // 先3年,到期本息和再存2年
p4 = p * pow(1 + r1, 5); // 先1年,到期本息和再存1年,如此重复5次
p5 = p * pow(1 + r0 / 4, 4 * 5); // 活期,4个月结算一次
printf("p1 = %10.2f\n", p1); // 右对齐输出(数据在右端),不足左边补空格,否则将不会截断
printf("p2 = %-10.3lf\n", p2); // 左对齐输出(数据在左端),不足右边补空格,否则将不会截断
printf("p3 = %3.8f\n", p3); // 左对齐输出(数据在左端),实际长度大于width不会截断
printf("p4 = %10.*f\n", n, p4); // 指定保留 n 位小数
printf("p5 = %f\n", p5); // 默认右对齐
return 0;
}
编译运行: :::success b12@PC:~/chapter3$ gcc -Wall ./src/calInterests2.c -o ./bin/calInerests2 -lm
b12@PC:~/chapter3$ ./bin/calInerests2
p1 = 1150.00
p2 = 1183.822
p3 = 1183.82200000
p4 = 1109.50359
p5 = 1017.646235 :::
3、计算月供
购房从银行贷了一笔款 d,准备每月还款额为 p,月利率为 r,计算多少月能还清。设 d 为 300000 元,p 为6000 元,r 为 1%。对求得的月份取小数点后一位,对第 2 位按四舍五入处理。
提示:计算还清月数 m 的公式如下:
C 的库函数中有求对数的函数 log10
,是求以 10 为底的对数,表示
。
4、分析下面的程序
#include <stdio.h>
int main() {
char c1, c2;
c1 = 97;
c2 = 98;
printf("c1=%c,c2=%c\n", c1, c2);
printf("c1=%d,c2=%d\n", c1, c2);
return 0;
}
(1)运行时会输出什么信息?为什么?
对上述程序编译运行:
:::success
b12@PC:~/chapter3$ gcc -Wall ./src/test4.c -o ./bin/test4
b12@PC:~/chapter3$ ./bin/test4
c1=a,c2=b
c1=97,c2=98
:::
因为字符型数据是以 ASCII 码的整数形式存在的。
- 第 1 行是将c1,c2按
%c
的格式输出,97 是字符 a 的 ASCII 码,98 是字符 b 的 ASCII 码。 - 第 2 行是将c1,c2按
%d
的格式输出,所以输出两个十进制整数。
(2)如果将程序第4,5行改为 c1=197;c2=198;
运行时会输出什么信息?为什么?
照着题目要求修改,编译运行:
:::success
b12@PC:~/chapter3$ gcc -Wall ./src/test4.c -o ./bin/test4
b12@PC:~/chapter3$ vi ./src/test4.c
b12@PC:~/chapter3$ ./bin/test4
c1=,c2=
c1=-59,c2=-58
:::
由于 gcc 编译器将字符作为,即认为是有符号的。即此处发生最高位符号位作为整形输出为负数的原因。
%d | 198 | 199 |
---|---|---|
二进制 | 1100 0110 | 1100 0111 |
%c | 1100 0110 | 1100 0111 |
如果改变 gcc 默认编码字符集呢?其实 shell 下没拓展的 ASCII 字符集,因此终端还是不会输出!gcc 支持 Unicode
(3)如果将程序第 3 行改为 int c1, c2;
运行时会输出什么信息?为什么?
如果给 c1 和 c2 赋的值是 197 和 198,则用 %c
输出时是不可预料的字符。用 %d
输出时,输出整数 197 和 198,因为它们在 int 类型的有效范围内。
5. scanf 输入
用下面的 scanf 函数输入数据,使 a=3,b=7,x=8.5,y=71.82,c1=’A’,c2=’a’。在键盘上应如何输入?
#include <stdio.h>
int main() {
int a, b;
float x,y;
char c1,c2;
scanf("a=%d b=%d",&a,&b);
scanf("%f %e",&x,&y);
scanf("%c%c",&c1,&c2);
printf("a=%d,b=%d,x=%f,y=%f,c1=%c,c2=%c\n",a,b,x,y,c1,c2);
return 0;
}
:::success
b12@PC:~/chapter3$ gcc -Wall ./src/scanf5.c -o ./bin/scanf5
b12@PC:~/chapter3$ ./bin/scanf5
a=3 b=7
6.6 9.9Bb
a=3,b=7,x=6.600000,y=9.900000,c1=B,c2=b
b12@PC:~/chapter3$ ./bin/scanf5
a=99 b=66
6.6 9.9 Bb
a=99,b=66,x=6.600000,y=9.900000,c1= ,c2=B
b12@PC:~/chapter3$ ./bin/scanf5
a=99 b=33
6.6 9.9
Bb
a=99,b=33,x=6.600000,y=9.900000,c1=
,c2=B
:::
- 第一次:在浮点数 y 之后紧跟着字符
Bb
,此时因为scanf("%f %e",&x,&y);
检测到字符B
表明此次输入结束,scanf
函数调用完毕而后进行scanf("%c%c",&c1,&c2);
刚好接受输入的字符。 - 第二次:在浮点数 y 之后空格分隔,后接字符
Bb
,此时因为scanf("%f %e",&x,&y);
检测到空格表明此次输入结束,scanf
函数调用完毕而后进行scanf("%c%c",&c1,&c2);
而接受第一个空格入c1
造成c2=B
而b
字符不见了!。 - 第二次:在浮点数 y 之后换行,后接字符
Bb
,此时因为scanf("%f %e",&x,&y);
检测到换行表明此次输入结束,scanf
函数调用完毕而后进行scanf("%c%c",&c1,&c2);
而接受此时的换行符入c1
造成c2=B
而b
字符不见了!。
遇到这种因为 scanf
引起的问题无法消除缓冲区内字符的情况,主要就是“配对”缓冲区或者“清空”缓冲区的内容。下面为了简单起见,使用较为简单的程序进行模拟:
scanf("%f %e\n",&x,&y);
使用格式控制字符在输入浮点数后匹配换行,则这个换行符被此scanf
函数“吸收”。#include <stdio.h>
int main() {
float x,y;
char c1,c2;
scanf("%f %e\n",&x,&y);
scanf("%c%c",&c1,&c2);
printf("x=%f,y=%f,c1=%c,c2=%c\n", x, y, c1, c2);
return 0;
}
编译运行: :::success b12@PC:~/chapter3$ gcc -Wall ./src/scanf5_1.c -o ./bin/scanf5_1
b12@PC:~/chapter3$ ./bin/scanf5_1
9.6 6.9
Ac
x=9.600000,y=6.900000,c1=A,c2=c :::scanf("\n%c%c",&c1,&c2);
前面进行格式匹配:跟上面原理类似#include <stdio.h>
int main() {
float x,y;
char c1,c2;
scanf("%f %e",&x,&y);
scanf("\n%c%c",&c1,&c2);
printf("x=%f,y=%f,c1=%c,c2=%c\n", x, y, c1, c2);
return 0;
}
编译运行: :::success b12@PC:~/chapter3$ gcc -Wall ./src/scanf5_2.c -o ./bin/scanf5_2
b12@PC:~/chapter3$ ./bin/scanf5_2
6.9 9.6
Kc
x=6.900000,y=9.600000,c1=K,c2=c :::使用
getchar()
函数“消灭”换行。#include <stdio.h>
int main() {
float x,y;
char c1,c2;
scanf("%f %e",&x,&y);
char ch = getchar();
printf("ch=%d,ch is %c\n", ch, ch);
scanf("%c%c",&c1,&c2);
printf("x=%f,y=%f,c1=%c,c2=%c\n", x, y, c1, c2);
return 0;
}
编译运行:此时在输入完浮点数之后就会输出
printf("ch=%d,ch is %c\n", ch, ch);
:::success b12@PC:~/chapter3$ gcc -Wall ./src/scanf5_3.c -o ./bin/scanf5_3
b12@PC:~/chapter3$ ./bin/scanf5_3
9.4 4.9
ch=10,ch is
So
x=9.400000,y=4.900000,c1=S,c2=o :::使用
fflush(stdin);
清空缓存区。网上说在stdlib.h
中,但是它不是 C 标准!很容易出错且不保险。原因#include <stdio.h>
#include <stdlib.h>
int main() {
float x,y;
char c1,c2;
scanf("%f %e",&x, &y);
fflush(stdin); // empty buffer
scanf("%c%c",&c1,&c2);
printf("x=%f,y=%f,c1=%c,c2=%c\n", x, y, c1, c2);
return 0;
}
:::success b12@PC:~/chapter3$ gcc -Wall ./src/scanf5_4.c -o ./bin/scanf5_4
b12@PC:~/chapter3$ ./bin/scanf5_4
5.5 2.3
Ak
x=5.500000,y=2.300000,c1=
,c2=A :::
综上,最为保险的方式就是使用吸收方法,或者避免产生这种情况(只能说这个函数设计有点意思!)。类似问题还有含空格字符串输入问题等,解决办法可以参考下:
未完!