1、什么是算术运算?什么是关系运算?什么是逻辑运算?

  1. 解:略。

2、C语言中如何表示“真”和“假”?系统如何判断一个量的“真”和“假”?

  • 对于逻辑表达式,若其值为“真”,则以1表示,若其值为“假”,则以0表示。
  • 但是在判断一个逻辑量的值时,系统会以0作为“假”,以非0作为“真”。例如3 && 5的值为“真”,系统给出3 && 5的值为1。

    3、写出下面各逻辑表达式的值。设a=3b=4c=5

  1. a + b > c && b == c0
    1. k = a + b = 7 则表达式为 k > 5 && b == c 可知左侧关系表达式 7 > 5 成立,则表达式为 1 && b == c
    2. 由于 b != c ,因此右侧关系表达式返回值为 0 ,则整个表达式 1 && 0 = 0
  2. a || b + c && b - c1
    1. 最先看到 || ,由于逻辑量 a = 3 是真,因此 || 短路运算直接返回 1
  3. !(a > b) && !c || 11
    1. ! 是右结合性继续向后看,但是遇到第二个操作符 ( 优先级比 ! 则先计算括号内的内容,即 (a > b) 返回值为 0
    2. !0 返回 1 ,因此整个表达式为 1 && !c || 1
    3. 遇到 !c 返回 0 ,由于 && 优先级高于 || ,因此先计算 && 部分即 (1 && 0) || 10 || 1 返回 1
  4. !(x = a) && (y = b) && 00
    1. ! 是右结合性继续向后看,但是遇到第二个操作符 ( 优先级比 ! 则先计算括号内的内容,即 (x = a) 赋值表达式给 x = 3 赋值成功并返回 3
    2. 此时表达式为 !3 && (y = b) && 0 ,则 !3 返回 0 ,则有 0 && (y = b) && 0 直接短路 && 后面表达式内容而返回 0
  5. !(a + b) + c - 1 && b + c / 21
    1. ! 是右结合性继续向后看,但是遇到第二个操作符 ( 优先级比 ! 则先计算括号内的内容,即 (a + b) 返回值为 7 ,此时表达式为 !7 + c - 1 && b + c / 20 + 5 - 1 && b + c / 2
    2. 算数运算表达式高于逻辑表达式:先计算 && 左侧算术表达式结果即 4 && b + c / 2,左侧算术表达式返回 4 逻辑量为真
    3. 继续右侧算术表达式4 && b + c / 2:由于 + 二元运算符遇到 / ,先计算 c / 2 = 2 再进行 b + 2 返回 7 。因此整个表达式为 1 && 7 返回 1

4、有 3 个整数a,b,c,由键盘输入,输出其中最大的数

解题思路:3 个中挑出最大的一共需要比较 2 次,即在 n 名选手中挑出最牛逼的需要进行 n-1 轮 PK。原理就是打擂台,首先自告奋勇第一轮两个人上台,然后胜者留下继续打剩下 n - 2 ,以此类推。

  • 流程图:
  • N-S 图见图:

image.png

  • C语言:
    1. #include <stdio.h>
    2. int main () {
    3. int a, b, c;
    4. printf("Please input three digits: ");
    5. scanf("%d %d %d", &a, &b, &c);
    6. if (a > b) { // a 和 b 比较大小,如果 a 大
    7. if (a > c) { // 如果还是 a 大
    8. printf("Max: %d\n", a);
    9. } else { // 否则 c 最大
    10. printf("Max: %d\n", c);
    11. }
    12. } else { // a 和 b 比较大小,如果 b 大
    13. if (b > c) { // 如果还是 b 大
    14. printf("Max: %d\n", b);
    15. } else { // 否则 c 最大
    16. printf("Max: %d\n", c);
    17. }
    18. }
    19. return 0;
    20. }
    21. // 2.使用第三方变量(看起来了简洁很多)
    22. #include <stdio.h>
    23. int main () {
    24. int a, b, c;
    25. printf("Please input three digits: ");
    26. scanf("%d %d %d", &a, &b, &c);
    27. int tmp = a > b ? a : b; // a,b最大者放入 tmp
    28. tmp = tmp > c ? tmp : c; // tmp,c最大者放入 tmp
    29. printf("Max: %d\n", tmp);
    30. return 0;
    31. }
    编译运行: :::success b12@PC:~/chapter4$ gcc -Wall ./src/threeMax.c -o ./bin/threeMax
    b12@PC:~/chapter4$ ./bin/threeMax
    Please input three digits: 12 34 9
    Max: 34 :::

    11、输入4个整数,要求按由小到大的顺序输出

    解题思路:本题可以转换为上面的形式。即先在 4 个中找到最大的,然后剔除最大者就变成上一个问题。
  1. 先在 4 人中找出最大者,即 4 人 PK 找到一直站台舞台的上人就是最大的。其它 3 人进入待命区。
  2. 然后再在待命区中选一个复活:即 3 人 PK 找到一直站台舞台的上人就是次大的。其它 2 人进入待命区。
  3. 然后再在待命区中选一个复活:即 3 人 PK 找到一直站台舞台的上人就是次次大的。其它 1 人进入待命区。
  4. 最后这个在待命区就是最小的了。

综上一共需要 3 趟比较,但是一趟要进行 PK x-1 轮选出此趟最大者,其中 x 就是参入 PK 的总人数。

  1. #include <stdio.h>
  2. int main () {
  3. int tmp, a, b, c, d;
  4. printf("Please input four numbers:");
  5. scanf ("%d,%d,%d,%d", &a, &b, &c, &d);
  6. // 1.在 a,b,c,d 中找最大值并放到 a 中
  7. if (a < b) { // a是a,b 中最大
  8. tmp = a;
  9. a = b;
  10. b = tmp;
  11. }
  12. if (a < c) { // a是a,b,c 中最大
  13. tmp = a;
  14. a = c;
  15. c = tmp;
  16. }
  17. if (a < d) { // a是a,b,c,d 中最大
  18. tmp = a;
  19. a = d;
  20. d = tmp;
  21. }
  22. // 2.在 b,c,d 中找到最大并放在 b
  23. if (b < c) { // b是 b,c 中最大
  24. tmp = b;
  25. b = c;
  26. c = tmp;
  27. }
  28. if (b < d) { // b是 b,c,d 中最大
  29. tmp = b;
  30. b = d;
  31. d = tmp;
  32. }
  33. // 3.在 c,d 中找到最大并放在 c
  34. if (c < d) { // b是 b,c,d 中最大
  35. tmp = c;
  36. c = d;
  37. d = tmp;
  38. }
  39. printf("Decending order: %d %d %d %d\n", a, b, c, d);
  40. return 0;
  41. }

编译运行: :::success b12@PC:~/chapter4$ gcc -Wall ./src/fourSort.c -o ./bin/fourSort
b12@PC:~/chapter4$ ./bin/fourSort
Please input four numbers:6,8,1,4
Decending order: 8 6 4 1
b12@PC:~/chapter4$ ./bin/fourSort
Please input four numbers:6,0,99,-7
Decending order: 99 6 0 -7 ::: 相比而已,这就是选择排序的 for 循环展开形式,只要知道本质是什么即可。即对 n 个人进行“打擂台”依次挑出最大者的过程。

5、从键盘输入一个小于 1000 的正数,要求输出它的平方根(如平方根不是整数,则输出其整数部分)。要求在输入数据后先对其进行检查是否为小于 1000 的正数。若不是,则要求重新输入

解题思路:要求重新输入,则就是判断输入合法,如果一直不合法就让它一直输入(无退出选择),那么就要进行 while 检测。虽然一定要获取第一个输入,但不能使用 do-while 进行运算后再判断合法性。

  1. #include <stdio.h>
  2. #include <math.h>
  3. #define M 1000
  4. int main () {
  5. int number;
  6. printf("Please input a number(<= %d):", M);
  7. scanf("%d", &number);
  8. while (number > M) {
  9. printf("Invalid input, please input again(<= %d):", M);
  10. scanf("%d", &number);
  11. }
  12. printf("The sqrt root is %d\n", (int)sqrt(number));
  13. return 0;
  14. }

编译运行: :::success b12@PC:~/chapter4$ gcc ./src/thousandSqrt.c -o ./bin/thousandSqrt -lm
b12@PC:~/chapter4$ ./bin/thousandSqrt
Please input a number(<= 1000):345
The sqrt root is 18

b12@PC:~/chapter4$ ./bin/thousandSqrt
Please input a number(<= 1000):1001
Invalid input, please input again(<= 1000):1000
The sqrt root is 31 :::

6、有一个分段函数如下,写程序,输入 x 的值,输出相应 y 得值。

课后习题 - 图2
解题思路:典型 if-else 判断,由于范围太大,用 switch-case 实现起来太麻烦。

  1. #include <stdio.h>
  2. int main () {
  3. int x, y;
  4. printf("Please input x:");
  5. scanf("%d", &x);
  6. if (x < 1) {
  7. y = x;
  8. } else if (1 <= x && x < 10) {
  9. y = 2 * x - 1;
  10. } else {
  11. y = 3 * x - 11;
  12. }
  13. printf("x = %d, y = %d\n", x, y);
  14. return 0;
  15. }

运行结果: :::success b12@PC:~/chapter4$ gcc -Wall ./src/PiecewiseFunction.c -o ./bin/PiecewiseFunction
b12@PC:~/chapter4$ ./bin/PiecewiseFunction
Please input x:4
x = 4, y = 7

b12@PC:~/chapter4$ ./bin/PiecewiseFunction
Please input x:-1
x = -1, y = -1

b12@PC:~/chapter4$ ./bin/PiecewiseFunction
Please input x:20
x = 20, y = 49 :::

7、有一函数如下:有人分别编写了以下两个程序,请分析它们是否能实现题目要求。不要急于上机运行程序,先分析上面两个程序的逻辑,画出它们的流程图,分析它们的运行情况。然后上机运行程序,观察并分析结果。

课后习题 - 图3
程序1:

  1. #include <stdio.h>
  2. int main () {
  3. int x, y;
  4. printf("Enter x:");
  5. scanf("%d", &x);
  6. y = -1;
  7. if (0 != x) // 1
  8. if (x > 0) // 2
  9. y = 1;
  10. else // 3
  11. y = 0;
  12. printf("x = %d, y = %d\n", x, y);
  13. return 0;
  14. }

其流程图如下:
出错原因在于第 10 行 else (3处)是和第 8 行 if (2处)匹配,而不是和第 7 行 if (1处)匹配。
课后习题 - 图4
编译运行:(发出警告,不仅仅是编码规范,而是易错) :::warning b12@PC:~/chapter4$ gcc -Wall ./src/if_else1.c -o ./bin/if_else1
./src/if_else1.c: In function ‘main’:
./src/if_else1.c:7:5: warning: suggest explicit braces to avoid ambiguous ‘else’ [-Wdangling-else]
7 | if (0 != x)
| ^
b12@PC:~/chapter4$ ./bin/if_else1
Enter x:-6
x = -6, y = 0 ::: 程序2:

  1. #include <stdio.h>
  2. int main () {
  3. int x, y;
  4. printf("Enter x:");
  5. scanf("%d", &x);
  6. y = 0;
  7. if(x >= 0) // 1
  8. if (x > 0) // 2
  9. y = 1;
  10. else // 3
  11. y = -1;
  12. printf("x = %d, y = %d\n", x, y);
  13. return 0;
  14. }

其流程图如下:
出错原因在于第 10 行 else (3处)是和第 8 行 if (2处)匹配,而不是和第 7 行 if (1处)匹配。即函数为
课后习题 - 图5
编译运行:(发出警告,不仅仅是编码规范,而是易错) :::warning b12@PC:~/chapter4$ gcc -Wall ./src/if_else2.c -o ./bin/if_else2
./src/if_else2.c: In function ‘main’:
./src/if_else2.c:7:4: warning: suggest explicit braces to avoid ambiguous ‘else’ [-Wdangling-else]
7 | if(x >= 0) // 1
| ^
b12@PC:~/chapter4$ ./bin/if_else2
Enter x:-4
x = -4, y = 0 ::: 总之,即使 if-else 内只有一行代码也不要偷懒不写 {} ,代码不是要求简洁,而是要求可读性好。千万别学书上没格式地乱缩进等。。
正确代码:

  1. #include <stdio.h>
  2. int main() {
  3. int x, y;
  4. printf("Enter x:");
  5. scanf("%d", &x);
  6. if (x > 0) {
  7. y = 1;
  8. } else if (0 == x) {
  9. y = 0;
  10. } else {
  11. y = -1;
  12. }
  13. printf("x = %d, y = %d\n", x, y);
  14. return 0;
  15. }

编译运行: :::success b12@PC:~/chapter4$ gcc ./src/if_else.c -o ./bin/if_else
b12@PC:~/chapter4$ ./bin/if_else
Enter x:3
x = 3, y = 1

b12@PC:~/chapter4$ ./bin/if_else
Enter x:0
x = 0, y = 0

b12@PC:~/chapter4$ ./bin/if_else
Enter x:-1
x = -1, y = -1 :::

8、给出一百分制成绩,要求输出成绩等级’A’、’B’、’C’、’D’、’E’。90分以上为’A’,80~89分为B’,70~70分为’C’,60~69分为’D’,60分以下为’E’。

解题思路:可以使用 switch-case 或者 if-else 解决。在使用switch-case 时找到每个 10 区间对应的值即可,但是需要注意 100 的特殊情况。由于分数可以 65.5 ,因此数据类型就是 float

  1. // scoreGrade.c
  2. #include <stdio.h>
  3. int main () {
  4. float score;
  5. char grade;
  6. printf("Please input student score:");
  7. scanf("%f", &score);
  8. while (0 > score || score > 100) {
  9. printf("Invalid input, pelase input again:");
  10. scanf("%f", &score);
  11. }
  12. switch ((int)(score / 10)) {
  13. case 10:
  14. case 9:
  15. grade = 'A';break;
  16. case 8:
  17. grade = 'B';break;
  18. case 7:
  19. grade = 'C';break;
  20. case 6:
  21. grade = 'D';break;
  22. default:
  23. grade = 'E';
  24. }
  25. // if (score >= 90) {
  26. // grade = 'A';
  27. // } else if (score >= 80) {
  28. // grade = 'B';
  29. // } else if (score >= 70) {
  30. // grade = 'C';
  31. // } else if (score >= 60) {
  32. // grade = 'D';
  33. // } else {
  34. // grade = 'E';
  35. // }
  36. printf("score: %5.1f, grade: %c\n", score, grade);
  37. return 0;
  38. }

运行结果: :::success b12@PC:~/chapter4$ gcc -Wall ./src/scoreGrade.c -o ./bin/scoreGrade
b12@PC:~/chapter4$ ./bin/scoreGrade
Please input student score:101
Invalid input, pelase input again:-1
Invalid input, pelase input again:58
score: 58.0, grade: E :::

9、给一个不多于5位的正整数,要求:

  1. 求出它是几位数
  2. 分别输出每一位数字
  3. 按逆序输出各位数字,例如原数为321,应输出123

解题思路:要求1和2可同步进行,使用函数递归,从高位到低位进行退栈的过程进行打印输出即可。同时逆序就是低位到高位,可以直接使用 do-while 取余整除迭代进行。

  1. #include <stdio.h>
  2. void putDigit(int num, int cnt) {
  3. /* 函数进行递归正序输出,cnt参数计算长度 */
  4. if (0 == num / 10) { // 一位的时候单独处理
  5. printf("Total length:%d\n", cnt + 1);
  6. printf("Each digit:%d", num);
  7. } else {
  8. putDigit(num / 10, cnt + 1);
  9. printf(", %d", num % 10);
  10. }
  11. }
  12. int main () {
  13. int num;
  14. printf("Please input a number(0~99999):");
  15. scanf("%d", &num);
  16. putDigit(num, 0);
  17. // 迭代逆序输出
  18. printf("\nReversed:");
  19. do {
  20. printf("%d", num % 10);
  21. num /= 10;
  22. } while (num);
  23. return 0;
  24. }

:::success b12@PC:~/chapter4$ gcc -Wall ./src/countNum.c -o ./bin/countNum
b12@PC:~/chapter4$ ./bin/countNum
Please input a number(0~99999):98423
Total length:5
Each digit:9, 8, 4, 2, 3
Reversed:32489 :::

10、企业发放的奖金根据利润提成

利润I低于或等于100000元的,奖金可提成10%;利润高于100000元,低于200000元(1000001000000时,超过1000000元的部分按1%提成。从键盘输入当月利润I,求应发奖金总数。
要求:

  1. 用if语句编程序。
  2. 用switch语句编程序。

解题思路:本题所表达是意思如下课后习题 - 图6
由此可以清晰看出其间的递推关系:除了第一层的 课后习题 - 图7单独计算外,其他都是在前者的基础上累加区间利润。

  1. 利润为100 000元时应得的奖金,即100000元×0.1。
  2. 100 000元以上部分应得的奖金,即(num-100 000)×0.075元。
  3. 200000~400000元这个区间的奖金也应由两部分组成:
    1. 利润为200 000元时应得的奖金,即100 000×0.1+100 000×0.075。
    2. 200 000元以上部分应得的奖金,即(num-200000)×0.05元。

程序中先把100 000元、200 000元、400 000元、600 000元、1 000 000元各关键点的奖金计算出来,即 bon1,bon2,bon4,bon6和bon10。然后再加上各区间附加部分的奖金即可。
流程图:

  1. #include <stdio.h>
  2. int main () {
  3. int i;
  4. printf("Please input interests:");
  5. scanf("%d", &i);
  6. double bonus, bonus1, bonus2, bonus4, bonus6, bonus10;
  7. bonus1 = 100000 * 0.1;
  8. bonus2 = bonus1 + 100000 * 0.075;
  9. bonus4 = bonus2 + 100000 * 0.05;
  10. bonus6 = bonus4 + 100000 * 0.03;
  11. bonus10 = bonus6 + 100000 * 0.015;
  12. if (i <= 100000) {
  13. bonus = i * 0.1;
  14. } else if (i <= 200000) {
  15. bonus = bonus1 + (i - 100000) * 0.075;
  16. } else if (i <= 400000) {
  17. bonus = bonus2 + (i - 200000) * 0.05;
  18. } else if (i <= 600000) {
  19. bonus = bonus4 + (i - 400000) * 0.03;
  20. } else if (i <= 1000000) {
  21. bonus = bonus6 + (i - 600000) * 0.015;
  22. } else {
  23. bonus = bonus10 + (i - 1000000) * 0.01;
  24. }
  25. printf("Bonus:%10.2f\n", bonus);
  26. return 0;
  27. }

编译运行: :::success b12@PC:~/chapter4$ gcc -Wall ./src/bonus.c -o ./bin/bonus
b12@PC:~/chapter4$ ./bin/bonus
Please input interests:234000
Bonus: 19200.00 ::: N-S流程图:
image.png
使用 switch-case 同上面成绩转换一样,注意最大区间的判断即可。

  1. #include <stdio.h>
  2. int main () {
  3. int i;
  4. printf("Please input interests:");
  5. scanf("%d", &i);
  6. double bonus, bonus1, bonus2, bonus4, bonus6, bonus10;
  7. bonus1 = 100000 * 0.1;
  8. bonus2 = bonus1 + 100000 * 0.075;
  9. bonus4 = bonus2 + 100000 * 0.05;
  10. bonus6 = bonus4 + 100000 * 0.03;
  11. bonus10 = bonus6 + 100000 * 0.015;
  12. int branch = i / 100000;
  13. if (i >= 1000000) { // 最大区间的范围压缩
  14. branch = 10;
  15. }
  16. switch (branch) {
  17. case 0:
  18. bonus = i * 0.1; break;
  19. case 1:
  20. bonus = bonus1 + (i - 100000) * 0.075; break;
  21. case 2:
  22. case 3:
  23. bonus = bonus2 + (i - 200000) * 0.05; break;
  24. case 4:
  25. case 5:
  26. bonus = bonus4 + (i - 400000) * 0.03; break;
  27. case 6:
  28. case 7:
  29. case 8:
  30. case 9:
  31. bonus = bonus6 + (i - 600000) * 0.015; break;
  32. case 10:
  33. bonus = bonus10 + (i - 1000000) * 0.01; break;
  34. }
  35. printf("Bonus:%10.2f\n", bonus);
  36. return 0;
  37. }

编译运行:
可能会疑惑:明明题目给定课后习题 - 图9时,利润是 课后习题 - 图10,但是上面代码进行 课后习题 - 图11后怎么没有判断右区间相等的情况?例如课后习题 - 图12case 0 ,那么 课后习题 - 图13 它不是等于 branch=1 吗?明显错了?其实不然,因为它跑到下一个 case 1 去了,此时 bonus = bonus1 + (i - 100000) * 0.075; 后面相加部分为 0 ,这也是 switch-case 使用的时候需要非常注意的地方,如果拿不准或找不到规律,直接使用 if-else 。 :::success b12@PC:~/chapter4$ gcc -Wall ./src/bonus.c -o ./bin/bonus
b12@PC:~/chapter4$ ./bin/bonus
Please input interests:100000
Bonus: 10000.00
b12@PC:~/chapter4$ ./bin/bonus
Please input interests:200000
Bonus: 17500.00 :::

12、有4个圆塔,圆心分别为(2,2),(-2,2),(-2,-2),(2,-2),圆半径为1

4个塔的高度为10m,塔以外无建筑物。今输入任一点的坐标,求该点的建筑高度(塔外的高度为零)。
解题思路:其实说半天就是一个立体图的俯视图,问你是不是在四个水塔上,是就是高度为 10 m,否则就是地上,高度为 0 m。
水塔.png
按书上对 4 个塔中心距离求解
N-S流程图:
image.png
因为对称性的发现,问题可以直接转换到求一个点是否在塔上,可以把其转换为都在第一象限上(),即对坐标取绝对值
流程图:
参考代码:

  1. #include <stdio.h>
  2. #define X 2
  3. #define Y 2
  4. #define R 1
  5. int main () {
  6. int h = 10;
  7. float x, y;
  8. printf("Please input a point (x, y):");
  9. scanf ("%f,%f", &x, &y);
  10. x = x >= 0 ? x : -x; // fabs(x)
  11. y = y >= 0 ? y : -y; // fabs(y)
  12. if ((x - X) * (x - X) + (y - Y) * (y - Y) > R) {
  13. h = 0;
  14. }
  15. printf("The height of (%f, %f) is %d\n", x, y, h);
  16. return 0;
  17. }

编译运行: :::success b12@PC:~/chapter4$ gcc -Wall ./src/tower.c -o ./bin/tower
b12@PC:~/chapter4$ ./bin/tower
Please input a point (x, y):0.5,0.7
The height of (0.500000, 0.700000) is 0
b12@PC:~/chapter4$ ./bin/tower
Please input a point (x, y):2.1,-2.3
The height of (2.100000, 2.300000) is 10 :::