Decode a message without a key - c++

Here is what I should do
making a program that reads a text file that contains encrypted message and crack it it is kind of close to substitution cipher where I should swap swap each letter back with another meaning like shifting B back to A if its being shifted by one, and try comparing shifted words by some common used words to find if 2 of the common words have been found on the shifted ones
ex: shift the word by one
check when you shifted it is there 2 common words found?
no keep going
yes means thats it stop shifting
Now this issue here which makes the program hard for me is that I do not have a key to be entered it would've been awesome if I had it.
3 issues I am having now, is in my void function it will not print anything,
the second issue is, even if I fix my issue (I know this because in my function I have added something to convert string to c_string) and the issue is it will not shift until it finds the words I am looking which I have declared in string "Common[]"
3rd issue is whenever I compile I get an error invalid conversion from const char** to char comparison between signed and unsigned integer expressions
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <ctype.h>
using namespace std;
void makeshift (string encrypt, int key)
{
for (int i = 0 ; i<encrypt.size();i++)
{
cout<<encrypt<<endl; // to see what is in file way to debug
const char *encryptedc; // this is to convert string to cstring
encryptedc = encrypt.c_str();
encryptedc-=key;
cout<<"decrypted message is "<<encryptedc<<endl;
}
}
int main (int argc, char* argv[])
{
// this will make me compare between encrypted message to check if it
// contains this words or not!
const char* common[]{"the","and","in","he","with","that","as","at","do"};
string encrypted; // The encrypted message gotten from file
ifstream message(argv[1]); // get file name typed by user
if(message.is_open()) // check if file is open
{
while (!message.eof()) // check if we reached end of file
{
// get the whole line in file
getline(message,encrypted);
///loop throgh it to store numbers in declared varibles
for (int i = 0 ; i < encrypted.size();i++)
{
makeshift(encrypted,i);
// here is where the error occurs which is "invalid conversion
// from const char to char
if(encrypted.find(common) != -1)
{
cout<<"found common"<<endl;
cout<<encrypted<<endl;
break;
}
}
}
}
}

Compile error
First, you say you're getting a compile error on this line:
if(encrypted.find(common) != -1)
The reason for that is because find() expects its argument to be a string, but common is an array of strings. In other words, find() can only search for one word at a time. It can't search for a whole list of words.
To fix that, you'll want to write a loop and check one word each iteration.
Shift function
Next up is the makeshift function. A couple of suggestions there.
There's no real need to call c_str(). You can change encrypted directly by modifying each encrypted[i] in the loop.
It needs to return the result. If you modify encrypted but do not return it then the caller won't see the result.
The printouts ought to be outside the loop. Presumably you just want to see the before and after results after you've decrypted the entire string.
Here's what it looks like with those issues addressed:
string makeshift (string encrypt, int key)
{
cout << encrypt << endl; // to see what is in file way to debug
for (int i = 0 ; i<encrypt.size();i++)
{
encrypted[i] -= key;
}
cout << "decrypted message is " << encryptedc << endl;
return encrypted;
}
And then you would call it as:
string decrypted = makeshift(encrypted, i);
By the way, I'm not sure if the encrypted[i] -= key; line is completely correct. My guess is you'll need to handle wraparound. Like if you subtract 3 from the letter "A" you should probably wrap around to "X", correct? If so, I'll leave that as a TODO for you.
I/O error checking
Lastly, let's talk about I/O. Specifically, this bit of code:
ifstream message(argv[1]); // get file name typed by user
if(message.is_open()) // check if file is open
{
while (!message.eof()) // check if we reached end of file
{
// get the whole line in file
getline(message,encrypted);
...
}
}
A good practice in C++ is to check the results of I/O operations (e.g. getline). After you read a line you need to check that the read actually worked. You don't want to continue on if getline() failed (say, because it hit end-of-file).
Conveniently, if you write while (getline(...)) then that'll do a whole bunch of things all at once--it'll check if the file is open, if it's at EOF, and it'll read lines and tell you if the reads were successful. That means you can replace the stuff above with a single loop:
ifstream message(argv[1]); // get file name typed by user
while (getline(message, encrypted))
{
...
}

