学生信息管理系统(通讯录)----------通俗易懂、附源码、C语言实现

简介: 学生信息管理系统(通讯录)----------通俗易懂、附源码、C语言实现

绪论:


本篇文章使结构体章节后的习题,如果你对C语言有问题,或者结构体有什么问题不妨看看我之前所写的文章(章回体),对于文件管理(已补上)和动态内存分配问题(已补上)我将在后面补上,对于这个学生信息管理系统我用了多种方法和分源管理的形式来写可能内容偏多,但都有着重大意义,可以自行对我的源码进行copy和删减一些用了多种方法的地方,当然直接用也是没什么问题的。


思维导图

image.png

要XMind思维导图的话可以私信哈

目录



1.界面的创建、和功能的选择

2.功能的实现

       2.1动态内存管理:

3.文件的保存、和文件的调用


补充:

对于分源管理:这样做的原因是可以将这个程序的实现,分开来实现,主函数放在了test.c中这里就像一个枢纽(主干)来选择功能,而contact.c 中放着的是这些主干后的分支(他代表着所要实现的功能的具体代码),而contact.h(头文件)这里存放着一些在test.c 和 contact.c 同时需要用到的东西,如头文件的应用、#define 定义的常量 、以及函数的声明 、这样只需在.c(源文件)中引用#include"contact" 即可包含该文件中的内容


如果不想分源也可以写在一个源文件内,只要把函数、以及结构体和头文件拷贝到一个test.c文件中即可


下面先上源码:


test.c:

 #define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
enum function
{
  Exit ,
  Add,
  Del,
  Search,
  Modeify,
  Show,
  Sort,
  Refresh
};
void menu()
{
  printf("********************************\n");
  printf("********************************\n");
  printf("*****    1. Add  2.Del     *****\n");
  printf("********************************\n");
  printf("*****  3.Search  4.Modeify *****\n");
  printf("********************************\n");
  printf("*****   5.Show   6.Sort    *****\n");
  printf("********************************\n");
  printf("*****  7.refresh    0.exit *****\n");
  printf("********************************\n");
  printf("********************************\n");
}
int main()
{
  int input = 0;
  Info_System con ;
//初始化
  InitCon(&con);
  //初始化方法二:Info_System con = {0};直接将全部置成0
  do
  {
    menu();
    printf("请选择>:");
    scanf("%d", &input);
    switch(input)
    {
    case Add:
      Add_Stu_message(&con);
      break;
    case Del:
      Del_Stu_message(&con);
      break;
    case Search:
      Search_Stu_message(&con);
      break;
    case Modeify:
      Modeifyh_Stu_message(&con);
      break;
    case Show:
      Show_Stu_message(&con);
      break;
    case Sort:
      Sort_Stu_message(&con);
      break;
    case Refresh:
      Refresh_Stu_message(&con);
      break;
    case Exit:
      //保存文件
      SaveContact(&con);
      DestroyContact(&con);
      printf("退出\n");
      break;
    default:
      printf("选择错误,重新选择:\n");
      break;
    }
  } while (input);
  return 0;
}

contact.h:

#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define Name_Max 20
#define Sex_Max 5
#define Class_Max 20
#define Room_Max 20
#define PeoMax 100
#define InitPeo 3
#define AddCap 2
typedef struct PeoInfo//学生信息
{
  int ID;// 学号
  char Name[Name_Max];// 姓名
  char Sex[Sex_Max];// 性别
  char Class[Class_Max];// 班级
  char Room[Room_Max];// 宿舍号
  int Score;// 成绩
}PeoInfo;
//
//typedef struct management_System
//{
//
//  PeoInfo Contact[PeoMax];//存放人的信息
//  int sz;//已近存放了多少个人
//}Info_System;
typedef struct management_System
{
  PeoInfo* Contact;//存放人的信息
  int sz;//已近存放了多少个人
  int capacity;//容量大小
}Info_System;
void InitCon(Info_System *con);
void Add_Stu_message(Info_System* con);
void Show_Stu_message(const Info_System* con);
void Del_Stu_message (Info_System* con);
void Search_Stu_message(const Info_System* con);
void Modeifyh_Stu_message(Info_System* con);
void Sort_Stu_message(Info_System* con);
void Refresh_Stu_message(Info_System* con);
void DestroyContact(Info_System* con);
//保存文件
void SaveContact(Info_System*  con);
//加载文件
void LoadContact(Info_System* pc);

