C++中FILE实操作---C++来实现学生管理系统【Final_version*(੭*ˊᵕˋ)੭*ଘ】

 

            /*C++类来实现学生管理系统*/
/***********************************************************/
//该系统实现了那些操作
//1、菜单、增、删、改、查、打印、保存、载入
//2、检查是否已经存在的学号
//3、实现二级菜单 选择性修改等操作
//4、学号/姓名/成绩可以实现排序  同时 实现综合程序的方法  排序函数的汇总  多种方法选择
//5、除了实现冒泡排序,还实现了选择排序算法
//6、实现了控制台背景颜色和字体颜色像模板似可以调整
//==========================================================
//学到的知识点:
//1--绝对路径,指定盘符
//2--相对路径,不指定盘符,在执行文件的当前目录下
//3--void类型,即什么类型都能接受,double  int char 等都可以传送
//4--刷新添加,每次写入将之前清零 保存写入现有的所有
//5--停止条件: 1】写入write停止条件: 内存中数据为0时候,有效数据的位置,即g_user[i].m_Num!=0 
//              2】加载Load 停止条件: 文件中数据读取返回值为0,读取不到数据时,即int n=fread(&us, 1, sizeof(us), pf)=0
//6--fwrite  : 两种模式 w  写入 清空原来写入 
//                      a(append)追加,原来基础上写入
//7--堆栈调用:debug模式下调用堆栈来查看程序的堆栈 压入调出情况   程序最好压入少,否则栈满了会崩溃
//             当选择菜单选择0退出时,可能还有数据在栈内压这呢。
//             尽量保持多级菜单复用时候考虑压栈等  一般三级  
//8--排序算法:冒泡排序 VS 选择排序
//             冒泡:简单,构架好想,但每次移动,移动次数多
//             选择:难度,构架难想,但移动次数比较少
//9--生命周期:类成员变量的生命期
//              a)类成员函数(在对象构造之后,即实例化)被各个成员函数都可以调用,类似C语言对全局变量的调用
//              b)Time(类的对象) = Time(内部成员变量)
//              c)Begin_Time(类对象内成员变量) :对象定义时,也是构造函数执行时
//              d)Over_Time (类对象内成员变量) :对象析构函数时,所有需要在析构函数内写入堆栈释放语句即可。
//?????????????????????????????//
//未解决问题:
//1、写入到txt文件中的数据有乱码【正常,txt不支持这个格式的查看,ue可以查看十六进制】
//2、项目多少有点不稳定,好像在选择修改地方【已修复bug!---后面少了break】
/***********************************************************/
#include"Stu_CW.h"

int main(){

    Stu_CW stu_mag;
    stu_mag.Welcome_String();
    system("color 4f");
    //stu_mag.String_Pr();    
    system("pause");
    system("cls");
    stu_mag.Start();
    
    return 0;
}
C++类管理学生系统---链表学习.cpp
            /*重要的点一定记住*/
/***********************************************/
//1、关于重定义的问题
//   ฅʕ•͡头文件专注声明用,不可以用作全局变量引用等, •ʔฅ
//   即申明全局变量,全局函数一定要在cpp中申明,其他类引用该全局变量
//   就include该cpp的h文件,然后extern一下就好了。否则容易出现该重复定义错误。

/**********************************************/

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;

class Stu_CW{
    
     //默认是私有保护
    void Print();   //打印
    void Save();    //保存    
    void Add();     //
    void Delete();  //
    void Modify();  //
    void Find();    //
    int Sort_Judge(int choose_sort_m, int nMin, int j);//排序判断
    void Gather_Sort(int m);//汇总排序
    int DisplayMenu();      //子菜单显示
    int Color_Set();        //颜色设置    
    
public://公开接口   此处函数对外开放,内部函数可以在类内调用其它私有函数
    Stu_CW();//自构函数如果放在私有区,那么久无法初始化
    ~Stu_CW();
    void String_Pr();       //字符串显示
    int Menu();             //主菜单^(* ̄(oo) ̄)^
    void Load();            //载入
    void Start();
    // 纯属学习娱乐用
    static int Learning_Code(int para, char * point, double Math);
    // 输出显示界面
    void Welcome_String();
};
Stu_CW.h
#include"Stu_CW.h"

