ROT13 Implementation using Char Arrays - c++

I'm a newbie programmer who has been working on a ROT13 implementation as part of a tutorial and came across the following code. It outputs the correct characters however I'm not quite sure how it works and there is no explanation attached.
char rot13[] = { 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M' };
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < alphabet.length(); i++) {
std::cout << rot13[alphabet[i] - 'A'];
}
Specifically, I dont quite understand how minusing the 'A' from a character within the string alphabet provides us with our ROT13 number. I initially thought that 'A' corresponded to an index within rot13[] and minusing that would provide us with a new index, however wouldn't that indicate that any numbers beneath A's index (Z,Y,X...) would become negative indexes as a result and throw errors.
Is anyone able to explain the logic behind this code to me?

Granted that alphabet[i] is an uppercase letter (which is the case in your example), alphabet[i] - 'A' will compute the distance to the letter 'A' in the ASCII table. So 'A'-'A' will be 0, 'B'-'A' will be 1 and so on, up to 'Z'-'A' which is 25.
Your character array rot13 is written so that the index 0 has the letter 'N', the index 1 is the letter 'O' and so on up to index 12 with the letter 'Z' and then index 13 is 'A', index 14 is 'B' and so on up to index 25 which is 'M'
To make things clearer, let’s rewrite this line:
std::cout << rot13[alphabet[i] - 'A'];
As:
char letterBeforeRot13 = alphabet[i];
int index = letterBeforeRot13 - 'A';
char letterAfterRot13 = rot13[index];
std::cout << letterAfterRot13;
This is pretty much what your compiler does, but with more details.
If we pick an example where alphabet[i] equals to the letter 'A', letterBeforeRot13 is assigned to the letter 'A', index is assigned to 'A'-'A' which is 0, letterAfterRot13 is assigned to the element of the array rot13 at index 0, which is 'N'. So the letter 'A' is transformed into 'N'.
You can do the same for any letter and you will see that everything is fine, including the edge cases when you thought that things would be out of bounds. You cannot have negative indexes with this technique.

Related

Alphabet that moves with an "offset". In circular direction

Hi, I don't know how to solve this. I am having problems with the 'cycle' that should occur when z is exceeded or a negative offset is placed that exceeds a. I think I would have to rethink the whole program. Sorry for my english and I hope you can help me or guide me :)
**Write a C++ program (with only if and else) to encode a letter. The encoding consists of returning the letter of the alphabet that is offset places to the right or to the left of the entered letter. The location to the right is given when the offset value is positive. On the other hand, if the offset value is negative the offset will be to the left. An offset value of 0 is considered invalid.
In the right path, after the letter z, the letter a is considered to be coming. The same for the uppercase alphabet, if the entered letter is uppercase.
On the left path, if the letter a is exceeded, the letter z is considered as coming. The same for the uppercase alphabet, if the letter entered is uppercase.
It is required to validate that the values entered are valid:
The value of the offset must be in the range (-26;26) and different from 0.**
let's consider all your letters are not capital which will make things easier.
char* encodeMessage(const char* input, int arraySize, int offset) {
char* encoded = (char*) malloc(arraySize);
for(int i=0;i<sizeof(input) / sizeof(char);i++) {
if(input[i] >= 'a' && input[i] <= 'z') {
char newLetter = input[i] - 'a';
newLetter += offset;
newLetter = newLetter % 26;
if(newLetter < 0) {
newLetter += 26;
}
encoded[i] = newLetter + 'a';
// added this condition to avoid encoding null characters
} else {
encoded[i] = input[i];
}
}
return encoded;
}
you can easily modify it to encode capital letters.

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
}

C++ place char in corresponding slot in array

I need to store a letter a-z char to its corresponding slot in a size 0 - 25 array in c++. What's the best way to do this without a lot of if statements?
You can determine character index the following way:
int index = yourCharacter-'a';
And then use that index to store what you need
To work out the index just subtract 'a' from a char variable that holds the characters a-z. For example:
char c='x';
int index=(int)(c-'a');
Is this what are you looking for?
char c;
...
arrayName[c - 'a'] = value;
Edit
Not homework, so I'll clarify my answer.
const char * letters = "abcdefghijklmnopqrstuvwxyz";
Stores the letters from 'a' to 'z' in in an array. (Note that the array size is 27, not 26, because of the null character at the end of the string.)
Characters are just integers, so you can do arithmetic on them.
char c = ...;
array[c - 'a'] = c.
Note that upper case characters are distinct from lower case ones, so you'll need to handle them separately (if required).
if (c >= 'A' && c <= 'Z')
c += 'a' - 'A'; // make lower case
If you want to be portable, you can't use the solution proposed by most
others: 'a' to 'z' are not necessarily contiguous. The surest
solution is to look the letter up in a table, and use the index of that
table, e.g.:
char letters[] = "abcdefghijklmnopqrstuvwxyz";
int index = std::find( begin( letters ), end( letters ) - 1, ch )
- begin( letters );
if ( index < size( letters ) - 1 )
// it's good
else
// character wasn't a (lower case) letter.
Note the - 1 for end and size: this is because letters has an
additional '\0' at the end.
Note that in a lot of cases, on a modern machine, it may be just simpler
to use an array of 256 entries; the difference in space isn't likely to
cause you to run out of memory, and the code to manage it will be a lot
simpler.
char letters[26];
for (char c = 'a'; c <= 'z'; c++)
{
letters[c - 'a'] = c;
}

C++ string manipulation / input

This is for homework! But I need help anyway. The assignment is to input a sentence then output the number of words, and the number of occurrences of each letter. The output must have the letters in alphabetical order. So far, I've been able to count the number of words and get all the letters to lower case so that I'll be able to keep count of them. My question is how to actually keep count of the letters.
Example of output:
I say Hi.
3 words
1 a
1 h
2 i
1 s
1 y
Here's the code that I have so far:
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
int letters[26];
char letter;
int word = 0;
cout << "Please enter a sentence: "<< endl;
do
{
cin.get(letter);
if(isspace(letter))
word++;
letter = tolower(letter);
cout << letter;
}
while (letter != '\n');
cout << "The number of words = " << word << endl;
return 0;
}
Should I input directly into a C-string? or will that mess up the word count?
If you're allowed to use STL, use std::map for mapping letters to counters. It will additionally sort the letters.
Otherwise, treat chars as indexes in an array of counters and increment them.
My question is how to actually keep
count of the letters
It's fairly straight forward. Simply create an array of 26 integers, (one for each letter), and initialize it to zero.
int letters[26] = { 0 }; // Initialize array to zero
Each value in the array corresponds to a count of a particular letter. Array index 0 refers to 'a', array index 1 refers to 'b', and so on. Then, everytime you encounter a letter, increment the appropriate value in the array. You can use the character 'a' (ASCII value 97) as a starting offset. So, given the variable char letter; you would do:
++letters[tolower(letter) - 'a'];
But always make sure that before you increment the appropriate value in the array, you check that isalpha(letter) && islower(letter) to make sure that your letter is in the range of lowercase a-z; otherwise you will access an index beyond the bounds of the array. You can also test for this condition by saying if (letter >= 'a' && letter <= 'z').
Hint: tolower(letter)-'a' is:
0 if letter is a
1 if letter is b
...
Hm, just few points to make your home task more useful to you (and your code more correct):
Think what happens if you have file with several spaces in a row (word counting).
Think how to be more correct with 'letters' (check for isalpha() at least). Also isalpha() could be key for simpler counting with fixed array [256] (this might be even the best solution as for performance vs std::map usage, check std::map documentation anyway).
Think about more effective file input. At least line at once.

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"
}