Can I please have some help understanding some bitwise and, and if shorthand? I put comments on what I thought it is.
//Bitwise AND not sure how it decides 32 or 0, then set board[i]
board[i] = (randNum & 1024) ? 32 : 0;
//it the j variable j in the neighborOffset array, then mods it by 2048
//then takes that variable from the board array, then shifts 1 to 32
//then bitwise and of those 2 variables.
if(board[(i + neighborOffset[j]) % 2048] & (1 << 5))
//Not sure about this one. Can someone please explain it?
board[i] |= ((board[i] ^ 34) && (board[i] ^ 35)) ? ( (board[i]^3) ? 0 : (1<<4)) : (1<<4);
//Not sure how it decides if it uses 'X' or ' '
putchar(board[i] ? 'X':' ');
-----------------------------------------------
I figured out this one.
putchar(board[i] ? 'X':' ');
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <stdlib.h>
//#include <dos.h>
int main()
{
int board[2048] = {0};
board[0] = 5;
board[1] = 9;
board[2] = 0;
board[3] = 2;
putchar(board[0] ? 'X':' ');
putchar(board[1] ? 'X':' ');
putchar(board[2] ? 'X':' ');
putchar(board[3] ? 'X':' ');
printf(" \n");
return (0);
}
Output
XX X
The reason on success putchar returns 1.
http://www.cplusplus.com/reference/cstdio/putchar/
Not sure about this one. Can someone please explain it?
board[i] |= ((board[i] ^ 34) && (board[i] ^ 35)) ? ( (board[i]^3) ? 0 : (1<<4)) : (1<<4);
Don't ask for a fish, ask how to catch fish. Instead of explaining this to you, let me teach you how to explain it to yourself.
I don't understand this crazy code any more than you do right now, so I'm going to write down the process that I would use to understand this code.
We begin to understand it by first reformatting it so that indentation gives us a clue:
board[i] |=
((board[i] ^ 34) && (board[i] ^ 35)) ?
((board[i]^3) ?
0 :
(1<<4)) :
(1<<4);
OK, that's not much better. Let's try to understand it by introducing two explanatory variables.
int original = board[i];
int result =
((original ^ 34) && (original ^ 35)) ?
((original ^ 3) ?
0 :
(1<<4)) :
(1<<4);
board[i] = original | result;
That's still not very clear. Let's try to undestand it by turning conditional expressions into conditional statements.
int original = board[i];
int result;
if ((original ^ 34) && (original ^ 35))
{
if (original ^ 3)
result = 0;
else
result = 1 << 4;
}
else
result = 1 << 4;
board[i] = original | result;
Still not very clear, but now we can notice that the structure of the "if" statements is bizarre: we have two possible results, and in one of them all three conditions must be met, so why do we have nested if statements at all? Rewrite.
int original = board[i];
int result;
if ((original ^ 34) && (original ^ 35) && (original ^ 3))
result = 0;
else
result = 1 << 4;
board[i] = original | result;
OK, we're getting a lot simpler now. Let's think about those three conditions. What does
(original ^ 34) && ...
mean? Well, the condition will be considered to be true if and only if the result is not zero, so let's introduce three more explanatory variables and make that clear.
int original = board[i];
int result;
int condition34 = (original ^ 34) != 0;
int condition35 = (original ^ 35) != 0;
int condition3 = (original ^ 3) != 0;
if (condition34 && condition35 && condition3)
result = 0;
else
result = 1 << 4;
board[i] = original | result;
OK, now let's ask ourselves "what does (x ^ y) != 0 even mean? Under what circumstances can this be false? Only if x^y is zero. Under what circumstances can x^y being zero be true? Only if x and y have all the same bits. Under what circumstances can x and y have all bits the same? Only if they are equal. So the condition is false if and only if the operands are equal, and therefore it is true if and only if they are unequal. So we can rewrite this as:
int original = board[i];
int result;
int condition34 = (original != 34);
int condition35 = (original != 35);
int condition3 = (original != 3);
if (condition34 && condition35 && condition3)
result = 0;
else
result = 1 << 4;
board[i] = original | result;
Now we are getting somewhere. Now let's look at the action on board[i]. If result is zero then original|result is a no-op. The only other possibility is that result is 16. So let's rewrite this again, this time to eliminate result:
int original = board[i];
int condition34 = (original != 34);
int condition35 = (original != 35);
int condition3 = (original != 3);
if (condition34 && condition35 && condition3)
{ /* do nothing */ }
else
board[i] = original | 16;
Now let's notice that we can invert the if and eliminate the "do nothing" case:
int original = board[i];
int condition34 = (original != 34);
int condition35 = (original != 35);
int condition3 = (original != 3);
if (!(condition34 && condition35 && condition3))
board[i] = original | 16;
Now we can use the fact that
!(a && b)
is the same thing as
!a || !b
So:
int original = board[i];
int condition34 = (original != 34);
int condition35 = (original != 35);
int condition3 = (original != 3);
if ((!condition34) || (!condition35) || (!condition3))
board[i] = original | 16;
But now we are inverting a not-equals, which seems silly. Turn them into equals and eliminate the inversion.
int original = board[i];
int condition34 = (original == 34);
int condition35 = (original == 35);
int condition3 = (original == 3);
if (condition34 || condition35 || condition3)
board[i] = original | 16;
Now let's eliminate the explanatory variables again:
if ((board[i] == 34) || (board[i] == 35) || (board[i] == 3))
board[i] |= 16;
And there you go. Now we have the program fragment in a form that can be understood. If the board position is 34, 35 or 3, then set the 16 bit, otherwise, do nothing.
I have no idea why someone would want to write the original program fragment when the way I've shown is so much more clear, but sometimes people write strange code.
This is what you do when you encounter code you can't make sense of: rewrite it into exactly equivalent code that you can make sense of. Simplifying complex expressions by extracting sub-expressions into explanatory variables is a great technique for that.
//Bitwise AND not sure how it decides 32 or 0, then set board[i]
board[i] = (randNum & 1024) ? 32 : 0;
The & operator is performing a bitwise AND operation
xxxxxxxxxxx
& 10000000000
--------------
?0000000000
The ? will be 1 if the number had a 1 in the 1024 location and will be 0 other wise.
Once this test is performed if the result was 1 then the anser 32 is returned, else 0 is returned. This if else conditional is performed using the ? ternary operator.
//Not sure how it decides if it uses 'X' or ' '
putchar(board[i] ? 'X':' ');
Here a similar test is being done with the ? ternary check. If the element at board[i] evaluates true then X else ' '
Related
When I am trying to get the input for my variable, it is only meeting one of the requirements (ie: the < 1 requirement) and skips the other requirement even though im using the && operator.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int x;
do {
x = get_int("what is the height of the pyramid?:");
} while (x > 0 && x < 8);
printf("%i", x);
}
I tried just using the x < 8 for the requirement but it still went through when I entered 9, 10, 11 etc.
If you want x to be between 0 and 8 (both ends exclusive), then you need to repeatedly ask for input when this condition is not satisfied.
In other words, when x is outside this range it means x is less than or equal to 0 OR greater than or equal to 8.
That said, I believe the proper input range for that problem set is actually 1-8 (both ends inclusive):
do {
x = get_int("What is the height of the pyramid?: ")
} while (x < 1 || x > 8);
The test is exactly the opposite of your intent. The do/while condition should test a condition for repeating the input and write while (!(x > 0 && x < 8)); or equivalently: while (x < 1 || x >= 8);
It is unclear what your requirements are, but it seems the number should be between 1 and 7 inclusively. If 8 should be included, the test should be modified as while (!(x > 0 && x <= 8)); or equivalently: while (x < 1 || x > 8);
do/while loops are often confusing and error prone. I suggest using a for(;;) aka for ever loop and break statements when conditions are met:
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int x;
for (;;) {
x = get_int("What is the height of the pyramid? ");
if (x == INT_MAX) {
printf("Input error or end of file\n");
return 1;
}
if (x > 0 && x < 8) {
break
}
printf("The height should be between 1 and 7\n");
}
printf("%i\n", x);
return 0;
}
#include <stdio.h>
int main()
{
int x = 2, y = 0;
int m = (y |= 10);
int z = y && m;
printf("%d\n", z);
return 0;
}
Above program gives me output as 1. Below code is giving me output 0 but what is the reason for different outputs here?
#include <stdio.h>
int main()
{
int x = 2, y = 0;
int z = y && (y |= 10);
printf("%d\n", z);
return 0;
}
In
int z = (y |= 10);
y is masked with 10 so set to 10, so y && m is a boolean worth 1 because both y and m are non-zero, assigned to z
Now, in
int z = y && (y |= 10);
y == 0 so && short-circuits, not evaluating the right hand part and not changing the value of y. Therefore, z is set to 0.
Had you used:
int z = y & (y |= 10);
this would have depended on how/in which order the compiler evaluates the operands (implementation defined behaviour to get 0 or 10)
note that && short-circuiting doesn't evaluate the second parameter if the first is zero for a very good reason:
if ((pointer != NULL) && pointer->value == 12) { do_something(); }
this condition checks if the value is 12 but only if the pointer is non-NULL. If the second expression was evaluated first, this could crash.
So I'm trying to create a program where the user enters a 12-bit binary hamming code sequence like "100010010001" and it should print out its corresponding ASCII character, which in this case is 'A'.
I'm trying to get my program to ignore the 4 parity bits which are positioned in _ _ 0 _ 1 0 0 _ 0 0 0 1 and shift the other 8 bits over so they're together. In the else statement, I tried to convert the remaining 8 bits to a character. When I attempt to run the program however, the program crashes after I type my binary sequence and press enter. This is the part of the program that I'm struggling with and I was wondering if someone could help me or give me hints as to what I'm doing wrong?
char charToBin(char usersInput[]) {
char c = " ";
for (int i = 12; i >= 0; i--) {
if((i == 0) || (i == 1) || (i == 3) || (i == 7)){
usersInput[i] = usersInput[i + 1];
}else{
c = strtol(usersInput[i], (char **)NULL, 2);
}
}
return c;
}
For your code, you can't use "strtol" without a twist. The char array that you give to "strtol" may not end with "\0". Also, does not matter what you do your array will always have 12 indexes unless you copy a "\0" to index 9 so that "strtol" know that it is the end of the input.
Also, sometimes loops are not the best. For your case, you already know how many indexes you are working with. There is no point in using a loop. Nonetheless, I wrote two methods and included the test code as an example below.
#include <stdio.h>
/*
* This function generate a hammer binary digit string for testing.
* It does not care about the validity of the hammer bit.
* The array that is passed to this function should be the length of 12.
*/
void generateChar(int value, char * output){
output[0] = '0';
output[1] = '0';
output[3] = '0';
output[7] = '0';
output[2] = (value & 0b10000000) > 0? '1' : '0';
output[4] = (value & 0b01000000) > 0? '1' : '0';
output[5] = (value & 0b00100000) > 0? '1' : '0';
output[6] = (value & 0b00010000) > 0? '1' : '0';
output[8] = (value & 0b00001000) > 0? '1' : '0';
output[9] = (value & 0b00000100) > 0? '1' : '0';
output[10] = (value & 0b00000010) > 0? '1' : '0';
output[11] = (value & 0b00000001) > 0? '1' : '0';
}
/*
* First method.
*
*/
char charToBin(char usersInput[]) {
char c = 0;
c = usersInput[2] == '1'? c | 0b10000000 : c;
c = usersInput[4] == '1'? c | 0b01000000 : c;
c = usersInput[5] == '1'? c | 0b00100000 : c;
c = usersInput[6] == '1'? c | 0b00010000 : c;
c = usersInput[8] == '1'? c | 0b00001000 : c;
c = usersInput[9] == '1'? c | 0b00000100 : c;
c = usersInput[10] == '1'? c | 0b00000010 : c;
c = usersInput[11] == '1'? c | 0b00000001 : c;
return c;
}
/*
* Second method.
*/
char charToBin2(char usersInput[]) {
char temp[9];
int pos = 0;
temp[8] = '\0'; // Protect from overflow.
for ( int i = 2; i < 12; i++ ){
if ( i == 3 || i == 7 ) continue;
temp[pos] = usersInput[i];
pos++;
}
return (char) strtol(temp, (char **)NULL, 2);
}
int main(){
char a[] = "100010010001";
char t[12];
int b;
// Test for method 1
for ( int i = 0; i < 256; i++ ){
generateChar(i, t);
b = charToBin(t);
printf("%d ", (unsigned char) b );
}
printf("\n\n");
// Test for method 2
for ( int i = 0; i < 256; i++ ){
generateChar(i, t);
b = charToBin2(t);
printf("%d ", (unsigned char) b );
}
return 0;
}
if((i == 0) || (i == 1) || (i == 3) || (i == 7)){
usersInput[i] = usersInput[i + 1];
}else{
In here your if (condition), the curly bracket after that is not necessary.
if((i == 0) || (i == 1) || (i == 3) || (i == 7))
usersInput[i] = usersInput[i + 1];
else{
that would fix a bit maybe
You program has two compile error:
You can not assign string to character ( c= " ") ;
The strtol call takes a string, not a character
After fixing the compile error, two fixes are needed to logic:
1. Perform the filtering of the input string from left to right, to avoid copying position 12 to 11, 11 to 10, which will result in duplicating the last positions. An extra counter is needed to help with the compaction.
2. Perform the strtol once, after the input is fully compacted.
char charToBin(char usersInput[]) {
char j = 0 ;
// Copy relevant input positions, INCLUDING terminating NUL byte at position 12.
for (int i = 0; i <= 12 ; i++) {
if((i == 0) || (i == 1) || (i == 3) || (i == 7)){
continue ;
} ;
usersInput[j] = usersInput[i] ;
j++ ;
} ;
char c = strtol(usersInput, (char **)NULL, 2);
return c;
}
Alternatively you could use bit operations. Something like:
char charToBin(char usersInput[]) {
unsigned c = strtol(usersInput, NULL, 2);
unsigned part1 = c & 0xFu;
unsigned part2 = c >> 1u & 0x70u;
unsigned part3 = c >> 2u & 0x80u;
return (char) (part1 | part2 | part3);
}
Which would give with your input of
char userInput[] = "100010010001";
char ch = charToBin(userInput);
printf("result: %c(%d)\n", ch, ch);
the following output on the console:
result: A(65)
What does this function do that helps it to take input differently and how are the conditions in for loop executed?
void scanint(int &x)
{
int flag=0;
register int c = gc();
if(c == '-') flag=1;
x = 0;
for(;(c<48 || c>57);c = gc());//why is this used?
for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;}//how is this executed ?
if(flag == 1)x=-x;
}
It's not c.
void scanint(int &x) {/* Whatever */}
// ^^
This defines a function accepting a reference to an int and there are no references in c, the arguments are passed by value to functions. You could of course use a pointer to an int, but then the body of the function should be changed accordingly, using *x instead of ant occurrences of x.
The following assumes that gc() stands for a function similar to getchar(), so that the posted code is a very bad way of extracting an int value from stdin:
void scanint(int &x) // Or 'int *x' in C
{
int c = gc(); // register was deprecated in C++17
bool is_negative = (c == '-'); // C has bool from C99 too
x = 0; // '*x = 0;' in C. The same applies to the following code
// Considering only ASCII, ignores non-digit characters
// E.g. from " 123" it ignores the first two spaces,
// but, given " -123", it will ignore the sign too. Bad, as I said.
for( ;
( c < '0' || c > '9');
c = gc() )
;
// Now computes the actual number using an old trick that should
// be left to the compiler to be exploited:
// 10 * x = (2 + 8) * x = 2 * x + 8 * x = x << 1 + x << 3 (bit shifts)
for( ;
'0' <= c && c <= '9';
c = gc() )
{
x = (x << 1) + (x << 3) + c - '0';
}
if ( is_negative )
x = -x;
}
I'm a first time programmer trying to complete a simple command line program as part of the first assignment for an online course I am taking, but I seem to have hit a roadblock that I can't figure out with GDB or my own research.
After hours of rewrites, and hours of debugging, I finally got the code below to compile. The program is supposed to take a credit card number as an input, and then check whether it's valid per the specifications of the assignment. I used a test number from here: PayPal Test Credit Cards
The odd thing is, when I enter an AMEX card number, it correctly produces the text "AMEX", but when I try a Visa or a Master Card, it prints "INVALID".
In GDB I broke at the Verify function and it seems to incorrectly skip these two if/else if statements without proceeding to the Checksum function even though conditions appear to be met.
if (firstDigit == 4 && totalDigits == (13 | 16) && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Visa.
...
else if (firstDigit == 5 && secondDigit == (1 | 2 | 3 | 4 | 5) && totalDigits == 16 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Mastercard.
...
The AMEX line of code that correctly executes is:
else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express.
The arguments for all three lines seem to be formatted exactly the same. That is far as I could get in GDB though. I would print totalDigits, firstDigit, and secondDigit in GDB right before stepping through the above two non-executing lines and everything looked correct. So I'm stumped, why is the AMEX line executing, but not the others?
Thanks in advance everyone. This is the first program after hello.c that I've tried to write, so I am open to absolutely any criticism or suggestions if it looks like I'm doing something weird/wrong.
Full code:
checker.c
#include <stdio.h>
#include <stdlib.h>
int MAX = 16;
int* DigitSort(unsigned long long x, int* array);
int Verify(int* array);
int main (void)
{
int* output = malloc (sizeof(int) * (MAX + 2)); // creates a blank array for the individual digits of the card number.
unsigned long long userInput = 0;
do
{
printf("Please enter a credit card number:\n");
scanf("%lld", &userInput);
}
while (userInput <= 0); // checks to make sure the user entered a number.
switch(Verify(DigitSort(userInput, output))) // sorts the user's input into individual digits and verifies the card type and validity.
{
case 1 :
printf("VISA\n");
break;
case 2 :
printf("MASTERCARD\n");
break;
case 3 :
printf("AMEX\n");
break;
case 0 :
printf("INVALID\n");
break;
default :
printf("INVALID\n");
}
free(output);
return 0;
}
int Verify(int* array) // verifies whether or not a card number is valid. Must pass the function a sorted array of individual digits.
{
int* cardNumber = array;
int firstDigit = cardNumber[0];
int secondDigit = cardNumber[1];
int totalDigits = 0;
int Checksum(int* cardNumber, int totalDigits);
int i = 0;
while (firstDigit >= 1 && cardNumber[i] >= 0) // this step counts the number of digits in the array.
{
totalDigits = totalDigits + 1;
i++;
}
if (firstDigit == 4 && totalDigits == (13 | 16) && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Visa.
{
return 1;
}
else if (firstDigit == 5 && secondDigit == (1 | 2 | 3 | 4 | 5) && totalDigits == 16 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Mastercard.
{
return 2;
}
else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express.
{
return 3;
}
else // if the card number doesn't match any of the above conditions or fails the checksum, an 'I' for Invalid is returned.
{
return 0;
}
}
int* DigitSort(unsigned long long x, int* array) // takes a long long as input and sorts it into individual digits
{
int* arrayReversed = malloc (sizeof(int) * (MAX + 2)); // creates a new array to hold the reversed order of digits.
int i = 0;
arrayReversed[0] = 0;
if (i < (MAX - 1) && x >= 10)
{
do
{
arrayReversed[i] = x % 10;
x = x / 10;
i++;
}
while (i < (MAX -1) && x >= 10);
}
if (i < MAX && x >= 1 && x <= 9)
{
arrayReversed[i] = (int) x;
x = (x - x);
}
if (x == 0)
{
int j = 0;
do
{
array[j] = arrayReversed[i]; // sorts the digits from the reversed array and places them into the sorted array.
j++;
i--;
}
while (j < MAX && i >= 0);
array[j] = -1;
}
free(arrayReversed);
return array;
}
int Checksum(int* cardNumber, int totalDigits)
{
int sum1 = 0;
int sum2 = 0;
int i = (totalDigits - 2);
int j = (totalDigits - 1);
while (i >= 0)
{
sum1 = ((cardNumber[i] * 2)%10) + ((cardNumber[i] * 2)/10) + sum1;
i -= 2;
}
while (j >= 0)
{
sum2 = (cardNumber[j] + sum2);
j -= 2;
}
if (((sum1 + sum2) % 10) == 0)
{
return 0;
}
else
{
return 1;
}
}
Your first problem is here:
if (firstDigit == 4 && totalDigits == (13 | 16) && ...
You need to write:
if (firstDigit == 4 && (totalDigits == 13 || totalDigits == 16) && ...
Your first check is looking for 0x1D == 29 as the number of digits (because, as paisanco points out in a comment, the | operator is the bitwise OR operator), and no credit card needs 29 digits (yet, and not for a long time to come). Note the extra parentheses for clarity and accuracy. Don't mess around risking removing them — the code won't work properly again. And in general, be explicit if your condition has both && and || operators and use parentheses to group terms explicitly.
You have similar problems elsewhere. As it happens, (4 | 7) is the same value as 7, so the condition works when the second digit is 7 (but not when it is 4). But it doesn't mean what you intended it to mean.
Computer languages don't work the same as human languages. Get used to writing out the condition somewhat more verbosely. Some other languages provide shorthands for these conditions; C is not such a language.