This question already has answers here:
Convert a character digit to the corresponding integer in C
(14 answers)
How to convert a single char into an int [duplicate]
(11 answers)
understanding c-'0'
(7 answers)
Closed 2 years ago.
I have a Parse program that parsing arithmetic expressions in the expression class there is a function parse here is it;
//function parse
void express::parse(){
char ch;
char lastVal;
char lastop;
for(int j=0;j<len;j+=1){
ch = pStr[j];
if(ch>= '0' && ch <= '9'){
s.push(ch - '0');
}else if(ch =='+' || ch == '-' || ch == '/' || ch == '*'){
if(s.getTop() == 1){
s.push(ch);
}else{
lastVal = s.pop(); // number
lastop = s.pop(); // operator
//if ch is * or / && lastop + or -
if((ch == '*' || ch == '/') && (lastop == '+' || lastop == '-')){
s.push(lastop);
s.push(lastVal);
}else{
switch(lastop){
case '+': s.push(s.pop() + lastVal);break;
case '-': s.push(s.pop() - lastVal);break;
case '*': s.push(s.pop() * lastVal);break;
case '/': s.push(s.pop() / lastVal);break;
default: cout << "Unkowen Number"; exit(1);break;
}//end switch
}//end if
s.push(ch);
}//end if
}//end if
}//end for
};
and the s.pop() that is a stack class to hold the character whether it a number or an operator and to help me make the operation first of the '*' , '/' so I need to know what is the that statement means s.push(ch - '0');?
is it about the ASCII code or what i don't know but when I erase it the result change.
What you are doing by ch - '0' is that you are effectively converting the character (e.g. '9') to the actual numerical value (the number 9)!
s.push(ch - '0');
ch here is a character of the input string. It is of type char which in C++ is an integral type (having a width of CHAR_BITS bits, which is 8 bits on almost every system you would encounter nowadays), so you can do arithmetic operations on it.
'0' is a character representing digit zero "0".
ch - '0' converts a character to a corresponding integer number. '0' -> 0; '1' -> 1 and so on. It uses the fact that C++ standard requires digits to occupy sequential codes, see [lex.charset/3]: "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." In ASCII character encoding digits occupy sequential codes (see https://en.wikipedia.org/wiki/ASCII) starting from 48: character '0' has code 48, '1' has code 49, etc.
s.push() pushes a resulting integer onto a stack.
Related
Currently, I'm having some trouble implementing a parse integer program I've made. I get two yellow lines appearing under the function when it is called in the program
using namespace std;
char parseInt(char userInput[40], char& integers);
int main()
{
char userInput[40];
char integers[40];
cout << "After you enter string input, the program will parse all the integers "
<< "inside the string and display them. \n Enter a string: \n";
cin.ignore();
cin.getline(userInput, 40);
parseInt(userInput, integers); //Here lies the problem
cout << "The integers inside the string you entered were: \n" << integers;
return 0;
}
char parseInt(char userInput[40], char& integers)
{
int j = 0;
for(int i = 0; i<sizeof(userInput); i++)
{
if( userInput[i] == 1 || userInput[i] == 2 || userInput[i] == 3 ||
userInput[i] == 4 || userInput[i] == 5 || userInput[i] == 6 ||
userInput[i] == 7 || userInput[i] == 8 || userInput[i] == 9 ||
userInput[i] == 0 )
{
integers = userInput[i];
j++;
}
}
}
When the parse Int function is called, the two error messages I'm getting are :
-cannot bind rvalue (char) (char*) (&integers) to '(char&)'
-invalid conversion from 'char*' to char [-fpermissive]
I'm just having a hard time understanding exactly what the error codes are trying to say, I'm trying to understand them more.
Many bugs here.
sizeof(userInput) doesn't work like you expect (user4581301 mentioned this in a comment). userInput is a parameter, and due to parameter type adjustment.
The type of a function is determined using the following rules. The type of each parameter (including function parameter packs) is determined from its own decl-specifier-seq and declarator. After determining the type of each parameter, any parameter of type "array of T" or of function type T is adjusted to be "pointer to T". After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type.
As a result, your loop only goes up to sizeof (char*).
You are reading in a string but checking the numeric value of each character. Don't expect that '1' == 1, it's not true on any character encoding in common use. (EloyBG mentioned this one)
You declared integers as a reference to just one integer, but tried to pass a whole array. (Ilan mentioned this)
You're trying to stuff many values into a reference to just one integer. (EloyBG mentioned this too, but his fix is misleading for the same reason as #1)
Reaching the end of a non-void function is illegal, you have to return a value or leave abnormally (user4581301 mentioned this too)
The C way to fix it would be to pass the length of the array as a separate parameter. In C++, you can use a reference to array to either enforce a fixed length or even infer the actual length:
void parseInt(char (&userInput)[40], char (&integers)[40])
Parameter adjustment only changes arrays, not references to arrays, and therefore your sizeof attempt will again work.
In parseInt, integers is declared like single character but you are passing an array. Furthermore, you compare userInput as integer instead of as ASCII.
void parseInt(char userInput[40], char integers[40])
{
int j = 0;
for(int i = 0; i<sizeof(userInput); i++)
{
if( userInput[i] == '1' || userInput[i] == '2' || userInput[i] == '3' ||
userInput[i] == '4' || userInput[i] == '5' || userInput[i] == '6' ||
userInput[i] == '7' || userInput[i] == '8' || userInput[i] == '9' ||
userInput[i] == '0' )
{
integers[j] = userInput[i];
j++;
}
}
}
If you use your code,
It return a single character by reference, but not return a chain of characters.
char parseInt(char userInput[40], char& integers)
{
int j = 0;
for(int i = 0; i<sizeof(userInput); i++)
{
Here, you are comparing the userInput with the first elements of the ASCII table.
if( userInput[i] == 1 || userInput[i] == 2 || userInput[i] == 3 ||
userInput[i] == 4 || userInput[i] == 5 || userInput[i] == 6 ||
userInput[i] == 7 || userInput[i] == 8 || userInput[i] == 9 ||
userInput[i] == 0 )
{
In the next line, you change the value of the single character but you do not adding a new character, because it is not a array (I supuse you got the idea because you declare j)
integers = userInput[i];
j++;
}
}
}
In the main,
cin.ignore()
is unnecesary,it makes that you lose the first character of the chain.
Declare integers like an array of characters
Compare userInput as ASCII not as integer (you can compare it as integer but you have to use the integer that corresponds with the character on the ASCII table)
Delete the cin.ignore() line
You are passing in char integers[40] into a function that it's second parameter requires a char to be passed by reference.
change char& to char[40]
char parseInt(char userInput[40], char integers[40])
I am wondering about the function below.
inline int nextInt()
{
register int s = 0, ch;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
for (s = ch - '0', ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())
s = s * 10 + ch - '0';
return s;
}
I know that this function behaviors scanf function-like by returning the integer value. However, I didn't understand the function's detailed procedure because many variables are in for loops and it is a little bit confused to me to understand correctly. Even though I copied and pasted them on my visual studio and see each value in variables by printf, but I failed to know what they are doing.
Could you explain above codes to me about what they are doing line by line?
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
reads and ignores characters until it gets something in the range 0-9.
for (s = ch - '0', ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())
s = s * 10 + ch - '0';
stores the numeric value of the last-read ascii character into s (e.g. '1' puts 1 into s). Then it reads the next character into ch. Then it tests if ch is a numeric digit. If so, it multiplies the existing value of s by 10 and adds the numeric value of ch. Now it reads another character and proceeds to the test again.
If you type 123, it reads '1' and stores 1 into s. Then it reads '2', multiplies s (1) by 10 (10) and adds 2 (12). Then it reads '3', multiplies s (12) by 10 (120) and adds 3 (123).
First line
register int s = 0, ch;
The register keyword is an outdated storage specifier telling the compiler to keep a value in a processor register (outdated because nowadays the compilers are very good at making that decision themselves, and the register keyword is ignored anyway).
From the presence of this keyword, I conclude that this is very old code. For any modern compiler, the above can safely replaced with
int s = 0, ch;
Second line
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
Let's rewrite this into the equivalent while loop:
ch = getchar();
while (ch < '0' || ch > '9')
{
ch = getchar();
}
Now it's easier to see what it does: It reads a character, and as long as it is not a digit, discards it and reads the next character.
In the name of DRY (don't repeat yourself), it would better be written using a do while loop:
do
{
ch = getchar();
} while (ch < '0' || ch > '9');
Third and fourth line
for (s = ch - '0', ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())
s = s * 10 + ch - '0';
Let's again replace it with an equivalent while loop:
s = ch - '0', ch = getchar();
while (ch >= '0' && ch <= '9')
{
s = s * 10 + ch - '0';
ch = getchar();
}
The s = ch - '0', ch = getchar() is just two expression statements combined with the comma operator. The comma operator just ignores the value of its first argument after evaluating it, and returns the value of the second. It is used here because there can only be one initializer statement in a for and for some reason the author of that code thought he must cram both in there. So let's split it now in two statements:
s = ch - '0';
ch = getchar();
The expression ch - '0' just evaluates the value of the digit. This uses the fact that the type char actually is an integer type, and 0 really is the character code for the digit 0. Also it makes use of the requirement that all ten digits are consecutive in the character set.
The variable s stores the integer read so far. Since so far only one digit has been read, the integer read so far is just the value of the digit we read.
The second statement here of course just reads the next character.
The loop now runs as long as the next character read is still a digit.
The statement
s = s * 10 + ch - '0'
effectively appends the next digit to s. Multiplying by 10 just "appends a zero", and adding (ch - '0') then replaces that final 0 with the digit value.
Note that to avoid overflow (and thus undefined behaviour) when reading a number close to INT_MAX, this should actually read
s = s * 10 + (ch - '0');
Alternatively, given that this code can only read positive numbers anyway, the author could just have used an unsigned type, as there overflow behaviour is well defined.
OK, let's break it down:
inline int nextInt()
The inline keyword is a hint to the compiler that this function is small and should be "inlined" (basically a little optimization that inserts the function into source code rather than making it a function call).
register int s = 0, ch;
The register keyword, for all practical intents and purposes and in 99.99% of cases, is semantically meaningless, making this line equivalent to int s = 0, ch;.
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
This line is a little silly. It's actually calling getchar() twice, meaning that it pulls in (potentially) two characters, compares one of them to ensure it's between 0 and 9, and keeps going if it isn't. A better way to write this might be do ch = getchar(); while (ch < '0' || ch > '9');.
for (s = ch - '0', ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())
s = s * 10 + ch - '0';
These two lines, in effect, keep multiplying s by 10 while pushing a new integer into the ones column as long as the user keeps entering integers. If the user enters 8 1 3 4, the resulting integer will be 8134.
This question already has answers here:
How do you convert char numbers to decimal and back or convert ASCII 'A'-'Z'/'a'-'z' to letter offsets 0 for 'A'/'a' ...?
(4 answers)
Closed 7 years ago.
The following code basically takes a string and converts it into an integer value. What I don't understand is why the int digit = s[i] - '0'; is necessary. Why can't it work by using int digit = s[i] instead? What purpose does the -'0' have?
int main(){
string s = "123";
int answer = 0;
bool is_negative = false;
if (s[0] == '-')
{
is_negative = true;
}
int result = 0;
for (int i = s[0] == '-' ? 1 : 0; i < s.size(); ++i)
{
int digit = s[i] - '0';
result = result * 10 + digit;
}
answer = is_negative ? -result : result;
cout << answer << endl;
system("pause");
}
Firstly, in your question title
the use of '0'
should be written as
the use of s[i] - '0'
That said, by subtracting the ASCII value of char 0 (represented as '0'), we get the int value of the digit represented in char format (ASCII value, mostly.)
It's because the value inside s[i] is a char type.
To convert the char '1' into an integer, you do '1' - '0' to get 1. This is determined by position in the ASCII table, char '0' is 48, while char '1' is 49.
The reason for the subtraction is that s[i] is, for example, '6'. The value '6' evaluates to 54 (the ascii code). The ASCII code of '0' is 48. So '6' - '0' = 6, which is the char value expressed as an int.
I got the program to work as expected, but can anyone explain how it works?
#include <iostream>
using namespace std;
int main(void) {
int exit;
string name;
cin >> name;
for (int i = 0; i < name.length(); i++) {
// the line below is the one I don't understand
if ('a' <= name[i] && name[i] <= 'z') name[i] = char(((int)name[i]) - 32);
}
cout << name;
cin >> exit;
return 0;
}
EDIT: Let me rephrase:
The thing I don't understand is how does the string-to-array deal work, as in:
'a'<= name[i]. What exactly does this compare and how?
EDIT2
Thanks for the quick responses guys, love you all. I figured it out.
This is the line:
if('a'<=name[i] && name[i]<='z')name[i]=char(((int)name[i])-32);
broken down:
if( 'a'<=name[i] ) {
if( name[i]<='z' ) {
// name_int is a temporary, which the above code implicitly creates,
// but doesn't give a name to:
int name_int = name[i];
name_int = name_int - 32;
name[i] = char(name_int);
}
}
and note that 32 happens to equal 'a'-'A' in the character encoding you are using.
(Technically name_int should be an int&& or somesuch, but no need to be that confusing.)
I assume from the edit in your comment that you are wondering how the [] can apply to a string object. The operator [] is overloaded for string to return a reference to the character at the specified position offset of the represented string. There need not be any direct conversion of the string into an array. The code that implements the overload could well be walking a linked list. It depends on how string was implemented.
It assumes ASCII character format where to convert from lowercase to uppercase you subtract 32 from the original ASCII value. This is because the ASCII values for uppercase are smaller than those for lower case and it's a constant difference between A and a, B and b and so on.
For reference: http://www.asciitable.com/
'a' <= name[i] && name[i] <= 'z'
This line is comparing the corresponding ASCII values of these two characters. 'a' in ASCII is 97 and 'z' is 122. If name[i] is one of the characters from 'a' to 'z' the expression returns true. This is commonly used to check if a variable is alphabetic.
if ('a' <= name[i] && name[i] <= 'z')
char objects are numeric values similar to ints. So 'a' <= name[i] is simply testing if the numeric value of 'a' is less than or equal to the character you're examining. Combined with name[i] <= 'z' and you're testing if the numeric value of name[i] is between the values of 'a' and 'z'. Now, it just so happens that the most common scheme for assigning numeric values to chars, named "The American Standard Code for Information Interchange" (ASCII), has the alphabet arranged in order; 'a' + 1 = 'b', 'b' + 1 = 'c', and so on. So figuring out if the character is between 'a' and 'z' tells you if it's a lower case letter.
name[i] = char(((int)name[i]) - 32);
Once you know that chars are just numeric values you might infer from the basic properties of arithmetic which we all learned in grade school that 'a' + ('A' - 'a') results in the value 'A'. Further, ASCII has the upper case alphabet arranged similarly to the lower case alphabet so that 'A' + 1 = 'B', etc. So taking anycharin the lower case alphabet and adding'A' - 'a'will result in the upper case version of that letter. In ASCII'A' - 'a'` happens to have the value -32. So take the numeric value for a lower case letter, subtract 32, and you have the value for the upper case letter.
For comparison here's a version of the code that doesn't depend on ASCII:
auto l = std::locale();
if (std::islower(name[i], l))
name[i] = std::tolower(name[i], l);
I have a char * which contains year and month lets say YYYYMM. How can I compare MM within the range of 01 to 12 ? Do I have to do atoi for the substring and do it or anything else exists?
If the first character of the month portion of the string is '0' the second must be between '1' and '9' inclusive to be valid. If the first character is '1' the second must be between '0' and '2' inclusive to be valid. Any other initial character is invalid.
In code
bool valid_month (const char * yyyymm) {
return ((yyymm[4] == '0') && (yyymm[5] >= '1') && (yyymm[5] <= '9')) ||
((yyymm[4] == '1') && (yyymm[5] >= '0') && (yyymm[5] <= '2'));
}
You can do atoi() of the substring or you can simply compare the ASCII values. For example:
if (buf[4] == '0')
{
// check buf[5] for values between '1' and '9'
}
else if (buf[4] == '1')
{
// check buf[5] for values between '0' and '2'
}
else
{
// error
}
Either way is acceptable. I guess it really depends on how you will eventually store the information (as int or string).
Assuming your char* variable is called "pstr" and is null terminated after the MM you can do:
int iMon = atoi(pstr + 4);
if ( (iMon >= 1) && (iMon <= 12) )
{
// Month is valid
}