C语言设计之 学生信息管理系统

/*********************************
      Project: 学生信息管理系统
	  Writer:  SHOW
	  Time:    2011/12/25
	  Function: 通过链表可以任意添加学生信息,查找学生信息,删除学生信息,显示所有学生信息,按各科成绩对学生进行排序。
	  涉及知识点:1.单链表的插入,删除,查找
	              2.二级指针,及初始化问题
	  版本:2.0  
				 1. 结构中新加了语文,数学,英语成绩。并且可以按三门成绩对学生信息进行排序,也就是Sort_Node对节点进行排序
				 2. 解决了版本1.0留下的问题 1。原因是因为在主函数里没有把*phead 根指针赋予NULL。而是(*phead) -> next =NULL,
				    这样程序一开始就插入了头结点。
*********************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<conio.h>

/* 定义一个学生信息的结构  */
typedef struct address{
	char name[8];
	char tel[20];
	int chinese;
	int math;
	int english;
	struct address *next;
	int num;  
}ADDR;

//========================================================================
// 函数说明: 单链表插入节点函数
// 实现功能: 能在任意位置插入节点,参考C和指针的经典写法   
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针。
//            new_num: 为插入的序号,提供有序插入的信息。
// 返回值:   无
//========================================================================
void Insert_Node(ADDR **phead,int new_num,char name[],char tel[],int chinese,int math,int english)
{
	ADDR *current;
	ADDR *newnode;

	while( (current = *phead) != NULL && current -> num <= new_num)
		phead = ¤t -> next;  
	
	newnode = (ADDR*)malloc(sizeof(ADDR));
    
	/*  插入的学生信息 */
	strcpy(newnode -> name,name);
	strcpy(newnode -> tel,tel);
	newnode -> num = new_num;
	newnode -> chinese = chinese;
	newnode -> math = math;
	newnode -> english = english;
	/*******************/

	newnode -> next = current;
	*phead = newnode;
}

//========================================================================
// 函数说明: 单链表查找节点函数,
// 实现功能: 通过传入的序号找到该节点并返回节点指针  
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针。
//            seek_num: 需要查找的序号
// 返回值:   如果找到了节点,则返回该节点,遍历后没有找到返回NULL
//========================================================================
ADDR* Seek_Node(ADDR **phead,int seek_num)
{
	ADDR *current;

	while( (current = *phead) != NULL && current -> num != seek_num)
	{
		phead = ¤t -> next;  
	}
	
	if(current == NULL)
		return NULL;
    if(current -> num == seek_num)
		return current;
	else
		return NULL;
}

//========================================================================
// 实现功能: 单链表删除节点函数,通过传入的数据域seek_num序号,删除对应节点。
// 函数说明: 此写法参考尚观C视频教程写法,删除后必须把该节点的前一个节点指向后一节点,要不然链表就乱了。
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针。
//            new_num: 为删除的序号
// 返回值:   删除成功返回头结点*phead,反之返回NULL。
//========================================================================
ADDR* Delete_Node(ADDR **phead,int seek_num)
{
	ADDR *p,*q;
	if(*phead == NULL)
		return NULL;
	else if((*phead) -> num == seek_num)
	{
		p= *phead;
		*phead = (*phead) -> next;
	}
	else
	{
		p = *phead;
		while((p -> num != seek_num) && (p -> next != NULL))
		{
			q = p;
			p = p-> next;
		}
		if(p -> num != seek_num)
			return NULL;
		else
		{
			q -> next = p -> next;
			free(p);
		}
	}
	return *phead;
}

//========================================================================
// 函数说明: 单链表获取节点长度函数
// 实现功能: 通过遍历整个链表只要没到尾部 lengh++。
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针。
// 返回值:   返回节点个数
//========================================================================
int Get_NodeLengh(ADDR **phead)
{
	ADDR *current;
	int lengh = 0;
	while( (current = *phead) != NULL)
	{
		lengh ++;
		phead = ¤t -> next;  
	}	
	return lengh;
}

