1.实现的功能
1.1.输出,查找
查找这是硬写的。。那个条件限制写的真的是一言难尽。。
1)按班级输出
2)按科目(数学,英语,c++的任意组合),按限制条件的输出
限制条件有:各科及平均分,总分的上下限。
3)输入学号查找学生,按设定的条件显示信息。
4)直接输出全部信息
1.2.输入
1)于指定位置插入任意个学生的数据
2)于结尾处添加数据
1.3.修改/删除
1)输入学号查找,找到之后输入要改的内容,不能手动改平均分和总分,其他的可以。
2)按学号查找后删除该学生的数据
3)清空所有数据
1.4. 排序数据
1)按照各科成绩,平均分或总分进行排序,从高到低或从低到高,这个排序的交换用了当时感觉非常诡异的方法,但是现在也懒得改了,确实能用=。=
1.5. 存储/读取数据
会把信息存到当前目录一个叫student_data的txt文件里,并且可以读取。
读写也是一样硬写出来的。。懒得改了。。
2.程序清单
#include<stdlib.h>
#include<stdio.h>
#include<direct.h>
#include<fstream>
#include<iostream>
#include<string.h>
#include<iomanip>
using namespace std;
//基本变量
int stumax = 0;
//读入的学生一共有多少
//输出选项
bool class_limited(false), score_limited(false), no_limited(false);
int selected_class(0);
float min_math_score = 0, max_math_score = 99999, min_english_score = 0, max_english_score = 99999;
float min_program_score = 0, max_program_score = 99999;
float min_aver_score = 0, max_aver_score = 99999, min_total_score = 0, max_total_score = 9999999;
char selected_no[25], selected_subjects[4]; //字符串多存一个\0 //sub:[0]:数学 [1]:英语 [2]:高程
//修改用
char change_no[25];
struct student
{
char no[25], name[25];//学生学号和名字,最多24字符
int Class;//班级
float math, english, program, ave, total;//分别是数学,英语,高程,平均分,总分,用float存,防止小数,平均分和总分不能手动修改
}a[100];//学生数组
void read_data()
{//读取数据
stumax = 0;//设置学生数初始为0,因为要重新读取,舍弃现在已经有的数据。
ifstream test("student_data.txt");
//ifstream输入流,用这个可以读取文件,括号是构造函数,
//把要读取的文件路径写在括号里,要加双引号,如果放在程序所在目录就不用加前面的路径,直接写文件名就行。
//这样,就会读取这个文件了,接下来检测是不是真的找到并打开了这个文件,如果没找到,还要做其他处理
if (!test.is_open())
{//is_open()这个函数能检测是不是打开了这个文件,如果没有,返回假,写的时候很方便,!is_open就是没打开的意思。
ofstream create("student_data.txt");
//如果没打开,说明可能文件不存在,那就创建这个文件,ofstream是输出流,创建的时候如果文件不存在,就会自动创建空文件,
//这样就可以新建文件了。
//然后,就能像用cout一样向文件中输出数据了。
//注:如ifstream刚创建时参数写的那个文件,输入就用的哪个文件,ofstream参数写的哪个文件, ofstream<<就向哪个文件输出。
create << 0;//读取方式是先读取有多少人,再读取人数次数据,读到每个人的数据,输出0
cout << "无数据,已新建存档";
//提示没有找到数据,已经新建
create.close();
//不关闭很麻烦的,关闭输出流
}
else
{
test.close();//用于测试,在上面is_open测试下来的,如果打开了文件,证明已经存在,如果没有手动修改过,文件的内容
//应该没问题,验证完毕,就把测试用的流关掉。
}
ifstream fin("student_data.txt");//重新开一个输入流,还打开student_data.txt,当然可以用test,只是为了和上面分开额。
fin >> stumax;//和后面的写入顺序一样,先读入记录的学生总数,好知道要读入多少个学生数据
//注1:fin和上面的create,test一样,只是自己起名为这个,可以随便起名。
//注2:ifstream用法和cin一样,但是不需要键盘输入,而用文件输入,比如每空格/tab分隔输入,回车啥的。
for (int i = 0; i < stumax; i++)
{//循环stumax次,i=0,i<stumax正好是stumax次,比如i=0;i<3,取值是0,1,2三次。
fin >> a[i].no >> a[i].name >> a[i].Class >> a[i].math >> a[i].english >> a[i].program;
//和下面的输入顺序一样,是自己定义的存储方式,学号、名字、班级、成绩。
a[i].total = a[i].math + a[i].english + a[i].program;//总成绩是三科之和
a[i].ave = a[i].total / 3;//平均成绩是总成绩除以3
//总成绩和平均成绩不写入/输入,直接计算,防止出错。
}
cout << "已读取" << stumax << "位学生的记录。" << endl;
//提示读取了多少学生记录。
fin.close();
//关闭输入流
}
void write_data() //写入数据
{//写入数据
ofstream fout("student_data.txt", ios::out);
//打开输出流,前面参数是文件路径,后面参数是打开方式,因为这个out变量不在std命名空间里,所以要加ios::表示命名空间在ios
//ios指的是In/Out Stream,std是STanDard
if (!fout.is_open())
{//如果打开失败,就退出,虽然一般不会出错吧。。
cerr << "出现错误@=-=@!" << endl;
exit(0);//调用这个系统函数直接退出
}
fout << stumax << endl;//先输出有多少人,这样读取的时候就知道读取多少次
for (int i = 0; i < stumax; i++)//stumax次输出,先输出endl换行和后输出没啥区别,每个数据间加个空格,读取时好识别是不同的数据
//就像cin输入时,一行输入多个数据要加空格。
fout << endl << a[i].no << ' ' << a[i].name << ' ' << a[i].Class << ' ' << a[i].math << ' ' << a[i].english << ' ' << a[i].program;
fout.close();//关闭
}
void enter_data()
{//基础输入
fflush(stdin);
//清空cin缓冲区,没啥用,防止多余数据读入,调用后cin里没读取的数据会被清空。
for (int i = stumax; i < 100; i++)
{//最多读取100个,但是可以中途打断
//i = stumax的原因是,上次输入后有stumax个学生,所以追加时,下一个空位置的下标就是stumax,下标从0开始,所以很奇妙
cin >> a[i].no;//输入学号,也可能是结束符,在输入学号时输入0即可结束输入,或者等到输入满100个后自动结束
if (! (a[i].no[0] == '0' && a[i].no[1]=='\0') )
{//如果输入的是"0",no里存的就是 0 \0 \0 \0 \0...如果输入别的
//字符数组里默认存的全是\0,如果输入一个字符串,读入会依次到数组里,
//但是输入最后会默认加个\0,所以假如输入“0”,读入的就是a[0] == 0
//a[1] == \0,所以没有结束的条件就是不符合这个,就是!(a[0]==0&&a[1]=='\0')
//如果要问这俩有什么区别,'0'是0这个字符的ascii码,\0的码值是0
cin >> a[i].name >> a[i].Class >> a[i].math >> a[i].english >> a[i].program;
//输入顺序
a[i].total = a[i].math + a[i].english + a[i].program;
a[i].ave = a[i].total / 3;
//计算总分和平均分
stumax++;//记录多了一个学生
}
else//假如打断或者装满了,就结束输入。
break;
}
//每次输入完成后调用这个函数,把数据写入文件,防止忘记保存。。当然也不能撤销了。
write_data();
}
void show()
{//基础输出
if (stumax != 0)
{//stumax 是学生数,如果不等于0,就说明有记录,如果有记录,则输出
cout << " \t学号\t姓名\t班级\t数学\t英语\t高程\t平均分\t总分" << endl;//输出表头,这个是基本输出,测试用的
for (int i = 0; i < stumax; i++)//setw是对齐用的宽度为12个字符算空格和输出的字符
cout << i + 1 << "." << setw(12) << a[i].no << '\t' << a[i].name << '\t' << a[i].Class << '\t' << a[i].math << '\t' << a[i].english << '\t' << a[i].program << '\t' << fixed << setprecision(1) << a[i].ave << '\t' << a[i].total << endl;
}
}
void insstu(int ins_start, int ins_num)
{//插入数据
int ins_index = ins_start - 1;
//如果要在第三个位置插入2个数据,输入参数就是ins_start = 3,ins_num = 2
//因为第三个数据的下标其实是2,所以要-1,所以有ins_index = ins_start-1,是开始插入的位置
//从这个开始,因为要插入ins_num个数据,所以要把之后的数据向后移ins_num位
for (int i = (stumax - 1) + ins_num; i >= ins_index + ins_num; i--) //移位
{//stumax - 1是原本的最后一个数据,+ins_num后就是它应该去的地方,直到移动到把ins_index 所在位置也挪到ins_num个之后。
a[i] = a[i - ins_num];
}//每次将ins_num个之前的数据移动到当前位置
cout << "请输入学生的学号,名字,班级,数学,英语,高程成绩\n";//移动完成,输出提示
for (int i = ins_index; i < ins_index + ins_num; i++)
{//输入数据,计算,从ins_index开始,输入ins_num个
cin >> a[i].no >> a[i].name >> a[i].Class >> a[i].math >> a[i].english >> a[i].program;
a[i].total = a[i].math + a[i].english + a[i].program;
a[i].ave = a[i].total / 3;
stumax++;//加一个人
}//没写中途退出
write_data();//输入后,写入数据
}
void output_reset()
{//重置查找选项
class_limited = 0, score_limited = 0, selected_class = 0, memset(selected_subjects, 1, sizeof(selected_subjects)); //osub:1:数学 2:英语 3.高程
min_math_score = 0, max_math_score = 99999, min_english_score = 0, max_english_score = 99999, min_program_score = 0, max_program_score = 99999, min_aver_score = 0, max_aver_score = 99999, min_total_score = 0, max_total_score = 999999;
}
void output_lim()
{//查找
cout << endl;
int j = 1; //记录输出数量
cout << " \t学号\t姓名\t班级";
if (selected_subjects[0])cout << '\t' << "数学";
if (selected_subjects[1])cout << '\t' << "英语";
if (selected_subjects[2])cout << '\t' << "高程";
if (selected_subjects[0] && selected_subjects[1] && selected_subjects[2])
cout << '\t' << "平均分" << '\t' << "总分"; //列表表头
cout << endl;
for (int i = 0; i < stumax; i++)
{
if ((!no_limited || memcmp(a[i].no, selected_no, 25) == 0) && (!class_limited || a[i].Class == selected_class) && (a[i].math >= min_math_score && a[i].math <= max_math_score) && (a[i].english >= min_english_score && a[i].english <= max_english_score) && (a[i].program >= min_program_score && a[i].program <= max_program_score) && (a[i].ave >= min_aver_score && a[i].ave <= max_aver_score) && (a[i].total >= min_total_score && a[i].total <= max_total_score))
{// 全部条件满足时进行输出
cout << j << '.' << setw(12) << a[i].no;
cout << '\t' << a[i].name << '\t' << a[i].Class << '\t';
if (selected_subjects[0]) cout << a[i].math << '\t';
if (selected_subjects[1]) cout << a[i].english << '\t';
if (selected_subjects[2]) cout << a[i].program << '\t';
if (selected_subjects[0] && selected_subjects[1] && selected_subjects[2]) //全部显示时显示平均分和总成绩
cout << fixed << setprecision(1) << a[i].ave << '\t' << a[i].total;
cout << endl;
j++;
}
}
if (j == 1) //显示数量判定
cout << "未查找到符合条件的学生QAQ 您可以修改条件。。" << endl;
else
cout << "查找到了" << j - 1 << "位符合条件的学生!" << endl;
system("pause");//暂停
}
void outPut_menu()
{//查找菜单
int outputSelect(0);
while (1)
{
cout << "-------请选择查找方式--------" << endl;
cout << "1.按班级输出 2.指定学号查找" << endl;
cout << "3.显示指定科目 4.按成绩输出" << endl;
cout << "5.清除条件 6.显示目前条件" << endl;
cout << "9.直接输出(测试) 0.退出查询" << endl;
cout << "-----------------------------" << endl;
cout << "多条件查找请逐个添加 " << endl;
cin >> outputSelect;
switch (outputSelect)
{
case 1:
class_limited = true;//设置标志
cout << "请输入您想查看的班级,输入0来显示全部班级:\n";
cin >> selected_class;
if (selected_class == 0) class_limited = 0;
output_lim();
break;
case 2:
no_limited = 1; //激活条件变量
output_reset(); // 重置变量以从全部学生中查找
cout << "请输入您想查找的学生学号:";
cin >> selected_no;
output_lim();
no_limited = 0; //复位条件变量
break;
case 3:
memset(selected_subjects, 0, sizeof(selected_subjects)); //清空这里在清空的时候写了3*sizeof,居然把struct a 里的数据都清掉了!!!导致a.math的数据都没了。 找了半天才发现!
cout << "请输入您想显示的科目序号" << endl;
cout << "1.数学 2.英语 3.高程" << endl;
cout << "输入“12”以显示数学和英语" << endl;
cin >> selected_subjects;
for (int i = 0; i < 3; i++)
{
if (selected_subjects[i] != '\0') selected_subjects[(selected_subjects[i] - 49)] = 1;
}
output_lim();
break;
case 4:
cout << "请输入您需要限制的科目:" << endl;
cout << "1.英语 2.数学 3.高程 4.平均分 5.总分" << endl;
cin >> outputSelect;
cout << "请输入您需要查找的最低分与最高分:" << endl;
switch (outputSelect)
{
case 1:
cin >> min_english_score >> max_english_score;
break;
case 2:
cin >> min_math_score >> max_math_score;
break;
case 3:
cin >> min_program_score >> max_program_score;
break;
case 4:
cin >> min_aver_score >> max_aver_score;
break;
case 5:
cin >> min_total_score >> max_total_score;
break;
}
output_lim();
break;
case 5:
output_reset();
cout << "成功!" << endl;
break;
case 6:
cout << "目前显示" << selected_class << "班,显示科目";
if (selected_subjects[0]) cout << "数学 ";
if (selected_subjects[1]) cout << "英语 ";
if (selected_subjects[2]) cout << "高程 ";
cout << endl;
break;
case 9:
show();
}
if (outputSelect == 0)
{
output_reset(); //退出时复位变量
break;
}
}
}
int change(int insa, char posa[])
{//更改数据
int asw = 0;
if (memcmp(posa, "学号", 4) == 0) { cin >> a[insa].no; asw = 1; }
if (memcmp(posa, "姓名", 4) == 0) { cin >> a[insa].name; asw = 1; }
if (memcmp(posa, "班级", 4) == 0) { cin >> a[insa].no; asw = 1; }
if (memcmp(posa, "数学", 4) == 0) { cin >> a[insa].math, asw = 1; }
if (memcmp(posa, "英语", 4) == 0) { cin >> a[insa].english; asw = 1; }
if (memcmp(posa, "高程", 4) == 0) { cin >> a[insa].program; asw = 1; }
a[insa - 1].total = a[insa - 1].math + a[insa - 1].english + a[insa - 1].program, a[insa - 1].ave = a[insa - 1].total / 3;
write_data();
return asw;
}
void dlt(int pos)
{//删除数据
for (int i = pos; i < stumax; i++)
{//覆盖
a[i] = a[i + 1];
}
stumax--;
write_data();
}
void searchstuNo()
{//更改删除菜单
int recno(-1);
char yon;
int changeSelect;
char changea[15];
for (int i = 0; i < stumax; i++)
if (memcmp(a[i].no, change_no, 25) == 0)
{
recno = i;
break;
}
if (recno == -1) cout << "未找到学生!" << endl;
else
{
cout << "\t学号\t姓名\t班级\t数学\t英语\t高程\t平均分\t总分" << endl;
cout << recno << '.' << setw(12) << a[recno].no;
cout << '\t' << a[recno].name << '\t' << a[recno].Class << '\t' << a[recno].math << '\t' << a[recno].english << '\t' << a[recno].program << '\t' << fixed << setprecision(1) << a[recno].ave << '\t' << a[recno].total;
cout << endl;
cout << "请选择-----------------" << endl;
cout << "1.更改数据 2.删除数据" << endl;
cout << "-----------------------" << endl;
cin >> changeSelect;
switch (changeSelect)
{//更改或删除
case 1:
cout << "请输入您想修改的信息:学号、姓名、班级、数学、英语、高程" << endl;
cin >> changea;
if (change(recno, changea))
cout << "修改成功!" << endl;
else
cout << "修改失败!" << endl;
break;
case 2:
cout << "您确定吗?Y是N否" << endl;
cin >> yon;
if (yon == 'y' || yon == 'Y')
dlt(recno);
if (yon == 'n' || yon == 'N')
break;
default:
cout << "输入错误!" << endl;
}
}
}
void sort_data()
{//排序
int sorta(0), sortc;
student temp;
cout << "请输入需要排序的选项:\n1.数学 2.英语 3.高程 4.平均分 5.总分" << endl;
cin >> sortc;
sortc -= 1;
cout << "请输入排序方式:1.由高到低 2.由低到高" << endl;
cin >> sorta;
student t;
for (int i = 0; i < stumax - 1; i++)
for (int j = i + 1; j < stumax; j++)
{
float sorts[5] = { a[i].math,a[i].english,a[i].program,a[i].ave,a[i].total };
float sortss[5] = { a[j].math,a[j].english,a[j].program,a[j].ave,a[i].total };
if ((sorts[sortc] < sortss[sortc] && sorta == 1) || (sorts[sortc] > sortss[sortc] && sorta == 2))
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
int start()
{//主菜单
int mainSelect;
int insloc, insnum; //插入位置
read_data();
while (1)
{
system("pause");//如果不想清屏把这两句删了就行
system("cls");
cout << "---欢迎使用学生信息管理系统---" << endl << endl;;
cout << "1.输入数据 2.查找数据" << endl;
cout << "3.修改数据 4.重置数据" << endl;
cout << "5.显示数据 6.存储数据" << endl;
cout << "7.排序数据 0.退出系统" << endl;
cout << "------------------------------" << endl;
cout << stumax << "个学生的信息已读取。" << endl;
cout << "请选择:\n";
cin >> mainSelect;
switch (mainSelect)
{
case 1:
cout << "请选择输入方法:\n1.指定位置添加\t2.于结尾处添加" << endl;
cin >> mainSelect;
switch (mainSelect)
{
case 1:
if (stumax == 0)
{
cout << "没有数据!" << endl;
break;
}
show();
cout << "请您输入您想添加的位置与添加的人数:" << endl;
cin >> insloc >> insnum;
if (insloc <= 0 || insloc >= stumax)
cout << "你想干嘛?没有这个位置。" << endl;
else
insstu(insloc, insnum);
break;
case 2:
cout << "请输入学生的学号,名字,班级,数学,英语,高程成绩,于学号处输入0来结束:\n";
enter_data();
break;
default:
cout << "您的输入有误!已返回。" << endl;
break;
}
break;
case 2: if (!stumax)
{
cout << "无数据!\n"; break;
}
else
{
outPut_menu(); break;
}
case 3:
output_lim();
cout << "请输入您想要修改的学生的学号:(不支持修改平均分和总分)" << endl;
cin >> change_no;
searchstuNo();
break;
case 4:
int reset;
cout << "您真的想重置数据吗?(0.否 1.是)" << endl;
cin >> reset;
if (reset)
{
for (int i = 0; i < 100; i++)
memset(&a[i], 0, sizeof(struct student));
stumax = 0;
cout << "已完成!\n";
write_data(); //写入
}
else
cout << "已取消!" << endl;
break;
case 5:
show();
break;
case 6:
write_data();
system("cls");
cout << "成功!" << endl;
break;
case 7:
sort_data();
write_data();
break;
case 0:
return 0;
default:
cout << "您的输入有误!" << endl;
break;
}
}
}
int main()
{
start();
return 0;
}
3.运行结果
运行结果:
添加学生。
显示指定科目。
按分数查找。
4.吐槽
这个程序写的真的很强行= =但是当时真的觉得自己好强啊!
纪念一下吧= =