struct SUser{//结构体  每个接头体保存三个数据 
    int m_Num;         //学号数据
    char m_Name[20];   //姓名数据
    float m_Math;      //成绩数据

};
SUser g_user[10000];//可以实现保存10000条数据记录
Stu_CW::Stu_CW(){

}

Stu_CW::~Stu_CW(){

}
void Stu_CW::Print(){
    printf("\n==========================\n");
    printf("学号\t姓名\t成绩\n");//其中\t挺好用的
    int i = 0, num = 0;
    while (g_user[i].m_Num){//0.1f只取一位
        if (g_user[i].m_Num > 0){//将-1屏蔽 不打印 =0 停止退出循环
            printf("%d\t%s\t%0.1f\n", g_user[i].m_Num, &g_user[i].m_Name, g_user[i].m_Math);
            //这里注意,数组加引用就有问题了,数组第一个代表的是指针
            //所以此处用g_user[i].m_Math  而不能用&g_user[i].m_Math
            ++num;
        }
        ++i;//这里很重要,必须是先+后赋值

    }
    printf("当前共用: %d 条记录\n", num);
    printf("==========================\n\n");
}
void Stu_CW::Save(){
    FILE *p; int i = 0;
    p = fopen("学生管理系统.txt", "w");
    if (!p){
        puts("\n文件不存在/未保存文件!\n");
        return;
    }

    while (g_user[i].m_Num){//不为0时才存储,否则全部存储就浪费
        if (-1 != g_user[i].m_Num){    //删除时候g_user[i].m_Num=-1  去掉这种情况
            fwrite(&g_user[i], 1, sizeof(g_user[i]), p);//将什么,以什么样的方式写入哪里的文件
            //每次写一块,总共写多少块
            /*fprintf(p, "%d %s %f", &g_user[i]);*/
        }
        ++i;
    }
    fclose(p);
}
void Stu_CW::Load(){
    FILE *pf = fopen("学生管理系统.txt", "r");
    int i = 0, choose_key = 0;
    if (!pf){
        puts("文档中未保存数据,请重新录入");
        printf("\n 请选择:(1)继续 (2)退出");
        scanf_s("%d", &choose_key);
        switch (choose_key){
        case 1:
            return;
        case 2:
            return;
        }
    }

    //SUser us;//定义一个结构体大小的结构体对象  创建临时结构体 传送到g_user
    /*int n = fread(&g_user, 1, sizeof(us), pf);//读入方法一
    while (n){
    ++i;
    n = fread(&g_user[i], 1, sizeof(us), pf);
    }*/
    //while (fread(&us, 1, sizeof(us), pf))//读入方法二
    //    g_user[i++] = us;//每次读入的数据放到g_user
    while (fread(&g_user[i++], 1, sizeof(SUser), pf) > 0);//读入方法三
    fclose(pf);
    printf("\n");
    //Print();
}
void Stu_CW::Add(){////一共可以录入[10000]条数据,即为截止条件
    int i = 0;//结构体中学号录入指针+1
    int j = 0;//保持i的不动,即将g_user[i].m_Num作为被比较对象    
    int com_Num;//定义一个临时变量来检查是否有已存在的学号,输入时,将学号数据赋给该变量,
    //然后再给g_user[i].m_Num,同所有g_user[i].m_Num中i之前数据比较
    while (g_user[i].m_Num)//{//此处不能使g_user非零;应该是结构体中的某一个数据非零
        //想想g_user结构体中的名字怎么可能=0?
        i++;//先取值用,后++  从0开始赋值
    printf("请输入学号: ");
    scanf_s("%d", &com_Num);//scanf_s("%s"不能添加其他的\n之类的 否则不现实
    g_user[i].m_Num = com_Num;
    j = i;
    while (g_user[i].m_Num){//学号非空来检查是否重定义
        --j;
        if (g_user[j].m_Num == com_Num){
            printf("学号已存在,请重新是输入\n");
            printf("请输入学号: ");
            scanf_s("%d", &com_Num);
            j = i;//输入的数据还需要在检查一次
        }
        if (j < 0){ break; }
    }
    printf("请输入姓名:  ");
    scanf_s("%s", g_user[i].m_Name, sizeof(g_user[i].m_Name));
    //scanf_s("%s", g_user[i].m_Name) 直接这样,无法输入/崩溃
    printf("请录入数学成绩: ");
    scanf_s("%f", &g_user[i].m_Math);
    Save();
    Print();
}
void Stu_CW::Delete(){//

    printf("\n请输入需要删除的学号序列号:  ");
    int i = 0;
    int s_num = 0;//需要中间变量存储输入值,将和g_user[i].m_Num
    int flag = 0;//设置标志位 作为判断是否找到被删除的序号
    scanf_s("%d", &s_num);
    while (g_user[i].m_Num){
        if (g_user[i].m_Num == s_num){
            g_user[i].m_Num = -1;//为什么不填0呢?填0代表结束了,后续的数据无法使用。
            //-1只是代表不打,但不会结束跳出循环;0会结束,跳出循环
            flag = 1;
            break;
        }
        ++i;//往下找的同时,将s_num同g_user[i].m_Num对比;
    }
    if (flag == 0){//如果没找到需要删除的学号的序号
        puts("\n\n 并未找到您所需要删除的学号 \n\n");
        return;
    }
    else{//找到了
        Save();
        Print();
    }
}
void Stu_CW::Modify(){//
    int i = 0, s_num = 0, modify_i = 0;
    printf("\n请输入您需要修改的记录的学号: ");
    scanf_s("%d", &s_num);
    while (g_user[i].m_Num){//内容非空的情况下,进行学号数据的对比
        if (g_user[i].m_Num == s_num){
            printf("\n\n (1)选择修改学号\n\n\n (2)选择修改姓名\n\n\n (3)选择修改成绩\n\n");
            printf("\n请选择需要修改的内容的选项: ");
            scanf_s("%d", &modify_i);
            do{
                switch (modify_i){
                case 1:
                    printf("请重新修改学号: ");
                    scanf_s("%d", &g_user[i].m_Num);
                    break;
                case 2:
                    printf("请重新修改姓名: ");
                    scanf_s("%s", g_user[i].m_Name, sizeof(g_user[i].m_Name));
                    break;
                case 3:
                    printf("请重新修改成绩: ");
                    scanf_s("%f", &g_user[i].m_Math);
                    break;
                }
                modify_i = 0;
            } while (modify_i);
            break;
        }
        ++i;//先增后赋值
    }
    if (!g_user[i].m_Num){//!g_user[i].m_Num即g_user[i].m_Num==0,即搜索到最后没有相同的内容
        puts("\n未找到您需要修改记录的序号!");
        return;
    }
    Save();
    Print();
}
void Stu_CW::Find(){//
    int i = 0, s_num = 0;
    printf("\n请输入需要查找的学号信息: ");
    scanf_s("%d", &s_num);
    while (g_user[i].m_Num){
        if (g_user[i].m_Num == s_num){
            printf("\n学号\t姓名\t成绩\n");
            printf("%d\t%s\t%0.1f\n", g_user[i].m_Num, g_user[i].m_Name, g_user[i].m_Math);
            system("pause");
            break;
        }
        ++i;
    }
    if (!g_user[i].m_Num){
        puts("\n不存在您查找的内容\n");
        return;
    }
}
int Stu_CW::Sort_Judge(int choose_sort_m, int nMin, int j){
    if (choose_sort_m == 1)
        return g_user[nMin].m_Num > g_user[j].m_Num;
    if (choose_sort_m == 2)
        return strcmp(g_user[nMin].m_Name, g_user[j].m_Name) > 0;
    if (choose_sort_m == 3)
        return g_user[nMin].m_Math < g_user[j].m_Math;
    return 0;
}

