问题
程序不会停止找到一个匹配后搜索匹配。由于比赛结束后测试的数值将不匹配,因此会出现混乱。
让我们来看,当我们为分别MMM和用户名和密码,输入执行下面的代码出现这种情况:
for(int i=0;i<=3;i++){
if(usernameinput ==username[i] && passinput==password[i])
{
flag=true;
}
else if (usernameinput !=username[i] && passinput!=password[i])
{
flag=false;
cout<<"please enter correct username and password"<<endl;
}
}
迭代1:
if("mmm" == "mmm" && "1234" == "1234") // both true. Enter
{
flag=true; // flag is now true
}
else if ("mmm" != "mmm" && "1234" != "1234")
{
flag=false;
cout<<"please enter correct username and password"<<endl;
}
现在,因为没有任何事情告诉程序匹配已经找到,我们可以停止查找,我们继续进行迭代2:
if("mmm" == "nnnn" && "1234" == "1212") // false
{
flag=true;
}
else if ("mmm" != "mmm" && "1234" != "1234") // both false, enter
{
flag=false; // flag is now false Ooops.
cout<<"please enter correct username and password"<<endl;
}
输出,即使凭据是正确的,flag
将是错误的,用户将被警告三次漏报。呸。
please enter correct username and password
please enter correct username and password
please enter correct username and password
我们需要退出循环时,我们得到了一个匹配。显而易见的解决方案是这样的:
if(usernameinput ==username[i] && passinput==password[i])
{
flag=true;
break;
}
别急!还有更多!如果输入是mmm和?
迭代1:
if("mmm" == "mmm" && "1235" == "1234") //Second case fails
{
flag=true;
break;
}
else if ("mmm" != "mmm" && "1234" != "1234") // first case fails
{
flag=false;
cout<<"please enter correct username and password"<<endl;
}
我们不进入要么情况。 flag
仍然是错误的,入侵者没有进入,但这看起来很丑,仍然给你三条错误信息。我们可以做得更好。
解决方案
做一个函数:
bool checkcredentials(const std::string & uname,
const std::string & pword)
{
bool rval = false;
for(int i=0;i<=3;i++)
{
if(uname== username[i])
{
if (pword==password[i])
{
rval = true; // could just return true here, but some folk get uptight
// over multiple returns in a function
}
break;
}
}
return rval;
}
调用函数不会像
if (checkcredentials(usernameinput, passinput))
{
// let the user in.
}
else
{
cout<<"please enter correct username and password"<<endl;
}
注意,检查密码函数什么都不做,但检查的凭据。所有与用户的通信都在其他地方完成。这使得该功能很简单。它只做一件事,它是由函数名称描述的一件事。
安全提示:在向用户返回消息之前等待一些小的随机数量的时间。这与试图通过对响应进行计时来猜测凭证的大小或凭证数据库的大小的任何人的首脑混淆。
这可以通过将用户名和密码配对并只有一个数组进行进一步清理。这可确保用户名与密码匹配,并且没有人添加用户名而不添加密码。
pair<string, string> credentials[]={ // array of pairs
{"mmm", "1234"},
{"nnnn", "1212"},
{"rrrr", "1234"},
{"aaa", "1212"}
};
bool checkcredentials(const std::string & uname,
const std::string & pword)
{
bool rval = false;
for(auto & cred: credentials)
{
if(uname == cred.first)
{
if (pword == cred.second)
{
rval = true;
}
break;
}
}
return rval;
}
Documentation on pair.
这可以用一个更聪明的数据结构得到改善。 map
是一个关联容器,在这种情况下,根据密钥,用户名查找一个值,密码。
map<string, string> credentials={
{"mmm", "1234"},
{"nnnn", "1212"},
{"rrrr", "1234"},
{"aaa", "1212"}
};
bool checkcredentials(const std::string & uname,
const std::string & pword)
{
auto cred = credentials.find(uname); // look for user name
if (cred != credentials.end() && // username exists
cred->second == pword) // password matches
{
return true;
}
return false;
}
Documentation on map.
题外话:而不是密码和用户名分离成自己阵列使用配对结构将它们分组,并只有一个阵列。需要较少的簿记。 – user4581301