用数组实现从文件搜索帐户和验证密码

最近一个同学在写个银行管理系统,然后问我怎么从文件搜索帐户,给了方法后又不懂文件里面的密码怎么与输入的匹配。一般来说,高效的做法是用链表实现。用数组实现不是高效的方法,而且浪费空间。再者,对于账户类有个人信息集合的,一般用结构体,代码写起来也方便简单。

但是他却用数组来做,而且没有用结构体。对于这种情况下如何搜索帐户,如何验证密码呢? 我尝试了一下,发现不难解决。

解决这个问题的方法:用文件数据的排序定位来做。

第一步:文件信息读入

 用fscanf 实现文件读出文件信息。

1 char a[20];
2 
3 FILE* fp;
4 fp = fopen("test.txt","rb");
5 fscanf (fp, "%s", a);
6 fclose(fp);

fcanf读取数据,以空格为分割点。比如对于文件内容为“abc ABC”(双引号之内)的情况,用如下代码:

 

fscanf (fp, "%s", a);
fscanf (fp, "%s", b);

 

 得到字符数组a 为abc;字符数组b为 ABC;

若文件内容为“abcABC”(双引号之内)的情况,即abc和ABC之间没有空格隔开,用以上代码,得到的结果将是:

字符数组a 为abcABC;字符数组b 为乱码。

fscanf();还有一个特点,就是在一个程序里面是顺序读入的。

在此举个例子:

txt文件(每个数据一行)内容:

abc

ABC

ruby

 

然后执行下面的代码:

复制代码
int main()
{
  char a[20],b[20],c[20];
  FILE* fp;
  fp = fopen("test.txt","rb");
  fscanf(fp, "%s", a);
  //……此处省略n行代码
  fscanf(fp, "%s",b);
  //……此处省略n行代码
 fscanf(fp, "%s",c);
 fclose(fp);
return 0;
}
复制代码

 

 得到的结果是:

字符数组a为 abc,b为ABC,c为ruby;

 

第二步:搜索账号

 

 

账号搜索的方法是遍历文件数据,找到与输入匹配的账号就停止搜索。

用 while(fscanf(fp,"%s",a) > 0) 实现遍历文件数据。

作用是把文件内容一行一行读入赋值给字符数组a,然后再与输入的账号进行比较。

同时使用标记 flag 判断是否找到匹配的账号,以便后续处理各种不同情况。

代码如下:

 

 

复制代码
char a[20];
char shuRu[20] = {'\0'}; //输入

int flag = 0;

cout << "请输入账号名: ";
cin >> shuRu;

FILE* fp;
fp = fopen("test.txt","rb");

while(fscanf(fp,"%s",a) > 0) //遍历文件数据
{
    if (strcmp(shuRu,a) == 0)
    {
                cout << "找到匹配账号" << endl;
        flag = 1;
                break;
        }
}

if (flag == 0){
  cout << "用户不存在,请注册!" << endl;
  //下一步
}
else
  //下一步;
fclose(fp);
复制代码

 

 代码中判断数据相同用strcmp(str1,str2); 如果两个字符数组存储的内容相同,则 strcmp(str1,str2)== 0

此时停止搜索,用break;跳出循环。

现在举例一下:

其中第三行为账号,第五行为密码。其他的为姓名,地址,年龄等其他信息。

运行如下:

 

 第三步:定位文件密码数据

如果是用结构体,当检测到帐号的时候,再用结构体的 “.” 也就是 “点”密码 来解决。简单方便。但是用的不是结构体,所以只能用其他方法。随笔开头写了用“排序定位”来做,如何实现?

从这个文件数据来看,账号与密码分别是第三行, 第五行,中间隔了个第四行。下面另一个帐户也是同样的排序。

那么就定位到第五行,然后再进行 输入密码 与 文件数据的比较。

代码如下:

 

复制代码
if (strcmp(shuRu,a) == 0)
{
    flag = 1;
    fscanf(fp,"%s",a);
    fscanf(fp,"%s",a);
    break;
}
复制代码

 

 这里面当检测到帐号的时 flag = 1;表示找到匹配账号。

然后用了 两个fscanf(fp,"%s",a); 这不是代码错误,前面提到了fscanf(); 是顺序读入,并且举了 a,b,c三个字符数组的例子。

这里再说明一下为何用两个fscanf();

第一个fscanf();是把账号下面的第一个数据赋值给了 字符数组a;

第二个fscanf();是把账号下面的第二个数据赋值给了 字符数组a;

由于密码数据是账号数据下面的第二个数据,所以必须用两个fscanf(); 因为fscanf();为顺序读入,无法进行跳跃。

 

第四步:验证密码  

定位了密码数据,那么就可以进行密码验证了。为了实现当密码输入错误时,能重新输入,我们必须把验证密码这个环节写成一个函数,然后自身循环调用,类似递归的用法。

