阶段项目1:成绩统计器
这个项目练什么#
整合 ch1–ch6 的能力:
- ch1–2:变量、类型、
int和char数组。 - ch3:
while循环读入,if判断及格。 - ch4:把统计和查找拆成函数。
- ch5:用
struct数组存一批记录,count记录实际数量。 - ch6:
char name[32]存姓名,strcmp比较。
任务要求#
- 声明一个固定容量的学生表
struct Student table[100]。 - 循环读入:每行输入
学号 姓名 分数,学号输入0停止。 - 输入格式错误(学号非数字、姓名或分数缺失)时,打印提示并跳过,不崩溃。
- 容量用满时,打印提示并停止录入,已录入的数据不受影响。
- 录入结束后,打印统计:最高分、最低分、平均分(保留 2 位小数)、及格(≥60)人数。
- 打印全部学生列表。
- 进入按姓名查找循环:输入姓名,打印对应记录;输入
.退出查找。 - 查找不到时打印友好提示。
数据与接口约定#
#define MAX_STUDENTS 100
#define NAME_LEN 32
struct Student {
int id;
char name[NAME_LEN];
int score;
};
// 打印最高分、最低分、平均分、及格人数
void print_stats(struct Student *table, int count);
// 按姓名查找,返回下标;找不到返回 -1
int find_by_name(struct Student *table, int count, const char *name);测试输入(正常)#
$ 1001 Alice 85
$ 1002 Bob 92
$ 1003 Carol 55
$ 1004 Dave 73
$ 1005 Eve 68
$ 0
$ Alice
$ Bob
$ Eve
$ .错误输入#
$ abc Alice 85
$ 1002 Bob
$ 1003
$ 1004 Carol 105
$ 0上面的输入依次覆盖:学号不是数字、缺少分数、缺少姓名和分数,以及录入 105 分(分数范围由使用者负责校验)。
容量满测试:先快速录入 100 条,再尝试录第 101 条,应打印容量满提示。
预期运行示例#
Enter students (ID Name Score, 0 to finish):
$ 1001 Alice 85
$ 1002 Bob 92
$ 1003 Carol 55
$ 1004 Dave 73
$ 1005 Eve 68
$ 0
========== Statistics ==========
Max: 92
Min: 55
Average: 74.60
Pass: 4/5
========== Student List ==========
1001 Alice 85
1002 Bob 92
1003 Carol 55
1004 Dave 73
1005 Eve 68
Search by name (enter . to quit):
$ Alice
Found: 1001 Alice 85
$ Zoe
Not found
$ .参考实现#
#include <stdio.h>
#include <string.h>
#define MAX_STUDENTS 100
#define NAME_LEN 32
struct Student {
int id;
char name[NAME_LEN];
int score;
};
void print_stats(struct Student *table, int count)
{
if (count == 0) {
printf("No data\n");
return;
}
int max = table[0].score, min = table[0].score;
int sum = 0, pass = 0;
for (int i = 0; i < count; i++) {
int s = table[i].score;
if (s > max) max = s;
if (s < min) min = s;
sum += s;
if (s >= 60) pass++;
}
printf("Max: %d\n", max);
printf("Min: %d\n", min);
printf("Average: %.2f\n", (float)sum / count);
printf("Pass: %d/%d\n", pass, count);
}
int find_by_name(struct Student *table, int count, const char *name)
{
for (int i = 0; i < count; i++) {
if (strcmp(table[i].name, name) == 0) return i;
}
return -1;
}
int main(void)
{
struct Student table[MAX_STUDENTS];
int count = 0;
printf("Enter students (ID Name Score, 0 to finish):\n");
while (1) {
int id, score;
char name[NAME_LEN];
if (scanf("%d", &id) != 1) {
printf("ID is not a number, skipping\n");
while (getchar() != '\n');
continue;
}
if (id == 0) break;
if (scanf("%31s %d", name, &score) != 2) {
printf("Failed to read name or score, skipping\n");
while (getchar() != '\n');
continue;
}
if (count >= MAX_STUDENTS) {
printf("Capacity full (%d), stopping input\n", MAX_STUDENTS);
while (getchar() != '\n');
break;
}
table[count].id = id;
snprintf(table[count].name, sizeof(table[count].name), "%s", name);
table[count].score = score;
count++;
}
printf("\n========== Statistics ==========\n");
print_stats(table, count);
printf("\n========== Student List ==========\n");
for (int i = 0; i < count; i++) {
printf("%d %s %d\n", table[i].id, table[i].name, table[i].score);
}
printf("\nSearch by name (enter . to quit):\n");
char query[NAME_LEN];
while (scanf("%31s", query) == 1) {
if (strcmp(query, ".") == 0) break;
int idx = find_by_name(table, count, query);
if (idx >= 0) {
printf("Found: %d %s %d\n",
table[idx].id, table[idx].name, table[idx].score);
} else {
printf("Not found\n");
}
}
return 0;
}编译:gcc -Wall -o project1 阶段项目1-成绩统计器.c
验收清单#
- 正常输入 5 个学生,统计正确。
- 学号非数字时跳过,不崩溃。
- 姓名或分数缺失时跳过,不崩溃。
- 容量满时打印提示并停止录入。
- 查找存在的姓名,打印对应记录。
- 查找不存在的姓名,打印"未找到"。
- 输入
.正常退出查找循环。 - 0 条数据时统计不崩溃。
返回课程:第 6 章:字符串