In all standardised character sets the character '0' (which prints as a zero on screen) has a non-zero numeric value.
There are a number of reasons for this - including the convention (used in C) of using a character with numeric value of 0 being used to mark the end of a string of characters. This convention, if '0' had a numeric value of zero, mean that it would not be possible to represent a value like 100 as a string (every digit '0' would mark the end of the string).
In character sets compatible with ASCII, '0' has a numeric value of 48. There are standardised character sets with '0' having a different numeric value.
Fortunately, in all standardised character sets, the arabic numerals ('0', '1', .... '9') are a contiguous set so, if x is a character containing an arabic numeral, x - '0' will convert x to its corresponding numeric value (e.g. '0' - '0' gives an integral value of 0, '1' - '0' is 1, etc).
So, when examining digits presented in a string, it is necessary to subtract '0' from each to convert it to its numeric value. For example, adding the characters of "12" as 10*'1' + '2' will (for an ASCII character set) give a value of 540, but subtracting '0' from each character (i.e. 10*('1' - '0') + ('2' - '0') will give 12.
This can be demonstrated in the following code snippet.
#include <iostream>
int main()
{
char digit = '0';
std::cout << digit << '\n'; // will print 0 (followed by newline)
std::cout << (int)digit << '\n'; // for an ASCII character set will print 48
std::string test = "12";
int incorrect_sum = 0;
int correct_sum = 0;
for (const auto c : test)
{
incorrect_sum *= 10;
incorrect_sum += c;
correct_sum *= 10;
correct_sum += c - '0'; // note the correction here
}
std::cout << incorrect_sum << ' ' << correct_sum << '\n'; // will print 540 and 12
}