void Stu_CW::Gather_Sort(int m){
    int i = 0, n = 0, nMin = 0;
    while (g_user[n].m_Num)//循环的特点--[2][1][],即是否有学号存在,即g_user[n].m_Num是否未
        ++n;//一直循环,最后获得n极为总数
    /*选择排序算法实现部分*/
    while (i < n - 1){
        nMin = i;
        int j = i + 1;
        while (j < n){
            if (Sort_Judge(m, nMin, j)){
                SUser sortNum = g_user[nMin];
                g_user[nMin] = g_user[j];
                g_user[j] = sortNum;
            }
            ++j;
        }
        ++i;
    }
    /*冒泡排序算法实现部分*/
    /*for (i = 0; i < n - 1; i++){//冒泡法既然是前者VS后者,需用两层循环,此为外循环
    for (j = 0; j < n - (i + 1); j++){//j总小于i一个数   拿第一个数同后面每一个数进行比较(内循环);然后拿第二个数(外循环)同。。。
    if (Sort_Judge(m, j)){//选择模式 语句更加简短
    SUser sortNum = g_user[j];//每次到循环申请一个结构体作为中间传递变量 g_user[i]数据全部传递
    g_user[j] = g_user[j + 1];
    g_user[j + 1] = sortNum;
    }
    //switch (m){// 排序汇总函数选择方法一
    //case 1:
    //    if (g_user[j].m_Num>g_user[j + 1].m_Num){//前后对比  内循环数据来比较就行
    //        SUser sortNum = g_user[j];//每次到循环申请一个结构体作为中间传递变量 g_user[i]数据全部传递
    //        g_user[j] = g_user[j + 1];
    //        g_user[j + 1] = sortNum;
    //    }
    //    break;
    //case 2:
    //    if (strcmp(g_user[j].m_Name,g_user[j + 1].m_Name)>0){//前后对比  内循环数据来比较就行
    //        SUser sortNum = g_user[j];//每次到循环申请一个结构体作为中间传递变量 g_user[i]数据全部传递
    //        g_user[j] = g_user[j + 1];
    //        g_user[j + 1] = sortNum;
    //    }
    //    break;
    //case 3:
    //    if (g_user[j].m_Math<g_user[j + 1].m_Math){//前后对比  内循环数据来比较就行  成绩高,排名越靠前
    //        SUser sortNum = g_user[j];//每次到循环申请一个结构体作为中间传递变量 g_user[i]数据全部传递
    //        g_user[j] = g_user[j + 1];
    //        g_user[j + 1] = sortNum;
    //    }
    //    break;
    //}

    }
    }*/

}
//void SortByNum(){
//    //冒泡法,基本数据排序算法
//    //特点    前面数据同后面数据对比,如果不合适将数据依次对调
//    //前提    先获得存在多少实际数据//如果结构体g_user[10000]全用太浪费
//    int i = 0, n = 0,j=0;
//    while (g_user[n].m_Num)//循环的特点--[2][1][],即是否有学号存在,即g_user[n].m_Num是否未
//        ++n;//一直循环,最后获得n极为总数
//    for (i=0; i < n - 1; i++){//冒泡法既然是前者VS后者,需用两层循环,此为外循环
//        for (j=0; j < n - (i + 1); j++){//j总小于i一个数   拿第一个数同后面每一个数进行比较(内循环);然后拿第二个数(外循环)同。。。
//            if (g_user[j].m_Num>g_user[j+1].m_Num){//前后对比  内循环数据来比较就行
//                SUser sortNum = g_user[j];//每次到循环申请一个结构体作为中间传递变量 g_user[i]数据全部传递
//                g_user[j] = g_user[j + 1];
//                g_user[j + 1] = sortNum;
//            }
//        }
//    }
//    
//}
//void SortByName(){
//    //直接调用SortByName代码  只需要修改一句,即对比那个地方
//    int i = 0, n = 0, j = 0;
//    while (g_user[n].m_Num)//循环的特点--[2][1][],即是否有学号存在,即g_user[n].m_Num是否未
//        ++n;//一直循环,最后获得n极为总数
//    for (i = 0; i < n - 1; i++){//冒泡法既然是前者VS后者,需用两层循环,此为外循环
//        for (j = 0; j < n - (i + 1); j++){//j总小于i一个数   拿第一个数同后面每一个数进行比较(内循环);然后拿第二个数(外循环)同。。。
//            if (strcmp(g_user[j].m_Name,g_user[j + 1].m_Name)>0){//前后对比  内循环数据来比较就行
//                SUser sortNum = g_user[j];//每次到循环申请一个结构体作为中间传递变量 g_user[i]数据全部传递
//                g_user[j] = g_user[j + 1];
//                g_user[j + 1] = sortNum;
//            }
//        }
//    }
//    /*注*///strcmp 两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。如:
//    //"A"<"B" "a">"A" "computer">"compare"
//}
//void SortByMath(){
//    //直接调用SortByName代码  只需要修改一句,即对比那个地方
//    int i = 0, n = 0, j = 0;
//    while (g_user[n].m_Num)//循环的特点--[2][1][],即是否有学号存在,即g_user[n].m_Num是否未
//        ++n;//一直循环,最后获得n极为总数
//    for (i = 0; i < n - 1; i++){//冒泡法既然是前者VS后者,需用两层循环,此为外循环
//        for (j = 0; j < n - (i + 1); j++){//j总小于i一个数   拿第一个数同后面每一个数进行比较(内循环);然后拿第二个数(外循环)同。。。
//            if (g_user[j].m_Math>g_user[j + 1].m_Math){//前后对比  内循环数据来比较就行
//                SUser sortNum = g_user[j];//每次到循环申请一个结构体作为中间传递变量 g_user[i]数据全部传递
//                g_user[j] = g_user[j + 1];
//                g_user[j + 1] = sortNum;
//            }
//        }
//    }
//}
int Stu_CW::DisplayMenu(){
    Print();
    printf("\n==========================\n");
    puts("1】按学号排序");//puts专门输出字符
    puts("2】按名字排序");
    puts("3】按成绩排序");
    puts("0】返回主菜单");
    printf("==========================\n\n");
    printf("请输入选项: ");
    int i = 0;
    scanf_s("%d", &i);
    switch (i){//按0已经考虑到直接返回主菜单,防止堆栈压满情况; case 0
    case 1:
        //SortByNum();//排序选择方法一
        Gather_Sort(i);//排序选择方法2 ---汇总的方法
        break;
    case 2:
        //SortByName();
        Gather_Sort(i);
        break;
    case 3:
        //SortByMath();
        Gather_Sort(i);
        break;
    }
    return i;
}
int Stu_CW::Color_Set(){
    char bg[3];
    char fg[3];
    char yanse[9] = "color ";
    /*system("color ..");
    system("cls");*/
    puts("0 = 黑色 1 = 蓝色   2 = 绿色   3 = 湖蓝色   4 = 红色   5 = 紫色   6 = 黄色   7 = 白色 ");
    puts("8 = 灰色 9 = 淡蓝色 A = 淡绿色 B = 淡浅绿色 C = 淡红色 D = 淡紫色 E = 淡黄色 F = 亮白色");
    printf("\n请按照您的喜好和心情b( ̄▽ ̄)d选择背景颜色: ");
    //===================================================
    scanf_s("%s", bg, 2);//大小控制为1,读取到为空,插入,显示为0
    //scanf("%s", bg); 也行
    puts("0 = 黑色 1 = 蓝色   2 = 绿色   3 = 湖蓝色   4 = 红色   5 = 紫色   6 = 黄色   7 = 白色 ");
    puts("8 = 灰色 9 = 淡蓝色 A = 淡绿色 B = 淡浅绿色 C = 淡红色 D = 淡紫色 E = 淡黄色 F = 亮白色");
    printf("\n请按照您的喜好和心情b( ̄▽ ̄)d选择前景颜色: ");
    scanf_s("%s", fg, 2);
    //scanf("%s", fg);
    /*printf("color 1A");
    printf("\n%s", strcat(strcat(yanse, bg), fg));*/
    system(strcat(strcat(yanse, bg), fg));//
    return 0;
}
int Stu_CW::Menu(){//菜单
    puts("1】浏览所有信息");//puts专门输出字符
    puts("2】添加信息");
    puts("3】删除信息");
    puts("4】修改信息");
    puts("5】查找信息");
    puts("6】颜色设置");
    puts("0】退出");
    printf("请选择: ");
    int i = 0;
    scanf_s("%d", &i);
    switch (i){
    case 1:
        DisplayMenu();
        Print();
        break;
    case 2:
        Add();
        break;
    case 3:
        Delete();
        break;
    case 4:
        Modify();
        break;
    case 5:
        Find();
        break;
    case 6:
        Color_Set();
        break;
    }
    return i;
}
void Stu_CW::String_Pr(){
    printf("\n\t\t-----------------------------------\n");
    printf("\t\t***********************************\n");
    printf("\n\t\t ***   欢迎使用学生管理系统   ***\n");
    printf("\n\t\t ***        香草←作家        ***\n");
    printf("\n\t\t ***      2017/8/5 3:00      ***\n");
    printf("\t\t***********************************");
    printf("\n\t\t-----------------------------------");

}
void Stu_CW::Start(){//初始加载
    Load();
    while (Menu()){//无限循环
    };
}

