questions about a function that act like scanf - c++

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.

Related

What is (ch - '0')? C++ [duplicate]

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.

C++ character counter

I need to design a character counter, whenever I enter single char. it gives me the next one in succession e.g. enter A, it shows B, Z-->A for both lower and Upper letters. only using (for loop)
What went wrong?
The characters doesn't show in order I mean whenever I enter a letter it's random response giving me a random number that hasn't any function of the program the body looks acceptable but in turns of internal details something isn't going the way I wanted to be. Here's my code:
char count[256];
int size = 0;
for ( c != 0; ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) ; c++ )
{
size += count[c];
}
return size;
return 0;
using ASCI codes will be helpfull here
for e.g
char alphabet ;
cout <<"Enter alphabet"<<endl;
cin>>alphabet ;
int a = (int) alphabet;
a++;
cout<<"Next alphabet is :"<<(char)a<<endl ;
Take your input
Check if it is an alphabet
Check if it is a 'z' or 'Z', if so, make it an 'a', or 'A' (hint: use ascii codes and a little arithmetic)
Else add a character to it
Print

C++ caesar cipher — understanding ascii keys

I am currently doing a caesar cipher program. It should encrypt for both lower and upper case.
e.g
If I typed in a, it will then shift the keys by 3 and the final output will become d.
Take a look at my codes
char c;
c = (((97-52)+3) % 26) + 52;
cout << c;
The letter 'a' has an ASCII code of 97.
So by right
1) ((97-52)+3) will give you 48
2) 48 % 26 will give you 8 since 48/26 will give you a remainder of 8.
3) 8 + 52 = 60(which will by right give you a value of '>' according to the ascii table)
but my output that I have got is J and I don't understand which am I getting the output of 'J' instead of '>'
My concepts might be wrong so I need help.
Let me link ASCII chart I use first: http://pl.wikipedia.org/wiki/ASCII
The website is polish, but table itself is in english.
I think it's plainly obvious that problem is the equatation you use:
(((letter-52)+3) % 26) + 52;
Actually first letter in ASCII is 65(hexadecimal 0x41 - follow with the chart provided).
Your idea with the modulo would be fine, if there were no chars between letter blocks in ASCII. But there are (again check up chart).
That is why you should manually check if the sign:
is a capital letter: if (letter >= 0x41 && letter <= 0x5a)
is a non-capital: if (letter >= 0x61 && letter <= 0x7a)
Usually when making Ceasar cipher, you should follow these:
Replace a capital letter with capital letter moved in the alphabet by a given number.
If the letter would be out of alphabet scope, continue iteration from the start of alphabet (X moved 5 to the right would give C).
Other chars stay the same
Now let's implement this (in code I'll use letter values of chars - to avoid mistakes):
#include <iostream>
#include <cstdlib>
using namespace std;
string Ceasar(string input, int offset)
{
string result = "";
for (int i = 0; i < input.length(); ++i)
{
// For capital letters
if (input[i] >= 'A' && input[i] <= 'Z')
{
result += (char) (input[i] - 'A' + offset) % ('Z' - 'A') + 'A';
continue;
}
// For non-capital
if (input[i] >= 'a' && input[i] <= 'z')
{
result += (char) (input[i] - 'a' + offset) % ('z' - 'a') + 'a';
continue;
}
// For others
result += input[i];
}
return result;
}
int main()
{
cout << Ceasar(string("This is EXamPLE teXt!?"), 8).c_str();
system("PAUSE");
}

C++ manipulating numbers in ASCII to stay only in range of letters

#include <iostream>
using namespace std;
Int main() {
cout<<"Give me a letter" <<endl;
char letter;
cin>>letter;
cout<<letter;
(Int)letter;
letter+=2;
cout<<(char)letter;
(Int)letter;
letter-=25;
cout<<(char)letter;
return 0;
}
How would I manipulate the numbers in a way so that the numbers will always output a letter.
ie: if the letter z was chosen and adding 2 is a symbol how would I manipulate it in a way so that it will always stay between the numbers for capital numbers and uncapitalized numbers. Thanks. Please try to keep answers at a beginner level please I am new to this.
if(letter > 'z') {
//do stuff
}
if(letter < 'a' && letter > 'Z') {
//do stuff
}
if(letter < 'A') {
//do stuff
}
It just depends on how you want to handle the character when it goes into one of the three ranges on the ASCII chart in which the characters are not letters.
As a side note, you don't have to cast a char to an int to do math with it.
char myChar = 'a' + 2;
cout << myChar;
This will print: c
c has an ASCII value of 2 more than a.
The surest method is to use a table for each category, and do
your arithmetic on its index, modulo the size of the table.
Thus, for just lower case letters, you might do something like:
char
transcode( char original )
{
char results = original;
static std::string const lower( "abcdefghijklmnopqrstuvwxyz" );
auto pos = std::find( lower.begin(), lower.end(), results );
if ( pos != lower.end() ) {
int index = pos - lower.begin();
index = (index + 2) % lower.size();
results = lower[ index ];
}
return results;
}
This solution is general, and will work regardless of the sets
of letters you want to deal with. For digits (and for upper and
lower case, if you aren't too worried about portability), you
can take advantage of the fact that the code points are
contiguous, and do something like:
char
transcode( char original )
{
char results = original;
if ( results >= '0' && results <= '9' ) {
char tmp = results - '0'
tmp = (tmp + 2) % 10;
results = tmp + '0';
}
return results;
}
An alternative implementation would be to use something like:
results = results + 2;
if ( results > '9' ) {
results -= 10;
}
in the if above. These two solutions are mathematically
equivalent.
This is only guaranteed to work for digits, but will generally
work for upper or lower case if you limit yourself to the
original ASCII character set. (Be aware that most systems today
support extended character sets.)
You can test directly against ASCII chars by using 'x' notation. Further, you can test things together using && ("and" respectively"):
if ('a' <= letter && letter <= 'z') {
// Letter is between 'a' and 'z'
} else if ('A' <= letter && letter <= 'Z')) {
// Letter is between 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}
Or you can use the standard library function std::isalpha which handles this for you:
if (std::isalpha(letter)) {
// Letter is between 'a' and 'z' or 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}

How does this array conversion work ( lowercase to uppercase using a string)?

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);