1

while solving a leetcode challange , I stumbled upon various solutions that were adding and subtracting '0' for successful submission and I have no idea why . any help? I mostly do linked list and array so this problem is quite new to me .

class Solution {
public:
string addBinary(string a, string b) {
    string result;
    int i=a.size()-1;
    int j=b.size()-1;
    int carry = 0;
    while(i>=0 || j>=0|| carry)
    {
        if(i>=0)
           { carry += a[i] - '0';//like here
            i--;}
         if(j>=0)
         { carry += a[j] - '0';//here 
          j--;
         }
        result += (carry%2 + '0'); //and here as well
        carry = carry/2;
    }
    reverse(result.begin(),result.end());
    return result;
}

};

  • Because we don't want to use magic numbers. That is, we want the program to be as portable as possible. – Jason Apr 17 '22 at 17:52
  • 1
    The character values that represent the digits `'0'..'9'` are required to be contiguous and increasing, so subtracting `'0'` converts a digit character to the value that it represents. So `'0'-'0'` is 0, `'1'-'0'` is 1, etc. – Pete Becker Apr 17 '22 at 17:52
  • 2
    Do you understand the difference between `1` and `'1'`? – aschepler Apr 17 '22 at 17:56

2 Answers2

0

In C++, '0' is a character literal.

The fundamental reason why/how a[i] - '0' works is through promotion. This is because:

arithmetic operators do not accept types smaller than int as arguments, and integral promotions are automatically applied after lvalue-to-rvalue conversion, if applicable

In particular when you wrote:

a[i]-'0'

This means

both a[i] and '0' will be promoted to an int. And so the result will be an int.

Let's looks at some example for more clarifications:

char c1 = 'E';
char c2 = 'F';

int result = c1 + c2;

Here both c1 and c2 will be promoted to an int. And the result will be an int. In particular, c1 will become(promoted to) 69 and c2 will become(promoted to) 70. And so result will be 69 + 70 which is the integer value 139.

This also makes the program more portable than using magic numbers.

Also note that the C++ Standard (2.3 Character sets) guarantees that:


  1. ...In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous.

For example, say we have:

std::string str = "123";
int a = str[0] - '0'; //the result of str[0] - '0' is guaranteed to be the integer 1
int b = str[1] - '0'; //the result of str[1] - '0' is guaranteed to be the integer 2
int c = str[2] - '0'; //the result of str[2] - '0' is guaranteed to be the integer 3

Lets consider the statement int a = str[0] - '0';:

Here both str[0] and 0 will be promoted to int. And the final result that is used to initialize variable a on the left hand side will be the result of subtraction of those two promoted int values on the right hand side. Moreover, the result is guaranteed to be the integer 1.

Similarly, for statement int b = str[1] - '0';:

Here both str[1] and 0 will be promoted to int. And the final result that is used to initialize variable b on the left hand side will be the result of subtraction of those two promoted int values on the right hand side. Moreover, the result is guaranteed to be the integer 2.

And similarly for variable c.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 4
    Also, I don't think this "works because of promotion". There is a promotion, but it doesn't work because of promotion any more than adding two shorts together works because of promotion. – eerorika Apr 17 '22 at 17:58
  • 1
    @eerorika I am explaining how the expression `a[i] - '0'` works and so i think it is essential to point out what is happening behind the scene. Similarly, for adding two shorts together. – Jason Apr 17 '22 at 18:06
  • 2
    I agree that it's useful to explain promotion. But I don't agree with "works because of promotion". – eerorika Apr 17 '22 at 18:07
  • @eerorika This is how the standard defines addition(which is an arithmetic operation) of 2 character literals. First promotion happens and then addition. Ofcourse, **promotion is a step in the whole process and itself is not the cause**. – Jason Apr 17 '22 at 18:10
  • If the standard didn't define that integer operands promote, then that wouldn't necessarily mean that integer operations cannot be performed. Hence, promotion isn't what "makes" integer operations "work". It does affect how they work. – eerorika Apr 17 '22 at 18:12
  • @eerorika Promotion is not the cause of the process, but while explaining how the expression work, it is not incorrect to say that *"fundamental reason why/how a[i] - '0' works is through promotion"*. I use the phrase fundamental reason to emphasize on the fact that promotion is an integral part of the working. This is not to be interpreted/confused with "that it is the cause of ". Promotion is a step in the whole process and is itself not the cause. – Jason Apr 17 '22 at 18:19
  • 2
    @eerorika Also, i never used the term *"works because of"*. I said *"works through promotion"*. If it is your wish to morph someone words and then do the interpretation then you're free to do so. – Jason Apr 17 '22 at 18:27
  • "Reason why X works is Y" means "X works because of Y" to me. On the other hand, I'm not a native speaker. – eerorika Apr 17 '22 at 18:29
  • 3
    @eerorika I used *"why/how"* and not just *"why"*. Whatever makes more sense to you, you can interpret it that way. Moreover, i clearly said that promotion is not the cause. – Jason Apr 17 '22 at 18:32
  • 1
    This totally misses the point, which is that subtracting `'0'` from a digit character gives the value that the digit represents. – Pete Becker Apr 17 '22 at 19:02
  • @PeteBecker I have added that part in my now edited answer. – Jason Apr 17 '22 at 19:31
  • Thank you sir, well explained. – Shashank Srivastava Apr 18 '22 at 15:07
