Ambiguity about Boolean functions in C - 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.

Related

C Integer range must meet 3 different conditions

If I wanted to limit the range of values to be assigned to an integer to three different conditions. eg; Must be between 9 and 95 and also be divisible by 5 would this be the correct way to accomplish this?
I've been told that i can have multiple conditions as long as they are separated by && but I am having little success with my code.
if (input >= 5 && input <= 95 && input %5)
Your code seems fine to me, except for this line.
if (input >= 5 && input <= 95 && input %5)
The expression input % 5 returns the remainder of input/5. You want input to be divisible by 5, which happens when input % 5 returns a remainder of 0. Since C interprets 0 as false, and pretty much all other integers as true, this expression will do exactly the opposite of what you want it to do. Try using
if (input >= 5 && input <= 95 && (input % 5 == 0))
That should do what you want it to do.
There are a number of issues with your code as it stands. First, the outright bugs:
The expression input % 5 will give you the remainder when divided by five. This means you will get zero if it is a multiple, non-zero otherwise. Unfortunately, zero is treated as false so this will only be true if input is not a multiple. The correct expression is (input % 5) == 0.
If you enter something that cannot be interpreted as an integer, the scanf will fail and input will be left at whatever value it was beforehand. This should be caught and acted upon, by checking the return value - this gives you the number of items successfully scanned so should be one.
Your code seems to return the value if okay but return nothing if it's invalid.
Next, while not bugs, these things are my personal preferences which can make code easier to read and maintain:
I prefer to explicitly separate sub-expressions so I never have to worry about precedence rules (provided it doesn't make the expression unreadable in the process). To that end, I would make the full if statement if ((input >= 5) && (input <= 95) && ((input % 5 == 0)).
I'm not a big fan of the if (condition) transferControl else ... construct since the else is totally superfluous.
I also prefer error catching to be done in a localised fashion at the start, catching problems early. Only after all checks are passed do you do the success portion.
A function (assuming it is a function, which seems likely) should generally do one thing, such as check if the value is valid. Writing issues to standard output is probably best left to the caller so that the function is truly re-usable. It would be better to have a function do the check and return some value to indicate whether or not there was a failure, along with the value if valid.
It's usually better to use puts("something") rather than printf("something\n"). The printf call is best left to where you actually need to do argument formatting.
Taking that all into account, the code that I would posit would be along the lines of:
#include <stdbool.h>
bool InputValidRangeAndMultiple(
unsigned *pValue,
unsigned minVal,
unsigned maxVal,
unsigned multVal
) {
unsigned input;
// If no unsigned int available, error.
if (scanf("%u", pValue) != 1) return false;
// If value invalid in any way (range or multiple), error.
if ((*pValue < minVal) || (*pValue > maxVal)) return false;
if ((*pValue % multVal) != 0) return false;
// Value is now deemed okay.
return true;
}
Calling that function can be done thus, with the prompts and errors handled outside the "input and check" function:
#include <stdio.h>
unsigned value;
puts("Enter Value.\nValue must be divisible by 5 and within 5 and 95...");
if (! InputValidRangeAndMultiple(&value, 5u, 95u, 5u)) {
puts("Invalid input...");
returnOrDoSomethingIntelligent();
}
// The 'value' variable is now valid.

Please explain the output to this code: [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
#include<stdio.h>
void main()
{
if(0xA)
if(052)
if('\xeb')
if('\012') //what do the above 3 statements mean?
printf("Hello World!")
else;
else;
else;
else;
}
Output:
Hello World!
so here, what is the meaning of 052, \xeb and \012?
And what is the significance of the multiple else statements?
From the C Standard (6.8.4.1 The if statement)
2 In both forms, the first substatement is executed if the
expression compares unequal to 0. In the else form, the second
substatement is executed if the expression compares equal to 0. If the
first substatement is reached via a label, the second substatement is
not executed.
So as each expression in the if statements
if(0xA)
if(052)
if('\xeb')
if('\012')
are unequal to 0 then the enclosed call of the function printf (provided that a semicolon is present)
printf("Hello World!");
is executed.
So the if statements do not make much sense.
0xA is a hexadecimal integer constant equal to decimal 10
052 is octal integer constant equal to decimal 42
'\xeb' is a character constant specified as a hexadecimal escape sequence
'\012' is a character constant specified as an octal escape sequence
Take into account that according to the C Standard the function main without parameters shall be declared like
int main( void )
Thus as each expression of the if statements is not equal to 0 then the program is in fact equivalent to the following program
#include<stdio.h>
int main( void )
{
printf("Hello World!");
}
This is a trick question. Presumably someone thought you could learn something from it. Presumably this person also thinks that a good way to teach a child to ride a bicycle is to flatten the bicycle's tires, and put large boulders in the way, and randomly give the child a rough shove to the side, because it "builds character", and if you can learn to ride a bicycle in spite of those obstacles, you will eventually be a really good bike rider. But I digress.
Anyway, here's an explanation of what's going on in that code.
0xA is a hexadecimal constant. It has the value 0A16, or 10 (base 10).
052 is an octal constant. It has the value 528, or 42 (base 10).
'\xeb' is a hexadecimal character constant. It is a character with the value EB16, or 235 (base 10) (which in ISO-8859-1 or Unicode ends up being an e with two dots over it, ë).
'\012' is an ordinary, octal character constant. It is a character with the value 128, or 10 (base 10) (which in ASCII ends up being a newline character, '\n').
When you say
if( expr )
in C, the expression is considered "true" if it is nonzero, or "false" if it is zero. Needless to say, all four of those constants are nonzero.
The full syntax of an if statement in C is either
if( expr )
statement-or-block
or
if( expr )
statement-or-block
else
statement-or-block
where statement-or-block is either a single statement, or a "block" (sequence) of multiple statements enclodes in braces { }.
A little-used piece of syntax in C is the "empty statement". If you have nothing, followed by a semicolon, that's an empty statement, and it does... nothing.
It is considered mandatory in polite circles to indent your code to portray its structure. So the normal way of presenting this code would be:
#include <stdio.h>
int main()
{
if(0xA)
if(052)
if('\xeb')
if('\012')
printf("Hello World!")
else
;
else
;
else
;
else
;
}
And, again, all four expressions evaluate immediately to "true". So, in English, this code says "If true, then if true, then if true, then if true, then print 'Hello world!', else do nothing, else do nothing, else do nothing, else do nothing."
Phrased that way it sounds pretty stupid, I know. And in fact, it's just as stupid in C as it is in English.
P.S. Besides the bizarre and unnecessary conditionals, another problem with the code as posted, which I have quietly corrected, is that it declared main as void, which is something else that's not done in polite circles, and throws further doubt on the validity of the book this code came from.
The code you posted is equivalent to
#include<stdio.h>
int main( void ) // void main() is not a standard signature
{
if(0xA)
{
if(052)
{
if('\xeb')
{
if('\012')
{
printf("Hello World!")
}
else
{
}
}
else
{
}
}
else
{
}
}
else
{
}
}
Curly braces can be omitted if there is only a single statement within them:
if ( a )
{
do_something();
}
can be written as
if ( a )
do_something();
although I and others recommend against doing this except in specific cases.
An if statement itself counts as a single statement, so it's possible to write
if ( a )
{
if ( b )
do_something();
}
as
if ( a )
if ( b )
do_something();
And, of course, the compiler doesn't care about indentation, so
if ( a )
if ( b )
do_something();
means the same thing - however, as you've discovered, code written this way is a little hard to understand.
The test condition of an if, while, or for may be any scalar type (integer, floating-point, or pointer value). C didn't originally have a distinct Boolean type, so the rule is any non-zero value in a Boolean context evaluates to "true", while zero evaluates to "false".
Each of 0xA, 052, '\xeb', and '\012' is a scalar expression with a non-zero value (0xA and 052 are integer literals in hexadecimal and octal format, respectively, while '\xeb' and '\012' are escape sequences representing character values in hex and octal format), so the bodies of all the if statements are executed.
You have four nested if statements, and only the innermost one is doing anything interesting. The else clauses are empty and can be omitted entirely:
#include<stdio.h>
int main( void )
{
if(0xA)
{
if(052)
{
if('\xeb')
{
if('\012')
{
printf("Hello World!")
}
}
}
}
And, as I said above, the curly braces may be omitted as well:
#include<stdio.h>
int main( void )
{
if(0xA)
if(052)
if('\xeb')
if('\012')
printf("Hello World!")
}
All of which reduces to
int main( void )
{
printf("Hello World!")
}
A reasonably smart compiler won't bother generating the machine code for the if statements at all, and should generate machine code as though the program had been written as above.

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.

macro syntax induced error

I the following code and a small little part of it didn't make sense because it was beyond the knowledge I have currently and I was wondering if someone could clear this little problem out for me
stack.h
#ifndef _STACK_H
#define _STACK_H
#include "lis1.h"
typedef List Stack ;
#define stack_init list_init
#define stack_destroy list_destroy
#define stack_size(stack) (stack)->size
#define stack_is_empty(stack) ((stack)->size==0)?1:0
int stack_push(Stack*stack,void*data);
int stack_pop(Stack*stack,void**data);
#endif
please note the #define stack_is_empty(stack) ((stack)->size==0)?1:0 carefully
and on compilation of the following program ,
#include<stdio.h>
#include"stack.h"
static char ams[5] = { 'h', 'e', 'l', 'l', 'o' };
void* data;
Stack stack;
char*ss;
void debug(int a)
{
printf(" debug %d \n", a);
}
int main()
{
stack_init(&stack, NULL);
debug(1);
int i;
for (i = 0; i < 5; i++)
{
stack_push(&stack, (void*) (&ams[i]));
};
debug(2);
while (printf("checker\n") && stack_is_empty(&stack) != 1)
{
printf("->");
printf("[%d ", stack_size(&stack));
stack_pop(&stack, &data);
printf("%c]", *((char*) data));
printf("--\n");
};
return 0;
}
I get this
debug 1 debug 2 checker
->[5 o]-- checker
->[4 l]-- checker
->[3 l]-- checker
->[2 e]-- checker
->[1 h]-- checker
segmentation fault
but if I change #define stack_is_empty(stack) ((stack)->size==0)?1:0
to #define stack_is_empty(stack) (((stack)->size==0)?1:0), there is no seg fault
My Query
My question why did the program work perfectly fine in the former case until the conditional spews a '1'..I seem to understand why the latter works.
In C, a macro is just substituted textually, with no regard to whether it produced the expression that you might expect.
Without the parentheses, your while loop condition expands to:
printf("checker\n")&&((&stack)->size==0)?1:0!=1
Which is interpreted as:
(printf("checker\n") && ((&stack)->size==0)) ? 1 : (0 != 1)
The printf thus becomes part of the condition for this ternary expression, but that's doesn't cause a problem, it returns the number of bytes printed which will be interpreted as true as long as it's non-zero. Then you perform an and with your actual condition, the part that checks the stack size. If the stack size is equal to zero, this returns 1, or true. If the stack size is not equal to zero, this returns the result of (0 != 1), which is always true. So this condition always returns a true value, and the while loop keeps going, even after it's run out of items on the stack.
When you add the parentheses, it's interpreted as you expected:
printf("checker\n") && ((((&stack)->size==0)) ? 1 : 0) != 1)
When writing macros that expand to an expression, you should always have a pair of parentheses around the result, to ensure that it is interpreted as a single expression, rather than operator precedence rules possibly causing the expression to be interpreted differently than you intended.
I should note that there is a lot of redundancy in this statement. You are checking the value of a boolean expression, (&stack)->size==0 to see if it is true, returning 1 if it is and 0 if not. But the == already returned a 1 if it was true and a 0 if not; there's no need for the ternary operator. Then you use != 1 to see if it's false. But how do you get false from a boolean expression? Simply use the not operator, !. You can skip the ternary operator and != 1 comparisons entirely:
#define stack_is_empty(stack) ((stack)->size==0)
while (!stack_is_empty(&stack)) {
// ...
}
Remember that C macros are just text replacement, NOT expression evaluations.
Using your umbra keyed stack_is_empty, your if condition becomes :
While (printf("checker\n") && ((&stack)->size)==0)?1:0!=1) {
Trouble is, the != operator has high precedence, so it effectively becomes :
While (printf("checker\n") && ((&stack)->size)==0)?1: (0!=1) ) {
Since 0 != 1, that while loop is going to keep going beyond the size of your stack.
After the macro substitution
printf("checker\n")&&stack_is_empty(&stack)!=1
becomes
printf("checker\n")&&((&stack)->size==0)?1:0!=1
because the ternary operator ?: has a fairly low precedence, this is equivalent to:
(printf("checker\n") && ((&stack)->size==0)) ? 1: (0 != 1)
Note that printf("checker\n") always returns a true value(because it returns how many characters it prints), so the check (&stack)->size==0) is never evaluated due to shortcut circuit.
Advice: always use enough parenthesis in macro definition.

(Extreme Noob here) Why wont this C code work?

Why won't this work, I'm very new to programming but I can't seem to figure out why this wont work correctly.
#include <stdio.h>
#include <math.h>
int main(){
int num1;
printf("Enter 1, 2, 3.");
scanf("%d", &num1);
if(num1 = 1)
printf("You entered one");
else if(num1 = 2)
printf("You entered two");
else if(num1 = 3)
printf("You entered three");
else
printf("Invalid");
}
In C it is valid to use assignment (int x = 5) within a conditional (if statement).
For example:
int x = 0;
if (x = 5)
{
}
This will evaluate to true (it returns 5 to the "if" and all non zero terms are true by convention) if the assignment could be done and the value != 0. Which, in this case, it can be done and returns 5.
You were likely looking for this:
int x = 0;
if (x == 5)
{
}
This will evaluate to false (0).
Remember: You use a single equal sign "=" to mean "assignment". Use a double equal sign "==" to mean "comparison".
Replace all the = with == and you should be fine (because = is used for assignment, while == is used to test for equality, which seems to be what you want to do)
In C, as in other many programming languages, the = operator means "assignment". When you do a = 3, that means "assign a with 3", which of course it's something that succeeds and returns true, that's why your program will always enter the first branch.
What you have to do is use the "equality testing" operator, ==, so that a == 3 returns true if and only if the value held by variable a is 3.
Your code having one mistake you have taken = instead of ==, in C = operator means assignment operator while== operator is used for comparision.
To clear about your doubts regarding operators read this link
http://www.tutorialspoint.com/cprogramming/c_operators.htm
And because you started with int main() just for compiler reasons put return 0; at the end of your program to be more correct.
It doesn't work because you need to change the = sign to ==. You use the equal sign sometimes when you declare a int or char. == is meaning equal to and you want to use that when your not declaring ints and chars.While != means not equal.You should also put a return 0; at the end of your program.

Resources