You are passing the value of encrypted to makeshift, so whatever you do in makeshift function will not change the encrypted in main function
you have 2 solutions here:
you can either pass the pointer of encrypted to the makeshift function
void makeshift (string* encrypt, int key){
for (int i = 0 ; i<encrypt.size();i++)
{ cout<<encrypt->c_str()<<endl; // to see what is in file way to debug
const char *encryptedc; // this is to convert string to cstring
encryptedc = encrypt->c_str();
encryptedc-=key;
cout<<"decrypted message is "<<encryptedc<<endl;
}
}
int main (int argc, char* argv[]){
...
makeshift(&encrypted, i);
...
}
Or you can return the value of encryptedc and assign it back to encrypted in main function
string makeshift (string encrypt, int key){
for (int i = 0 ; i<encrypt.size();i++)
{ cout<<encrypt.c_str()<<endl; // to see what is in file way to debug
const char *encryptedc; // this is to convert string to cstring
encryptedc = encrypt.c_str();
encryptedc-=key;
cout<<"decrypted message is "<<encryptedc<<endl;
return encryptedc; //you can assign const char* to string
}
}
int main (int argc, char* argv[]){
...
encrypted = makeshift(encrypted, i);
...
}

Related

Why a "no matching function" error for call by reference with literal number?

