基于单链表实现简单的学生管理系统(纯C)

为方便展示,所以全部代码放在一个文件中。
流程图:
在这里插入图片描述

代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define Status int  //Status 有状态的意思,旨在记录函数运行后的状态
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0

#define STD //控制手动输入还是读取文件输入

typedef struct student //学生结构体定义
{
	char id[10];  //学号
	char name[20]; //姓名
	int age; //年龄
	char sex; //性别 W为女,M为男
	char born[20]; //出生年月
	char addr[20]; //地址
	char phone[15]; //电话
	char email[20]; //E-mail
}Stu;

typedef Stu ElemType;

typedef struct LNode { //链表的结构体定义
	ElemType data;
	struct LNode *next;
}LNode,*List;

//初始化链表
void InitList(List *L);
//求链表的长度
int ListLength(List L);
//在链表第i个元素之前插入e
Status ListInsert(List L, int i, ElemType e);
//删除第i个元素,并将该元素的值给e
Status ListDelete(List L, int i, ElemType *e);
//在L中查找满足函数cmp()的元素e,若找到返回其序号,没找到返回0
int MyFindList(List L, ElemType e, int(*cmp)(ElemType, ElemType));
//将L中第i个元素的数据给e
Status GetStu(List L, int i, ElemType *e);
//对L中的元素一次调用函数visit()
int TraverseList(List L, int(*visit)(ElemType e)); //没使用
//该函数用于MyFindList()
int cmp_name(ElemType a, ElemType b);
该函数用于MyFindList()
//int cmp_id(ElemType a, ElemType b)  //作为函数参数,辅助其他函数
//{
//	return strcmp(a.id, b.id);
//}


//打印学生结构体信息,可用于TraverseList()
void my_scanf_stu(ElemType *S);
//输入学生结构体信息
void my_print_stu(Stu S);
//将第i个位置的元素的数据改为e
Status change_stu(List L, int i, ElemType e);
//在L中交换结点e1和结点e2的位置
void swap(List *L, ElemType e1, ElemType e2);
//根据姓名的字母进行排序
void selet_sort(List *L);
//使用文件进行数据的输入
void my_scan_file(List L, int n_stu);

int main()   
{
	List L = NULL;
	ElemType e;
	char ch;
	int n_stu;
	printf("输入1--建表 输入2-录入 输入3--删除 输入4--查询\n");
	printf("输入5--遍历 输入6--修改 输入7--排序 输入#--退出!\n<<  ");
	while ((ch = getchar()) != '#')
	{
		if (ch == '\n')
			continue;
		while (ch != '\n' && getchar() != '\n');
		//if (getchar() != '\n')
		//{
		//	while (getchar() != '\n'); //过滤多余垃圾字符
		//	printf("请按要求输入!\n<<  ");
		//	continue;
		//}
		switch (ch)
		{
		case '1':
			if (L == NULL)
			{
				InitList(&L);
				printf("建表成功,请重新指定操作\n");
			}
			else
				printf("表已经建立,请不要重复,请重新指定操作\n");
			break;
		case '2':
			if (L != NULL)
			{
				printf("输入即将录入学生的人数: ");
				scanf("%d", &n_stu);
#ifdef STD
				while (n_stu--) //循环录入n_stu的学生的信息
				{
					my_scanf_stu(&e);

					while (getchar() != '\n'); //用于清理输入缓存之类的
					if (!ListInsert(L, 1, e))
					{
						printf("录入失败,分支2出错!\n");
					}
				}
#else 
				my_scan_file(L, n_stu);
				printf("录入成功,请重新指定操作\n");
#endif
				
			}
			else
				printf("请先建表,请重新指定操作\n");
			break;
		case '3':

			if (L != NULL)
			{
				printf("输入学生名字进行删除!\n");
				scanf("%s", e.name);
				while (getchar() != '\n');
				if (ListDelete(L, MyFindList(L, e, cmp_name), &e))
				{
					my_print_stu(e);
					printf("已被删除,请重新指定操作\n");
				}
				else
				{
					printf("删除失败,请重新指定操作\n");
				}
			}
			else
				printf("请先建表,请重新指定操作\n");
			break;
		case '4':
			printf("输入学生名字进行查询!\n");
			scanf("%s", e.name);
			while (getchar() != '\n');
			if (GetStu(L, MyFindList(L, e, cmp_name), &e))
			{
				printf("该学生的信息为:\n");
				my_print_stu(e);
				printf("\n请重新指定操作\n");
			}
			else
				printf("不存在该学生,请重新指定操作\n");
			break;
		case '5':
			if (L != NULL)
			{
				List t=L->next;
				for (int i = 0; i < ListLength(L); ++i)
				{
					my_print_stu(t->data);
					putchar('\n');
					t = t->next;
				}
				printf("已完成遍历,请重新指定操作\n");
			}
			else
				printf("请先建表,请重新指定操作\n");
			break;
		case '6':
			if (L != NULL)
			{
				printf("输入学生名字进行修改!\n");
				scanf("%s", e.name);
				while (getchar() != '\n');
				n_stu = MyFindList(L, e, cmp_name); //返回位序
				ListDelete(L, n_stu, &e); //删除
				printf("请重新输入要修改学生的信息!\n");
				my_scanf_stu(&e);  //输入
				ListInsert(L, n_stu, e); //插入
				while (getchar() != '\n'); //用于清理输入缓存之类的
				printf("修改成功,请重新指定操作\n");
			}
			else
				printf("请先建表,请重新指定操作\n");

			break;
		case '7':
			if (L != NULL)
			{

				selet_sort(&L);
				printf("排序成功,请重新指定操作\n");
				
			}
			else
				printf("请先建表,请重新指定操作\n");
		}
		printf("<<  ");
		
	}

	printf("ending good luck!\n");
	return 0;
}


