资源描述
福 建 工 程 学 院
实 验 报 告
专 业 计算机科学与技术
班 级 计算机1001
座 号
姓 名
日 期 2012/5/14
福建工程学院计算机与信息科学系
实验报告
2010–2011学年第一 学期 任课老师:章静
实验题目
日记管理系统的开发
实验时间
实验开始日期:2012\05\03报告提交日期:2012\05\14
实验目的、要求
一、实验题目:
设计一个简单实用个人日记管理系统.
二、实验要求
1.该实验的课内学时是4个课时.
2.程序完成后应该完成如下基本功能:
1)用自定义日记的存储结构,每篇日记至少包含日期,内容等字段;
2)使用者必须输入密码;
3)写日记与保存功能;
4)日记查阅:按日期查看,按关键字查看,按顺序查看功能(从某一篇开始)
3.在完成上述基本功能的前提下,有能力的同学可以完成如下加强功能:
1)实现日记的永久存储。
2)对保存的密码进行变换,以免泄密。
3)允许多人使用。
4)在程序的提示语言清晰明确,界面美观并且适用。
实验设计内容
(1)实验设计的数据结构
/*定义日记结点类型*/
typedef struct Diary
{
char date[15]; /*日期*/
char title[20]; /*日记标题*/
int flag; /*判断日记是否符合查阅要求,是为0,否为-1*/
struct Diary *next;
}Diary;
/*定义用户结点类型*/
typedef struct User
{
char name[20]; /*用户名*/
char password[20];/*登录密码*/
int count; /*该用户拥有的日志的个数*/
Diary *first; /*指向用户拥有的日记链表的表头*/
struct User *next;
}*Us,User;
最后的用户信息以及在该用户目录下的日志信息以二进制的形式存在文件中.
(2)总体函数模块结构图:
初始化用户、日志信息读取
密码修改
日志管理系统
用户登陆和注册
写入日记
日记查询
日记删除
用户、日记信息保存
按顺序查询
按日期查询
按照关键字查询
(3)重点函数分析
1。初始化函数:程序运行会运行此函数,讲已有的用户信息和她们的日志信息读入链表中。
Us Init()
{
FILE *fp1,*fp2;
Us L=NULL;
User *p;
Diary *s;
if ((fp1=fopen(”Userlist。txt","r+”))==NULL) return L;
while(!feof(fp1))
{
p=(User *)malloc(sizeof(User));
if(fread(p,sizeof(User),1,fp1)!=1) break; //从一个流中读取数据(接受数据的指针,单个元素的大小,元素个数,提供数据的文件指针)
p-〉first=NULL; //读取系统已有的用户信息
p—〉next=L;
L=p;
chdir(p—>name);
//把相应用户目录作为当前工作目录
if((fp2=fopen(”dairylist。txt”,”r”))==NULL) {
continue;
}
else
while(!feof(fp2))
{
s=(Diary *)malloc(sizeof(Diary)); //读取系统相应用户的相应日记信息
if(fread(s,sizeof(Diary),1,fp2)!=1) break;
s—〉next=L—〉first; //first为该用户的节点拥有的日志链表
L—>first=s;
}
fclose(fp2); //关闭存储日志信息的文件,把父目录作为当前工作目录
}
fclose(fp1);
return(L);
}
2.登录
结构流程图:
开始
输入用户名及其对应密码
N
Y
进入日志操作界面
判断输入的用户名和密码链表中是否存在
代码:
/*用户登录函数*/
void Login(Us L)
{
char temp[20];
char flag;
int i,j,count;
User *p;
Diary *s;
p=L;
system(”cls");
printf(”\n\t\t\t|^^^^^^^^^^^^^^^^^^^^^^^|\n”);
printf("\t\t\t|\t用户登入\t|\n");
printf(”\t\t\t|^^^^^^^^^^^^^^^^^^^^^^^|\n");
printf(”\n\t已有的用户名:\n");
printf("\t\t|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|\n”);
printf("\t\t|\t序号\t 用户名\t\t|\n");
count=1;
while(p!=NULL) //将已经有的用户名和对应序号打印出来
{
printf(”\t\t|\t%d\t %s\t\t|\n",count,p—〉name);
p=p-〉next;
count++;
}
printf(”\t\t|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|\n");
count-—;
printf("\n\n\t输入序号:\t\t”);
i=Input_Integer(); //这样我们在选择序号时输入字符也不会造成死循环
while(i〉count||i==—1)
{
printf(”\n\n\t输入序号错误”);
printf(”\n\t是否继续进行输入:(Y or N) ");
scanf(”%c”,&flag);
if(flag==’N’||flag==’n’)
return;
printf(”\n\n\t输入序号:\t\t”);
scanf("%d",&i);
}
j=1;
p=L;
while(j<i)
{
j++;
p=p—〉next;
}
printf("\n\t你选择的用户:\t\t%s",p—>name);
printf("\n\t输入密码:\t\t");
Password_input(temp); //输入密码
Express_chage_dark(temp); //明码转化为暗码,以跟以保存的用户密码比较
while(strcmp(p—〉password,temp)!=0)
{
printf(”\n\t输入的密码错误!!!\n”);
printf(”\n\t是否继续输入:(Y or N)\t”);
scanf(”%c”,&flag);
if (flag==’N’||flag==’n’)
return;
printf("\n\t输入密码:\t\t”);
Password_input(temp);
Express_chage_dark(temp);
}
printf(”\n\n\t\t\t登入中,请稍等。。。。.”);
system(”cls”);
User_Operate(p,L); //用户登入后,进行用户操作
}
3.用户注册:
结构流程图:
Y
N
N
Y
开始
输入要注册的用户名
检查该用户是否已经存在
输入密码(密码确认)
注册成功
两次输入密码相同
代码:
/*新用户申请函数*/
Us User_apply(Us L)
{
char temp1[20];
char temp2[20];
int i;
char flag;
User *p;
User *s;
rewind(stdin);
s=(User *)malloc(sizeof(User));
system("cls”);
printf(”\n\t\t\t|^^^^^^^^^^^^^^^^^^^^^^^|\n”);
printf(”\t\t\t|\t申请用户\t|\n");
printf("\t\t\t|^^^^^^^^^^^^^^^^^^^^^^^|\n");
printf("\n\t已有的用户名:\n”);
p=L;
while(p!=NULL)
{
printf(”\t\t\t%s\n”,p—>name);
p=p—>next; //输出系统已存在的用户名,以让用户申请新用户时,有个注意,不申请重复的用户名
}
p=L;
printf(”\n\n\t输入用户名:\t\t");
scanf(”%s",s—〉name);
rewind(stdin);
while(p!=NULL&&strcmp(p-〉name,s—〉name)!=0)
p=p-〉next; //判断有没有重复的用户名
while(p!=NULL)
{
printf(”\n\t该用户名已经存在!!!!!\n”);
printf(”\n\t是否继续进行申请用户:(Y or N) ");
scanf(”%c”,&flag);
if (flag=='N’||flag==’n')
{
free(s);
return L;
}
printf("\t输入用户名:\t");
scanf("%s”,s->name);
rewind(stdin);
p=L;
while(p!=NULL&&strcmp(p—〉name,s—>name)!=0)
p=p—>next;
}
printf(”\n\t\t\t该用户名可以使用\n");
printf(”\n\t输入密码:\t\t");
Password_input(temp1);
printf(”\n\t确认密码:\t\t");
Password_input(temp2);
while(strcmp(temp1,temp2)!=0)
{
printf(”\n\t两次输入的密码不一致!!!\n”);
printf("\n\t输入密码:\t\t”);
Password_input(temp1);
printf("\n\t确认密码:\t\t”);
Password_input(temp2);
}
strcpy(s-〉password,temp1);
s—〉first=NULL;
s—〉count=0; //申请好用户,
mkdir(s—〉name); //生成相应用户对应的文件夹,文件夹里用来存储相应用户的相应日记
Express_chage_dark(s->password); //进行密码家秘密
s-〉next=L;
L=s;
Save_user(L);
getchar();//每添加一个用户时,都要进行存储用户信息的保存
printf("\n\t\t申请中,请稍等。。.。.”);
printf(”\n\n\t\t\t申请成功!\n\n\t");
getchar();
return(L);
}
4.写日志操作:
说明:在次用户登陆后,打开文件,直接找到该用户目录下的日志表单,将写入的日志直接写到这个人的用户的文件夹中,日志具体内容并不是保存在链表中的,由于考录到日志内容可能会很长,这样可以节省空间。
函数结构流程图:
开始
输入日记内容、日记名、日记时间
打开文件 fp=fopen
讲日记内容写入到文件中
保存更新后的用户信息和日志信息链表
代码:
/*写日记*/
void Write_dairy(User *H,Us L)
{
int choice;
char temp[200]; //用于存储写入的日记
FILE *fp;
Diary *s;
int i;
printf(”\n\n\t输入日记内容:\n\n\t\t");
scanf(”%s",temp);
getchar();
rewind(stdin);
Express_chage_dark(temp); //对日记内容加密
s=(Diary *)malloc(sizeof(Diary)); //为保存日志的节点动态申请空间
printf("\n\n\t输入要保存的日记名:\t”);
scanf("%s”,s—〉title);
getchar();
rewind(stdin);
while(Search_dairy(H,s-〉title)!=1)
{
printf("\n\t该日记名已经存在,请重新输入!!!!");
printf(”\n\t重新输入要保存的日记名:\t”);
scanf("%s”,s—〉title);
getchar();
}
printf(”\n\t\t该日记名可以使用”);
printf("\n\t输入日期时间:(2012\\05\\01)\t”);
scanf("%s",s—〉date);
getchar();
rewind(stdin);
s—〉flag=0;
chdir(H-〉name); //把相应用户目录作为当前工作的目录(因为日志信息是直接放在文件中的,每次对日志内容添加、修改是都要先打开文件)
if((fp=fopen(s—>title,”w”))==NULL)
{
printf(”对不起,不能打开文件!!!”);
return;
}
i=0;
printf("\n\t保存中,请稍等。.。。。");
while(temp[i]!='\0')
{
fwrite(temp+i,1,1,fp); //将信息写入文件流中(要输出数据的地址,要读写的字节数,要读写的字节数据的个数,文件类型的指针)
i=i+1;
}
s-〉next=H->first; //头插法,新写的日志排在最前面
H-〉first=s;
H—>count++;
fclose(fp);
Save_dairy(H); //保存相应用户的日记信息
Save_user(L); //保存用户信息,因为此时用户的count已经改变了,需要保存
printf("\n\n\t保存完毕!\n\n\t”);
}
4。 查阅日记操作
函数流程图:
开始
按顺序查询
选择查询方式
按关键字查询
按日期查询
输出日记
返回
代码:
/*查阅日记*/
void Consult_dairy(User *H,int i)
{
Diary *p;
FILE *fp;
char temp[200];
int j;
int flag=0;
//先进行遍遍历,若有找到符合条件的日志则做标记
p=H-〉first;
if (i==—1) //进行顺序查询
{
printf(”\n\n\t请输入要顺序查看的日记序号:\t”);
scanf(”%d",&j);
if(j〈=H-〉count)
{
while(j〉1)
{
p=p—〉next;
j-—;
}
p—>flag=—1; //找到符合条件日记,对应结点的flag赋为-1,以便待会筛选出来
flag=1; //在此用户的日志链表中有找到过符合条件的日志
}
}
else
{
if (i==0) printf("\n\t输入要查询的日期:\t"); //进行日期查询
if (i==15) printf(”\n\t输入要查询的关键字:\t”); //进行关键字查询
scanf(”%s”,temp);
rewind(stdin);
while(p!=NULL)
{
if(strstr((p-〉date+i),temp)!=NULL) //分配的空间是连续的
{ p—〉flag=—1; //找到符合条件的结点,其flag赋予—1,以便待会筛选出来
flag=1; //在此用户的日志链表中有找到过符合条件的日志
}
p=p->next;
}
}
if(flag==0) printf(”\n\t\t对不起,找不到所需要的日记”);
else
{
p=H—〉first;
printf(”\n\t要查看的日记如下\n");
chdir(H—>name); //把相应用户的目录弄为当前工作目录(要对文件进行操作)
while(p!=NULL)
{
if(p->flag==—1) //先前找到的符合条件的日子打印出来
{
printf("\n\t——————————-----——-----———---—————\n”);
printf("\t\t日记名:%s\t\t时间%s\n”,p—>title,p->date);
p—>flag=0; //筛选输出结点的flag为—1的日记名,日期
Read_dairy(p-〉title);
}
p=p-〉next;
}
}
printf("\n\n\t\t”);
}
5。删除用户日记
函数流程图:
代码:
/*删除用户日记*/
void Delete_dairy(User *H,Us L)
{
Diary *p; //指向要删除的结点
Diary *pre; //指向要删除的结点的前驱结点
int i,j;
char flag;
printf("\n\n\t请输入要删除的日记序号:\t\t”);
scanf(”%d”,&i);
rewind(stdin);
j=i;
p=H—>first; //先找到要进行删除的结点
if(j〈=H—〉count) //先判断一下输入的药删除日志的编号是否小于该用户拥有的总日志的个数
{
while(i〉1)
{
p=p-〉next;
i——;
}
p—>flag=-1; //要删除的结点的flag标识符设为—1
p=H—〉first; //再对找到的结点进行删除操作
while(p!=NULL&&(p->flag==0))
{
pre=p;
p=p—〉next;
}
printf(”\n\t要删除的日记是:\n”);
printf("\t\t序号:%d\t 日记名:%s\t时间:%s”,j,p—〉title,p-〉date);
getchar();
printf(”\n\t是否确认要删除:(Y or N) \t”);
scanf(”%c",&flag);
rewind(stdin);
if(flag==’Y’||flag==’y')
{
if(H-〉first==p) H-〉first=p—>next; //要删除的结点为第一结点时
else pre—〉next=p-〉next; //要删除的结点不是第一结点时
}
else
return ;
chdir(H-〉name); //把相应用户的目录弄为当前工作目录
H—〉count-—; //用户的日记数减1
remove(p—〉title); //去掉相应的文件
free(p); //释放要删除的结点空间
Save_dairy(H); //保存用户日记信息,不然原有的用户日记信息还是不变
Save_user(L); //保存用户信息
printf("\n\t删除中,请稍等。。.。.");
printf(”\n\n\t删除成功!!!\n\t");getchar();
}
else{
printf(”序号太大\n”);
}
}
7.用户及其拥有的日志信息在文件中的保存
/*保存用户日记信息*/
void Save_dairy(User *H)
{
FILE *fp;
Diary *p;
chdir(H—>name); //把相应用户目录作为当前工作目录(用于文件操作)
if((fp=fopen(”dairylist.txt”,"w"))==NULL)
{
printf("输入有误:不能打开文件!\n”);
return;
}
p=H->first;
while(p!=NULL)
{
fwrite(p,sizeof(Diary),1,fp); //将信息写入文件流中(要输出数据的地址,要读写的字节数,要读写的字节数据的个数,文件类型的指针)
p=p->next;
}
fclose(fp);
}
/*保存全部用户日记信息*/
void Save_user(Us L)
{
FILE *fp;
User *p;
fp=fopen("Userlist。txt”,”w");
p=L;
while(p!=NULL)
{
fwrite(p,sizeof(User),1,fp);
p=p—〉next;
}
fclose(fp);
}
调试过程记录
1。while(feof(fp)==0)
{
fwrite(fp,”%c”,&temp[i]);
i++;
}
本系实验主要是考察队文件的运用,而我一开始对文件这一部分的编程比较陌生,在经过看书查阅各种资料后,对其的一些知识有所了解,经过实验中的反复运用加以熟练.例如通过实验代码的反复测试我发现了:
Fwrite 写入的是一个数据块,fscanf 一个一个的输入,这边只能用fscanf
实验结果记录以及与预期结果比较以及分析
1。主界面
2.用户注册界面
3。用户操登陆
4。登陆后菜单:
4。1写日志功能:
4.2查看自己日志:(按顺序查找)
4。3查看好友日志:(按日期查找)
4。4删除日志:
4。5更改密码:
总结以及心得体会
这次实验综合考察了链表和文件的操作,有一定的复杂性.在实验的训练中,一开始拿到题目没有什么思路主要是不明白日志具体要实现什么功能,然后要实现的这些功能又要用什么样的函数来构成。然后通过查阅有关资料,看人家的成平的具体结构在思想中有了大体的结构才开始一个功能一个功能的实现的编写。而日志管理系统的编写中最主要的就是文件的运用,在这里我的我们用户所写的日志并不存在用户的日志链表中,而是直接写入文件,读取的时候是通过日志的名称找到那一个日志的文件,然后打开文件直接从文件中读取并显示出来。这样么可以节省很多的空间,因为用户的日志的长度有长有短,如果日志的内容页存在日志的链表中会真用很大空间,造成浪费现象,而且用户输入的日志长度还会有所限制.考虑到这些,就采用直接将用户的日志内容存在文件中的方法了。
总之,在日志系统的编写中,不仅对链表的使用更加熟练也加强了文件这一部分的运用.同时也十分感谢老师在实验过程中给予的耐心指导。
指导老师评阅意见
指导老师:年月日
整体代码:
/*日记管理系统*/
#include〈stdio.h〉
#include<math。h>
#include<string.h〉
#include<stdlib。h〉
#define Enter 13 //回车键
/*定义日记结点类型*/
typedef struct Diary
{
char date[15]; /*日期*/
char title[20]; /*日记标题*/
int flag; /*判断日记是否符合查阅要求,是为0,否为—1*/
struct Diary *next;
}Diary;
/*定义用户结点类型*/
typedef struct User
{
char name[20]; /*用户名*/
char password[20];/*登录密码*/
int count; /*该用户拥有的日志的个数*/
Diary *first; /*指向用户拥有的日记链表的表头*/
struct User *next;
}*Us,User;
/*函数原型*/
Us Init();/*初始化函数*/
void main_menu(Us L);
void Help(); /*帮助使用函数*/
Us User_apply(Us L);/*新用户申请函数*/
void Save_user(Us L);/*保存所有用户信息*/
void Login(Us L);/*用户密码登录函数*/
int Input_Integer();/*整数控制函数*/
void Express_chage_dark(char temp[]);/*明文转化为密文*/
void Dark_chage_express(char temp[]);/*密文转化为明文*/
void User_Operate(User *H,Us L);
int Search_dairy(User *H,char temp[]);/*查找是否有同名日记操作*/
void Write_dairy(User *H,Us L);
void Save_dairy(User *H);/*保存用户日记信息*/
void Rejigger_user_password(User *H,Us L);/*修改用户密码*/
void Read_dairy(char title[]);/*读日记*/
void Password_input(char temp[]);
void Delete_dairy(User *H,Us L);
void Consult_dairy_meno(User *H);/*查阅日记菜单*/
void Consult_dairy(User *H,int i);
Us findfriend(Us L);
int main()
{
Us L;
begin();
main_menu(L);
}
/*初始化函数*/
Us Init()
{
FILE *fp1,*fp2;
Us L=NULL;
User *p;
Diary *s;
if ((fp1=fopen("Userlist。txt”,"r+”))==NULL) return L;
while(!feof(fp1))
{
p=(User *)malloc(sizeof(User));
if(fread(p,sizeof(User),1,fp1)!=1) break; //从一个流中读取数据(接受数据的指针,单个元素的大小,元素个数,提供数据的文件指针)
p—>first=NULL; //读取系统已有的用户信息
p—>next=L;
L=p;
chdir(p-〉name);
//把相应用户目录作为当前工作目录
if((fp2=fopen(”dairylist。txt”,”r”))==NULL) {
continue;
}
else
while(!feof(fp2))
{
s=(Diary *)malloc(sizeof(Diary)); //读取系统相应用户的相应日记信息
if(fread(s,sizeof(Diary),1,fp2)!=1) break;
s->next=L—〉first; //first为该用户的节点拥有的日志链表
L—>first=s;
}
fclose(fp2); //关闭存储日志信息的文件,把父目录作为当前工作目录
}
fclose(fp1);
return(L);
}
/*开始函数*/
int begin()
{
int i,j;
system(”color b");
for(i=1;i〈=1;i++)
{
printf("\n\n\n\n\n\n\n\t\t\t★★★★★★★★★★★★★★★★★\n”);
printf("\t\t\t★★\n”);
printf(”\t\t\t★ 欢迎使用日志管理系统 ★\n");
printf("\t\t\t★★\n”);
printf(”\t\t\t★ 设计者: 张 夷 ★\n”);
printf(”\t\t\t★ 3100301101 ★\n");
printf(”\t\t\t★ 日期:2012。4.28 ★\n”);
printf(”\t\t\t★★\n");
printf(”\t\t\t★★★★★★★★★★★★★★★★★\n”);
printf(”\n\t\t\t系统开始启动.\n”);
for(j=1;j〈100000000;j++)
{}
system("cls”);
printf(”\n\n\n\n\n\n\n\t\t\t★★★★★★★★★★★★★★★★★\n”);
printf(”\t\t\t★★\n”);
printf(”\t\t\t★ 欢迎使用日志管理系统 ★
展开阅读全文