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 am currently taking a C++ programming class and am working on a project in which I have to create a fairly simple movie database. My code essentially works as intended yet in certain cases it causes the main menu to loop infinitely and I cannot figure out why. I brought this to my teacher and he cannot explain it either. He gave me a workaround but I would like to know if anyone can see the cause of the problem. Full code is as follows:
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct MovieType
{
string title;
string director;
int year;
int length;
string rating;
};
MovieType addMovie() {
MovieType newMovie;
cout << "Movie title :";
getline(cin, newMovie.title);
cout << "Director :";
getline(cin, newMovie.director);
cout << "Year :";
cin >> newMovie.year;
cout << "Length(in minutes) :";
cin >> newMovie.length;
cout << "Rating :";
cin >> newMovie.rating;
cout << endl;
return newMovie;
}
void listMovie(MovieType movie) {
cout << "______________________________________" << endl;
cout << "Title : " << movie.title << endl;
cout << "Director : " << movie.director << endl;
cout << "Released : " << movie.year << endl;
cout << "MPAA Rating : " << movie.rating << endl;
cout << "Running time : " << movie.length << " minutes" << endl;
cout << "______________________________________" << endl;
}
void search(vector<MovieType> movieVector) {
string strSearch;
cout << endl << "Search title: ";
getline(cin, strSearch);
for (int c = 0; c < movieVector.size(); c++) {
if (movieVector.at(c).title == strSearch)
listMovie(movieVector.at(c));
}
}
int main() {
bool quit = 0;
vector<MovieType> movieVector;
while (quit == 0) {
char selection = 'f';
cout << "Main Menu:" << endl;
cout << "'a' - Add movie" << endl;
cout << "'l' - List movies" << endl;
cout << "'s' - Search by movie title" << endl;
cout << "'q' - Quit" << endl;
cout << "Please enter one of the listed commands:";
cin >> selection;
cin.ignore();
cout << endl;
if (selection == 'a')
movieVector.push_back(addMovie());
else if (selection == 'l') {
for (int c = 0; c < movieVector.size(); c++) {
listMovie(movieVector.at(c));
}
}
else if (selection == 's') {
search(movieVector);
}
else if (selection == 'q')
quit = 1;
}
return 0;
}
When an unexpected input type is entered during the addMovie function(like entering text for the int type year), it just runs through the function then loops through the menu infinitely. It appears to me that the code just stops even looking at the input stream. I have tried using cin.ignore() in many different places but it doesn't matter if there is nothing left in the stream it just keeps going.
I am using NetBeans to compile my code.
I really have no idea why it behaves like this otherwise I would offer more information but I am just curious as to why this happens, because as I said before, my professor doesn't even know why this is happening.
Any help or insight is greatly appreciated.
cin enters an error state where cin.fail() is true. In this state it just ignores all input operations. One fix is to clear the error state, but better, only use getline operations on cin, not formatted input.
E.g., instead of
cin >> newMovie.year;
… do
newMovie.year = stoi( line_from( cin ) );
… where line_from can be defined as
auto line_from( std::istream& stream )
-> std::string
{
std::string result;
if( not getline( stream, result ) )
{
// Throw an exception or call exit(EXIT_FAILURE).0
}
return result;
}
Disclaimer: code untouched by compiler.
The part of code where I rename the file just won't work. I tried writing it separately in another project, it works. Help me please.
#include <iostream>
#include <stdio.h>
#include <fstream>
using namespace std;
int main () {
char address[] = "";
char newname[] = "";
int action;
char confirm;
int result;
cout << "File Manipulator 1.0" << endl;
cout << "--------------------" << endl << endl;
cout << "Type the full address of a file you wish to manipulate." << endl << endl;
ADDRESS:cin >> address;
fstream file(address);
if (!file.good()) {
cout << "The selected file does not exist! Try again. ";
goto ADDRESS;
} else {
cout << endl << "-----------------------------------" << endl;
cout << "Type 1 to move the selected file." << endl;
cout << "Type 2 to rename the selected file." << endl;
cout << "Type 3 to delete the selected file." << endl;
cout << "-----------------------------------" << endl << endl;
ACTION:cin >> action;
if (action == 1) {
cout << 1;
} else if (action == 2) {
cout << "Enter the new name: ";
cin >> newname;
cout << "Are you sure you want to rename the selected file? Y/N ";
CONFIRM:cin >> confirm;
if (confirm == 'Y' || 'y') {
result = rename(address, newname);
if (result == 0) {
cout << "renamed";
} else {
perror("not renamed");
}
} else if (confirm == 'N' || 'n') {
cout << "No";
} else {
cout << "You typed an invalid command! Try again. ";
goto CONFIRM;
}
} else if (action == 3) {
cout << 3;
} else {
cout << "You typed an invalid command! Try again." << endl;
goto ACTION;
}
}
return 0;
}
BTW the whole code is not finished, so check just the renaming part. Thanks.
Well, this is the solution.
#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>
using namespace std;
int main() {
string address;
string newname;
Here you can see I used strings instead of char arrays.
char input;
int action;
char confirm;
int result;
cout << "File Manipulator 1.0" << endl;
cout << "--------------------" << endl << endl;
cout << "Type the full address of a file you wish to manipulate." << endl << endl;
getline(cin, address);
ifstream myfile(address.c_str());
I used ifstream with c_str() function which passes contents of a std::string into a C style string.
// try to open the file
if (myfile.is_open())
{
When the condition is met, you must close the opened file in order to be able to manipulate/work with it later.
myfile.close();
CREATE:cout << endl << "-----------------------------------" << endl;
cout << "Type 1 to move the selected file." << endl;
cout << "Type 2 to rename the selected file." << endl;
cout << "Type 3 to delete the selected file." << endl;
cout << "-----------------------------------" << endl << endl;
cin >> action;
switch (action)
{
case 1:
{
// do nothing.
}
break;
case 2:
{
// rename file.
cout << "Enter the new name" << endl << endl;
cin.ignore();
I used here the ignore() function to ignores the amount of characters I specify when I call it.
getline(cin, newname);
cout << "Are you sure you want ot rename the selected file ? Y/N" << endl << endl;
cin >> confirm;
if (confirm == 'Y' || confirm == 'y')
{
Same case with c_str() that i explained earlier.
rename(address.c_str(), newname.c_str());
}
}
break;
case 3:
{
// delete file.
remove(address.c_str());
}
break;
default:
{
cout << "You typed an invalid command!" << endl;
}
break;
}
}
else
{
cout << "The selected file does not exist! Would you like to create it? ";
cin >> input;
If the file name you input doesn't exist, you are prompted to create a file with the specified name, then you are redirected with goto to the manipulation menu.
if (input == 'y' || input == 'Y')
{
// create the file.
ofstream output(address.c_str());
output.close();
cout << "File created";
goto CREATE;
}
}
return 0;
}
Thanks for trying anyway :)
I'm working on a program very important to my programming class, and there's something I can't quite figure out; When I try to read from a binary file I've created after opening the program, it fails even if the file's in the directory, and after I try to wipe the contents of the file, I can still 'read' them from the file even though said file is empty when I examine it in explorer. I've determined from this that even though I'm using BinaryFile.read, it's not truly reading from the file, and instead reading from variables stored in the program itself. How can I get my program to read from the actual file?
(please note that this is not yet a complete program, hence the commented sections and empty functions.)
(Also please note that, due to the nature of my class, I am only allowed to use what has been taught already (namely, anything in the fstream header and most things before which are necessary to make a basic program - he's letting me use things in stdio.h, as well.)
//
// main.cpp
// Binary Program
//
// Created by Henry Fowler on 11/19/14.
// Copyright (c) 2014 Bergen Community College. All rights reserved.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstdlib>
#include <math.h>
#include <stdio.h>
using namespace std;
struct Record
{
char Name[20];
char LastName[20];
double Pay;
int Clearance;
int ID;
};
void CreateFile(fstream&); //Working
void CheckExist(fstream&); //Working
void Populate(fstream&,Record[],int&,int&); //Working
void Display(fstream&,Record[],int&,int&); //Working
void Append(fstream&,Record[],int&,int&); //Working
void DeleteFromFile(fstream&,fstream&,Record[],int&,int&);
// void SearchInFile(fstream&,Record[],int&,int&);
// void ModifyRecord(fstream&,Record[],int&,int&);
//void SortFile();
void WipeFile(fstream&);
void DelFile(fstream&);
int main(int argc, const char * argv[])
{
Record EmpRecords[20];
char Binary[] = "BinaryFile.dat";
char Binary2[] = "BinaryFileTemp.dat";
int maxsize; //make sure to set i to max size so you can use it later for things like wiping the file or deleting specific records
fstream BinaryFile;
fstream BinaryFile2;
string InputStr;
// char Read;
//int Choice = 0;
int i = 0;
int choice = 0;
int switchchoice;
CreateFile(BinaryFile); //working
CheckExist(BinaryFile); //working
BinaryFile.close();
while(choice==0)
{
cout << "Options: " << endl;
cout << "End Program (0)" << endl;
cout << "Input new records to file (1)" << endl;
cout << "Display current contents of file (2)" << endl;
cout << "Append a record at the end of the file (3)" << endl;
cout << "Delete a record from the file (4)" << endl;
cout << "Search for a record in the file (5)" << endl;
cout << "Modify a certain record (6)" << endl;
cout << "Sort file (unimplemented)" << endl;
cout << "Wipe contents of file (8)" << endl;
cout << "Please choose an option: ";
cin >> switchchoice;
switch(switchchoice)
{
case 0:
{
cout << "Exiting.";
BinaryFile.close();
system("PAUSE");
return 0;
break;
}
case 1:
{
Populate(BinaryFile, EmpRecords,i,maxsize); //working
break;
}
case 2:
{
Display(BinaryFile, EmpRecords,i,maxsize); //working i think
break;
}
case 3:
{
Append(BinaryFile, EmpRecords,i,maxsize); //working
break;
}
case 4:
{
DeleteFromFile(BinaryFile,BinaryFile2,EmpRecords,i,maxsize); //!
break;
}
case 5:
{
// SearchInFile(BinaryFile, EmpRecords,i,maxsize); //!
break;
}
case 6:
{
// ModifyRecord(BinaryFile, EmpRecords,i,maxsize); //!
break;
}
case 7:
{
cout << "Error, file sorting is currently unimplemented. Please try again.";
break;
}
case 8:
{
WipeFile(BinaryFile);
break;
}
}
}
system("PAUSE");
return 0;
}
void CreateFile(fstream& BinaryFile)
{
BinaryFile.open("BinaryFile.dat", ios::out | ios::binary);
}
void CheckExist(fstream &BinaryFile)
{
if(BinaryFile.good())
{
cout << endl << "File does exist" << endl;
}
else
{
cout << "file named can not be found \n";
system("PAUSE");
}
}
void Populate(fstream &BinaryFile,Record EmpRecords[],int &i, int &maxsize)
{
BinaryFile.open("BinaryFile.dat", ios::out | ios::binary);
int choice = 0;
while(choice==0)
{
cout << "Please input employee first name: ";
cin >> EmpRecords[i].Name;
cout << "Please input employee last name: ";
cin >> EmpRecords[i].LastName;
cout << "Please input Employee Pay: ";
cin >> EmpRecords[i].Pay;
cout << "Please input Employee Clearance (1-10): ";
cin >> EmpRecords[i].Clearance;
cout << "Please input Employee ID (6 numbers, i.e. 122934): ";
cin >> EmpRecords[i].ID;
cout << "Input another employee's information? (0) = yes, (1) = no: ";
cin >> choice;
BinaryFile.write((char *) (&EmpRecords[i]),sizeof(EmpRecords[i]));
i = i+1;
}
maxsize = i;
cout << "i is " << i << endl;
cout << "maxsize is " << maxsize << endl;
BinaryFile.close();
}
void Display(fstream &BinaryFile,Record EmpRecords[],int &i,int &maxsize)
{
BinaryFile.open("BinaryFile.dat", ios::in | ios::binary | ios::app);
int i2 = maxsize;
i = 0;
while(i2>0)
{
BinaryFile.read((char *) (&EmpRecords[i]),sizeof(EmpRecords[i]));
cout << i << endl;
cout << EmpRecords[i].Name << " " << EmpRecords[i].LastName << endl;
cout << "Pay: $" << EmpRecords[i].Pay << endl;
cout << "Clearance: " << EmpRecords[i].Clearance << endl;
cout << "Employee ID: " << EmpRecords[i].ID << endl;
BinaryFile.read((char *) (&EmpRecords[i]),sizeof(EmpRecords[i]));
cout << endl;
i2 = i2-1;
i = i+1;
}
BinaryFile.close();
}
void Append(fstream &BinaryFile,Record EmpRecords[],int &i,int &maxsize)
{
BinaryFile.open("BinaryFile.dat", ios::out|ios::binary|ios::ate|ios::app);
cout << "Please input employee first name: ";
cin >> EmpRecords[maxsize].Name;
cout << "Please input employee last name: ";
cin >> EmpRecords[maxsize].LastName;
cout << "Please input Employee Pay: ";
cin >> EmpRecords[maxsize].Pay;
cout << "Please input Employee Clearance (1-10): ";
cin >> EmpRecords[maxsize].Clearance;
cout << "Please input Employee ID (6 numbers, i.e. 122934): ";
cin >> EmpRecords[maxsize].ID;
cout << "Input another employee's information? (0) = yes, (1) = no: ";
BinaryFile.write((char *) (&EmpRecords[i]),sizeof(EmpRecords[i]));
maxsize = maxsize+1;
cout << "maxsize is " << maxsize << endl;
BinaryFile.close();
}
void DeleteFromFile(fstream &BinaryFile,fstream &BinaryFile2, Record EmpRecords[],int &i,int &maxsize)
{
BinaryFile.open("BinaryFile.dat", ios::out|ios::binary|ios::app);
BinaryFile2.open("BinaryFileTemp.dat", ios::out|ios::binary|ios::app);
int Choice;
cout << "Would you like to delete a file by name or by employee number?" << endl;
cout << "Name (1)" << endl;
cout << "Number (2)" << endl;
cout << "Choice: ";
cin >> Choice;
int i2 = maxsize;
if(Choice==1)
{
cout << "Please input employee first name: ";
// cin >> firstname;
cout << "Please input employee last name: ";
// cin >> lastname;
cout << "Searching...";
int i2 = maxsize;
i = 0;
while(i2>0)
{
BinaryFile.read((char *) (&EmpRecords[i]),sizeof(EmpRecords[i]));
cout << i << endl;
BinaryFile.read((char *) (&EmpRecords[i]),sizeof(EmpRecords[i]));
// if(EmpRecords[i].Name == firstname)
// {
// cout << "Found first name." << endl;
// if (EmpRecords[i].LastName == lastname)
// {
// cout << "Found last name." << endl;
/// }
// }
// else
// {
// cout << "Could not find name.";
// // BinaryFile2.write((char *) (&EmpRecords[i]),sizeof(EmpRecords[i]));
// }
cout << endl;
i2 = i2-1;
i = i+1;
}
}
BinaryFile.close();
if( remove( "BinaryFile.dat" ) != 0 )
cout << endl << "Error deleting file" << endl;
else
{
cout << "File successfully deleted" << endl << endl;
}
int result;
char oldname[]="BinaryFileTemp.dat";
char newname[]="BinaryFile.dat";
result = rename(oldname,newname);
if(result == 0)
cout << "DEBUG: Success" << endl;
else
cout << "DEBUG: Failure" << endl;
}
void WipeFile(fstream &BinaryFile)
{
int sure;
cout << "There is no undoing this action." << endl;
cout << "Continue (1)" << endl;
cout << "Cancel (2)" << endl;
cout << "Wipe file? ";
cin >> sure;
if(sure == 1)
{
cout << "Wiping file.";
BinaryFile.open("BinaryFile.dat", ios::out | ios::binary | ios::trunc);
BinaryFile.close();
}
else
{
cout << "Canceling.";
}
}
void DelFile(fstream &BinaryFile)
{
BinaryFile.close();
if( remove( "BinaryFile.dat" ) != 0 )
cout << endl << "Error deleting file" << endl;
else
{
cout << "File successfully deleted" << endl << endl;
}
}
Here the problem seems to be, even though you are wiping the file contents, you are not clearing the data you had stored in Record EmpRecords[20]; or the int maxsize value.
Few things you can do inside void WipeFile(fstream &BinaryFile) function: To keep it simple, we'll just reset maxsize to 0:
Pass the maxsize variable as reference to WipeFile(), the same way you are passing for Populate()
Update maxsize = 0, to indicate all the records are removed, when you delete the file contents.
It is better to memset the contents of EmpRecords as well similarly.
For now, I just modified your code to reset maxsize to 0 in WipeFile() and it worked.
void WipeFile(fstream &BinaryFile, int &maxsize)
{
int sure;
cout << "There is no undoing this action." << endl;
cout << "Continue (1)" << endl;
cout << "Cancel (2)" << endl;
cout << "Wipe file? ";
cin >> sure;
if(sure == 1)
{
cout << "Wiping file.";
BinaryFile.open("BinaryFile.dat", ios::out | ios::binary | ios::trunc);
BinaryFile.close();
maxsize = 0;
}
else
{
cout << "Cancelling.";
}
}
Sorry for the lack of previous explanation to my school's assignment. Here's what I'm working with and what I have / think I have to do.
I have the basic structure for populating the address book inside an array, however, the logic behind populating a text file is a bit beyond my knowledge. I've researched a few examples, however, the implementation is a bit tricky due to my novice programming ability.
I've gone through some code that looks relevant in regard to my requirements:
ifstream input("addressbook.txt");
ofstream out("addressbook.txt");
For ifstream, I believe implementing this into the voidAddBook::AddEntry() would work, though I've tried it and the code failed to compile, for multiple reasons.
For ostream, I'm lost and unsure as to how I can implement this correctly. I understand basic file input and output into a text file, however, this method is a bit more advanced and hence why I'm resorting to stackoverflow's guidance.
#include <iostream>
#include <string.h> //Required to use string compare
using namespace std;
class AddBook{
public:
AddBook()
{
count=0;
}
void AddEntry();
void DispAll();
void DispEntry(int i); // Displays one entry
void SearchLast();
int Menu();
struct EntryStruct
{
char FirstName[15];
char LastName[15];
char Birthday[15];
char PhoneNum[15];
char Email[15];
};
EntryStruct entries[100];
int count;
};
void AddBook::AddEntry()
{
cout << "Enter First Name: ";
cin >> entries[count].FirstName;
cout << "Enter Last Name: ";
cin >> entries[count].LastName;
cout << "Enter Date of Birth: ";
cin >> entries[count].Birthday;
cout << "Enter Phone Number: ";
cin >> entries[count].PhoneNum;
cout << "Enter Email: ";
cin >> entries[count].Email;
++count;
}
void AddBook::DispEntry(int i)
{
cout << "First name : " << entries[i].FirstName << endl;
cout << "Last name : " << entries[i].LastName << endl;
cout << "Date of birth : " << entries[i].Birthday << endl;
cout << "Phone number : " << entries[i].PhoneNum << endl;
cout << "Email: " << entries[i].Email << endl;
}
void AddBook::DispAll()
{
cout << "Number of entries : " << count << endl;
for(int i = 0;i < count;++i)
DispEntry(i);
}
void AddBook::SearchLast()
{
char lastname[32];
cout << "Enter last name : ";
cin >> lastname;
for(int i = 0;i < count;++i)
{
if(strcmp(lastname, entries[i].LastName) == 0)
{
cout << "Found ";
DispEntry(i);
cout << endl;
}
}
}
AddBook AddressBook;
int Menu()
{
int num;
bool BoolQuit = false;
while(BoolQuit == false)
{
cout << "Address Book Menu" << endl;
cout << "(1) Add A New Contact" << endl;
cout << "(2) Search By Last Name" << endl;
cout << "(3) Show Complete List" << endl;
cout << "(4) Exit And Save" << endl;
cout << endl;
cout << "Please enter your selection (1-4) and press enter: ";
cin >> num;
cout << endl;
if (num == 1)
AddressBook.AddEntry();
else if (num == 2)
AddressBook.SearchLast();
else if (num == 3)
AddressBook.DispAll();
else if (num == 4)
BoolQuit = true;
else
cout << "Please enter a number (1-4) and press enter: " << endl;
cout << endl;
}
return 0;
}
int main (){
Menu();
return 0;
}
As it currently stands, I'm still stuck. Here's where I believe I should start:
cout << "Please enter your selection (1-4) and press enter: ";
cin >> num;
cout << endl;
if (num == 1)
AddressBook.AddEntry();
else if (num == 2)
AddressBook.SearchLast();
else if (num == 3)
AddressBook.DispAll();
else if (num == 4)
BoolQuit = true;
//save first name
//save last name
//save dob
//save phone number
//save email
//exit
else
cout << "Please enter a number (1-4) and press enter: " << endl;
cout << endl;
}
Somehow, during menu option 4 the array should dump the data into a .txt file and arrange it in a way that it can be easily imported upon reloading the program. I'm a little confused as to how I can store the array data from each character array into a .txt file.
Well first, if the input is coming from the file input, then instead of doing cin >> x you would have to do input >> x. If it's coming from standard input (the keyboard), then you can use cin.
Also, your else if statement should be something like this:
while (true)
{
// ...
else if (num == 4)
{
for (int i = 0; i < AddressBook.count; ++i)
{
AddBook::EntryStruct data = AddressBook.entries[i];
out << data.FirstName << " " << data.LastName
<< std::endl
<< data.Birthday << std::endl
<< data.PhoneNum << std::endl
<< data.Email;
}
}
break;
}