// 纯属学习类的添加 类的成员函数添加
int Stu_CW::Learning_Code(int para, char * point, double Math)
{
    return 0;
}


// 输出显示界面
void Stu_CW::Welcome_String()
{
    cout << "  \t\t\t┏┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┓" <<endl;
    cout << "  \t\t\t┃  **********************************************  ┃" << endl;
    cout << "  \t\t\t┃***┏┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┓***┃" << endl;
    cout << "  \t\t\t┃***┃****************************************┃***┃" << endl;
    cout << "  \t\t\t┃***┃***                                  ***┃***┃" << endl;
    cout << "  \t\t\t┃***┃***       欢迎使用学生管理系统       ***┃***┃" << endl;
    cout << "  \t\t\t┃***┃***                                  ***┃***┃" << endl;
    cout << "  \t\t\t┃***┃***                                  ***┃***┃" << endl;
    cout << "  \t\t\t┃***┃***       (~ ̄▽ ̄)~轻心御风       ***┃***┃" << endl;
    cout << "  \t\t\t┃***┃***                                  ***┃***┃" << endl;
    cout << "  \t\t\t┃***┃***        2017.08.06|3:00pm        ***┃***┃" << endl;
    cout << "  \t\t\t┃***┃***                                  ***┃***┃" << endl;
    cout << "  \t\t\t┃***┗┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┛***┃" << endl;
    cout << "  \t\t\t┃  **********************************************  ┃" << endl;
    cout << "  \t\t\t┗┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┛" << endl;
}
Stu_CW.cpp

 

posted @ 2017-08-06 14:58  心沉大海-汇聚成一  阅读(155)  评论(0)    收藏  举报