Reading variable length user input in C++ - c++

How do I read in a variable number of characters? The user can input a positive or negative number that is too big to be stored in an integer. I am then checking to make sure the char is a number and storing it in an array of ints (although that will probably be changed to a short since I only need to be able to store 0-9).
istream& operator>>(istream &in, LargeInt &l)
{
char x;
do
{
cin >> x;
int v = (int)x;
switch( v )
{
case 48: v = 0;
case 49: v = 1;
case 50: v = 2;
case 51: v = 3;
case 52: v = 4;
case 53: v = 5;
case 54: v = 6;
case 55: v = 7;
case 56: v = 8;
case 57: v = 9;
default: v=10 /* END INPUT */;
}
l.largeInt[ l.usedLength ] = v;
l.usedLength++;
//need to check array length and make bigger if needed
}
while( (x == 45) || ((x > 47) && (x < 57)) );
}

If you wish to read digits, you need to do it a character at a time. E.g.
char ch;
while (std::cin.get(ch) && ch >= '0' && ch <= '9') {
// You have a digit to process (maybe you want to push_back it into a vector)
}
Notice that you need to use ch - '0' to get the value of the digit because ch contains the character code rather than the value. In ASCII this means that '0' is in fact 48, '1' is 49 and so on (and 'A' is 65). The values may be different for different character encodings but the digits are guaranteed by the standard to be sequential, so that subtracting zero works.

Why not input a string, and then convert it to a number?

A few points. First of all, if you only need to store values from 0 to 9, you might as well store them in a char (which is just a small integer type in C++).
Second, you probably need to add a break; to the end of all the cases in your switch statement -- in C++, execution falls through from one case to the next without a break to stop it. Then again, you should probably just get rid of the switch statement entirely. You'd probably be better off using isdigit from <ctype.h>. Since char is a small integer type in C++, you can also do math on it, so you could just subtract '0' from each digit after verifying that it is a digit. Edit: contrary to the later edit, I would strongly advise against subtracting 48 from each digit. First of all, it's not guaranteed to work (and won't with some character sets -- even if you don't think your code will ever be used on an IBM mainframe, it's a poor habit). Second, it makes the intent much more apparent. I don't think there's a good reason to expect the reader to have memorized the ASCII table so they'll know that 48 is equivalent to '0'.
Finally, to deal with the problem you knew you had, you'll probably want to look up std::vector.

Related

Using getchar_unlocked()

I recently learnt that using getchar_unlocked() is a faster way of reading input.
I searched on the internet and found the code snippet below:
But I am unable to understand it.
void fast_scanf(int &number)
{
register int ch = getchar_unlocked();
number= 0;
while (ch > 47 && ch < 58) {
number = number * 10 + ch - 48;
ch = getchar_unlocked();
}
}
int main(void)
{
int test_cases;fast_scanf(test_cases);
while (test_cases--)
{
int n;
fast_scanf(n);
int array[n];
for (int i = 0; i < n; i++)
fast_scanf(array[i]);
}
return 0;
}
So, this code takes input for an integer array of size n for a given number of test_cases . I didn't understand anything in the function fast_scanf, like why this line:
while (ch > 47 && ch < 58)
{ number = number * 10 + ch - 48;
why the register is used while declaring ch?
why the getchar_unlocked() is used twice in the function? and so on..
It would be great help if someone elaborates this for me. Thanks in advance!
Okay, since what you are asking needs to be explained clearly, I am writing it here... so I don't jumble it all up inside the comments...
The function: (Edited it a bit to make it look like more C++-standard)
void fast_scanf(int &number)
{
auto ch = getchar_unlocked();
number= 0;
while (ch >= '0' && ch <= '9')
{
number = number * 10 + ch - '0';
ch = getchar_unlocked();
}
}
Here, take up consideration by looking at the ASCII Table first, since you won't understand how the results are coming up if you don't...
1) Here, you have a character ch takes up the input character from the user using getchar_unlocked() (The auto keyword does that automatically for you and is only usable in C++, not C)...
2) You assign the variable number to zero so that the variable can be re-used, note that the variable is a reference so it changes inside your program as well...
3) while (ch >= '0' && ch <= '9')... As pointed out, checks whether the characters is within the numerical ASCII limit, similar to saying that the character has to be greater than or equal to 48 but less than or equal to 57...
4) Here, things are a little bit tricky, Variable number is multiplied with the product of itself and 10 and the real integer value of the character you stored)...
5) In the next line, ch is reassigned so that you don't have to stay in the loop forever, since ch will remain that number forever if the user doesn't type anything... remember a loop goes back to where it was declared after reaching the end, checks if the condition is true, continues if it is true else breaks)...
For example: 456764
Here, ch will first take 4 then the others follow so we go with 4 first...
1) Number will be assigned to zero. While loop checks if the given character is a number or not, if it is continues the loop else breaks it...
2) Multiplication of 0 with 10 will be zero... and adding it with difference 52 (that is '4') with 48 (that is '0') gives you 4 (the real numerical value, not the char '4')...
So the variable number now is 4...
And the same continues with the others as well... See...
number = number * 10 + '5' - '0'
number = 4 * 10 + 53 - 48
number = 40 + 5
number = 45... etc, etc. for other numbers...