contact.c:

 #define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void AddCapacity(Info_System* con)
{
  assert(con);
  PeoInfo* ptr = (PeoInfo*)realloc(con->Contact,sizeof(PeoInfo) * (AddCap+ con->capacity));
  if (ptr == NULL)
  {
    perror("realloc");
    return ;
  }
  con->Contact = ptr;
  con->capacity += AddCap;
  ptr = NULL;
  printf("增容成功\n");
}
void LoadContact(Info_System* pc)
{
  //读数据
  //1. 打开文件
  FILE* pf = fopen("contact.txt", "rb");
  if (pf == NULL)
  {
    perror("LoadContact");
  }
  else
  {
    //2. 读数据
    PeoInfo tmp = { 0 };
    int i = 0;
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))//用fread先读到临时变量tmp内
    {
      //增容
      Check_Capacity(pc);
      pc->Contact[i] = tmp;//把tmp内的文件取进来
      pc->sz++;//增加人数
      i++;
    }
    fclose(pf);//关闭文件
    pf = NULL;
  }
}
void InitCon(Info_System* con)
{
  Refresh_Stu_message(con);
  LoadContact(con);
}
//初始化
//void InitCon(Info_System* con)
//{
//  assert(con);
//  con->sz = 0;
//  memset(con->Contact, 0, sizeof(Info_System));//利用memset将一块连续的空间初始化成0最后
//要初始化多少个字节
//}
int FindById(int Id, const Info_System* con)
{
  int t = con->sz;//不要改变sz,用t来代替需要查找的人
  while (t--)
  {
    if (Id == con->Contact[t].ID)
    {
      return t;
    }
  }
  printf("找不到此人\n");
  return -1 ;//返回-1是因为区别于返回0(返回0表示查找的人的下标为0)
}
int FindByName(char * name,const Info_System* con)
{
  int t = con->sz;//不要改变sz,用t来代替需要查找的人
  while (t--)
  {
    if (strcmp(name, con->Contact[t].Name) == 0)//--ret 是因为ret表示的是总人数,而总人数-1才能找到最后一个人
    {
      return t;
    }
  }
  printf("找不到此人\n");
  return -1;//返回-1是因为区别于返回0(返回0表示查找的人的下标为0)
}
//增加
void Add_Stu_message(Info_System* con)
{
  assert(con);
  if (con->sz == PeoMax)
  {
    AddCapacity(con);
  }
  printf("依次输入学号 名字 班级 性别 宿舍 计算机成绩\n并且以空格/回车分隔\n");
  scanf("%d %s %s %s %s %d", &con->Contact[con->sz].ID,
    con->Contact[con->sz].Name,
    con->Contact[con->sz].Class,
    con->Contact[con->sz].Sex,
    con->Contact[con->sz].Room,
    &con->Contact[con->sz].Score
  );
  con->sz += 1;
  //con->sz++;
  printf("添加完成\n");
}
void Show_Stu_message(const Info_System* con)
{
  assert(con);
  printf("%-10s %-20s %-20s %-5s %-20s %-10s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
  for (int i = 0; i < con->sz;i++)//解引用操作符的优先级都很(最)高
  {
    printf("%-10d %-20s %-20s %-5s %-20s %-10d\n", con->Contact[i].ID,
      con->Contact[i].Name,
      con->Contact[i].Class,
      con->Contact[i].Sex,
      con->Contact[i].Room,
      con->Contact[i].Score);
  }
}
void Del_Stu_message(Info_System* con)
{
  assert(con);
  if (con->sz == 0)
  {
    printf("没有学生信息\n");
    return;
  }
  int input = 0;
  printf("输入学号进行删除;>");
  scanf("%d", &input);
  int ret = FindById(input,con);
  if (ret != -1)
  {
    for (ret; ret < con-> sz - 1; ret++) //sz -1 也要转化成下标
    {
      con->Contact[ret] = con->Contact[ret+1]; //注意返回的就是所对应的下标
    }
    con->sz--;
    printf("删除成功\n");
  }
  //if (ret!=-1)
  //{
  //  memmove(con->Contact + ret, con->Contact + ret + 1, (con->sz)*sizeof(PeoInfo) - (ret) * sizeof(PeoInfo));
  //  con->sz--;
  //  printf("删除成功\n");
  //}
}
void Search_Stu_message(const Info_System* con)
{
  assert(con);
  int i = 0;
  printf("1.Id\n2.Name\n选择查找方法:>");
  scanf("%d", &i);
  if (i == 1)
  {
    int input = 0;
    printf("输入学号进行查找:>");
    scanf("%d", &input);
    int ret = FindById(input, con);
    if (ret != -1)
    {
      printf("%-10s %-20s %-20s %-5s %-20s %-10s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
      printf("%-10d %-20s %-20s %-5s %-20s %-10d\n", con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        con->Contact[ret].Score);
    }
  }
  else if (i == 2)
  {
    char name[20] = { 0 };
    printf("输入姓名进行查找:>");
    scanf("%s",name);
    int ret = FindByName(name, con);
    if (ret != -1)
    {
      printf("%-10s %-20s %-20s %-5s %-20s %-10s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
      printf("%-10d %-20s %-20s %-5s %-20s %-10d\n", con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        con->Contact[ret].Score);
    }
  }
  else
  {
    printf("选择错误\n");
  }
}
void Modeifyh_Stu_message(Info_System* con)
{
  assert(con);
  int i = 0;
  printf("1.Id\n2.Name\n选择查找方法:>");
  scanf("%d", &i);
  if (i == 1)
  {
    int input = 0;
    printf("输入要修改的学生信息的学号:>");
    scanf("%d", &input);
    int ret = FindById(input, con);
    if (ret != -1)
    {
      printf("修改:>\n");
      printf("依次输入学号 名字 班级 性别 宿舍 计算机成绩\n并且以空格/回车分隔\n");
      scanf("%d %s %s %s %s %d", &con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        &con->Contact[ret].Score
      );
      printf("修改完成\n");
    }
  }
  else if (i == 2)
  {
    char name[20] = { 0 };
    printf("输入要修改的学生信息的姓名:>");
    scanf("%s", name);
    int ret = FindByName(name, con);
    if (ret != -1)
    {
      printf("修改:>\n");
      printf("依次输入学号 名字 班级 性别 宿舍 计算机成绩\n并且以空格/回车分隔\n");
      scanf("%d %s %s %s %s %d", &con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        &con->Contact[ret].Score
      );
      printf("修改完成\n");
    }
  }
  else
  {
    printf("选择错误\n");
  }
}
int Sort_Name(const void* e1, const void* e2)
{
  return strcmp(((PeoInfo*)e1)->Name, ((PeoInfo*)e2)->Name);
}
int Sort_age(const void* e1, const void* e2)
{
  return ((PeoInfo*)e1)->ID  - ((PeoInfo*)e2)->ID;
}
void Sort_Stu_message(Info_System* con)
{
  assert(con);
  int input = 0;
  printf("1.以名字排序\n2.以学号排序\n");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    qsort(con->Contact, con->sz, sizeof(con->Contact[0]), Sort_Name);
    printf("排序成功\n");
    break;
  case 2:
    qsort(con->Contact, con->sz, sizeof(con->Contact[0]), Sort_age);
    printf("排序成功\n");
    break;
  default:
    printf("输入错误\n");
    break;
  }
}
void Refresh_Stu_message(Info_System* con)
{
  InitCon(con);
  printf("刷新成功\n");
}
void DestroyContact(Info_System* con)
{
  free(con->Contact);
  con->Contact = NULL;
  con->capacity = 0;
  con->sz = 0;
  con = NULL;
}
void SaveContact(Info_System* con)
{
  FILE* pf = fopen("contact.txt","wb");
  if (pf == NULL)
  {
    perror("SaveContact");
    return;
  }
  int i = 0;
  for (i = 0; i < con->sz; i++)
  {
    fwrite(con->Contact + i, sizeof(PeoInfo), 1, pf);
  }
  fclose(pf);
  pf = NULL;
}

1.界面的创建、和功能的选择

创建目录(界面):

在main函数内创建一个目录函数

int main()
{
  menu();
    retrn 0;
}

直接通过打印的方法,打印出自己所想要的目录(界面)


创建选择功能:

通过dowhile循环来不断的进行选择并且通过switch语句来控制所选择功能,并且通过枚举变量来实现。

int main()
{
  int input = 0;
  do
  {
    printf("请选择>:");
    scanf("%d", &input);
    switch(input)
    {
    case Add:
      Add_Stu_message(&con);
      break;
    case Del:
      Del_Stu_message(&con);
      break;
    case Search:
      Search_Stu_message(&con);
      break;
    case Modeify:
      Modeifyh_Stu_message(&con);
      break;
    case Show:
      Show_Stu_message(&con);
      break;
    case Sort:
      Sort_Stu_message(&con);
      break;
    case Refresh:
      Refresh_Stu_message(&con);
      break;
    case Exit:
      printf("退出\n");
      break;
    default:
      printf("选择错误,重新选择:\n");
      break;
    }
  } while (input);
  return 0;
}

初始化学生信息:

对于已经创建好的结构体,他们此时还是一些随机值需要初始化

所以写一个初始化函数来进行初始化

void InitCon(Info_System* con)
{
  assert(con);
  con->sz = 0;
  memset(con->Contact, 0, sizeof(Info_System));//利用memset将一块连续的空间初始化成0最后要初始化多少个字节
}

其中有到了memset来直接对其初始化:

第一个元素放目标地址,第二个元素表示要放东西的整形形式(如0 -> 0 ;而 'a' -> 97),第三个元素表示这个目标的大小(byte),具体用法可以看这篇博客:进阶C语言第三章-------《字符函数和内存函数》 完整思维导图+基本练习题+深入细节+通俗易懂+知识点+建议收藏_溟洵的博客-CSDN博客

2.功能的实现

添加学生信息:

对于下面的scanf操作的解释:

       我们需要引用并且存进结构体中而对于数组来说不需要加上& (因为其数组名表示其地址 而对于整形就需要&了)

       先从con通过->访问其里面的成员Contact  而其又是PeoInfo结构体的数组变量所以就可以通过访问数组空间 再用.操作符来找到学生的信息(这里不用-> 是因为前面con->Contact[con->sz] 已经表示成Contact[PeoMax]结构体变量了不需要在*解引用了 )

void Add_Stu_message(Info_System* con)
{
assert(con);
if (con->sz == PeoMax)
{
  printf("信息已满,请删除或刷新后再试\n");
  return;
}
printf("依次输入%s %s %s %s %s %s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
scanf("%d %s %s %s %s %d",                  
&con->Contact[con->sz].ID,                                            
con->Contact[con->sz].Name,                             
con->Contact[con->sz].Class,                             
con->Contact[con->sz].Sex,                                
con->Contact[con->sz].Room,                          
&con->Contact[con->sz].Score
);
printf("添加完成\n");
}

展示学生信息:

void Show_Stu_message(Info_System* con)
{
  assert(con);
  printf("%-10s %-20s %-20s %-5s %-20s %-10s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
  for (int i = 0; i < con->sz;i++)
    {
      printf("%-10d %-20s %-20s %-5s %-20s %-10d\n",
       con->Contact[i].ID,
      con->Contact[i].Name,
      con->Contact[i].Class,
      con->Contact[i].Sex,
      con->Contact[i].Room,
      con->Contact[i].Score
      );
    }
}

对于printf打印只需要满足所给条件(%d)和所写条件(con->Contact[i].ID)对应的类型一致即可。

删除学生信息:

void Del_Stu_message(Info_System* con)
{
  assert(con);
  if (con->sz == 0)
  {
    printf("没有学生信息\n");
    return;
  }
  int input = 0;
  printf("输入学号进行删除;>");
  scanf("%d", &input);
  int ret = FindById(input,con);
  if (ret != -1)
  {
    for (ret; ret < con-> sz - 1; ret++) //sz -1 也要转化成下标
    {
      con->Contact[ret] = con->Contact[ret+1]; //注意返回的就是所对应的下标
    }
    con->sz--;
    printf("删除成功\n");
  }
  //if (ret!=-1)
  //{
  //  memmove(con->Contact + ret, con->Contact + ret + 1, (con->sz)*sizeof(PeoInfo) - (ret) * sizeof(PeoInfo));
  //  con->sz--;
  //  printf("删除成功\n");
  //}
}

查找学生信息

void Search_Stu_message(const Info_System* con)
{
  assert(con);
  int i = 0;
  printf("1.Id\n2.Name\n选择查找方法:>");
  scanf("%d", &i);
  if (i == 1)
  {
    int input = 0;
    printf("输入学号进行查找:>");
    scanf("%d", &input);
    int ret = FindById(input, con);
    if (ret != -1)
    {
      printf("%-10s %-20s %-20s %-5s %-20s %-10s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
      printf("%-10d %-20s %-20s %-5s %-20s %-10d\n", con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        con->Contact[ret].Score);
    }
  }
  else if (i == 2)
  {
    char name[20] = { 0 };
    printf("输入姓名进行查找:>");
    scanf("%s",name);
    int ret = FindByName(name, con);
    if (ret != -1)
    {
      printf("%-10s %-20s %-20s %-5s %-20s %-10s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
      printf("%-10d %-20s %-20s %-5s %-20s %-10d\n", con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        con->Contact[ret].Score);
    }
  }
  else
  {
    printf("选择错误\n");
  }
}

查找学生的函数:

int FindByName(char * name,const Info_System* con)
{
  int t = con->sz;//不要改变sz,用t来代替需要查找的人
  while (t--)
  {
    if (strcmp(name, con->Contact[t].Name) == 0)//--ret 是因为ret表示的是总人数,而总人数-1才能找到最后一个人
    {
      return t;
    }
  }
  printf("找不到此人\n");
  return -1;//返回-1是因为区别于返回0(返回0表示查找的人的下标为0)
}
int FindById(int Id, const Info_System* con)
{
  int t = con->sz;//不要改变sz,用t来代替需要查找的人
  while (t--)
  {
    if (Id == con->Contact[t].ID)
    {
      return t;
    }
  }
  printf("找不到此人\n");
  return -1 ;//返回-1是因为区别于返回0(返回0表示查找的人的下标为0)
}

修改学生信息

void Modeifyh_Stu_message(Info_System* con)
{
  int i = 0;
  printf("1.Id\n2.Name\n选择查找方法:>");
  scanf("%d", &i);
  if (i == 1)
  {
    int input = 0;
    printf("输入要修改的学生信息的学号:>");
    scanf("%d", &input);
    int ret = FindById(input, con);
    if (ret != -1)
    {
      printf("原信息:\n%-10s %-20s %-20s %-5s %-20s %-10s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
      printf("%-10d %-20s %-20s %-5s %-20s %-10d\n", con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        con->Contact[ret].Score);
      printf("修改:>\n");
      printf("依次输入学号 名字 班级 性别 宿舍 计算机成绩\n并且以空格/回车分隔\n");
      scanf("%d %s %s %s %s %d", &con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        &con->Contact[ret].Score
      );
    }
  }
  else if (i == 2)
  {
    char name[20] = { 0 };
    printf("输入要修改的学生信息的姓名:>");
    scanf("%s", name);
    int ret = FindByName(name, con);
    if (ret != -1)
    {
      printf("原信息:\n%-10s %-20s %-20s %-5s %-20s %-10s\n", "学号", "名字", "班级", "性别", "宿舍", "计算机成绩");
      printf("%-10d %-20s %-20s %-5s %-20s %-10d\n", con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        con->Contact[ret].Score);
      printf("修改:>\n");
      printf("依次输入学号 名字 班级 性别 宿舍 计算机成绩\n并且以空格/回车分隔\n");
      scanf("%d %s %s %s %s %d", &con->Contact[ret].ID,
        con->Contact[ret].Name,
        con->Contact[ret].Class,
        con->Contact[ret].Sex,
        con->Contact[ret].Room,
        &con->Contact[ret].Score
      );
    }
  }
  else
  {
    printf("选择错误\n");
  }
}

排序学生信息

int Sort_Name(const void* e1, const void* e2)
{
  return strcmp(((PeoInfo*)e1)->Name, ((PeoInfo*)e2)->Name);
  //注意强转要写成 PeoInfo* 结构体类型
  //返回大于0的数才交换,即是升序形式
}
int Sort_age(const void* e1, const void* e2)
{
  return ((PeoInfo*)e1)->ID  - ((PeoInfo*)e2)->ID;
}
void Sort_Stu_message(Info_System* con)
{
  assert(con);
  int input = 0;
  printf("1.以名字排序\n2.以学号排序\n");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    //ASCII升序
    qsort(con->Contact, con->sz, sizeof(con->Contact[0]), Sort_Name);//头文件stdlib,比较函数int compare(const void *elem1, const void *elem2)
    //此处con->Contact 直接找到了数组名传进去,所以qsort内所接受到的结构体时PeoInfo类型的
    printf("排序成功\n");
    break;
  case 2:
    //升序
    qsort(con->Contact, con->sz, sizeof(con->Contact[0]), Sort_age);
    printf("排序成功\n");
    break;
  default:
    printf("输入错误\n");
    break;
  }
}

刷新学生信息

void Refresh_Stu_message(Info_System* con)
{
  InitCon(con);//直接再次调用初始化函数
  printf("刷新成功\n");
}

动态内存管理:

对于动态内存来说,他所要修改的地方是空间的开辟问题,对此我们

1. 首先需要重新定义一下结构体:来知道容量的大小来确保容量的够用

//静态的
//typedef struct management_System
//{
//
//  PeoInfo Contact[PeoMax];//存放人的信息
//  int sz;//已近存放了多少个人
//}Info_System;
//动态的
typedef struct management_System
{
  PeoInfo* Contact;//存放人的信息
  int sz;//已近存放了多少个人
  int capacity;//容量大小
}Info_System;

2. 对此还需要再定义两个常量,来定义起始人数和后面容量不够时每次增加的容量

#define InitPeo 3
#define AddCap 2

(用#define定义是因为这样当你需要对程序进行修改时就可以直接在此处修改,而不要跑到代码内一处处的修改)

3. 因为是动态的所以我们还要修改一下Add函数,当进行增加人数时应该判断一下所开辟的空间是否够(通过AddCapacity函数来增容)

void AddCapacity(Info_System* con)
{
  assert(con);
  PeoInfo* ptr = (PeoInfo*)realloc(con->Contact,sizeof(PeoInfo) * (AddCap+ con->capacity));
  if (ptr == NULL)
  {
    perror("realloc");
    return ;
  }
  con->Contact = ptr;
  con->capacity += AddCap;
  ptr = NULL;
}
void Add_Stu_message(Info_System* con)
{
  assert(con);
  if (con->sz == con->capacity)
  {
    AddCapacity(con);
  }
    printf("依次输入学号 名字 班级 性别 宿舍 计算机成绩\n并且以空格/回车分隔\n");
  scanf("%d %s %s %s %s %d", &con->Contact[con->sz].ID,
    con->Contact[con->sz].Name,
    con->Contact[con->sz].Class,
    con->Contact[con->sz].Sex,
    con->Contact[con->sz].Room,
    &con->Contact[con->sz].Score
  );
  con->sz += 1;
  //con->sz++;
  printf("添加完成\n");
}

4. 当我们退出程序时还应该将所借的空间归还给操作系统

//contact.c
void DestroyContact(Info_System* con)
{
  free(con->Contact);
  con->Contact = NULL;
  con->capacity = 0;
  con->sz = 0;
  con = NULL;
}
//contact.h
void DestroyContact(Info_System* con);
//test.c
...
case Exit:
  DestroyContact(&con);
  printf("退出\n");
    break;
...

3.文件的保存、和文件的调用

所要修改的地方:

1. 我们需要把学生信息管理系统的初始化(InitCon),此时我们需要把原本(改变学生人数、对信息初始化)换成文件版,此时我们可以先进行加载把之前写过的信息加载进来、以及初始化一些基础信息,具体如下:

void LoadContact(Info_System* pc)
{
  //读数据
  //1. 打开文件
  FILE* pf = fopen("contact.txt", "rb");//以二进制的方式读入、后面存同样也是二进制
  if (pf == NULL)
  {
    perror("LoadContact");
  }
  else
  {
    //2. 读数据
    PeoInfo tmp = { 0 };
    int i = 0;
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))//用fread先读到临时变量tmp内
    {
      //增容
      Check_Capacity(pc);
      pc->Contact[i] = tmp;//把tmp内的文件取进来
      pc->sz++;//增加人数
      i++;
    }
    fclose(pf);//关闭文件
    pf = NULL;
  }
}
void InitCon(Info_System* con)
{
  Refresh_Stu_message(con);
  LoadContact(con);
}
void Refresh_Stu_message(Info_System* con)
{
  assert(con);
  con->sz = 0;
  con->capacity = InitPeo;
  PeoInfo* ptr = (PeoInfo*)malloc(sizeof(PeoInfo) * InitPeo);//为学生信息先开辟一定大小的空间
  if (ptr == NULL)
  {
    perror("malloc");
    return;
  }
  con->Contact = ptr;
  ptr = NULL;
  memset(con->Contact, 0, sizeof(PeoInfo) * InitPeo);
}

2.  当我们写完数据后我们需要将这些数据进行保存,并且保存到文件中

void SaveContact(Info_System* con)
{
  FILE* pf = fopen("contact.txt","wb");//以写的方法
  if (pf == NULL)
  {
    perror("SaveContact");
    return;
  }
  int i = 0;
  for (i = 0; i < con->sz; i++)
  {
    fwrite(con->Contact + i, sizeof(PeoInfo), 1, pf);//将数据一一的从con->contact+i中获取后存进文件pf中
  }
  fclose(pf);//关闭
  pf = NULL;
}

持续更新大量C语言知识,关注喔老铁!

相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
178 9
|
2月前
|
存储 C语言
【C语言篇】深入理解指针3(附转移表源码)
【C语言篇】深入理解指针3(附转移表源码)
46 1
|
1月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
75 16
|
1月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
94 8
|
1月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
105 7
|
1月前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
129 8
|
1月前
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
32 1
|
1月前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
83 4
|
1月前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
75 3
|
2月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
34 2