如何将char数组与cstring和循环程序进行比较

时间:2020-09-14 06:24:02

标签: c++ arrays loops char c-strings

假定我的程序需要用户输入才能创建密码。有特定的条件。

用户应该能够重试五次以创建“良好”密码。如果他们输入了“好”密码,该程序应该就结束了。如果他们在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;
  }
}

2 个答案:

答案 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=2arraySize

如您所见,文件读取存在一些问题,因此请不要那样做。 :)

另一个考虑因素是,您可能不希望将单个字符混在一起,可能更希望分别拥有五个旧密码-而且它们很好地都位于文件的一行中。

我的建议是,由于您有5个旧密码(此数字可以更改吗?),最长为12个字符或最长size个字符(此数字可以更改吗?)个字符,因此您可以更改myArraychar 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;