I'm developing a simple console based email application.
In my app, messages are stored in std::vector, and I want to add possibility to delete messages.
How can I delete a element from a vector?
Here's my code:
//MAIN MENU OPTION 1 SELECTED:
// print list of all messages to the console
void viewInbox() {
vector<Message> inbox{
Message("jayleno#hotmail.com", "Knife you tonight", "Hey Sam, what kind of suit do you wanna be buried in?!"),
Message("paypalservices#hotmail.com", "Urgent from paypal.com", "Dear paypal user, someone has hacked your account. Give us your password now so we change it!"),
};
cout << "You have " << inbox.size() << " new messages.\n";
cout << "Index Subject" << '\n';
for (int i = 0; i < inbox.size(); ++i)
std::cout << "Message " << i << ": " << inbox[i].getSubject() << '\n';
cout << "Please enter number of message you would like to view\n";
int read;
cin >> read;
cout << "From: " << inbox[read].getAddress() << '\n';
cout << "Subject: " << inbox[read].getSubject() << '\n';
cout << inbox[read].getMessageText() << '\n';
cout << "To erase this message press 1\n";
//Code here for deleting a message...
}//end of viewInbox()
To erase a message from the vector use vector::erase which takes an iterator.
The easiest way to get an iterator to a particular message is to use inbox.begin() + message_number.
I have refactored your code into smaller functions to make the code easier to work with:
void viewMessage(vector<Message>& messages, size_t message_number) {
vector<Message>::iterator message = messages.begin() + message_number;
cout << "From: " << message->getAddress() << endl;
cout << "Subject: " << message->getSubject() << endl;
cout << message->getMessageText() << endl;
cout << "To erase this message press 1\n";
int erase;
cin >> erase;
// Maybe do some error checking on cin...
if (erase == 1) {
messages.erase(message);
}
}
void viewMessages(vector<Message>& messages){
auto inbox_size = messages.size();
cout << "You have " << inbox_size << " new messages.\n";
cout << "Index Subject" << '\n';
for (size_t i = 0u; i != inbox_size; ++i) {
std::cout << "Message " << i << ": " << messages[i].getSubject() << '\n';
}
cout << "Please enter number of message you would like to view\n";
size_t message_number;
cin >> message_number;
// Maybe do some error checking on cin...
// And some bounds checking of message_number...
viewMessage(messages, message_number);
}
void viewInbox() {
vector<Message> inbox{
Message{ "jayleno#hotmail.com", "Knife you tonight", "Hey Sam, what kind of suit do you wanna be buried in?!" },
Message{"paypalservices#hotmail.com", "Urgent from paypal.com", "Dear paypal user, someone has hacked your account. Give us your password now so we change it!"},
};
viewMessages(inbox);
// Maybe call viewMessages again to see results of erase...
}
As I have commented, watch out for error checking on your input.
Related
I'm creating a password system for an encryption program.
For this i moved my main chunk of code inside an if statement, however now, instead of reading the code line by line, it simply prints it all at once. (e.g. when it comes to std::cout << "Enter here: "; std::getline(std::cin, userin); the user cant input anything, it just prints the next line and keeps going.
int main(){
std::string userin;
std::string pass;
int attempts = 3;
std::cout << " ENCRYPTER" << std::endl;
std::cout << " " << std::endl;
while (attempts > 0){
std::cout << "Please Enter the Password" << std::endl;
if(attempts > 1){
std::cout << "You have " << attempts << " attempts remaining." << std::endl;
}
else {
std::cout << "You have " << attempts << " attempt remaining." << std::endl;
}
std::cin >> pass;
std::cout << " " << std::endl;
if(pass == "12345"){
std::cout << greetingFunc() << std::endl;
std::cout << " " << std::endl;
std::cout << "NOTE: Use only LETTERS. No numbers or grammar." << std::endl;
std::cout << " " << std::endl;
std::cout << "Please enter the message you wish to encrypt." << std::endl;
std::cout << "Enter here: "; std::getline(std::cin, userin);
std::cout << " " << std::endl;
std::cout << "Encrypted Message: " << encryptFunc(userin) << std::endl;
std::cout << " " << std::endl;
std::cout << "Highlight it and right click to copy." << std::endl;
system("pause");
} else {
std::cout << "Incorrect password. Please try again." << std::endl;
attempts--;
}
}
return 0;
}
Here is what is received in the console after the password is correctly entered.
Welcome to the Code Encrypter
NOTE: Use only LETTERS. No numbers or grammar.
Please enter the message you wish to encrypt.
Enter here:
Encrypted Message:
Highlight it and right click to copy.
Press any key to continue . . .
See how it just prints everything without running the functions or allowing the user to input their data.
How can i get it to read each line and stop to let the user input the info, and then proceed to call the encryption function? Thanks.
Just add std::getchar(); after std::cin >> pass
The problem is that when you enter pass and click enter, this enter keyboard will be considered as your next input. std::getchar(); receives the effect of enter keyboard. Now you can enter userin.
Note: Use std::getchar() only after you get a string by std::cin.
If you use std::getline(std::cin, pass); instead of std::cin >> pass;, you don't have to worry about the final '\n' because getline() doesn't let this character interrupt the next input.
Using stream operators with getline(cin, variable) is always a problem because some data remains in the input buffer. So you should remove everything still in there then read your input.
I.e.
while(getline(cin, userin))
if (userin != "")
break;
so this should works:
int main(){
std::string userin;
std::string pass;
int attempts = 3;
std::cout << " ENCRYPTER" << std::endl;
std::cout << " " << std::endl;
while (attempts > 0){
std::cout << "Please Enter the Password" << std::endl;
if(attempts > 1){
std::cout << "You have " << attempts << " attempts remaining." << std::endl;
}
else {
std::cout << "You have " << attempts << " attempt remaining." << std::endl;
}
std::cin >> pass;
std::cout << " " << std::endl;
if(pass == "12345"){
std::cout << greetingFunc() << std::endl;
std::cout << " " << std::endl;
std::cout << "NOTE: Use only LETTERS. No numbers or grammar." << std::endl;
std::cout << " " << std::endl;
std::cout << "Please enter the message you wish to encrypt." << std::endl;
std::cout << "Enter here: ";
while (std::getline(std::cin, userin))
if (userin != "")
break;
std::cout << " " << std::endl;
std::cout << "Encrypted Message: " << encryptFunc(userin) << std::endl;
std::cout << " " << std::endl;
std::cout << "Highlight it and right click to copy." << std::endl;
system("pause");
} else {
std::cout << "Incorrect password. Please try again." << std::endl;
attempts--;
}
}
return 0;
}
It looks like you're having issues with the input buffer. This is a very common issue when running command line/terminal programs.
When the cin >> pass is called, the stream buffer may have inputs remaining (namely the '\n' from pressing enter). You can do a few things, but the easiest thing is to call cin.get() after the cin >> pass.
You could also try creating a helper function or parsing the input using a while loop.
When the program enters in the if and then break, empty cout-s are printed again.
void Person::ShowRecords()
{
std::ifstream data("Input.txt");
while (true)
{
if (!data.good())
{
break;
}
Person person;
data >> person;
std::cout << "First Name: " << person.getFirstName() << "\n";
std::cout << "Last Name: " << person.getLastName() << "\n";
std::cout << "Phone number: " << person.getNumber() << "\n";
std::cout << "EGN: " << person.getEGN() << "\n\n";
}
}
I really think that the most didactic way of tackling stream input is:
while (true) {
// Read
// Check (if fail then break)
// Use
}
Notice the pattern: infinite loop with Read/Check/Use. Check is where we can exit the loop. First you read, than you check if the reading operation was successful or failed, than you can use the data or exit based on that.
Adapting this to your case:
void Person::ShowRecords()
{
std::ifstream data("Input.txt");
while (true) {
// Read
Person person;
data >> person;
// Check
if (!data) {
break;
}
// Use
std::cout << "First Name: " << person.getFirstName() << "\n";
std::cout << "Last Name: " << person.getLastName() << "\n";
std::cout << "Phone number: " << person.getNumber() << "\n";
std::cout << "EGN: " << person.getEGN() << "\n\n";
}
}
The non didactic and probably more idiomatic way is:
void Person::ShowRecords()
{
std::ifstream data("Input.txt");
Person person;
while (data >> person) { // Read and, immediately after, Check
std::cout << "First Name: " << person.getFirstName() << "\n"; // Use
std::cout << "Last Name: " << person.getLastName() << "\n";
std::cout << "Phone number: " << person.getNumber() << "\n";
std::cout << "EGN: " << person.getEGN() << "\n\n";
}
}
So I'm writing this spinoff game of Paperboy as a class project. If I wanted to I could say I'm finished and turn it in but I want it to have a professional touch to it. My game consists of different modes: easy and hard. However I have not implemented the hard mode yet.
Anyway, here is my code
void easyMode() {
string playerName;
int numNewspapers, numDelivered = 0, numMissed = 0, score = 0;
cout << "Enter Your Player Name: ";
cin >> playerName;
cout << "\nEnter How Many Newspapers That Need To Be Delivered: ";
cin >> numNewspapers;
cout << "\n\nYou have " << numNewspapers << " newspapers to deliver!\n\n";
cout << "Time To Deliver !!\n\n";
cout << "*===================================*\n\n";
//cout << string(50, '\n');
while (numDelivered < numNewspapers) {
int outcome = RandomNumberEasy();
cout << "*===================================*\n\n";
cout << "Delivering Newspaper...\n\n";
// Game Sequence
//*===================================*
// Delivered Successfully
//*===================================*
if (outcome <= 3 || outcome > 7) {
cout << "You Successfully Delivered The Newspaper.\n\n";
numDelivered++;
score = score + 15;
cout << "Your score is " << score << " points!\n\n";
}
// Delivery Failed
//*===================================*
else {
cout << "The Neighbor's Dog Chased You. Delivered Paper Didn't Quite Land On Step\n\n";
numDelivered++;
numMissed++;
score = score + 5;
cout << "Your score is " << score << " points!\n";
}
cout << "\n";
sleep(1);
}
// END GAME
//*===================================*
if (numDelivered == numNewspapers) {
int SuccDeliver = numDelivered - numMissed;
cout << "*===================================*\n\n";
cout << "Congratulations, " << playerName << "!\n\n";
cout << "Your Final Score Is: " << score;
cout << "\n\nYou missed " << numMissed << " Newspapers And Delivered " << SuccDeliver << " Newspapers\n\n";
}
}
As you can see I do have the sleep function in there, but when I run my program, it waits a long time and the outputs every iteration all at once. I want it to wait in between each iteration but I can't seem to get it to work.
Any help is appreciated!
The problem seems to be that the output buffer is not being flushed. A way to do it is to use cout << endl instead of cout << "\n". Mainly, this part:
cout << "\n";
sleep(1);
Should be like this:
cout << endl;
sleep(1);
And that should fix it!
main.cpp
void torsoOPCB(Fl_Widget *w, void* p) {
for(std::size_t i=0; i < torso.size(); i++) {
cout << "Name: " << torso[i].GetName() << endl;
cout << "Part Number: " << torso[i].GetPartNumber() << endl << endl;
} // This loop is to check if the inputs are in the vector torso
dialog = new Fl_Window(340, 300, "Robot Part");
Fl_Multiline_Output* output = new Fl_Multiline_Output(100, 10, 400, 200, "Torso list:");
for(std::size_t i = 0; i < torso.size(); i++) {
output->value(torso[i].print().c_str());
}
dialog->end();
dialog->set_non_modal();
dialog->show();
}
I'm learning how to use FLTK in C++ and I'm not sure why it keeps showing me the latest user's inputs. For example, if I entered the inputs for torso[0] and torso[1], the output will only show torso[1] which is the latest input. The inputs are stored correctly I think but I'm not sure why it won't show both torso[0] and torso[1].
Here is my print fucntion
Torso.cpp
std::string Torso::print()
{
ostringstream of;
of << "Part name: " << GetName()
<< endl << "Part #: " << GetPartNumber()
<< endl << "Weight: " << GetWeight()
<< endl << "Cost: " << GetCost()
<< endl << "Battery Comp: " << GetDescription()
<< endl << "Description: " << GetBatteryCompartmentSize() << endl;
return of.str();
}
I'm using FLTK version 1.3.4. Thank you in advanced
You are only showing the very last item in
for(std::size_t i = 0; i < torso.size(); i++) {
output->value(torso[i].print().c_str());
}
The output value is always being overwritten. If you wish to show all the output, gather it up first before putting it into the widget
std::ostringstream oss;
for(std::size_t i = 0; i < torso.size(); i++) {
oss << torso[i].print() << "\n";
}
output->value(oss.str().c_str());
If you don't mind multiple outputs on the same line, change the "\n to ". "
I am working on a program that reads data from a text file called "phonebook.txt" and displays it in terminal. It ask how many contacts the user wants to add. The user will input the number of contacts he/she wants and the program will output this along with the old contacts from "phonebook.txt" to "updated-phonebook.txt." Now I chose to use a dynamic array over a vector simply because I wanted to get a feel for how to handle memory allocation.
#include <iostream>
#include <string>
#include <fstream>
#define nullptr 0;
struct Person
{
std::string lName, fName, streetAddr, city, state, zip, phoneNum;
};
int main ()
{
std::ofstream outFile;
std::string dummy;
int amount, total, count = 0;
Person *contact;
//set the pointer to 0 so its not pointing
//to anything else in memory
contact = nullptr;
std::ifstream inFile("/home/isemanthaj/My_Programs/Class_Programs/Assignment_3/phonebook/phonebook.txt",std::ios::in);
if (!inFile)
{
std::cout << "File failed to open" << std::endl;
}
else
outFile.open("updated_phonebook.txt", std::ios::out);
std::cout << "How many contacts do you want to add?" << std::endl;
std::cin >> amount;
contact = new Person[amount];
std::cout << "Contacts in the previous book \n" << std::endl;
std::cin.ignore();
while (inFile)
{
//dummy stores the contact number which is the first line
// in the read file. I don't want to carry the number over
// to the other updated_phonebook.txt file
std::getline(inFile, dummy);
std::getline(inFile, contact[count].lName);
std::getline(inFile, contact[count].fName);
std::getline(inFile, contact[count].streetAddr);
std::getline(inFile, contact[count].city);
std::getline(inFile, contact[count].state);
std::getline(inFile, contact[count].zip);
std::getline(inFile, contact[count].phoneNum);
std::cout << contact[count].lName << std::endl;
std::cout << contact[count].fName << std::endl;
std::cout << contact[count].streetAddr << std::endl;
std::cout << contact[count].city << std::endl;
std::cout << contact[count].state << std::endl;
std::cout << contact[count].zip << std::endl;
std::cout << contact[count].phoneNum << std::endl;
outFile << contact[count].lName << std::endl;
outFile << contact[count].fName << std::endl;
outFile << contact[count].streetAddr << std::endl;
outFile << contact[count].city << std::endl;
outFile << contact[count].state << std::endl;
outFile << contact[count].zip << std::endl;
outFile << contact[count].phoneNum << std::endl;
count++;
}
// I know this is a little wacky here.
// I want the program to display the total amount of contacts
// to the screen
total = amount + count;
for (int index = 0; index < total; index++)
{
std::cout << "Last name: ";
std::getline(std::cin, contact[index].lName);
std::cout << "First name: ";
std::getline(std::cin, contact[index].fName);
std::cout << "Street address: ";
std::getline(std::cin, contact[index].streetAddr);
std::cout << "City: ";
std::getline(std::cin, contact[index].city);
std::cout << "State: ";
std::getline(std::cin, contact[index].state);
std::cout << "Zip code: ";
std::getline(std::cin, contact[index].zip);
std::cout << "Phone number: ";
std::getline(std::cin, contact[index].phoneNum);
std::cout << std::endl;
std::cout << "Contact: " << index + 1 << std::endl;
std::cout << "Last name: " << contact[index].lName << std::endl;
std::cout << "First name: " << contact[index].fName << std::endl;
std::cout << "Street address: " << contact[index].streetAddr << std::endl;
std::cout << "City: " << contact[index].city << std::endl;
std::cout << "State: " << contact[index].state << std::endl;
std::cout << "Zip code: " << contact[index].zip << std::endl;
std::cout << "Phone number: " << contact[index].phoneNum << std::endl;
std::cout << std::endl;
outFile << "Last name: " << contact[index].lName << std::endl;
outFile << "First name: " << contact[index].fName << std::endl;
outFile << "Street address: " << contact[index].streetAddr << std::endl;
outFile << "City: " << contact[index].city << std::endl;
outFile << "State: " << contact[index].state << std::endl;
outFile << "Zip code: " << contact[index].zip << std::endl;
outFile << "Phone number: " << contact[index].phoneNum << std::endl;
}
inFile.close();
outFile.close();
delete [] contact;
return 0;
}
I am trying to store the new contacts the user created and the old contacts from the read file in one dynamic array of structures. Am I getting this segmentation fault because I am using two different indexes "count" and "index" to store the contacts in the same dynamic array?
Your segfault is happening because you are trying to access an out-of-bounds element of contact array. The size of contact is amount, and you are iterating it from 0 to amount + count. Obviously, amount + count >= amount, so sooner or later you will run out of bounds.
I would suggest you to use std::vector instead of a plain array. You will always be aware of it's size and will be able to iterate it safely.
If you want to keep the arrays, you will have to either reallocate contact after copying the contacts from the old file, to make it size equal to total, or make two separate arrays: one to hold the records from the old file with the size of amount elements, and another one for the newly-added contacts with the size of count elements.
As it is mentioned in the comments, your end-of-file check is wrong, this and this questions are relevant.