学生成绩管理系统--C语言

#include <stdio.h>
#include <stdlib.h> //malloc()函数需要这个头文件,即动态内存申请需要这个头文件
#include <string.h>

//学生信息的定义:
typedef struct Student {
	char num[10]; //学号
	char name[20];  //姓名
	int score; //成绩
} Stu;

//链表结点的定义:
typedef struct Node {
	Stu   data; //数据域
	struct Node  *next;//指针域
} Node, *LinkList; //LinkList是Node指针的别名。

//输入学生信息
void scanf_1(Node *head) {
	LinkList p, p1; //声明LinkList类型的指针p,p1
//p 在代码中用作指向新创建的链表点的指针。
//p1用于追踪链表的尾结点;它在添加新结点时会使用,以保持链表的结尾。
	int i, n;     // n表示学生的人数
	p1 = head; //p1初始化为头结点,用于最后的结点连接
	printf("请输入学生的人数:");
	scanf("%d", &n);
	printf("请输入学生的信息:\n");
	for (i = 1; i <= n; i++) {
		p = (LinkList)malloc(sizeof(Node)); //动态内存分配给新结点p
		p->next = NULL; //初始化p的下一个结点指针为NULL
		printf("学号:");
		scanf("%s", p->data.num); //获取学生学号
		// 检查学号是否已经存在
		LinkList q = head;
		int mark = 0;
		while (q->next != NULL) {
			q = q->next;//将指针 q 指向它的下一个结点(迭代链表)
			if (strcmp(q->data.num, p->data.num) == 0) {
				mark = 1;//如果找到相同学号,标记为1
				printf("这个学号已经存在,请输入一个新的学号.\n");
				free(p); // 释放之前分配的内存
				i--;     // 由于没有添加新学生,所以下一个循环仍应该添加第i个学生
				break;   // 退出循环
			}
		}

		// 如果学号不存在,则正常继续
		if (mark == 0) {
			printf("姓名:");
			scanf("%s", p->data.name);
			printf("成绩:");
			scanf("%d", &p->data.score);
			// 将新结点附加到链表的末尾
			p1->next = p; //将新结点 p 接在 p1 结点之后(将新结点添加到链表末尾)
			p1 = p1->next; //将 p1 移动至新的位置,即新插入的结点 p(将p1移动到链表的最后)
		}
		printf("------------这是一条分界线---------------\n");
	}
	printf("··················(*^_^*)······················\n");
}



//输出学生信息
void printf_1(Node *head) {
	LinkList p;
	p = head; //p初始化为头结点,用于最后的结点连接
	printf("请输出学生的信息:\n\n");
	printf("学号\t姓名\t成绩\n");
	//遍历链表并输出信息
	/*使用while循环遍历链表。
	  循环条件是p->next不为NULL,即还没有到达链表的末尾。
	  在循环中,首先将指针p移动到下一个结点(p->next),
	  然后输出当前结点的信息,包含三个成员:学号(num)、姓名(name)和成绩(score)。
	  通过指针解引用,可以访问这些成员的值,并使用printf函数输出。*/
	while (p->next != NULL) {
		p = p->next;
		printf("%s\t%s\t%d\n", p->data.num, p->data.name, p->data.score);
	}
}