The problem asks to create a program that asks the user to enter some text and that text will be surrounded by asterisks depending on the width of the screen for example if the user inputs "Hello world" the output should be:
****************
* Hello World! *
****************
I've tried to create the functions but I'm stuck becaus of a compiler error with the shown minimal code.
Question: Why does it tell me no matching function for within_width(text, 80)?
Some of the code I have is below:
#include <iostream>
#include <string>
void display_header (std::string &header) {
std::string text;
header = text;
}
bool within_width (std::string& text, unsigned short int& max_width) {
}
int main() {
std::string text;
std::cout << "Please enter header text: ";
std::getline(std::cin, text);
if (within_width(text, 80)) {
// call the display_header function and pass in the text
// inputted by the user
} else {
std::cout << text;
}
return 0;
}
This declaration of the function
bool within_width (std::string& text, unsigned short int& max_width)
asks for an unsigned short int variable, because it has a reference parameter, see the second &.
To satisfy it, you need to put the value 80 into a variable and give the variable as parameter.
unsigned short int MyWidth=80;
if (within_width(text, MyWidth))
Alternatively (but I assume you are not allowed) you can use a call by value parameter
bool within_width (std::string& text, unsigned short int max_width)
Then you could call as shown.
I won't give a full answer to the exercise here, just some clues.
the display_header() and within_width() functions need to know the string given in parameters but may not modify it ; thus the type of this parameter should be const std::string & (the const was missing).
the second parameter of the within_width() function is just an integer that will be compared to the length of the string ; you don't need to pass it by reference (or at least const), rather by value. Here, the (non-const) reference prevents from passing the literal constant 80.
(it seems to be the main concern of the question after edition)
You need to reason step by step.
all of this depends on the size of the string (12 for Hello World!) ; this information is available via size(text) (or text.size())
(https://en.cppreference.com/w/cpp/iterator/size)
(https://en.cppreference.com/w/cpp/string/basic_string/size)
This size will have to be compared to max_width
Displaying the line with header will require 4 more characters because * will be prepended and * will be appended.
Thus the two surrounding lines will have the length size(header)+4 too.
In order to create such a string made of *, you could use a constructor of std::string taking two parameters : the count of characters and the character to be repeated.
(https://en.cppreference.com/w/cpp/string/basic_string/basic_string)
Send all of this to std::cout in the correct order.
Edit: Just noticing that this answer probably goes far beyond the scope of the task you have been given (just filling in some skeleton that has been provided by your teacher).
I'll still leave it here to illustrate what could be done with arbitrary input. Maybe you want to experiment a little further than what you have been asked...
bool within_width(...)
Pretty simple: string.length() <= max – just wait a second, you need to consider asterisks and spaces at beginning and end of output, so: max - 4
But you can do better, you can split the string, best at word boundaries. That's a bit difficult more difficult, though:
std::vector<std::string> lines;
// we'll be starting with an initially empty line:
auto lineBegin = text.begin();
auto lineEnd = text.begin();
for(auto i = text.begin(); i != text.end(); ++)
// stop condition empty: we'll stop from inside the loop...
{
// ok, we need to find next whitespace...
// we might try using text.find_first_of("..."), but then we
// need to know any whitespace characters ourselves, so I personally
// would rather iterate manually and use isspace function to determine;
// advantage: we can do other checks at the same time, too
auto distance = std::distance(lineBegin, i);
if(std::distance(lineBegin, i) > maxLineLength)
{
if(lineEnd == lineBegin)
{
// OK, now we have a problem: the word itself is too long
// decide yourself, do you want to cut the word somewhere in the
// middle (you even might implement syllable division...)
// or just refuse to print (i. e. throw an exception you catch
// elsewhere) - decide yourself...
}
else
{
lines.emplace_back(lineBegin, lineEnd);
lineBegin = lineEnd; // start next line...
}
}
// OK, now handle current character appropriately
// note: no else: we need to handle the character in ANY case,
// if we terminated the previous line or not
if(std::isspace(static_cast<unsigned char>(*i)))
{
lineEnd = i;
}
// otherwise, we're inside a word and just go on
}
// last line hasn't been added!
lines.emplace_back(lineBegin, lineEnd);
Now you can calculate maximum length over all the strings contained. Best: Do this right when adding a new line to the vector, then you don't need a separate loop...
You might have noticed that I didn't remove whitespace at the end of the strings, so you wouldn't need to add you own one, apart, possibly, from the very last string (so you might add a lines.back() += ' ';).
The ugly part, so far, is that I left multiple subsequent whitespace. Best is removing before splitting into lines, but be aware that you need to leave at least one. So:
auto end = text.begin();
bool isInWord = false; // will remove leading whitespace, if there is
for(auto c : text)
{
if(std::isspace(static_cast<unsigned char>(c)))
{
if(isInWord)
{
*end++ = ' '; // add a single space
isInWord = false;
}
}
else
{
*end++ = c;
isInWord = true;
}
}
This would have moved all words towards the beginning of the string, but we yet to drop the surplus part of the string yet contained:
text.erase(end, text.end());
Fine, the rest is pretty simple:
iterate over maximum length, printing a single asterisk in every loop
iterate over all of your strings in the vector: std::cout << "* " << line << "*\n";
repeat the initial loop to print second line of asterisks
Finally: You introduced a fix line limit of 80 characters. If console is larger, you just won't be using the entire available width, which yet might be acceptable, if it is smaller, you will get lines broken at the wrong places.
You now could (but that's optional) try to detect the width of the console – which has been asked before, so I won't go any deeper into.
Final note: The code presented above is untested, so no guarantee to be bugfree!

bool function doesn't work as a while condition

I am trying to to check if a file has successfully opened, read from it and output what I've read from it all in one function, because I have 7 files to operate on in the same code and I want to avoid writing the same code over and over again.
So I have made a bool function and put it as a while condition.
If I succeed, the function returns true and if I don't it returns false. So a while(!function) should keep trying until it works, correct ? And the answer is yes, it works as intended.
But if I change the condition of the while to while(function) one would expect to repeat the function until it fails somehow (maybe it can't open the file.). But it doesn't behave as expected. It only works correctly on the first while iteration.
This is the example:
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <fstream>
#include <sstream>
bool readConfig(std::fstream& file, std::string (&str)[10], std::string identity) {
if(file.is_open()) {
if(file.seekg(0)) {
std::cout<<"Start from 0"<<std::endl;
}
// Get content line by line of txt file
int i = 0;
while(getline(file, str[i++]));
std::cout<<"i= "<<i<<std::endl;
for(int k = 0; k<i; k++) {
std::cout<<identity<<" = "<<str[k]<<std::endl;
}
return true;
} else {
std::cout<<"ERROR ! Could not open file."<<std::endl;
return false;
}
}
int main() {
char configFilePath[]="test.txt";
std::fstream configFile;
configFile.open(configFilePath, std::fstream::in);
std::string test[10];
std::string id = "testing";
while(!readConfig(configFile, test,id)) {
usleep(1000*1000);
};
return 0;
}
This is the content of test.txt :
line 1
line 2
line 3
line 4
This is the output:
Start from 0
i= 5
testing = line 1
testing = line 2
testing = line 3
testing = line 4
testing =
i= 1
testing = line 1
i= 1
testing = line 1
and so on.
Why does it work on the first iteration but then it stops at i=1 ? I am asking because I don't know if what I did is correct or not. while(!function) works, but maybe it won't work all the time, maybe my code is flawed.
Or maybe while(getline(configFile, string[i++])); is at fault here ?
This is the code I am trying to replace:
void readConfig(std::fstream& configFile, std::string (&str)[10], std::string identity) {
if(configFile) {
// Get content line by line of txt file
int i = 0;
while(getline(configFile, str[i++]));
//for debug only
if((i-1) == 0) {
std::cout<<identity<<" = "<<str[i-1]<<std::endl;
} else {
for(int k = 0; k<i-1; k++) {
std::cout<<identity<<" = "<<str[k]<<std::endl;
}
}
} else {
log("ERROR ! Could not get content from file.");
}
}
int main() {
file.open(file, std::fstream::in);
if(file.is_open()) {
std::cout<<"Successfully opened URL Display Text file."<<std::endl;
std::string inputs[10];
std::string id = "url_text";
readConfig(file, inputs, id);
file.close();
} else {
// Could not open file
log("Error ! Could not open file.");
}
}
I do this 7 times, instead of just calling a function 7 times, that does all of that.
But if I change the condition of the while to while(function) one would expect to repeat the function until it fails somehow (maybe it can't open the file.).
You reasoning is off here. The function is not opening the file, so that is nothing that can go wrong on the next iteration when it suceeded on the first.
What the function does is: it reads all the contets of the file, then returns true. And subsequent iterations there is nothing left to read, but still the function returns true.
You should check if the file is open only once, not in each iteration. If the function is supposed to read a single line then make it so, currently it reads all.
Change the test from if (file.is_open()) to if (file). Failing to open the file is not the only way that a file stream can end up in a bad state. In particular, on the second call to this function, the stream is open, but it's in a failed state because the last read attempt failed.
If you just want to read the file line by line, print the lines and store them, I'd do it like this.
Rather than using a c-style array use a std::vector or std::array
Check the if the file is open before you call the read function
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
void readConfig(std::ifstream& configFile,
std::vector<std::string>& lines,
const unsigned int limit) {
std::string line;
while (std::getline(configFile, line)) {
if (lines.size() >= limit) {
break;
}
lines.push_back(line);
}
}
int main() {
const std::array<std::string, 3> fileNames = {"test1.txt",
"test2.txt",
"test3.txt"};
// Iterate over all your files
for (const auto& fileName : fileNames) {
// Open the file
std::ifstream configFile(fileName);
if (!configFile.is_open()) {
std::cout << "ERROR! Could not open file.\n";
continue;
}
// Read the file
std::vector<std::string> lines;
constexpr unsigned int limit = 4;
readConfig(configFile, lines, limit);
if (configFile.is_open()) {
configFile.close();
}
// Work with the file content
std::cout << fileName << "\n";
for (const auto& line : lines) {
std::cout << "testing = " << line << "\n";
}
std::cout << "\n";
}
return 0;
}
Your output paints a fairly clear picture of what is going on. You have enough debugging output to identify what choices have been made. They key point I would focus on is the following sequence:
testing =
i= 1
The first of these lines is the fifth line read from your four-line file. Not surprisingly, there is nothing there. The next output line comes from the next invocation of readConfig, somewhere in the branch where file.isopen() is true. However, note that there is not a line saying "Start from 0" between these two. That means file converted to false after the call to file.seekg(0) (the value returned by that function is file, not directly a boolean). This indicates some sort of error state, and one should expect that error state to persist until cleared. And there is no attempt made to clear it.
The next bit of code is the getline loop. As with seekg, the getLine function returns the stream (file) rather than a boolean. As expected, the error state has persisted, making the loop condition false, hence no iterations of the loop.
testing = line 1
The next line of output is ambiguous. It could indicate that the position was successfully changed to the start of the file, and that the first line of input was successfully read. Or it could indicate that the call to getLine returned before erasing the provided string, leaving the contents from the first call to readConfig. I'm thinking the latter, but you could check for yourself by manually erasing str[0] before the getline loop.
In general, reusing resources like this makes debugging harder because the results could be misleading. Debugging would be less confusing if str was a local variable instead of a parameter. Similar for file – instead of a stream parameter, you could pass a string with the name of the file to open.

In C++ while using cin.get(), how can I not limit the number of characters a user can enter?

Im trying to get a users input using cin.get() but I dont want to limit the amount of characters that they can enter. How can I do this?
EDIT: I guess a better way to phrase this would be: How can I dynamicaly change the character array to fit the length of the users input?
This is a strange requirement for a C++ program. You can of course go the C way and simply keep on getting more memory whenever your input outgrows the currently available memory. It goes something like this (warning: code fragments ahead):
while(cin.get(c)) {
if (cur_pos == cur_len) {
cur_len = grow_charbuf(buffer, cur_len);
}
buffer[cur_pos++] = c;
}
Here, the grow function is where it gets ugly. It needs to allocate a larger piece of memory, copy the contents of the current buffer to the beginning of that, dealocate the memory occupied by the current buffer, and return the new size. For example, something along these lines:
char* new_charbuf(size_t len) {
return new char [len];
}
size_t grow_charbuf(char* buf, size_t cur_len) {
size_t new_len = cur_len * 2;
char* new_buf = new char [new_len];
// copy old buffer contents to new buffer
delete[] buf;
buf = new_buf;
return new_len;
}
And you can then use it as follows:
cur_len = 1000; // or whatever
char* buffer = new_charbur(cur_len);
// write into the buffer, calling grow_charbuf() when necessary
// and don't forget to free the memory once you are done...
// or don't free it, if the program eventually exits anyway
This is terrible code. It might work, but you should never ever do this in C++ if you can avoid it. Apart from this, I have avoided handling any error conditions or exceptions that this code might cause. It is meant just to illustrate the idea.
Managing your memory manually is a bad idea because it requires a lot of code and is not easy to get right. You can get away with less if your program has a known, limited life-span.
Don't use characters array at all. Use std::string or other standard containers.
And of cause learn to use streams.
Here an example. It reads as many characters as the user inputs until the user presses enter. As you cna see, there is no explicite buffer-size required:
/////TEST PUT ANYWHERE IN GLOBAL SCOPE
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int test()
{
//SET BP HERE AND STEP THROUGH
string line;
getline(cin,line);
std::stringstream user_input( line );
while(!user_input.eof())
{
string word;
user_input >> word;
cout << word << endl;
}
return 0;
}
static int _test = test();
/////END TEST
You need a cin.getline(). In other words you need to have a specified size of char array and use it like so:
Using cin.get()
char str[100];
char sayHello[100];
cin.get(str, 100);
// make sure to add cin.ignore() or program will terminate right before next cin().
cin.ignore();
cout << str << endl;
cin.get(sayHello, 100);
cout << sayHello;
or for cin.getline()
char input[100];
cin.ignore(); // stops the sentence from truncating.
cin.getline(input,sizeof(input));
You could also use getline() for strings like so:
string name;
getline(cin, name);
The problem is that in c++ when receiving input your cin looks for the 0 aka the space in your sentence. It then ends thinking that was the end.

Decoding / Encloding Text File using Stack Library - Can't Encode Large Files C++

I am working on a program that can encode and then decode text in C++. I am using the stack library. The way the program works is that it first asks you for a cypher key, which you put in manually. It then asks for the file name, which is a text file. If it is a normal txt file, it encodes the message to a new file and adds a .iia files extension. If the text file already has a .iia file extension, then it decodes the message, as long as the cypher key is the same as the one used to encode it.
My program does encode and decode, but how many characters it decodes is determined by temp.size() % cypher.length() that is in the while loop in the readFileEncode() function. I think this is what is keeping the entire file from being encoded and then decoded correctly. Another words, the ending file after it has been decoded from say "example.txt.iia" back to "example.txt" is missing a large portion of the text from the original "example.txt" file. I tried just cypher.length() but of course that does not encode or decode anything then. The entire process is determined by that argument for the decoding and encoding.
I cannot seem to find out the exact logic for this to encode and decode all the characters in any size file. Here is the following code for the function that does the decoding and encoding:
EDIT: Using WhozCraig's code that he edited for me:
void readFileEncode(string fileName, stack<char> &text, string cypher)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
stack<char> temp;
char ch;
while (file.get(ch))
temp.push(ch ^ cypher[temp.size() % cypher.length()]);
while (!temp.empty())
{
text.push(temp.top());
temp.pop();
}
}
EDIT: A stack is required. I am going to implement my own stack class, but I am trying to get this to work first with the stack library. Also, if there is a better way of implementing this, please let me know. Otherwise, I believe that there is not much wrong with this except to get it to go through the loop to encode and decode the entire file. I am just unsure as to why it stops at, say 20 characters sometimes, or ten characters. I know it has to do with how long the cypher is too, so I believe it is in the % (mod). Just not sure how to rewrite.
EDIT: Ok, tried WhozCraig's solution and I don't get the desired output, so the error now must be in my main. Here is my code for the main:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cctype>
#include <stack>
using namespace std;
void readFileEncode(string fileName, stack<char> &text, string cypher);
int main()
{
stack<char> text; // allows me to use stack from standard library
string cypher;
string inputFileName;
string outputFileName;
int position;
cout << "Enter a cypher code" << endl;
cin >> cypher;
cout << "Enter the name of the input file" << endl;
cin >> inputFileName;
position = inputFileName.find(".iia");//checks to see if the input file has the iia extension
if (position > 1){
outputFileName = inputFileName;
outputFileName.erase(position, position + 3);// if input file has the .iia extension it is erased
}
else
//outputFileName.erase(position, position + 3);// remove the .txt extension and
outputFileName = inputFileName + ".iia";// add the .iia extension to file if it does not have it
cout << "Here is the new name of the inputfile " << outputFileName << endl; // shows you that it did actually put the .iia on or erase it depending on the situation
system("pause");
readFileEncode(inputFileName, text, cypher); //calls function
std::ofstream file(outputFileName); // calling function
while (text.size()){// goes through text file
file << text.top();
text.pop(); //clears pop
}
system("pause");
}
Basically, I am reading .txt file to encrypt and then put a .iia file extension on the filename. Then I go back through, enter the file back with the .iia extension to decode it back. When I decode it back it is gibberish after about the first ten words.
#WhozCraig Does it matter what white space, newlines, or punctuation is in the file? Maybe with the full solution here you can direct me at what is wrong.
just for information: never read file char by char it will take you hours to finish 100Mb.
read at least 512 byte(in my case i read directly 1 or 2Mb ==> store in char * and then process).
If I understand what you're trying to do correctly, you want the entire file rotationally XOR'd with the chars in the cipher key. If that is the case, you can probably address your immediate error by simply doing this:
void readFileEncode(string fileName, stack<char> &text, string cypher)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
stack<char> temp;
char ch;
while (file.get(ch))
temp.push(ch ^ cypher[temp.size() % cypher.length()]);
while (!temp.empty())
{
text.push(temp.top());
temp.pop();
}
}
The most notable changes are
Opening the file in binary-mode using std::ios::in|std::ios::binary for the open-mode. this will eliminate the need to invoke the noskipws manipulator (which is usually a function call) for every character extracted.
Using file.get(ch) to extract the next character. The member will pull the next char form the file buffer directly if one is available, otherwise load the next buffer and try again.
Alternative
A character by character approach is going to be expensive any way you slice it. That this is going through a stack<>, which will be backed by a vector or deque isn't going to do you any favors. That it is going through two of them just compounds the agony. You may as well load the whole file in one shot, compute all the XOR's directly, then push them on to you stack via a reverse iterator:
void readFileEncode
(
const std::string& fileName,
std::stack<char> &text,
const std::string& cypher
)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
// retrieve file size
file.seekg(0, std::ios::end);
std::istream::pos_type pos = file.tellg();
file.seekg(0, std::ios::beg);
// early exit on zero-length file.
if (pos == 0)
return;
// make space for a full read
std::vector<char> temp;
temp.resize(static_cast<size_t>(pos));
file.read(temp.data(), pos);
size_t c_len = cypher.length();
for (size_t i=0; i<pos; ++i)
temp[i] ^= cypher[i % c_len];
for (auto it=temp.rbegin(); it!=temp.rend(); ++it)
text.push(*it);
}
You still get your stack on the caller-side, but I think you'll be considerably happier with the performance.

How can I detect that input is being redirected in from a file?

I've written a program that takes its first argument and reverses the letters. So, for instance:
revstr cat
Will produce tac.
Now I want this to work when a file is redirected in. So, if filler.txt is a file containing "Now is the time for all good men to come to the aid of their country!", then:
revstr < filler.txt
Should produce:
!yrtnuoc rieht fo dia eht ot emoc ot nem doog lla rof emit eht si woN
But I don't know how to detect that such redirection is occurring!
This is what I've tried - obviously, it's no good. Where am I going wrong?
int main(int argc, char* argv[]) {
string temp,input,output;//store input from file, and get which file//
ofstream out("output.txt");
if(argc == 3)
{
if(ifstream(argv[2]))
{
input = argv[2];
ifstream in(input);
while(in.good())
{
in >> temp;
ReverseWord(temp);
cout << temp << endl;
out << temp << endl;
}
}
else
ReverseWord(argv[2]);
}
else
}
I'm fairly new to C++ and am doing my best to learn.
There are two possible approaches for you (well, you can even support both):
You can accept a file name as command line argument (using a main that accepts arguments), then open an ifstream using this filename as the stream to read from. Users use your program like revstr filename.txt.
You can read your input from std::cin. Then users need to use redirection to pass you the contents of a file. If your program is started using: revstr < filename.txt, then reading from std::cin will read the contents of the file. The program never even sees the filename.
You can support both by reading from an ifstream, if you get an argument, and from cin, if you don't get an argument. The function that does the reading can get the steam passed in as a generic istream&.
You should change your definition of your main() function so that it accepts arguments passed from command line:
int main(int argc, char* argv[])
The first variable will hold the number of command-line arguments provided, the second is a vector whose elements are pointers to NULL-terminated strings. These strings are the command-line arguments themselves. Please keep in mind, that the first string will always be the name of the executable.
For instance, supposing the name of the file to be opened will be passed as the first argument:
int main(int argc, char* argv[])
{
std::string filename;
if (argc > 1)
{
// Oh, there's some command line arguments here...
filename = argv[0];
}
// Go on processing...
}