Code review in C regarding bools and if/else if - c

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:
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?
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.
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;
}

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).
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.)
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);.

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.

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.
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.
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

Ambiguity about Boolean functions in C

Part of my C code 1:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
[snip!!]
#define FALSE 0
#define TRUE 1
[snip!!]
typedef int Boolean;
[snip!!]
typedef struct {
int identification ;
char name[NAMESIZE] ;
char subject[SUBJECTSIZE] ;
int grade ;
} RECORD ;
typedef struct {
char type ;
RECORD student ;
} TRANSACTION ;
typedef struct {
char occupied ;
RECORD student ;
} MASTER ;
char *prog ;
Boolean get_transaction_record(FILE *fp, TRANSACTION *transaction);
[snip!!]
void main(int argc, char *argv[])
{
FILE *fpmas,*fptrans ;
int current_key ,
relative_record_number ;
Boolean allocated;
TRANSACTION transaction;
MASTER master ;
clrscr();
prog = argv[0];
[snip!!]
else
{
get_transaction_record(fptrans, &transaction) ;
current_key = choose_next_key(transaction.student.identification);
while(current_key != TRAILER)
{
relative_record_number = do_initial_status(
current_key,&allocated, fpmas,&master);
while(current_key == transaction.student.identification)
{
apply_transaction (&allocated, &transaction,&master) ;
get_transaction_record(fptrans, &transaction);
}
do_final_status (fpmas, relative_record_number, allocated, &master);
current_key = choose_next_key(transaction.student.identification);
} //end of while
fcloseall();
} //end of else
}
Part of code 2:
Boolean get_transaction_record(FILE *fp, TRANSACTION *transaction)
{
if (fscanf (fp, "%4d%c%20s%10s%2d",
&transaction -> student. Identification,
&transaction -> type,
transaction -> student.name,
transaction -> student. Subject,
&transaction -> student. Grade) == 5)
return(TRUE);
return(FALSE);
}
How these return(); work (in the screenshot I attached) ?! I see before Boolean application like this typedef int Boolean; before. But that usage was in accompany with if() . But I do not see any if() in this code!
My main question is, how it works when the return value (TRUE or FALSE), get back to main() function'?! In main(), there is no condition evaluation to take decision about that (TRUE or FALSE) returned value. So what?
Boolean - return
First, your C learning book is largely outdated. C99 (out in 1999) allows #include <stdbool.h> that contain a bool type and true/false defines, use these instead of making your own boolean.
C and many other languages are a bit weird with boolean, if and what is true of false. In C what is 0 is false, everything else is true, hence why TRUE is defined as 1 and FALSE defined as 0 in your book. Note that comparison operators such as ==, &&, ||, ! (not to be confused with binary operators &, |, ~) returns either 1 or 0 depending of the condition.
See this example:
#include <stdio.h>
#include <stdbool.h>
bool return_the_truth(void)
{
return true; // A trivial function that returns true.
}
int main(void) {
if (2)
printf("As you see just \"2\" is true since it's different of zero\n");
if (0)
printf("That line won't be printed\n");
if (4 - 4)
printf("Neither this one since 4-4 is zero\n");
if (true == 1)
printf("true is in fact a one.\n");
if (true == 2)
printf("But merely a integer with value 1 so this line won't print.\n");
// You can invoke a function that returns a boolean and ignore it's return value.
return_the_truth();
// It is never mandatory to use the returned value. This example is absurd but perfectly valid
fopen("delete_me.txt","a"); // <- Don't forget to delete this file afterward.
if (printf("printf() return an int that is the numbers of characters printed.\n"))
printf("Hence again, this line is printed because what in the if() is not zero.");
int boolean_check_result = 42 == 40+2;
if (boolean_check_result)
printf("You can write expressions like this, there boolean_check_result is %d.\n",boolean_check_result);
printf("You can performs math with boolean, there is %d true expressions there, it works because a comparison returns 1 if true, 0 if false and we doing a sum of 1 and zeros (it's brainfuck to understand don't do that or people reviewing your code will hate you).\n",
(4 == 5) + (4 < 5) + (4 != 5) + (4 > 5) + (4 >= 5) // <- The expressions.
);
// These examples below are valid C.
5 + 6; // This sum goes to... nothing
7 == 7; // Same for this boolean, nothing will happen
printf; // Functions are kind of constants variables so that works.
// It's a non-sense, a compiler will output warnings because making computations without using the results is likely a programming error.
printf("But remind you that in the case of a function (returning a boolean or not), there might be side-effects you want and don't care about the returned value such as with this printf().\n");
}
// Did you know that you can use a `void` value ?
// The code below is perfectly valid.
// It's useful for C++ wrappers when you want to exactly mimic the behavior a library in order to catch errors.
void a_function_that_does_nothing(void)
{
}
void you_can_return_a_void(void)
{
return a_function_that_does_nothing(); // Allowed because the function return a void
}
There is tons of valid case where a returned boolean are not used inside a if().
So to answer your original question (that I might forgot while writing this answer hehe...):
how it works when the return value (TRUE or FALSE), get back to main()
function'?!
And ! 🥁 🥁 🥁 Nothing happens. The value is just lost, just like with printf() and any other functions. In the book the boolean value was an error indicator since scanf() return the number of inputs read, not 5 mean that the input was incorrect.
Not checking it is fine for learning purposes. In real-world input parsing, first don't use scanf(), then it could introduce a security vulnerability since some variables would not be written and in incorrect state and trigger unwanted behavior later that can be exploited by a malicious hacker to leak sensitive data of thousands of customers and costs millions of USD to a company (I'm barely exaggerating).
So don't be outraged when a boolean or other returned value is not used, memcpy() is a function where it's commonly sane to ignore it's return value. What is important is to understand what you are doing.
If you're still extremely angry about the fact that this boolean wasn't used and could avoid a potential security vulnerability... (I'm joking there, yet) as an exercise you can add error checking and do something useful such as printing an expressive error message telling the user that the input is incorrect and remind they what you are expecting and quit.

Why ExtJS sorter function is obliged to return -1/0/1

Ext.util.Sorter.sorterFn return value is restricted to -1/0/1. Also I found mentions of this expectation in comments in the source code.
Why not just to return any negative number/0/any positive number?
I am not asking why it is good to have a comparator that conviniently returns -1/0/1.
I am asking why authors of the framework decided to limit us with -1/0/1 even while JS itself allows any negative number/0/any positive number in its comparator callbacks.
Basically you could use any number as long as they have an order, like -1/0/1 or -12/0/200.
Here is an example:
sorters: [{
sorterFn: function(person1, person2) {
let lhs = person1.data.name,
rhs = person2.data.name;
return (lhs > rhs) ? 200 : (lhs === rhs ? 0 : -12);
}
}],
And here the fiddle, which shows the results Fiddle
!!! First of all you might want to consider the comments from PeterKoltai and aaandri98 !!!
Further - to keep your code readable for everyone (now and in the future) you might want to go with static numbers, that are -1/0/1.
And the rule is: one has to be negativ and one positive, because of the part inside Ext.Array.binarySearch
if (comparison >= 0) {
begin = middle + 1;
} else if (comparison < 0) {
end = middle - 1;
}

For-Loop and Arrays Java

Can anyone explain to me in words what the code after 'for' exactly means? I'm confused with the mixing of int and booleans within 'for' (still a beginner). It's about checking whether two arrays have the same values in the same sequence. Thanks in advance:
public static boolean equal(int[] a1, int[] a2) {
if (a1.length != a2.length) {
return false;
} boolean equal = true;
for (int i = 0; i < a1.length && equal; i++) {
equal &= a1[i] == a2[i];
}
return equal;
}
The for loop consists of 4 parts:
for(initialisation; condition; increment/decrement) {
body
}
Where initialisation is the part where you initialise variables which are in scope throughout the loop.
Condition is the boolean expression which if evaluated to true results in the execution of the body.
Increment/decrement is where you may change the value of any variable in the loop scope.
All 3 parts after the for keyword are optional, so you could create an infinite loop as shown:
for(;;) {
System.out.println("body");
}
The line equal &= a1[i] == a2[i]; is using the &= (logical-and assignment) operator, which is the same as equal = equal & (a1[i] == a2[i]);. It combines the logical-and with the assignment operator. This line can be parsed like this:
bool = (itself) AND (int == int)
bool = (itself) AND (another bool)
bool = (some bool value)
Be very careful with the & operator, since it has two different meanings. It means logical-AND for boolean types, but bitwise-AND for numeric types. To make it clearer to read, use equal = equal && a1[i] == a2[i]; which also has the upside of short-circuit operation (which can save a few unnecessary comparisons).
On another note, there are a few redundancies in this loop.
boolean equal = true;
for (int i = 0; i < a1.length && equal; i++) {
equal &= a1[i] == a2[i];
}
The looping condition checks that the array still has elements AND that the previous element(s) have all matched. Since the looping condition is also checking the boolean equal, there is no need to use the compound and-assignment operator. A simple equal = a1[i] == a2[i]; would work and even save the unnecessary (true) & (something) operation every loop iteration. This works because the looping condition guarantees that equal == true, since the loop will stop execution otherwise.

Passing an array through "isalpha" through a loop

I've been at this for quite some time now and the existing answers offer little to no help. I am new to programming and am trying to write a sub-part of my program which tries to check whether any given input is constituted solely of alphabets.
For this, the idea I have in mind is to pass an entire array through the isalpha function by using a loop which passes each character at a time. The idea makes logical sense but I am having syntactic trouble implementing it. I will greatly appreciate any help!
Below is my code-
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(**<what I'm putting here is creating the problem, I think>**) = true)
{
printf("%c", p[i]);
}
}
You should modify your code as this (assuming you have the string type defined yourself):
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(p[i]) == true) // HERE IS THE ERROR, YOU HAD =, NOT ==
{
printf("%c", p[i]);
}
}
Operator = is for assignment and operator == is for comparison!
So what was happening? The assignment resulted in true, no matter what p[i] was.
As Quentin mentioned:
if(isalpha(p[i]) == true)
could be more elegant and error prune if written like this:
if(isalpha(p[i]))
Here is an example in C:
/* isalpha example */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int i = 0;
char str[] = "C++";
while (str[i]) // strings in C are ended with a null terminator. When we meet
// the null terminator, while's condition will get false.
{
if (isalpha(str[i])) // check every character of str
printf ("character %c is alphabetic\n",str[i]);
else
printf ("character %c is not alphabetic\n",str[i]);
i++;
}
return 0;
}
Source
Ref of isalpha().
C does not have a string type.
Tip: Next time post your code as it is!
Aslo, as Alter noticed, it would be nice to use:
isalpha((unsigned char)str[i])
and in your code
isalpha((unsigned char)p[i])
for safety reasons.
Your example is here.
I.e. parameter of isalpha() is i-th character of string p. The only question is how to access to i-th character. Usually you can use []. I.e. just use following code: isalpha(p[i]) (I see that you already use [] in call of printf).
Also isalpha(p[i]) = true is wrong condition. It looks like you planned to check isalpha(p[i]) == true (you can skip == true).
Late but:
both other answers say omitting == true is desirable, but don't say it is necessary for portability.
The C core-language operators == != < <= > >= && || which return a 'logical' value use an int value of 1 for true and 0 for false. In C99 and up with stdbool.h and by common convention before that true is 1 and false is 0, so e.g. if( (a < b) == true ) will work correctly, although it is redundant and many (including me) consider it poor style. Language elements that test a logical value, namely if(c) while(c) for(;c;) and the operands to && || and the left operand to ?: consider any value that compares equal to 0 to be false, and any other value to be true.
The character-classification routines in ctype.h as well as some other standard-library routines like feof(f) and ferror(f) are specified to return some nonzero int for true and 0 (an int) for false, and on many implementations the nonzero value used for true is not (always) 1. In those cases isalpha(whatever) == true might result in testing say 4 == 1 and fail even when whatever is an alphabetic character. OTOH isalpha(...) != false or isalpha(...) != 0 does work correctly if you really want to write something explicit.

