C语言实现学生信息管理系统
前言
由于疫情原因,最近只能呆在家里上网课,但实在不想听这个旅游管理的专业课(一直他喵的洗脑不要我们转专业DX)和英语(PS. 数学还是要听一听的),所以搞出来了这个东西……
连带摸鱼耗费了4天的时间,共760行左右的代码,实现了链表节点的增删查改功能。由于还没有系统学习过C语言,所以许多东西都是自己摸索加查资料得来的。可能十分臃肿,欢迎批评斧正。
PS. 在大神们看来这可能不算什么,但我还是十分兴奋的(=v=)。
代码详情
main.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"head.h"
newStudent *studentNext;
int main(void)
{
int modeCode;
initStudentList();
loadData(1);
while(1)
{
welcome();
printf("\nPlease select mode:");
scanf("%1d%*c", &modeCode);
switch(modeCode)
{
case 1:
system("cls");
addStudent();
break;
case 2:
system("cls");
selStudentMain();
break;
case 3:
system("cls");
delStudentMain();
break;
case 4:
system("cls");
changeStudentMain();
break;
case 5:
system("cls");
loadData(0);
break;
case 6:
system("cls");
updateData();
break;
case 0:
free(studentNext);
exit(0);
}
}
}
head.h
//当前加载学生数量
int studentNumber = 0;
//学生结构体
typedef struct students
{
char id[11];
char name[40];
char sex[7];
char age[4];
struct students *next;
}newStudent;
//全局链表
extern newStudent *studentNext;
//欢迎词
void welcome();
//链表初始化
void initStudentList();
//更新学生数据
int updateData();
//加载学生数据
int loadData(int autoCode);
//添加学生
int addStudent();
//删除学生主菜单
int delStudentMain();
//通过学号删除学生
int delStudentById(char *id, int autoCode);
//通过姓名删除学生
int delStudentByName(char *name, int autoCode);
//删除当前所有数据
int delAllStudent();
//搜索学生主菜单
int selStudentMain();
//通过学号搜索学生
newStudent *selStudentById(char *id);
//通过姓名搜索学生
newStudent *selStudentByName(char *name);
//展示所有学生
int showStudent();
//更改学生数据主菜单
int changeStudentMain();
//更改学生数据
int changeStudent(newStudent *studentTmp);
//欢迎词
void welcome()
{
system("cls");
printf("========================================\n");
printf("= _____ _____ __ __ _____ =\n");
printf("= / ____| / ____| | \\/ | / ____| =\n");
printf("= | | | (___ | \\ / | | (___ =\n");
printf("= | | \\___ \\ | |\\/| | \\___ \\ =\n");
printf("= | |____ ____) | | | | | ____) | =\n");
printf("= \\_____| |_____/ |_| |_| |_____/ =\n");
printf("========================================\n");
printf("=====CUIT Student Management System=====\n");
printf("========================================\n");
printf("============Student Number:%d============\n", studentNumber);
printf("========================================\n");
printf("=============1.Add Student==============\n");
printf("=============2.Sel Student==============\n");
printf("=============3.Del Student==============\n");
printf("=============4.Cha Student==============\n");
printf("=============5.load Data==============\n");
printf("=============6.update Data==============\n");
printf("=============0.Exit System==============\n");
printf("========================================\n");
}
//链表初始化
void initStudentList()
{
studentNext = (newStudent*)malloc(sizeof(newStudent));
studentNext->next = NULL;
}
//更新学生数据
int updateData()
{
FILE *fp = NULL;
newStudent *studentTmp = NULL;
if(studentNext->next != NULL)
{
if(remove("studentInfo.txt") == 0)
{
fp = fopen("studentInfo.txt", "w");
studentTmp = studentNext->next;
if(fp != NULL)
{
while(studentTmp != NULL)
{
fprintf(fp, "|%s|%s|%s|%s|\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
studentTmp = studentTmp->next;
}
fclose(fp);
printf("Updata completed\n");
delAllStudent();
loadData(1);
}
else
printf("File open fail\n");
}
else
printf("File delete fail\n");
}
else
{
fp = fopen("studentInfo.txt", "w");
if(fgetc(fp) != EOF)
{
fclose(fp);
remove("studentInfo.txt");
fp = fopen("studentInfo.txt", "w");
fclose(fp);
}
else
printf("The current data is empty!\n");
}
system("pause");
return 1;
}
//加载学生数据
int loadData(int autoCode)
{
FILE *fp = NULL;
char data[64] = {0};
char *str = NULL;
int i = 0;
int number = 0;
int judgeCode = 0;
newStudent *studentTmp = NULL;
fp = fopen("studentInfo.txt", "r+b");
printf("Start load Data...\n");
while(fscanf(fp, "%[^\n]%*c", data) != EOF)
{
studentTmp = (newStudent*)malloc(sizeof(newStudent));
str = strtok(data, "|");
for(i = 0; i < 4; i++)
{
if(str != NULL && str != EOF && str != '\0')
{
switch(i)
{
case 0:
if(selStudentById(str) == NULL)
{
strcpy(studentTmp->id, str);
break;
}
else
{
judgeCode = 1;
break;
}
case 1:
strcpy(studentTmp->name, str);
break;
case 2:
strcpy(studentTmp->sex, str);
break;
case 3:
strcpy(studentTmp->age, str);
break;
}
if(judgeCode)
break;
str = strtok(NULL, "|");
}
}
if(!judgeCode)
{
studentTmp->next = studentNext->next;
studentNext->next = studentTmp;
studentNumber++;
number++;
}
}
printf("All done, loaded %d student...\n", number);
fclose(fp);
if(!autoCode)
system("pause");
return 1;
}
//添加学生
int addStudent()
{
int sexCode = 0; //性别状态码
int judgeCode = 0;
FILE *fp = NULL; //文件变量
char continueCode = 1; //判断是否继续添加
newStudent *studentSel = NULL;
while(1)
{
fp = fopen("studentInfo.txt", "a");
//分配新内存
newStudent *studentTmp = (newStudent*)malloc(sizeof(newStudent));
printf("Please enter the id of the new student:");
scanf("%10[^\n]%*c", &studentTmp->id);
if(studentNext->next != NULL)
{
studentSel = selStudentById(studentTmp->id);
if(studentSel != NULL)
{
printf("The same ID has been entered!\n");
printf("Students found:%-11s%-20s%-7s%-4s\n", studentSel->id, studentSel->name, studentSel->sex, studentSel->age);
printf("Would you like to update this student's information?[Yes(1)/No(0)]:");
scanf("%1d%*c", &judgeCode);
if(judgeCode == 1)
delStudentById(studentTmp->id, 1);
else
return -1;
}
}
printf("Please enter the name of the new student:");
scanf("%39[^\n]", &studentTmp->name);
while(1)
{
printf("Please choose the sex of the new student[Male(1)/Female(0)]:");
scanf("%1d%*c", &sexCode);
if(sexCode == 1)
{
strcpy(studentTmp->sex ,"Male");
break;
}
else if(sexCode == 0)
{
strcpy(studentTmp->sex, "Female");
break;
}
else
printf("Choose Error\n");
}
printf("Please enter the age of the new student:");
scanf("%3[^\n]%*c", &studentTmp->age);
if(fp != NULL)
{
fprintf(fp, "|%s|%s|%s|%s|\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
fclose(fp);
}else
{
printf("File open fail!\n");
}
studentTmp->next = studentNext->next;
studentNext->next = studentTmp;
studentNumber++;
while(continueCode)
{
printf("Do you want to continue adding students?[Yes(1)/No(0)]:");
scanf("%1d%*c", &continueCode);
if(continueCode)
system("cls");
break;
}
if(!continueCode)
break;
}
return 1;
}
//删除学生主菜单
int delStudentMain()
{
int modeCode = 0;
int judgeCode = 0;
char id[11] = {0};
char name[40] = {0};
if(studentNext->next != NULL)
{
printf("What keywords do you want to delete data from?\n");
printf(">Cancel(Other)\n");
printf(">Student's id(1)\n");
printf(">Student's name(2)\n");
printf(">Delete all student(3)\n");
printf("I choose to delete data by:");
scanf("%1d%*c", &modeCode);
switch(modeCode)
{
case 1:
system("cls");
printf("Please enter the ID of the student you want to delete:");
scanf("%10s%*c", &id);
delStudentById(id, 0);
modeCode = 1;
break;
case 2:
system("cls");
printf("Please enter the name of the student you want to delete:");
scanf("%[^\n]%*c", &name);
delStudentByName(name, 0);
modeCode = 1;
break;
case 3:
system("cls");
printf("Are you sure you want to delete all student data?[Yes(1)/No(0)]:");
scanf("%1d%*c", &judgeCode);
if(judgeCode)
delAllStudent();
modeCode = 1;
break;
default:
modeCode = 0;
break;
}
}
else
{
printf("The current data is empty!\n");
system("pause");
}
return(modeCode);
}
//通过学号删除学生
int delStudentById(char *id, int autoCode)
{
int judgeCode = 1;
newStudent *studentDel = NULL;
newStudent *studentTmp = NULL;
studentTmp = studentNext;
studentDel = studentNext->next;
if(studentNext->next != NULL)
{
while(judgeCode)
{
judgeCode = strncmp(studentDel->id, id, 10);
if(!judgeCode)
{
printf("Removed student:%-11s%-20s%-7s%-4s\n", studentDel->id, studentDel->name, studentDel->sex, studentDel->age);
studentTmp->next = studentDel->next;
studentNumber--;
printf("successfully deleted\n");
break;
}
if(studentDel->next == NULL)
{
printf("No corresponding ID found!\n");
break;
}
studentTmp = studentDel;
studentDel = studentDel->next;
}
free(studentDel);
}
else
{
printf("The current data is empty!\n");
}
if(!autoCode)
system("pause");
return 1;
}
//通过姓名删除学生
int delStudentByName(char *name, int autoCode)
{
int judgeCode = 1;
newStudent *studentDel = NULL;
newStudent *studentTmp = NULL;
studentTmp = studentNext;
studentDel = studentNext->next;
if(studentNext->next != NULL)
{
while(judgeCode)
{
judgeCode = strcmp(studentDel->name, name);
if(!judgeCode)
{
printf("Removed student:%-11s%-20s%-7s%-4s\n", studentDel->id, studentDel->name, studentDel->sex, studentDel->age);
studentTmp->next = studentDel->next;
studentNumber--;
printf("successfully deleted\n");
break;
}
if(studentDel->next == NULL)
{
printf("No corresponding name found!\n");
break;
}
studentTmp = studentDel;
studentDel = studentDel->next;
}
free(studentDel);
}
else
{
printf("The current data is empty!\n");
}
if(!autoCode)
system("pause");
return 1;
}
//删除当前所有数据
int delAllStudent()
{
free(studentNext);
initStudentList();
studentNumber = 0;
return 1;
}
//搜索学生主菜单
int selStudentMain()
{
int modeCode = 0;
char id[11] = {0};
char name[40] = {0};
newStudent *studentTmp = NULL;
if(studentNext->next != NULL)
{
printf("What keywords do you want to select data from?\n");
printf(">Cancel(Other)\n");
printf(">Student's ID(1)\n");
printf(">Student's name(2)\n");
printf(">Show all student(3)\n");
printf("I choose to select data by:");
scanf("%1d%*c", &modeCode);
switch(modeCode)
{
case 1:
system("cls");
printf("Please enter the ID of the student you want to select:");
scanf("%10[^\n]%*c", &id);
studentTmp = selStudentById(id);
if(studentTmp != NULL)
printf("Students found:%-11s%-20s%-7s%-4s\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
else
printf("No corresponding ID found!\n");
system("pause");
modeCode = 1;
break;
case 2:
system("cls");
printf("Please enter the name of the student you want to select:");
scanf("%[^\n]%*c", &name);
studentTmp = selStudentByName(name);
if(studentTmp != NULL)
printf("Students found:%-11s%-20s%-7s%-4s\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
else
printf("No corresponding ID found!\n");
system("pause");
modeCode = 1;
break;
case 3:
showStudent();
break;
default:
modeCode = 0;
break;
}
}
else
{
printf("The current data is empty!\n");
system("pause");
}
return(modeCode);
}
//通过学号搜索学生
newStudent *selStudentById(char *id)
{
int judgeCode = 1;
newStudent *studentTmp = NULL;
if(studentNext->next != NULL)
{
studentTmp = studentNext->next;
while(judgeCode)
{
judgeCode = strncmp(studentTmp->id, id, 10);
if(judgeCode)
studentTmp = studentTmp->next;
if(studentTmp == NULL)
judgeCode = 0;
}
}
else
{
printf("The current data is empty!\n");
}
return studentTmp;
}
//通过姓名搜索学生
newStudent *selStudentByName(char *name)
{
int judgeCode = 1;
newStudent *studentTmp = NULL;
if(studentNext->next != NULL)
{
studentTmp = studentNext->next;
while(judgeCode)
{
judgeCode = strcmp(studentTmp->name, name);
if(judgeCode)
studentTmp = studentTmp->next;
if(studentTmp == NULL)
judgeCode = 0;
}
}
else
{
printf("The current data is empty!\n");
}
return studentTmp;
}
//展示所有学生
int showStudent()
{
newStudent *studentNow;
if(studentNext->next != NULL)
{
studentNow = studentNext->next;
while(studentNow != NULL)
{
printf("%-11s%-20s%-7s%-4s\n", studentNow->id, studentNow->name, studentNow->sex, studentNow->age);
studentNow = studentNow->next;
}
printf("All done...\n");
}
else
{
printf("The current data is empty!\n");
}
system("pause");
return 1;
}
//更改学生数据主菜单
int changeStudentMain()
{
int modeCode = 0;
char id[11] = {0};
char name[40] = {0};
newStudent *studentTmp = NULL;
if(studentNext->next != NULL)
{
printf("What keywords do you want to select data from?\n");
printf(">Cancel(Other)\n");
printf(">Student's ID(1)\n");
printf(">Student's name(2)\n");
printf("I choose to select data by:");
scanf("%1d%*c", &modeCode);
switch(modeCode)
{
case 1:
system("cls");
printf("Please enter the ID of the student you want to select:");
scanf("%10[^\n]%*c", &id);
studentTmp = selStudentById(id);
if(studentTmp != NULL)
{
printf("Students found:%-11s%-20s%-7s%-4s\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
changeStudent(studentTmp);
}
else
printf("No corresponding ID found!\n");
system("pause");
modeCode = 1;
break;
case 2:
system("cls");
printf("Please enter the name of the student you want to select:");
scanf("%[^\n]%*c", &name);
studentTmp = selStudentByName(name);
if(studentTmp != NULL)
{
printf("Students found:%-11s%-20s%-7s%-4s\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
changeStudent(studentTmp);
}
else
printf("No corresponding ID found!\n");
system("pause");
modeCode = 1;
break;
default:
modeCode = 0;
break;
}
}
else
{
printf("The current data is empty!\n");
system("pause");
}
return 1;
}
//更改学生数据
int changeStudent(newStudent *studentTmp)
{
int sexCode = 0;
if(studentNext->next != NULL)
{
printf("Please enter the id of the new student:");
scanf("%10[^\n]%*c", &studentTmp->id);
printf("Please enter the name of the new student:");
scanf("%39[^\n]%*c", &studentTmp->name);
while(1)
{
printf("Please choose the sex of the new student[Male(1)/Female(0)]:");
scanf("%1d%*c", &sexCode);
if(sexCode == 1)
{
strcpy(studentTmp->sex ,"Male");
break;
}
else if(sexCode == 0)
{
strcpy(studentTmp->sex, "Female");
break;
}
else
printf("Choose Error\n");
}
printf("Please enter the age of the new student:");
scanf("%3[^\n]%*c", &studentTmp->age);
}
else
{
printf("The current data is empty!\n");
system("pause");
}
return 1;
}
一些我想要说的点
scanf读取空格以及缓冲区对scanf的影响
最开始的时候,我希望通过:
char str_1[11] = {0};
char str_2[11] = {0};
scanf("%10s", &str_1);
scanf("%10s", &str_2);
的方式来获取字符串,但我发现上例是无法读取空格的。而且,第二个scanf函数被跳过了。
关于第一个问题,稍微了解一点CTF知识的都知道,这里肯定不能使用gets()
函数,因为他不安全。不过,我们可以使用gets_s()
函数替换他。不过因为我喜欢搞事XD,所以我倔强地想要用scanf()
函数(雾);还有一方面,虽然我没有上过C语言课,但我觉得像gets_s()
、scanf_s()
这种函数应该不会讲的吧(,所以我打算用初学者的常用函数来实现。
而第二个问题我则完全没有头绪…
后来在一位师傅和搜集来的资料的帮助下。谜题,解开了。
师傅给我了一个这样的写法:
char str_1[11] = {0};
char str_2[11] = {0};
//这个是师傅给的写法
//scanf("%[^\n]%*c", &str_1);
//scanf("%[^\n]%*c", &str_2);
//我改进了一下(
scanf("%10[^\n]%*c", &str_1);
scanf("%10[^\n]%*c", &str_2);
详细资料:https://blog.csdn.net/q_l_s/article/details/22572777
首先,第一个问题。采取%10[^\n]%*c
的写法需要分开来讲:
{%10[^\n]}
{10}:读入10个字符
{[^\n}:读入回车符前(不含回车符)的所有字符
{%*c}:忽略后面的字符
可以查看上面的详细资料,资料就不展开了
第二个问题的资料:https://blog.csdn.net/hhhhhyyyyy8/article/details/80917713
简单来说,就是前一个scanf把这次读取的回车符留在了缓冲区里,第二个scanf来读取缓冲区时便会读入这个回车导致第二个scanf被跳过。
整体架构(结构?)
由于我没有学过软件工程之类的课程,所以这里的用词可能不太准确。
|-主函数
|----|-次函数-|-功能函数
| |-功能函数
| |...
|
|-次函数-|...
...
上面的结构打的有点混乱,简单来说就是每个功能有自己独立的主函数,由这个函数来调用功能函数。比如查询学生数据,有一个进行数据输入的主函数,然后将收集的信息加载到功能函数中。
这次整体代码的架构很失败(PS. 最开始压根没有思考到架构这一码事,在慢慢码的过程中才发现架构很重要),有许多代码其实可以用函数封装重复使用。在早期还在一些功能上的函数里面加入了数据输入……下次需要注意。
后言
emmmm总之就先这么多吧……以后来温故知新
PS. 估计以后不想看见这坨屎山(确信