void search(Node *head, int i) { //这个函数接受两个参数:一个指向Node类型的指针head,表示链表的头结点;一个整数i,表示要查询的位置。
	//这里定义了两个变量:一个整数k用于记录遍历到的位置,一个LinkList类型的指针p用于遍历链表。
	int k;
	LinkList p;//声明一个LinkList类型的指针p
	//通过printf函数提示用户输入要查询的位置,然后使用scanf函数读取用户输入的整数并存储在变量i中。
	printf("请输入你要查询的位置:");
	scanf("%d", &i);
	//如果输入的位置i小于0,则打印“查找失败”。这里假设位置是从1开始的,因此负数位置是无效的。
	if (i < 0) {
		printf("查找失败!\n");
	}
	//遍历链表并查找位置
	/*
	使用while循环遍历链表。循环条件有两个:一是p->next不为NULL,即还没有到达链表的末尾;
	二是k小于i,即还没有到达要查询的位置。
	在循环中,每次迭代将指针p移动到下一个结点,并将k增加1。
	*/
	p = head;
	k = 0;
	while (p->next != NULL && k < i) {
		p = p->next;
		k = k + 1;
	}
	// 检查是否找到了位置
	/*如果输入的位置i等于变量k(表示遍历到的位置),则说明找到了要查询的位置。
	输出该位置学生的学号、姓名和成绩。否则,打印“查找失败”。*/
	if (i == k)
		printf("学号:%s\t 姓名: %s\t成绩: %d\n", p->data.num, p->data.name, p->data.score);
	else
		printf("查找失败!\n");
}



void delete_1(Node *head, int i, Stu *e) {
	/*
	head:链表的头结点。
	i:要删除的结点的位置。
	e:一个指向Stu类型的指针,用于保存被删除结点的数据。
	*/
	LinkList p, p1; //定义指针p,p1
	int k;
	p1 = head;
	k = 0;
	//获取要删除的位置
	printf("请输入你要删除的位置:\n");
	scanf("%d", &i);

	//查找要删除的结点
	/*
	这个循环用于查找要删除的结点。
	循环条件有两个:一是p1->next不为NULL,确保没有到达链表的末尾;
	二是k小于i-1,确保没有越界。
	在循环中,每次迭代都会将p1移动到下一个结点,并将k增加1。
	*/
	while (p1->next != NULL && k < i - 1) { // 检查是否找到了要删除的结点
		p1 = p1->next;
		k++;
	}
	// 检查是否找到了要删除的结点
	if (p1 == NULL) {
		printf("删除失败!\n");
	}
	//删除节点
	/*如果找到了要删除的结点,这部分代码将执行。
	  首先,将p1->next指向的结点的地址赋给p。
	  然后,将p1->next设置为下一个节点的地址,即跳过了要删除的结点。
	  接下来,通过指针解引用将被删除结点的数据赋给e。
	  最后,使用free函数释放被删除结点的内存,并打印“删除成功”。*/
	p = p1->next;
	p1->next = p->next;
	*e = p->data; //同时,还通过指针解引用保存了被删除结点的数据。
	free(p);
	printf("删除成功!\n");
}

void  exit_1() {
	printf("退出成功!请按任意键结束!");
	exit(0);
}


int main() {
	Node *head;//指向链表头结点
	head = (LinkList)malloc(sizeof(Node)); //为头结点head分配内存,并且将返回的内存地址赋给head指针。
	//LinkList是Node指针的别名。
	head->next = NULL; //将头结点的next指针设为NULL,初始化链表为空链表。
	int select = -1; //声明并初始化一个名为select的整型变量,用于之后用户选择菜单选项。
	int i;
	Stu e;//声明一个名为e的Stu结构体变量,用于临时存储和传递学生信息。

	while (select != 0) {
		printf("*********************\n");
		printf("*    1. 添加信息;   *\n");
		printf("*    2. 显示信息;  *\n");
		printf("*    3. 位置信息;   *\n");
		printf("*    4. 删除信息;  *\n");
		printf("*    5. 退出系统。  *\n");
		printf("*********************\n");
		printf("\n");
		printf("在以上选项选择你要操作的选项的序号:");
		scanf("%d", &select);
		printf("\n");
		switch (select) {
			case 1:
				scanf_1(head);
				break; //调用in函数向链表输入数据
			case 2:
				printf_1(head);
				break;//调用out函数显示所有学生信息
			case 3:
				search(head, i);
				break;//调用search在链表中查找指定位置的学生信息
			case 4:
				delete_1(head, i, &e);
				break;//调用delete_1删除链表中指定位置的学生记录
			case 5:
				exit_1();
				break;//调用exit_1退出程序。
		}
	}
	return 0;
}方法。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值