Compound statement to change value after returning it?

Im wondering if it is possible to have a variable changed after returning its value?
The function in question is a simple get function for a private Boolean flag variable. I would like reads of this flag to be destructive, so I thought:
bool myGet (context_t * someContext) {
return (someContext->flag) ? (someContext->flag = false) : false;
}
Reasoning that the result of evaluating the statement (someContext->flag = false)would be true, but it appears not.
Maybe it's evaluated before the condition (someContext->flag)?.
Is there any other way to achieve the intended functionality without resorting to temporarily storing the flag value, clearing the flag and then returning the temporary copy? Thanks.
All of the argument to return must be evaluated before the return itself is evaluated, i.e. before execution leaves the current function.
The value of an assignment is the assigned value, so it's false as you experienced.
I think the closest you can come is with post-increment, but that will of course strictly limit the values available.
There's nothing wrong with doing it the explicit way:
bool getAndClear(context_t *someContext)
{
if(someContext->flag)
{
someContext->flag = false;
return true;
}
return false;
}
it's very clear and way easier to understand than your scary code. It's easy to imagine that it's possible for compiler to optimize it, since it's pretty straight-forward.
If I wanted to get clever, I'd probably use something like:
bool getAndClear2(context_t *someContext)
{
const bool flag = someContext->flag;
someContext->flag ^= flag; /* Clears if set, leaves alone if not set. */
return flag;
}
Note that it doesn't branch, which is sometimes nifty. But, again, being clever is not always the most awesome path to take.
Also note that I consider it a requirement that this function isn't just named "get" something, since it doesn't take a const pointer that would be an instant warning flag in my head. Since it has super-strange (for a getter) side-effects, that should be reflected in the name somehow.
Reasoning that the result of evaluating the statement (someContext->flag = false) would be true, but it appears not.
(someContext->flag = false) is an assignment expression. Its value is the value of the expression being assigned (i.e. false).
The assignment does go through, although it happens before the return, not after it. If you want to be fancy and stay with the ternary operator, you can use comma operator, like this:
return (someContext->flag) ? (someContext->flag = false, true) : false;
This is not very readable, though, so I would prefer this equivalent implementation, which has no conditionals:
bool temp = someContext->flag;
someContext->flag = false;
return temp;
When you do (someContext->flag = false) it set someContext->flag to false, then return it.
You could do :
return (someContext->flag) ? !(someContext->flag = false) : false;
This way you will return the oposite of someContext->flag that you just set to false (so you return true) but someContext->flag will stay false after the return
EDIT
the most unreadable would be :
return !(someContext->flag = !someContext->flag);
You can use the post-decrement operator:
return (someContext->flag) ? someContext->flag-- : false;
This will only have the desired result if the true value for your flag has the numeric value 1.

Resources