//========================================================================
// 函数说明: 单链表数据域排序函数
// 实现功能: 运用冒泡排序算法进行排序,但只是移动了数据的位置,而没有对节点进行移动。
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针。
//            score:为需要进行排序的数据域值
// 返回值:   返回根指针
//========================================================================
/*ADDR* Sort_Node_Data(ADDR **phead,int score)
{
	ADDR *p;
	int n,m,lengh,temp;
	lengh = Get_NodeLengh(phead);
	p =  *phead;
	for( n=0; n<=lengh; n++)
	{
		p = *phead;
		for(m=0; m<(lengh - n); m++)
		{
			if(p->score > p->next->score)
			{
				temp = p -> score;
				p -> score = p -> next -> score;
				p -> next -> score = temp;
			}
			p = p -> next;
		}
	}
	return *phead;
}*/

//========================================================================
// 函数说明: 单链表节点排序函数
// 实现功能: 对节点进行排序,移动节点的位置
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针
// 返回值:   返回根指针
//========================================================================
ADDR* Sort_Node(ADDR **phead,char flag)
{
	ADDR *p,*q,*t,*s,*h;
 
 	h=(ADDR *)malloc(sizeof(ADDR));
 	h->next=*phead;
 	p=h;

	if((*phead) -> next == NULL)
		return NULL;
 	while(p->next->next!=NULL)
 	{
 		for(s=p,q=p->next;q->next!=NULL;q=q->next)
 		{
			switch(flag)
			{
				case 'n': 
				if(q->next->num < s->next->num)
					s = q;
					break;
				case 'c':
					if(q->next->chinese<s->next->chinese)
					s=q;
					break;
				case 'm':
					if(q->next->math<s->next->math)
					s=q;
					break;
				case 'e':
					if(q->next->english<s->next->english)
					s=q;
					break;
				default: break;
			}	
 		}

 		if(s!=q)
 		{
 			t=s->next;
 			s->next=t->next;
 			t->next=p->next;
 			p->next=t;
 		}
 		p=p->next;
 	}
 	*phead=h->next;
 	free(h);
 	return *phead;
} 

/* 函数声明 */
void InputStudent(ADDR **phead);
void DisplayAllStudent(ADDR **phead);
void SeekStudent(ADDR **phead);
void MenuSelect(void);
void HandleMenu(ADDR **phead);
void DeleteStudent(ADDR **phead);
void SortStudent(ADDR **phead);

/* 用带参数的宏分配内存 */
#define ASK(top) do{\
     	top=(ADDR *)malloc(sizeof(ADDR));\
    	if(top==NULL){printf("memory fail!");}\
}while(0);

/* 主函数 */
int main(void)
{

	ADDR **phead; // 定义一个二级指针

	ADDR *Temp;
	
	ASK(Temp);

	phead = &Temp; // 必须先给指针初始化内存,不然程序果断崩溃 ,也是自己用指针经常犯的错误谨记 ¥¥¥¥¥
	
	memset(*phead,NULL,sizeof(ADDR));

	(*phead) = NULL;
                          
	while(1)
	{
		HandleMenu(phead);
	}

	return 1;
}

//========================================================================
// 函数说明: 添加学生信息子函数
// 实现功能: 添加一个学生信息,添加一个节点。学生信息通过scanf函数从控制台输入 
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针。
// 返回值:   无
//========================================================================

void InputStudent(ADDR **phead)
{
	int num;
	char name[8];
	char tel[20];
	int chinese,math,english;

	printf(" --- 请输入新加入学生信息: ---\n");

	while(1)
	{
		printf("学号:");
		scanf("%d",&num);
		printf("姓名:");
		scanf("%s",name);
		printf("电话号码:");
		scanf("%s",tel);
		printf("语文:");
		scanf("%d",&chinese);
		printf("数学:");
		scanf("%d",&math);
		printf("英语:");
		scanf("%d",&english);

		Insert_Node(phead,num,name,tel,chinese,math,english);

		printf("任意键继续添加信息,输入0 返回\n");
		if(getch() == '0')
			break;
		else
			continue;
	}
}

//========================================================================
// 函数说明: 显示所有学生信息子函数
// 实现功能: 遍历整个链表,把所有链表信息都打印出来
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针
// 返回值:   无
//========================================================================
void DisplayAllStudent(ADDR **phead)
{
	ADDR *current;	
		/* 只要不为NULL,也就是没到尾部。那么找到的节点则都为先前插入的节点,也就是肯定存在信息的*/
		while( (current = *phead) != NULL ) 
		{
			printf("学号:%d,姓名:%s,电话号码:%s,语文:%d,数学:%d,英语:%d\n",
			current -> num,current -> name,current -> tel,current -> chinese, current -> math, current -> english);
			phead = ¤t -> next;  
			
		}
}

