高级语言程序设计课程第四次个人作业
高级语言程序设计课程第四次个人作业
这个作业属于哪个课程:https://edu.cnblogs.com/campus/fzu/2026gjyycxsj
这个作业要求在哪里:https://edu.cnblogs.com/campus/fzu/2026gjyycxsj/homework/16750
学号:010100223
姓名:武子腾
一、运行以下程序给出结果(题1,无需代码)
(1)对用户输入的整数求和
题目:程序反复读取用户输入的整数并累加,输入非数字(如 q)结束,输出累加和。
代码:
#include <stdio.h>
int main(void) /* 对用户输入的整数求和 */
{
long num;
long sum = 0L;
int status;
printf("请输入一个整数来求和");
printf("(q 退出):");
status = scanf("%ld", &num);
while (status == 1) /* == 表示"等于" */
{
sum = sum + num;
printf("请输入下一个整数(q 退出):");
status = scanf("%ld", &num);
}
printf("这些整数的和等于 %ld。\n", sum);
return 0;
}
运行结果(输入 10 20 30 q):
请输入一个整数来求和(q 退出):请输入下一个整数(q 退出):请输入下一个整数(q 退出):请输入下一个整数(q 退出):这些整数的和等于 60。
截图说明:这里
10 + 20 + 30 = 60,输入 q 后scanf返回 0(不是 1),循环结束,打印累加和。
(2)猜 π 的值
题目:用户输入一个数,程序判断它与 3.14159 的差的绝对值是否超过 0.0001,超过则提示"再试一次",否则提示"差不多了"。
代码:
#include <math.h>
#include <stdio.h>
int main(void)
{
const double ANSWER = 3.14159;
double response;
printf("π 的值是多少?");
scanf("%lf", &response);
while (fabs(response - ANSWER) > 0.0001)
{
printf("再试一次!\n");
scanf("%lf", &response);
}
printf("差不多了!\n");
return 0;
}
运行结果(输入 3.1415):
π 的值是多少?差不多了!
截图说明:
fabs(3.1415 - 3.14159) = 0.00009 < 0.0001,所以直接输出"差不多了!"。
二、设计题
题2:用 while 和 do-while 分别求 π 的近似值
题目:用公式 π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ... 求 π 的近似值,直到某一项的绝对值小于 10⁻⁴ 为止,讨论两个程序的不同。
(a)while 版:
#include <stdio.h>
#include <math.h>
int main(void)
{
double pi = 0.0; /* 累加的 π/4 结果 */
double term = 1.0; /* 当前项,第一项为 1/1 */
int sign = 1; /* 符号,交替 +1 / -1 */
int n = 1; /* 分母,1, 3, 5, 7, ... */
while (fabs(term) >= 1e-4)
{
pi += term;
n += 2;
sign = -sign;
term = sign * 1.0 / n;
}
printf("用 while 求得的 π ≈ %f\n", 4 * pi);
return 0;
}
(b)do-while 版:
#include <stdio.h>
#include <math.h>
int main(void)
{
double pi = 0.0;
double term = 1.0;
int sign = 1;
int n = 1;
do
{
pi += term;
n += 2;
sign = -sign;
term = sign * 1.0 / n;
} while (fabs(term) >= 1e-4);
printf("用 do-while 求得的 π ≈ %f\n", 4 * pi);
return 0;
}
运行结果:
用 while 求得的 π ≈ 3.141393
用 do-while 求得的 π ≈ 3.141393
讨论:两个程序结果相同(都约等于 3.141393)。不同之处在于:
while先判断后执行,如果一开始条件不满足则循环体一次也不执行;do-while先执行后判断,循环体至少执行一次。本题中第一项
term = 1.0一定满足>= 1e-4,所以两者都正常进入循环。但如果初值本身就不满足条件,while会直接跳过(一次都不累加),而do-while仍会执行一次——这是两者的本质区别。
题3:逻辑表达式的短路求值
题目:设计程序,验证逻辑表达式中的运算符只有会影响表达式求值时才会执行(短路求值)。
代码:
#include <stdio.h>
int main(void)
{
int a = 0, b = 0;
int x = 1, y = 1;
/* && 短路:左边为假(0)时,右边不再执行 */
if (a != 0 && (++b) > 0)
printf("(a != 0 && ++b) 为真\n");
else
printf("(a != 0 && ++b) 为假\n");
printf("执行后 b = %d(b 没变,说明 ++b 被跳过了)\n\n", b);
/* || 短路:左边为真(非0)时,右边不再执行 */
if (x != 0 || (++y) > 0)
printf("(x != 0 || ++y) 为真\n");
printf("执行后 y = %d(y 没变,说明 ++y 被跳过了)\n", y);
return 0;
}
运行结果:
(a != 0 && ++b) 为假
执行后 b = 0(b 没变,说明 ++b 被跳过了)
(x != 0 || ++y) 为真
执行后 y = 1(y 没变,说明 ++y 被跳过了)
截图说明:
a != 0为假(0),&&右边++b被短路跳过,b 仍是 0;x != 0为真(1),||右边++y被短路跳过,y 仍是 1。这就证明了短路求值。
题4:for 循环输出六行字母
题目:第一行 FEDCBA,第二行 FEDCB,第三行 FEDC……以此类推,共六行。
代码:
#include <stdio.h>
int main(void)
{
int row, col;
for (row = 0; row < 6; row++) /* 控制行数,共 6 行 */
{
for (col = 0; col < 6 - row; col++) /* 每行从 'F' 开始,字符数逐行减一 */
printf("%c", 'F' - col);
printf("\n");
}
return 0;
}
运行结果:
FEDCBA
FEDCB
FEDC
FED
FE
F
题5:计算 s = 1 + (1+2) + (1+2+3) + ... + (1+2+...+n)
代码:
#include <stdio.h>
int main(void)
{
int n, i, j;
long sum = 0;
printf("请输入 n:");
scanf("%d", &n);
for (i = 1; i <= n; i++) /* 外层循环:第 i 组,即 1+2+...+i */
for (j = 1; j <= i; j++) /* 内层循环:累加 1 到 i */
sum += j;
printf("s = 1 + (1+2) + ... + (1+2+...+%d) = %ld\n", n, sum);
return 0;
}
运行结果(输入 5):
请输入 n:s = 1 + (1+2) + ... + (1+2+...+5) = 35
验证:1 + 3 + 6 + 10 + 15 = 35。
题6:for 循环给数组赋值、输出、求和(长度 8)
代码:
#include <stdio.h>
#define LEN 8
int main(void)
{
int arr[LEN];
int i, sum = 0;
for (i = 0; i < LEN; i++)
arr[i] = 2 * (i + 1); /* 赋值 */
printf("数组元素:");
for (i = 0; i < LEN; i++)
{
printf("%d ", arr[i]);
sum += arr[i]; /* 求和 */
}
printf("\n数组元素之和 = %d\n", sum);
return 0;
}
运行结果:
数组元素:2 4 6 8 10 12 14 16
数组元素之和 = 72
题7:if-else 多分支 + switch 改写 + 条件运算符
题目:设计一个 if-else 多分支程序(分支数大于 3),再用 switch 改写;同时设计一个用条件运算符 ?: 的双分支程序。
(a)if-else 多分支(成绩等级判定,5 个分支):
#include <stdio.h>
int main(void)
{
int score;
printf("请输入成绩(0~100):");
scanf("%d", &score);
if (score >= 90)
printf("等级:A(优秀)\n");
else if (score >= 80)
printf("等级:B(良好)\n");
else if (score >= 70)
printf("等级:C(中等)\n");
else if (score >= 60)
printf("等级:D(及格)\n");
else
printf("等级:E(不及格)\n");
return 0;
}
(b)switch 改写:
#include <stdio.h>
int main(void)
{
int score;
printf("请输入成绩(0~100):");
scanf("%d", &score);
switch (score / 10) /* 十位数决定等级 */
{
case 10:
case 9: printf("等级:A(优秀)\n"); break;
case 8: printf("等级:B(良好)\n"); break;
case 7: printf("等级:C(中等)\n"); break;
case 6: printf("等级:D(及格)\n"); break;
default: printf("等级:E(不及格)\n"); break;
}
return 0;
}
(c)条件运算符 ?: 双分支(判断奇偶):
#include <stdio.h>
int main(void)
{
int n;
printf("请输入一个整数:");
scanf("%d", &n);
printf("%d 是%s\n", n, (n % 2 == 0) ? "偶数" : "奇数");
return 0;
}
运行结果(a、b 输入 85,c 输入 7):
等级:B(良好)
等级:B(良好)
7 是奇数
说明:switch 用
score / 10(整除)把连续分数映射成离散的十位数,case 9和case 10共用同一段(fall-through),实现 ≥90 为 A 的逻辑。
题8:循环中 break 和 continue
代码:
#include <stdio.h>
int main(void)
{
int i;
printf("【break】遇到 5 就退出整个循环:\n");
for (i = 1; i <= 10; i++)
{
if (i == 5)
break; /* 直接跳出循环 */
printf("%d ", i);
}
printf("\n\n");
printf("【continue】遇到 5 跳过它,继续后面的循环:\n");
for (i = 1; i <= 10; i++)
{
if (i == 5)
continue; /* 跳过本次,进入下一次 */
printf("%d ", i);
}
printf("\n");
return 0;
}
运行结果:
【break】遇到 5 就退出整个循环:
1 2 3 4
【continue】遇到 5 跳过它,继续后面的循环:
1 2 3 4 6 7 8 9 10
讨论:
break是彻底终止循环(后面的 5~10 都不打印了);continue是跳过本次(只跳过了 5,6~10 照常打印)。两者作用完全不同。
题9:求 100~200 间的全部素数
代码:
#include <stdio.h>
#include <math.h>
int main(void)
{
int n, i, is_prime, count = 0;
printf("100~200 之间的素数有:\n");
for (n = 100; n <= 200; n++)
{
is_prime = 1; /* 先假设 n 是素数 */
for (i = 2; i <= (int)sqrt(n); i++) /* 只需试除到 √n */
{
if (n % i == 0)
{
is_prime = 0;
break;
}
}
if (is_prime)
{
printf("%d ", n);
count++;
if (count % 8 == 0)
printf("\n");
}
}
printf("\n共 %d 个素数。\n", count);
return 0;
}
运行结果:
100~200 之间的素数有:
101 103 107 109 113 127 131 137
139 149 151 157 163 167 173 179
181 191 193 197 199
共 21 个素数。
算法思想:素数是只能被 1 和它本身整除的数。对每个 n,用 2 到 √n 之间的数依次试除,一旦整除就说明它不是素数,立即 break 退出内层循环;若全部试完都没整除,则是素数。只试除到 √n 是因为:若 n 有大于 √n 的因子,必然对应一个小于 √n 的因子,所以不必检查超过 √n 的部分,能大幅减少判断次数。
传统流程图(N-S 图见下方):
开始
│
▼
n = 100
│
▼
┌─────────────────┐
│ n ≤ 200? │──否──→ 输出 count,结束
└────────┬────────┘
│是
▼
is_prime = 1
i = 2
│
▼
┌───────────────┐
│ i ≤ √n? │──否──→ 跳到"判断 is_prime"
└──────┬────────┘
│是
▼
n % i == 0? ──是──→ is_prime = 0; break
│否
▼
i = i + 1 ──→ 回到"i ≤ √n?"
│
▼
判断 is_prime:若为 1,则打印 n,count++
│
▼
n = n + 1 ──→ 回到"n ≤ 200?"
N-S 流程图:
┌──────────────────────────────────────────────┐
│ 开始 │
├──────────────────────────────────────────────┤
│ for (n = 100; n <= 200; n++) │
│ ┌──────────────────────────────────────────┐ │
│ │ is_prime = 1 │ │
│ │ for (i = 2; i <= sqrt(n); i++) │ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ │ n % i == 0 ? │ │ │
│ │ │ 是 → is_prime = 0; break │ │ │
│ │ │ 否 → 继续 │ │ │
│ │ └────────────────────────────────────┘ │ │
│ │ is_prime == 1 ? │ │
│ │ 是 → 打印 n,count++ │ │
│ │ 否 → 跳过 │ │
│ └──────────────────────────────────────────┘ │
├──────────────────────────────────────────────┤
│ 输出 素数个数 count │
│ 结束 │
└──────────────────────────────────────────────┘
三、第6章 6.16 编程练习(题10)
第1题:26 个小写字母数组
题目:创建含 26 个元素的数组,存入 26 个小写字母并打印。
代码:
#include <stdio.h>
#define COUNT 26
int main(void)
{
char arr[COUNT];
int i;
for (i = 0; i < COUNT; i++)
arr[i] = 'a' + i;
printf("26 个小写字母:");
for (i = 0; i < COUNT; i++)
printf("%c", arr[i]);
printf("\n");
return 0;
}
运行结果:
26 个小写字母:abcdefghijklmnopqrstuvwxyz
第5题:字母金字塔
题目:输入一个大写字母,用嵌套循环打印金字塔(如输入 E 打印 A/ABA/ABCBA/ABCDCBA/ABCDEDCBA)。
代码:
#include <stdio.h>
int main(void)
{
char ch, base = 'A';
int rows, i, j;
printf("请输入一个大写字母:");
scanf("%c", &ch);
rows = ch - base + 1;
for (i = 0; i < rows; i++)
{
for (j = 0; j < rows - i - 1; j++) /* 内层1:前导空格 */
printf(" ");
for (j = 0; j <= i; j++) /* 内层2:升序 */
printf("%c", base + j);
for (j = i - 1; j >= 0; j--) /* 内层3:降序 */
printf("%c", base + j);
printf("\n");
}
return 0;
}
运行结果(输入 E):
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
第7题:倒序打印单词
题目:读入一个单词到字符数组,用 strlen 得到长度,倒序打印。
代码:
#include <stdio.h>
#include <string.h>
int main(void)
{
char word[40];
int len, i;
printf("请输入一个单词:");
scanf("%s", word);
len = strlen(word);
printf("倒序打印:");
for (i = len - 1; i >= 0; i--)
printf("%c", word[i]);
printf("\n");
return 0;
}
运行结果(输入 hello):
请输入一个单词:倒序打印:olleh
第10题:上下限平方和
题目:输入上限和下限整数,计算范围内所有整数平方和;反复进行,直到输入的上限小于下限为止。
代码:
#include <stdio.h>
int sum_of_squares(int lower, int upper);
int main(void)
{
int lower, upper;
printf("输入下限和上限整数(上限小于下限则结束):\n");
while (scanf("%d %d", &lower, &upper) == 2 && lower < upper)
{
printf("从 %d 到 %d 的平方和为 %d\n",
lower * lower, upper * upper,
sum_of_squares(lower, upper));
printf("输入下一组上下限:");
}
printf("完成(Done)\n");
return 0;
}
int sum_of_squares(int lower, int upper)
{
int i, sum = 0;
for (i = lower; i <= upper; i++)
sum += i * i;
return sum;
}
运行结果(输入 5 9、3 25、5 5):
输入下限和上限整数(上限小于下限则结束):
从 25 到 81 的平方和为 255
输入下一组上下限:从 9 到 625 的平方和为 5520
输入下一组上下限:完成(Done)
第13题:2 的前 8 次幂数组
题目:创建 8 元素 int 数组,用 for 循环设为 2 的前 8 次幂,用 do-while 显示。
代码:
#include <stdio.h>
#define LEN 8
int main(void)
{
int arr[LEN];
int i;
for (i = 0; i < LEN; i++)
arr[i] = 2 << i; /* 2,4,8,16,32,64,128,256 */
printf("2 的前 8 次幂:");
i = 0;
do
{
printf("%d ", arr[i]);
i++;
} while (i < LEN);
printf("\n");
return 0;
}
运行结果:
2 的前 8 次幂:2 4 8 16 32 64 128 256
第16题:单利 vs 复利
题目:Daphne 以 10% 单利、Deirdre 以 5% 复利各投资 100 美元,计算多少年后 Deirdre 超过 Daphne。
代码:
#include <stdio.h>
int main(void)
{
double daphne = 100.0, deirdre = 100.0;
const double RATE1 = 0.10, RATE2 = 0.05;
int year = 0;
do
{
daphne += 100.0 * RATE1; /* 单利 */
deirdre += deirdre * RATE2; /* 复利 */
year++;
} while (deirdre <= daphne);
printf("第 %d 年后,Deirdre(%.2f 美元)超过 Daphne(%.2f 美元)\n",
year, deirdre, daphne);
return 0;
}
运行结果:
第 27 年后,Deirdre(373.35 美元)超过 Daphne(370.00 美元)
第18题:Rabnud 博士的朋友数量
题目:起初 5 个朋友,每周少 1 个再翻倍,直到超过邓巴数 150。
代码:
#include <stdio.h>
int main(void)
{
int friends = 5, week = 0;
do
{
friends--;
friends *= 2;
week++;
} while (friends <= 150);
printf("第 %d 周后,朋友数达到 %d,超过了邓巴数 150\n",
week, friends);
return 0;
}
运行结果:
第 6 周后,朋友数达到 194,超过了邓巴数 150
四、第7章 7.12 编程练习(题11)
第1题:统计空格、换行、其他字符
题目:读取输入到 # 为止,报告空格数、换行数、其他字符数。
代码:
#include <stdio.h>
int main(void)
{
char ch;
int n_space = 0, n_newline = 0, n_other = 0;
printf("请输入文本(输入 # 结束):\n");
while ((ch = getchar()) != '#')
{
if (ch == ' ')
n_space++;
else if (ch == '\n')
n_newline++;
else
n_other++;
}
printf("空格:%d,换行:%d,其他字符:%d\n",
n_space, n_newline, n_other);
return 0;
}
运行结果(输入 a b c + 回车 + q + 回车 + #):
请输入文本(输入 # 结束):
空格:2,换行:2,其他字符:4
第2题:每行 8 个字符-ASCII 码对
题目:读取字符到 #,每行打印 8 个"字符-ASCII码"对。
代码:
#include <stdio.h>
int main(void)
{
char ch;
int count = 0;
printf("请输入字符(输入 # 结束):\n");
while ((ch = getchar()) != '#')
{
if (ch == '\n')
continue;
printf("%c-%3d ", ch, ch);
count++;
if (count % 8 == 0)
printf("\n");
}
printf("\n");
return 0;
}
运行结果(输入 abcdefgh#):
请输入字符(输入 # 结束):
a- 97 b- 98 c- 99 d-100 e-101 f-102 g-103 h-104
第4题:用 if-else 替换句号和感叹号
题目:读取输入到 #,把 . 替换成 !,把 ! 替换成 !!(用 if-else)。
代码:
#include <stdio.h>
int main(void)
{
char ch;
int n_repl = 0;
printf("请输入文本(输入 # 结束):\n");
while ((ch = getchar()) != '#')
{
if (ch == '.')
{
ch = '!';
n_repl++;
}
else if (ch == '!')
{
putchar('!');
n_repl++;
}
putchar(ch);
}
printf("\n共替换了 %d 次。\n", n_repl);
return 0;
}
运行结果(输入 a.b!c#):
请输入文本(输入 # 结束):
a!b!!c
共替换了 2 次。
第5题:用 switch 替换句号和感叹号
题目:同第 4 题,改用 switch 实现。
代码:
#include <stdio.h>
int main(void)
{
char ch;
int n_repl = 0;
printf("请输入文本(输入 # 结束):\n");
while ((ch = getchar()) != '#')
{
switch (ch)
{
case '.': ch = '!'; n_repl++; break;
case '!': putchar('!'); n_repl++; break;
default: break;
}
putchar(ch);
}
printf("\n共替换了 %d 次。\n", n_repl);
return 0;
}
运行结果(输入 a.b!c#):
请输入文本(输入 # 结束):
a!b!!c
共替换了 2 次。
第7题:计算周薪
题目:基本工资 10 美元/时,超 40 小时部分按 1.5 倍;税金分三级(前 300 美元 15%、300~450 美元 20%、超 450 美元 25%),输出总收入、税金、净收入。
代码:
#include <stdio.h>
#define BASE_PAY 10.0
#define OVER_TIME 40
#define OVER_RATE 1.5
#define RATE1 0.15
#define RATE2 0.20
#define RATE3 0.25
#define BREAK1 300.0
#define BREAK2 450.0
int main(void)
{
double hour, gross, tax, net;
printf("请输入本周工作小时数:");
scanf("%lf", &hour);
if (hour <= OVER_TIME)
gross = hour * BASE_PAY;
else
gross = OVER_TIME * BASE_PAY
+ (hour - OVER_TIME) * BASE_PAY * OVER_RATE;
if (gross <= BREAK1)
tax = gross * RATE1;
else if (gross <= BREAK2)
tax = BREAK1 * RATE1 + (gross - BREAK1) * RATE2;
else
tax = BREAK1 * RATE1 + (BREAK2 - BREAK1) * RATE2
+ (gross - BREAK2) * RATE3;
net = gross - tax;
printf("总收入:%.2f 美元\n税金:%.2f 美元\n净收入:%.2f 美元\n",
gross, tax, net);
return 0;
}
运行结果(输入 45):
请输入本周工作小时数:总收入:475.00 美元
税金:81.25 美元
净收入:393.75 美元
验证:总收入 = 40×10 + 5×15 = 475;税金 = 300×0.15 + 150×0.2 + 25×0.25 = 45 + 30 + 6.25 = 81.25;净收入 = 475 − 81.25 = 393.75。
五、编写运行过程中遇到的问题与解决
-
题目原文是机器翻译/OCR 乱码:作业原文里
long num被翻成"长数"、while被翻成"而"、scanf参数被写成scanf("%ld",&num)(中文逗号)等。解决:根据 C 语言语法和上下文还原成正确的可编译代码,尤其注意把中文标点改回英文标点。 -
scanf 读字符时残留的换行符:第 7 章题目里连续
getchar()会把上一次回车也读进去。解决:在统计循环里用if (ch == '\n') continue;显式跳过换行,保证统计和显示都正确。 -
7-4/7-5 的替换逻辑:
. → !、! → !!初看容易写错。解决:!分支里先putchar('!')多输出一个,再把原字符putchar(ch)输出,正好得到两个感叹号。 -
6-5 金字塔对齐:题目提示"每行用 3 个内层循环分别处理空格、升序、降序",如果漏掉空格循环,金字塔就左对齐了。解决:加一段
for (j = 0; j < rows - i - 1; j++) printf(" ");打印前导空格。 -
6-13 用
2 << i求 2 的幂:2 << i等价于2 × 2^i = 2^(i+1),比调用pow()更直观,且不需要<math.h>。
六、总结与思考
这次作业覆盖了 C 语言流程控制的三个核心:循环(while / do-while / for)、分支(if-else / switch / 条件运算符)、跳转(break / continue),并开始接触数组和函数。
- while 与 do-while 的区别我通过 π 级数题真正体会到了:while 先判断、可能一次都不执行;do-while 先执行、至少一次。初值能满足条件时两者结果一致,但语义上要分清"先判断还是先执行"。
- 短路求值是逻辑运算符的重要特性,
&&左边为假、||左边为真时右边不执行。这个特性不仅能提高效率,还能用来"安全地"写条件(比如x != 0 && 10/x > 1不会除零)。 - break 和 continue 是循环控制的两把利器:break 是"退出整个循环",continue 是"跳过本次进入下一次",用途完全不同。
- 素数判断让我学到"试除到 √n 就够"的优化思想——数学上若 n 有大于 √n 的因子,必然对应一个小于 √n 的因子,所以可以把内层循环次数从 n 降到 √n,效率大幅提升。
- if-else 与 switch 的取舍:switch 适合对"整型/字符"的离散值做多路分支,结构清晰;但它的 case 只能用常量,判断范围(如
score >= 90)还是要靠 if-else。用score / 10把连续分数"离散化"是一个把 if-else 改写成 switch 的常用技巧。 - 通过这次作业,我对 C 语言的流程控制有了更系统的理解,也养成了写代码前先想清逻辑、写完用笔算验证结果的习惯。
浙公网安备 33010602011771号