Simple Encryption program array - c++

Building a simple program that multiplies the ASCII value of chars in a string by 3 to encrypt and then divide by 3 to decrypt. So far I got the encryption part down but whenever I enter what the encryption gave and try to decrypt it doesn't work. I think it has something to do with the buffer stream but I could be wrong if anyone could help.
#include<iostream>
using namespace std;
int main()
{
string message;
int charValue;
int counter;
int encrypt;
char choice;
char quit = 'N';
while (quit == 'N')
{
cout << "Enter E to encrypt or D to Decrypt\n";
cin >> choice;
toupper(choice);
cout << "Enter text no spaces: ";
cin >> message;
int messagelen = message.length();
string stringArray[255];
if (choice == 'E')
{
for (counter = 0; counter < messagelen; counter++) //*3 to ascii val
{
stringArray[counter] = message[counter] * 3;
}
for (counter = 0; counter < messagelen; counter++)
{
cout << stringArray[counter];
}
}
else
{
for (counter = 0; counter < messagelen; counter++) // divide 3 to ascii val
{
stringArray[counter] = message[counter] / 3;
}
for (counter = 0; counter < messagelen; counter++)
{
cout << stringArray[counter];
}
}
cout << "\nY to go again N to quit";
cin >> quit;
}
return 0;
}

This is a working implementation, although I agree with the other answer that you should use encrypt and decrypt functions. I found quite a few other bugs with your code working through it. You should enable all warnings with -Wall -Werror and fix them:
#include <iostream>
#include <vector>
#include <sstream>
int main()
{
// removed some unused variables
std::string message;
size_t counter;
char choice;
char quit;
// use vector of int instead of array of strings
std::vector<int> encryptArray;
// change to do while loop. Not particularly necessary, but I think
// it makes more sense in this case. Your condition is broken. If the
// user enters 'Y' at the end to go again, then the quit == 'N'
// condition is false and the program terminates.
do
{
std::cout << "Enter E to encrypt or D to Decrypt\n";
std::cin >> choice;
// toupper returns a value, you need to assign it to choice.
// Not capturing the return value makes this a noop.
choice = toupper(choice);
if (choice == 'E')
{
std::cout << "Enter text no spaces: ";
std::cin >> message;
size_t messagelen = message.length();
// initialize vector to input message length size
encryptArray = std::vector<int>(messagelen);
for (counter = 0; counter < messagelen; counter++) //*3 to ascii val
{
encryptArray[counter] = message[counter] * 3;
}
// Note, this 2nd loop is more work than you need, you could
// simply put the std::cout line in the loop above below the
// assignment
for (counter = 0; counter < messagelen; counter++)
{
// added the separator just for clarity. You could also print
// hex bytes
std::cout << encryptArray[counter] << "|";
}
}
else
{
// all the data we care about is in the vector now
for (counter = 0; counter < encryptArray.size(); counter++) // divide 3 to ascii val
{
// you don't want to /3 what's in the message here, you want
// to /3 the encrypted values, which are in the vector
encryptArray[counter] = encryptArray[counter] / 3;
}
// plenty of ways to convert the vector to a string, this is not
// a "modern" way.
// Note, you could skip this loop entirely, and in the one
// above, simply do ss << (char)(encryptArray[i] / 3);
// Not necessary to write the data back to encryptArray first.
std::stringstream ss;
for (size_t i=0; i<encryptArray.size(); ++i)
{
ss << (char)encryptArray[i];
}
std::cout << "decrypted string: " << ss.str() << std::endl;
}
std::cout << "\nY to go again N to quit: ";
std::cin >> quit;
} while(quit != 'N'); // loop until quit == N
return 0;
}
Finally, I removed using namespace std;, here's why
Things get squirrely working with stdin on godbolt, but here's a working demonstration, at least initially.

It would genuinely help you to break this down into smaller problems. Let's "encrypt" a std::string into a std::vector<int>:
std::vector<int> encrypt_msg(std::string s) {
std::vector<int> v;
for (auto ch = s.begin(); ch != s.end(); ch++) {
v.push_back(static_cast<int>(*ch) * 3);
}
return v;
}
Then let's "decrypt" a message, performing the transformation in reverse.
std::string decrypt_msg(std::vector<int> v) {
std::string s;
for (auto i : v) {
s += static_cast<char>(i / 3);
}
return s;
}
Now you can test and see that your individual functions that do one thing work, and putting together the overall program should be much easier.

Related

Reading input in loop until sentinel value is reached in C++

