一、代码实现
二、界面、录入和打印 功能点
三、增删改查 功能点
四、统计和退出 功能点
五、误输入功能测试
六、测试
一、代码实现
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 班级结构体
struct Class
{
int Class_ID;
struct Student *Studenthead; // 定义一个结构体指针指向学生信息链表指针
struct Class *next;
};
// 学生结构体
struct Student
{
int Student_ID;
char Student_name[10];
float Chinese;
float Math;
float English;
float sum;
float avg;
struct Student *next;
};
// 录入班级人数
void intput_Classstudentnum(int *cn, int *sn)
{
printf("请输入有几个班级: ");
scanf("%d", cn);
printf("请输入每个班级有几个学生: ");
scanf("%d", sn);
printf("#########################################\n");
}
// 班级链表尾插法
struct Class *insertClass(struct Class *head, struct Class *node) // 尾插法 第一个创建的是头节点 (顺序)
{
struct Class *pc = head;
if (pc == NULL)
{
head = node;
return head;
}
while (pc->next != NULL)
{
pc = pc->next;
}
pc->next = node;
return head;
}
// 学生链表尾插法
struct Student *insertStudent(struct Student *head, struct Student *node) // 尾插法 第一个创建的是头节点 (顺序)
{
struct Student *ps = head;
if (ps == NULL)
{
head = node;
return head;
}
while (ps->next != NULL)
{
ps = ps->next;
}
ps->next = node;
return head;
}
// 动态创建学生信息链表的内存
struct Student *create_Student(struct Student *Studenthead, int Class_ID, int sn)
{
struct Student *ps = Studenthead;
struct Student *node = NULL;
char name[10]; // 存储学生姓名的字符数组
for (int j = 0; j < sn; j++)
{
node = (struct Student *)malloc(sizeof(struct Student));
if (node == NULL)
{
// 处理内存分配失败的情况
printf("学生内存分配失败\n");
exit(1);
}
node->Student_ID = j + 1;
printf("请输入%d班第%d位学生信息\n", Class_ID, node->Student_ID);
printf("学生姓名: ");
scanf(" %s", name);
strcpy(node->Student_name, name);
printf("学生中文成绩: ");
scanf("%f", &(node->Chinese));
printf("学生数学成绩: ");
scanf("%f", &(node->Math));
printf("学生英文成绩: ");
scanf("%f", &(node->English));
node->sum = node->Chinese + node->Math + node->English;
node->avg = node->sum / 3;
Studenthead = insertStudent(Studenthead, node);
printf("------------------------------------\n");
}
printf("#########################################\n");
return Studenthead;
}
// 动态创建班级信息链表的内存
struct Class *create_Class(struct Class *head, int cn, int sn)
{
struct Class *pc = head;
struct Class *node = NULL;
for (int i = 0; i < cn; i++)
{
node = (struct Class *)malloc(sizeof(struct Class));
if (node == NULL)
{
// 处理内存分配失败的情况
printf("班级内存分配失败\n");
exit(1);
}
node->Class_ID = i + 1;
node->Studenthead = create_Student(node->Studenthead, node->Class_ID, sn);
head = insertClass(head, node);
}
return head;
}
// 计算学生节点的个数
int countNodesStudent(struct Class *head, int cn)
{
int count = 0; // 用来存储节点个数
struct Class *pc = head; // 从链表的头节点开始
struct Student *ps = head->Studenthead;
for (int i = 0; i < cn; i++)
{
pc = pc->next;
}
while (ps != NULL)
{
count++; // 增加计数器的值
ps = ps->next; // 移动到下一个节点
}
return count;
}
// 判断增删改查位置的有效性
int validity(struct Class *head, int markClass, int markStdent) // 有效性
{
struct Class *pc = head;
int cntClass = 1; // 用来记录当前班级的位置
while (pc != NULL)
{
if (cntClass == markClass)
{
// 班级位置有效
struct Student *ps = head->Studenthead;
int cntStudent = 1; // 用来记录当前学生的位置
while (ps != NULL)
{
if (cntStudent == markStdent)
{
// 学生位置有效
return 1;
}
cntStudent++;
ps = ps->next;
}
}
cntClass++;
pc = pc->next;
}
// mark 超出链表范围
printf("超出链表范围,请重新输入:\n");
return 0;
}
// 增加新的学生信息
void add(struct Class *head) // 增加节点
{
int positionClass = 0; // 班级节点位置
int positionStudent = 0; // 学生节点位置
struct Class *pc = head;
char newName[10];
int val = 0; // 效验位
while (val == 0)
{
printf("请输入要增加在第几个班级的里面:");
scanf("%d", &positionClass);
printf("请输入要增加在第几个学生的后面:");
scanf("%d", &positionStudent);
val = validity(head, positionClass, positionStudent);
}
printf("请输入要增加的学生信息:\n");
// 输入学生信息,包括学号、姓名和成绩等
struct Student *newStudent = (struct Student *)malloc(sizeof(struct Student));
if (newStudent == NULL)
{
printf("学生内存分配失败\n");
exit(1);
}
// 填充新学生的信息
newStudent->Student_ID = countNodesStudent(head, positionClass) + 1; // 请根据实际情况设置学号
printf("学生姓名: ");
scanf(" %s", newName);
strcpy(newStudent->Student_name, newName);
printf("学生中文成绩: ");
scanf("%f", &(newStudent->Chinese));
printf("学生数学成绩: ");
scanf("%f", &(newStudent->Math));
printf("学生英文成绩: ");
scanf("%f", &(newStudent->English));
newStudent->sum = newStudent->Chinese + newStudent->Math + newStudent->English;
newStudent->avg = newStudent->sum / 3;
// 找到要增加班级节点的位置
for (int i = 1; i < positionClass; i++)
{
pc = pc->next;
}
// 找到要插入学生节点的位置
struct Student *ps = pc->Studenthead;
for (int j = 1; j < positionStudent; j++)
{
ps = ps->next;
}
// 插入新学生节点
newStudent->next = ps->next;
ps->next = newStudent;
// 添加成功
printf("增加成功!!!\n");
printf("------------------------------------\n");
}
// 删除学生信息
void delete(struct Class *head) // 删除节点
{
int positionClass = 0; // 班级节点位置
int positionStudent = 0; // 学生节点位置
struct Class *pc = head;
int val = 0; // 效验位
while (val == 0)
{
printf("请输入要删除第几个班级的学生:");
scanf("%d", &positionClass);
printf("请输入要删除第几个学生:");
scanf("%d", &positionStudent);
val = validity(head, positionClass, positionStudent);
}
// 找到要删除班级节点的位置
for (int i = 1; i < positionClass; i++)
{
pc = pc->next;
}
// 找到要删除的学生节点的位置
struct Student *ps = pc->Studenthead;
if (positionStudent == 1)
{
// 如果要删除的是头节点,更新班级头节点指针
pc->Studenthead = ps->next;
free(ps);
}
else
{
// 如果要删除的不是头节点,找到要删除节点的前一个位
for (int j = 1; j < positionStudent - 1; j++)
{
ps = ps->next;
}
// 删除学生节点
struct Student *del = ps->next;
ps->next = del->next;
free(del);
}
// 删除成功
printf("删除成功!!!\n");
printf("------------------------------------\n");
}
// 查找学生信息
void search(struct Class *head) // 查找、搜索
{
int positionClass = 0; // 班级节点位置
int positionStudent = 0; // 学生节点位置
struct Class *pc = head;
int val = 0; // 效验位
while (val == 0)
{
printf("请输入要查找第几个班级的学生:");
scanf("%d", &positionClass);
printf("请输入要查找第几个学生:");
scanf("%d", &positionStudent);
val = validity(head, positionClass, positionStudent);
}
// 找到要查找班级节点的位置
for (int i = 1; i < positionClass; i++)
{
pc = pc->next;
}
// 找到要查找的学生节点的位置
struct Student *ps = pc->Studenthead;
for (int j = 1; j < positionStudent; j++)
{
ps = ps->next;
}
// 显示查询的学生信息
printf("你要查询的学生信息如下:\n");
printf("三年级%d班学生 学号: G3C0%dS00%d 姓名: %s\n", pc->Class_ID, pc->Class_ID, ps->Student_ID, ps->Student_name);
printf("各科的成绩: 中文:%0.1f分 数学:%0.1f分 英文:%0.1f分\n", ps->Chinese, ps->Math, ps->English);
printf("总分:%0.2f分 平均分:%0.2f分\n", ps->sum, ps->avg);
printf("------------------------------------\n");
}
// 修改学生信息
void modify(struct Class *head) // 修改、修正
{
int positionClass = 0; // 班级节点位置
int positionStudent = 0; // 学生节点位置
struct Class *pc = head;
int val = 0; // 效验位
while (val == 0)
{
printf("请输入要修改第几个班级的学生:");
scanf("%d", &positionClass);
printf("请输入要修改第几个学生:");
scanf("%d", &positionStudent);
val = validity(head, positionClass, positionStudent);
}
// 找到要修改班级节点的位置
for (int i = 1; i < positionClass; i++)
{
pc = pc->next;
}
// 找到要修改的学生节点的位置
struct Student *ps = pc->Studenthead;
for (int j = 1; j < positionStudent; j++)
{
ps = ps->next;
}
// 修改学生信息
printf("请输入修改后的学生信息: \n");
printf("三年级%d班学生 学号: G3C0%dS00%d 姓名: %s\n", pc->Class_ID, pc->Class_ID, ps->Student_ID, ps->Student_name);
printf("学生中文成绩: ");
scanf("%f", &(ps->Chinese));
printf("学生数学成绩: ");
scanf("%f", &(ps->Math));
printf("学生英文成绩: ");
scanf("%f", &(ps->English));
ps->sum = ps->Chinese + ps->Math + ps->English;
ps->avg = ps->sum / 3;
// 修改成功
printf("修改成功!!!\n");
printf("------------------------------------\n");
}
// 学生中文成绩
void Chinese_MaxScore(struct Class *head, int cn, int sn)
{
struct Class *pc = head;
float maxScore = 0;
int studentNum;
int classNun;
char name[10];
for (int i = 0; i < cn; i++)
{
struct Student *ps = pc->Studenthead;
for (int j = 0; j < sn; j++)
{
if (maxScore < ps->Chinese)
{
maxScore = ps->Chinese;
classNun = pc->Class_ID;
studentNum = ps->Student_ID;
strcpy(name, ps->Student_name);
}
ps = ps->next;
}
pc = pc->next;
}
printf("---------------年级中文最高分--------------\n");
printf("中文最高分是: %d班 学号: G3C0%dS00%d 姓名: %s 分数: %0.1f分\n", classNun, classNun, studentNum, name, maxScore);
}
// 学生数学成绩
void Math_MaxScore(struct Class *head, int cn, int sn)
{
struct Class *pc = head;
float maxScore = 0;
int studentNum;
int classNun;
char name[10];
for (int i = 0; i < cn; i++)
{
struct Student *ps = pc->Studenthead;
for (int j = 0; j < sn; j++)
{
if (maxScore < ps->Math)
{
maxScore = ps->Math;
classNun = pc->Class_ID;
studentNum = ps->Student_ID;
strcpy(name, ps->Student_name);
}
ps = ps->next;
}
pc = pc->next;
}
printf("---------------年级数学最高分--------------\n");
printf("数学最高分是: %d班 学号: G3C0%dS00%d 姓名: %s 分数: %0.1f分\n", classNun, classNun, studentNum, name, maxScore);
}
// 学生英文成绩
void English_MaxScore(struct Class *head, int cn, int sn)
{
struct Class *pc = head;
float maxScore = 0;
int studentNum;
int classNun;
char name[10];
for (int i = 0; i < cn; i++)
{
struct Student *ps = pc->Studenthead;
for (int j = 0; j < sn; j++)
{
if (maxScore < ps->English)
{
maxScore = ps->English;
classNun = pc->Class_ID;
studentNum = ps->Student_ID;
strcpy(name, ps->Student_name);
}
ps = ps->next;
}
pc = pc->next;
}
printf("---------------年级英文最高分--------------\n");
printf("英文最高分是: %d班 学号: G3C0%dS00%d 姓名: %s 分数: %0.1f分\n", classNun, classNun, studentNum, name, maxScore);
}
// 年纪平均分
void Grade_Avg(struct Class *head, int cn, int sn)
{
struct Class *pc = head;
int gradeSum = 0;
int gradesn = 0;
float gradeAvg = 0.0;
for (int i = 0; i < cn; i++)
{
struct Student *ps = pc->Studenthead;
for (int j = 0; j < sn; j++)
{
gradeSum += ps->sum;
gradesn++;
ps = ps->next;
}
pc = pc->next;
}
if (gradesn > 0)
{
gradeAvg = (float)gradeSum / gradesn;
}
printf("---------------年级平均分--------------\n");
printf("年级平均分是: %0.2f分\n", gradeAvg);
}
// 统计学生各科的结果
void result(struct Class *head, int cn, int sn)
{
Chinese_MaxScore(head, cn, sn);
Math_MaxScore(head, cn, sn);
English_MaxScore(head, cn, sn);
Grade_Avg(head, cn, sn);
}
// 打印各个学生的相关信息
int printMessage(struct Class *head)
{
struct Class *pc = head;
int totalStudent = 0; // 用来计算第几个学生的
// 遍历班级
while (pc != NULL)
{
printf("三年级%d班的学生信息如下:\n", pc->Class_ID);
struct Student *ps = pc->Studenthead;
// 遍历学生
while (ps != NULL)
{
totalStudent++;
printf("三年级第%d个学生学生信息如下:\n", totalStudent);
printf("三年级%d班学生 学号: G3C0%dS00%d 姓名: %s\n", pc->Class_ID, pc->Class_ID, ps->Student_ID, ps->Student_name);
printf("各科的成绩: 中文:%0.1f分 数学:%0.1f分 英文:%0.1f分\n", ps->Chinese, ps->Math, ps->English);
printf("总分:%0.2f分 平均分:%0.2f分\n", ps->sum, ps->avg);
printf("------------------------------------\n");
ps = ps->next;
}
pc = pc->next;
}
printf("#########################################\n");
return totalStudent;
}
// 释放malloc的内存
void release(struct Class *head)
{
struct Class *freeClass = head;
while (freeClass != NULL)
{
struct Class *nextClass = freeClass->next;
// 释放当前班级的学生信息内存
struct Student *freeStudent = freeClass->Studenthead;
while (freeStudent != NULL)
{
struct Student *nextStudent = freeStudent->next;
free(freeStudent);
freeStudent = nextStudent;
}
// 释放当前班级的内存
free(freeClass);
freeClass = nextClass;
}
head = NULL;
}
// 系统目录
void menu()
{
printf("****************************************\n");
printf("******* 学生信息系统 *******\n");
printf("****************************************\n");
printf("******* 1.录入学生信息 *******\n");
printf("*******--------------------------*******\n");
printf("******* 2.添加学生信息 *******\n");
printf("*******--------------------------*******\n");
printf("******* 3.删除学生信息 *******\n");
printf("*******--------------------------*******\n");
printf("******* 4.查询学生信息 *******\n");
printf("*******--------------------------*******\n");
printf("******* 5.修改学生信息 *******\n");
printf("*******--------------------------*******\n");
printf("******* 6.统计学生信息 *******\n");
printf("*******--------------------------*******\n");
printf("******* 7.打印学生信息 *******\n");
printf("*******--------------------------*******\n");
printf("******* 0.退出系统 *******\n");
printf("****************************************\n");
}
int main()
{
struct Class *head = NULL;
int cn, sn; // classnum,studentnum;
int intput = 0;
do
{
menu();
printf("请输入选择: ");
scanf("%d", &intput);
getchar();
printf("#########################################\n");
switch (intput)
{
case 1:
intput_Classstudentnum(&cn, &sn);
head = create_Class(head, cn, sn);
break;
case 2:
add(head);
break;
case 3:
delete (head);
break;
case 4:
search(head);
break;
case 5:
modify(head);
break;
case 6:
result(head, cn, sn);
break;
case 7:
printMessage(head);
break;
case 0:
release(head);
printf("退出\n");
break;
default:
printf("选择错误,请重新输入!\n");
break;
}
} while (intput);
return 0;
}
// printf("[%s:%d]:pc = %p\n", __func__, __LINE__, pc);//调试信息
二、界面、录入和打印 功能点
1. 界面
2. 录入
3. 打印
三、增删改查 功能点
1. 查找
2. 修改![请添加图片描述](https://i-blog.csdnimg.cn/blog_migrate/42e0d704ef8df4c3627338bcbef51941.png)
3. 增加
4. 删除
before
删除之前的结果
添加了头节点判断
after
四、统计和退出 功能点
1. 统计学生成绩
2. 退出
五、误输入功能测试
1. 错误输入界面选择信息看是否提示
2. 错误增加到超出链表范围和判断边界是否有效等
3. 在输入整型的时候地方输入符号(可以增加一些功能点提示)
六、测试
软件测试是确保软件质量的关键活动之一。测试的目的是发现和纠正潜在的问题,以确保软件在实际使用中能够正常运行。以下是一些常见的软件测试方法:
- 单元测试(Unit Testing):
单元测试是针对代码中的最小单元(通常是函数或方法)的测试。
它通常由开发人员编写,用于验证单元是否按照预期工作。
单元测试通常是自动化的,可以频繁运行以捕获代码中的问题。
- 集成测试(Integration Testing):
集成测试是测试不同模块或组件之间的交互。
它旨在检测组件之间的接口问题和交互问题。
可以通过逐步集成组件并测试它们的方式进行。
- 功能测试(Functional Testing):
功能测试是验证软件的功能是否按照规范工作的测试。
它测试软件是否实现了其规格说明中定义的功能。
常见的功能测试包括黑盒测试、白盒测试、用户界面测试等。
- 性能测试(Performance Testing):
性能测试是验证软件在不同负载下的性能和稳定性的测试。
它包括负载测试、性能测试、压力测试和可伸缩性测试,用于检测性能瓶颈和资源利用率。
- 安全测试(Security Testing):
安全测试旨在发现软件中的潜在安全漏洞。
它包括渗透测试、授权测试、认证测试等,以确保软件对恶意攻击具有一定的抵御能力。
- 回归测试(Regression Testing):
回归测试是在对软件进行更改后重新运行先前的测试,以确保新更改未引入新问题或导致现有问题。
它通常与持续集成一起使用,以确保代码变更不会破坏现有功能。
- 用户验收测试(User Acceptance Testing,UAT):
UAT是由最终用户或客户执行的测试,以验证软件是否满足其预期需求和使用情况。
它通常发生在软件交付给客户之前。
探索性测试(Exploratory Testing):
探索性测试是一种以探索为目的的测试方法,测试人员会在没有明确测试计划的情况下尝试各种情况。
它有助于发现未知的问题和异常情况。
- 自动化测试(Automated Testing):
自动化测试是使用自动化测试工具来执行测试用例的方法。
它可以提高测试效率和一致性,尤其是在回归测试中。
这些是常见的测试方法,具体的测试策略和方法取决于项目的特定需求和软件类型。通常,综合使用多种测试方法来确保软件质量。
结论
在开发用户友好的应用程序时,开发人员需要密切关注用户界面设计、输入验证、错误处理和用户反馈。此外,与测试、设计和产品管理等其他岗位的协作对于确保应用程序质量和用户友好性也至关重要。通过综合利用这些策略和最佳实践,你可以降低用户误操作的风险,提供更好的用户体验。