核心是链表的增删改查,然后增加了密码登陆的部分和一点点文件,需要注意的是文件要和源码在同一目录下,否则很容易找不到文件(补充一个报错函数perror,比如fp=fopen("student.txt","r"); //只读
if(!fp){
printf("文件打开失败!\n"); 出现文件打开失败时,可以将printf改为perror,perror("....");在运行,会显示出是因为找不到文件)
代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Student
{
int num;
char name[20];
float grade;
char mima[20];
struct Student *next;
} ; //定义结构体
struct Student *phead=NULL;
int count=0; //全局变量,计算文件内数据值
int c;
void Creatphead()
{
phead=(struct Student *)malloc(sizeof(struct Student));
if(!phead){
printf("头节点创建失败\n");
return;
}
phead->next=NULL;
}
//无论老师还是学生,都要登陆账号
void denglu(struct Student *phead)
{
int a;
char agrc[20];
struct Student *p=phead->next;
printf("请输入你的账号:");
scanf("%d",&a);
while(p->num!=a){
p=p->next;
c++;
}
printf("请输入你的密码:");
scanf("%s",agrc);
if((strcmp(agrc,p->mima))) //strcmp函数,相同时会返回0
{
printf("账号或密码错误\n");
exit(1);
}
else{
printf("密码正确\a\n");
}
}
//inti部分实现读取文件内容
void inti(struct Student *phead)
{
FILE *fp=NULL;
struct Student *p=NULL;
struct Student *q=phead;
fp=fopen("student.txt","r"); //只读
if(!fp){
printf("文件打开失败!\n");
exit(0);
}
while(1){
p=(struct Student *)malloc(sizeof(struct Student));
fscanf(fp,"%d%s%f%s",&p->num,&p->name,&p->grade,&p->mima);//这里我用的是fscanf
p->next=NULL;
if(feof(fp)){ //feof用来判断文件指针是否到文件末尾,到末尾则返回1,否则返回0
break;
}
count++;
q->next=p;
q=q->next;
}
}
void add(struct Student *phead)
{
struct Student *p=NULL;
struct Student *q=phead;
while(q->next!=NULL){
q=q->next;
}
p=(struct Student *)malloc(sizeof(struct Student));
printf("请输入学号:");
scanf("%d",&p->num);
printf("请输入姓名:");
scanf("%s",p->name);
printf("请输入成绩:");
scanf("%f",&p->grade);
printf("请输入密码:");
scanf("%s",p->mima);
p->next=NULL;
q->next=p; //这里用的是尾插
}
//是整体输出,其实就是链表的遍历
void output(struct Student *phead)
{
struct Student *p=phead->next;
while(p){
printf("*******************************************\n");
printf("姓名:%s\t 学号:%d\t 成绩:%f\t 密码:%s\n",p->name,p->num,p->grade,p->mima); //\t制表符,看起来更整齐
printf("*******************************************\n");
p=p->next;
}
}
//删除部分
void delate(struct Student *phead)
{
int a;
struct Student *p,*pre;
printf("请输入要删除学生的学号:");
scanf("%d",&a) ;
p=phead->next;
while(p->num!=a){
pre=p; //删除一个后前后节点相连,用pre保存前一个结点
p=p->next; //先等于再移动,保证pre是p的前一个
}
pre->next=p->next;
free(p);
}
void amend(struct Student *phead)
{
int a;
printf("请输入要修改学生的学号:");
scanf("%d",&a) ;
struct Student *p=phead->next;
while(p->num!=a){
p=p->next;
}
printf("请输入学号:");
scanf("%d",&p->num);
printf("请输入姓名:");
scanf("%s",p->name);
printf("请输入成绩:");
scanf("%f",&p->grade);
printf("请输入密码:");
scanf("%s",p->mima);
}
//输出这里只输出一条数据
void query(struct Student *phead)
{
int a;
struct Student *p=phead->next;
printf("请输入要查找学生的学号:");
scanf("%d",&a);
while(p->num!=a){
p=p->next;
}
printf("姓名:%s\t 学号:%d\t 成绩:%f\t 密码:%s\n",p->name,p->num,p->grade,p->mima);
}
void fush(struct Student *phead)
{
FILE *fp=NULL;
struct Student *p=phead->next;
fp=fopen("student.txt","w");
while(p!=NULL){
fprintf(fp,"%d\t%s\t%f\t%s\n",p->num,p->name,p->grade,p->mima);
p=p->next;
}
printf("数据保存成功!\n");
}
//排序功能,应用于链表的冒泡排序
void asort(struct Student *phead)
{
struct Student *p,*q,*pre;
p=phead->next;
q=NULL;
if(p==NULL||p->next==NULL){
return;
}
while(p!=q){
while(p->next!=q){
if(p->grade>p->next->grade){ //这里看起来有点乱哈
float t=p->grade;
p->grade=p->next->grade;
p->next->grade=t;
int a=p->num;
p->num=p->next->num;
p->next->num=a;
pre=p;
strcpy(pre->name,p->name); //字符串的交换用的是strcpy,把后面的字符串赋
给前面的,借助中间指针pre实现交换
strcpy(p->name,p->next->name);
strcpy(p->next->name,pre->name);
strcpy(pre->mima,p->mima);
strcpy(p->mima,p->next->mima);
strcpy(p->next->mima,pre->mima);
}
p=p->next;
}
q=p;
p=phead->next;
}
}
void student(struct Student *phead)
{
system("cls"); //清屏函数
int i;
printf("\t\t\t欢迎使用学生查询系统\n"); //学生只可以查成绩和位次
denglu(phead);
query(phead);
printf("是否要查看自己的位次:请选择(1.看/2,不看)\n");
scanf("%d",&i);
switch(i) {
case 1:printf("\n%d\n",c+1);
case 2:exit(0);
}
}
void teacher(struct Student *phead)
{
system("cls");
denglu(phead);
printf("目前共有%d条数据\n",count);
int a;
printf("\t\t\t欢迎使用学生管理系统\n");
printf("\t\t\t/***********************/\n");
printf("\t\t\t|1.添加数据 2.删除信息|\n");
printf("\t\t\t|3.修改数据 4.查找数据|\n");
printf("\t\t\t|5.显示所有 6.排序 |\n");
printf("\t\t\t|7.数据存档 8.退出程序|\n");
printf("\t\t\t/***********************/\n");
while(1){
printf("\t请输入您的选择:");
scanf("%d",&a);
switch(a){
case 1:add(phead);break;
case 2:delate(phead);break;
case 3:amend(phead);break;
case 4:query(phead);break;
case 5:output(phead);break;
case 6:asort(phead);break;
case 7:fush(phead);break;
case 8:exit(0) ;
}
}
}
//人机交互面板
void creatface(struct Student *phead)
{
int a;
inti(phead);
printf("\t\t\t欢迎使用学生管理系统\n");
printf("\t\t\t请选择你是学生还是教师 : 1.(教师) 2.(学生)");
scanf("%d",&a);
switch(a){
case 1:teacher(phead);break;
case 2:student(phead);break;
}
}
int main()
{
Creatphead();
creatface(phead);
return 0;
}
顺带回顾一下文件的知识,读写文件也可以用fwrite,fread,数据块读写操作
void rewind(FILE *fp)可以将文件指针移到文件的开始位置,比如在文件末尾添加数据后调用
rewind使之回到开始的位置,再从头循环逐个显示当前文件的内容
int fseek(FILE *fp,long offset,int whence)文件指针由whence的地址移到offset的地址.fseek(fp,sizeof(struct stu)*n,0),文件指针由0后移n个数据记录的地址,也就是移到第n个数据处。