一、实验目的
掌握线性表的链式存储结构及其基本操作。
二、实验内容
实现一个简单的学生信息管理系统,该系统的功能有:
1、利用单链表建立学生基本信息表;
2、浏览每个学生的信息;
3、根据学号查询某个学生的基本信息;
4、添加学生信息到单链表中;
5、删除一个学生的信息。
三、实验环境
Visual Studio 2022
四、实验内容与完成情况
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义学生信息结构体类型
struct Student {
char id[20];
char name[20];
int age;
char sex;
};
// 定义单链表的节点类型
struct Node {
struct Student data;
struct Node* next;
};
// 定义单链表类型
struct LinkedList {
struct Node* head; // 表头
int size;
};
// 初始化单链表
void initList(struct LinkedList* list) {
list->head = (struct Node*)malloc(sizeof(struct Node));
list->head->next = NULL;
list->size = 0;
}
// 浏览每个学生的信息
void browse(struct LinkedList* list) {
struct Node* p = list->head->next;
while (p != NULL) {
printf("学号:%s\t姓名:%s\t年龄:%d\t性别:%c\n",
p->data.id, p->data.name, p->data.age, p->data.sex);
p = p->next;
}
}
// 根据学号查询某个学生的基本信息
void search(struct LinkedList* list) {
char id[20];
printf("请输入要查询的学生学号:");
scanf("%s", id);
struct Node* p = list->head->next;
int found = 0;
while (p != NULL) {
if (strcmp(p->data.id, id) == 0) {
found = 1;
printf("学号:%s\t姓名:%s\t年龄:%d\t性别:%c\n",
p->data.id, p->data.name, p->data.age, p->data.sex);
break;
}
p = p->next;
}
if (!found) {
printf("未找到该学生信息!\n");
}
}
// 添加学生信息到单链表中
void add(struct LinkedList* list) {
char id[20];
char name[20];
int age;
char sex;
printf("请输入学生学号:");
scanf("%s", id);
printf("请输入学生姓名:");
scanf("%s", name);
printf("请输入学生年龄:");
scanf("%d", &age);
printf("请输入学生性别(M/F):");
scanf(" %c", &sex);
struct Node* p = (struct Node*)malloc(sizeof(struct Node));
strcpy(p->data.id, id);
strcpy(p->data.name, name);
p->data.age = age;
p->data.sex = sex;
p->next = list->head->next;
list->head->next = p;
list->size++;
printf("添加成功!\n");
}
// 删除一个学生的信息
void removeStudent(struct LinkedList* list) {
char id[20];
printf("请输入要删除的学生学号:");
scanf("%s", id);
struct Node* p = list->head;
int found = 0;
while (p->next != NULL) {
if (strcmp(p->next->data.id, id) == 0) {
found = 1;
struct Node* q = p->next;
p->next = q->next;
free(q);
list->size--;
printf("删除成功!\n");
break;
}
p = p->next;
}
if (!found) {
printf("未找到该学生信息!\n");
}
}
// 主函数
int main() {
struct LinkedList list;
initList(&list);
// 将这些学生信息加入到链表中
const char* ids[] = { "20180001","20180003","20180004","20180010",
"20180008","20180002","20180007","20180005",
"20180009","20180006" };
const char* names[] = { "王晓佳","林一鹏","谢宁","张丽娟","刘家琪",
"成平","赵学意","江永康","郑可欣","李小燕" };
int ages[] = { 21, 22, 23, 24, 23, 21, 23, 24, 23, 22 };
char sexes[] = { 'F', 'M', 'M', 'F', 'F',
'M', 'M', 'M', 'F', 'F' };
for (int i = 0; i < 10; i++) {
struct Node* p = (struct Node*)malloc(sizeof(struct Node));
strcpy(p->data.id, ids[i]);
strcpy(p->data.name, names[i]);
p->data.age = ages[i];
p->data.sex = sexes[i];
p->next = list.head->next;
list.head->next = p;
list.size++;
}
// 循环显示菜单,等待用户操作
while (1) {
printf("请选择要进行的操作:\n");
printf("1:浏览学生信息\n");
printf("2:查询学生信息\n");
printf("3:添加学生信息\n");
printf("4:删除学生信息\n");
printf("5:退出程序\n");
int control;
scanf("%d", &control);
switch (control) {
case 1:
browse(&list);
break;
case 2:
search(&list);
break;
case 3:
add(&list);
break;
case 4:
removeStudent(&list);
break;
case 5:
printf("程序已退出!\n");
return 0;
default:
printf("输入错误,请重新选择!\n");
}
}
return 0;
}
五、出现的问题及对问题的解决方案
1. 语法错误:因为写错标点符号、函数名等导致编译失败。解决方案: 认真检查代码并逐个排查可能存在错误的地方。
2. 提示" error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.",解决方案: 因为用CPP运行C语言程序中strcpy 函数不安全,可以使用更加安全的strcpy_s函数代替。也可以在文件开头加上一行代码:#define _CRT_SECURE_NO_WARNINGS。
六、实验思考
1.链表头节点的作用:链表头节点是指第一个节点之前的节点,它并不保存数据,只是为了方便操作而存在。在创建链表时,要给头节点分配内存空间,并将头节点的next指针初始化为NULL。
2.节点的创建和销毁:链表中的每个节点都需要动态申请内存空间,创建完之后需要手动释放。在插入和删除节点时,一定要注意释放被删除节点的内存空间,避免内存泄漏。
3.插入和删除节点:插入和删除节点时,需要考虑新节点的位置和相邻节点的关系。头插法和尾插法是两种常见的插入操作,头插法适用于不需要保持顺序的情况,而尾插法适用于需要保持顺序的情况。删除节点时,要先找到要删除节点的前驱节点,然后将前驱节点的next指针指向后继节点,最后释放被删除节点的内存空间。
4.遍历链表:遍历链表时,可以使用一个指针从头节点开始,逐一访问每个节点,直到最后一个节点。在访问每个节点时,可以使用节点中存储的数据,执行具体的操作。