void InitList(List *L)
{
	*L = (LNode*)malloc(sizeof(LNode));
	if (*L == NULL) exit(OVERFLOW);  //申请内存失败
	(*L)->next = NULL
		;	
}
int ListLength(List L)  //求链表长度
{
	int j = 0;
	while (L->next)
	{
		j++;
		L = L->next;
	}
	return j;
}
Status ListInsert(List L, int i, ElemType e)
{
	//在带头节点的单链线性表L中第i个位置之前插入元素e
	int j = 0;
	List p = L, s;
	while (p && j < i - 1)
	{
		p = p->next;
		j++;

	}
	if (!p || j > i - 1)
		return ERROR;
	s = (List)malloc(sizeof(LNode));
	if (!s) exit(OVERFLOW);
	s->data = e;
	s->next = p->next;
	p->next = s;

	return OK;
}
Status ListDelete(List L, int i, ElemType *e)
{
	int j = 0;
	List p = L, t;
	while (p->next && j < i - 1)
	{
		p = p->next;
		j++;
	}

	if (!p->next || j > i - 1)
		return ERROR;

	*e = p->next->data;
	t = p->next;
	p->next = t->next;
	free(t);

	return OK;
}
int MyFindList(List L, ElemType e, int(*cmp)(ElemType, ElemType))
{
	int j = 0;
	L = L->next;
	while (L != NULL)
	{
		j++;
		if (cmp(e, L->data) == 0)
			return j;
		L = L->next;
	}
	return ERROR;
}
Status GetStu(List L, int i, ElemType *e)
{
	int j = 0;
	List p = L;
	while (p->next && j < i - 1)
	{
		p = p->next;
		j++;
	}
	if (!p->next || j > i - 1)
		return ERROR;
	*e = p->next->data;
	return OK;
}
int TraverseList(List L, int(*visit)(ElemType e))
{
	List r;
	int i;
	r = L->next;
	while (r != NULL)
	{
		i = visit(r->data);
		if (i == 0)
			return 0;
		r = r->next;
	}
	return 1;
}
int cmp_name(ElemType a, ElemType b)  //作为函数参数,辅助其他函数
{
	return strcmp(a.name, b.name);
}

void my_scanf_stu(ElemType *S)
{
	printf("输入学生的学号,姓名,年龄,性别('W'为女,'M'为男),");
	printf("出生年月日(是字符串即可),地址,电话,E-mail\n");
	scanf("%s%s%d %c", S->id, S->name, &S->age, &S->sex);
	scanf("%s%s%s%s", S->born, S->addr, S->phone, S->email);
}
void my_print_stu(Stu S)
{
	printf("学号: %s 姓名: %s 年龄: %d 性别: ", S.id, S.name, S.age);
	if (S.sex == 'W')
		printf("女\n");
	else
		printf("男\n");
	printf("出生: %s 地址: %s 电话: %s E-mail: %s\n", S.born, S.addr, S.phone, S.email);

}
Status change_stu(List L, int i, ElemType e)
{
	//在带头节点的单链线性表L中,将第i个位置的数据修改.
	int j = 0;
	List p = L, s;
	while (p && j < i - 1)
	{
		p = p->next;
		j++;

	}
	if (!p || j > i - 1)
		return ERROR;
	s = (List)malloc(sizeof(LNode));
	if (!s) exit(OVERFLOW);
	p->next->data = e;

	return OK;
}
void swap(List *L, ElemType e1, ElemType e2) //交换两个结点的位置
{
	int position1 = MyFindList(*L, e1, cmp_name); //根据名字找到对应序号
	int position2 = MyFindList(*L, e2, cmp_name);
	GetStu(*L, position1, &e1);
	change_stu(*L, position1, e2);  //将位序position1的值更改为e2
	change_stu(*L, position2, e1);  //将位序position2的值更改为e1

	//ListDelete(L, position1, &t1); //从L中将e1删除,其值给t1
	//ListDelete(L, position2, &t2); //从L中将e2删除,其值给t2
	//ListInsert(L, position1, t1);  //在第position1个位置之前插入t1
	//ListInsert(L, position2, t2);  //在第position2个位置之前插入t2
}
void my_scan_file(List L, int n_stu)
{
	FILE *f = fopen("data.txt", "r");
	ElemType S;

	while (n_stu--  && feof(f) != EOF) //循环录入n_stu的学生的信息
	{
		fscanf(f, "%s%s%d %c%s%s%s%s",
			S.id, S.name, &S.age, &S.sex, S.born, S.addr, S.phone, S.email);

		if (!ListInsert(L, 1, S))
		{
			printf("录入失败,分支2出错!\n");
		}
	}
	fclose(f);

}
void selet_sort(List *L)
{
	ElemType t;
	List p;
	int n = ListLength(*L);
	for (p = (*L)->next; p->next != NULL; p = p->next)
	{
		t = p->data;
		for (List q = p->next; q != NULL; q = q->next)
		{
			if (strcmp(t.name, q->data.name) > 0) //非降序
			{
				strcpy(t.name, q->data.name); //导致名字和对应数据错乱
			}
		}
		if (strcmp(t.name, p->data.name) != 0)
		{
			swap(L, t, p->data);
		}
	}
}

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页