文章篇幅较长,请按照目录查阅
基本问题分解
第一个问题:如何限制用户输入长度?
struct User
{
char UserName[200];
char Password[200];
};
int ScanfTheString(char *s,int size)
{
fgets(s,size+1,stdin);
if(strlen(s)>size)
{
fflush(stdin);
memset(s,0,strlen(s));
printf("输入不合法!请重新输入!");
return ERROR;
}
fflush(stdin);
return OK;
}
每次读取的时候进行一次检测,用fgets安全函数,保证不会数组越界,并且对于这个稍大的数组读取长度,超了20,那么马上报错,而且把字符串清空,同时把缓冲器清空,提醒用户再次输入。
第二个问题:想实现一个可以限制用户输入长度的密码,并且密码是用星号掩盖的,怎么处理?代码如下:
void ScanThePassword(char *passwd,int MAX_PASSWD_LEN )
{
unsigned char c;
int i = 0;
while ((c=getch())!='\r')
{
if (i<MAX_PASSWD_LEN && isprint(c))
{
passwd[i++] = c;
putchar('*');
}
else if (i>0 && c=='\b')
{
--i;
putchar('\b');
putchar(' ');
putchar('\b');
}
}
putchar('\n');
passwd[i] = '\0';
fflush(stdin);
}
这里用到的是getch函数,这个函数的作用是在后台读取,但是不显示在控制台中,所以就看不到具体的密码,同时在输入密码的时候输出空格,当接受到退格符号的时候就打印退格,实际上密码是隐藏的,星号只是一个安全隐藏信号,同时利用循环来限制密码的输入长度。
登录和注册的完整实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <conio.h>
#include <cctype>
#define PrintLine printf("*******************************\n")
#define OK 1
#define ERROR 0
#define Status int
using namespace std;
struct User
{
char UserName[30];
char Password[30];
};
bool ScanfTheString(char *s,int size);/*用来输入一些字符串,比如用户名等(加入了字符长度限度,通用)*/
void ScanThePassword(char *passwd,int MAX_PASSWD_LEN);/*专用于密码的输入*/
void Register();/*用于用户的注册,包含goto语句*/
void Login_In();/*用于用户的登录*/
bool ScanfTheString(char *s,int size)
{
fgets(s,size+4,stdin);
if(strlen(s)>size)
{
fflush(stdin);
memset(s,0,strlen(s));
MessageBox(NULL,"输入不合法!请重新输入!","错误!",MB_OK);
return false;
}
s[strlen(s)-1]='\0';
fflush(stdin);
return true;
}
void ScanThePassword(char *passwd,int MAX_PASSWD_LEN )
{
unsigned char c;
int i = 0;
while ((c=getch())!='\r')
{
if (i<MAX_PASSWD_LEN && isprint(c))
{
passwd[i++] = c;
putchar('*');
}
else if (i>0 && c=='\b')
{
--i;
putchar('\b');
putchar(' ');
putchar('\b');
}
}
putchar('\n');
passwd[i] = '\0';
fflush(stdin);
}
void Register()
{
int cnt=1;
struct User NewUser;
char PassWordNow1[30]="";
char PassWordNow2[30]="";
memset(NewUser.UserName,0,sizeof(NewUser.UserName));
memset(NewUser.Password,0,sizeof(NewUser.Password));
char temp[30]="";
bool IsUsed=false;
FILE *fp1;
if((fp1=fopen("User.txt","a+"))==NULL)
{
MessageBox(NULL,"用户数据库连接失败,请联系开发者!","奥,我的天",MB_OK);
exit(0);
}
while(1)
{
printf("请输入您的用户名(不超过20个字符):");
if(ScanfTheString(NewUser.UserName,20))
{
while(!feof(fp1))
{
if(cnt%2==0)
{
fscanf(fp1,"%s",temp);
memset(temp,0,sizeof(temp));
cnt++;
continue;
}/*文件中,奇数行是用户名,所以我们弄个计数器来读取*/
fscanf(fp1,"%s",temp);
cnt++;
if(strcmp(temp,NewUser.UserName)==0)
{
MessageBox(NULL,"用户名已经存在!请使用其他用户名!","糟糕!",MB_OK);
IsUsed=true;
break;
}
}
if(IsUsed)
{
IsUsed=false;
continue;
}
loop:printf("请输入您的密码(不超过20个字符):");
ScanThePassword(PassWordNow1,20);
printf("请再次输入您的密码以确认(不超过20个字符):");
ScanThePassword(PassWordNow2,20);
if(strcmp(PassWordNow1,PassWordNow2)==0)
{
MessageBox(NULL,"注册成功!欢迎!","欢迎!",MB_OK);
strcpy(NewUser.Password,PassWordNow2);
/*写入文件*/
fprintf(fp1,"%s\n%s\n",NewUser.UserName,NewUser.Password);
fclose(fp1);
break;
}
else
{
goto loop;
}
}
else
{
continue;
}
}
}
void Login_In()
{
/*在用户数据库中查找用户名字,若找不到,那么提醒用户注册,或者检查账户名
如果密码正确,登入 使用别的条件
如果密码错误,提醒用户检查密码
可以设计一个变量,超过三次以上自动终止程序*/
FILE *fp1;/*打开数据库*/
int cnt=1,cnt1=0;
bool IsExisted=false;
char Username[30]="";
char temp[30]="";
char password[30]="";
while(1)
{
printf("请输入您的用户名(不超过20个字符):");
if(ScanfTheString(Username,20))
{
if((fp1=fopen("User.txt","r+"))==NULL)
{
MessageBox(NULL,"用户数据库连接失败,请联系开发者!","奥,我的天",MB_OK);
exit(0);
}
while(!feof(fp1))
{
if(cnt%2==0)
{
fscanf(fp1,"%s",temp);
memset(temp,0,sizeof(temp));
cnt++;
continue;
}
fscanf(fp1,"%s",temp);
cnt++;
if(strcmp(temp,Username)==0)
{
IsExisted=true;
break;
}
}
if(IsExisted)
{
fscanf(fp1,"%s",temp);
while(1)
{
printf("请输入您的密码(不超过20个字符):");
ScanThePassword(password,20);
if(strcmp(temp,password)==0)
{
MessageBox(NULL,"登录成功!","欢迎!",MB_OK);
}
else if(strcmp(temp,password)!=0&&cnt1<3)
{
printf("密码错误!请重新输入密码!\n");
cnt1++;
continue;
}
else if(strcmp(temp,password)!=0&&cnt1>=3)
{
printf("密码连续输入错误超过三次!请核实密码后再登录!");
exit(0);
}
fclose(fp1);
return ;
}
}
else
{
int n;
printf("用户名不存在,是否注册新用户?\n");
printf("输入1则注册新用户,输入2则重新输入用户名\n");
printf("请输入:");
scanf("%d",&n);
fflush(stdin);
if(n==1)
{
fclose(fp1);
Register();
return ;
}
else
{
fclose(fp1);
cnt=1;
continue;
}
}
}
}
}
int main()
{
MessageBox(NULL,"欢迎使用活动管理程序!","欢迎!",MB_OK);
Login_In();
return 0;
}
第三个问题:当数据规模很大,无法只用模拟cnt的办法来遍历数据时该采用什么方法?
方案①:先全部存到一行中,继续采用cnt计数的方法,到时候打印则计数打印即可。
方案②:用链表存储各个数据,同时在每一组数据中添加标志符
如:
begin1:
Lumxi
123
end1;
这样的方法来划定每一个数据点,以此来实现更加有条理的数据整理,此处要对前面的代码进行重构,主要更改的方面是要用链表存储的方式来实现数据存储,不然就达不到课设的任务要求。
方案③:认识到文件只是一个临时存储的作用,主要的操作是要在我们的自己的数据结构里面操作的(如链表和二叉树等),这样一个方案可以更有逻辑性地进行增删改查,而不是用cnt计数这样低级的思想和方法来进行。
最后敲定是方案③作为我们的主要技术方案。
第一次的代码编写
对以上代码进行重构
如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <conio.h>
#include <cctype>
#define PrintLine printf("*******************************\n")
#define OK 1
#define ERROR 0
#define Status int
using namespace std;
char UserNow[30];/*特开一个变量来记录当前用户名来获取相关权限*/
typedef struct User
{
char UserName[30];
char Password[30];
struct User *next;
}UserNode,*UserLinkList;
typedef struct Activity
{
char ActivityName[30];
char ActivityMain[500];
char ActivityTime[20];
char ActivityRequest[200];
int PeopleNum;
char ActivityCreater[20];
struct Activity *next;
}ActivityNode,*ActivityLinkList;
bool ScanfTheString(char *s,int size);/*用来输入一些字符串,比如用户名等(加入了字符长度限度,通用)*/
bool ScanThePassword(char *passwd,int MAX_PASSWD_LEN);/*专用于密码的输入*/
int CreateLinkList_User(UserLinkList &L);/*创建用户链表*/
int CreateLinkList_Activity(ActivityLinkList &L);/*创建活动链表*/
void LoadDataIntoLinkList();/*把文件中的数据读入链表*/
void LoadDataIntoDoctment();/*把链表中的数据写入文件*/
void TestIfRead();
void Register();/*用于用户的注册,包含goto语句*/
void ShowTable();/*展示菜单*/
void Login_In();/*用于用户的登录*/
void Add_Activity();/*增加活动*/
void Delete_Activity();/*删除活动*/
void ShowActivity();/*展示活动*/
/*重构代码部分,需要用到链表*/
int CreateLinkList_User(UserLinkList &L)
{
UserLinkList p,q;
L=new UserNode;
L->next=NULL;
q= new UserNode;
q=L;
FILE *fp;
if((fp=fopen("User.txt","r"))==NULL)
{
MessageBox(NULL,"数据库连接失败!,请联系管理员!","错误!",MB_OK);
exit(0);
}
while(!feof(fp))
{
p=new UserNode;
fscanf(fp,"%s",p->UserName);
fscanf(fp,"%s",p->Password);
q->next=p;
p->next=NULL;
q=p;
}
fclose(fp);
return OK;
}
int CreateLinkList_Activity(ActivityLinkList &L)
{
ActivityLinkList p,q;
L=new ActivityNode;
L->next=NULL;
q=new ActivityNode;
q=L;
FILE *fp;
if((fp=fopen("Activity.txt","r"))==NULL)
{
MessageBox(NULL,"数据库连接失败!,请联系管理员!","错误!",MB_OK);
exit(0);
}
while(!feof(fp))
{
p=new ActivityNode;
fscanf(fp,"%s",p->ActivityName);
fscanf(fp,"%s",p->ActivityMain);
fscanf(fp,"%d",&p->PeopleNum);
fscanf(fp,"%s",p->ActivityRequest);
fscanf(fp,"%s",p->ActivityCreater);
q->next=p;
p->next=NULL;
q=p;
}
fclose(fp);
return OK;
}
bool ScanfTheString(char *s,int size)
{
fgets(s,size+4,stdin);
int len=strlen(s);
if(len>size||len==1)
{
fflush(stdin);
memset(s,0,strlen(s));
MessageBox(NULL,"输入不合法!请重新输入!","错误!",MB_OK);
return false;
}
s[strlen(s)-1]='\0';
fflush(stdin);
return true;
}
bool ScanThePassword(char *passwd,int MAX_PASSWD_LEN )
{
unsigned char c;
int i = 0;
while ((c=getch())!='\r')
{
if (i<MAX_PASSWD_LEN && isprint(c))
{
passwd[i++] = c;
putchar('*');
}
else if (i>0 && c=='\b')
{
--i;
putchar('\b');
putchar(' ');
putchar('\b');
}
}
putchar('\n');
passwd[i] = '\0';
fflush(stdin);
return true;
}
void Register()
{
/*先连接数据库,读入数据到我们的链表中*/
UserLinkList T;
if(CreateLinkList_User(T))
{
UserNode NewUser;
char PassWordNow1[30]="";
char PassWordNow2[30]="";
memset(NewUser.UserName,0,sizeof(NewUser.UserName));
memset(NewUser.Password,0,sizeof(NewUser.Password));
while(1)
{
printf("请输入您的用户名(不超过20个字符):");
while(1)
{
if(ScanfTheString(NewUser.UserName,20))
{
UserLinkList p=T->next;
Lable_IS_Used:if(strcmp(NewUser.UserName,p->UserName)==0)
{
MessageBox(NULL,"用户名已经存在!请使用其他用户名!","糟糕!",MB_OK);
p=T->next;
break;
}
else if(p->next!=NULL)
{
p=p->next;
goto Lable_IS_Used;
}
else if(p->next==NULL)/*到尾了都没有检索到相应的用户名,那么就可以了*/
{
Lable_IS_CMP:printf("请输入您的密码(不超过20个字符):");
if(ScanThePassword(PassWordNow1,20))
{
Lable_IS_CMP_Again:printf("请再次输入您的密码以确认(不超过20个字符):");
if(ScanThePassword(PassWordNow2,20))
{
if(strcmp(PassWordNow1,PassWordNow2)==0)
{
MessageBox(NULL,"注册成功!欢迎!","欢迎!",MB_OK);
strcpy(NewUser.Password,PassWordNow2);
FILE *fp;
if((fp=fopen("User.txt","a+"))==NULL)
{
MessageBox(NULL,"用户数据库连接失败,请联系开发者!","奥,我的天",MB_OK);
exit(0);
}
else
{
/*写入文件*/
fprintf(fp,"%s\n%s\n",NewUser.UserName,NewUser.Password);
fclose(fp);
strcpy(UserNow,NewUser.UserName);
return ;
}
}
else
{
goto Lable_IS_CMP;
}
}
else
{
goto Lable_IS_CMP_Again;
}
}
else
{
goto Lable_IS_CMP;
}
}
}
else
{
memset(NewUser.UserName,0,sizeof(NewUser.UserName));
break;
}
}
}
}
}
void Login_In()
{
UserLinkList T;
UserNode User;
int cnt1=0;
if(CreateLinkList_User(T))
{
while(1)
{
printf("请输入您的用户名(不超过20个字符):");
if(ScanfTheString(User.UserName,20))
{
UserLinkList p=T->next;
Lable_CMP:if(strcmp(User.UserName,p->UserName)==0)
{
Lable_Password:printf("请输入您的密码(不超过20个字符):");
if(ScanThePassword(User.Password,20))
{
if(strcmp(User.Password,p->Password)==0)
{
MessageBox(NULL,"登录成功!","欢迎!",MB_OK);
strcpy(UserNow,User.UserName);
return ;
}
else if(strcmp(p->Password,User.Password)!=0&&cnt1<3)
{
printf("密码错误!请重新输入密码!\n");
cnt1++;
goto Lable_Password;
continue;
}
else if(strcmp(p->Password,User.Password)!=0&&cnt1>=3)
{
printf("密码连续输入错误超过三次!请核实密码后再登录!");
exit(0);
}
}
}
else if(strcmp(User.UserName,p->UserName)!=0 && p->next!=NULL)
{
p=p->next;
goto Lable_CMP;
}
else if(strcmp(User.UserName,p->UserName)!=0 && p->next==NULL)
{
int n;
printf("用户名不存在,是否注册新用户?\n");
printf("输入1则注册新用户,输入2则重新输入用户名\n");
printf("请输入:");
scanf("%d",&n);getchar();
if(n==1)
{
Register();
return ;
}
else
{
continue;
}
}
}
else
{
continue;
}
}
}
}
int main()
{
Login_In();
return 0;
}
---------------------------------------分割线---------------------------------(4.18)
活动的增加和删除
增加的主体代码
void Add_Activity()
{
ActivityLinkList L;
CreateLinkList_Activity(L);
ActivityNode NewActivity;
ActivityLinkList T=L->next;
FILE *fp;
while(1)
{
if((fp=fopen("Activity.txt","a+"))==NULL)
{
MessageBox(NULL,"用户数据库连接失败,请联系开发者!","奥,我的天",MB_OK);
exit(0);
}
printf("请输入您的活动名称(不超过20个字符):");
if(ScanfTheString(NewActivity.ActivityName,20))
{
/*以下是检查重名的部分*/
Lable_Is_Used:if(strcmp(T->ActivityName,NewActivity.ActivityName)==0)
{
MessageBox(NULL,"活动名已经存在!请使用其他活动名!","糟糕!",MB_OK);
T=L->next;
continue;
}
else if(T->next!=NULL)
{
T=T->next;
goto Lable_Is_Used;
}
else if(T->next==NULL)/*到尾都没有检测到 就可以了*/
{
Lable_ActivityMain:printf("请输入活动的内容介绍:(不超过200个字符):");
if(ScanfTheString(NewActivity.ActivityMain,200))
{
printf("请输入活动的人数(请输入整数):");
scanf("%d",&NewActivity.PeopleNum);getchar();
Lable_ActivityRequest:printf("请输入活动的要求(不超过50个字符):");
if(ScanfTheString(NewActivity.ActivityRequest,50))
{
Lable_Activity_Time:printf("请输入活动的时间:");
if(ScanfTheString(NewActivity.ActivityTime,20))
{
Lable_Activity_Location:printf("请输入活动的地点:(不超过20个字符)");
if(ScanfTheString(NewActivity.ActitityLocation,20))
{
strcpy(NewActivity.ActivityCreater,UserNow);
MessageBox(NULL,"活动创建成功!","成功!",MB_OK);
/*写入文件中*/
system("cls");
char temp[250];
while(!feof(fp))
{
fscanf(fp,"%s",temp);
}
fprintf(fp,"%s\n%s\n%d\n%s\n%s\n%s\n%s\n",NewActivity.ActivityName,NewActivity.ActivityMain,NewActivity.PeopleNum,NewActivity.ActivityRequest,NewActivity.ActivityTime,NewActivity.ActitityLocation,NewActivity.ActivityCreater);
fclose(fp);
return ;
}
else
{
goto Lable_Activity_Location;
}
}
else
{
goto Lable_Activity_Time;
}
}
else
{
goto Lable_ActivityRequest;
}
}
else
{
goto Lable_ActivityMain;
}
}
}
else
{
continue;
}
}
}
删除的前置代码
void ShowActivity()
{
ActivityLinkList L;
CreateLinkList_Activity(L);
ActivityLinkList p=L->next;
int cnt=1;
while(p->next!=NULL)
{
printf("%d:\n",cnt++);
printf("活动名称:%s\n活动简介:%s\n活动人数限定:%d人\n活动参加人员要求:%s\n活动举行时间:%s\n活动举办地点:%s\n活动发起人:%s\n",p->ActivityName,p->ActivityMain,p->PeopleNum,p->ActivityRequest,p->ActivityTime,p->ActitityLocation,p->ActivityCreater);
p=p->next;
}
return ;
}
int LinkDelete_L(ActivityLinkList &L,int i )
{
// 在带头结点的单链线性表L中,删除第i个元素,并用e返回其值
ActivityNode *p=L,*pre=L;
while(i--)
{
pre=p;/*record the prior*/
p=p->next;
if(p==NULL)
{
return ERROR;
}
}
pre->next=p->next;
return OK;
/*end in the target prior*/
}
删除的主体函数
void DeleteActivity()
{
ActivityLinkList L;
CreateLinkList_Activity(L);
ShowActivity();
printf("请输入想要删除的活动序号:");
int n;scanf("%d",&n);getchar();
ActivityLinkList j=L->next;
for(int i=0;i<n-1;i++)
{
if(j->next==NULL)
{
MessageBox(NULL,"输入数据不合法!","错误!",MB_OK);
}
j=j->next;
}
if(!(strcmp(j->ActivityCreater,UserNow)==0))
{
printf("你必须是该活动的创建者才能删除该活动!");
return ;
}
LinkDelete_L(L,n);
FILE *fp;
if((fp=fopen("Activity.txt","w+"))==NULL)
{
MessageBox(NULL,"数据库连接失败!,请联系管理员!","错误!",MB_OK);
exit(0);
}
ActivityLinkList p=L->next;
if(p->next==NULL)
{
printf("当前的活动列表是空的哦~快去发起活动吧");
}
/*这里要给出一个返回的菜单选项*/
while(p->next!=NULL)
{
fprintf(fp,"%s\n%s\n%d\n%s\n%s\n%s\n%s\n",p->ActivityName,p->ActivityMain,p->PeopleNum,p->ActivityRequest,p->ActivityTime,p->ActitityLocation,p->ActivityCreater);
p=p->next;
}
fclose(fp);
system("cls");
ShowActivity();
return ;
}
做个小结:这次共花费三小时完成两个功能的编写,其中百分之三十的时间用于调试代码,致命的是链表结构的不熟悉,因为是cv数据结构的链表代码,如何研究之后发现是带有头节点的,所以才有乱码出现,然后没啥好说的了,后面还有添加一些回归函数的功能就可以了,然后更改的功能实现的主体思想也和删除一样,先写入链表,在链表里面改,然后最后w+方式重新洗入文件。
------------------------------分割线--------------------4.19
活动的更改操作
前置函数
void ShowSingetActivity(ActivityLinkList &p)
{
printf("1:活动名称:%s\n2:活动内容:%s\n3:活动人数:%d\n4:活动要求:%s\n5:活动时间:%s\n6:活动地点:%s\n7:活动发起人:%s\n",p->ActivityName,p->ActivityMain,p->PeopleNum,p->ActivityRequest,p->ActivityTime,p->ActitityLocation,p->ActivityCreater);
}
void ShowSingetActivity_Modify(ActivityLinkList &p)
{
printf("1:活动名称:%s\n2:活动内容:%s\n3:活动人数:%d\n4:活动要求:%s\n5:活动时间:%s\n6:活动地点:%s\n",p->ActivityName,p->ActivityMain,p->PeopleNum,p->ActivityRequest,p->ActivityTime,p->ActitityLocation);
}
void ModifyActivity()
{
/*首先是从文件中读入数据到链表中*/
ActivityLinkList L;
CreateLinkList_Activity(L);
ActivityLinkList p=L->next;/*用于做遍历*/
ShowActivity();
Lable_Change:printf("请输入你想要更改的活动序号:\n");
int n;scanf("%d",&n);getchar();
ActivityLinkList j=L->next;
for(int i=0;i<n-1;i++)
{
if(j->next==NULL)
{
MessageBox(NULL,"输入数据不合法!","错误!",MB_OK);
return ;
}
j=j->next;
}
/*当前j已经遍历到了我们想要更改的节点处*/
if(!(strcmp(j->ActivityCreater,UserNow)==0))
{
printf("你必须是该活动的创建者才能更改该活动的内容!");
goto Lable_Change;
}
ShowSingetActivity_Modify(j);/*注意要把创建者给隐藏起来*/
bool IsCompleted=false;
/*备忘:更改了之后要建立一个联系,写一个通知功能*/
while(1)
{
if(IsCompleted)
{
break;
}
printf("请输入你想要更改的内容(输入0以结束修改):");
int n;scanf("%d",&n);getchar();
switch(n)
{
case 1:
/*更改名称*/
/*下面做一个重名检查*/
while(1)
{
printf("请输入新活动名称:(不超过20个字符)");
char temp[30]="";
if(ScanfTheString(temp,20))
{
while(p->next!=NULL)
{
if(strcmp(p->ActivityName,temp)==0)
{
MessageBox(NULL,"活动名已经存在!请使用其他活动名!","糟糕!",MB_OK);
break;
}
else
{
p=p->next;
continue;
}
}
/*当到了这里,那么就证明没有重名*/
strcpy(j->ActivityName,temp);
break;
clean;
}
else
{
continue;
}
}
break;
case 2:
/*更改活动内容*/
while(1)
{
printf("请输入想更改的活动内容(不超过200个字符):");
if(ScanfTheString(j->ActivityMain,200))
{
clean;break;
}
else
{
continue;
}
}
break;
case 3:
/*更改活动人数*/
printf("请输入想更改为的活动人数:(输入一个整数)");
scanf("%d",&j->PeopleNum);getchar();
clean;
break;
case 4:
/*更改活动要求*/
while(1)
{
printf("请输入想更改的活动要求:(不超过200个字符)");
if(ScanfTheString(j->ActivityRequest,200))
{
clean;break;
}
else
{
continue;
}
}
break;
case 5:
/*更改活动时间*/
while(1)
{
printf("请输入想更改为的时间:");
if(ScanfTheString(j->ActivityTime,20))
{
clean;break;
}
else
{
continue;
}
}
break;
case 6:
/*更改活动地点*/
while(1)
{
printf("请输入想更改为的地点(不超过20个字符)");
if(ScanfTheString(j->ActitityLocation,20))
{
clean;break;
}
else
{
continue;
}
}
break;
case 0:
printf("修改完成!\n");
ShowSingetActivity(j);
system("pause");
clean;
IsCompleted=true;
break;
default:
MessageBox(NULL,"输入不合法!","错误!",MB_OK);
break;
}
}
/*写入文件*/
FILE *fp;
if((fp=fopen("Activity.txt","w+"))==NULL)
{
MessageBox(NULL,"用户数据库连接失败,请联系开发者!","奥,我的天",MB_OK);
exit(0);
}
p=L->next;/*重置遍历指针*/
while(p->next!=NULL)
{
fprintf(fp,"%s\n%s\n%d\n%s\n%s\n%s\n%s\n",p->ActivityName,p->ActivityMain,p->PeopleNum,p->ActivityRequest,p->ActivityTime,p->ActitityLocation,p->ActivityCreater);
p=p->next;
}
fclose(fp);
return ;
}
同时对代码进行了微调,由于需要征集活动状态和人数等信息,所以加入了相关信息,然后通过了调试,计划下一步是完成用户进行选择活动的函数。
-------------------------------- 分割线---------------------------------------(4.20)
今日编写的几个功能:评论功能和活动状态更新统计功能,要注意的是fclose这个函数必须要用,否则会GG(找了两个小时)
代码如下:
评论功能:
前置链表功能
int CreateLinkList_Comment(CommentLinkList &L)
{
CommentLinkList p,q;
L=new CommentNode;
L->next=NULL;
q=new CommentNode;
q=L;
FILE *fp;
if((fp=fopen("Comment.txt","r"))==NULL)
{
MessageBox(NULL,"数据库连接失败!,请联系管理员!","错误!",MB_OK);
exit(0);
}
/*存储顺序:活动名称、评论(评论人,评论时间,评论内容)*/
while(!feof(fp))
{
p=new CommentNode;
fscanf(fp,"%s",p->ActivityName);
fscanf(fp,"%s",p->CommentUser);
fscanf(fp,"%s",p->CommentTime);
fscanf(fp,"%s",p->word);
q->next=p;
p->next=NULL;
q=p;
}
fclose(fp);
return OK;
}
获得时间前置函数
void GetTime(char *s)
{
time_t timep;
struct tm *p;
time (&timep);
p=localtime(&timep);
sprintf(s,"%d年%d月%d日%d:%d:%d",1900+p->tm_year,1+p->tm_mon,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
}
评论展示
void ShowComment()
{
CommentLinkList L,q;
CreateLinkList_Comment(L);
q=L->next;
while(q->next!=NULL)
{
printf("活动名称:%s\n",q->ActivityName);
printf("评论者:%s \n",q->CommentUser);
printf("评论时间:%s\n",q->CommentTime);
printf("评论:%s\n",q->word);
q=q->next;
}
}
评论添加
void Add_Comment()
{
ShowActivity();
printf("你想对哪个活动进行评论?请输入序号(输入0回退)");
int n;scanf("%d",&n);getchar();
if(n==0)
{
return ;
}
ActivityLinkList L,p;
CreateLinkList_Activity(L);
p=L->next;
for(int i=0;i<n-1;i++)
{
if(p->next==NULL)
{
printf("输入值不合法!请重新输入");
}
p=p->next;
}
CommentNode N;
while(1)
{
printf("请输入评论内容(不超过100个字符)");
if(ScanfTheString(N.word,100))
{
strcpy(N.ActivityName,p->ActivityName);
strcpy(N.CommentUser,UserNow);
GetTime(N.CommentTime);
/*写入文件*/
FILE *fp;
if((fp=fopen("comment.txt","a"))==NULL)
{
MessageBox(NULL,"数据库连接失败,请联系开发者","错误!",MB_OK);
}
else
{
/*存储顺序:活动名称、评论(评论人,评论时间,评论内容)*/
fprintf(fp,"%s\n",N.ActivityName);
fprintf(fp,"%s\n",N.CommentUser);
fprintf(fp,"%s\n",N.CommentTime);
fprintf(fp,"%s\n",N.word);
fclose(fp);
}
break;
}
else
{
continue;
}
}
return ;
}
明日计划,对删除进行优化删除活动同时也把对应的评论也删除,同时写出查找的功能
计划变动:由于今天课表太慢了,而且明天要提交第一次的代码,所以今天对各个功能进行联合调试,写出主菜单供老师检查。
4.24日更新
活动的查询
本次更新主要是对活动的查询进行了编码学到了几个分割字符串功能函数
首先说一下查询功能的基本思想:首先读入一个含有加号的字符串,对字符串进行分割,并且把分割出来的子串分别读入的二维数组中,然后遍历链表,用字符串匹配函数对活动名字符串和得到的分割子串组进行匹配,匹配到一次就让cnt++,直到当cnt等于被分割出来的总数的时候就证明是匹配成功了。
这里要做一个特判,假如没有加号的时候,那么要做一个直接的判断,假如直接cmp成功了,那么就直接show当前的活动名。即可
代码如下:
void Search(ActivityLinkList L)
{
ActivityLinkList p;
p=L->next;
bool IsFind=false;
/*读取数据到链表中*/
/*实现单词组合查询活动名,例如输入“自助+山”查询,可以查到如下活动*/
Label_Cin:
printf("查询方式为关键字查询,请输入如自助+山+五+华农的搜索格式,每一个关键词应有一个加号分割,若只有一个关键词,则不需加号!\n");
printf("请输入(输入0回退):");
/*切割字符串strtok*/
int j=0;
char MainString[60];
char SubString[60][60];
char *Token;
if(ScanfTheString(MainString,50))
{
if(MainString[0]=='0')
{
return ;
}
Token=strtok(MainString,"+");
while(Token!=NULL)
{
strcpy(SubString[j++],Token);
Token=strtok(NULL, "+");
}
while(p->next!=NULL)
{
int cnt=0;
if(strcmp(p->ActivityName,MainString)==0)
{
ShowSingetActivity(p);
IsFind=true;
p=p->next;
continue;
}
/*定下一个活动名称*/
for(int i=0; i<j; i++)
{
if(strstr(p->ActivityName,SubString[i])!=NULL)
{
cnt++;
}
}
if(cnt==j)/*全部匹配*/
{
IsFind=true;
ShowSingetActivity(p);
cnt=0;
}
p=p->next;
}
if(!IsFind)
{
printf("没有找到任何活动哦,是否重新输入关键词?");
printf("【1】重新输入\n【0】回退");
int n;
scanf("%d",&n);
getchar();
if(n==1)
{
goto Label_Cin;
}
else
{
return ;
}
}
}
else
{
goto Label_Cin;
}
}
至此,课设的基本功能已经全部完成,之后的课设优化计划是继续分析课设的内核要求,看有没有需要增加的信息,把信息全部增加完成之后,定下各个结构体的内容,如何写出链表的增加和插入的函数,把每一个函数中的增删查看的操作全部变成链表中操作,然后封装好文件保存的函数,优化各个函数的代码即可。
关于界面的问题暂时还没有想法。
下面是对代码进行重构的前置操作,首先需要引入几个链表操作的函数并且进行改写
int LinkInsert_L_User();
int LinkInsert_L_Activity();
int LinkInsert_L_Comment();
int LinkDelete_L_Activity();
int LinkDelete_L_Comment();
基本模板如下:
int LinkInsert_L(LinkList &L,int i,ElemType e){
LNode *p=L,*newnode;
int j,k,m,n;
newnode=(LNode *)malloc(sizeof(LNode));
newnode->data=e;
for(j=1;j<=i-1;j++) p=p->next;
newnode->next=p->next;
p->next=newnode;
return OK;
}
第一次代码重构
步骤:创建新节点,在外面把数据读好,然后把一个节点传进去,然后慢慢赋值数据,做遍历,然后最后一个赋值,链接上链表即可.
首先我们先讲解一下重构的思路是什么,主要是要实现程序内操作全部用链表操作,在程序结束或者待操作全部完成后再进行保存文件。那么也就意味着,我们要用大量的引用,在主函数就把链表创建好
注册登录部分的代码重构
登录部分
void Login_In(UserLinkList T)
{
UserNode User;
int cnt1=0;
while(1)
{
printf("请输入您的用户名(不超过20个字符):");
if(ScanfTheString(User.UserName,20))
{
UserLinkList p=T->next;
Lable_CMP:
if(strcmp(User.UserName,p->UserName)==0)
{
Lable_Password:
printf("请输入您的密码(不超过20个字符):");
if(ScanThePassword(User.Password,20))
{
if(strcmp(User.Password,p->Password)==0)
{
MessageBox(NULL,"登录成功!","欢迎!",MB_OK);
clean;
strcpy(UserNow,User.UserName);
return ;
}
else if(strcmp(p->Password,User.Password)!=0&&cnt1<3)
{
printf("密码错误!请重新输入密码!\n");
cnt1++;
goto Lable_Password;
continue;
}
else if(strcmp(p->Password,User.Password)!=0&&cnt1>=3)
{
printf("密码连续输入错误超过三次!请核实密码后再登录!");
exit(0);
}
}
}
else if(strcmp(User.UserName,p->UserName)!=0 && p->next!=NULL)
{
p=p->next;
goto Lable_CMP;
}
else if(strcmp(User.UserName,p->UserName)!=0 && p->next==NULL)
{
int n;
printf("用户名不存在,是否注册新用户?\n");
printf("输入1则注册新用户,输入2则重新输入用户名\n");
printf("请输入:");
scanf("%d",&n);
getchar();
clean;
if(n==1)
{
Register(T);
return ;
}
else
{
continue;
}
}
}
else
{
continue;
}
}
}
注册部分
void Register(UserLinkList &T)
{
/*先连接数据库,读入数据到我们的链表中*/
UserNode NewUser;
char PassWordNow1[30]="";
char PassWordNow2[30]="";
memset(NewUser.UserName,0,sizeof(NewUser.UserName));
memset(NewUser.Password,0,sizeof(NewUser.Password));
while(1)
{
printf("请输入您的用户名(不超过20个字符):");
while(1)
{
if(ScanfTheString(NewUser.UserName,20))
{
UserLinkList p=T->next;
Lable_IS_Used:
if(strcmp(NewUser.UserName,p->UserName)==0)
{
MessageBox(NULL,"用户名已经存在!请使用其他用户名!","糟糕!",MB_OK);
p=T->next;
break;
}
else if(p->next!=NULL)
{
p=p->next;
goto Lable_IS_Used;
}
else if(p->next==NULL)/*到尾了都没有检索到相应的用户名,那么就可以了*/
{
Lable_IS_CMP:
printf("请输入您的密码(不超过20个字符):");
if(ScanThePassword(PassWordNow1,20))
{
Lable_IS_CMP_Again:
printf("请再次输入您的密码以确认(不超过20个字符):");
if(ScanThePassword(PassWordNow2,20))
{
if(strcmp(PassWordNow1,PassWordNow2)==0)
{
MessageBox(NULL,"注册成功!欢迎!","欢迎!",MB_OK);
clean;
strcpy(NewUser.Password,PassWordNow2);
FILE *fp;
if((fp=fopen("User.txt","a+"))==NULL)
{
MessageBox(NULL,"用户数据库连接失败,请联系开发者!","奥,我的天",MB_OK);
exit(0);
}
else
{
/*写入文件*/
LinkInsert_L_User(T,NewUser);
SaveDocument_User(NewUser);
strcpy(UserNow,NewUser.UserName);
return ;
}
}
else
{
goto Lable_IS_CMP;
}
}
else
{
goto Lable_IS_CMP_Again;
}
}
else
{
goto Lable_IS_CMP;
}
}
}
else
{
memset(NewUser.UserName,0,sizeof(NewUser.UserName));
break;
}
}
}
}
那么通过一天的测试和代码重构,最终把昨晚上因为内存泄露产生的问题给解决了,主要是结构体传值时产生的问题,那么在这里对于活动增加的以及几个前置函数进行展示,计划在两天内对代码进行完全重构,以及封装一个保存文件的函数。
活动增加部分的代码
链表的插入(注意被插入节点的位置判定)
int LinkInsert_L_Activity(ActivityLinkList &L,ActivityNode *NewNode)
{
ActivityNode *p=L,*newnode;
newnode=(ActivityNode *)malloc(sizeof(ActivityNode));
/*读入元素*/
strcpy(newnode->ActitityLocation,NewNode->ActitityLocation);
strcpy(newnode->ActivityCreater,NewNode->ActivityCreater);
strcpy(newnode->ActivityMain,NewNode->ActivityMain);
strcpy(newnode->ActivityName,NewNode->ActivityName);
strcpy(newnode->ActivityRequest,NewNode->ActivityRequest);
strcpy(newnode->ActivityTime,NewNode->ActivityTime);
newnode->IsStoped=NewNode->IsStoped;
newnode->Paticipater=NewNode->Paticipater;
newnode->PeopleNum=NewNode->PeopleNum;
for(int i=0;i<NewNode->Paticipater;i++)
{
strcpy(newnode->Joiner[i],NewNode->Joiner[i]);
}
while(p->next->next!=NULL)
{
p=p->next;
}/*遍历到尾部*/
newnode->next=p->next;
p->next=newnode;
return OK;
}
活动文件的保存
void SaveDocumen_Activity(ActivityLinkList L)/*与读入是捆绑的*/
{
FILE *fp;
if((fp=fopen("Activity.txt","w"))==NULL)
{
MessageBox(NULL,"数据库连接失败!,请联系管理员!","错误!",MB_OK);
exit(0);
}
ActivityLinkList p=L->next;
while(p->next!=NULL)
{
fprintf(fp,"%s\n",p->ActivityName);
fprintf(fp,"%s\n",p->ActivityMain);
fprintf(fp,"%d\n",p->PeopleNum);
fprintf(fp,"%s\n",p->ActivityRequest);
fprintf(fp,"%s\n",p->ActivityTime);
fprintf(fp,"%s\n",p->ActitityLocation);
fprintf(fp,"%s\n",p->ActivityCreater);
fprintf(fp,"%d\n",p->IsStoped);
fprintf(fp,"%d\n",p->Paticipater);
for(int i=0; i<p->Paticipater; i++)
{
fprintf(fp,"%s\n",p->Joiner[i]);
}
p=p->next;
}
fclose(fp);
}
活动增加部分改动(要注意新增节点的内存分配,否则在参数传递中会出问题)
void Add_Activity(ActivityLinkList &L)
{
ActivityNode *NewActivity=new ActivityNode;
ActivityLinkList T=L->next;
FILE *fp;
while(1)
{
if((fp=fopen("Activity.txt","a+"))==NULL)
{
MessageBox(NULL,"用户数据库连接失败,请联系开发者!","奥,我的天",MB_OK);
exit(0);
}
printf("请输入您的活动名称(不超过20个字符):");
if(ScanfTheString(NewActivity->ActivityName,20))
{
/*以下是检查重名的部分*/
Lable_Is_Used:if(strcmp(T->ActivityName,NewActivity->ActivityName)==0)
{
MessageBox(NULL,"活动名已经存在!请使用其他活动名!","糟糕!",MB_OK);
T=L->next;
continue;
}
else if(T->next!=NULL)
{
T=T->next;
goto Lable_Is_Used;
}
else if(T->next==NULL)/*到尾都没有检测到 就可以了*/
{
Lable_ActivityMain:printf("请输入活动的内容介绍:(不超过200个字符):");
if(ScanfTheString(NewActivity->ActivityMain,200))
{
printf("请输入活动的人数(请输入整数):");
scanf("%d",&NewActivity->PeopleNum);getchar();
Lable_ActivityRequest:printf("请输入活动的要求(不超过50个字符):");
if(ScanfTheString(NewActivity->ActivityRequest,50))
{
Lable_Activity_Time:printf("请输入活动的时间:");
if(ScanfTheString(NewActivity->ActivityTime,20))
{
Lable_Activity_Location:printf("请输入活动的地点:(不超过20个字符)");
if(ScanfTheString(NewActivity->ActitityLocation,20))
{
strcpy(NewActivity->ActivityCreater,UserNow);
MessageBox(NULL,"活动创建成功!","成功!",MB_OK);
NewActivity->Paticipater=0,NewActivity->IsStoped=false;
LinkInsert_L_Activity(L,NewActivity);
/*写入文件中*/
clean;
SaveDocumen_Activity(L);
free(NewActivity);
return ;
}
else
{
goto Lable_Activity_Location;
}
}
else
{
goto Lable_Activity_Time;
}
}
else
{
goto Lable_ActivityRequest;
}
}
else
{
goto Lable_ActivityMain;
}
}
}
else
{
continue;
}
}
}
活动的删除部分重构
链表删除部分
int LinkDelete_L_Activity(ActivityLinkList &L,int n )
{
// 在带头结点的单链线性表L中,删除第n个元素
ActivityNode *p=L,*pre=L;
while(n--)
{
pre=p;/*record the prior*/
p=p->next;
if(p==NULL)
{
return ERROR;
}
}
pre->next=p->next;
return OK;
/*end in the target prior*/
}
删除部分的改动
void DeleteActivity(ActivityLinkList &L)
{
Lable_Delete:
ShowActivity(L);
printf("请输入想要删除的活动序号:");
int n;
scanf("%d",&n);
getchar();
if(n==0)
{
return ;
}
ActivityLinkList j=L->next;
for(int i=0; i<n-1; i++)
{
j=j->next;
if(j->next==NULL)
{
MessageBox(NULL,"输入数据不合法!","错误!",MB_OK);
goto Lable_Delete;
}
}
if(!(strcmp(j->ActivityCreater,UserNow)==0))
{
printf("你必须是该活动的创建者才能删除该活动!");
return ;
}
LinkDelete_L_Activity(L,n);
ActivityLinkList p=L->next;
if(p->next==NULL)
{
printf("当前的活动列表是空的哦~快去发起活动吧\n");
}
/*这里要给出一个返回的菜单选项*/
ShowActivity(L);
SaveDocumen_Activity(L);
return ;
}
展示活动部分的改动
void DeleteActivity(ActivityLinkList &L)
{
Lable_Delete:
ShowActivity(L);
printf("请输入想要删除的活动序号:");
int n;
scanf("%d",&n);
getchar();
if(n==0)
{
return ;
}
ActivityLinkList j=L->next;
for(int i=0; i<n-1; i++)
{
j=j->next;
if(j->next==NULL)
{
MessageBox(NULL,"输入数据不合法!","错误!",MB_OK);
goto Lable_Delete;
}
}
if(!(strcmp(j->ActivityCreater,UserNow)==0))
{
printf("你必须是该活动的创建者才能删除该活动!");
return ;
}
LinkDelete_L_Activity(L,n);
ActivityLinkList p=L->next;
if(p->next==NULL)
{
printf("当前的活动列表是空的哦~快去发起活动吧\n");
}
/*这里要给出一个返回的菜单选项*/
ShowActivity(L);
SaveDocumen_Activity(L);
return ;
}
单个活动
void ShowSingetActivity(ActivityLinkList &p)
{
printf("1:活动名称:%s\n2:活动内容:%s\n3:活动人数:%d\n4:活动要求:%s\n5:活动时间:%s\n6:活动地点:%s\n",p->ActivityName,p->ActivityMain,p->PeopleNum,p->ActivityRequest,p->ActivityTime,p->ActitityLocation);
if(p->IsStoped)
{
printf("7:活动状态:已停止征集\n");
printf("8:活动报名人数:%d\n",p->Paticipater);
printf("9.参与者名单:\n");
for(int i=0; i<p->Paticipater; i++)
{
printf("%s\n",p->Joiner[i]);
}
}
else
{
printf("7:活动状态:正在征集中\n");
}
printf("活动发起人:%s\n",p->ActivityCreater);
}
活动的更改的改动部分
void ModifyActivity(ActivityLinkList &L)/*有bug*/
{
ShowActivity(L);
Lable_Change:
printf("请输入你想要更改的活动序号:(输入0回退):\n");
int n;
scanf("%d",&n);
getchar();
if(n==0)
{
return ;
}
/*首先是从文件中读入数据到链表中*/
ActivityLinkList p=L->next;/*用于做遍历*/
ActivityLinkList j=L->next;
for(int i=0; i<n-1; i++)
{
j=j->next;
if(j->next==NULL)
{
MessageBox(NULL,"输入数据不合法!","错误!",MB_OK);
goto Lable_Change;
}
}
/*当前j已经遍历到了我们想要更改的节点处*/
if(((strcmp(j->ActivityCreater,UserNow))!=0))
{
printf("你必须是该活动的创建者才能更改该活动的内容!");
goto Lable_Change;
}
ShowSingetActivity_Modify(j);/*注意要把创建者给隐藏起来*/
bool IsCompleted=false;
/*备忘:更改了之后要建立一个联系,写一个通知功能*/
while(1)
{
if(IsCompleted)
{
break;
}
printf("请输入你想要更改的内容(输入0以结束修改):");
int n;
scanf("%d",&n);
getchar();
switch(n)
{
case 1:
/*更改名称*/
/*下面做一个重名检查*/
while(1)
{
printf("请输入新活动名称:(不超过20个字符)");
char temp[60]="";
if(ScanfTheString(temp,50))
{
while(p->next!=NULL)
{
if(strcmp(p->ActivityName,temp)==0)
{
MessageBox(NULL,"活动名已经存在!请使用其他活动名!","糟糕!",MB_OK);
break;
}
else
{
p=p->next;
continue;
}
}
/*当到了这里,那么就证明没有重名*/
strcpy(j->ActivityName,temp);
break;
}
else
{
continue;
}
}
break;
case 2:
/*更改活动内容*/
while(1)
{
ShowSingetActivity(j);
printf("请输入想更改的活动内容(不超过200个字符):");
if(ScanfTheString(j->ActivityMain,200))
{
break;
}
else
{
continue;
}
}
break;
case 3:
/*更改活动人数*/
printf("请输入想更改为的活动人数:(输入一个整数)");
scanf("%d",&j->PeopleNum);
getchar();
break;
case 4:
/*更改活动要求*/
while(1)
{
printf("请输入想更改的活动要求:(不超过200个字符)");
if(ScanfTheString(j->ActivityRequest,200))
{
clean;
break;
}
else
{
continue;
}
}
break;
case 5:
/*更改活动时间*/
while(1)
{
printf("请输入想更改为的时间:");
if(ScanfTheString(j->ActivityTime,20))
{
break;
}
else
{
continue;
}
}
break;
case 6:
/*更改活动地点*/
while(1)
{
printf("请输入想更改为的地点(不超过20个字符)");
if(ScanfTheString(j->ActitityLocation,20))
{
break;
}
else
{
continue;
}
}
break;
case 7:
/*更改活动状态*/
while(1)
{
printf("输入0表示继续征集,输入1表示停止征集");
int n;
scanf("%d",&n);
getchar();
if(n!=0 && n!=1)
{
printf("输入不合法!,请重新输入!");
clean;
}
else
{
j->IsStoped=n;
break;
}
}
break;
case 0:
printf("修改完成!\n");
ShowSingetActivity(j);
IsCompleted=true;
break;
default:
MessageBox(NULL,"输入不合法!","错误!",MB_OK);
break;
}
}
/*写入文件*/
SaveDocumen_Activity(L);
return ;
}
报名代码的改动部分
void ChoseAndParticipate(ActivityLinkList &L)
{
ShowActivity(L);
Lable_Chose:
ActivityLinkList j=L->next;
if(j->next==NULL)
{
printf("当前活动列表是空的,快去发起活动吧!");
}
printf("请选择你想要参加的活动(输入0回退)");
int n;
scanf("%d",&n);
getchar();
if(n==0)
{
return ;
}
for(int i=0; i<n-1; i++)
{
if(j->next==NULL)
{
printf("输入值不合法,请重新输入!");
goto Lable_Chose;
}
j=j->next;
}
if(j->IsStoped)
{
printf("该活动已停止征集,请选择其他活动吧!");
goto Lable_Chose;
}
else
{
/*这里做一个查重,已经参加了活动就不参加了*/
for(int i=0; i<j->Paticipater; i++)
{
if(strcmp(UserNow,j->Joiner[i])==0)
{
printf("您已经报名了该活动!不能再报名了!请选择其他活动");
goto Lable_Chose;
}
}
strcpy(j->Joiner[j->Paticipater],UserNow);
j->Paticipater++;
printf("报名成功!\n");
system("pause");
clean;
SaveDocumen_Activity(L);
return ;
}
}
至此,绝大部分的代码重构已经完成,明天计划对评论的进行改动。
4.26
对评论部分进行了改动。
评论操作的改动
评论的前置函数
int LinkInsert_L_Comment(CommentLinkList &L,CommentNode *NewNode)
{
CommentNode *p=L,*newnode;
newnode=(CommentNode *)malloc(sizeof(CommentNode));
/*读入元素*/
strcpy(newnode->ActivityName,NewNode->ActivityName);
strcpy(newnode->CommentTime,NewNode->CommentTime);
strcpy(newnode->CommentUser,NewNode->CommentUser);
strcpy(newnode->word,NewNode->word);
while(p->next->next!=NULL)
{
p=p->next;
}/*遍历到尾部*/
newnode->next=p->next;
p->next=newnode;
return OK;
}
评论增加的主体部分
void Add_Comment(ActivityLinkList L,CommentLinkList &T)
{
ShowActivity(L);
printf("你想对哪个活动进行评论?请输入序号(输入0回退)");
int n;
scanf("%d",&n);
getchar();
if(n==0)
{
return ;
}
ActivityLinkList p;
p=L->next;
for(int i=0; i<n-1; i++)
{
if(p->next==NULL)
{
printf("输入值不合法!请重新输入");
}
p=p->next;
}
CommentNode *N=new CommentNode;
while(1)
{
printf("请输入评论内容(不超过100个字符)");
if(ScanfTheString(N->word,100))
{
GetTime(N->CommentTime);
strcpy(N->ActivityName,p->ActivityName);
strcpy(N->CommentUser,UserNow);
LinkInsert_L_Comment(T,N);
/*写入文件*/
SaveDocment_Comment(T);
free(N);
break;
}
else
{
continue;
}
}
return ;
}
展示评论部分
void ShowComment_All(CommentLinkList L)
{
CommentLinkList q=L->next;
if(q->next==NULL)
{
printf("当前评论区是空的哦,快去评论你心仪的活动吧!\n");
system("pause");
clean;
return ;
}
while(q->next!=NULL)
{
printf("活动名称:%s\n",q->ActivityName);
printf("评论者:%s \n",q->CommentUser);
printf("评论时间:%s\n",q->CommentTime);
printf("评论:%s\n",q->word);
q=q->next;
}
system("pause");
clean;
}
菜单展示
void ShowTable()
{
printf("\t-------------------------------------------------\n");
printf("\t\t+ 活动管理程序 +\n");
printf("\t-------------------------------------------------\n");
printf("\t\t ***************\n");
printf("\t\t 1、增加活动\n");
printf("\t\t 2、浏览活动\n");
printf("\t\t 3、修改活动信息\n");
printf("\t\t 4、删除活动信息\n");
printf("\t\t 5、查看评论\n");
printf("\t\t 6、发表评论\n");
printf("\t\t 7、选择并报名活动\n");
printf("\t\t 8、关键字查询活动\n");
printf("\t\t 0、退出系统\n");
printf("\t\t ***************\n");
}
至此代码重构已经全部完成,比预期来得要快和顺利,接下来是开发投票功能和进行界面的优化。
4.27
好了那么今天被算法题折磨了一天之后还想起来有课设还没打完,这样的生活真是太棒了呢^^
(简单吐槽一下,咳咳)
那么这里稍微梳理一下投票功能的开发思路,主要思路也是借鉴的是开发的评论的思路,也是先创建一个链表,然后把东西传进去,同时把Activityname做一个绑定,这样就建立起来了一个联系。
然后在考虑数据结构的时候,采用的仍然是链表的方式来存储,但是一个节点呢,是一个活动->活动对应选项->的各个不同的选项
这里给出数据结构比较直观理解了。
投票功能的开发
struct SingleVote
{
char choice[50];
int num;
};
typedef struct Vote/*活动的一个投票节点*/
{
char ActivityName[50];/*投票对应的活动名称*/
char VoteName[50];/*投票对应的项目,比如这个节点是专门对应地点的、或者时间的*/
int cnt;/*记数的,投票选项的个数*/
struct SingleVote SV[20];/*投票选项*/
struct Vote *next;
}VoteNode,*VoteLinkList;
那么投票的话需要呈递的信息有两个,一个是给活动发起人设定投票,一个是给活动参加者参与投票.
给活动创建者呈递信息
bool ShowActivity_I_Create(ActivityLinkList L)
{
bool IsFind=false;
ActivityLinkList p=L->next;
if(p->next==NULL)
{
printf("当前的活动列表是空的哦~快去发起活动吧\n");
return false;
}
while(p->next!=NULL)
{
if(strcmp(UserNow,p->ActivityCreater)==0)
{
IsFind=true;
ShowSingetActivity(p);
}
p=p->next;
}
if(!IsFind)
{
printf("您未创建任何活动!");
return false;
}
return true;
}
给活动参与者呈递信息.
bool ShowActivity_I_Participate(ActivityLinkList L)
{
bool IsFind=false;
ActivityLinkList p=L->next;
if(p->next==NULL)
{
printf("当前的活动列表是空的哦~快去发起活动吧\n");
return false;
}
while(p->next!=NULL)
{
for(int i=0;i<p->Paticipater;i++)
{
if(strcmp(UserNow,p->Joiner[i])==0)
{
ShowSingetActivity(p);
}
}
}
if(!IsFind)
{
printf("您未参加任何活动!");
return false;
}
return true;
}
保存投票信息文件
void SaveDocument_Vote(VoteLinkList &L)
{
FILE *fp;
if((fp=fopen("Vote.txt","w"))==NULL)
{
MessageBox(NULL,"数据库连接失败!,请联系管理员!","错误!",MB_OK);
exit(0);
}
VoteLinkList p=L->next;
while(p->next!=NULL)
{
fprintf(fp,"%s\n",p->ActivityName);
fprintf(fp,"%s\n",p->VoteName);
fprintf(fp,"%d\n",p->cnt);
for(int i=0;i<p->cnt;i++)
{
fprintf(fp,"%s\n%d\n",p->SV[i].choice,p->SV[i].num);
}
p=p->next;
}
fclose(fp);
}
创建投票链表
int CreateLinkList_Vote(VoteLinkList &L)
{
VoteLinkList p,q;
L=new VoteNode;
L->next=NULL;
q=new VoteNode;
q=L;
FILE *fp;
if((fp=fopen("Vote.txt","r"))==NULL)
{
MessageBox(NULL,"数据库连接失败!,请联系管理员!","错误!",MB_OK);
exit(0);
}
/*存储顺序:活动名称、投票决策内容、投票选项个数、具体投票选项*/
while(!feof(fp))
{
p=new VoteNode;
fscanf(fp,"%s",p->ActivityName);
fscanf(fp,"%s",p->VoteName);
fscanf(fp,"%d",&p->cnt);
for(int i=0;i<p->cnt;i++)
{
fscanf(fp,"%s%d",p->SV[i].choice,&p->SV[i].num);
}
q->next=p;
p->next=NULL;
q=p;
}
fclose(fp);
return OK;
}
投票的增加(链表插入前置函数)
int LinkInsert_L_Vote(VoteLinkList &L,VoteNode *NewNode)
{
VoteNode *p=L,*newnode;
newnode=(VoteNode *)malloc(sizeof(VoteNode));
/*读入元素*/
strcpy(newnode->ActivityName,NewNode->ActivityName);
newnode->cnt=NewNode->cnt;
strcpy(newnode->VoteName,NewNode->VoteName);
for(int i=0;i<newnode->cnt;i++)
{
strcpy(newnode->SV[i].choice,NewNode->SV[i].choice);
newnode->SV[i].num=NewNode->SV[i].num;
}
while(p->next->next!=NULL)
{
p=p->next;
}/*遍历到尾部*/
newnode->next=p->next;
p->next=newnode;
return OK;
}
增加投票的具体函数
void Add_Vote(ActivityLinkList L,VoteLinkList &V)/*新增的投票,不断地调用这个函数*/
{
ActivityLinkList p=L->next;
if(!ShowActivity_I_Create(L))
{
return ;
}
Lable_Cin:printf("你想对哪一个活动发起投票?");
int n;scanf("%d",&n);getchar();
int idx=1;
while(p->next!=NULL)
{
if(p->next==NULL)
{
printf("输入不合法!请重新输入!");
goto Lable_Cin;
}
if(idx==n)
{
break;
}
if(strcmp(p->ActivityCreater,UserNow)==0)
{
idx++;
}
p=p->next;
}
char IsStop[10];IsStop[0]='0';IsStop[1]='\0';
/*设定好要用的变量*/
while(1)
{
VoteNode *NewNode=new VoteNode;int idx=0;
printf("您是%s活动的创建者:\n",p->ActivityName);
printf("请输入您想添加的投票内容:(不超过20个字符,输入0回退)");
if(ScanfTheString(NewNode->VoteName,50))
{
if(strcmp(NewNode->VoteName,IsStop)==0)
{
break;
}
/*此处进行活动名的绑定*/
strcpy(NewNode->ActivityName,p->ActivityName);
/*进行一次查重*/
/*重置遍历指针*/
VoteLinkList p=V->next;
/*进行遍历查找*/
while(p->next!=NULL)
{
/*判断是否重复*/
if(strcmp(p->ActivityName,NewNode->ActivityName)==0 && strcmp(p->VoteName,NewNode->VoteName)==0)
{
printf("该投票内容已经存在,是否添加新的投票内容?");
printf("【1】添加新的投票选项 【0】回退");
int n;scanf("%d",&n);getchar();
if(n==1)
{
/*展示投票的选项*/
printf("【1】活动名称:%s\n",p->ActivityName);
printf("【2】投票内容:%s\n",p->VoteName);
printf("【3】投票选项:\n");
for(int i=0;i<p->cnt;i++)
{
printf("【%d】:%s ",i+1,p->SV[i].choice);
}
printf("\n");
/*增加投票选项,要做一个查重*/
while(1)
{
char temp[50]="";
printf("请输入你想增加的投票选项(不超过20个字符,输入0后回退,结束):");
if(ScanfTheString(temp,50))
{
if(strcmp(temp,IsStop)==0)
{
return ;
}
strcpy(p->SV[p->cnt++].choice,temp);
continue;
}
else
{
continue;
}
}
}
if(n==0)
{
return ;
}
}
}
/*新增投票的选项*/
NewNode->cnt=0;
while(1)
{
printf("请输入至少两个以上的投票选项(不超过20个字符,输入0结束):");
if(ScanfTheString(NewNode->SV[idx].choice,50))
{
if(strcmp(NewNode->SV[idx].choice,IsStop)==0)
{
if(NewNode->cnt==0)
{
printf("请至少设置两个投票选项!");
continue;
}
if(NewNode->cnt==1)
{
printf("请至少设置两个投票选项!");
continue;
}
LinkInsert_L_Vote(V,NewNode);
free(NewNode);
break;
}
idx++;NewNode->cnt++;
}
else
{
continue;
}
}
}
else
{
continue;/*继续读入*/
}
}
SaveDocument_Vote(V);
}
用户进行投票
首先需要指定投票规则,每个用户仅可以对一个投票内容内的投票选项进行一次投票,投了就不能再次投票。那么在这里呢,首先要做的是锁定每一个活动,那么在这个锁定的过程中,可能会锁定到非法区域,这时候要做一个非法检测。
void PartipateVote(ActivityLinkList L,UserLinkList T,VoteLinkList &V)/*对参加的活动进行投票*/
{
clean;
printf("是否进行投票?\n");
printf("【0】回退 【1】进入投票界面");
UserLinkList p=T->next;
int n;
scanf("%d",&n);
getchar();
clean;
if(n==0)
{
return ;
}
else if(n==1)/*进入投票*/
{
if(!ShowActivity_I_Participate(T,L))
{
return ;
}
printf("你想对哪一个活动进行投票?(请输入活动编号)\n");
Label_CIN:
int n;
scanf("%d",&n);
getchar();
/*进入显示投票选项*/
/*同样的,也是对用户节点进行锁定后调用数据*/
while(p->next!=NULL)
{
if(strcmp(p->UserName,UserNow)==0)
{
break;/*锁定*/
}
}
if(n>p->ActivityNum_Participate+1)
{
printf("输入值不合法!请重新输入!\n");
goto Label_CIN;
}
/*先定义一个变量存储当前锁定到的活动名,因为之后也就只用活动名而已*/
char temp[50]="";
/*重置遍历指针*/
VoteLinkList q=V->next;
strcpy(temp,p->Activity_Participate[n-1]);
/*定位投票位置*/
/*投票位置数组*/
int idx=1,pos=0;
int a[MaxPeople]= {0};
while(q->next!=NULL)
{
if(strcmp(q->ActivityName,temp)==0)
{
/*写入位置数组*/
a[idx++]=pos;
}
pos++;
q=q->next;
}
if(idx==1)
{
printf("当前活动没有发起任何投票!");
system("pause");
clean;
return ;
}
printf("为您找到如下的投票选项:\n");
printf("活动名称:%s\n",temp);
/*重置遍历指针*/
q=V->next;
for(int i=1; i<idx; i++)
{
int pnow=a[i]-a[i-1];
while(pnow--)/*遍历次数*/
{
q=q->next;
}
printf("投票内容:%s\n",q->VoteName);
for(int i=0; i<q->cnt; i++)
{
printf("【%d】%s ",i+1,q->SV[i].choice);
}
printf("\n");
}
while(1)
{
printf("你想对什么内容进行投票?【输入投票内容】(输入0回退)");
char chose[50]="";
char IsStop[5]="";
IsStop[0]='0',IsStop[1]='\0';
if(ScanfTheString(chose,50))
{
/*同样做一个遍历查找,如果找不到对应的东西就让他回去*/
if(strcmp(chose,IsStop)==0)
{
clean;
return ;
}
q=V->next;
bool IsFind=false;
for(int i=1; i<=idx; i++)
{
int pnow=a[i]-a[i-1];
while(pnow--)
{
q=q->next;
}
if(strcmp(q->VoteName,chose)==0)
{
IsFind=true;
/*进入投票界面*/
while(1)
{
printf("投票选项:\n");
for(int i=0; i<q->cnt; i++)
{
printf("【%d】%s (当前票数:%d) ",i+1,q->SV[i].choice,q->SV[i].num);
}
printf("\n");
printf("请选择你要进行投票的选项【输入投票序号,输入0后回退】:");
int n;
scanf("%d",&n);
getchar();
if(n>q->cnt)
{
printf("输入值不合法!请重新输入!\n");
system("pause");
continue;
}
if(n==0)
{
return ;
}
/*首先做一个检索,如果没有检测到已经投票,那么就投票+1*/
bool IsCom=false;
for(int i=0; i<q->SV[n-1].num; i++)
{
if(strcmp(UserNow,q->SV[n-1].Voter[i])==0)
{
IsCom=true;
break;
}
}
if(!IsCom)
{
strcpy(q->SV[n-1].Voter[q->SV[n-1].num],UserNow);
q->SV[n-1].num++;
printf("投票成功!请勿重复刷票!\n");
system("pause");
clean;
continue;
}
else
{
printf("你已经为这个选项投过票了\n");
system("pause");
clean;
continue;
}
}
}
}
if(!IsFind)
{
printf("没有找到对应的活动内容,请检查输入是否正确!\n");
continue;
}
}
else
{
continue;
}
}
}
}
审核功能改动
那么如果涉及到审核的话就涉及到一个反馈信息的内置功能,于是新增了邮箱系统,来执行反馈的功能,整体改动较多,代码不一一陈列,只列出具体函数。
void Examine(ActivityLinkList &L,UserLinkList &T)
{
ActivityLinkList p=L->next;
int idx=0;
UserLinkList q=T->next;
if(!ShowActivity_I_Create(L))
{
system("pause");
return ;
}
printf("请选择你想要审核的活动");
int n;
scanf("%d",&n);
getchar();
while(p->next!=NULL)
{
if(strcmp(UserNow,p->ActivityCreater)==0)
{
if(idx==n-1)
{
break;/*同样的一个锁定节点*/
}
idx++;
}
p=p->next;
}
/*首先先展示当前审核的状态*/
printf("当前活动:%s\n",p->ActivityName);
printf("待审核名单:\n");
int num=1;
for(int i=0; i<p->Paticipater_Selecting; i++)
{
if(p->Joiner_Selecting_Num[i]==0)
{
printf("【%d】%s\n",num++,p->Joiner_Selecting[i]);
}
}
if(num==1)
{
printf("当前没有新的需要审核的人员!\n");
system("pause");
clean;
return ;
}
printf("确认开始审核吗?【1】进入审核 【0】回退\n");
int k;
scanf("%d",&k);
getchar();
if(k==0)
{
return ;
}
for(int i=0; i<p->Paticipater_Selecting; i++)
{
q=T->next;/*重置遍历指针*/
while(q->next!=NULL)
{
if(strcmp(q->UserName,p->Joiner_Selecting[i])==0 && p->Joiner_Selecting_Num[i]==0)/*锁定了当前节点*/
{
printf("报名者:%s\n",q->UserName);
printf("性别:%s\n",q->sex);
printf("电话:%s\n",q->PhoneNum);
printf("是否审核通过?请输入(1代表通过,0代表未通过)");
int n;
scanf("%d",&n);
getchar();
if(n==1)
{
strcpy(q->Activity_Participate[q->ActivityNum_Participate],p->ActivityName);/*审核通过,将用户假如名单*/
strcpy(p->Joiner[p->Paticipater++],q->UserName);/*同时将当前的活动名加入用户已经参加的活动*/
p->Joiner_Selecting_Num[i]=1;/*标记*/
q->ActivityNum_Participate++;
sprintf(q->MB[q->MailNum].Main,"恭喜你成功报名%s,请关注后续动态!",p->ActivityName);
GetTime(q->MB[q->MailNum].time);
strcpy(q->MB[q->MailNum].Sender,UserNow);
q->MB[q->MailNum].IsRead=0;
q->MailNum++;
}
else if(n==0)
{
p->Joiner_Selecting_Num[i]=1;
GetTime(q->MB[q->MailNum].time);
strcpy(q->MB[q->MailNum].Sender,UserNow);
sprintf(q->MB[q->MailNum].Main,"很遗憾,你未能成功报名%s,谢谢参与!",p->ActivityName);
q->MB[q->MailNum].IsRead=0;
q->MailNum++;
}
}
q=q->next;
}
printf("审核结束!喝杯茶休息一下吧~");
system("pause");
clean;
}
}
邮箱系统
void ShowMailBox(UserLinkList &T)
{
/*需要两次遍历*/
UserLinkList p=T->next;
while(p->next!=NULL)
{
if(strcmp(p->UserName,UserNow)==0)
{
break;
}
p=p->next;
}
int idx=1;
for(int i=0;i<p->MailNum;i++)
{
if(p->MB[i].IsRead==0)
{
printf("【%d】(未读)",idx++);
printf("发信人:%s ",p->MB[i].Sender);
printf("发信时间:%s\n",p->MB[i].time);
printf("信件内容:%s\n",p->MB[i].Main);
system("pause");
}
}
for(int i=0;i<p->MailNum;i++)
{
if(p->MB[i].IsRead==1)
{
printf("【%d】(已读)",idx++);
printf("发信人:%s ",p->MB[i].Sender);
printf("发信时间:%s\n",p->MB[i].time);
printf("信件内容:%s\n",p->MB[i].Main);
system("pause");
}
}
for(int i=0;i<p->MailNum;i++)
{
if(p->MB[i].IsRead==0)
{
p->MB[i].IsRead=1;
}
}
}
5.6日更新
本次更新内容是菜单的优化,旨在优化用户体验.