Reputation: 133
Im creating a password checker in C. The user enters their password and the program must check it fits the format aa$B1BB$B$$aB
(where a
represents lowercase, B
uppercase, $
symbol and 1
is a digit).
I have currently programmed an array of numbers 0
to 9
, symbols and letters and am trying to create a series of iterative loops to search each character of the password against the matching array of the criteria that it should meet. This was the easiest way I thought of but if anyone has any better suggestions it would be much appreciated.
The errors I am currently facing is that the program isn't running as I expected. If the password is not 13 characters long it should call the else if
statement but it doesn't. So far I have only created statements for checking digits 1
, 2
, 3
and 4
. The printf("Password ok #")
statements are just for testing purposes.
#include <string.h>
#include <stdio.h>
int main() {
char password[20];
int i, length;
int numbers[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
char letters[] = { 'a', 'b', 'c', 'c', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z' };
char symbols[] = { '!', '@', '#', '$', '%', '^', '&', '*',
'-', '_', '+', '=' };
printf("Password rules:\n"
" --------------------- \n"
" must follow the format ee$L1LL$L$$eL \n"
" --------------------- \n"
" Please enter your current password:");
scanf("%c", password);
printf("%19s", password);
length = strlen(password);
if (length = 13) {
printf("Password ok 1");
for (int i = 0; i < strlen(letters); i++) {
if ((password[1] == letters[i]) && (password[2] == letters[i])) {
printf("Password ok 2");
} else {
printf("Digits 1 or 2 do not fit the correct format");
}
}
for (int i = 0; i < strlen(symbols); i++) {
if (password[3] == symbols[i]) {
printf("Password ok 3");
} else {
printf("Digit 3 does not fit the correct format");
}
}
for (int i = 0; i < strlen(letters); i++) {
if (password[4]==symbols[i]) {
printf("Password ok 4");
} else {
printf("Digit 3 does not fit the correct format");
}
}
} else if (length != 13) {
printf("\nPassword must be 13 digits long");
}
}
Upvotes: 1
Views: 1213
Reputation: 11
Below code is perfect by using ctype.h
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
bool valid(const char *password);
int main(void)
{
char password[] = "Password@123";
if (valid(password))
{
printf("Your password is valid!\n");
}
else
{
printf("Your password needs at least one uppercase letter, lowercase letter, number and symbol\n");
}
}
// TODO: Complete the Boolean function below
bool valid(const char *password)
{
int length = strlen(password);
int lower_count = 0;
int upper_count = 0;
int digit_count = 0;
int symbol_count = 0;
for(int i = 0; i < length; i++){
if(islower(password[i])){
lower_count += 1;
}
if(isupper(password[i])){
upper_count += 1;
}
if(isdigit(password[i])){
digit_count += 1;
}
if(ispunct(password[i])){
symbol_count += 1;
}
}
printf("Lower Count: %d\nUpper Count: %d\nDigit Count: %d\nSymbol Count: %d\n", lower_count, upper_count, digit_count, symbol_count);
if(lower_count != 0 && upper_count != 0 && digit_count != 0 && symbol_count != 0){
return true;
}
return false;
}
Output is:
Lower Count: 7
Upper Count: 1
Digit Count: 3
Symbol Count: 1
Your password is valid!
Upvotes: 0
Reputation: 3071
If you're allowed to use ctype
macros like isupper()
, islower()
then you can call them against every pattern-char as.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
enum { // Enumerate codes used in the password-pattern
eLower = 'a',
eUpper = 'B',
eDigit = '1',
eSymbol = '$'
};
char* pp_errors[] = { // Error strings for pattern-mismatch
"No Error",
"Lower case letter expected",
"Upper case letter expected",
"Digit is expected",
"Punctuation expected",
"Pattern Not handled"
};
int
check_pattern_char (const unsigned char pwdC, const unsigned char patC)
{
switch (patC) {
case eLower : if (!islower (pwdC)) return 1;
break;
case eUpper : if (!isupper (pwdC)) return 2;
break;
case eDigit : if (!isdigit (pwdC)) return 3;
break;
case eSymbol : if (!ispunct (pwdC)) return 4;
break;
default: return 5; // pattern not handled
}
return 0;
}
int main ()
{
char password [128];
char pattern [] = "aa$B1BB$B$$aB";
int ptlen = strlen (pattern);
printf ("Enter a password that follows pattern [%s]: ", pattern);
while (1 != scanf ("%127s", password));
if ( (int) strlen (password) != ptlen) {
printf ("\nPassword must be [%d] chars long.\n", ptlen);
return 1;
}
for (int pi = 0; pi < ptlen; ++pi) {
int status;
if ( (status = check_pattern_char (password[pi], pattern[pi]))) {
printf ("\nERROR: [%s] at pos[%d] [%c][%c]\n",
pp_errors[status], pi + 1, pattern[pi], password[pi]);
return 2;
}
}
printf ("\nPassword [%s] accepted against Pattern[%s]\n", password, pattern);
return 0;
}
Or you can write your own functions for them like :
static inline int my_islower (const char ch) {
return (ch >= 'a' && ch <= 'z');
}
static inline int my_isupper (const char ch) {
return (ch >= 'A' && ch <= 'Z');
}
static inline int my_isdigit (const char ch) {
return (ch >= '0' && ch <= '9');
}
static inline int my_ispunct (const char ch) {
// allowed punctuations
char puncts[] = "!@#$%^&*-_+=";
for (char* pp = puncts; *pp; )
if (*pp++ == ch) return 1;
return 0;
}
static inline
is telling compiler that this function is local to this translation-unit
(current file) & requesting it to inline function if possible at the calling location. This mitigates the overheads of calling small functions.
Upvotes: 3
Reputation: 153328
To check if the password fits
format aa$B1BB$B$$aB
Use fgets()
to read, sscanf()
to scan and "%n"
to detect scanning end.
// scanf("%c",password); // %c only reads 1 character
// printf("%19s",password);
if (fgets(password, sizeof password, stdin)) {
password[strcspn(password, "\n")] = '\0'; // Lop off potential \n
printf("<%s>\n", password);
int n = 0;
// format aa$B1BB$B$$aB
#define FMT_a "%*1[a-z]"
#define FMT_B "%*1[A-Z]"
#define FMT_1 "%*1[0-9]"
#define FMT_S "%*1[-!@#$%^&*_+=]" // '-' first
sscanf(password,
FMT_a FMT_a FMT_S FMT_B FMT_1 FMT_B FMT_B FMT_S FMT_B FMT_S FMT_S FMT_a FMT_B "%n",
&n);
bool Success = n > 0 && password[n] == '\0';
A more robust approach uses a series of strchr()
calls in case letters [a-z] are not consecutive.
IMO, use a more generous read buffer.
// char password[20];
char password[100];
Upvotes: 1