I am writing a program that takes a char and compares it to see if it's in a range of certain chars. For instance, if the char I get is an n I go to state 3, if its a - m or o - z I go to state 4. I'm new to C++ so I'm still learning.
Can I say something like:
char c = file.next_char();
...
if (c in 'a'...'m', 'o'...'z')
{
state = 3;
} else {
state = 4;
}
There is no such syntax in C++. The options are:
Use a switch statement, when the list of values is generally not contiguous, or
Convert the list of explicit character values into contiguous ranges into equivalent boolean expressions. As you know, alphabetic characters consist of a contiguous range of octets in ASCII, so your pseudo-code is equivalent to:
if ( (c >= 'a' && c <= 'm')
||
(c >= 'o' && c <= 'z'))
If you are using ascii (English), you can rely on the fact that all the lower case letters are adjacent. Just check 'a' <= c && c <= 'z'
after ruling out 'n'.
You never said what happens if the state is not one of those, so I left it alone.
// 3 and 4 mean nothing. Give your states meaningful names
enum state_type {FirstState, SecondState, ThirdState, FourthState};
state_type state = FirstState;
char c = get_next_char();
if ('n' == c){
state = FourthState;
} else if ('a' < c && c < 'z'){
state = ThirdState;
} else {
// no change?
}
You could maybe use a for loop to compare it to see if it's a letter in the first or second range. The code would be something this:
char range1[/*amount in array here*/] = "abcdefghijklmnopqrstuvwxyz";
//Substitute range on line above(the characters in the string)
for(int i = 0; i <= /*amount in array here*/; i++) {
if(range1[i] == /*nameoflettervariablehere*/){
//Code here
}
}
I'm sorry but I don't know of a more efficient way.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
Task:
To register in the system, each resident must come up with a password. The password consists of letters of the Latin alphabet (uppercase and lowercase), as well as numbers from 0 to 9, that is, it is possible to use 62 characters in total. The password length is from 5 to 20 characters. The password is stored in the database in encrypted form, encryption is carried out according to the following algorithm:
The number b of uppercase Latin letters is counted. For each uppercase letter character in the password, a cyclic shift to the right by bb characters is performed (for example, if b=3, then the D character is converted to the G character, the Y character to the B character).
Similarly, for each lowercase character in the password, a cyclic shift to the right is performed by m characters, where m is the number of lowercase letters in the password.
To quickly search for users in the database, a hash function is calculated for each encrypted password using the following algorithm:
All 62 characters are ordered, numbers come first, then lowercase letters, then uppercase letters.
Each character is assigned a code - the number of the character in this sequence, starting from 0. Thus, the digit codes match their values, the lowercase letter code a-10, b-11, etc.
All codes are summed up, and the remainder of the resulting sum s is found from dividing by the numbers p and q. The resulting pair of numbers (s mod p,s mod q) will be the value of the hash function.
A hash function is considered good if collisions rarely occur, that is, the values of the function match for different passwords.
John came up with a new password. At the same time, there are already nn passwords in the database, and I would like to avoid collisions. Will John succeed?
Input data
The first line contains a string representing John's password.
The second line contains an integer n – the number of passwords in the database.
The third line contains integers p and q. The following lines store passwords in unencrypted form.
Output data
An integer is the number of passwords whose hash function matches the hash function of John's password.
Sample Input:
AabB1cd
5
13 17
Nik143pasw
qeAom1
q1w2e3r4t
aBoba2012
N33iEj
Sample Output:
2
Note:
Passwords that match John's hash function are highlighted.
Processing of John's password:
After cyclic shift: CefD1gh (uppercase letters are shifted by 2, lowercase by 4)
The sum of the character codes is 38+14+15+39+1+16+17=140
The hash function is equal to (10,4)
You have a few logic problems in your code. When you are rotating your upper and lower-case characters to their "encrypted" forms, you iterate through the password twice, and sometimes incorrectly rotate the characters. Take for example just the line
if (pas[i] + big >= 'A' && pas[i] + big <= 'Z') pas[i] = pas[i] + big;
Consider the case where pas[i] == '9' and big == 8. You will end up transforming all of your 9's into As.
Now consider the line in the next loop
if (pas[i] + small >= 'a' && pas[i] + small <= 'z') pas[i] = pas[i] + small;
Which will similarly transform some upper-case letters into lower-case if small is large enough.
You can also combine these two problems. Consider the case where pas[i] is originally Y, big is 1, little is 7. You'll transform Y --> Z, and then in the next step transform Z --> a.
Compartmentalize and abstract your single large main function into smaller functional blocks. This will allow you to reason about each piece individually instead of trying to keep the entirely of main() in your head. Humans have limited short-term memory.
Some suggested functions would include
bool is_upper(char c)
bool is_lower(char c)
bool is_numeric(char c)
char rotate_upper(char c, int steps)
char rotate_lower(char c, int steps)
Instead of looping through the password twice on your transformation step, consider looping through the password once. If the character is upper-case, transform accordingly. If it's lower-case, transform accordingly. This will prevent you from double-rotating some numbers.
Combining all of the above, the two encryption loops of your main function could turn from:
for (int i = 0; i < pas.length(); i++)
{
if (pas[i] + big >= 'A' && pas[i] + big <= 'Z') pas[i] = pas[i] + big;
else if (pas[i] >= 'A' && pas[i] <= 'Z') {
int tempVar = big;
while (tempVar > 0) {
if (pas[i] == 'Z') {
pas[i] = 'A';
tempVar = tempVar - 1;
}
tempVar = tempVar - 1;
pas[i] = pas[i] + 1;
}
}
}
for (int i = 0; i < pas.length(); i++)
{
if (pas[i] + small >= 'a' && pas[i] + small <= 'z') pas[i] = pas[i] + small;
else if (pas[i] >= 'a' && pas[i] <= 'z') {
int tempVar = small;
while (tempVar > 0) {
if (pas[i] == 'z') {
pas[i] = 'a';
tempVar = tempVar - 1;
}
pas[i] = pas[i] + 1;
tempVar = tempVar - 1;
}
}
}
to
for (int i = 0; i < pas.length(); i++) {
char c = pas[i];
if (is_upper(c)) {
pas[i] = rotate_upper(c, big);
}
else if (is_lower(c)) {
pas[i] = rotate_lower(c, small);
}
}
You can transform 30 lines of code into just under 10. That's much easier to read for both you, the developer, and for any potential reviewers.
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...
As I have read, the C++ compiler initialize table with the random data, before I initialize it by myself.
I've got a program which after performing (for example) give me this output - char table.
{'D','K','2','EMPTY FIELD','1','+','EMPTY FIELD','EMPTY FIELD','3','EMPTY FIELD','/'}
Now I would like to delete whole inconvenient data like letters, and empty fields.
I'm trying to achieve this by this code, but I think it transfer it into ASCII code. Am I able to achieve this in another way ?
char wynik[20];
int j = 0;
for (int i = 0; i <20; i++)
{
if (wyjscie[i] == '+' || wyjscie[i] == '-' || wyjscie[i] == '/' || wyjscie[i] == '*' || (wyjscie[i] >-241241 || wyjscie[i] < 2141242142 ))
{
wynik[j] = wyjscie[i];
j++;
}
}
(wyjscie[i] >-241241 || wyjscie[i] < 2141242142 ) is your problem. You're confusing the integer values represented by a character and the integer codes of characters. If you want to check if a character c is between 0 and 9 you could do c >= '0' && c <= '9'.
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
}
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"
}