0
gets(s);
for(;s[i];){
   f&=(s[i++]<'a');
}
for(i=0;s[i];){
   putchar(s[i++]^f*32);
}

I don't know how s[i++]^f*32 works, I have never seen this expression before and I would like to know how it works, I know it uppercases letters if f is 1 but why is it to the 32th power and why to the 0 power it makes it lowercase

Abhishek Dutt
  • 1,308
  • 7
  • 14
  • 24
  • 3
    `^` isn't the power operator but the XOR operator. Please [read a book first](https://stackoverflow.com/q/388242/995714). See [Why is my power operator (^) not working?](https://stackoverflow.com/q/4843304/995714). See also [Why is the gets function so dangerous that it should not be used?](https://stackoverflow.com/q/1694036/995714). `gets` has been removed completely from newer C and C++ standards – phuclv Mar 21 '21 at 10:13
  • 2
    Not sure why that code was written in such unreadable way. I'd recommend clearing all that and rewriting the logic from scratch. As Martin Fowler said: “Any fool can write code that a computer can understand. Good programmers write code that humans can understand”. [Here](https://stackoverflow.com/q/735204/5935112) is a bunch of solutions that you can use for uppercasing the text. – Just Shadow Mar 21 '21 at 10:30
  • What are the initial values of `f` and `i`? – i486 Mar 21 '21 at 10:41
  • I've updated my answer, I believe there's a bug in your code. – Dominique Mar 21 '21 at 10:59

2 Answers2

2

As mentioned in the first comment, ^ indeed is the XOR operator, not the power. In top of this, there are consequences for the order of the operators, as you can see here:

s[i++]^f*32     // a piece of your code
=(s[i++]^f)*32  // due to the order of operators, this is the same thing.

What does this mean for some values, let's say s[i++]=7 and f=9?

Binary, this is the situation:

s[i++]      = 0111
f           = 1001
s[i++]^f    = 1110
s[i++]^f*32 = 111000000

The result of this is 7*64=252.

As far as uppercase and lowercase are concerned, it might be interesting to know that, in ASCII, there is a simple relation between those, let's show you this example:

"A" = 65 = 1000001
"a" = 97 = 1100001

"A" XOR 32 = "a"
"a" XOR 32 = "A"

I believe this is what you are looking for (but I don't understand the logic behing the f variable).

Edit

Based on the comments:

Your code is wrong, it should be the following:

s[i++]^(f*32)

In case f is 1, this flips s[i++] between lowercase and uppercase. In case f is 0, it does nothing.

Dominique
  • 16,450
  • 15
  • 56
  • 112
  • It seems `f` variable is 1 if all letters are uppercase and 0 otherwise (even if 1 letter is lowercase). – i486 Mar 21 '21 at 10:42
  • Considering `f` equal 9 may be important as a part of a general discussion of the operator, but has no meaning in this problem, as `f` can only be 0 or 1 here. (Assumed `f` is zero initially, which the presented excerpt of code doesn't show.) (It must be ONE initially, see the comment by @i486.) – CiaPan Mar 21 '21 at 10:43
  • @CiaPan `f` must be 1 initially, otherwise it will always be 0. – i486 Mar 21 '21 at 10:43
  • @i486 Right, I somehow read `xor` instead of `and` there. – CiaPan Mar 21 '21 at 10:45
  • In case my answer solves your issue, please accept it (this is how this site works). – Dominique Mar 22 '21 at 11:21
0

Here's the magic behind it.

If you take a closer look at the ASCII table, you'll notice that the ASCII codes of the uppercase and lowercase of the same letter differ with value 32.

So, for example the ASCII code of A is 65 while for a it's 97 and 97 - 65 = 32.
This means if you take any capital letter (from ASCII) and +32 to it, you'll get the lowercase of the same letter. And -32 for uppercase again.
'A' + 32 = 0100 0001 + 0010 0000 = 0110 0001 = 'a'

Another interesting thing, is that instead of +-32 for upper/lower casing you actually can invert the 6th bit of the character. This will have exact the same result because 32 = 0010 0000 (pay attention that for 32 sixth bit is 1).

And we can use XOR (^) operation there for that inversion.
So, 'A' ^ 32 = 'a' and 'a' ^ 32 = 'A'

A : 65 = 0100 0001  
               XOR
    32 = 0010 0000  
           |  
           v  
a : 97 = 0110 0001

Now let's get back to the code of the question.
Starting from the second part of the code:

for(i=0;s[i];){
   putchar(s[i++]^f*32);
}

What it does, it just iterates over the string s and does inversion ^32*f based on the value of f. So, if the f is 1 it will do inversion, if 0 then not (as 32*f = 0).
And the value of the f is based on the other part of the code:

for(;s[i];){
   f&=(s[i++]<'a');
}

which determines whether all the characters of the original s where capital letters or not. It does that by checking if the characters are <'a' (as all the capital letters in ASCII are <'a').

P.S. As others also stated, the fix should be s[i++]^(f*32).
The brackets are important there because of the operator precedence.

P.P.S In general I'd recommend rewriting that code to make it more readable.
You might want to take a look at the other solutions here.

Just Shadow
  • 10,860
  • 6
  • 57
  • 75
  • There are character encodings out there in the world that are not ASCII. This code can all be written portably with functions from the standard library, without hard-coding ASCII dependencies. In general, if you're writing "magic" code, you're doing something wrong. – Pete Becker Mar 21 '21 at 14:29
  • Totally agree! I was recommending the same in a comment of the question itself. – Just Shadow Mar 22 '21 at 07:40
  • @RobertGaube glad that it helped. Feel free to mark it as an answer to make it easier for the others to find this question/answer :) – Just Shadow Mar 22 '21 at 15:31