C++ cin.getline() causes program to crash - c++

I'm making a simple encryption/decryption program... I'm a beginner.
#include <time.h>
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
char s[1025];
char o[1025];
char key[1025];
char tochar(int a)
{
if(a<26) return 'a'+a;
if(a>25 and a<52) return 'A'+a-26;
if(a>51) return '0'+a-52;
}
int toint(char t)
{
if(t>='a' and t<='z') return 0-'a'+t;
if(t>='A' and t<='Z') return 26+t-'A';
if(t>='0' and t<='9') return 52+t-'0';
}
int main()
{
int i,j,keylenght;
//for(j=0;j<62;j++)cout<<j<<" "<<tochar(j)<<" "<<toint(tochar(j))<<endl;
cout<<"Enter String:\n";
cin.getline(s,1024);
cout<<"Function [encrypt/decrypt]: ";
char f;
cin>>f;
if(f=='e')
{
cout<<"Generate key? [y/n]: ";
cin>>f;
if(f=='y')
{
cout<<"Enter key length [up to 1024]: ";
cin>>keylenght;
srand(time(0));
for(i=0;i<keylenght;i++)
{
key[i]=tochar(rand()%62);
}
}
else
{
cout<<"Enter key: \n";
cin.getline(key,1024);
for(keylenght=0;key[keylenght]!='\0';keylenght++);
}
for(i=0;s[i]!='\0';i++)
{
if(key[keylenght%i]!=' ')
{
if(s[i]!=' ')o[i]=tochar((toint(s[i])+toint(key[i%keylenght]))%62);
else o[i]=' ';
}
else
{
o[i]=s[i];
}
}
cout<<endl<<"Encrypted string: "<<o<<endl<<"Generated key: "<<key;
}
else
{
cout<<"Enter key: ";
cin>>key;
for(keylenght=0;key[keylenght]!='\0';keylenght++);
for(i=0;s[i]!='\0';i++)
{
if(s[i]!=' ')
{
if(key) o[i]=tochar((62+toint(s[i])-toint(key[i%keylenght]))%62);
}
else o[i]=' ';
}
cout<<endl<<"Decrypted string:\n"<<o;
}
return 0;
}
The first time I use getline() it works flawlessly. However when I try to use it to write in the key[] string, it crashes the program.
Can anyone tell me what's going on?

The problem is that you are mixing your input types. When you call
cin>>f;
That leaves a newline in the input buffer. Then on your call to getline() key only gets the newline. What you need to do is clear the input buffer before you call getline. I like to use:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')

Do not use istream::getline(), use std::getline() instead. It is safer.

Related

How to exit the loop :while(cin>>n) in C++

This is a program that counts how many letters and numbers a string has,but when I Press Enter to exit after entering,it has no response.
#include <iostream>
using namespace std;
int main()
{
char c;
int nums=0,chars=0;
while(cin>>c){
if(c>='0'&&c<='9'){
nums++;
}else if((c>='A'&&c<='Z')||(c>='a'&&c<='z')){
chars++;
}
}
printf("nums:%d\nchars:%d",nums,chars);
return 0;
}
Pressing enter does not end input from std::cin and std::cin stops when encountering a whitespace.
Better would be to use std::getline and std::isdigit as shown below:
int main()
{
int nums=0,chars=0;
std::string input;
//take input from user
std::getline(std::cin, input);
for(const char&c: input){
if(std::isdigit(static_cast<unsigned char>(c))){
nums++;
}
else if(std::isalpha(static_cast<unsigned char>(c))){
chars++;
}
}
std::cout<<"nums: "<<nums<<" chars: "<<chars;
return 0;
}
Demo

Why does this not ask user for another input?

