假定我的程序需要用户输入才能创建密码。有特定的条件。
用户应该能够重试五次以创建“良好”密码。如果他们输入了“好”密码,该程序应该就结束了。如果他们在5次尝试中都没有输入密码,则程序应结束。我尝试使用do-while和for循环,但不会中断或结束程序。
我有一个包含5个密码的文本文件。用户不能使用这五个密码。我将密码放入一个char数组中。我不确定如何将文件中的密码与用户输入进行比较。
我只能在该程序中使用cstrings。我不允许使用任何字符串。
“ prevPswds.txt”
2347UCDa!
PassUCD97~
@489sqUCD
123AaaUCD$%
UCDAsue1,
main.cpp:
#include <iostream>
#include <cstring>
#include <cctype>
#include <fstream>
//#include <string.h>
using namespace std;
int main()
{
//Initialize variables
const int size = 15;
char* check = NULL;
char checkUCD[] = "UCD";
char specialChar[] = { '~', '!', '@', '#', '$', '%', '^', '&', '*', '-', '_', '?' };
char password[size];
int counter=0;
bool length = false;
bool uppercase = false;
bool lowercase = false;
bool number = false;
bool special = false;
bool ucd = false;
bool previous = false;
bool lower = false;
bool upper = false;
bool num = false;
//bool done = false;
ifstream file("prevPswds.txt");
const int arraySize = 150;
char myArray[arraySize];
char current_char;
int count = 0;
//Read in file
for (int k = 0; k < arraySize; k++)
{
if (file.is_open())
{
int c = 0;
while (!file.eof())
{
file.get(myArray[c]);
c++;
count++;
}
}
}
for (int i = 0; i < 5; i++)
{
cout << "----CREATE A PASSWORD----" << endl;
cout << "Password requires:" << endl;
cout << "-8 to 12 characters" << endl;
cout << "-At least 1 uppercase letter" << endl;
cout << "-At least 1 lowercase letter" << endl;
cout << "-At least 1 number" << endl;
cout << "-At least 1 special character (~, !, @, #, $, %, ^, &, *, -, _, ?)" << endl;
cout << "-'UCD' \n" << endl;
cout << "Password cannot include:" << endl;
cout << "-Lowercase letters 'l,' 'i,' 'o,' or 'z'" << endl;
cout << "-Uppercase letters 'I,' 'O,' or 'S'" << endl;
cout << "-Numbers '0,' '1,' or '5'" << endl;
cout << "-------------------------" << endl;
//Get user input
cout << "Please enter a password." << endl;
cin.getline(password, size);
cout << endl;
counter++;
//Check requirements
if (strlen(password) < 8 || strlen(password) > 12)
{
cout << "-Password must be 8 - 12 characters." << endl;
}
else
{
length = true;
}
for (int i = 0; i < size; i++)
{
if (isupper(password[i])) //Check for uppercase
{
uppercase = true;
}
if (islower(password[i])) //Check for lowercase
{
lowercase = true;
}
if (isdigit(password[i])) //Check for numbers
{
number = true;
}
if (password[i] != 'l' || password[i] != 'i' || password[i] != 'o' || password[i] != 'z') //Check for exceptions
{
lower = true;
}
if (password[i] != 'I' || password[i] != 'O' || password[i] != 'S') //Exceptions
{
upper = true;
}
if (password[i] != '0' || password[i] != '1' || password[i] != '5') //Exceptions
{
num = true;
}
}
for (int i = 0; i < size; i++) //Check for special characters
{
if (specialChar[i])
{
if (ispunct(password[i]))
{
special = true;
}
}
}
check = strstr(password, checkUCD); //Check for 'UCD'
if (check)
{
ucd = true;
}
//Give feedback and suggestion
if (uppercase == false)
{
cout << "Password must contain at least 1 uppercase letter." << endl;
}
if (lowercase == false)
{
cout << "Password must contain at least 1 lowercase letter." << endl;
}
if (number == false)
{
cout << "Password must contain at least 1 number." << endl;
}
if (special == false)
{
cout << "Password must contain at least 1 special character." << endl;
}
if (ucd == false)
{
cout << "Password must contain 'UCD.'" << endl;
}
if (lower == false)
{
cout << "Password cannot contain 'l', 'i', 'o', or 'z.'" << endl;
}
if (upper == false)
{
cout << "Password cannot contain 'I', 'O', or 'S.'" << endl;
}
if (num == false)
{
cout << "Password cannot contain '0', '1' or '5.'" << endl;
}
}
if (length == true || uppercase == true || lowercase == true || number == true || special == true || ucd == true || previous == true || lower == true || upper == true || num == true)
{
return 1;
}
}
答案 0 :(得分:0)
这有点长,所以我尝试添加一些小标题,以便您可以轻松跳到下一期。
首先首先要解决的问题:Why is “using namespace std;” considered bad practice?帮个忙,停止使用它。如果让它成为一种成年习惯,将很难改变,并且有时会遇到麻烦并被迫改变。
其次,您还遇到了以下问题:Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())
) considered wrong?我认为您的代码确实有效,但我也认为这是偶然的。
for (int k = 0; k < arraySize; k++)
{
if (file.is_open())
{
int c = 0;
while (!file.eof())
{
file.get(myArray[c]);
c++;
count++;
}
}
}
外部循环从k=0
开始,然后我们到达内部循环,您在其中读取文件中的所有字符-然后又读取一个字符,因为eof
仅在以下情况下设置您尝试阅读末尾的 (使用get
)。但是,由于您不尝试在此处处理该字符,因此您不会注意到最后一次读取失败-尽管您的count
可能偏离了一个。
一旦内循环终止,您便返回外循环并设置k=1
。但是,由于您已经阅读了整个文件,因此仅跳过了内部循环。以此类推,k=2
至arraySize
。
如您所见,文件读取存在一些问题,因此请不要那样做。 :)
另一个考虑因素是,您可能不希望将单个字符混在一起,可能更希望分别拥有五个旧密码-而且它们很好地都位于文件的一行中。
我的建议是,由于您有5个旧密码(此数字可以更改吗?),最长为12个字符或最长size
个字符(此数字可以更改吗?)个字符,因此您可以更改myArray
到char myArray[5][size]{}
。然后使用getline
读取旧密码,如下所示:
for (int k = 0; k < 5 && file.getline(myArray[k], size); k++)
{}
我认为这将使您的比较工作更加轻松,因为您只需要遍历五个数组并比较myArray[k][i] == password[i]
。
第三问题是您的支票。我将简化它们-除非您有充分的理由希望以后能够看到哪些失败了。代替:
if (isupper(password[i])) //Check for uppercase
{
uppercase = true;
}
if (islower(password[i])) //Check for lowercase
{
lowercase = true;
}
...
if (uppercase == false)
{
cout << "Password must contain at least 1 uppercase letter." << endl;
}
if (lowercase == false)
{
cout << "Password must contain at least 1 lowercase letter." << endl;
}
...
if (length == true || uppercase == true || lowercase == true || number == true || special == true || ucd == true || previous == true || lower == true || upper == true || num == true)
{
return 1;
}
将其更改为:
if (!isupper(password[i])) //Check for uppercase
{
passwordIsGood = false;
cout << "Password must contain at least 1 uppercase letter." << endl;
}
if (!islower(password[i])) //Check for lowercase
{
passwordIsGood = false;
cout << "Password must contain at least 1 lowercase letter." << endl;
}
...
if (passwordIsGood)
{
return 1;
}
这将使您的代码更加统一,并且更易于阅读。
第四步:这还将使您更容易修复不重置每个“创建密码”循环中的布尔值的错误。您设置了f.ex。 length = false
声明变量时,然后在检查其正确之后length = true
。但是,如果该密码因其他问题而失败,length
永远不会重置,那么下一个密码可能是错误的长度,但是length
已经是true
,因此检查失败。
第五问题是您将支票if
置于密码循环之外。程序的结构为:
for (int i = 0; i < 5; i++)
{
cout << "----CREATE A PASSWORD----" << endl;
... lots of lines ...
}
if (length == true || uppercase == true || lowercase == true || number == true || special == true || ucd == true || previous == true || lower == true || upper == true || num == true)
{
return 1;
}
因此,在检查是否满足要求之前,您总是通过“创建密码”循环五次。
我的建议是重构。
将所有密码检查功能移至其自身的功能中:
bool checkPassword(char* password, int size)
{
if (strlen(password) < 8 || strlen(password) > 12)
{
cout << "-Password must be 8 - 12 characters." << endl;
return false;
}
for (int i = 0; i < size; i++)
{
if (!isupper(password[i])) //Check for uppercase
{
cout << "Password must contain at least 1 uppercase letter." << endl;
return false;
}
...
}
...
return true;
}
然后您的循环变为:
for (int i = 0; i < 5; i++)
{
cout << "----CREATE A PASSWORD----" << endl;
...
//Get user input
cout << "Please enter a password." << endl;
cin.getline(password, size);
cout << endl;
counter++;
//Check requirements
bool passwordIsGood = checkPassword(password, size);
if (passwordIsGood)
{
return 1;
}
}
现在,突然发现发生的事情要容易得多。
第六个问题是您的某些支票没有执行您想要的操作。具体来说就是这样的:
if (password[i] != 'l' || password[i] != 'i' || password[i] != 'o' || password[i] != 'z')
请注意,OR中的条件之一必须为真,否则OR为真。如果a=1
为假,则a!=1
为假,而a!=2
为真。这意味着a != 1 || a != 2
是正确的。 a
必须同时为 1和2,才能使a != 1 || a != 2
为假。
获得所需行为的一种方法是将检查更改为:
if (!(password[i] == 'l' || password[i] == 'i' || password[i] == 'o' || password[i] == 'z'))
那变得比我预期的要长得多……我希望它至少对您有帮助。 :)
答案 1 :(得分:-1)
if (length == true || uppercase == true || lowercase == true || number == true || special == true || ucd == true || previous == true || lower == true || upper == true || num == true)
{
//return 1; take this line out and place after all {}
i = 5; //should end the for loop
}
}
return 1;