What approach should I take towards converting ascii chars to other chars in c++

Well currently I am re creating my own version of enigma as a little project but if you understand how the enigma machine works it has rotors which connect a character to a completely different character for example A might be connected to F or U may be connected to C and this is done three times. Currently I am getting the char for the rotor by using this function:
char getRotorOne(char i) {
if(i == 'a') {
return 'g';
}if(i == 'b') {
return 'A';
}if(i == 'c') {
return 'o';
}
The main problem with this is it takes a long time to write and it seems inefficient and I think there must be a better way. The other problem with this is on the original enigma machine there were only the 26 letters of the alphabet on this there are the 94 tapeable characters of ascii (32-126) is there any other simpler way that this can be done? If you think this question is unclear or you don't understand please tell me instead of just flagging my post, then you can help me improve my question.
Use tables! Conveniently, C string literals are arrays of characters. So you can do this:
// abc
const char* lower_mapping = "gAo";
// ABC
const char* upper_mapping = "xyz";
char getRotorOne(char i) {
if (i >= 'a' && i <= 'z') return lower_mapping[i - 'a'];
if (i >= 'A' && i <= 'Z') return upper_mapping[i - 'A'];
assert(false && "Unknown character cannot be mapped!");
}
Since chars are really just small integers, and ASCII guarantees contiguous ranges for a-z and A-Z (and 0-9) you can subtract from a given character the first one in its range (so, 'a' or 'A') to get an index into that range. That index can then be used to look up the corresponding character via a table, which in this case is just a simple hardcoded string literal.
This is an improvement on Cameron's answer. You should use a simple char array for each rotor, but as you said you want to process ASCII characters in the range 32-126, you should build each mapping as an array of 95 characters:
char rotor1[95] ="aXc;-0..."; // the 95 non control ascii characters in arbitrary order
Then you write your rotor function that way:
char getRotorOne(char i) {
if ((i < 32) || (i > 126)) return i; // do not change non processed characters
return rotor1[i - 32]; // i - 32 is in range 0 - 94: rotor1[i - 32] is defined
}

Homemade Vigenere cipher; working with acsii character manipulation

As the post title suggests, I'm working to strengthen my grasp on C++ and character manipulation, this time through creating a Vigenere Cipher. For those unfamiliar with it, it's a fairly simple way to encrypt a text file.
The basic way it works is that there exists a string "key", and each character (in my case at least) is a lowercase alphabetical character. These are stored into an array and are used to "shift" the value of the file being encoded. A character of 'a' will shift the target by 0, while 'z' will shift it by 25. The "shift" is cyclical, meaning that if 'z' is shifted by 'b' (1) it should result in an 'a'.
My current method is found below:
//Assume cipher[] contains "[a][b][c][x ][y ][z ]" Cipher is a <string> object
//Assume ptr[] contains "[0][1][2][23][24][25]
#A whole bunch of includes
char c;
ifstream is;
ofstream os;
is.open(argv[3]) //"myinput.txt"
os.open(argv[4]) //"myoutput.txt"
int i = 0;
while( is.good() ) {
c = is.get();
if( is.good() ) { //did we just hit the EoF?
c = tolower( c - 0 ); //just make sure it's lowercase
c = c + ptr[ i % cipher.size() ] % 26;
if( c> 122 )
c = ( c % 123 ) + 97;
i++;
os.put( c );
}
}
My problem lies in my modulo operations, I believe. Maybe it's because I've spent so much time hashing this out, but I spent hours last night writing this, and then another hour lying in bed trying to wrap my mind around how to effectively create what I want:
grab char.
check char. //let char = 'z'
check the cipher. //let the cipher = 'y'
eval cipher shift //'y' shift value = 24
shift z 24 places (cyclically) //'z'==25, 25+24=49, 49%26=23. 23='x'
HERE IS THE ISSUE: How to do this with ACSII? ('a'=97, z='121')
Imagine that you want to "shuffle" the "ones" digits 0-9 between 20 and 29 by two steps, such that 20 becomes 22, and 29 becomes 21,. How would you do that?
Well, I would subtract 20 [our base number], and then shuffle the remaining digit, and then add 20 back in again.
newnum = num - 20;
newnum %= 10;
newnum += 20;
The same principle would apply for ascii - just that of course the base isn't 20.

How do I use the switch statement?

I am trying to understand the switch statement better. I don't need the code but kinda a walkthrough on how it would be done.
If someone enters a 7 digit phone number EG. 555-3333 but enters it as "jkl-deff" as it would correspodnd to the letters on the dial pad, how would I change the output back to numbers?
Would this work:
switch (Digit[num1])
case 'j,k,l':
num1 = 5;
break;
case 'd,e,f':
num1 = 3;
break;
To do that with a switch statement, you'd have to walk through the char array, switching on each character. Group all the chars that have the same number together.
Something like
switch (phoneChar[i])
case 'a':
case 'b':
case 'c':
newChar[i] = '2';
break;
That said, I'm not sure that switch case is the best way to do that. I don't know what would be the best off the top of my head, but something feels wrong about this :)
Edit
The i would be the index of the current character under consideration. You'll have a 7 (or 8 or 10 or 12 character string depending on formatting) for a phone number. You'd have to take each character at a time.. so phone[0] = 'j' in the above example.
I would not use a switch!
// A,B,C => 2; D,E,F => 3 etc.
static int convert[] = {2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9,9};
for(int loop =0 ;loop < Digit.size(); ++loop)
{
num = convert[Digit[loop] - 'a'];
// Thus the character 'a' gets mapped to position 0
// the character 'b' gets mapped to position 1 etc.
// num is then the character mapped into the covert[] array above.
}
You could probably do it like this:
if (islower(c)) { num=(c-'a')/3; num = 2 + (num==8) ? 7 : num; }
to convert a character to a phone pad digit. The num==8 part at the end handles the exra digit on the 9 key.
Altogether it would look like this:
char c = getNextCharacterSomehow();
int num = -1;
if (isdigit(c)) num = c-'0';
else if (islower(c)) { num=(c-'a')/3; num = 2 + (num==8) ? 7 : num; }
else if (isupper(c)) { num=(c-'A')/3; num = 2 + (num==8) ? 7 : num; }
Also, a note about the switch statement: The item that comes between the "case" and the ":" has to have the same type as the thing specified by the "switch()" portion. And that type must be a scalar, which excludes things like strings.