I'm relatively new to C++ and I'm trying to write some code that asks a user to enter numbers and use -999 as a sentinel value to end the input loop. The numbers they enter must populate an array to be used in a binary tree later. The issue I'm having is the loop doesn't terminate if -999 is entered, and I also don't know how to read those values into the array without specifying how large the array is. The program must dynamically size the array based on how many inputs were given. I have attached my code. Any help is greatly appreciated!
#include <iostream>
#include <string.h>
//#include "binarySearchTree.h"
//#include "binaryTree.h"
using namespace std;
int i;
int n;
struct Node {
int data;
struct Node* left;
struct Node* right;
}
Node(int val)
{
data = val;
left = NULL;
right = NULL;
};
int main() {
//struct Node* root = new Node(1);
cout << "Enter values up to -999: \n";
int numbers[] = {};
for(int i =0; i!=999; i++){
cin >> numbers[i];
}
cout << "\nYour numbers are: ";
for(int j=0; j<=sizeof(numbers) ; j++){
cout << numbers[j] << " ";
}
return 0;
}
Here is a program that does what you want.
#include <iostream>
#include <vector>
// never, ever use using namespace std;
int main()
{
std::vector<int> input; // this is the way to spell "an array that can grow as needed"
// int numbers[] = {}; is not one.
int number;
while (std::cin >> number // check whether the input is successful, i.e. a number
// is entered. entering a non-number or an
// end-of-file indicator is a failure
&& number != -999) // and whether that number is not -999
{
input.push_back(number); // add it to the end of our growing-as-needed array
}
for (auto i : input) // that's how you enumerate entries in the array
{
std::cout << i << " ";
}
std::cout << "\n"; // print a newline when you are done
}
Live demo
Beside all other problems, the main problem is here:
for(int i =0; i!=999; i++){
cin >> numbers[i];
}
You are reading from the standard input into the i-th element of the array numbers. You are comparing i with 999, which basically makes no sense. Why comparing i? And why comparing it with 999, instead of -999?
Let's try to fix it. Start with an empty infinite loop:
while (true) {
// Read
// Check
// Use
}
Read an integer:
while (true) {
// Read
int val;
cin >> val;
// Check
// Use
}
Now let's check if we managed to read something and if not let's exit from the loop.
while (true) {
// Read
int val;
cin >> val;
// Check
if (cin.fail()) {
break;
}
// Use
}
We need to exit from the loop also if we read a -999:
while (true) {
// Read
int val;
cin >> val;
// Check
if (cin.fail()) {
break;
}
if (val == -999) {
break;
}
// Use
}
Now you want to put it in the i-th position of numbers, so:
int i = 0;
while (true) {
// Read
int val;
cin >> val;
// Check
if (cin.fail()) {
break;
}
if (val == -999) {
break;
}
// Use
numbers[i] = val;
++i;
}
Ok, now we have a working loop (hopefully). What other problems you have in your code?
int numbers[] = {};
j<=sizeof(numbers)
You cannot define arrays without a compile time size in C++. Use std::vector<>.
Then, the sizeof operator doesn't do what you think it does. Save it for (much?) later. Use std::vector::size(). But for starters, you can assume that 1000 numbers will be enough for everyone (Bill Gates docet), and keep the count in variable i:
#include <iostream>
using namespace std;
int main()
{
cout << "Enter values. Use -999 to stop entering values.\n";
int numbers[1000]; // We accept 1000 numbers at most 🤮
int i = 0;
while (true) {
// Read
int val;
cin >> val;
// Check
if (cin.fail()) {
break;
}
if (val == -999) {
break;
}
// Use
numbers[i] = val;
++i;
}
cout << "Your numbers are: ";
for (int j = 0; j < i; j++) {
cout << numbers[j] << " ";
}
cout << '\n';
return 0;
}
Switching to std::vector<> is much better. And learn Why is "using namespace std;" considered bad practice?:
#include <iostream>
#include <vector>
int main()
{
std::cout << "Enter values. Use -999 to stop entering values.\n";
std::vector<int> numbers;
while (true) {
// Read
int val;
std::cin >> val;
// Check
if (std::cin.fail()) {
break;
}
if (val == -999) {
break;
}
// Use
numbers.push_back(val);
}
std::cout << "Your numbers are: ";
for (int j = 0; j < numbers.size(); j++) {
std::cout << numbers[j] << " ";
}
std::cout << '\n';
return 0;
}
Finally, if you think that while(true) {} is ugly, you can use other versions of the same loop, e.g.:
for (int val; std::cin >> val && val != -999;) {
numbers.push_back(val);
}

input the letter f or any letter and cout an alphabet pattern like a abc abcd abcde abcdef but it only works if i press 0

