学生籍贯信息记录簿学生籍贯信息记录簿
C语言程序设计上机A设计报告
题目名称:_____学生籍贯信息记录簿__________ 设计环境:_______WindowsXp________ ____ 指导教师:____ ___肖 德 成 ____________ 专业班级:_________工力0801____ ______
姓 名:_______ _____ ____ 学 号:________ _ _______
联系电话:______ _ _____ ___
电子邮件:__ ___ __ __ 设计日期: 2010年 11月 6 日...
学生籍贯信息
簿
C语言程序设计上机A设计
题目名称:_____学生籍贯信息记录簿__________ 设计环境:_______WindowsXp________ ____ 指导教师:____ ___肖 德 成 ____________ 专业
:_________工力0801____ ______
姓 名:_______ _____ ____ 学 号:________ _ _______
联系电话:______ _ _____ ___
电子邮件:__ ___ __ __ 设计日期: 2010年 11月 6 日至2010年 11 月 21 日
报告成绩:______ ____ 指导教师签名:____ _ ____
学生籍贯信息记录簿
一、 课题内容和要求
1、 设计目标:
按照软件工程的规范,以Visual C++为开发工具,设计并实现一个能模拟学生籍贯信息记录簿的系统。
2、 基本要求:
编制一个学生籍贯信息记录簿,每个学生信息包括:学号、姓名、籍贯。具体
功能:
(1)创建信息链表并以磁盘文件保存;
(2)读取磁盘文件并显示输出所有学生的籍贯信息;
(3)按学号或姓名查询其籍贯;
(4)按籍贯查询并输出该籍贯的所有学生;
(5)能添加、删除和修改学生的籍贯信息;
(6)显示输出四川籍和非四川籍学生的信息并可分别存盘。 3、 需求描述
该系统应实现以下功能:
(1)、添加功能:
使用者通过屏幕的输入将一条新的学生的相关信息存取到源数据文件(sichuan.txt)
或者(feisichuan.txt)中去。每次默认将所添加的信息存放在文件的最后一行的位置。 (2)、删除功能:
使用者通过在屏幕中输入要删除的学生的学号,完成删除该学生的所有籍贯的信息。
(3)、修改:
使用者在屏幕中输入要修改的学生的学号,再输入修改之后的信息,即可完成修改。
(4)、查询功能:
1按学号查询:
使用者通过在屏幕中输入要查询的学生的学号,即可在屏幕上显示要查询的学生的
籍贯的相关信息。
2按姓名查询:
1
使用者通过在屏幕中输入要查询的学生的姓名,即可在屏幕上显示要查询的学生的
籍贯的相关信息。
3按籍贯查询:
使用者通过在屏幕中输入要查询的学生的籍贯,即可在屏幕上显示所有该籍贯的学
生的相关信息。
(5)、显示功能:
1显示所有学生的信息:
实现将所有的学生的籍贯的信息全部输出到屏幕上的功能。
2显示四川学生的信息:
实现将所有四川的学生的籍贯的信息全部输出到屏幕上的功能。
3显示非四川学生的信息:
实现将所有非四川的学生的籍贯的信息全部输出到屏幕上的功能。
(6)、读取功能:
读取两个不同的txt文件中的学生数据到两个链表中。
(7)、融合功能:
融合两个链表到一个链表当中。
(8)、写入功能:
把链表中的信息按籍贯的不同分别写入到两个不同的文件中。
一、 需求
1、 功能模块:
(1)、添加功能模块:将所要添加的学生的籍贯信息按四川籍和非四川籍分别存入
“sichuan.txt”或者“feisichuan.txt”中。
(2)、删除功能模块:输入学生的学号,可以在文件中将相关学生的籍贯信息全部删
掉。
(3)、查询功能模块:输入学号或者姓名,显示该学号和姓名所对应的学生的籍贯信
息。或者输入籍贯,显示所有该籍贯的学生的信息。
(4)、显示功能模块: 显示全部学生的籍贯信息。包括学号、姓名、籍贯。或分别显示四川籍的学生或非四川籍的学生。
2、 数据储存:
2
用txt文件来存储学生学号、姓名、籍贯。其中,sichuan.txt和feisichuan.txt文件有两
次打开方式,第一次是以读写方式打开已存在的sichuan.txt和feisichuan.txt文件,将其
中的所有信息存储在线性链表中。然后在完成一系列的查询、删除、添加操作后,再次
打开sichuan.txt和feisichuan.txt文件,以读写方式打开,就用一个空的sichuan.txt和
feisichuan.txt文件来覆盖原来的还有学生籍贯的sichuan.txt和feisichuan.txt文件,再将改
变后的线性表里面的数据再次存储在sichuan.txt和feisichuan.txt文件里面。 一、 概要设计
1、整体流程图:
3
2、存储结构:
主要是通过建立一个线性链表,其中包含一个Head型的头指针,而Head是一个
结点类,包括两个部分(数据和指针)。
在整个程序运行的时候, Readstudent1
首先从sichuan.txt文件中,用fgets()
函数和sscanf()函数配合使用,将学生信息读取到一个线性链表中。再用Readstudent2
函数从feisichuan.txt文件中,再用fgets()函数和sscanf()函数配合使用,将学生信息
读取到另一个线性链表中。再用Add_studentlink函数将两个链表融合。
添加时,用到Insert()函数,将所要添加的学生的信息作为数据域形成一个新的结
点,然后将这个新的节点插入到所规定的位置后面即可。
删除时,用到Delete()函数,即将线性链表中该序号的结点的数据全部删掉即可。
查找时,
用到
SearchID(),Searchname(),Searchprovince ()函数,查找线性链表中该序号的结点的
全部数据。
显示时,用到Show()函数,显示线性链表中所有结点的全部数据。用Show1()显
示线性链表中四川籍学生和用Show2()显示线性链表中非四川籍学生。
存入时,用到Writestudent()函数,判断学生的籍贯,再根据四川和非四川的籍
贯,分别存盘,其中要用到sprintf()函数和fwrite()函数。
四、源程序代码
1、主程序:
#include
#include
#include
#include
4
#include
#define FILENAME1 "sichuan.txt" /*定义sichuan.txt文件*/ #define FILENAME2 "feisichuan.txt" /*定义feisichuan.txt文件*/
typedef struct student_info
{ int studentID; /*学号*/
char name[8]; /*姓名*/
char province[10]; /*籍贯*/
struct student_info * next;
}StudentLink;
void Insert(student_info **Head); /*函数声明*/
void SearchID(student_info * Head); void Searchname(student_info * Head); void Searchprovince(student_info * Head); void Update(student_info * Head); void Delete(student_info **Head); void Show(student_info * Head); void Show1(student_info * Head); void Show2(student_info * Head); void Readstudent1(student_info * * Head); void Readstudent2(student_info * * Head); void Writestudent(student_info *Head); struct student_info *Add_studentlink(student_info *Head1,student_info *Head2,student_info *Head);
int main()
{ student_info * Head=NULL; /*定义表头指针*/
student_info * Head1=NULL;
student_info * Head2=NULL;
int i=0;
Readstudent1 (&Head1); /*读sichuan.txt文件*/
Readstudent2 (&Head2); /*读feisichuan.txt文件*/
Head=Add_studentlink(Head1,Head2,Head);
do /*显示一个简易菜单*/
{ printf("\n");
printf("----------欢迎使用学生籍贯信息记录薄系统---------\n");
printf(" [1]----------添加(Insert)\n");
printf(" [2]----------按学号查询(SearchID)\n");
printf(" [3]----------按姓名查询(Searchname)\n");
printf(" [4]----------按籍贯查询(Searchprovince)\n");
printf(" [5]----------修改(Update)\n");
printf(" [6]----------删除(Delete)\n");
printf(" [7]----------显示所有学生(Show)\n");
5
printf(" [8]----------显示四川学生(Show1)\n");
printf(" [9]----------显示非四川学生(Show2)\n");
printf(" [0]----------退出(Exit)\n");
printf("-------------------------------------------------\n");
printf(" 请选择要进行的操作:");
scanf("%d",&i); /*接收用户的选择*/
switch(i) /*调用对应的函数*/
{case 1:Insert(&Head);
break;
case 2:SearchID(Head);
break;
case 3:Searchname(Head);
break;
case 4:Searchprovince(Head);
break;
case 5:Update(Head);
break;
case 6:Delete(&Head);
break;
case 7:Show(Head);
break;
case 8:Show1(Head);
break;
case 9:Show2(Head);
break;
case 0:break;
default:printf("错误选择~请重选");
break;}
}
while(i!=0);
Writestudent(Head); /*写链表到txt文件*/
return 0;
}
void Readstudent1(student_info * * Head) /*读sichuan.txt文件的函数定义*/ { int a;
char b[8], c[10];
FILE *fp = NULL; /*定义文件指针*/
char buffer[30]; /*开辟一个30长度的空间*/
if((fp=fopen("sichuan.txt","r+"))==NULL) /*以读写方式打开sichuan.txt文件*/
{ printf("error"); }
while(fgets(buffer,30,fp)!=0) /*从fp指向的文件取得一个长度为30的字符串,存入起始地址为buffer的空间*/
{ student_info * p,*q,*r;
p=q=*Head;
6
while(p!=NULL)
{ q=p;
p=p->next; } /*走链*/
r=(student_info *)malloc(sizeof(StudentLink)); /*申请空间*/
r->next=NULL; /*设置指针域*/
if(r==NULL)
{ printf("分配空间失败~");
exit(0);}
if (q==NULL) /*原链表为空表*/
*Head=r; /*新结点作为头元素*/
else
{ q->next=r; } /*在表尾插入元素*/
sscanf(buffer, "%d %s %s\n",&a,&b,&c); /*把buffer中的数据按指定的类型赋给a,b,c*/
r->studentID=a; /*接收插入a,b,c*/
memcpy(r->name,b,8);
memcpy(r->province,c,10);}
fclose(fp); /*关闭文件*/ }
void Readstudent2(student_info * * Head) /*读feisichuan.txt文件的函数定义*/ { int a;
char b[8], c[10];
FILE *fp = NULL; /*定义文件指针*/
char buffer[30]; /*开辟一个30长度的空间*/
if((fp=fopen("feisichuan.txt","r+"))==NULL) /*以读写方式打开feisichuan.txt文件*/
{printf("error"); }
while(fgets(buffer,30,fp)!=0) /*从fp指向的文件取得一个长度为30的字符串,存入起始地址为buffer的空间*/
{ student_info * p,*q,*r;
p=q=*Head;
while(p!=NULL)
{ q=p;
p=p->next; } /*走链*/
r=(student_info *)malloc(sizeof(StudentLink)); /*申请空间*/
r->next=NULL; /*设置指针域*/
if(r==NULL)
{printf("分配空间失败~");
exit(0);}
if (q==NULL) /*原链表为空表*/
*Head=r; /*新结点作为头元素*/
else
{q->next=r;} /*在表尾插入元素*/
sscanf(buffer, "%d %s %s\n",&a,&b,&c); /*把buffer中的数据按指定的类型赋给a,b,c*/
r->studentID=a; /*接收插入a,b,c*/
memcpy(r->name,b,8);
7
memcpy(r->province,c,10);
}
fclose(fp); /*关闭文件*/ }
struct student_info *Add_studentlink(student_info *Head1,student_info *Head2,student_info *Head) /*融合函数的定
义*/
{
student_info *p1,*p2;
p1=Head1;
p2=Head2;
while(p1->next!=NULL) /*指向第一个链表的链表尾*/
{p1=p1->next;}
p1->next=p2; /*把第二个链表的头文件指向第一个文件的链表尾*/
Head=Head1;
return Head;
}
void Insert(student_info * *Head) /*插入函数的定义*/ {
int in_studentID; /*说明变量*/
student_info * p,*q,*r; /*定义指针*/
printf("请输入学号:");
scanf("%d",&in_studentID);
p=q=*Head; /*查找符合条件的记录*/
while(p!=NULL)
{if(p->studentID== in_studentID) /*找到相同的编号*/
{printf("已经有相同的学号:");
return;}
else
{ q=p;
p=p->next; } /*走链*/
}
r=(student_info *)malloc(sizeof(StudentLink)); /*申请空间*/
r->next=NULL; /*设置指针域*/
if(r==NULL)
{ printf("分配空间失败~");
return;}
if (q==NULL) /*原链表为空表*/
*Head=r; /*新结点作为头元素*/
else
{q->next=r; } /*在表尾插入元素*/
r->studentID=in_studentID; /*接收插入数据*/
printf("请输入姓名:");
8
scanf(" %s",r->name);
printf("请输入籍贯:");
scanf(" %s",r->province);
}
void SearchID(student_info * Head) /*查找函数的定义*/ {
int flag=1; /*设定标记变量的初值*/
int studentID;
student_info * p;
printf("请输入要查询的学号:");
scanf("%d",&studentID);
p=Head;
while(p!=NULL && flag) /*查找符合条件的记录*/
{ if(p->studentID==studentID)
{ printf("姓名:%-10s",p->name);
printf("籍贯:%-10s",p->province);
flag=0; /*找到标记变量设为0*/
}
else
p=p->next; /*指针走到下一个结点*/
}
if(flag)
printf("没有查询到~~");
}
void Searchname(student_info * Head) /*查找函数的定义*/ { int flag=1; /*设定标记变量的初值*/
char name[8];
student_info * p;
printf("请输入要查询的姓名:");
scanf("%s",&name);
p=Head;
while(p!=NULL && flag) /*查找符合条件的记录*/
{ if(strcmp(p->name,name)==0)
{ printf("学号:%-10d",p->studentID);
printf("姓名:%-10s",p->name);
printf("籍贯:%-10s",p->province);
flag=0; /*找到标记变量设为0*/
}
else
p=p->next; /*指针走到下一个结点*/
}
if(flag)
9
printf("没有查询到~~");
}
void Searchprovince(student_info * Head) /*查找函数的定义*/ { int flag=1; /*设定标记变量的初值*/
char province[10];
student_info * p;
printf("请输入要查询的籍贯:");
scanf("%s",&province);
p=Head;
while(p!=NULL) /*查找符合条件的记录*/
{ if(strcmp(p->province,province)==0)
{ printf("学号:%-10d",p->studentID);
printf("姓名:%-10s",p->name);
printf("籍贯:%-10s\n",p->province);
flag=0; /*找到标记变量设为0*/
}
p=p->next; /*指针走到下一个结点*/
}
if(flag)
printf("没有查询到~~");
}
void Update(student_info * Head) /*修改函数的定义*/ { int flag=1; /*设定标记变量的初值*/
int studentID;
student_info * p;
printf("请输入要修改的学号:");
scanf("%d",&studentID);
p=Head;
while(p!=NULL && flag) /*查找符合条件的记录*/
{ if (p->studentID==studentID)
{printf("请输入姓名:");
scanf("%s",p->name);
printf("请输入籍贯:");
scanf("%s",p->province);
flag=0;}
else
p=p->next; /*指针走到下一个结点*/
}
if (flag)
printf("没有找到要修改的记录~~");
}
10
void Delete(student_info * * Head) /*删除函数的定义*/ { int flag=1;
int studentID;
student_info * p,*q;
printf("请输入要删除学生的学号:");
scanf("%d",&studentID);
p=q=*Head;
while(p!=NULL && flag) /*查找符合条件的记录*/
{ if (p->studentID==studentID)
{ if(p==*Head) /*删除的是表头元素*/
{ *Head=p->next;
free(p);
}
else
{ q->next=p->next; /*删除普通元素*/
free(p);}
flag=0;
}
else
{ q=p;
p=p->next; /*指针走到下一个结点*/
} /*q所指结点为p所指结点的前驱*/
}
if(flag)
printf("没有找到可以删除的数据~~");
}
void Show(student_info * Head) /*列表显示所有学生数据*/ { student_info * p;
p=Head;
while(p!=NULL)
{ printf("学号:%-10d",p->studentID);
printf("姓名:%-10s",p->name);
printf("籍贯:%-10s\n",p->province);
p=p->next;}
}
void Show1(student_info * Head) /*列表显示四川学生数据*/ { student_info * p;
p=Head;
while(p!=NULL)
{ if(strcmp(p->province,"四川")==0)
{ printf("学号:%-10d",p->studentID);
printf("姓名:%-10s",p->name);
11
printf("籍贯:%-10s\n",p->province);
}
p=p->next;
}
}
void Show2(student_info * Head) /*列表显示非四川学生数据*/
{ student_info * p;
p=Head;
while(p!=NULL)
{ if(strcmp(p->province,"四川")!=0)
{ printf("学号:%-10d",p->studentID);
printf("姓名:%-10s",p->name);
printf("籍贯:%-10s\n",p->province);
}
p=p->next;
}
}
void Writestudent(student_info *Head) /*写数据到txt文件的函数定义*/ { FILE* fp1 = fopen("sichuan.txt", "w+"); /*以读写方式打开文件sichuan.txt*/
FILE* fp2 = fopen("feisichuan.txt", "w+"); /*以读写方式打开文件feisichuan.txt*/
char new_buff1[1000]; /*开辟一个1000长度的空间*/
char new_buff2[1000]; /*开辟一个1000长度的空间*/
int i=0,j=0;
student_info * p;
p=Head;
while(p!=NULL)
{ if(strcmp(p->province,"四川")==0)
{sprintf(new_buff1+i, "%d %s %s\n",p->studentID,p->name, p->province);/*把链表中的结点数据按指定类型,存
入起始地址为new_buffer1的空间*/
i = strlen(new_buff1); /*统计字符串new_buff1中字符的个数*/
}
if(strcmp(p->province,"四川")!=0)
{sprintf(new_buff2+j, "%d %s %s\n",p->studentID,p->name, p->province);/*把链表中的结点数据按指定类型,存
入起始地址为new_buffer2的空间*/
j = strlen(new_buff2); /*统计字符串new_buff2中字符的个数*/
}
p=p->next;
}
fwrite(new_buff1,sizeof(char), strlen(new_buff1),fp1); /*把new_buff1所指向的sizeof(char)*strlen(new_buff)个字节输
出到fp1所指向的文件中*/
fwrite(new_buff2,sizeof(char), strlen(new_buff2),fp2); /*把new_buff2所指向的sizeof(char)*strlen(new_buff)个字节输
出到fp2所指向的文件中*/
12
fclose(fp1); /*关闭文件*/
fclose(fp2); /*关闭文件*/ }
四、 测试数据及其结果分析
1、欢迎菜单:
2、显示所有学生信息:
3、显示四川学生信息
13
4、显示非四川学生信息
5、添加操作:
14
6、删除操作:
15
16
7、修改操作:
17
8、按学号查询:
9、按姓名查询:
10、按籍贯查询:
18
9、操作前sichuan.txt文件中的信息:
10、操作前feisichuan.txt文件中的信息:
11、操作后sichuan.txt文件中的信息:
12、操作后feisichuan.txt文件中的信息:
六、调试过程中的问题
1、Readstudent函数:
由于要从原来的文件中读取通信录的信息,并存在线性链表中,所以,要用到fgets()
函数和sscanf()函数,但是由于student_info变量由三个字符串变量studentID, name,
province组成,所以在fgets(buffer,30,fp)后,还要用sscanf()从buffer中按照%d,%s,%s
19
的格式提取数据到a,b,c中,再用a,b,c赋值给链表中的studentID, name,province再赋值给b,c时用等号赋值会出现等号左端不是一个可变值,所以要用到memcpy()函数。 2、Add_studentlink()函数:
融合函数就是把两个文件读取后形成的链表融合到一起,就是要注意最后要反会头文件。
2、Insert()函数:
没有什么太大的问题,就是为了能顺利的把数据写入链表用了指针的指针。而没有用返回头文件的方式。
lete()函数基本没有问题。 3、Search()函数,De
4、Writestudent()函数:
就是调用sprintf()函数和fwrite()函数,将修改后的线性链表的数据全部存入到文件之中。但是,要注意要根据每个学生的籍贯不同分别存盘,所以要用strcmp()函数来判断四川学生和非四川学生。还要同时打开两个文件和定义两new_buff[1000]的空间。最后要记得关闭文件。
5、算法改进思想:
由于要用到文件操作,本文中是将所有的文件信息读入到线性链表中,然后对线性链表进行操作,这样最后只要将变化后的线性链表中的数据全部重新写入到文件中即可,从而避免了文件的修改(包括存取和删除)的复杂操作。但是,这样也是就带来了一个问题,如果文件中的数据量很大,全部读出来会使得内存的占用空间很大,而每次要修改的数据只有一条,这样就会造成很大的浪费。
七、课程设计总结
1、程序中的不足:
在程序编写的过程中,用到了fgets()等函数从txt文件中进行按行读写内容。这样,就将读写的数据保存到buffer之中。在读入线性链表中的时候再用到sscanf()函数,将一个字符串分割成一个整数和两个字符串,并逐一读入相应的变量中。其实,可以直接使用ostream流操作,只需重载“<<”,“>>”即可实现。
在写链表数据到文件之中开辟了两个new_buff[1000]的空间,这种做法在数据少的时候可以用,但是当数据超过1000时就回发生数据溢出。
20
还有就是上文中所说的,有关空间使用的问题。虽然方便了文件的操作,但是这样会带来利用空间以及效率的问题。
2、收获:
3周的学习,使得我对c和c++编程开始有了进一步的认识,以及将数据结构的知识运用到编程之中。对文件操作来说,有什么不会的函数,最好的办法就是查看MSDN或是上网查找。有什么错误的话,可以设置断点,一步步调试。一般来说,断言错误是由于溢出而产生的,而内存泄露错误是由于指针在用完之后没有释放而产生的。实在不会的,就可以向老师和同学请教。看着自己的成果,虽然做的不是很好,但是,我发现还是能够从中领会到自己所积累的对数据结构和c以及c++的认识。希望,以后还有更多的机会能够做类似的实习等活动,一来是自己开始喜欢这种方式的学习,二来是希望自己还能够有更大的进步和提高。
21
本文档为【学生籍贯信息记录簿】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。