This part of a larger project. Right now it's supposed to ask user for a string, calculate how many words are in it, print out the # of words, ask user if they want to do it again, then if they want to, ask for another string, and so on. But this only works fine the first time. After that, it takes the answer to the yes/no question as the test string. For example: I like coding. 3. Again? Yes/no. Yes. 1. Again? Yes/no... Can someone tell me how to fix this glitch?
#include <iostream>
#include <string>
using namespace std;
string original[10] = { "hello", "sir", "madam", "officer", "stranger", "where", "is", "the", "my", "your" };
string translated[10] = { "ahoy", "matey", "proud beauty", "foul blaggart", "scurvy dog", "whar", "be", "th'", "me", "yer" };
string input;
string ans;
bool playAgain()
{
cout << "Another? yes/no: ";
cin >> ans;
if (ans.compare("yes") == 0) { return true; }
if (ans.compare("no") == 0) { return false; }
}
int getNumOfWords(string input)
{
int numOfSpaces = 0;
string current;
for (int i = 0; i < input.length(); i++)
{
current = input.at(i);
if (current.compare(" ") == 0)
{
numOfSpaces++;
}
}
return numOfSpaces + 1;
}
void play(string input)
{
int numOfWords = getNumOfWords(input);
cout << numOfWords << endl;
}
void start()
{
getline(cin, input);
play(input);
}
int main()
{
bool playing;
do
{
start();
playing = playAgain();
} while (playing);
return 0;
}
When cin.getline() reads from the input, there is a newline character left in the input stream, so it doesn't read your c-string. Use cin.ignore() beore calling getline()
void start()
{ cin.ignore();
getline(cin, input);
play(input);
}
It's because of the difference between getline and cout. The former reads in the entire line up to and including the terminating \n, while cout will read only up to the \n or whitespace. The cin in your code reads in yes or no to ans (try printing it out immediately afterwards), but it doesn't account for the \n. Thus, when you call getline it finds the \n waiting in stdin, and so reads that into input instead of blocking until cin wasn't empty.

C++ encrypt and decrypt secret messages using files

I have my prototypes in a header file, but I need some help. I am having some trouble getting the program to compile all the way through. It appears to be getting caught in a loop with the input. Possibly some issues with the functions. Thanks in advance for any input.
#include <iostream>
#include <conio.h>
#include "header.h"
#include <fstream>
class Caesar
{
public: void readText(char *input);
void encrypt(char *input,char *output,char *key);
void decrypt(char *input,char *output,char *key);
};
void main()
{
Caesar a;
char key[1000];
ifstream fin;
int choice;
char input[100],output[100];
cout<<"\n Enter input file: ";
cin>>input;
cout << input;
cout<<"\n Enter output file: ";
cin>>output;
cout <<output;
cout<<"\n Enter key: ";
cin>>key;
cout <<key;
cout<<"\n\n 1. Encrypt\n 2. Decrypt\n\n Select choice(1 or 2): "<< endl;
cin >> choice;
cout << choice;
a.readText(input);
if(choice==1)
{
a.encrypt(input,output,key);
}
if(choice==2)
{
a.decrypt(input,output,key);
}
else
{
cout<<"\n\n Unknown choice";
}
}
void Caesar::readText(char *input)
{
ifstream reader;
char buf;
reader.open(input);
cout<<"\n\n <--- "<<input<<" --->\n";
buf=reader.get();
while(!reader.eof())
{
cout<<buf;
buf=reader.get();
}
reader.close();
}
void Caesar::encrypt(char *input,char *output,char *key)
{
ifstream reader;
ofstream writer;
char buf;
reader.open(input);
writer.open(output);
buf=reader.get();
while(!reader.eof())
{
if(buf>='a'&&buf<='z')
{
buf-='a';
buf+=key[buf];
buf%=26;
buf+='A';
}
writer.put(buf);
buf=reader.get();
}
reader.close();
writer.close();
readText(input);
readText(output);
}
void Caesar::decrypt(char *input,char *output,char *key)
{
ifstream reader;
ofstream writer;
char buf;
reader.open(input);
writer.open(output);
buf=reader.get();
while(!reader.eof())
{
if(buf>='A'&&buf<='Z')
{
buf-='A';
buf+=26-key[buf];
buf%=26;
buf+='a';
}
writer.put(buf);
buf=reader.get();
}
reader.close();
writer.close();
readText(input);
readText(output);
}
if(choice=1)
should be
if(choice==1)
and also in the other if
In your case, you are assigning the value 1 to choice, then test if choice is true, and it is, since any non-zero numeral type is implicitly casted to bool true.
I have just executed your code and tried debugging it and took a screen shot
you program gets into a loop after entering the choice.there is no problem with cin>>.
From your comments, it seems like you're just trying to debug main. Everything seems to work fine. What are you inputting for key? If it's a very large integer, that may be your problem as it might exceed the maximum integer range and cause overflow.
Your key is an integer variable. You are inputting a string for the file name that holds your key, so that should be changed to a C string array. Change all of the passed key parameters to char* instead of int.
You have an infinite loop when the readText() function is called.
Maybe try this:
void Caesar::readText(char *input)
{
ifstream reader(input);
if(reader.is_open())
{
char buf;
cout<<"\n\n <--- "<<input<<" --->\n";
while(reader.get(buf))
{
cout << buf;
}
}
reader.close();
}
Make sure that your text file is in the same folder as your code. See this for more details: ifstream not opening file