So far nothing happens when you enter f it only works when 0 is entered but I want it so when you press f you get this a ab abc abcd abcde abcdef
#include <iostream>
using namespace std;
int main()
{
int f = 0;
int z;
cout << "";
while(cin >> f)
{
if(f == 0)
{
cout << "ABCDEF\nABCDE\nABCD\nABC\nAB\nA";
break;
}
}
}
The variable f is an int. When you press the key 'f', the cin istream tries to set the int to 'f', which isn't a number, so the conversion from a character to a number fails.
That failure sets the bad-bit in cin, which breaks out of the while loop.
Here's one way to make your program do what you want:
#include <iostream>
using namespace std;
int main()
{
char c = 0; // we want chars, not integers.
int z;
cout << "";
while (cin >> c)
{
if ('a' <= c && c <= 'z') // test for the range we want
{
// print all glyphs from a to 'c'
for (char i = 'a'; i <= c; ++i)
cout << i;
cout << '\n';
break;
}
}
}
Reading the input into a char is the easy bit: std::cin >> c for a char c will do it.
The fun bit is writing a portable way of printing the letters up to a certain character. Here's one way:
// Prints up to and including 'c'.
// Outputs the alphabet if 'c' is not a lower case letter.
void print(char c)
{
static const char s[] = "abcdefghijklmnopqrstuvwxyz";
for (std::size_t i = 0; s[i]; ++i){
std::cout << s[i];
if (s[i] == c){
std::cout << '\n';
return;
}
}
}
If you enter f you cause an error because it is expecting an integer. You can convert the a char to an integer. If you want to turn a result if you enter f you have to options:
1.
char input;
std:cin >> input;
if((int)input == 102){
.....
2.
char input;
std:cin >> input;
if(input == 'f'){
.....
EDIT:
If you want to print the Alphabet in descending order Michael Roy had a nice solutions but in accesnding order
if....
for(char i = input; i >= 'a'; --i)
cout << i - 32; //the 32 is for converting the lower case char into upper case
cout << '\n';
So in total it could look something like this:
char input;
std:cin >> input;
if('a' < input < 'z'){
for(char i = input; i >= 'a'; --i)
cout << i - 32;
cout << '\n';
}else{
cout << "Not a valid input";
}
System("Pause");//so the console doesn't close automatically

Stuck on C++ code using Structure

Currently I am stuck and not sure where to go from here...
I'm supposed to write a program that declares a struct to store the data for a player. Then declare an array of 10 components to store the data for 10 baseball players.
The program reads from a file and stores the data for ten baseball players, including player’s team, name of player, number of homeruns, batting average, and runs batted in.
The program prints out a menu (in a loop, so this can be done again and again) giving the user a choice to:
print out all users and statistics
print out the statistics for a specific player
print out all data for a specific team
update the data for a particular player (change one of the statistics)
Before the program terminates, give the user the option to store the data in an output file.
If anyone has ANY TIPS OR ADVICE I will be very grateful... I'm fairly new to coding in C++ and just stuck here... thank you in advance...
#include <iostream>
#include <fstream>
using namespace std;
struct BaseballID
{
string teamName, playerFirstName, playerLastName;
int homeRuns, rbi;
double batting_average;
};
int main()
{
BaseballID listofplayers[10];
ifstream infile;
infile.open("/users/AlecKleyer/Desktop/computer science term 2/BaseballStats.txt");
if (!infile)
{
cout << "Error opening file!";
return 0;
}
for (int j = 0; j < 10; j++) {
infile >> listofplayers[j].teamName >> listofplayers[j].playerFirstName >> listofplayers[j].playerLastName >>listofplayers[j].homeRuns >> listofplayers[j].rbi >> listofplayers[j].batting_average;
}
cout << "Please Type The Following Letter: ";
cout << "\n(A) For All Users and Stats";
cout << "\n(B) For A Specific Player";
cout << "\n(C) Print out for specific team";
cout << "\n(D) Update stats for a player";
char input = 0;
cin >> input;
if (input == 'A' || input == 'a') {
printInfoAll(*listofplayers[]);
}
if (input == 'B' || input == 'b') {
}
if (input == 'C' || input == 'c') {
}
if (input == 'D' || input == 'd') {
}
}
void printInfoAll(listofplayers1[])
{
for (int i = 0; i < 10; i++) {
cout << &listofplayers[i];
}
}
One thing you did right was making a function of printInfoAll (even if its buggy). Note this will not compile and there might be more errors.
#include <iostream>
#include <fstream>
using namespace std;
struct BaseballID
{
string teamName, playerFirstName, playerLastName;
int homeRuns, rbi;
double batting_average;
};
void printInfo(const BaseballID& id) {
cout << id.teamName << " " << id.playerFirstName // and so on!!!!
<< "\n"; // and a newline.
}
void printInfoAll(const BaseballID listofplayers1[]) // we need a type and a paramter
{
for (int i = 0; i < 10; i++) {
cout << printInfo(listofplayers[i]); // you
}
}
void printMenu() { // factor out the components in easy reusable parts.
cout << "Please Type The Following Letter: ";
cout << "\n(A) For All Users and Stats";
cout << "\n(B) For A Specific Player";
cout << "\n(C) Print out for specific team";
cout << "\n(D) Update stats for a player";
}
int main()
{
BaseballID listofplayers[10]; // consider using std::vector instead
// from here
ifstream infile;
infile.open("/users/AlecKleyer/Desktop/computer science term 2/BaseballStats.txt");
if (!infile.isOpen()) // I think the isOpen is needed.
{
cout << "Error opening file!";
return 0;
}
for (int j = 0; j < 10; j++) {
infile >> listofplayers[j].teamName >> listofplayers[j].playerFirstName >> listofplayers[j].playerLastName >>listofplayers[j].homeRuns >> listofplayers[j].rbi >> listofplayers[j].batting_average;
// hmm you trust your indata I don't check for errors here.
}
// to here should be a function, but then you need to restructure a bit more
printMenu();
char input = 0;
cin >> input;
switch(input) {
case 'A': case 'a':
printInfoAll(*listofplayers[]);
break;
case 'B': // and so on
// code for 'B' and 'b'
break;
....
default:
printMenu();
break;
}
// at this point you will find out you should have put it all in a loop.
return EXIT_SUCCESS;
}
The reason for adding const to the parameters is so that the user of the functions can see it promises not to change the values.

C++: Sorting name/age pairs alphabetically, can only manage 5 pairs

Sorry if this post isn't the best, I'm brand new to the site and coding in general. My programs take input like "Sam 16 Emily 4 Molly 19" and sorts it alphabetically, while keeping the ages the same. It works like a charm, unless you enter more than 5 pairs. After you enter 5, the following names are sorted fine, but the ages aren't the right ones. I'm not sure where the code is getting the numbers it's outputting. This is my code. I apologize for posting everything (~30 lines), but I really don't know where the issue is.
#include"../std_lib_facilities.h"
vector<string> name;
vector<int> age;
void read_pairs()
{
string n;
int v;
while (cin >> n >> v && n != "NoName") { // read string int pair
for (int i = 0; i<name.size(); ++i)
name.push_back(n);
age.push_back(v);
}
}
void write_pairs(string label)
{
cout << label;
for (int i = 0; i<name.size(); ++i)
cout << '(' << name[i] << ',' << age[i] << ")\n";
}
int find_index(const vector<string>& v, const string& n)
// find n's index in v
{
for (int i = 0; i<n.size(); ++i)
if (n == v[i]) return i;
}
int main()
try
{
cout << "Please enter your name/age pairs. When finished, enter 'No More'\n";
read_pairs();
vector<string> original_names = name; // copy the names
vector<int> original_ages = age; // copy the ages
sort(name.begin(), name.end()); // sort the names
for (int i = 0; i<name.size(); ++i) // update ages
age[i] = original_ages[find_index(original_names, name[i])];
write_pairs("\nSorted:\n");
keep_window_open("~");
}
catch (runtime_error e) {
cout << e.what() << '\n';
keep_window_open("~");
}
catch (...) {
cout << "exiting\n";
keep_window_open("~");
}
You have many problems in your code. I couldn't even get it to compile for a while.
In the first place, that for loop in read_pairs() is preventing you from storing any names in name. In the second place, you need to see if n in read_pairs() is the break signal before inputting the age - otherwise you will break cin, you will learn that later, as I know that you are using Bjarne Stroustrup's book - the same one I learned from. In the third place, your code was breaking in find_index() because you were calling i < n.size(); rather than i < v.size(); in your for loop. Finally, you may want to handle multiple instances of the same name so you don't get one age for it. I have implemented a simple way to do this by setting the value of v[i] to "" in find_index() before I returned the position of the name in the array - this way, you cannot get the age for that name more than once.
This is the working code, with some comments included. Feel free to ask if you don't understand something, but I think you understand enough to figure it out.
#include "stdafx.h"
#include"../std_lib_facilities.h"
vector<string> name;
vector<int> age;
void read_pairs()
{
string n;
int v;
while (true) { // read string int pair
cin >> n; // input name
if (n == "No") // if name is "No", break so we do not input a string for age
break;
cin >> v; // input age
// insert name/age into vectors
name.push_back(n);
age.push_back(v);
}
}
void write_pairs(string label)
{
cout << label;
for (int i = 0; i<name.size(); ++i)
cout << '(' << name[i] << ',' << age[i] << ")\n"; // output name/age pairs
}
int find_index(vector<string>& v, const string n)
// find n's index in v
{
for (int i = 0; i < v.size(); i++)
{
if (n == v[i])
{
v[i] = ""; // remove name in case two of same name
return i;
}
}
}
int main()
try
{
cout << "Please enter your name/age pairs. When finished, enter 'No More'\n";
read_pairs(); // read name/age pairs
vector<string> original_names = name; // copy the names
vector<int> original_ages = age; // copy the ages
sort(name.begin(), name.end()); // sort the names
for (int i = 0; i < name.size(); i++) // update ages
age[i] = original_ages[find_index(original_names, name[i])];
write_pairs("\nSorted:\n"); // write name/age pair
keep_window_open("~");
}
catch (runtime_error e) {
cout << e.what() << '\n';
keep_window_open("~");
}
catch (...) {
cout << "exiting\n";
keep_window_open("~");
}

How to count unique words in string and output line where they occur? C++

So I'm working on this homework assignment and I'm really having trouble. I'm supposed to count the number of words more than two characters(have to contain one letter), unique words, and the number of times each unique word appears in the Programming Execution Environment. I'm also supposed to get input to search for in the PEE and output the number of times it appears and the line where it appears. I have some of it working, but I'm really struggling with counting how many times each word appears. I know my code is really bad right now, but that's why I'm here. I'm really struggling with these string functions for some reason. Any help is really appreciated!
#include <iostream>
#include <cstring>
#include <string>
#include <cctype>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
//PEE string
string envstr("");
bool checkChar(unsigned c)
{
return (ispunct(c) || isspace(c) || isblank(c) || isdigit(c) || c == '\n');
}
void searchWord(unsigned c, size_t length)
{
multiset<string> words;
vector<string> vwrds; //this was something i was trying out
string tempword;
while (!checkChar(envstr[c]) && c < length)
{
tempword = tempword + envstr[c]; //problem here
c++;
}
tempword = tempword + " ";
vwrds.push_back(tempword);
words.insert(tempword); //this is just a bunch of random letters
tempword.clear();
//for (multiset<string>::const_iterator i(words.begin()), end(words.end()); i != end; i++)
//cout << *i;
}
bool checkIfWord(char c)
{
bool valid = false;
int i;
for (i = c; i > c - 2; i--)
{
if (!checkChar(envstr[i]))
valid = true;
}
if (valid)
searchWord(i, envstr.length());
return valid;
}
int main()
{
//this code given by my instructor
extern char **environ; // needed to access your execution environment
int k = 0;
size_t wordCount = 0;
while (environ[k] != NULL)
{
cout << environ[k] << endl;
string str(environ[k]);
envstr = envstr + str;
k++;
}
//iterator to count words
wordCount = count_if(envstr.begin(), envstr.end(), checkIfWord);
cout << "\nThe PEE contains " << wordCount << " words. \n";
//transform environment string to lowercase
transform(envstr.begin(), envstr.end(), envstr.begin(), tolower);
string input;
do
{
cout << "Enter your search item: \n";
cin >> input;
//string can only be forty characters
if (input.length() > 40 || input == "\n")
{
cout << "That search query is too long. \n";
continue;
}
//change the search string to lowercase, like the envstr
transform(input.begin(), input.end(), input.begin(), tolower);
int j = 0;
int searchCount = 0;
vector<size_t> positions;
size_t pos = envstr.find(input, 0);
//search for that string
while (pos != string::npos)
{
positions.push_back(pos);
pos = envstr.find(input, pos + 1);
searchCount++;
}
cout << "\nThat phrase occurs a total of " << searchCount << " times.\n";
cout << "It occurs in the following lines: \n";
//output where that string occurs
for (vector<size_t>::iterator it = positions.begin(); it != positions.end(); ++it)
{
for (int i = *it; i < envstr.length() - 1 && checkChar(envstr[i]); i++)
{
cout << envstr[i];
}
cout << endl;
}
positions.clear();
} while (input != "END");
cin.get();
return 0;
}
First, your function checkChar() returns false when the parameter is a char, so if you want to print where that string occurs, it should be:
for (int i = *it; (i < envstr.length() - 1) && !checkChar(envstr[i]); i++)
{
cout << envstr[i];
}
Second, the code for counting words makes no sense and there is a potential out-of-bounds here: if (!checkChar(envstr[i])), I would suggest you to split the string using delimter '\', then do something.