Search code examples
c++charlowercase

Why does the validation for lowercase letters always fail?


I am writing a program that takes a password as input and validates based on the following criteria:

  • 8 characters or more
  • at least one uppercase letter
  • at least one lowercase letter
  • at least one digit

The validation function successfully checks for all of the criteria except for lowercase letters even though the method is the same.

P.S. I am aware that using namespace standard is considered bad practice but for the sake of this program, it shouldn't cause any issues to my knowledge.

Main:

#include <iostream>
#include <string>
#include "Passwords.h"

using namespace std;

int main()
{
    string password;    //string for user input
    bool longEnough, foundUpper, foundLower, foundDigit;    //booleans to validate password

    for(int i = 3; i > 0; i--)  //loop 3 times or until valid password is entered
    {
        longEnough = false; //reset bools to false
        foundUpper = false;
        foundLower = false;
        foundDigit = false;
        getInput(password); //calling getInput function
        if(validatePass(password, longEnough, foundUpper, foundLower, foundDigit) == true)  //check if the password is valid
        {
            getValidOutput(password); //calls function to display output for valid password
            exit(0);    //end program
        }
        else
        {
            getInvalidOutput(password, longEnough, foundUpper, foundLower, foundDigit);   //calls function to display output for invalid password
            cout << "You have " << i-1 << " more attempts.\n";
        }
    }
    cout << "You have run out of attempts, the session has been locked.";
    exit(0);    //end program
}

Header file:

#ifndef PASSWORDS_H_INCLUDED
#define PASSWORDS_H_INCLUDED

using namespace std;

void getInput(string& password) //prompts and receives user input for password
{
    cout << "Please enter a password with at least 8 characters, one uppercase, one lowercase, and one digit: ";
    cin >> password;
}

bool validatePass(string password, bool& longEnough, bool& foundUpper, bool& foundLower, bool& foundDigit)  //checks if password is valid
{
    if(password.length() >= 8)  //check for length
    {
        longEnough = true;
    }
    for(int i = 0; i < password.length(); i++)  //check each character
    {
        char position = password.at(i); //set current character
        if(isupper(position) == true)   //check for uppercase letters
        {
            foundUpper = true;
        }
        if(islower(position) == true)   //check for lowercase letters
        {
            foundLower = true;
        }
        if(isdigit(position) == true)   //check for digits
        {
            foundDigit = true;
        }
    }
    if(longEnough == true && foundUpper == true && foundLower == true && foundDigit == true)    //return true if valid, return false otherwise
    {
        return true;
    }
    else
    {
        return false;
    }
}

void getValidOutput(string password)    //output if the password is valid
{
    cout << "The password \"" << password << "\" is valid.";
}

void getInvalidOutput(string password, bool longEnough, bool foundUpper, bool foundLower, bool foundDigit)  //output if the password is invalid
{
    cout << "The password \"" << password << "\" is invalid for the following reasons:\n";
    if(longEnough == false)
    {
        cout << "The password has less than 8 characters\n";
    }
    if(foundUpper == false)
    {
        cout << "The password does not contain an uppercase letter\n";
    }
    if(foundLower == false)
    {
        cout << "The password does not contain a lowercase letter\n";
    }
    if(foundDigit == false)
    {
        cout << "The password does not contain a digit\n";
    }
}

#endif // PASSWORDS_H_INCLUDED


Solution

  • Your checks are wrong:

        if(isupper(position) == true)   //check for uppercase letters
        {
            foundUpper = true;
        }
    

    std::isupper:

    int isupper( int ch );
    

    Checks if the given character is an uppercase character as classified by the currently installed C locale. In the default "C" locale, std::isupper returns a nonzero value only for the uppercase letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ).

    In your comparison true is promoted to int, ie 1, and any nonzero value different from 1 returned from isupper will make isupper(position) == true yield false, because eg 2 == 1 is false.

    Change the comparisons to

         if(isupper(position))
         {
             foundUpper = true;
         }
    

    int can be converted to bool and then any nonzero value yields true.

    Same for islower and isdigit.

    Live Demo