C++学生信息系统

某班开设有英语、数学、程序设计三门课程,该班同学不多于50人。编写具有下列功能的菜单驱动的程序。
(1)添加学生信息
(2)显示所有学生信息
(3)删除学生信息 让操作者输入要删除学生的名字,将其删除
(4)查询学生信息 让操作者输入要查询学生的名字,显示其信息或提示无
(0)退出系统

简要解题思路:
1、定义一个Student的结构体,内有性别,ID年龄,英语,数学,程序编辑成绩,利用动态单向链表的结构,每个结点除了存放数据元素的自身信息外,还存放了与之相联系的后继结点元素的地址,形成了一个单向链表。
2.void input(Student *&head)用于输入每个结点的信息

判断是否要操作
char ch;
cout << “输入数据(y/n):”;
cin >> ch;
if (ch == ‘y’||ch==‘Y’)

Student *p, *q, *head;
p = new Student;//动态分配空间
相类似的输入:cin >> p->age;输入年龄,成绩等信息

3.void show(Student * head)
L1:return;
if (!head) { cout << “\t空链表!” << endl; goto L1; }
判断是否已输入内容,没有就输出空链表,并且去到
自从提倡结构化设计以来,goto 就成了有争议的语句。首先,由于goto 语句可以灵活跳转,如果不加限制,它的确会破坏结构化设计风格。其次,goto 语句经常带来错误或隐患。它可能跳过了某些对象的构造、变量的初始化、重要的计算等语句。它能从多重循环体中咻地一下子跳到外面,用不着写很多次的break 语句。
由于是用head指针放回值
while (head)
{
cout << “student’s ID:\t” << head->ID << endl;
需要在最后面加上
head = head->next; //head指针往下一个结构体指针

4.void deleting(Student *head)
重点之一:
char sname[20];
cout << “input the deleted student’s name” << endl; cin >> sname;//输入想要查询的学生的姓名
Student *p;
if (!head) {
cout << “List nulll!\n”; return;
}
if (strcmp(head->name, sname) == 0)//若链表头的学生信息即为所求,则直接显示出该学生的信息即可
用strcmp判断的是name字符串和sname字符串值是不是一样,而
直接的head->name==sname,是判断是不是2个字符数组指针所指地方一样,很明显不是我们想要的效果

5.void search(Student*head)

思想和删除一样

6.void reserve(Student*head)
用文本文档存储
char fileName[30];
if (!head) { cout << “\t空链表!” << endl; return; }
ofstream outstuf; //建立输出文件流对象
cout << “Please input the name of the students’file:” << endl; cin >> fileName;
//输入文件名格式,例如: d:\student.txt
outstuf.open(fileName, ios::out);//连接文件,指定打开方式为写方式

代码区:

#include <iostream>
#include<cstring>
#include <fstream>
using namespace std;
struct Student
{
	char sex[10]; char ID[25];
	int age = 0;
	char name[50];
	double scoreE;
	double scoreM;
	double scoreC;
	Student *next;
}; Student *p, *q, *head;

void input(Student  *&head)
{
	char ch;
	cout << "输入数据(y/n):";
	cin >> ch;
	if (ch == 'y' || ch == 'Y')
	{
		p = new Student;//动态分配空间 
		cout << "input ID:" << endl;
		cin >> p->ID; ///将学号录入p指针指向的结构体里的ID变量  

		cout << " input sex(m/w):" << endl;
		cin >> p->sex;//将性别录入p指针指向的结构体里的sex变量

		cout << " input age:" << endl;
		cin >> p->age;//将年龄录入p指针指向的结构体里的age变量

		cout << "输入学生的名字:" << endl;
		cin >> p->name;//将姓名录入p指针指向的结构体里的name变量 

		cout << " 输入学生的英语、数学、程序设计的成绩:" << endl;
		cin >> p->scoreE >> p->scoreM >> p->scoreC;
	}
	else goto L0;						//若输入n,则返回菜单栏 
	while (ch == 'y' || ch == 'Y')			//输入下一个同学的信息 
	{
		if (head == NULL) 	head = p;
		else
			q->next = p;
		q = p; cout << "输入数据(y/n):" << endl;
		cin >> ch;
		if (ch == 'y' || ch == 'Y')
		{
			p = new Student;
			cout << " input ID:" << endl; cin >> p->ID;				//将学号录入p指针指向的结构体里的ID变量 
			cout << " input sex:" << endl; cin >> p->sex;			//将性别录入p指针指向的结构体里的sex变量
			cout << "input age:" << endl; cin >> p->age;			//将年龄录入p指针指向的结构体里的age变量
			cout << "输入学生的名字:" << endl; cin >> p->name;		//将姓名录入p指针指向的结构体里的name变量
			cout << " 输入学生的英语、数学、程序设计的成绩:" << endl;
			cin >> p->scoreE >> p->scoreM >> p->scoreC;				//将各科成绩录入p指针指向的结构体里的scoreE、scoreM、scoreC变量 
		}

	}
	q->next = NULL;
L0:return;
}

void show(Student * head)
{
	if (!head) { cout << "\t空链表!" << endl; goto L1; }
	cout << "\t链表中的数据是: \n";
	while (head)
	{
		cout << "student's ID:\t" << head->ID << endl;
		cout << "student's sex:\t" << head->sex << endl;
		cout << "student's age:\t" << head->age << endl;
		cout << "student's name:" << head->name << endl;
		cout << " 输入学生的英语、数学、程序设计的成绩:" << endl;
		cout << head->scoreE << '\t' << head->scoreM << '\t' << head->scoreC << endl;
		head = head->next;			//head指针往下一个结构体指 
	}
	cout << endl;
L1:return;
}


void deleting(Student *&head)//这个就是问题所在
{
	char sname[20];
	cout << "input the deleted student's name" << endl; cin >> sname;/*输入要删除的学生的姓名*/
	Student *p;
	if (!head)
	{
		cout << "List null!\n"; return;
	}
	if (strcmp(head->name, sname) == 0)/*如果链表头的学生信息即为所求
									 则将p指向链表头,head指针指向链表第二个结构体,使其成为新的链表头
									 然后释放原来链表头的空*/
	{
		p = head; head = head->next; delete p; p = NULL;
		cout << sname << "'s information have been deleted.\n"; return;
	}
	for (Student *pg = head; pg->next; pg = pg->next)
	{
		if (strcmp(pg->next->name, sname) == 0)						//找到了对应的姓名 
		{
			/*将p指向对应姓名的结构体,同时将该结构体的上一个结构体的next指针指向该结构体的下一个结构体
			  将该结构体的空间释放,则该学生的信息已被删除 */
			p = pg->next; pg->next = p->next; delete p; p = NULL;
			cout << sname << "'s information have been deleted.\n"; return;
		}
	}
	cout << sname << " She/He is not in this class:" << endl; return;
}


void search(Student*head) {
	char sname[20];
	cout << "input the deleted student's name" << endl; cin >> sname;//输入想要查询的学生的姓名 
	Student *p;
	if (!head) {
		cout << "List nulll!\n"; return;
	}
	if (strcmp(head->name, sname) == 0)//若链表头的学生信息即为所求,则直接显示出该学生的信息即可 
	{
		cout << "student's ID:\t" << head->ID << endl;
		cout << "student's sex:\t" << head->sex << endl;
		cout << "student's age:\t" << head->age << endl;
		cout << "student's name':" << head->name << endl;
		cout << " 输入学生的英语、数学、程序设计的成绩:" << endl;
		cout << head->scoreE << '\t' << head->scoreM << '\t' << head->scoreC << endl;
		return;
	}
	for (Student *pg = head; pg->next; pg = pg->next)
	{
		if (strcmp(pg->next->name, sname) == 0)	//若pg指向的结构体的下一个结构体的信息即为所求,直接显示即可, 
		{
			cout << "student's ID:\t" << head->ID << endl;
			cout << "student's sex:\t" << head->sex << endl;
			cout << "student's age:\t" << head->age << endl;
			cout << "student's name':" << head->name << endl;
			cout << " 输入学生的英语、数学、程序设计的成绩:" << endl;
			cout << head->scoreE << '\t' << head->scoreM << '\t' << head->scoreC << endl;
			return;
		}
	}
	cout << sname << " :She/He is not in this class:" << endl; return;
}

void reserve(Student*head)//保存在文本文件 ,文本文件是顺序存取文件,以默认的方式打开 
{
	char fileName[30];
	if (!head) { cout << "\t空链表!" << endl; return; }
	ofstream outstuf;                   //建立输出文件流对象 
	cout << "Please input the name of the students'file:" << endl; cin >> fileName;
	//输入文件名格式,例如: d:\student.txt 
	outstuf.open(fileName, ios::out);//连接文件,指定打开方式为写方式 
	if (!outstuf) {//调用重载算符函数测试流,判断文件是否能打开 
		cerr << "File couldn't be open!" << endl; abort(); return;
	}
	outstuf << "\t链表中的数据是: \n";//写入一个标题 
	while (head)
	{       //把链表的信息按顺序写入流中 
		outstuf << "student's ID:\t" << head->ID << endl;
		outstuf << "student's sex:\t" << head->sex << endl;
		outstuf << "student's age:\t" << head->age << endl;
		outstuf << "student's name':" << head->name << endl;
		outstuf << " 输入学生的英语、数学、程序设计的成绩:" << endl;
		outstuf << head->scoreE << '\t' << head->scoreM << '\t' << head->scoreC << endl;
		head = head->next;			//head指针往下一个结构体指 针 
	}
	outstuf << endl;
	outstuf.close();//关闭文件 
	return;
}


int main()
{
	Student *head = NULL; int key;
	int choice, bh;
L:
	cout << "\n\n\n\n\n" << endl;
	cout << "\t\t|\t==========student==========\t|\n" << endl;
	cout << "\t\t|\t 1. insert information     \t|\n" << endl;
	cout << "\t\t|\t 2. demonstrate information\t|\n" << endl;
	cout << "\t\t|\t 3. delete information     \t|\n" << endl;
	cout << "\t\t|\t 4. search information     \t|\n" << endl;
	cout << "\t\t|\t 5. conserve information   \t|\n" << endl;
	cout << "\t\t|\t 0. exit                   \t|\n" << endl;
	cout << "\t\t|\t===========================\t|\n\n" << endl;
	cout << "\t\t select(0~5):";
	cin >> choice;
	switch (choice)
	{
	case 1: input(head); goto L;
	case 2: show(head);  goto L;
	case 3:
		deleting(head);
		goto L;
	case 4:search(head); goto L;
	case 5:reserve(head); goto L;
	case 0: cout << " \t退出程序的运行!\n" << endl; break;
	default: cout << "\t输入错误,请重新输入!\n" << endl; goto L;
	}
}

效果图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
特点:可以修改,且可见,每次修改后保存在那个固定的文件里就相当于更新了文件,文件内容也会改变。
在这里插入图片描述
本博客有好多的知识点,例如输入输出流,链表等,其中我想分析的是函数参数的传递的问题。
原因是我一直都没找到为什么一直删不了第一个结点,后来同学说用引用传值就解决了。
1.传值参数 值传递机制
特点:作为实际参数的表达式的值被复制到相应的形式参数名标识的对象中,成为形参的初始 值。函数体中对形参的访问和修改都是对标识对象的操作,与实际参数对象无关,并且按实际形参强制转换。
函数返回时形参被撤销,不影响实参的值,是通过匿名对象传递返回值。
值传送的实参可以是参量,有确定的变量或表达式。
2.指针参数 指针传递/地址调用
例"int func(const int* const p)"
形参被说明为指针类型,形参指针对应的实际参数是地址表达式。调用函数时,实际参数把对象的地址付给形参名标识的对象。形参可以间接地访问这个地址所指的对象。可以用·const约束形参指针访问特性。const int *const p和const int *p以及int *p的区别。
3.引用参数
例”void swap(int &,int &);
形参不用开辟新的存储空间,形参名做为引用绑定在实参标识的对象上。执行函数时,对形参操作是对实参对象的操作,直到函数执行结束,撤销引用绑定。
例:void annoym(const int &ref)
const约束的实参可以是常量或表达式,是表达式就会建立匿名对象用于存放表达式的值。非约束的引用参数对应的实参必须是对象名。
总结:引用参数和指针参数不需要像传值参数一样产生实参对象的副本,引用参数不像这座城市那样通过间址访问实参对象,可以用于大对象参数的高效操作。

  • 2
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

广大菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值