Program hangs because of some reason

The following code is supposed to read records from input and store them in a file called file.dat. Then it is supposed to arrange these records in ascending order, but for some reason the program hangs in the second while loop at line "file1.seekg(-(sizeof(r)),std::ios::cur);". Can someone please tell me what's wrong?
#include <iostream>
#include <fstream>
#include <strstream>
int main()
{
std::ofstream file;
file.open("file.dat",std::ios::trunc|std::ios::binary);
if(!file)
std::cout<<"unable to open for output";
struct record
{
char code[6];
char name[20];
int i;
};
record r;
int a = 0;
while(1)
{
std::cout<<"Record " << a + 1 << std::endl;
std::cout<<"Enter character code, name and an int \n";
std::cin.ignore();
std::cin.getline(r.code,6);
std::cin.getline(r.name,20);
std::cin>>r.i;
file.write((char *)&r,sizeof(r));
std::cout<<"\nAdd another (y\\n) : ";
char c;
std::cin>>c;
if(c == 'n')
break;
a++;
std::cout<<'\n'<<'\n';
}
file.close();
std::fstream file1("file.dat",std::ios::in|std::ios::out|std::ios::binary);
if(!file1)
std::cout<<"unable to open file1";
else
{
if(a>0)
{ while(a)
{
file1.seekp(0);
for(int i = a; i>0;i--)
{
record r1;
file1.read((char *)&r,sizeof(r));
file1.read((char *)&r1,sizeof(r1));
if(r1.i < r.i)
{
file1.seekp(-(sizeof(r)*2),std::ios::cur);
file1.write((char *)&r1,sizeof(r));
file1.write((char *)&r,sizeof(r));
file1.seekg(-(sizeof(r)),std::ios::cur);
}
}
a--;
}
}
file1.close();
}
std::ifstream file2("file.dat",std::ios::binary);
if(!file2)
std::cout<<"unable to open file2";
else
while(1)
{
std::cout<<"\n\n";
file2.read((char *)&r,sizeof(r));
if(file2.eof())
break;
std::cout<<r.code<<'\t'<<r.name<<'\t'<<r.i;
}
}
first
change std::get.ignore -> std::cin.ignore()
if you want to discard one character.
it compiled well and created file.dat file..
you might check the record inside file.dat though
If you are trying to ignore the new line character entered after the actual dat, then you have to use:
std::cin.ignore();
If you want more reference on use of ignore go to this LINK

Break a loop when the user just input an enter in visual c++ or code blocks

I want to know how to make stop a while loop when the user just input an Enter without asking to continue or , here is my code:
int main()
{
bool flag = true;
int userInput;
while(flag){
cout<<"Give an Integer: ";
if(!(cin >> userInput) ){ flag = false; break;}
foo(userInput);
}
}
Thanks in advance.
Try this:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
int userInput;
string strInput;
while(true){
cout<<"Give an Integer: ";
getline(cin, strInput);
if (strInput.empty())
{
break;
}
istringstream myStream(strInput);
if (!(myStream>>userInput))
{
continue; // conversion error
}
foo(userInput);
}
return 0;
}
Use getline. Break if the string is empty. Then convert the string to an int.
for(std::string line;;)
{
std::cout << "Give an Integer: ";
std::getline(std::cin, line);
if (line.empty())
break;
int userInput = std::stoi(line);
foo(userInput);
}
std::stoi will throw an exception on failure, handle that however you want.