0

It seems to be converting strings' characters to its numeric values. For instance, if you define "char c = '0';", you had indeed stored the ASCII code (or equivalent string encoding) of the char '0' in variable c, not the value zero itself. So to get the actual numeric value out of the ASCII code, you have to subtract by the ASCII code from the char '0'.

Remember that strings are a sequence of numeric values, i.e., integers representing characters, using the ASCII Table or equivalent, depending on the string encoding being used (Unicode, etc...).

Please note the actual characters' numeric values will depending on the actual encoding being used. The most known and basic Encoding is probably ASCII, which does not support languages other than the original english. For international purposes, the most common nowadays is UNICODE UTF-8, which uses basically the same codes used by ASCII for plain English usual characters, but other more complicated encodings exist.

And, as correctly noted by Anoop Rana in the other answer to this question, the C++ standard guarantees the numeric values will be in a sequence in any encoding. So, by using this technique, you avoid magic numbers that would make your code work just with specific encodings.

Here goes a didactic code that may help:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    const string str = "5";
    cout << "char: " << str << endl;
    cout << "ASCII char's value: " << (int)str[0] << endl;
    cout << "ASCII char's value of the character '0' is: " << ((int)'0') << endl;
    cout << "Value represented by the ASCII code " << str[0] << 
        " is the binary value " << (int)str[0] << "-" << ((int)'0') <<
        "=" << (str[0] - '0') << endl;
    

    return 0;
}

The output is:

char: 5
ASCII char's value: 53
ASCII char's value of the character '0' is: 48
Value represented by the ASCII code 5 is the binary value 53-48=5

The ASCII table code can be consulted here: https://www.asciitable.com/

By the way, I think there may be a bug in your code, since parameter b is not being used. Maybe the second 'if' should be taking the value of b instead of a?

AQTS
  • 54
  • 5
  • If it was ASCII everywhere this would be much simpler. The rule is that **whatever encoding is used**, `'0'..'9'` must be contiguous and increasing, so subtracting `'0'` gives you the numeric value, regardless of the encoding. Yes, it works for ASCII, but it works for every other valid character encoding, too. – Pete Becker Apr 17 '22 at 19:01
  • Yes, good point. Well, I tried to be didactic. And UTF-8 codes' values coincide with ASCII table in those basic set of characters as well, so I mentioned ASCII table and posted it here to help anyone not familiar with those basic concepts. – AQTS Apr 17 '22 at 19:08
  • I will try to improve the explanation, fell free to edit it (or ask me to do so, in case you are not satisfied and don't have permission to edit). – AQTS Apr 17 '22 at 19:14
  • In this case [EBCDIC](https://en.wikipedia.org/wiki/EBCDIC#Code_page_layout) encoding was probably more of a concern than UTF-8. – BoP Apr 17 '22 at 19:45
  • Dear Pete, I tried to upvote your comment but I troubled myself, since I am just starting here, and I ended up undoing it and Stackoverflow does not let me vote again. It is full of restrictions to starters. But reading the other response I realized the standard guarantees it for ANY encoding. I will edit my response too so it can be registered. Thank you. – AQTS Apr 18 '22 at 20:25
  • I also wanted to comment on Anoop answer, a very technical and correct one, but the system says I dont have reputation for that. Maybe not so didactic and this questions seems pretty basic, so my response tried to address it. But I checked the information and it is perfect. I gave and upvote and will edit mine accordingly. – AQTS Apr 18 '22 at 20:28