这是本人第一次写博客,有不足之处请见谅。
本文是利用简单的C语言编写的学生籍贯信息记录簿,写这篇是为了记录学习过程,也为后来者提供一些参考和思路。我使用的平台为Visual C++6.0。其功能主要分为录入、保存、查询、浏览、增加、修改、删除信息七大板块。通过这些板块的结合,使学生籍贯信息记录簿对学生信息的管理更高效、方便。
该平台是要求编辑一个学生籍贯信息记录簿记录每个学生的信息,包括:学号、姓名、性别、年龄、班级、籍贯。具体功能:
1.创建信息并以磁盘文件保存;
2.读取磁盘文件并显示输出所有学生的信息;
3.按照学号、姓名、班级或者其他条件查询学生籍贯等信息;
4.添加学生信息;
5.修改指定姓名或者学号的学生的信息并且可以保存;
6.删除学生信息;
7.退出系统。
#include
#include
#include
#include
#define LEN sizeof(struct Student)
在使用函数库中的输入输出函数时,编译系统要求程序提供有关此函数的信息(例如对这些输入输出函数的声明和宏定义、全局量的定义等),程序的第一行“#include
在程序中用到了系统提供的标准函数库中的输入输出函数时,要在程序开头写上一行:#include
stdlib.h是个头文件,里面定义了五种类型、一些宏和通用工具函数。具体的可以在编译器的include目录里面的stdlib.h头文件中查看。文中利用的malloc()、system()函数的声明都在stdlib.h头文件中。[2]
string.h是一个头文件,里面写的是关于字符串操作的一些基本函数。当程序中涉及对字符串的操作时,会用到这个头文件中的函数。
malloc.h是动态存储分配函数的头文件,当对内存区进行操作时,调用相关函数。
LEN代表struct Student类型数据长度,sizeof是“求字节数运算符”。
struct Student
{
char name[10];//定义姓名
char sex[4];//定义性别
long int num;//定义长整型学号
int age;//定义年龄
char classname[20];//定义班级
char nativeplace[20]; //定义籍贯
struct Student *next;
}*head,*p1,*p2,*p;
声明一个结构体类型struct Student,包括name(姓名)、sex(性别)、num(学号)、age(年龄)、classname(班级)、nativeplace(籍贯)。
在C语言中允许用户自己建立由不同类型数据组成的组合型的数据结构,这就被称为结构体。姓名、性别、班级、籍贯都为字符串;学号为长整型;年龄为整型。定义了结构体变量后,系统会自动为之分配内存单元。根据结构体类型中包括的成员情况,在Visual C++6.0中占62个字节(10+4+4+4+20+20).
struct Student *next; :next是指针变量,指向结构体变量。其成员中姓名、性别、学号、年龄、班级、籍贯用来存放节点中的有用数据,next是指针类型的成员,它指向struct Student类型数据(就是next所在的结构体类型)。一个指针类型的成员既可以指向其他类型的结构体数据,也可以指向自己所在的结构体类型数据。现在,next是struct Student类型中的一员,它又指向struct Student类型数据。用这种方式建立链表。
图二:建立链表图示
struct Student*head;
struct Student*p;
struct Student*p1;
struct Student*p2;
定义指向struct Student类型数据的指针变量head、p、p1、p2。
int Browse();//学生籍贯信息浏览函数
int Save();//信息保存函数
int Search();//信息查询函数
int Add();//增加信息函数
int Amend();//修改信息函数
int Delete();//删除信息函数
int Read();//读取信息函数
struct Student * Input();//学生籍贯信息录入函数
int menu();//菜单函数
int Choice();//菜单栏选择函数
int main();//主函数
将整个程序函数划分为十一部分,每个函数完成一个或多个功能,各司其职,通过函数划分不仅使复杂的籍贯管理系统简单化,在后期编译运行时较为容易的发现问题,同时函数模块可随时调用,使用方便。
int menu()//菜单函数,随时调用
{
printf("***************【学生籍贯信息记录簿】***************\n");
printf("* 0.退出系统 *\n");
printf("* 1.录入信息 *\n");
printf("* 2.保存信息 *\n");
printf("* 3.查询信息 *\n");
printf("* 4.浏览信息 *\n");
printf("* 5.增加信息 *\n");
printf("* 6.修改信息 *\n");
printf("* 7.删除信息 *\n");
printf("* 8.读取信息 *\n");
printf("****************************************************\n");
printf("\t\t请输入一个数<0-8>\n");
}
本部分用的是格式输出函数printf(格式控制,输出表列);运用此函数将双引号里的内容按原格式输出在屏幕上,这样一个简单的学生籍贯信息记录簿首页就完成了。
int Choice()
{
int ch=0;
scanf("%d",&ch);//判断输入的字符是什么字符
switch (ch)
{
case 0:
printf("退出成功!\n");
break;
case 1:
printf("****************【录入信息】****************\n\n");
head=Input();
system("pause");
break;
case 2:
printf("****************【保存信息】****************\n");
Save();
break;
case 3:
printf("****************【查询信息】****************\n");
Search();
break;
case 4:
printf("****************【浏览信息】****************\n\n");
Browse();
break;
case 5:
printf("****************【增加信息】****************\n\n");
Add();
break;
case 6:
printf("****************【修改信息】****************\n\n");
Amend();
break;
case 7:
printf("****************【删除信息】****************\n\n");
Delete();
break;
case 8:
printf("****************【读取信息】****************\n\n");
Read();
break;
default:
printf("选择错误,重新输入\n");
break;
}
return 0;
}
本部分使用的switch语句是多分支选择结构,根据表达式的值使流程跳转到不同的语句,使用了break语句是使流程跳出switch结构即终止switch语句的执行。根据输入的值(0-8)进行相关函数的调用,从而完成不同的功能。
struct Student * Input() //建立基础的学生信息库
{
long int i;
p1=(struct Student *)malloc(LEN);//用malloc函数开辟第一个节点。
p2=p1;
printf("输入学生学号(输入0结束):");
scanf("%ld",&i);
if(i!=0)
{
printf("请输入学生姓名 性别 学号 年龄 班级 籍贯:");
scanf("%s%s%ld%d%s%s",p1->name,p1->sex,&p1->num,&p1->age,p1->classname,p1->nativeplace);
head=NULL;
printf("信息录入成功\n\n");
while(1)
{
n=n+1;
if(n==1)
head=p1;
else
p2->next=p1;//连接第一个节点和第二个结点
p2=p1;
printf("输入学生学号(输入0结束):");
scanf("%ld",&i);
if(i==0)
{
break; //如果输入的学号为0 ,中断循环
}
else
{
p1=(struct Student *)malloc(LEN);//开辟动态存储区, 把起始地址赋给p1 强制类型转换
printf("请输入学生姓名 性别 学号 年龄 班级 籍贯:");
scanf("%s%s%ld%d%s%s",p1->name,p1->sex,&p1->num,&p1->age,p1->classname,p1->nativeplace);
printf("信息录入成功\n\n");
}
}
p2->next=NULL;//输入学号为0,链表建立完成
return head;
}
else
return 0;
}
链表的创建过程就是一个一个动态开辟节点存储单元和输入结点数据,并建立起前后链接关系的过程。
1.利用之前定义的指针变量head、p1、p2、p;
2.开辟头节点;
3.开辟成功后将头节点赋给临时变量p1
4.输入数据到节点中;
5.将p1指向下一个节点;
6.当输入的学号为0时,中断。
int Browse()//浏览信息
{
if(n!=0)
{
p=head; //p先指向开头
printf("共录入%d位学生信息:\n\n",n);
printf("姓名 性别 学号 年龄 班级 籍贯\n\n");
do
{
printf("%s %s %ld %d %s %s\n\n",p->name,p->sex,p->num,p->age,p->classname,p->nativeplace);
p=p->next;//p打印结束把p指向next以判断下一个区域有没有内容
}while(p!=NULL);//只要p指向的内存区域有数据就打印内容
}
else
printf("您还没有添加数据哦!\n");
}
该功能的基本设计思想是从头节点开始,利用一个临时指针变量p,依次输出结点数据的值,直到尾结点为止。
int Search()
{
int Byname();
int Bynum();
int Byclassname();
int Bynativeplace();
int n;
while(1)
{
printf("* 0.返回上一级 *\n");
printf("* 1.按姓名查询 *\n");
printf("* 2.按学号查询 *\n");
printf("* 3.按班级查询 *\n");
printf("* 4.按籍贯查询 *\n"); printf("**********************************************\n");
printf("\t\t请输入一个数<0-4>\n");
scanf("%d",&n);
switch(n)
{
case 0:
system("cls");
menu();
Choice();
break;
case 1:
Byname();
break;
case 2:
Bynum();
break;
case 3:
Byclassname();
break;
case 4:
Bynativeplace();
break;
default:
printf("选择错误,重新输入\n");
break;
}
system("pause");
system("cls");
}
}
//按姓名查询
int Byname()
{
int i=0;
int flag=0;
char a[20];
printf("请输入要查询的学生姓名:");
scanf("%s",&a);
p1=head;
while(p1!=NULL)
{
if(strcmp(a,p1->name)==0)
{
flag=1;
break;
}
else
p1=p1->next;
}
if(flag==1)
{
printf("姓名 性别 学号 年龄 班级 籍贯\n\n")
printf("%s %s %ld %d %s %s\n\n",p1->name,p1->sex,p1->num,p1->age,p1->classname,p1- >nativeplace);
}
else
printf("\n该班级的学生不存在!\n\n");
}
//按学号查询
int Bynum()
{
long int i;
int flag=0;
printf("请输入要查询的学生学号:");
scanf("%ld",&i);
p1=head;
while(p1!=NULL)
{
if(p1->num==i)
{
flag=1;
break;
}
else
p1=p1->next;
}
if(flag==1)
{
printf("姓名 性别 学号 年龄 班级 籍贯\n\n");
printf("%s %s %ld %d %s %s\n\n",p1->name,p1->sex,p1->num,p1->age,p1->classname,p1->nativeplace);
}
else
printf("\n该学号的学生不存在!\n\n");
}
//按班级查询
int Byclassname()
{
char b[20];
int flag=0;
printf("请输入要查询的学生班级:");
scanf("%s",&b);
p1=head;
while(p1!=NULL)
{
if(strcmp(b,p1->classname)==0)
{
printf("姓名 性别 学号 年龄 班级 籍贯\n\n")
printf("%s %s %ld %d %s %s\n\n",p1->name,p1->sex,p1->num,p1->age,p1->classname,p1->nativeplace);
flag=1;
}
p1=p1->next;
}
if(flag==0)
printf("\n该班级的学生不存在!\n\n");
}
//按籍贯查询
int Bynativeplace()
{
char c[20];
int flag=0;
printf("请输入要查询的学生籍贯:");
scanf("%s",&c);
p1=head;
while(p1!=NULL)
{
if(strcmp(c,p1->nativeplace)==0)
{
flag=1;
break;
}
else
p1=p1->next;
}
if(flag==1)
{
printf("姓名 性别 学号 年龄 班级 籍贯\n\n")
printf("%s %s %ld %d %s %s\n\n",p1->name,p1->sex,p1->num,p1->age,p1->classname,p1->nativeplace);
}
else
printf("\n该籍贯的学生不存在!\n\n");
}
信息查询功能:该功能分为四个部分,按照姓名查询、按照学号查询、按照班级查询、按照籍贯查询功能。通过switch()语句进行功能选择。
查询功能:输入学生姓名(学号、班级、籍贯)利用字符串比较函数strcmp(),如果输入的信息和文件中保存的信息相等,则将变量flag的值赋1,之后将只要flag为1的学生信息全部输出。这样可以实现相同班级或者籍贯的学生都能输出。
int Add() //添加信息函数
{
p1=(struct Student *)malloc(LEN); //开辟动态存储空间
if(n==0) //判断链表开头
head=p1; //n=0代表输入的是第一个数据
else p2->next=p1; //p2的结尾所指向的地址是p1
do
{
printf("请输入要添加的学生姓名 性别 学号 年龄 班级 籍贯:");
scanf("%s%s%ld%d%s%s",p1->name,p1->sex,&p1->num,&p1->age,p1->classname,p1->nativeplace);
p2=p1; //p2指向p1所在的地址
p2->next=NULL; //链表结束标志
n+=1;
}while(p!=NULL);
printf("添加成功!\n");
}
添加信息功能首先利用了malloc()函数开辟了动态存储空间,该函数的调用格式为(类型说明符*)malloc(size)
格式说明:
1.该函数的功能是在内存的动态存储区中分配一块长度为“size”字节的连续区域。函数的返回值为该区域的首地址,如果函数调用失败,则返回空指针(NULL)。
2.“类型说明符”表示把该区域用于何种数据类型,(类型说明符)表示把返回值强制转换为该类型的指针。
3.“size”是一个无符号函数,表示分配空间的字节长度,一般是单位长度数据类型数据所占的字节数[2]。
int Amend()
{
if(n!=0)
{
int c;
char a[20];
printf("请输入要修改的学生姓名:");
scanf("%s",&a);
p=head;
do
{
if(strcmp(a,p->name)==0)
{
printf("被修改人信息如下:\n");
printf("姓名 性别 学号 年龄 班级 籍贯\n") ;
printf("%s %s %ld %d %s %s\n\n",p->name,p->sex,p->num,p->age,p->classname,p->nativeplace);
break;
}
p=p->next; //指针指向下一个节点
}while(p!=NULL);
printf("*******************【修改信息】******************\n");
printf("* 1. 修改姓名 *\n");
printf("* 2. 修改性别 *\n");
printf("* 3. 修改学号 *\n");
printf("* 4. 修改年龄 *\n");
printf("* 5. 修改班级 *\n");
printf("* 6. 修改籍贯 *\n");
printf("* 7. 退出修改 *\n");
printf("*************************************************\n");
printf("\t\t请输入一个数<1-7>\n");
scanf("%d",&c);
switch(c)
{
case 1:
printf("姓名修改为:");
scanf("%s",&p->name);break;
case 2:
printf("性别修改为:");
scanf("%s",&p->sex);break;
case 3:
printf("学号修改为:");
scanf("%ld",&p->num);break;
case 4:
printf("年龄修改为:");
scanf("%d",&p->age);break;
case 5:
printf("班级修改为:");
scanf("%s",&p->classname);break;
case 6:
printf("籍贯修改为:");
scanf("%s",&p->nativeplace);break;
case 7:
printf("退出成功!\n");
menu();
Choice();
break;
default:
printf("选择错误,重新输入\n");
break;
}
printf("\n\n操作成功!\n\n");
}
else
printf("您还没有添加数据哟!\n");
}
该功能使用的字符串比较函数strcmp(),将输入的学生姓名同文件中的学生姓名进行比较,从而找到该学生的全部信息。并且利用了switch语句进行条件选择,分布进行信息修改。
int Delete()
{
if(n!=0)
{
char a[20];
printf("请输入要删除的学生姓名:");
scanf("%s",&a);
p=head;
if(strcmp(head->name,a)==0)
{
p1=head;
head=head->next;
free(p1);//释放删除结点
printf("数据已经被删除\n");n--;
}
else
{
do
{
if(strcmp(p->name,a)==0)
{ p1=p;
p2->next=p->next;
free(p1);break;
}
p2=p; //不满足if表示这不是要删除的那一个节点,l暂时指向p 之后p再指向下一个节点,如果这个是要删除的节点那么l指向这个节点的next的地址
p=p->next;
}while(p!=NULL);
printf("数据已经被删除\n");n--;
}
}
else
printf("没有任何学生的数据!\n");
}
此功能利用了字符串比较函数strcmp();
格式:strcmp(字符数组名1,字符数组名2)
功能:按照ASCII码顺序比较两个数组中的字符串,并由函数返回值返回比较结果。
利用strcmp()函数比较输入的姓名和文件中保存的姓名是否相同,相同则输出该学生信息并删除,不同则输出“该学生不存在”。其实该功能同查询功能有相同点。
该功能还需要进一步完善,目前只完成了删除学生个人信息,不能删除全部信息。
int Save()
{
FILE *fp;//打开文件
fp=fopen("D:\\学生籍贯信息记录簿data.txt","wb");
if(fp==NULL)
{
printf("打开文件失败!\n");
}
p=head;
while(p!=NULL)
{
if(fwrite(p,LEN,1,fp)!=1)//
{
printf("文件书写错误!\n");
fclose(fp);
break;
}
p=p->next;
}
fclose(fp);
printf("\n****************** 保存完成! ********************\n");
}
C语言中提供了fopen()函数,用于打开一个文件。
FILE *fp;
fp=fopen(“文件名”,“文件使用方式”)
int Read()
{
FILE *fp;
if((fp=fopen("D:\\学生籍贯信息记录簿data.txt","rb+"))==NULL)//打开一个二进制文件,允许读和写
{
printf("无法打开文件!");
exit(0);
}
do
{
p1=(struct Student*)malloc(LEN);
if(n==0) //判断链表开头
head=p1; //n=0代表输入的是第一个数据 else
p2->next=p1;//p2的结尾所指向的地址是p1
fread(p1,LEN,1,fp);
p2=p1;
n=n+1;
}while(p2->next!=NULL);
fclose(fp);
printf("读取完成!\n\n");
Browse();
}
此函数首先检查打开的操作是否有错,如果有错就在终端上输出上面的错误信息。exit函数的作用是关闭所有文件,终止正在调用的过程。待用户检查错误,修改后再运行。
图三:初始界面
图四:录入信息界面
图五:浏览信息界面
图六:查询功能界面
图七:添加信息界面
图八:修改信息界面
图九:读取信息界面
以上就是本人设计学生籍贯信息记录簿的全部内容,有不足之处请多指正。
[1]谭浩强 著.C程序设计(第四版)[M].北京:清华大学出版社,2010
[2]付兴宏,刘志勇,罗雨滋 主编.C语言程序设计实用教程[M].哈尔滨工程大学出版社,2016.