Why is my file 'database2' empty and no files being renamed? After the part where the problem is stated in comments, the file 'database2' becomes 0 bytes. The file 'database2' is also not renamed and the file 'database' is not being deleted. Please help me, here is part of my code:
int edit(){
char KeyStroke;
std::string strings;
string name;
string name1;
std::string dummy;
std::string strings2;
std::string strings3;
ifstream myfile;
ofstream myfile1;
bool found = false;
myfile.open("database");
cout << endl << "What is the name of the contact you wish to go in detail?" << endl;
getline(cin, name);
while ( !found && getline (myfile ,strings) ) {
if (strings.find(name) != std::string::npos) {
cout << endl << "Name:\t\t" << strings<<endl;
std::getline( myfile, strings );
cout << "Address:\t" << strings<<endl;
std::getline( myfile, strings );
cout << "Handphone:\t" << strings;
}
}
start:
cout << endl <<endl;
cout << "What do you wish to edit?"<<endl;
cout << "1) Name"<<endl;
cout << "2) Address"<<endl;
cout << "3) Handphone"<<endl;
cout << "4) Nothing" << endl;
myfile.close();
/*--Main part of this code is from here onwards--*/
lol:
myfile.open("database");
myfile1.open("database2");
KeyStroke = getch();
switch(KeyStroke){
case '1':
cout << "What is the new name: ";
getline(cin, name1);
while ( !myfile.eof()) {
getline (myfile ,strings);
if (strings.find(name) != std::string::npos) {
myfile1 << name1 << endl;
}
else{
if(strings[0] == ' '){
continue;
}
myfile1 << strings << endl;
}
}
myfile1 << " ";
myfile1.close(); /*Once the file closes here, the data written in earlier dissapears*/
myfile.close();
remove("database");
pause1();
rename("database2","database");
goto start;
This is whats happening:
You have a "loop" going on with the "start" label and the goto at the end. So this will be the first part of the loop:
cout << endl <<endl;
cout << "What do you wish to edit?"<<endl;
cout << "1) Name"<<endl;
cout << "2) Address"<<endl;
cout << "3) Handphone"<<endl;
cout << "4) Nothing" << endl;
myfile.close();
/*--Main part of this code is from here onwards--*/
lol:
myfile.open("database");
myfile1.open("database2");
cin.get (&KeyStroke,256);
See in the first part of your loop you open/create two files called "database" and "database2" (note that ofstream open method creates the file if it doesnt exist already) and then waits for the user input.
Lets say the user press 1 to change the name, at the end of the case 1 statement you have this:
myfile1 << " ";
myfile1.close(); /*Once the file closes here, the data written in earlier dissapears*/
myfile.close();
remove("database");
// pause1(); // undefined
rename("database2","database");
goto start;
You close the files, delete database, and rename databese2 to database, which is working as intended, and then you go back to the start of the "loop" with the goto, which excecutes this part of the code again:
cout << endl <<endl;
cout << "What do you wish to edit?"<<endl;
cout << "1) Name"<<endl;
cout << "2) Address"<<endl;
cout << "3) Handphone"<<endl;
cout << "4) Nothing" << endl;
myfile.close();
lol:
myfile.open("database");
myfile1.open("database2");
You open database file and since you renamed your old database2 to database (database2 now doesnt exist) it creates a new one (empty of course).
hope it helps.
Related
I have written some code for the search function in C++ to find artist name and song. My code doesn't seem to work. A message displays that the artist and song is found and then the menu repeats itself infinite times.
My full program code is as below.
#include "Music.h"
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
void Music::menu()
{
int input;
do {
cout << "Select an option from the menu" << endl;
cout << "1. Display records" << endl;
cout << "2. Search for records" << endl;
cout << "3. Writing records to a file" << endl;
cin >> input;
switch (input) {
case 1:
displayfile();
break;
case 2:
searchrecords();
break;
case 3:
writefile();
break;
default:
cout << "Invalid option entered. Try again" << endl;
menu();
}
} while (input != 4);
}
void Music::displayfile()
{
string line;
ifstream myfile;
myfile.open("Music.txt");
if (myfile.is_open()) {
while (getline(myfile, line)) {
cout << line << endl;
}
myfile.close();
}
else {
cout << "Unable to open file" << endl;
}
}
void Music::writefile()
{
ofstream write;
write.open("Music.txt", ofstream::app);
if (write.is_open()) {
cin.ignore();
cout << "Enter a title of song to the playlist" << endl;
cin.getline(title, 255).get();
write << " " << title;
cout << "Enter the artist of the song to playlist" << endl;
cin.getline(artist, 255).get();
write << " " << artist;
cout << "Enter the year of the song" << endl;
cin >> year;
write << "" << year;
cout << "Enter the duration of the song" << endl;
cin >> duration;
write << " " << duration;
cout << "Writing to a file is successful" << endl;
}
else {
cout << "File couldn't be open" << endl;
}
write.close();
displayfile();
}
bool Music::searchrecords()
{
bool found = true;
string search;
string line;
ifstream myfile;
myfile.open("Music.txt");
cout << "Enter the artist you want to search for: " << endl;
getline(cin, search).get();
cout << "Enter for the song you want to search for: " << endl;
getline(cin, search).get();
if (myfile.is_open()) {
while (!myfile.eof()) {
if (found) {
cout << "The artist is found" << search << endl;
cout << "The song is found" << search << endl;
return found;
}
else {
cout << "The artist is not found" << endl;
return false;
}
getline(myfile, line);
myfile.close();
displayfile();
}
}
}
Appreciate it if you could help me as I am stuck on what to do.
You have bool found = true; right in the beginning of Music::searchrecords function, so the first iteration of looking through file immediately returns.
You do getline(cin, search).get(); twice in a row, while apparently you want to read in two different string variables, one for artist, one for song
You do a loop with this if on each iteration
if (found) {
cout << "The artist is found" << search << endl;
cout << "The song is found" << search << endl;
return found;
}
else {
cout << "The artist is not found" << endl;
return false;
}
In both cases you terminate your function by calling return, so the very first iteration of looking through file returns from function (you don't read the file completely)
You call
myfile.close();
displayfile();
on each iteration, so even if you hadn't had your if right above, then your program would crash anyway, because you close file inside the loop that's iterating over it.
You don't compare line to check if you indeed found your song
In total, your program doesn't work at all, and StackOverflow isn't a forum to completely write the entire program instead of you. So you better use a debugger in your IDE to see what your program does step by step, or take a piece of paper and a pen to write down how you would accomplish your task
I am new to C++ and write a little todo list on the console.
I am only able to add one line to a text file but when I try to add more it just won't appear on my text file.
Please take a look what I am doing wrong
//output-file stream
ofstream file;
file.open("output.txt", std::ios_base::app); //append
bool isRunning = true;
while (isRunning) {
cout << "Please select an action:" << endl;
cout << "add - adding tasks to the list" << endl;
cout << "del - deleting tasks to the list" << endl;
cout << "list - show the list" << endl;
cout << "x - to exit program" << endl;
string input;
cin >> input;
string addedTask;
if (input == "add") {
cout << "Please enter a task you like to add: " << endl;
cin.ignore();
if (std::getline(std::cin, addedTask)) {
file << addedTask << "\n";
}
else {
cout << "Failed to read line" << endl;
}
}
Why can I only add one string line? I still can't figure out the problem or am I missing something?
Did you try replacing your
file << addedTask << "\n";
by
file << addedTask << endl;
I think it should work (for me it's working)
I'm trying to store multiple structs into an file and my problem is that when I try to add 2 structs into the same file, my second struct overwrites my first struct and when I go print out my first struct, its print out my second struct. I want to have multiple structs in my file that I can display one at a time and edit them one at a time if I want. Any clue on what's wrong with my code?
int main()
{
Record record1;
Record record2;
int choice;
int choice2;
cout << "Welcome to your Records! What do you want to do today?" << endl;
cout << endl << endl;
while(choice2 != -1)
{
cout << " " << endl;
cout << "1) Add new records to the file" << endl;
cout << "2) Display any record in the file" << endl;
cout << "3) Change any record in the file" << endl;
cout << "4) Exit" << endl;
cout << "Your Choice: ";
cin >> choice;
while(choice < 1 || choice > 4)
{
cout << "Invalid choice! Enter again" << endl;
cin >> choice;
}
if(choice == 1)
{
ofstream outFile("RecordFile.dat", ios::out | ios::binary);
AddItem(outFile);
outFile.close();
}
else if(choice == 2)
{
ifstream inFile("RecordFile.dat",ios::out | ios::binary);
DisplayItem(inFile);
inFile.close();
}
else if(choice == 3)
{
ofstream outFile("RecordFile.dat", ios::out | ios::binary);
EditItem(outFile);
outFile.close();
}
else if(choice == 4)
{
choice2 = -1;
}
}
return 0;
}
Header File
struct Record
{
char name[15];
int quantity;
double wholesalecost;
double retailcost;
};
void AddItem(ofstream& outFile);
void DisplayItem(ifstream& inFile);
void EditItem(ofstream& outFile);
Functions
void AddItem(ofstream& outFile)
{
Record record;
cout << "What is the name of this record: ";
cin.ignore();
cin.getline(record.name,15);
cout << "How many do we have(quantity): ";
cin >> record.quantity;
cout << "Whats the whole sale cost: ";
cin >> record.wholesalecost;
cout << "Whats the retail cost of " << record.name << ":";
cin >> record.retailcost;
if(outFile)
{
outFile.write((char*)&(record),sizeof(record));
}
else
{
cout << "File not Found" << endl;
}
}
void DisplayItem(ifstream& inFile)
{
Record record;
int recordnum;
cout << "Enter what record number you want to display " << endl;
cin >> recordnum;
recordnum--;
if(inFile)
{
inFile.seekg(sizeof(Record) * recordnum, ios::beg);
inFile.read(reinterpret_cast<char *>(&record), sizeof(record));
cout << "Name: " << record.name << endl;
cout << "Quantity: " << record.quantity << endl;
cout << "Whole Sale Cost: " << record.wholesalecost << endl;
cout << "Retail Cost: " << record.retailcost << endl;
}
else
{
cout << "File not found" << endl;
}
}
You are writing everything to the beginning of the file, so of course multiple writes overwrite eachother.
You need to define a file format that can contain multiple records and a way to find where to write new records that doesn't overlap with previous ones, as well as an easy way to find the location of existing records.
Have you considered just using a SQL (or other type of) database?
I'm new to c++ (and coding in general) and have recently been working with a struct held inside a vector, in this case :
struct Contact{
string name;
string address;
string phone;
string email;};
vector<Contact> contacts;
So, one of my functions involves searching through each of the contacts to find the one for which the string stored in name matches a search input. To do this I made a for loop as such:
for(int i = 0; i < contacts.size(); i++){
if(contacts[i].name == searchInput){
cout << contacts[i].address << "\n\r" << contacts[i].phone << "\n\r" << contacts[i].email;
But for some reason this was only able to find the correct contact if it was the name stored at:
contacts[0].name
and none of the others. So while trying to figure out what was wrong, I decided to do
cout << contacts.size();
which I thought should output 3, because I have only three contacts stored. Yet for some reason, it output 7. Is there anyway for me to accurately list the number of iterations of Contact stored in the contacts vector in order to get my for loop to work?
Edit for my full code:
#include <vector>
#include <iostream>
#include <fstream>
using namespace std;
struct Contact
{
string name;
string address;
string phone;
string email;
};
bool go;
bool a = false;
char command;
string endL = "\n\r";
string tab = "\t";
string line;
int i;
int counter = 0;
int contactCounter = 0;
vector<Contact> contacts;
void add(){
contacts.push_back(Contact());
int newcontact = contacts.size() - 1;
string input;
cout << "Enter the name: " << endL;
cin >> input;
contacts[newcontact].name = input;
cout << "Enter the address: " << endL;
cin >> input;
contacts[newcontact].address = input;
cout << "Enter the phone number: " << endL;
cin >> input;
contacts[newcontact].phone = input;
cout << "Enter the email address: " << endL;
cin >> input;
contacts[newcontact].email = input;
}
void search(string name){
for(int i = 0; i < contacts.size(); i++){
if(contacts[i].name == name){
cout << "Name: " << contacts[i].name << endL << "Address: " << contacts[i].address << endL << "Phone Number: " << contacts[i].phone << endL << "Email: " << contacts[i].email << endL << endL;
a = true;
}
}
if(a == false){
cout << "There is no contact under that name." << endL;
}
}
int main() {
ifstream phonebook;
phonebook.open("phonebook.txt");
if(phonebook.is_open()){
while(getline(phonebook,line)){
if(line.empty() == false){
if(counter % 4 == 0){
contacts.push_back(Contact());
contacts[contactCounter].name = line;
}else if(counter % 4 == 1){
contacts[contactCounter].address = line;
}else if(counter % 4 == 2){
contacts[contactCounter].phone = line;
}else if(counter % 4 == 3){
contacts[contactCounter].email = line;
contactCounter++;
}
counter++;
}
}
}else{cout << "an error has occurred while opening the phonebook";}
phonebook.close();
cout << contacts.size() << endL;
cout << "Enter a command." << endL << tab << "To add a contact, enter '+'" << endL << tab << "To search for a contact, enter 's'" << endL << tab << "To delete a contact, enter '-'" << endL << tab << "To quit the program, enter 'q'" << endL;
cin >> command;
while(command != 'q'){
if(command == '+'){
add();
command = '/';
}
else if(command == 's'){
string searched;
cout << "Please enter who you would like to search for: ";
cin >> searched;
search(searched);
command = '/';
}
else if(command == '-'){
cout << "Not done." << endL;
command = '/';
}
else if(command == '/'){
cout << "Enter a command." << endL << tab << "To add a contact, enter '+'" << endL << tab << "To search for a contact, enter 's'" << endL << tab << "To delete a contact, enter '-'" << endL << tab << "To quit the program, enter 'q'" << endL;
cin >> command;
}
else{
cout << "That command is invalid." << endL;
cout << "Enter a command." << endL << tab << "To add a contact, enter '+'" << endL << tab << "To search for a contact, enter 's'" << endL << tab << "To delete a contact, enter '-'" << endL << tab << "To quit the program, enter 'q'" << endL;
cin >> command;
}
}
ofstream newbook;
newbook.open("phonebook.txt");
if(newbook.is_open()){
for(int i=0; i < contacts.size(); i++){
newbook << contacts[i].name << endl;
newbook << contacts[i].address << endl;
newbook << contacts[i].phone << endl;
newbook << contacts[i].email << endl;
newbook << endL;
}
}else{cout << "there was an issue saving your contacts" << endL;}
newbook.close();
return 0;
}
There's actually nothing wrong with your code except this line
string endL = "\n\r";
Which should really only be
string endL = "\n";
\n is automatically converted to the line endings used by the system, which traditionally is \n (0x0a) on unix systems and \r\n (0x0d0a) on Windows.
But, how did this affect the program so much? Well it only takes affect after the phonebook is written at the end of the program so that phonebook.txt contains these bogus line endings that have \r\n\r at the end (on Windows). So when the file is read, it reads up until the new line \r\n and sees \rPerson Name as line after! Which explains why searching was failing.
You also may see some additional bogus contacts generated because there may be some extra \rs at the end which read as a single line each. Without looking at your phonebook.txt I can't say for certain why you have an additional 4 though I'd guess extra \rs would be the cause.
All in all, use \n for new lines.
To answer the title, vector::size() is THE way to get the number of stored objects in a vector. It's not lying to you.
Using the range based for loop ensures that you won't hit any nonexistent contacts:
for(auto&& contact: contacts)
{
// Contact contact is now accessible.
}
Also, it is probably not a good idea to store a as a global variable. What happens if you execute search twice?
i need to prevent the junk left in the buffer as entering a value for a switch case menu from being used in a function called by the menu where their is user input.
menu code
void menu()
{
bool done = false;
string input;
while(!done)
{
cout << "Welcome to the DVD database." << endl;
cout << "1. Add A DVD" << endl;
cout << "2. Delete a DVD." << endl;
cout << "3. Edit a DVD." << endl;
cout << "4. List By Category." << endl;
cout << "5. Retrieve by a DVD by Title." << endl;
cout << "6. Display collection by year" << endl;
cout << "7. Display collection by title" << endl;
cout << "-999. Exit program" << endl;
cout << "Please choose an option by entering the corresponding number" << endl;
cin >> input;
int value = atoi(input.c_str());
switch(value)
{
case 1:addDVD(); break;
case 2:deleteDVD(); break;
// case 3:editDVD(); break;
case 4:listByCategory();break;
case 6:displayByYear();break;
case 7:displayByTitle();break;
case -999: writeToFile(); exit(0); break;
default : cout <<"Invalid entry"<< endl; break;
}
}
}
void retrieveByTitle()
{
string search;
int size = database.size();
int index = 0;
bool found = false;
cin.ignore();
cout << "Please enter the title of the DVD you would like to retrieve: " << endl;
getline(cin,search);
cout << search;
while(!found && index<size)
{
if(database.at(index)->getTitle().compare(search)==0)
{
cout << database.at(index)->toString();
break;
}
}
cout << endl;
}
if 5 is entered in the menu, the program skips the user input in the method
This code works, but it has the same problem you describe if you eliminate the 'cin.ignore()', which removes the extra delimiters ignored by the cin >> operator:
#include <iostream>
#include <climits>
using namespace std;
int main() {
string a, b;
while (true) {
cout << "write 'x' to exit: " << endl;
cin >> a;
if (a == "x") {
break;
}
cout << "read '" << a << "'" << endl;
cout << "now write a line: " << endl;
cin.clear(); // clears cin status
cin.ignore(INT_MAX); // clears existing, unprocessed input
getline(cin, a);
cout << "read '" << a << "'" << endl;
}
return 0;
}
When dealing with interactive user input you should use std::getline()
The std::cin is flushed to the application every time you hit <enter>. So this is the logical junks you should read data from the user in.
std::string answer;
std::cout << "Question:\n";
std::getline(std::cin, answer);
This gets you everything the user provided in response to the previous question.
Once you have the input you should get the value you think is on the input. Once you have this you should check if there is any other junk on the input (if there is then abort and re-try) otherwise validate the data you expected.
If you were expected an integer;
std::stringstream linestream(answer);
int value;
std::string junk;
if ((answer >> value)) && (!(answer >> junk)))
{
// If you got data
// and there was no junk on the line you are now good to go
}
In your specific example there is already a simple way to do this:
std::getline(std::cin, input);
int value = boost::lexical_cast<int>(input); // throws an exception if there is not
// an int on the input (with no junk)