Have 2 questions regarding my decryption program, something is off C++ - c++

so there's something in my program that is not going the way I feel like it should go. If I could get some help I would appreciate it. I'll explain how it's supposed to work first and follow up with my questions starting with the most important one since I'm stuck on it and it isn't allowing me to progress.
So I wrote an encryption program that asks the user to input a string and then it encrypts it and creates a file called "secret.dat" and puts the encrypted phrase in there.
If the user were to put in the phrase:
hello world 123
it would send this into the file:
11spwwzshzcwoh234&6#12
The "11" indicates how many letters the letter was shifted to the right by. This is followed by the phrase he entered in encrypted. The '&' character shows where the encryption ends. Each space in his phrase uses the previous letter and shifts it over by 4 and finally after the '&' character it tells the number location of where the spaces are seperated by a '#' character.
The current program I am writing decrypts the "secret.dat" file and shows his phrase on the screen.
This is what I have so far:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
//Declare Variables
int shift;
ifstream inData;
string input;
string output;
int length;
//Open file
inData.open("secret.dat");
//Begin program
inData >> shift;
getline(inData, input, '&');
length = input.length();
for (int count = 0; count < length; count++)
{
if (input[count] >= 'a' && input[count] <= 'z')
{
output += ((input[count] - 'a' - shift) % 26) + 'a';
}
else if (input[count] >= '0' && input[count] <= '9')
{
output += ((input[count] - '0' - shift) % 10) + '0';
}
}
//Declare variables for location of spaces
int i = 0;
char ignore;
int spaces[20];
int location;
//Begin finding the spaces
while (!EOF)
{
inData >> location;
spaces[i] = location;
inData >> ignore;
}
//Preview each result to compare and make sure they are working right
cout << shift << endl;
cout << input << endl;
cout << output << endl;
cout << spaces[0] << endl;
cout << spaces[1] << endl;
return 0;
}
This is what I get as a result
11
spwwzshzswoh234
helloh]oXld]'()
4704512
0
Obviously the last 3 lines are not working correctly (NOTE: this is not how I am going to display it, I just printed these to the screen so that I could see what the result was and make sure it was correct, which it isn't).
So, my first and most important question is why my while loop isn't working correctly. It gives me a bunch of random numbers in the first array slot when it should put a 6 in the first spot, then it should skip the next character and then put a 12 in the second spot in the array which it just puts a 0 there. If I just call an integer from the file outside of the while loop it gives me a 6 no problem so I'm unsure on why it is doing this. I figured it would put the first integer in the first slot in the array, then skip the next character, then put the next integer in the array and skip the next character and so on until the end of the file. This part is what's keeping me from proceeding in the program so I put this as the most important.
Second, what's wrong with my formula for shifting the characters back? I used this same exact formula for shifting the characters forward for my encryption program except I added shift so I assumed just subtracting the shift would decrypt it.
Thanks for anyone willing to help!

In your encryption scheme, the character 'h' stands for the letter 'w' in clear text.
Let's work through how your code tries to decode this:
if (input[count] >= 'a' && input[count] <= 'z')
{
output += ((input[count] - 'a' - shift) % 26) + 'a';
}
input[count] is character "h". 'h' - 'a' is 7. Your value of "shift" is 11.
Your expression calculates (7-11) % 26, or -4 % 26.
Pop quiz: what's -4 % 26? You'd be surprised to learn that the answer is -4. Adding -4 to 'a' produces the character ']', which is what you see, in the corresponding position, in your output.
To fix this, change this line to read:
output += ((input[count] - 'a' - shift + 26) % 26) + 'a';
And change the other line, for digits, in the same way.

Related

Number of words in C++

I was asked to do a program for an assignment which sounds something like this:
Create a program to which you pass a text file with any number of words separated by a colon. The program will create a new file where the letters of the alphabet will be written (from A to Z), each on a new line, followed by a number of words from the input file that begins with the respective letter of the alphabet.
At first, it appeared to be quite easy to me. I was able to read the file, find the first letter in all the words and get them to appear in the console.
Here is the point that I am stuck on. I have no clue how to proceed. I am aware that I should use an array, which I could later use to get the required numbers, but I am not for the love of god able to make it work.
Here is what I came up with so far:
#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
#include <stdio.h>
using namespace std;
int main() {
ifstream fin("test.txt");
char ch;
string word;
int alphabet [26];
while (fin.get(ch))
{
if (isspace(ch))
{
continue;
}
else if (ch == ':') // found the end of a word
{
char first_letter = toupper(word[0]);
cout << first_letter << '\n';
word.clear();
}
else
{
word += ch;
}
}
if (word.size() > 0)
{
char first_letter = toupper(word[0]);
cout << first_letter << '\n';
}
}
Just to clarify. The input should look something like this - video:Elizabeth:Martin:service:work:place:British:file:stream:movie:song:quake:love:hate:York etc
And the output should look like this -
A 0
B 1
C 0
D 0
E 1
F 1
G 0
H 1
I 0
J 0
K 0
L 1
M 2
N 0
O 0
P 1
Q 1
R 0
S 3
T 0
U 0
V 1
W 1
X 0
Y 1
Z 0
Break the problem up into smaller problems.
Write a program that takes a text file and prints its contents
Modify the program to splits the words by colon and prints each word on it's own line
Modify the program to print only the first character of each word
Modify the program to count the number of instances of each letter (keep printing the letter) - print out the counts when done
Modify the program to not print out the letters
Now you're done.
At every point along the way you are making a single change to the logic which means you can isolate both your thought process and debug mistakes much more easily.
You want to store the characters in the array by looking at the character byte code. First, set alphabet to an array of all 0's. Then count the first letter of each word with the index representing the letter.
char first_letter = toupper(word[0]);
alphabet[first_letter - 'A']++;
Then, at the end, print out:
for(int i = 0; i < 26; ++i) {
printf("%c %d\n", i + 'A', alphabet[i]);
}

How to make C++ program that is supposed to add up ages and separate it into categories?

I'm supposed to make a program that counts the number of people in each age group:
0-16 (including 16) is infant
16-29 is young
29-55 is middle
55-75 is old
75+ is really old
The intervals are closed to the left and open to the right.
I wrote a program that compiles, but does not give me the correct values. I'm new at coding so can anyone point me in the right direction? Here is what I have:
#include <iostream>
using namespace std;
main()
{
int countinfant, countyoung, countmiddle, countold, countreallyold;
char age;
countinfant=0;
countyoung=0;
countmiddle=0;
countold=0;
countreallyold=0;
cout<< "Please Enter Ages. To end, enter *\n";
cin.get(age);
while (age>0 && age != '*')
{
if (age>=0 && age<=16) countinfant = countinfant + 1;
if (age>16 && age<=29) countyoung = countyoung + 1;
if (age>29 && age<=55) countmiddle = countmiddle + 1;
if (age>55 && age<=75) countold = countold + 1;
if (age>75 && age>=76) countreallyold = countreallyold + 1;
cin.get(age);
}
cout<< "\n The Number of Infant's Are: " << countinfant;
cout<< "\n The Number of Young's Are: " << countyoung;
cout<< "\n The Number of Middle's Are: " <<countmiddle;
cout<< "\n The Number of old's Are: " <<countold;
cout<< "\n The Number of Really Old's Are: " <<countreallyold;
cout<<endl;
return 0;
}
Actually your problem is very easy to figure out once I looked closer at the code.
The get function of input streams read a single character and not numbers. So if you enter the character 5 as input it will be read and stored in age as a character, and if the encoding used on your system is ASCII encoding (which is the most common these days) then the value for the character '5' is the integer 53.
You then proceed to use the character you have read as an integer, which as it is encoded will give you the wrong results.
To get the correct values you need to read an integer, however since you want to check for the asterisk to end the input you can't use normal integer input with the >> operator, which is why you used get I guess. The solution is to use strings and check the string for the asterisk, and if not an asterisk convert the string to an integer.
Something like
std::string input;
while (std::cin >> input && input != "*")
{
int age = std::stoi(input);
...
}
It does not work because you declared age as a char. The program reads the input as a char, so if you enter 0, the value in age will be the ASCII code of the character 0, which is 48 (0x30). You need to declare it as int age; and for the exit condition simply enter a negative value, e.g. -1, don't use the '*'.

How to reset .get()

I'm trying to find the amount of letters of the alphabet from a file I have. I can get the first letter A to give me the correct number, but when the for loop goes through it only gives me 0 for the rest of the letters. I feel like it has to do with my .get() not starting at the beginning of the file again. What do I need to do to fix this? Thanks!
ifstream openFile("data.txt");
int numberOfLetters(0);
char letter;
for (int i = 0; i < 26; i++)
{
numberOfLetters = 0;
openFile.clear();
while (!openFile.eof())
{
openFile.get(letter);
if (letter == char(i + 97) || letter == char(i + 65))
{
numberOfLetters++;
}
}
cout << numberOfLetters;
}
The problem is your outer loop: It looks like you want to use this loop to check if the characters taken from the file are equal to certain characters from a certain range. If this is the case, performing the input within the loop is not the way to go.
On the first iteration of the loop, the file will be read completely such that by the second iteration openFile.get(letter) won't extract anything into letter, leaving it with its previous value, same for the rest of the outer iterations. It must be that the last value previous had didn't pass the if() statement test, so numberOfLetter didn't increment.
The solution is to change the way you check if the character is alphabetic. Characters are represented using the ASCII format, which are just integers mapped to characters. Since characters are really integers, you can use arithmetic operations on them. Moreover, characters are represented alphabetically in ASCII, so you can simply compare their values to see if they are in the range of alphabetic characters:
while (openFile.get(letter))
{
if (('a' <= letter && letter <= 'z') || ('A' <= letter && letter <= 'Z'))
{
numberOfLetters++;
}
}
cout << numberOfLetters;
Fortunately the standard library provides a function std::isalpha() that does this for you.
...
if (std::isalpha(letter))
{
numberOfLeters++;
}
...
Based on your comment, checking if a character is alphabetic is not enough. Instead, use a data structure like std::map in order to keep a total count of the number of certain characters:
#include <map>
std:map<char, std::size_t> alpha_count;
while (openFile.get(letter))
{
if (std::isalpha(letter))
alpha_count[letter]++;
}
Now to print how many specific characters there are, loop through the map and print the character's count():
for (auto&& c : alpha_count)
{
std::cout << "# of " << c << ": " << alpha_count.count(c) << '\n';
}

C++ for loop with char type

>The character 'b' is char('a'+1),'c' is char('a'+2),etc. Use a loop to write out a table of characters with their corresponding integer values.
I cannot finish this exercise because of this error.
error: lvalue required as increment operand
for(char a='a'; a<24; ++a)
{
cout<<char('a'++);
}
The loop body will never execute with the controlling expression a < 24 because you have initialized variable a with character a and all printable characters are not less than ASCII value 32.
Try this:
for(char a='a'; a < 'a' + 24; ++a)
{
cout << a;
}
I think you would be less confused if you named your variable letter instead of a, because it only represents the letter 'a' at the very beginning.
for(char letter='a'; letter<24; ++letter)
{
cout<<char('a'++);
}
I'm going to assume you actually want to print out the entire alphabet, not just the first 24 letters.
It looks from here like you tried to do a mix of two possible approaches. In the first approach, you increment a char from a to z with each iteration of the for loop and print it out each time. In the second approach, you increment some offset from 0 to 25 and print out 'a' + offset.
You mix these two approaches up in the first line. You're starting the loop with letter set to 'a', which you do not know the numerical value of. You then compare letter to see if it is less than 24. Well in any ASCII-compatible character set, the character 'a' has value 97, so this condition will never pass.
You then misuse ++ on the cout line. The ++ operator attempts to modify its operand, yet 'a' is a literal and so cannot be modified. Have a look at what your assignment told you. You can do 'a' + 1 to get 'b', for example, so this assumes you have an offset (which you don't with your current approach).
So to repeat, you have two options. First: keep letter as a char starting at 'a' and fix the condition so that it checks if letter is less than or equal to the value of 'z' and then just print out letter. Second: change letter to offset and start it off at 0 and increment it while it is less than 26, and then print out 'a' + offset.
Note, however, that both of these approaches assume that the letters have consecutive values in the execution character set. This is not necessarily true.
The ++ operator is a "hidden assignment" (the operand's value is changed by it). But you can only assign to variables, which 'a' is not.
I know this has been closed for a while but since the exercise was about while loops and not for loops, I thought I would offer my solution. I'm just going through the book myself and someone in the future might stumble over this.
int i = 0;
char n = 'a'; // this will list the alphabet
int conv = 0;
conv = n; // this converts the alphabet into integer
while (i < 26) { // starts from 0 and goes to 25
cout << char(n + i) << '\t' << conv + i << '\n';
++i;
}
You may use the following: (http://ideone.com/akwGhl)
#include <iostream>
int main()
{
for (char c = 'a'; c <= 'z'; ++c) {
std::cout << "letter " << c << " has value " << int(c) << std::endl;
}
return 0;
}
hey through troubleshooting i obtained a sample that worked , i have yet to perfectly understand how my code works but as the solutions that were proposed to me here seemed too technical for my level i figured that i should publish mine
#include"header files . h"//i use the libraries given in the book
int main () {
char a ='a';
int i = 0 ;
while (i <= 25)//for (i = 0 ; i <= 25 ; i++)
//for those who used for
{
cout << a << '\t' << 'a' + i << endl;
a += 1; // augments the character value of a to b ... then to z
i++; // augments the value of i allowing us thus to make the augmentation,if you are using the for structure do not put I in your code
}
}

C++ display char while loop rows

I am very new to programming, so I apologize if this question seems absurdly simple. I am working on some extra questions in the current chapter of my C++ book. I have actually found a correct answer to the problem, but while doing so, I ran into a situation that is driving me crazy because I can't figure out WHY one particular solution works and another one doesn't.
So, the problem asks to print the ASCII values between 32 and 127 in a few rows with 16 characters per row. The solution I have come to (that works correctly) is this:
#include <iostream>
using namespace std;
int main()
{
char letter;
int count = 0;
for (letter = 32; letter < 127; letter++, count++)
{
if (count == 16)
{
cout << endl;
count = 0;
}
cout << letter << " ";
}
cout << endl;
return 0;
}
Again, the above code runs fine and does what I want it to. The difficulty lies in something I tried before this. I attempted to do the same problem with a nested while loop, like so:
#include <iostream>
using namespace std;
int main()
{
char letter = 32;
int count;
while (letter < 127)
{
count = 0;
while (count < 16)
{
cout << letter << " ";
letter++;
count++;
}
cout << endl;
}
cout << endl;
return 0;
}
This while loop just runs infinitely and also spits out some garbage after the ASCII characters I want, and I can't figure out why. What's even weirder is if I change the variable 'letter' in the code with while loops to an int instead of a char, it runs exactly the way I want it to and terminates when it should, just displaying the actual numbers instead of the ASCII values.
It's only when 'letter' is a char that I get an infinite loop. I'm sure it's something really simple, and I might just be too tired to see it right now, but any help/hints would be much appreciated! Even though I technically got the answer, it's driving me crazy that I don't know WHY the second answer fails so horribly.
Thanks in advance.
The answer is simple, true enough. Here is what happens - (signed)char can have values in the range [-128, 127] in the inner loop after you output the row up to 112, you increment count with another 16 and therefor you also increment letter with 16, this makes letter equal to 112 + 16 = 128, which due to the range of signed char is actually overflowing and becomes -128. So after this execution of the inner loop the condition of the outer loop still holds: -128 < 127. That is also why you get weird chars - these will be the values between -128 and 32.
How to fix the problem? Change the check in the inner loop:
while (count < 16 && letter < 127)
The inner while loop exits when letter == 48, 64, ..., 128. But as it is a (signed) char, 128 is interpreted as -128 and the outer loop will not terminate.
Change the inner loop to
while (count < 16 && letter < 127)
to get the same behavior as in your first example.
Or change letter to int, if it's OK to print all characters including 127:
int letter = 32;
...
cout << (char)letter << " ";
Try this code :
#include <iostream>
using namespace std;
int main()
{
int letter;
for (letter = 32; letter < 128; ++letter)
{
if (letter != 32 && letter % 16 == 0)
cout << endl;
cout << (char)letter << ' ';
}
}