1. 示例代码
1) status.h
/* DataStructure 预定义常量和类型头文件 */#ifndef STATUS_H
#define STATUS_H/* 函数结果状态码 */
#define TRUE 1 /* 返回值为真 */
#define FALSE 0 /* 返回值为假 */
#define RET_OK 0 /* 返回值正确 */
#define INFEASIABLE 2 /* 返回值未知 */
#define ERR_MEMORY 3 /* 访问内存错 */
#define ERR_NULL_PTR 4 /* 空指针错误 */
#define ERR_MEMORY_ALLOCATE 5 /* 内存分配错 */
#define ERR_NULL_STACK 6 /* 栈元素为空 */
#define ERR_PARA 7 /* 函数参数错 */
#define ERR_OPEN_FILE 8 /* 打开文件错 */
#define ERR_NULL_QUEUE 9 /* 队列为空错 */
#define ERR_FULL_QUEUE 10 /* 队列为满错 */
typedef int Status; /* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean; /* Boolean 是布尔类型,其值是 TRUE 或 FALSE */#endif // !STATUS_H
2) singleLinkList.h
/* 线性表的单链表存储结构头文件 */#ifndef SINGLELINKLIST_H
#define SINGLELINKLIST_H#include "status.h"#define NAMELEN 20 /* 姓名最大长度 */
#define CLASSLEN 10 /* 班级名最大长度 */
#define HEALTHLEN 10 /* 健康状态字符长度 */
#define N 4 /* 学生个数 */typedef struct {char name[NAMELEN];long studentId;char sex;int age;char className[CLASSLEN];int healthState;
} StudentInfo;typedef StudentInfo ElemType;typedef struct LNode {ElemType data;struct LNode *next;
} *LinkList;/* 辅助函数,创建一个新的节点 */
LinkList MakeNewLNode(ElemType e);/* 操作结果:构造一个空的线性表 L */
Status InitList(LinkList *L);/* 初始条件:线性表 L 已存在。操作结果:销毁线性表 L */
Status DestroyList(LinkList *L);/* 初始条件:线性表 L 已存在。操作结果:将 L 重置为空表 */
Status ClearList(LinkList L);/* 初始条件:线性表 L 已存在。操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE */
Status ListEmpty(LinkList L);/* 初始条件:线性表 L 已存在。操作结果:返回 L 中数据元素个数 */
int ListLength(LinkList L);/* 算法 2.8,L 为带头结点的单链表的头指针。当第 i 个元素存在时, 其值赋给 e 并返回 OK,否则返回 ERROR */
Status GetElem(LinkList L, int i, ElemType *e);/* 初始条件: 线性表 L 已存在, compare() 是数据元素判定函数(满足为 1,否则为 0)操作结果: 返回 L 中第 1 个与 e 满足关系 compare() 的数据元素的位序。若这样的数据元素不存在,则返回值为 0 */
int LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType));/* 算法 2.9,在带头结点的单链线性表 L 中第 i 个位置之前插入元素 e */
Status ListInsert(LinkList L, int i, ElemType e);/* 算法 2.10,在带头结点的单链线性表 L 中,删除第 i 个元素,并由 e 返回其值 */
Status ListDelete(LinkList L, int i, ElemType* e);/* 按学号非降序插入 */
void InsertAscend(LinkList L, ElemType e);#endif
3) singleLinkList.c
/* 线性表的单链表存储结构源文件实现 */#include "singleLinkList.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>/* 辅助函数,创建一个新的节点 */
LinkList MakeNewLNode(ElemType e)
{LinkList newLNode = (LinkList)malloc(sizeof(struct LNode));if (!newLNode) {printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);return NULL;}newLNode->data = e;newLNode->next = NULL;return newLNode;
}/* 操作结果:构造一个空的线性表 L */
Status InitList(LinkList *L)
{*L = (LinkList)malloc(sizeof(struct LNode));if (!(*L)) {printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);return ERR_MEMORY_ALLOCATE;}(*L)->next = NULL;return RET_OK;
}/* 初始条件:线性表 L 已存在。操作结果:销毁线性表 L */
Status DestroyList(LinkList *L)
{LinkList q;while (*L) {q = (*L)->next;free(*L);*L = q;}return RET_OK;
}/* 初始条件:线性表 L 已存在。操作结果:将 L 重置为空表 */
Status ClearList(LinkList L)
{LinkList p, q;p = L->next;while (p) {q = p->next;free(p);p = q;}L->next = NULL;return RET_OK;
}/* 初始条件:线性表 L 已存在。操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE */
Status ListEmpty(LinkList L)
{if (L->next) {return FALSE;}return TRUE;
}/* 初始条件:线性表 L 已存在。操作结果:返回 L 中数据元素个数 */
int ListLength(LinkList L)
{int count = 0;LinkList p = L->next;while (p) {++count;p = p->next;}return count;
}/* 算法 2.8,L 为带头结点的单链表的头指针。当第 i 个元素存在时, 其值赋给 e 并返回 RET_OK,否则返回 ERROR */
Status GetElem(LinkList L, int i, ElemType *e)
{int j = 1;LinkList p = L->next;while (p && j < i) {p = p->next;++j;}if (!p || j > i) { /* j > i 适用于 i < 1 时,如 i = 0 */printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);return ERR_PARA;}*e = p->data;return RET_OK;
}/* 初始条件: 线性表 L 已存在, compare() 是数据元素判定函数(满足为 1,否则为 0)操作结果: 返回 L 中第 1 个与 e 满足关系 compare() 的数据元素的位序。若这样的数据元素不存在,则返回值为 0 */
int LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType))
{int i = 0;LinkList p = L->next;while (p) {++i;if (compare(p->data, e)) {return i;}p = p->next;}return 0;
}/* 算法 2.9,在带头结点的单链线性表 L 中第 i 个位置之前插入元素 e */
Status ListInsert(LinkList L, int i, ElemType e)
{int j = 0;LinkList p = L;while (p && j < i - 1) {++j;p = p->next;}if (!p || j > i - 1) { /* 超出表长或者 i < 1 */printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);return ERR_PARA;}LinkList newLNode = MakeNewLNode(e);if (!newLNode) {printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);return ERR_MEMORY_ALLOCATE;}newLNode->next = p->next;p->next = newLNode;return RET_OK;
}/* 算法 2.10,在带头结点的单链线性表 L 中,删除第 i 个元素,并由 e 返回其值 */
Status ListDelete(LinkList L, int i, ElemType *e)
{int j = 0;LinkList p = L;while (p->next && j < i - 1) {++j;p = p->next;}if (!p->next || j > i - 1) { /* 理论上 j 最多只能等于 i - 1, 但此处当参数不合法时可用, 建议单独判断参数合法性 */printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);return ERR_PARA;}LinkList q = p->next;p->next = q->next;*e = q->data;free(q);return RET_OK;
}/* 初始条件:线性表 L 已存在操作结果:依次对 L 的每个数据元素调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(LinkList L, void(*vi)(ElemType))
{LinkList p = L->next;while (p) {vi(p->data);p = p->next;}return RET_OK;
}/* 按学号非降序插入 */
void InsertAscend(LinkList L, ElemType e)
{LinkList q = L, p = L->next;while (p && e.studentId > p->data.studentId) {q = p;p = p->next;}q->next = MakeNewLNode(e);q->next->next = p;
}
4) studentHealthRecord.h
/* 学生健康登记表定义头文件 */#ifndef STUDENTSHEALTHRECORD_H
#define STUDENTSHEALTHRECORD_H#include "status.h"
#include "singleLinkList.h"
#include <stdio.h>/* 打印学生信息 */
void PrintStuentInfo(char healthState[][HEALTHLEN], int arrayLen, ElemType e);/* 读入学生信息 */
void ReadIn(char healthState[][HEALTHLEN], int arrayLen, ElemType *e);/* 将学生信息写入指定文件 */
void WriteToFile(ElemType e, FILE *fp);/* 由 fp 指定文件读取学生信息到 e */
Status ReadFromFile(ElemType *e, FILE *fp);/* 查找表中学号为 studentId 的结点,如找到,q 指向此结点, p 指向 q 的前驱并返回 TRUE; 如无此元素,则返回 FALSE */
Status FindByStudentId(LinkList L, long studentId, LinkList *p, LinkList *q);/* 查找表中姓名为 name 的结点,如找到,q 指向此结点, p 指向 q 的前驱并返回 TRUE; 如无此元素,则返回 FALSE */
Status FindByName(LinkList L, char name[], LinkList *p, LinkList *q);/* 删除表中学号为 studentId 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteByStudentId(LinkList L, long studentId);/* 删除表中姓名为 name 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteByName(LinkList L, char name[]);/* 修改学生信息 */
void ModifyStudentInfo(char healthState[][HEALTHLEN], int arrayLen, ElemType *e);/* 显示操作选项 */
void ShowMenu(void);#endif // !STUDENTSHEALTHRECORD_H
5) studentHealthRecord.c
/* 学生健康登记表实现源文件 */#include "studentHealthRecord.h"
#include <string.h>
#include <stdlib.h>/* 打印学生信息 */
void PrintStuentInfo(char healthState[][HEALTHLEN], int arrayLen, ElemType e)
{if (e.healthState > arrayLen - 1) {printf("Error: Parameter out of bounds!\n");return;}printf("%-10s%-10ld", e.name, e.studentId);if (e.sex == 'm') {printf(" Man");}else {printf(" Female");}printf("%10d%10s%10s\n", e.age, e.className, healthState[e.healthState]);
}/* 读入学生信息 */
void ReadIn(char healthState[][HEALTHLEN], int arrayLen, ElemType *e)
{printf("Please input name(No more than %d characters): ", NAMELEN);scanf_s("%s", e->name, (unsigned int)sizeof(e->name));getchar();printf("Please input the student ID: ");scanf_s("%ld", &e->studentId);getchar();printf("Please input the gender: ");scanf_s("%c", &e->sex, 1);getchar();printf("Please input the age: ");scanf_s("%d", &e->age);getchar();printf("Please input the class name: ");scanf_s("%s", e->className, (unsigned int)sizeof(e->className));getchar();printf("Please input the health state(");for (int i = 0; i < arrayLen; ++i) {printf("%d: %s ", i, healthState[i]);}printf("): ");scanf_s("%d", &e->healthState);getchar();
}/* 将学生信息写入指定文件 */
void WriteToFile(ElemType e, FILE *fp)
{fwrite(&e, sizeof(StudentInfo), 1, fp);
}/* 由 fp 指定文件读取学生信息到 e */
Status ReadFromFile(ElemType *e, FILE *fp)
{size_t ret = fread(e, sizeof(StudentInfo), 1, fp);return (ret == 1) ? 1 : 0;
}/* 查找表中学号为 studentId 的结点,如找到,q 指向此结点, p 指向 q 的前驱并返回 TRUE; 如无此元素,则返回 FALSE */
Status FindByStudentId(LinkList L, long studentId, LinkList *p, LinkList *q)
{*p = L;while (*p) {*q = (*p)->next;if (*q && (*q)->data.studentId > studentId) {break;}if (*q && (*q)->data.studentId == studentId) {return TRUE;}*p = *q;}return FALSE;
}/* 查找表中姓名为 name 的结点,如找到,q 指向此结点, p 指向 q 的前驱并返回 TRUE; 如无此元素,则返回 FALSE */
Status FindByName(LinkList L, char name[], LinkList *p, LinkList *q)
{*p = L;while (*p) {*q = (*p)->next;if (*q && !strcmp((*q)->data.name, name)) {return TRUE;}*p = *q;}return FALSE;
}/* 删除表中学号为 studentId 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteByStudentId(LinkList L, long studentId)
{LinkList p, q;if (FindByStudentId(L, studentId, &p, &q)) {p->next = q->next;free(q);return TRUE;}return FALSE;
}/* 删除表中姓名为 name 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteByName(LinkList L, char name[])
{LinkList p, q;if (FindByName(L, name, &p, &q)) {p->next = q->next;free(q);return TRUE;}return FALSE;
}/* 修改学生信息 */
void ModifyStudentInfo(char healthState[][HEALTHLEN], int arrayLen, ElemType *e)
{PrintStuentInfo(healthState, arrayLen, *e);printf("Please input the content you want to modify, or click Enter to cancel\n");char str[100];printf("Please input name(No more than %d characters): ", NAMELEN);if (gets_s(str, sizeof(str)) == NULL) {printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);}if (strlen(str)) {strcpy_s(e->name, sizeof(e->name), str); /* 第二个参数为目标缓冲区大小 */}printf("Please input student ID: ");if (gets_s(str, sizeof(str)) == NULL) {printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);}if (strlen(str)) {e->studentId = atol(str);}printf("Please input gender(m: Man f: Female): ");if (gets_s(str, sizeof(str)) == NULL) {printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);}if (strlen(str)) {e->sex = str[0];}printf("Please input age: ");if (gets_s(str, sizeof(str)) == NULL) {printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);}if (strlen(str)) {e->age = atoi(str);}printf("Please input class name(No more than %d characters): ", CLASSLEN);if (gets_s(str, sizeof(str)) == NULL) {printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);}if (strlen(str)) {strcpy_s(e->className, sizeof(e->className), str);}printf("Please input the health state(");for (int i = 0; i < arrayLen; ++i) {printf("%d: %s ", i, healthState[i]);}printf("): ");if (gets_s(str, sizeof(str)) == NULL) {printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);}if (strlen(str)) {e->healthState = atoi(str);}
}void ShowMenu(void)
{printf("1: 将结构体数组 student 中的记录按学号非降序插入链表\n");printf("2: 将文件中的记录按学号非降序插入链表\n");printf("3: 键盘输入新记录,并将其按学号非降序插入链表\n");printf("4: 删除链表中第一个有给定学号的记录\n");printf("5: 删除链表中第一个有给定姓名的记录\n");printf("6: 修改链表中第一个有给定学号的记录\n");printf("7: 修改链表中第一个有给定姓名的记录\n");printf("8: 查找链表中第一个有给定学号的记录\n");printf("9: 查找链表中第一个有给定姓名的记录\n");printf("10: 显示所有记录\n");printf("11: 将链表中的所有记录存入文件\n");printf("12: 结束\n");printf(" 请选择操作命令: ");
}
6) main.c
/* 入口程序源文件 */#include "studentHealthRecord.h"
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>int main(void)
{char healthState[3][10] = { "Health", "Normal", "Unhealth" };StudentInfo student[N] = {{ "王小林", 790631, 'm', 18, "计91", 0 },{ "陈红", 790632, 'f', 20, "计91", 1 },{ "刘建平", 790633, 'm', 21, "计91", 0 },{ "张立立", 790634, 'm', 17, "计91", 2 }};bool flag = true;int choose;LinkList studentList;InitList(&studentList);ElemType e;char fileName[30];long studentId;char name[30];LinkList p, q;while (flag) {ShowMenu();scanf_s("%d", &choose);switch (choose) {case 1:for (int i = 0; i < N; ++i) {InsertAscend(studentList, student[i]);}break;case 2: printf("Please input file name: ");scanf_s("%s", fileName, (unsigned int)sizeof(fileName));FILE* fp;errno_t err_ret = fopen_s(&fp, fileName, "rb");if ( err_ret != 0) {printf("Open file failed!\n");}else {while (ReadFromFile(&e, fp)) {InsertAscend(studentList, e);}fclose(fp);}break;case 3: ReadIn(healthState, 3, &e);InsertAscend(studentList, e);break;case 4: printf("Please input the student ID to delete: ");scanf_s("%ld", &studentId);if (!DeleteByStudentId(studentList, studentId)) {printf("Error: No record of student ID of %ld.\n", studentId);}break;case 5:printf("Please input the name of the student of record to be deleted: ");scanf_s("%s", name, (unsigned int)sizeof(name));if (!DeleteByName(studentList, name)) {printf("Error: No record of student name of %s.", name);}break;case 6:printf("Please input the student ID of the record to be modified: ");scanf_s("%ld", &studentId);getchar();if (!FindByStudentId(studentList, studentId, &p, &q)) {printf("No record of the student Id of %ld\n", studentId);}else {ModifyStudentInfo(healthState, 3, &q->data);if (q->data.studentId != studentId) {p->next = q->next;InsertAscend(studentList, q->data);free(q);}}break;case 7:printf("Please input the name of the student of record to be deleted: ");scanf_s("%s", name, (unsigned int)sizeof(name));if (!FindByName(studentList, name, &p, &q)) {printf("No record of name of student %s.\n", name);}else {studentId = q->data.studentId;ModifyStudentInfo(healthState, 3, &q->data);if (q->data.studentId != studentId) {p->next = q->next;InsertAscend(studentList, q->data);free(q);}}break;case 8:printf("Please input the student ID of the record to be found: ");scanf_s("%ld", &studentId);if (!FindByStudentId(studentList, studentId, &p, &q)) {printf("No record of the student ID of %ld\n", studentId);}else {PrintStuentInfo(healthState, 3, q->data);}break;case 9:printf("Please input the name of the student of the record to be found: ");scanf_s("%s", name, (unsigned int)sizeof(name));if (!FindByName(studentList, name, &p, &q)) {printf("No record of the student name of %s.\n", name);}else {PrintStuentInfo(healthState, 3, q->data);}break;case 10:p = studentList->next;while (p) {PrintStuentInfo(healthState, 3, p->data);p = p->next;}break;case 11:printf("Please input the file name: ");scanf_s("%s", fileName, (unsigned int)sizeof(fileName));err_ret = fopen_s(&fp, fileName, "wb+");if (err_ret != 0) {printf("Open file failed!\n");}else {LinkList p = studentList->next;while (p) {WriteToFile(p->data, fp);p = p->next;}}fclose(fp);break;case 12:flag = false;}}int ret = DestroyList(&studentList);if (ret != RET_OK) {printf("Error: Destroy list failed!\n");}return 0;
}
2. 输出示例