0
\$\begingroup\$

I have written a program to test whether a password contains upper-case, digits and a $.

#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include<string.h>

int main()
{

    char pass[20];                      //Declaring the array to store pass
    int i,flag1=0, flag2=0, flag3=0; 


    printf("Please enter a password having a Upper case letter, a number and also a $ sign \n");
    scanf("%s",&pass); 

        {
            for(i=0;i<=strlen(pass);i++) 
            if( isupper(pass[i]) )
            flag1=1;
            else if(isdigit(pass[i]))               //Loop to check if all element in pass has a digit, alpha & '$'
            flag2=1;
            else if(pass[i]=='$')
            flag3=1;
        }
                {
                    if((flag1==1) && (flag2==1) && (flag3==1))      //All condition true
                    {
                    printf("\nNice Password!");
                    }
                    else
                        {
                        printf("\nPassword must contain a upper case letter, a number and a $ sign");  //Something missing
                        }
                }   


            return 0;
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Your indentation is inconsistent \$\endgroup\$
    – Mibac
    Commented Jul 15, 2017 at 14:07
  • \$\begingroup\$ With scanf("%s",&pass);, I guess code does not allow spaces either. \$\endgroup\$
    – chux
    Commented Jul 15, 2017 at 14:12
  • \$\begingroup\$ @chux how should I counter it? \$\endgroup\$ Commented Jul 15, 2017 at 14:23
  • \$\begingroup\$ BTW, if you can use something newer than C90, at least C99 if not C11. The newer standards allows such nice things as mixing variable-declarations and instructions. \$\endgroup\$ Commented Jul 15, 2017 at 15:01
  • \$\begingroup\$ To counter, use fgets() to read a line. \$\endgroup\$
    – chux
    Commented Jul 15, 2017 at 15:08

2 Answers 2

1
\$\begingroup\$
  1. As a first step, fix the indentation.
  2. As a second step, eliminate superfluous blocks, and use a block if a loop / if / else contains anything longer.
  3. Next, look at your comments. They just restate the code badly, and are thus worse than useless. Comments should be used to explain why something is done, or to express pre- and post-conditions as well as return-values, if it cannot be done acceptably in code.
  4. Don't abbreviate names more than neccessary to make them useable. Descriptive names are essential to making code self-explaining.
  5. Add a space around every binary operator, and after a comma.
  6. Avoid over-long lines. Horizontal scrolling, especially combined with vertical scrolling, kills readability.
  7. Extract the evaluation of the password into its own function for reusability.
  8. Test every function which can fail for failure.
  9. Don't read an unknown amount of data into a finite buffer. Buffer-overflows are bad. scanf accepts a maximum field length.
  10. scanf format specifier %s expects a char*, not a char[20]*.
  11. Be aware that passing anything but the value of an unsigned char or EOF to the character-classification-functions isdigit and isupper is undefined behavior. Cast to unsigned char.
  12. Make sure to end your output with a newline, or the next prompt in the terminal will be in a weird position.
  13. You don't use anything from <conio.h> so don't include it.
  14. As an aside, don't you also want a lower-case letter?
  15. As chux rightly points out, there's an inherent flaw with that password-security-scheme. Read "XKCD #936: Short complex password, or long dictionary passphrase?" for the details.

Applying all that yields:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

static int validPassword(const char* password) {
    int hasUpper = 0, hasDigit = 0, hasDollar = 0 /*, hasLower = 0*/;
    const unsigned char* p = (const unsigned char*)password;
    for(; *p; ++p) {
        if(isupper(*p))
            hasUpper = 1;
        /*else if(islower(*p))
            hasLower = 1;*/
        else if(isdigit(*p))
            hasDigit = 1;
        else if(*p == '$')
            hasDollar = 1;
    }
    return hasUpper && hasDigit && hasDollar /* && hasLower*/;
}

int main() {
    char password[32];

    puts("Please enter a password having an upper case letter, a number"
        " and also a $ sign:");
    if(scanf("%31s", password) != 1) {
        puts("Could not get the password.");
        return EXIT_FAILURE;
    }
    if(strlen(password) > 30) {
        puts("Password is too long.");
        return EXIT_FAILURE;
    }
    if(!validPassword(password)) {
        puts("Password must contain an upper case letter, a number and a $ sign.");
        return EXIT_FAILURE;
    }
    puts("Nice Password!");
    return 0;
}
\$\endgroup\$
3
2
\$\begingroup\$

You have introduced some weird an IMO unnecessary scope blocks here:

    {
        for(i=0;i<=strlen(pass);i++) 
        if( isupper(pass[i]) )
        flag1=1;
        else if(isdigit(pass[i]))               //Loop to check if all element in pass has a digit, alpha & '$'
        flag2=1;
        else if(pass[i]=='$')
        flag3=1;
    }

and here:

            {
                if((flag1==1) && (flag2==1) && (flag3==1))      //All condition true
                {
                printf("\nNice Password!");
                }
                else
                    {
                    printf("\nPassword must contain a upper case letter, a number and a $ sign");  //Something missing
                    }
            }   

The code should be reformatted like this probably:

        for(i=0;i<=strlen(pass);i++) {
            if( isupper(pass[i]) ) {
                flag1=1;
            }
            else if(isdigit(pass[i])) {               //Loop to check if all element in pass has a digit, alpha & '$'
                flag2=1;
            }
            else if(pass[i]=='$') {
                flag3=1;
            }
            if((flag1==1) && (flag2==1) && (flag3==1)) {     //All condition true
                printf("\nNice Password!");
            }
            else {
                printf("\nPassword must contain a upper case letter, a number and a $ sign");  //Something missing
            }   
        }
\$\endgroup\$
8
  • \$\begingroup\$ Your elimination of superfluous blocks changed the structure. \$\endgroup\$ Commented Jul 15, 2017 at 14:14
  • \$\begingroup\$ but if i will put this code : if((flag1==1) && (flag2==1) && (flag3==1)) { //All condition true printf("\nNice Password!"); } else { printf("\nPassword must contain a upper case letter, a number and a $ sign"); //Something missing } like you said wouldn't it be included in the loop? \$\endgroup\$ Commented Jul 15, 2017 at 14:14
  • \$\begingroup\$ @Deduplicator I didn't understand what you mean, can you say it in simple words I am new to programming. \$\endgroup\$ Commented Jul 15, 2017 at 14:16
  • \$\begingroup\$ @SrijanSingh I believe you wanted to use a block scope within the loop rather than a surrounding one. \$\endgroup\$ Commented Jul 15, 2017 at 14:18
  • \$\begingroup\$ @πάνταῥεῖ but including it in the loop will make it print the printf statement multiple times, isn't it? \$\endgroup\$ Commented Jul 15, 2017 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.