代码如下:

 

复制代码
void checkKey(char a[20])
{
    char mima[20];
    cout << "输入密码:";
    cin >> mima;
    if (strcmp(a, mima) == 0)
        cout << "登录成功" << endl;
    else
    {
        cout << "密码输入错误!请重新输入。" << endl;
        Sleep(2000);
        checkKey(a);
    }

    return;
}
复制代码

 

 

 第五步:demo运行

初步完成了这个功能,现在把完整代码贴出来。

 

复制代码
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <windows.h>
 5 using namespace std;
 6 
 7 //检测密码
 8 void checkKey(char a[20])
 9 {
10     char mima[20];
11     cout << "输入密码:";
12     cin >> mima;
13     if (strcmp(a, mima) == 0)
14         cout << "登录成功" << endl;
15     else
16     {
17         cout << "密码输入错误!请重新输入。" << endl;
18         Sleep(2000);
19         checkKey(a);
20     }
21 
22     return;
23 }
24 
25 int main()
26 {
27     char a[20];
28     char shuRu[20] = {'\0'};
29 
30     int flag = 0;
31 
32     cout << "请输入账号名: ";
33     cin >> shuRu;
34 
35     FILE* fp;
36     fp = fopen("test.txt","rb");
37 
38     while(fscanf(fp,"%s",a) > 0)
39     {
40 
41         if (strcmp(shuRu,a) == 0)
42         {
43             flag = 1;
44             fscanf(fp,"%s",a);
45             fscanf(fp,"%s",a);
46             break;
47 
48         }
49         
50     }
51     if (flag == 0)
52         cout << "用户不存在,请注册!" << endl;
53     else
54         checkKey(a);
55 
56     fclose(fp);
57     return 0;
58 }
复制代码

 

我们来运行一下。

首先文件数据如下:(每个帐户的第三行为帐号,第五行为密码)

运行结果:

 

第六步:bug修复 

看上去好像完成了相应预期功能,但是细心观察,不难发现一个bug。举例说明一下:

当文件内容为:

可以看出,第一个帐户的密码和第二个帐户的账号相同,都是aabbcc,此时程序运行就有错误,当搜索到了aabbcc,程序就把他当成了账号,于是出错。

修复bug也很简单,用一种特殊字符对账号进行处理。比如在账号后面追加一个 “@”。

因此,程序要修改两个地方

1. 帐户注册后把信息写入文件时,在账号后面追加一个 “@”

2. 登录时,当输入账号完毕后,也给输入的账号后面追加一个“@”

第一个地方不是我们讨论的范围,我们来看看与本篇随笔有关的要修改的第二个地方:

相关函数: strcat(str1,str2);实现把字符数组 str2 追加到 str1 后面。

代码如下:

 

cout << "请输入账号名: ";
cin >> shuRu;
strcat(shuRu,"@");

 

 所以,当你登录时,输入账号完成按回车键时,程序会自动给你输入的账号后面追加一个字符”@“,然后再与文件数据进行比较。

修改后的完整代码如下:

 

复制代码
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <windows.h>
 5 using namespace std;
 6 
 7 //检测密码
 8 void checkKey(char a[20])
 9 {
10     char mima[20];
11     cout << "输入密码:";
12     cin >> mima;
13     if (strcmp(a, mima) == 0)
14         cout << "登录成功" << endl;
15     else
16     {
17         cout << "密码输入错误!请重新输入。" << endl;
18         Sleep(2000);
19         checkKey(a);
20     }
21 
22     return;
23 }
24 
25 int main()
26 {
27     char a[20];
28     char shuRu[20] = {'\0'};
29 
30     int flag = 0;
31 
32     cout << "请输入账号名: ";
33     cin >> shuRu;
34     strcat(shuRu,"@");
35 
36     FILE* fp;
37     fp = fopen("test.txt","rb");
38 
39     while(fscanf(fp,"%s",a) > 0)
40     {
41 
42         if (strcmp(shuRu,a) == 0)
43         {
44             flag = 1;
45             fscanf(fp,"%s",a);
46             fscanf(fp,"%s",a);
47             break;
48 
49         }
50         
51     }
52     if (flag == 0)
53         cout << "用户不存在,请注册!" << endl;
54         
55     else
56         checkKey(a);
57 
58     fclose(fp);
59     return 0;
60 }
复制代码

 

 文件数据:

运行结果:

密码匹配成功。

总结:对于没有用链表 + 结构体的来写帐户登记的程序,属于纯文件信息处理。那么就只能差强人意的用一些方法来解决。用的是”排序定位“的方法。

代码是追求高效,简洁的。一开始没有用好的方法去解决,虽然也能通向罗马,从程序的维护和更新的角度来看,是不推荐的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值