//========================================================================
// 函数说明   查找学生信息子函数
// 实现功能: 通过键盘输入命令,判断查找单个学生还是所有学生信息。
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针
// 返回值:   无
//========================================================================
void SeekStudent(ADDR **phead)
{
	int num;
	char name[20];
	char tel[100];

	ADDR *temp_node;

	printf("---  任意键查找单个学生信息,查找所有学生信息请输入 a  ---\n");
	if(getch() == 'a')
	{
		DisplayAllStudent(phead);
		printf("返回请输入 0\n");

		/* 这里用while也是因为返回有清屏操作,为了让控制台显示所有同学信息,所以要先停在这里。*/
		while(1)       
		{
			if(getch() == '0')
				break;
		}
	}
	else
	{
		while(1)
		{
			printf("学号:");
			scanf("%d",&num);

			temp_node = Seek_Node(phead,num);

			if(temp_node == NULL)
			{
				printf("输出错误不存在此学号, 请重新输入 ,输入 0 返回\n");
				if(getch() == '0')
					break;
				else
					continue;
			}
			else 
			{
				printf("该学生信息为 -> 学号:%d,姓名:%s, 电话号码:%s,语文:%d,数学:%d,英语:%d\n",
				temp_node -> num,temp_node -> name,temp_node -> tel,temp_node -> chinese,temp_node -> math,temp_node -> english );
				printf("输入任意键继续查找,输入0 返回\n");
				if(getch() == '0')
					break;
				else
					continue;
			}
		}
	}
}

//========================================================================
// 函数说明   学生信息排序子函数
// 实现功能: 
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针
// 返回值:   无
//========================================================================
void SortStudent(ADDR **phead)
{
	int score;
	char ch;
	printf("按学号,语文,数学,英语排序请分别输入n, c , m , e 返回请输入 0 \n");
	
	while(1)
	{
		ch = getch();
		if(ch == '0')
			break;
		else 
		{
			switch(ch)
			{
				case 'n':
						printf("按学号排序结果如下:\n");
						break;
			    case 'c':
						printf("按语文成绩排序结果如下:\n");
						break;
				case 'm':
						printf("按数学成绩排序结果如下:\n");
						break;
	  		    case 'e':
						printf("按英语成绩排序结果如下:\n");
						break;
				default: break;
			}
			Sort_Node(phead,ch);
			DisplayAllStudent(phead);
			printf("\n");
		}
	}

}

//========================================================================
// 函数说明: 删除学生信息子函数
// 实现功能: 通过scanf从控制台输入需要删除的学号,再调用对应Delete_Node函数删除对应学号的节点
// 入口参数: phead:指向头结点的指针的指针,也就是指向根指针的指针
// 返回值:   无
//========================================================================
void DeleteStudent(ADDR **phead)
{
	int num;
	char ch;
		printf("--- 删除单个学生信息请输入 s,删除所有学生信息请输入 a / A ---\n");
		ch = getch();
			if(ch == 's')
			{
				while(1)
				{
					printf("学号:");
					scanf("%d",&num);
					if(Delete_Node(phead,num) == NULL)
					{
						printf("输入错误,不存在此学号,请重新输入,输入 0 返回\n");
						if(getch() == '0')
							break;
						else
							continue;
					}
					else
					{
						printf("任意键删除下一个,输入 0 返回\n");
						if(getch() == '0')
							break;
						else
							continue;
					}
				}
			}
			else if(ch == 'a' || ch == 'A')
			{
				(*phead) = NULL;  // 直接给根指针NULL
			}
		
}

/* 菜单子函数 */
void MenuSelect(void)
{
	printf("*******************************学生信息管理系统*********************************\n");
	printf("      添加学生信息请输入 1                         删除学生信息请输入 2      \n");
	printf("      查找学生信息请输入 3                         对成绩排序请输入 4      \n");
	printf("********************************************************************************\n");
}

/* 处理菜单子函数 */
void HandleMenu(ADDR **phead)
{
	char ch;
	system("cls"); //调用系统命令清屏操作 
	MenuSelect();
	ch = getch();

	switch(ch)
	{
		case '1': InputStudent(phead);
				  break;
		case '2': DeleteStudent(phead);
				  break;
		case '3': SeekStudent(phead);
			      break;
		case '4': SortStudent(phead);
				  break;
		default : break; 
	}	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值