Home > Software design >  Code review in C regarding bools and if/else if
Code review in C regarding bools and if/else if

Time:01-26

I came up with this solution with some help regarding the CS50 Week 2 Problem set password. The prompt is to use 2 function to come up with a simple password checker, verifying an input string has 1 uppercase letter, 1 lowercase letter, 1 number, and 1 symbol. The suggestion was to use bools. However, I have 3 questions on how and why this works:

  1. Bools... I still am struggling with them. Why don't I have to put the =true part? Are bools just assumed to have to be true?
  2. Doing some research, I understand now that the last statement in an if clause doesn't have to be else, because that can't be specified. But why does one if and three else if work? I originally anticipated that it would be a sort of nested if statements instead.
  3. Does the bool valid(string password) function take false and true as input because it's defined as using bool?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>

bool valid(string password);

int main(void)
{
    string password = get_string("Enter your password: ");
    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");
    }
}
bool valid(string password)
{
    bool haslower = false;
    bool hasupper = false;
    bool hasdigit = false;
    bool haspunct = false;
    int i;

    for (i = 0; password[i] != '\0'; i  )
    {
        if (isupper(password[i]))
        {
            hasupper = true;
        }
        else if (islower(password[i]))
        {
            haslower = true;
        }
        else if (isdigit(password[i]))
        {
            hasdigit = true;
        }
        else if (ispunct(password[i]))
        {
            haspunct = true;
        }
    }

    if (hasupper && haslower && hasdigit && haspunct)
    {
        return true;
    }

    return false;
}

CodePudding user response:

  1. Bools... I still am struggling with them. Why don't I have to put the =true part? Are bools just assumed to have to be true?

I assume you are actually asking why you don't have to do == true as in if(hasupper && haslower). This isn't really related to the bool type as such, but to the if and similar selection statements in C. Any plain variable or pointer type passed to these gets evaluated as "if non-zero then true, otherwise false". Similarly the logic operators like == return either 1 or 0. This goes way back to a time before C even had a bool type.

However, it is considered good style to only use variables of type bool in that manner. if(mybool) is ok some coding standards frown at code such as if(mypointer) and instead encourage to be explicit if(mypointer != NULL).

Also note that the bool type in C has the built-in ability to convert any non-zero integer value into true/false. So bool b=123; results in true (which in turn equals 1).


  1. Doing some research, I understand now that the last statement in an if clause doesn't have to be else, because that can't be specified. But why does one if and three else if work? I originally anticipated that it would be a sort of nested if statements instead.

else is always optional at the end of an if. Now as it happens, there is actually nothing in C called else if, it's just a very common coding style convention. Each else always belongs to the previous if, so your code is actually using else, and it can be rewritten 100% equivalent (but harder to read) like this:

// harder to read
if (isupper(password[i]))
{
  hasupper = true;
}
else 
  if (islower(password[i]))
  {
    haslower = true;
  }
  else 
    if (isdigit(password[i]))
    {
      hasdigit = true;
    }
    else 
      if (ispunct(password[i]))
      {
        haspunct = true;
      }

This works because every if or else can accept one statement on the next line without braces. You could type out the braces explicitly too, but that's even less readable:

// even harder to read
if (isupper(password[i]))
{
  hasupper = true;
}
else 
{
  if (islower(password[i]))
  {
    haslower = true;
  }
  else 
  {
    if (isdigit(password[i]))
    {
      hasdigit = true;
    }
    else 
    {
      if (ispunct(password[i]))
      {
        haspunct = true;
      }
    }
  }
}

The else if coding style convention reduces the amount of indention and braces, so it is very widely used as a "de facto" standard coding style. (In fact it is one of the very few style-related matters that all C programmers agree on.)


  1. Does the bool valid(string password) function take false and true as input because it's defined as using bool?

The type in front of the function name declares the return type (output) from the function. The input to the function is specified by the parameters, in this case string password. Which is CS50's dysfunctional way of writing char* password. An even better way would be to use const correctness - since this function shouldn't modify the string, it should be declared as bool valid (const char* password);.

CodePudding user response:

You can also eliminate the if/else use entirely by assigning the result of the comparison directly to the variable, because the result of a comparison operation is a value that can be assigned, just like x 5 can be assigned:

bool valid(const char *password)
{
    bool haslower = false;
    bool hasupper = false;
    bool hasdigit = false;
    bool haspunct = false;

    for (int i = 0; password[i] != '\0'; i  )
    {
        hasupper = hasupper || isupper(password[i]);
        haslower = haslower || islower(password[i]);
        hasdigit = hasdigit || isdigit(password[i]);
        haspunct = haspunct || ispunct(password[i]);
    }

    return(hasupper && haslower && hasdigit && haspunct);
}

The code does have to be more complex than just has* = is*(password[i]); because once any of the has* variables are true it has to remain true. Each new value of the has* variables from each char of password has to be or'd with the previous value of that has* variable.

And because the || operator short-circuits, once any of the has* variables is true, the corresponding is*() function doesn't need to be and won't be called any more.

C does not have any ||= compound operator, so you can't write

        hasupper ||= isupper(password[i]);

You could use the bitwise-or compound operator |=, though

        hasupper |= isupper(password[i]);

although that doesn't short-circuit and the use of bitwise operators on bool values probably isn't good style. One reason it's bad style is there's a critical difference in the symmetry between the || and |= operators and the && and &= operators.

Both the || and |= operators will "carry through" a true value as used above because any setting of a non-zero value or bit will always carry through to a true end result: both 0 || 1 and 0 | 2 are true. But if you want to check if all characters are upper case, for example, &= is not equivalent to &&: 1 && 2 is true, but 1 & 2 is false.

CodePudding user response:

  1. Bool or boolean is a primitive data type. There are only two possible values, true or false, which can be denoted as 1 or 0. Booleans are used to denote whether something is true or not, yer or no, and in this case, either it is a valid password or its not. Google more about this.

  2. end? or else? if statements have the option to be chained together using elseif where the predicate is checked through several conditional statements. For example, lets say the predicate is age. If you "age < 21 no alcholo, else yes alcohol" In this case you only need 2. What if you want to check whether a student qualifies for an award and you must check several conditions to see if each are met. If statements aren't required to be chained but they can very well be if needed. They can be nested within other ifs, loops as well and much more. Google what you don't understand and gravitate towards official documentation after a while.

  3. No, Bool is the return type. The function either returns true or false. The parameter takes in a string. So it takes in a set of characters and in this case a password.

You can call the function, or invoke the function in main or any other user defined function by calling the function valid and passing in a string argument. The argument MUST be a string not a bool. The function determines whether the password is indeed a valid password based on the conditional requirements you specified in your if statements. I'm surprised you wrote this but don't understand it but don't give up. Feel free to ask more questions. Be more specific about the lines you refer to next time as well!

Are you watching the shorts from cs50 provided by Doug? They are very useful in helping explain the material further.

Again, lots of jargon here, but google words and concepts you don't understand.

Best of luck!

  • Related