Caesar cipher in C++

To start off, I'm four weeks into a C++ course and I don't even know loops yet, so please speak baby talk?
Okay, so I'm supposed to read a twelve character string (plus NULL makes thirteen) from a file, and then shift the letters backwards three, and then print my results to screen and file. I'm okay with everything except the shifting letters. I don't want to write miles of code to take each character individually, subtract three, and re-assemble the string, but I'm not sure how to work with the whole string at once. Can someone recommend a really simple method of doing this?
If you are dealing with simple letters (A to Z or a to z), then you can assume that the internals codes are linear.
Letters are coded as numbers, between 0 and 127. A is coded as 65, B as 66, C as 67, Z as 90.
In order to shift letters, you just have to change the internal letter code as if it were a number, so basically just substracting 3 from the character. Beware of edge cases though, because substracting 3 to 'A' will give you '>' (code 62) and not 'X' (code 88). You can deal with them using "if" statements or the modulo operator ("%").
Here is an ASCII characters table to help you
Once you've loaded your string in, you can use the modulous operator to rotate while keeping within the confines of A-Z space.
I'd keep track of whether the letter was a capital to start with:
bool isCaps = ( letter >= 'A' ) && ( letter <= 'Z' );
if( isCaps )
letter -= 'A'-'a';
and then just do the cipher shift like this:
int shift = -3;
letter -= 'a'; // to make it a number from 0-25
letter = ( letter + shift + 26 ) % 26;
// add 26 in case the shift is negative
letter += 'a'; // back to ascii code
finally finish off with
if( isCaps )
letter += 'A'-'a';
so, putting all this together we get:
char *mystring; // ciphertext
int shift = -3; // ciphershift
for( char *letter = mystring; letter; ++letter )
{
bool isCaps = ( *letter >= 'A' ) && ( *letter <= 'Z' );
if( isCaps )
*letter -= 'A'-'a';
letter -= 'a';
letter = ( letter + shift + 26 ) % 26;
letter += 'a';
if( isCaps )
letter += 'A'-'a';
}
You're going to have to learn loops. They will allow you to repeat some code over the characters of a string, which is exactly what you need here. You'll keep an integer variable that will be your index into the string, and inside the loop do your letter-shifting on the character at that index and increment the index variable by one until you reach NULL.
Edit: If you're not expected to know about loops yet in your course, maybe they want you to do this:
string[0] -= 3; // this is short for "string[0] = string[0] - 3;"
string[1] -= 3;
string[2] -= 3;
...
It will only result in 12 lines of code rather than miles. You don't have to "reassemble" the string this way, you can just edit each character in-place. Then I bet after making you do that, they'll show you the fast way of doing it using loops.
Iterate over the characters with a for loop. And do what you want with the char*. Then put the new char back.
for(int i=0; i<12; i++){
string[i] = string[i] - 3;
}
Where string is your character array (string). There is a bit more involved if you want to make it periodic (I.E. have A wrap round to Z, but the above code should help you get started)
I'm a little unclear what you mean by "shift the letters backwards 3"?
Does that mean D ==> A?
If so, here's a simple loop.
(I didn't do reading from the file, or writing to the file... Thats your part)
#include <string.h>
int main(void)
{
char input[13] = "ABCDEFGHIJKL";
int i;
int len = strlen(input);
for(i=0; i<len; ++i)
{
input[i] = input[i]-3;
}
printf("%s", input); // OUTPUT is: ">?#ABCDEFGHI"
}