C++ data file not reading correctly when introducing ofstream? - c++

Ok so, this is gonna be a long one...
Explanation of what the project is supposed to do:
My final project is a bank teller system that stores all the account related data on a text files.
The file in question, "accounts.txt", is where all the account data is stored. It is read and write, and behaves strangely when an ofstream is introduced...
The "accounts.txt" file is formated as follows
01481
554-00-8336
Jane Jones
1483 N. RealmSecond Ave., Burlington, VT 05401
564 425 5052
02650
727-22-1072
Jennifer Armstrong
1450 W. Main Rd., Burlington, VT 05401
202 545 5485
it continues repeating the same ordered sets of information...
One of the core parts of the program relies on reading these values into 5 separate arrays, each pertaining to type of data (name, address, etc).
I am going to dump the entire program because I think it might be necessary to fix the problem, just understand that the main function in question is addAccount() and is located at the bottom.
Note that the purpose of this function is to read the entire accounts.txt file line by line into memory, determine at what point the arrays used to store the file are being filled with empty data (we were told by the course instructor to make the array size 100, meaning that most of the data read into the array is empty space) get the desired account information from the user, update the file in memory, and rewrite the file...
also note that the file format was predetermined by the course instructor
The code:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
const int TELLERS_SIZE = 5;
const int ACCOUNTS_SIZE = 100;
const string TELLERS_FILE = "tellers.txt";
const string ACCOUNTS_FILE = "accounts.txt";
int beginMenu();
bool login(string fileName);
int baseMenu();
void searchAccount(string fileName);
void addAccount(string fileName);
int main() {
int beginSelection;
do {
beginSelection = beginMenu();
if (beginSelection == 2) {
return 0;
}
bool loginIsTrue = login(TELLERS_FILE);
while (loginIsTrue) {
int baseSelection = baseMenu();
if (baseSelection == 1) {
addAccount(ACCOUNTS_FILE);
}
if (baseSelection == 4) {
searchAccount(ACCOUNTS_FILE);
}
if (baseSelection == 8) {
loginIsTrue = false;
}
}
} while (beginSelection == 1);
}
// Print the fisrt menu and return selection
int beginMenu() {
// Establish return value and validation
int menuSelection;
string userInput;
bool menuSelectionIsValid = false;
// Print options
do {
cout << "\n";
cout << "[1] Login" << "\n";
cout << "[2] Quit" << "\n";
cout << "Please enter a selection";
cout << "\n";
getline(cin, userInput);
// Validate input
if (userInput == "1") {
menuSelectionIsValid = true;
menuSelection = 1;
}
else if (userInput == "2") {
menuSelectionIsValid = true;
menuSelection = 2;
}
else {
cout << "Invalid input!" << "\n";
}
} while (!menuSelectionIsValid);
return menuSelection;
}
// Perform login and return true or false
bool login(string fileName) {
// Establish variables
string username[TELLERS_SIZE];
string password[TELLERS_SIZE];
string usernameInput;
string passwordInput;
bool loginIsValid = false;
// Establish fin
ifstream fin(fileName);
if (!fin.is_open()) {
cout << "File cannot be opened " << fileName << "\n";
return false;
}
// Read tellers.dat
for (int i = 0; i < TELLERS_SIZE; i++) {
fin >> username[i];
fin >> password[i];
}
// Read user input
cout << "\n";
cout << "Username: ";
getline(cin, usernameInput);
cout << "Password: ";
getline(cin, passwordInput);
// Verify login information
for (int i = 0; i < TELLERS_SIZE; i++) {
if (username[i] == usernameInput && password[i] == passwordInput) {
cout << "Login succesful" << "\n";
loginIsValid = true;
return true;
}
}
// Inform user of error
cout << "Invalid username or password!" << "\n";
return false;
}
// Print base functions menu and return selection
int baseMenu () {
// Establish return value and validation
int menuSelection;
string userInput;
bool menuSelectionIsValid = false;
do {
// Print options
cout << "\n";
cout << "[1] Add Account" << "\n";
cout << "[2] Remove Account" << "\n";
cout << "[3] Update Account" << "\n";
cout << "[4] Search Account" << "\n";
cout << "[5] Make A Deposit" << "\n";
cout << "[6] Make A Withdrawal" << "\n";
cout << "[7] Check Balance" << "\n";
cout << "[8] Logout" << "\n";
cout << "Please enter a selection";
cout << "\n";
getline(cin, userInput);
// Validate input
if (userInput == "1") {
menuSelectionIsValid = true;
menuSelection = 1;
}
else if (userInput == "2") {
menuSelectionIsValid = true;
menuSelection = 2;
}
else if (userInput == "3") {
menuSelectionIsValid = true;
menuSelection = 3;
}
else if (userInput == "4") {
menuSelectionIsValid = true;
menuSelection = 4;
}
else if (userInput == "5") {
menuSelectionIsValid = true;
menuSelection = 5;
}
else if (userInput == "6") {
menuSelectionIsValid = true;
menuSelection = 6;
}
else if (userInput == "7") {
menuSelectionIsValid = true;
menuSelection = 7;
}
else if (userInput == "8") {
menuSelectionIsValid = true;
menuSelection = 8;
}
else {
cout << "Invalid input!" << "\n";
}
} while (!menuSelectionIsValid);
return menuSelection;
}
// Locate account and print relevant information
void searchAccount(string fileName) {
// Establish arrays
string accountNumber[ACCOUNTS_SIZE];
string accountSSN[ACCOUNTS_SIZE];
string accountName[ACCOUNTS_SIZE];
string accountAddress[ACCOUNTS_SIZE];
string accountPhone[ACCOUNTS_SIZE];
// Establish validation variables
string userInput;
bool accountFound = false;
// Establish and validate fin
ifstream fin(fileName);
if (!fin.is_open()) {
cout << "File cannot be opened " << fileName << "\n";
}
// Get desired account number
cout << "\n";
cout << "Account number: ";
getline(cin, userInput);
// Read information from file
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
getline(fin, accountNumber[i]);
getline(fin, accountSSN[i]);
getline(fin, accountName[i]);
getline(fin, accountAddress[i]);
getline(fin, accountPhone[i]);
}
// Search for account
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
if (accountNumber[i] == userInput && userInput != "") {
accountFound = true;
}
// Display account information
if (accountFound == true) {
cout << "Account Found" << "\n";
cout << "Displaying account information" << "\n" << "\n";
cout << accountNumber[i] << "\n";
cout << accountSSN[i] << "\n";
cout << accountName[i] << "\n";
cout << accountAddress[i] << "\n";
cout << accountPhone[i] << "\n";
break;
}
}
// Inform user that account doesnt exist
if (accountFound == false) {
cout << "Unable to find account: " << userInput << "\n";
}
}
void addAccount(string fileName) {
string accountNumber[ACCOUNTS_SIZE];
string accountSSN[ACCOUNTS_SIZE];
string accountName[ACCOUNTS_SIZE];
string accountAddress[ACCOUNTS_SIZE];
string accountPhone[ACCOUNTS_SIZE];
ifstream fin(fileName);
// ofstream fout(fileName);
string userAccountNumber;
string userAccountSSN;
string userAccountName;
string userAccountAddress;
string userAccountPhone;
bool accountNumberIsTaken = true;
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
getline(fin, accountNumber[i]);
getline(fin, accountSSN[i]);
getline(fin, accountName[i]);
getline(fin, accountAddress[i]);
getline(fin, accountPhone[i]);
}
do {
accountNumberIsTaken = false;
cout << "\n";
cout << "Enter desired account number: ";
getline(cin, userAccountNumber);
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
if (userAccountNumber == accountNumber[i] || userAccountNumber == "") {
cout << "That account number is already in use" << "\n";
accountNumberIsTaken = true;
break;
}
}
} while (accountNumberIsTaken);
/*
cout << "Enter SSN: ";
getline(cin, userAccountSSN);
cout << "Enter full name: ";
getline(cin, userAccountName);
cout << "Enter address: ";
getline(cin, userAccountAddress);
cout << "Enter phone number: ";
getline(cin, userAccountPhone);
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
if (accountNumber[i] == "") {
cout << "empty space found at" << i;
accountNumber[i] = userAccountNumber;
accountSSN[i] = userAccountSSN;
accountName[i] = userAccountName;
accountAddress[i] = userAccountAddress;
accountPhone[i] = userAccountPhone;
break;
}
}
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
fout << accountNumber[i] << "\n";
fout << accountSSN[i] << "\n";
fout << accountName[i] << "\n";
fout << accountAddress[i] << "\n";
fout << accountPhone[i] << "\n";
}
*/
}
The issue:
The base code, without anything commented out, does not work at all.
Both the accountSearch() and addAccount() functions which rely on reading "accounts.txt" will report that an account number clearly present on "accounts.dat" is not present.
After commenting out ofstream fout(fileName); and the lower part of the addAccount() that relies on writing to the file AND making a slight change to the "accounts.txt" file and saving changes, things start working again
This project is being written in Visual Studio 2019.
Apologies if this is a poor explanation. Please ask for clarification if necessary.

You can't have filename opened as both an ifstream and an ofstream at the same time! So, move your declaration/constructor for fout to after the code for reading fin, like this:
void addAccount(string fileName) {
string accountNumber[ACCOUNTS_SIZE];
string accountSSN[ACCOUNTS_SIZE];
string accountName[ACCOUNTS_SIZE];
string accountAddress[ACCOUNTS_SIZE];
string accountPhone[ACCOUNTS_SIZE];
ifstream fin(fileName);
// ofstream fout(fileName); /// CANNOT BE HERE!
string userAccountNumber;
///... Here, have all your reading and input code (as it is) …
///...
///... Finished reading, etc., so CLOSE "fin" then get the "fout" …
fin.close();
ofstream fout(fileName); // NOW we can create the output stream!
///... and use your existing code to do the writing
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
fout << accountNumber[i] << "\n";
fout << accountSSN[i] << "\n";
fout << accountName[i] << "\n";
fout << accountAddress[i] << "\n";
fout << accountPhone[i] << "\n";
}
fout.close(); /// When finished, CLOSE the file!
}

Related

Count in string

currently I have a information.txt file with a list of residents and their unit number such as A-1-1 and A-1-2. I am having difficulty when I wish to allow my program to add user to its own unit number but limited to a situation where 1 unit maximum can have 2 residents registered in a single unit.
It is possible to code my program to read the unit number in the information.txt file and only allow the user to register themselves in the program when their unit is not fully registered (maximum 2 resident per unit)?
This is my university programming assignment...I am just a beginner...This is so far what I have...Please help me with this...Hope you can understand my situation.
void add_new_user(void)
{
system("CLS");
ifstream in_file ("information.txt");
USER new_user[40];
int index=0;
char option;
char unit_number;
if(!in_file)
{
cout << "Error opening txt file" << endl;
}
else
{
USER U_list[MAX_USER];
int index = 0;
fflush (stdin);
in_file.getline(U_list[++index].unit_number, LENGTH_UNIT);
while (in_file)
{
in_file.getline(U_list[index].name, LENGTH_NAME);
in_file.getline(U_list[index].email, LENGTH_MAIL);
in_file.getline(U_list[index].phone, MAX_NUM);
in_file.getline(U_list[index].IC, LENGTH_IC);
if(in_file.peek() == '\n')
in_file.ignore(256, '\n');
in_file.getline(U_list[++index].unit_number,LENGTH_UNIT);
}
in_file.close();
bool in = false;
do
{
char check_unit_number[LENGTH_UNIT];
int unit_number_count = 0;
cout << "==================================================" << endl;
cout << "==\tUser Management System\t\t==" << endl;
cout << "==================================================" << endl;
cout << "==\tAdd New User\t\t\t==" << endl;
cout << "==================================================\n";
fflush(stdin);
cout << "\nEnter unit number of the new user: " <<endl;
cin.get(check_unit_number, LENGTH_UNIT);
cin.ignore();
for (int i =1; i < index; i++)
if (strcmp(check_unit_number,U_list[i].unit_number) == 0)
unit_number = i;
if (strcmp(check_unit_number,U_list[unit_number].unit_number) == 0)
{
fflush(stdin);
cout << "\nEnter new user's unit number: " << endl;
cin.get(new_user[++index].unit_number, LENGTH_UNIT);
cin.clear();
fflush(stdin);
cout << "\nEnter new user's name: " << endl;
cin.get(new_user[index].name, LENGTH_NAME);
cin.clear();
fflush(stdin);
cout << "\nEnter new user's EMAIL ADDRESS: " << endl;
cin.get(new_user[index].email, LENGTH_MAIL);
cin.clear();
fflush(stdin);
cout << "\nEnter new user's phone number: " << endl;
cin.get(new_user[index].phone, MAX_NUM);
cin.clear();
fflush(stdin);
cout << "\nEnter new user's IC: " << endl;
cin.get(new_user[index].IC, LENGTH_IC);
cin.clear();
do
{
cout << "\nDo you confirm to register this new user? [Yes - Y, No - N]\n=>";
cin >> option;
if(option != 'Y' && option != 'N' && option != 'y' && option != 'n')
{
cout << endl;
cout << "Wrong input. Enter again." << endl;
cout << endl;
}
}while(option != 'Y' && option != 'N' && option != 'y' && option != 'n');
if(option=='Y' || option=='y')
{
ofstream out_file ( "information.txt", ios :: app);
out_file << setiosflags (ios :: left) << new_user[index].unit_number << endl;
out_file << setiosflags (ios :: left) << new_user[index].name << endl;
out_file << setiosflags (ios :: left) << new_user[index].email << endl;
out_file << setiosflags (ios :: left) << new_user[index].phone << endl;
out_file << setiosflags (ios :: left) << new_user[index].IC << endl;
out_file.close();
cout << endl;
cout << "The new user is successfully registered.\n" << endl;
system ("pause");
return;
}
else if(option=='N' || option=='n')
{
cout << "\nThe new user is not registered.\n" << endl;
system ("pause");
return;
}
}
else if (strcmp(check_unit_number,U_list[unit_number].unit_number) != 0)
{
cout << "\nThis unit number is not exist.\n" << endl;
system ("pause");
return;
}
}while(!in);
}
}
You have some basic problems in understanding IO operations.
You need to check the difference between formatted and unformatted input. For example
std::cin >> option; will read one character, but not the '\n' at the end of the line. A subsequent call to an unformatted input function, will read just the '\n' and nothing more.
Then, you are mixing up std::istream.get() and std::istream.getline(). They have a total different behaviour regarding the handling of the "end of line" character '\n'. Please read here and here.
You need to understand the difference.
Then, many additional problems resulting from using plain C-Style arrays and especially not standard C-elements like std::string. If you would use std::string then life would be very much simpler.
Anyway, there are many other more syntax and semantic errors, as well as design errors.
Important notice: Please make your design first on a piece of paper and then start coding. Always think many days, before writing the first line of code.
So, then to your code. Lets make it compilable:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define MAX_USER 100
#define LENGTH_UNIT 30
#define LENGTH_NAME 50
#define LENGTH_MAIL 80
#define MAX_NUM 35
#define LENGTH_IC 50
struct USER {
char unit_number[LENGTH_UNIT];
char name[LENGTH_NAME];
char email[LENGTH_MAIL];
char phone[MAX_NUM];
char IC[LENGTH_IC];
};
void add_new_user(void)
{
system("CLS");
ifstream in_file("information.txt");
USER new_user[40];
int index = 0;
char option;
char unit_number;
if (!in_file)
{
cout << "Error opening txt file" << endl;
}
else
{
USER U_list[MAX_USER];
int index = 0;
fflush(stdin);
in_file.getline(U_list[++index].unit_number, LENGTH_UNIT);
while (in_file)
{
in_file.getline(U_list[index].name, LENGTH_NAME);
in_file.getline(U_list[index].email, LENGTH_MAIL);
in_file.getline(U_list[index].phone, MAX_NUM);
in_file.getline(U_list[index].IC, LENGTH_IC);
if (in_file.peek() == '\n')
in_file.ignore(256, '\n');
in_file.getline(U_list[++index].unit_number, LENGTH_UNIT);
}
in_file.close();
bool in = false;
do
{
char check_unit_number[LENGTH_UNIT];
int unit_number_count = 0;
cout << "==================================================" << endl;
cout << "==\tUser Management System\t\t==" << endl;
cout << "==================================================" << endl;
cout << "==\tAdd New User\t\t\t==" << endl;
cout << "==================================================\n";
fflush(stdin);
cout << "\nEnter unit number of the new user: " << endl;
cin.get(check_unit_number, LENGTH_UNIT);
cin.ignore();
for (int i = 1; i < index; i++)
if (strcmp(check_unit_number, U_list[i].unit_number) == 0)
unit_number = i;
if (strcmp(check_unit_number, U_list[unit_number].unit_number) == 0)
{
fflush(stdin);
cout << "\nEnter new user's unit number: " << endl;
cin.get(new_user[++index].unit_number, LENGTH_UNIT);
cin.clear();
fflush(stdin);
cout << "\nEnter new user's name: " << endl;
cin.get(new_user[index].name, LENGTH_NAME);
cin.clear();
fflush(stdin);
cout << "\nEnter new user's EMAIL ADDRESS: " << endl;
cin.get(new_user[index].email, LENGTH_MAIL);
cin.clear();
fflush(stdin);
cout << "\nEnter new user's phone number: " << endl;
cin.get(new_user[index].phone, MAX_NUM);
cin.clear();
fflush(stdin);
cout << "\nEnter new user's IC: " << endl;
cin.get(new_user[index].IC, LENGTH_IC);
cin.clear();
do
{
cout << "\nDo you confirm to register this new user? [Yes - Y, No - N]\n=>";
cin >> option;
if (option != 'Y' && option != 'N' && option != 'y' && option != 'n')
{
cout << endl;
cout << "Wrong input. Enter again." << endl;
cout << endl;
}
} while (option != 'Y' && option != 'N' && option != 'y' && option != 'n');
if (option == 'Y' || option == 'y')
{
ofstream out_file("information.txt", ios::app);
out_file << setiosflags(ios::left) << new_user[index].unit_number << endl;
out_file << setiosflags(ios::left) << new_user[index].name << endl;
out_file << setiosflags(ios::left) << new_user[index].email << endl;
out_file << setiosflags(ios::left) << new_user[index].phone << endl;
out_file << setiosflags(ios::left) << new_user[index].IC << endl;
out_file.close();
cout << endl;
cout << "The new user is successfully registered.\n" << endl;
system("pause");
return;
}
else if (option == 'N' || option == 'n')
{
cout << "\nThe new user is not registered.\n" << endl;
system("pause");
return;
}
}
else if (strcmp(check_unit_number, U_list[unit_number].unit_number) != 0)
{
cout << "\nThis unit number is not exist.\n" << endl;
system("pause");
return;
}
} while (!in);
}
}
int main() {
add_new_user();
}
So, now it is at least compilable. However, it will not work. There are still compiler warnings:
All errors and warnings must be removed.
Let us start with refactoring.
First a code review. I put all finding as a comment in the source code.
Note: Nearly every line of code has a finding.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdlib.h> // Do not use C headers
#include <string.h> // Do not use C headers
using namespace std; // Should never be done in C++. Always use qualified names
#define MAX_USER 100 // Macros should never be used for that purpose in C++. Use constexpr instead
#define LENGTH_UNIT 30 // Macros should never be used for that purpose in C++. Use constexpr instead
#define LENGTH_NAME 50 // Macros should never be used for that purpose in C++. Use constexpr instead
#define LENGTH_MAIL 80 // Macros should never be used for that purpose in C++. Use constexpr instead
#define MAX_NUM 35 // Macros should never be used for that purpose in C++. Use constexpr instead
#define LENGTH_IC 50 // Macros should never be used for that purpose in C++. Use constexpr instead
struct USER {
char unit_number[LENGTH_UNIT]; // C-Style arrays should not be used in C++. Use datatype string instead
char name[LENGTH_NAME];// C-Style arrays should not be used in C++. Use datatype string instead
char email[LENGTH_MAIL];// C-Style arrays should not be used in C++. Use datatype string instead
char phone[MAX_NUM];// C-Style arrays should not be used in C++. Use datatype string instead
char IC[LENGTH_IC];// C-Style arrays should not be used in C++. Use datatype string instead
};
void add_new_user(void)
{
system("CLS"); // Should not be used
ifstream in_file("r:\\information.txt");
static USER new_user[40]; // Do not put this onto the functions stack. Why 40? No need to collect new users locally
// int index = 0; // index is defined again below
char option;
unsigned int unit_number; // Should not be char but unsigned int
if (!in_file)
{
cout << "Error opening txt file" << endl; // Should be written do std::cerr. endl not necesarry
}
else
{
static USER U_list[MAX_USER]; // Should not be put onto stack of function
int index = 0; // Should be unsigned
fflush(stdin); // Should never be done. Will end in undefined behaviour
in_file.getline(U_list[++index].unit_number, LENGTH_UNIT); // Should be optimized
while (in_file)
{
in_file.getline(U_list[index].name, LENGTH_NAME);
in_file.getline(U_list[index].email, LENGTH_MAIL);
in_file.getline(U_list[index].phone, MAX_NUM);
in_file.getline(U_list[index].IC, LENGTH_IC);
if (in_file.peek() == '\n') // Why that?
in_file.ignore(256, '\n');
in_file.getline(U_list[++index].unit_number, LENGTH_UNIT); // Bad index handling
}
in_file.close(); // No need. Destructor will close file for you. But, does not harm
bool in = false; // Starting an endless loop and jumping out with return. Bad design
do
{
char check_unit_number[LENGTH_UNIT];// C-Style arrays should not be used in C++. Use datatype string instead
// int unit_number_count = 0; This variable is used nowhere // endl not necessary. \n can be part of string
cout << "==================================================" << endl; // endl ist not necessary. All the following can be done in one statement.
cout << "==\tUser Management System\t\t==" << endl;
cout << "==================================================" << endl;
cout << "==\tAdd New User\t\t\t==" << endl;
cout << "==================================================\n";
fflush(stdin); // Should never be done. Will end in undefined behaviour
cout << "\nEnter unit number of the new user: " << endl; // endl not necessary. \n can be part of string
cin.get(check_unit_number, LENGTH_UNIT);
cin.ignore(); // ???
for (int i = 0; i < index; i++) // array indices start with 0 in c++
if (strcmp(check_unit_number, U_list[i].unit_number) == 0)
unit_number = i; // **** This will result in undefined and bad behaviour
// Because, unit number may never be initialized and that it has an undefined (random) value
// Or the value from the last loop run. In any case: wrong
if (strcmp(check_unit_number, U_list[unit_number].unit_number) == 0) // **** May leed to out of bounds undefined beahviour
{
fflush(stdin); // Should never be done. Will end in undefined behaviour
cout << "\nEnter new user's unit number: " << endl; // endl not necessary. \n can be part of string
cin.get(new_user[++index].unit_number, LENGTH_UNIT);
cin.clear(); // Better handling of errors necessary
fflush(stdin); // Should never be done. Will end in undefined behaviour
cout << "\nEnter new user's name: " << endl; // endl not necessary. \n can be part of string
cin.get(new_user[index].name, LENGTH_NAME);
cin.clear(); // Better handling of errors necessary
fflush(stdin); // Should never be done. Will end in undefined behaviour
cout << "\nEnter new user's EMAIL ADDRESS: " << endl; // endl not necessary. \n can be part of string
cin.get(new_user[index].email, LENGTH_MAIL);
cin.clear(); // Better handling of errors necessary
fflush(stdin); // Should never be done. Will end in undefined behaviour
cout << "\nEnter new user's phone number: " << endl; // endl not necessary. \n can be part of string
cin.get(new_user[index].phone, MAX_NUM);
cin.clear(); // Better handling of errors necessary
fflush(stdin); // Should never be done. Will end in undefined behaviour
cout << "\nEnter new user's IC: " << endl; // endl not necessary. \n can be part of string
cin.get(new_user[index].IC, LENGTH_IC);
cin.clear(); // Better handling of errors necessary
do
{
cout << "\nDo you confirm to register this new user? [Yes - Y, No - N]\n=>";
cin >> option;
if (option != 'Y' && option != 'N' && option != 'y' && option != 'n')
{
cout << endl; // endl not necessary. \n can be part of string
cout << "Wrong input. Enter again." << endl; // endl not necessary. \n can be part of string
cout << endl; // endl not necessary. \n can be part of string
}
} while (option != 'Y' && option != 'N' && option != 'y' && option != 'n');
if (option == 'Y' || option == 'y')
{
ofstream out_file("information.txt", ios::app);
out_file << setiosflags(ios::left) << new_user[index].unit_number << endl;
out_file << setiosflags(ios::left) << new_user[index].name << endl;
out_file << setiosflags(ios::left) << new_user[index].email << endl;
out_file << setiosflags(ios::left) << new_user[index].phone << endl;
out_file << setiosflags(ios::left) << new_user[index].IC << endl;
out_file.close();
cout << endl; // endl not necessary. \n can be part of string
cout << "The new user is successfully registered.\n" << endl; // endl not necessary. \n can be part of string
system("pause"); // Should not be used
return; // Like a goto. Bad design
}
else if (option == 'N' || option == 'n')
{
cout << "\nThe new user is not registered.\n" << endl; // endl not necessary. \n can be part of string
system("pause"); // Should not be used
return; // Like a goto. Bad design
}
}
else if (strcmp(check_unit_number, U_list[unit_number].unit_number) != 0)
{
cout << "\nThis unit number is not exist.\n" << endl; // endl not necessary. \n can be part of string
system("pause"); // Should not be used
return; // Like a goto.Bad design
}
} while (!in); // Using an endless loop and jumping out with return. Bad design
}
}
int main() {
add_new_user();
}
Next. Let's remove the hard bugs and the findings. Much better. But: The result will still not work as expected:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#include <string.h>
constexpr unsigned int MAX_USER = 100;
constexpr unsigned int LENGTH_UNIT = 30;
constexpr unsigned int LENGTH_NAME = 50;
constexpr unsigned int LENGTH_MAIL = 80;
constexpr unsigned int MAX_NUM = 35;
constexpr unsigned int LENGTH_IC = 50;
struct USER {
char unit_number[LENGTH_UNIT];
char name[LENGTH_NAME];
char email[LENGTH_MAIL];
char phone[MAX_NUM];
char IC[LENGTH_IC];
};
void add_new_user(void)
{
std::ifstream in_file("r:\\information.txt");
if (!in_file)
{
std::cerr << "\n\n*** Error opening source txt file\n\n";
}
else
{
static USER U_list[MAX_USER]; // Should not be put onto stack of function
int index = 0; // Should be unsigned
while (in_file)
{
in_file.getline(U_list[index].unit_number, LENGTH_UNIT); // Should be optimized
in_file.getline(U_list[index].name, LENGTH_NAME);
in_file.getline(U_list[index].email, LENGTH_MAIL);
in_file.getline(U_list[index].phone, MAX_NUM);
in_file.getline(U_list[index].IC, LENGTH_IC);
++index;
}
in_file.close();
bool in = false;
do
{
std::cout << "==================================================\n"
<< "==\tUser Management System\t\t==\n"
<< "==================================================\n"
<< "==\tAdd New User\t\t\t==\n"
<< "==================================================\n";
std::cout << "\nEnter unit number of the new user:\n";
USER new_user{};
std::cin.getline(new_user.unit_number, LENGTH_UNIT);
// We want to count, how many of these units are already in
unsigned int unitCounter = 0;
// Search the unit number that was entered by the user in the list of existing users read from the file
for (int i = 0; i < index; i++) {
if (std::strcmp(new_user.unit_number, U_list[i].unit_number) == 0) {
++unitCounter;
}
}
// If this units exists
if (unitCounter == 1)
{
std::cout << "\nEnter new user's name:\n";
std::cin.getline(new_user.name, LENGTH_NAME);
std::cout << "\nEnter new user's EMAIL ADDRESS:\n";
std::cin.getline(new_user.email, LENGTH_MAIL);
std::cout << "\nEnter new user's phone number:\n";
std::cin.getline(new_user.phone, MAX_NUM);
std::cout << "\nEnter new user's IC:\n";
std::cin.getline(new_user.IC, LENGTH_IC);
char option{};
do
{
std::cout << "\nDo you confirm to register this new user? [Yes - Y, No - N]\n=>";
std::cin >> option;
if (option != 'Y' && option != 'N' && option != 'y' && option != 'n')
{
std::cout << "\nWrong input. Enter again.\n\n";
}
} while (option != 'Y' && option != 'N' && option != 'y' && option != 'n');
if (option == 'Y' || option == 'y')
{
std::ofstream out_file("r:\\information.txt", std::ios::app);
out_file << std::left << new_user.unit_number << '\n';
out_file << new_user.name << '\n';
out_file << new_user.email << '\n';
out_file << new_user.phone << '\n';
out_file << new_user.IC << std::endl;
out_file.close();
std::cout << "\nThe new user is successfully registered.\n\n";
in = true;
}
else if (option == 'N' || option == 'n')
{
std::cout << "\nThe new user is not registered.\n\n";
in = true;
}
}
else if (unitCounter == 0) {
std::cout << "\n\nError Unit does not exist\n\n";
in = true;
}
else if (unitCounter >= 1) { // For 2 and more
std::cout << "\n\nError. Max 2 residents per unit\n\n";
in = true;
}
} while (!in);
}
}
int main() {
add_new_user();
}
Now, add a little bit minimum C++. Still keep the nasty char arrays instead of strings.
But, this solution will work already.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#include <string.h>
constexpr unsigned int MAX_USER = 100;
constexpr unsigned int LENGTH_UNIT = 30;
constexpr unsigned int LENGTH_NAME = 50;
constexpr unsigned int LENGTH_MAIL = 80;
constexpr unsigned int MAX_NUM = 35;
constexpr unsigned int LENGTH_IC = 50;
struct USER {
char unit_number[LENGTH_UNIT];
char name[LENGTH_NAME];
char email[LENGTH_MAIL];
char phone[MAX_NUM];
char IC[LENGTH_IC];
friend std::istream& operator >> (std::istream& is, USER& u) {
is.getline(u.unit_number, LENGTH_UNIT);
is.getline(u.name, LENGTH_NAME);
is.getline(u.email, LENGTH_MAIL);
is.getline(u.phone, MAX_NUM);
return is.getline(u.IC, LENGTH_IC);
}
friend std::ostream& operator << (std::ostream& os, const USER& u) {
return os << u.unit_number << '\n' << u.name << '\n' << u.email << '\n' << u.phone << '\n' << u.IC << std::endl;
}
};
struct DataBase {
USER U_list[MAX_USER]{};
unsigned int numberOfUserInDatabase{};
friend std::istream& operator >> (std::istream& is, DataBase& d) {
while (is >> d.U_list[d.numberOfUserInDatabase])
++d.numberOfUserInDatabase;
return is;
}
};
DataBase dataBase;
void add_new_user(void)
{
std::ifstream in_file("r:\\information.txt");
if (!in_file)
{
std::cerr << "\n\n*** Error opening source txt file\n\n";
}
else
{
in_file >> dataBase;
in_file.close();
bool in = false;
do
{
std::cout << "==================================================\n"
<< "==\tUser Management System\t\t==\n"
<< "==================================================\n"
<< "==\tAdd New User\t\t\t==\n"
<< "==================================================\n";
std::cout << "\nEnter unit number of the new user:\n";
USER new_user{};
std::cin.getline(new_user.unit_number, LENGTH_UNIT);
// We want to count, how many of these units are already in
unsigned int unitCounter = 0;
// Search the unit number that was entered by the user in the list of existing users read from the file
for (unsigned int i = 0; i < dataBase.numberOfUserInDatabase; i++) {
if (std::strcmp(new_user.unit_number, dataBase.U_list[i].unit_number) == 0) {
++unitCounter;
}
}
// If this units exists
if (unitCounter == 1)
{
std::cout << "\nEnter new user's name:\n";
std::cin.getline(new_user.name, LENGTH_NAME);
std::cout << "\nEnter new user's EMAIL ADDRESS:\n";
std::cin.getline(new_user.email, LENGTH_MAIL);
std::cout << "\nEnter new user's phone number:\n";
std::cin.getline(new_user.phone, MAX_NUM);
std::cout << "\nEnter new user's IC:\n";
std::cin.getline(new_user.IC, LENGTH_IC);
char option{};
do
{
std::cout << "\nDo you confirm to register this new user? [Yes - Y, No - N]\n=>";
std::cin >> option;
if (option != 'Y' && option != 'N' && option != 'y' && option != 'n')
{
std::cout << "\nWrong input. Enter again.\n\n";
}
} while (option != 'Y' && option != 'N' && option != 'y' && option != 'n');
if (option == 'Y' || option == 'y')
{
std::ofstream out_file("r:\\information.txt", std::ios::app);
out_file << new_user;
out_file.close();
std::cout << "\nThe new user is successfully registered.\n\n";
in = true;
}
else if (option == 'N' || option == 'n')
{
std::cout << "\nThe new user is not registered.\n\n";
in = true;
}
}
else if (unitCounter == 0) {
std::cout << "\n\nError Unit does not exist\n\n";
in = true;
}
else if (unitCounter >= 1) { // For 2 and more
std::cout << "\n\nError. Not more than max 2 residents per unit allowed\n\n";
in = true;
}
} while (!in);
}
}
int main() {
add_new_user();
}
And last but not least: Remove all C code. And make it an advanced C++ solution.
This will be too complicated in the beginning, but can show the way to go:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
// Here all unit/user data will be stored
const std::string userDataBaseFileName{ "information.txt"};
// CLass for one user
class User {
// User data
std::string unit{};
std::string name{};
std::string email{};
std::string phoneNumber{};
std::string IC{};
public:
// IO functions. Extractor operator
friend std::istream& operator >> (std::istream& is, User& u) {
std::getline(is, u.unit);
std::getline(is, u.name);
std::getline(is, u.email);
std::getline(is, u.phoneNumber);
return std::getline(is, u.IC);
}
// Inserter operator
friend std::ostream& operator << (std::ostream& os, const User& u) {
return os << u.unit << '\n' << u.name << '\n' << u.email << '\n' << u.phoneNumber << '\n' << u.IC << std::endl;
}
// Check, if 2 units are equal
bool equalUnit(const User& other) const { return unit == other.unit; }
};
// IO functions. Extractor operator
class DataBase {
std::vector<User> user{};
public:
// Here is the number of maximum users per unit
static constexpr size_t MaxUserPerUnit{ 2u };
static_assert(MaxUserPerUnit >= 1 , "Error: At least one user must be allowed per Unit\n"); // Must be greater than 1
// Calculate number of user per unit
size_t usersInUnit(const User& testUser) const { return std::count_if(user.begin(), user.end(), [&](const User& u) { return u.equalUnit(testUser); }); }
// IO functions. Extractor operator. Read all users
friend std::istream& operator >> (std::istream& is, DataBase& d) {
User tempUser{};
while (is >> tempUser) d += tempUser;
return is;
}
// Inserter operator
friend std::ostream& operator << (std::ostream& os, const DataBase& u) {
std::copy(u.user.begin(), u.user.end(), std::ostream_iterator<User>(os));
return os;
}
// Ad a new use to the database via += operator
DataBase& operator+=(const User& u) {
if (usersInUnit(u) < MaxUserPerUnit)
user.push_back(u);
else
std::cerr << "Error. Too many users in unit. Ignoring user:\n" << u << "\n\n";
return *this;
}
};
DataBase dataBase;
void addNewUser()
{
// Open source file and chek, if it could be opened
if (std::ifstream informationDataFileStream{ userDataBaseFileName }; informationDataFileStream) {
// The file is open. Read all data from file
informationDataFileStream >> dataBase;
// Some debug output
std::cout << "\n\nThe following data has been read from file:\n\n" << dataBase << "\n\n";
// Ask operator to enter a new user
std::cout << "\nPlease enter new user information. One at a line. In this order: Unit, Name, Email, Phone Number, ID:\n";
// Read a new user from operator
User tempUser{}; std::cin >> tempUser;
// Confirm, if the user wants really add this info.
std::cout << "\n\nYour entered the following data:\n\n" << tempUser << "\n\nDo you really want to add? (y = yes, everything else = No\n--> ";
char option{}; std::cin >> option;
if (option == 'y') {
// Give confirmation to user
std::cout << "\n\nData will be added to database\n";
// add new user to database
dataBase += tempUser;
// Save all data to disk
if (std::ofstream dataFileStream{ userDataBaseFileName }; dataFileStream) {
dataFileStream << dataBase;
}
else std::cerr << "\nError: Could not open file '" << userDataBaseFileName << "' for writing\n\n";
}
else std::cout << "\n\nData will NOT be added to database\n";
}
else std::cerr << "\nError: Could not open file '" << userDataBaseFileName << "' for reading\n\n";
}
int main() {
addNewUser();
}
Have fun . . .

How to Accept [ENTER] key as an invalid input and send out error message

This is a program that grade user inputs for the questions of Driver's License Exam.
I'm having trouble of validating the user input.
I'd like to accept the [ENTER] key as an invalid input and proceed to my validation rather than just go to an empty line and cannot process to the next question. Purpose is to send out error message and that no input is given and [ENTER] key is not valid input and only accept one more chance to enter valid input which are a/A, b/B, c/C, or d/D. So that is why I'm using if statement here instead of loop.
I tried if (testTakerAnswers[ans] == (or =) '\n') {} but still doesn't solve the problem of newline.
I include curses.h in here hope to use getch() statement from the other post but somehow I can't manage to work in my code with an array instead of regular input.
I'm looking for other methods as well rather than getch()
So should I adjust my bool function, or directly validate input in main() function.
#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
#include <curses.h>
using namespace std;
const unsigned SIZE = 20; // Number of qns in the test
char testTakerAnswers[SIZE]; //Array to hold test taker's answers
bool validateInput(char);
class TestGrader
{
private:
char answers[SIZE]; // Holds the correct answers // Answer is array
int getNumWrong (char[]);
void missedQuestions (char[]);
public:
void setKey(string); // Initialize object with standard keys
void grade(char[]); // Grades the answers from tester
};
void TestGrader::setKey(string key){
if (key.length()!=SIZE){
cout << "Error in key data.\n";
return;
}
for (unsigned pos = 0; pos < SIZE ; pos ++)
answers [pos] = key [pos];
}
void TestGrader::grade(char test[])
{
int numWrong = getNumWrong(test);
if (numWrong <= 5)
cout << "Congratulations. You passed the exam.\n";
else
cout << "You did not pass the exam. \n";
cout << "You got " << (SIZE-numWrong) << " questions correct. \n";
if (numWrong > 0){
cout << "You missed the following " << numWrong << " questions: \n";
missedQuestions(test);
}
}
int TestGrader::getNumWrong(char test[])
{
int counter = 0;
for (int i = 0; i < SIZE; i++){
if (answers[i] != toupper(testTakerAnswers[i])){
counter++;
}
}
return counter;
}
void TestGrader::missedQuestions(char test[])
{
// cout << testTakerAnswers[i]; This is to print taker's answers
int counter = 0;
for (int i = 0; i < SIZE; i++){
if (answers[i] != toupper(testTakerAnswers[i])){
cout << "\n" << i + 1 << ". Correct answers: " << answers[i];
counter++;
}
}
}
bool validateInput(char ans){ // Only A, B, C, D valid input
if (toupper(ans)!='A' && toupper(ans)!= 'B' && toupper(ans)!='C' && toupper(ans)!= 'D'){
cout << "\n********************WARNING*******************\n";
cout << "Invalid input! Enter only a/A, b/B, c/C, or d/D\n";
return false;
}
if (testTakerAnswers[ans] == '\n'){
return false;
}
return true;
}
int main()
{
const int NUM_QUESTIONS = 20;
string name; //Test taker's name
char doAnother; //Control variable for main processing loop
TestGrader DMVexam; //Create a TestGrader object
DMVexam.setKey("BDAACABACDBCDADCCBDA");
do {
cout << "Applicant Name: ";
getline(cin,name);
cout << "Enter answer for " << name << ".\n";
cout << "Use only letters a/A, b/B, c/C, and d/D. \n\n";
for (int i = 0; i < NUM_QUESTIONS; i++){
// Input and validate it
do{
cout << "Q" << i+1 << ": ";
cin >> testTakerAnswers[i];
if (!validateInput(testTakerAnswers[i])){
cout << "You get one more chance to correct.\nOtherwise, it count as wrong answer.";
cout << "\n*********************************************";
cout << "\nRe-enter: ";
cin >> testTakerAnswers[i];
cout << '\n';
break;
}
}while(!validateInput(testTakerAnswers[i]));
}
//Call class function to grade the exam
cout << "Results for " << name << '\n';
DMVexam.grade(testTakerAnswers);
cout << "\nGrade another exam (Y/N)? ";
cin >> doAnother;
while (doAnother != 'Y' && doAnother != 'N' && doAnother != 'y' && doAnother != 'n'){
cout << doAnother << " is not a valid option. Try Again y/Y or n/N" << endl;
cin >> doAnother;}
cout << endl;
cin.ignore();
}while(doAnother != 'N' && doAnother != 'n');
return 0;
}
Your issue is cin >> testTakerAnswers[i]; cin is whitespace delimited, that means that any whitespace (including '\n') will be discarded. So testTakerAnswers[i] can never be '\n'.
I'm not sure exactly what you want to do, but possibly try
getline(cin,input_string);
then
input_string == "A" | input_string == "B" | ...
So if only the enter key is pressed, input_string will become "".

What is a deleted function, and why only my functions that I pass files into are considered deleted? [duplicate]

This question already has answers here:
Using fstream Object as a Function Parameter
(3 answers)
Closed 6 years ago.
#include <bits/stdc++.h>
using namespace std;
class contact {
private:
vector< pair<string, int> > contact_info;
public:
void add_contact(string contact_name, int contact_number) {
contact_info.push_back(make_pair(contact_name, contact_number));
sort(contact_info.begin(),contact_info.end());
}
void edit_contact(string contact_name) {
int found_at;
for (unsigned int i =0; i < contact_info.size(); i++) {
if (contact_info[i].first == contact_name) {
found_at = i;
}
}
if (contact_info[found_at +1].first == contact_name) {
int choice;
int counter = found_at;
int index = 1;
while (contact_info[counter].first == contact_name) {
cout << index << ". " << contact_info[counter].first << " " << contact_info[counter].second;
counter++;
index++;
}
cout << "Choose any please: ";
cin >> choice;
found_at = found_at - (choice - 1);
}
cout << "Enter the new number: ";
cin >> contact_info[found_at].second;
}
void show_all() {
for (unsigned int i =0; i < contact_info.size(); i++) {
cout << contact_info[i].first << " " << contact_info[i].second << endl;
}
}
void delete_contact(string contact_name) {
int found_at;
for (unsigned int i =0; i < contact_info.size(); i++) {
if (contact_info[i].first == contact_name) {
found_at = i;
}
}
if (contact_info[found_at +1].first == contact_name) {
int choice;
int counter = found_at;
int index = 1;
while (contact_info[counter].first == contact_name) {
cout << index << ". " << contact_info[counter].first << " " << contact_info[counter].second;
counter++;
index++;
}
cout << "Choose any please: ";
cin >> choice;
found_at = found_at - (choice - 1);
}
contact_info.erase(contact_info.begin()+found_at);
}
void writeFile(ofstream contact_file) {
for (unsigned int i =0; i < contact_info.size(); i++) {
contact_file << contact_info[i].first << " " << contact_info[i].second << endl;
}
}
void readFile(ifstream contact_file) {
string input;
while (!contact_file.eof()) {
contact_file >> input;
size_t pos = input.find(" ");
string name = input.substr(0,pos);
string number_str = input.substr(pos);
int number = stoi(number_str) ;
contact_info.push_back(make_pair(name,number));
}
}
};
int main()
{
int choice;
ifstream contacts_file_read;
contacts_file_read.open("contacts.txt");
ofstream contacts_file_write;
contacts_file_write.open("contacts.txt");
bool in_prog = true;
contact contacts;
string name;
int number;
while (in_prog) {
cout << "1. Add contacts" << endl
<< "2. Edit contact" << endl
<< "3. Delete contact" << endl
<< "4. Show all" << endl
<< "5. exit" << endl;
cout << "Your choice: ";
cin >> choice;
contacts.readFile(contacts_file_read);
if (choice == 1) {
cout << "Enter name & number separated by a space: ";
cin >> name >> number;
contacts.add_contact(name, number);
} else if (choice == 2) {
cout << "Enter name of contacts to be edited: ";
cin >> name;
contacts.edit_contact(name);
} else if (choice == 3) {
cout << "Enter name of contact to be deleted: ";
cin >> name;
contacts.delete_contact(name);
} else if (choice == 4) {
contacts.show_all();
} else if(choice == 5) {
contacts.writeFile(contacts_file_write);
} else {
cout << "Wrong choice" << endl;
}
}
return 0;
}
So, I was asked in my programming class to make a phone book application in C++ using only objects, so this is my attempt at it.
All functions are good, I did recompile the program after finishing each function at it gave me 0 errors, however whenever I try to call writeFile or readFile function that were previously working fine, now the compiler gave me an error of "error: use of deleted functions... "
I don't know what are deleted functions and why only functions that take file objects as an argument are treated as such.
Can anyone please help?
Thanks.
Objects of type std::ifstream are not copyable -- indeed, the object represents the unique handle of an open file, and it would be difficult to conceptualize what it would mean to copy such unique responsibility.
Indeed, this inability to copy an object is encoded by making the copy constructor deleted, which causes the error that you see when you do attempt to copy it.
Your code should pass the original ifstream, not a copy (by taking a reference parameter):
void readFile(ifstream & contact_file)
// ^^^^^^^^^^

Reading data from csv file C++

Hi my project have many csv files. Which is located in the same directory as Datafolder/IAG/day1.csv, Datafolder/IAG/day2.csv and Datafolder/IAG/day3.csv. Same for Datafolder/CBA/day1.csv, Datafolder/CBA/day2.csv and Datafolder/CBA/day3.csv and Datafolder/NAB/day1.csv, Datafolder/NAB/day2.csv and Datafolder/NAB/day3.csv.
my goal is user can input which day's data they want and input. Once they input it will ask the user to enter either 1(to get the highest price value) or 2(lowest price value). But in my code I dont why once the user select the day and get the highest price it is stored as that value. Even though the user select another day and look for the highest price it is not actually displaying that day's highest value but the previous day's highest value which copied over again The following is codes. Thanks in advance guys.
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include "vector.h"
#include "stock.h"
#include <map>
using namespace std;
int counter = 0;
double highestPrice=0, lowestPrice=0;
ofstream outfile;
string sFileName;
string record;
Stock S1;
Vector<Stock> data;
int option;
ifstream codeindex;
ifstream IAGsales;
ifstream CBAsales;
ifstream NABsales;
ifstream* Tempsales = 0;
ifstream infile;
map<string,Vector<Stock>> mapIAG;
map<string,Vector<Stock>> mapCBA;
map<string,Vector<Stock>> mapNAB;
map<string,Vector<Stock>> mapTemp;
map<string,Vector<Stock>>::iterator it;
double price1, price2;
Time time1, time2;
Date date1;
string sXCode,sInputDate;
int main()
{
void initializing();
codeindex.open("Datafolder/code_index.txt");
if(! codeindex)
{
cout << codeindex <<" : File not found!!" << endl;
system("PAUSE");
exit(1);
}
do
{
initializing();
time1.initialize();
highestPrice = (data.getvalue(0)).getprice();//Initialise highest price
lowestPrice=0;
lowestPrice = (data.getvalue(0)).getprice();//Initialise lowest price
(data.getvalue(0)).gettime(time1, data.getvalue(0));//Initialise time1
switch (option)
{
case 1:
{
Date datehigh;
for(int i = 1 ; i < counter ; i ++)
{
if((data.getvalue(i)).getprice() > highestPrice)
{
highestPrice = (data.getvalue(i)).getprice();
(data.getvalue(i)).gettime(time1, data.getvalue(i));//get the time when highest price first occurred
(data.getvalue(i)).getdate(datehigh, data.getvalue(i));
}
}
cout << "Date: " << datehigh << endl;
cout << "Highest price : " << highestPrice << endl;
cout << "Start time(s): " << endl;
cout << time1 ;
for(int i = 0 ; i < counter ; i ++)
{
if( (data.getvalue(i)).getprice() == highestPrice)
{
(data.getvalue(i)).gettime(time2, data.getvalue(i));//get the time when highest price occurred
if(time2 != time1)//avoid duplicated time
{
(data.getvalue(i)).printtime();
(data.getvalue(i)).gettime(time1, data.getvalue(i));
//(data.getvalue(i)).getdate(datehigh, data.getvalue(i));
}
}//End of if( (data.get(i)).getprice() == highestPrice)
}//End of for(int i = 0 ; i < count ; i ++)
//main();
//initialize();
//(data.getvalue(0)).printdate();
break;
}
case 2:
{
Date datelow;
for(int i = 1 ; i < counter ; i ++)
{
if(((data.getvalue(i)).getprice() < lowestPrice) && ((data.getvalue(i)).getprice() > 0))
{
lowestPrice = (data.getvalue(i)).getprice();
(data.getvalue(i)).gettime(time1, data.getvalue(i));//get the time when lowest price first occurred
(data.getvalue(i)).getdate(datelow, data.getvalue(i));
}
}
int j =0;
//(data.getvalue(j)).printdate();
cout << "Date: " << datelow << endl;
cout << "Lowest price: " << lowestPrice << endl;
cout << "Start time(s): " << endl;
cout << time1<<endl;
for(int i = 0 ; i < counter ; i ++)
{
if( (data.getvalue(i)).getprice() == lowestPrice)
{
(data.getvalue(i)).gettime(time2, data.getvalue(i));//get the time when highest price occurred
if(time2 != time1)//avoid duplicated time
{
(data.getvalue(i)).printtime();
(data.getvalue(i)).gettime(time1, data.getvalue(i));
}
}//End of if( (data.get(i)).getprice() == lowestPrice)
}//End of for(int i = 0 ; i < count ; i ++)
//main();
//initialize();
break;
}
case 3:
{
outfile.open("output.csv");
if(! outfile)
{
cout << "Can not open outfile" << endl;
exit(1);
}
cout << "Data processing" << endl;
outfile << fixed << showpoint << setprecision(2);
outfile << "Date,Start time,Price of share,Volume of shares traded,Total value of shares traded" << endl;
price1 = data.getvalue(counter-1).getprice();//get price for the last row
double nVolumeOfTrades = data.getvalue(counter-1).getvolume();
double ntotalValueOfShares = data.getvalue(counter-1).getvalue();
// Get Date of trading
data.getvalue(counter-1).getdate(date1,data.getvalue(counter-1));
// Get Start time
data.getvalue(counter-1).gettime(time1,data.getvalue(counter-1));
for(int i = counter-2; i > -1 ; i --)
{
price2 = data.getvalue(i).getprice();
if(price2 != 0 && price1 != price2)
{
// Write values to file.
outfile << date1 << "," << time1 << "," << price1 << "," << nVolumeOfTrades << "," << ntotalValueOfShares << endl;
// Get Date of trading
data.getvalue(i).getdate(date1,data.getvalue(i));
// Get Start time
data.getvalue(i).gettime(time1,data.getvalue(i));
price1 = data.getvalue(i).getprice();
nVolumeOfTrades = 0;
ntotalValueOfShares = 0;
}
nVolumeOfTrades += data.getvalue(i).getvolume();
ntotalValueOfShares += data.getvalue(i).getvalue();
}
cout << "Data processed" << endl;
outfile.close();
//initialize();
//main();
break;
}
case 4:
{
break;
}
default:
{
cout << "Invalid option" << endl;
cout<<"Choose from options 1 to 4: "<<endl;
cout << "Enter 1 to get the highest stock price & time:" << endl;
cout << "Enter 2 to get the lowest stock price & time:" << endl;
cout << "Enter 3 to output the csv file: " << endl;
cout << "Enter 4 to exit from the program:" << endl;
cin >> option;
break;
}
}
if(option==4)
{
break;
}
cout << "\n\n" << endl;
}
while(1);
return 0;
}
void initializing()
{
// Present the user with Input options
cout<<"Enter the code of transaction:" <<endl;
while(! codeindex.eof()){
getline(codeindex,record);
cout<<record<<endl;
}
cin>>sXCode;
codeindex.clear();
codeindex.seekg(0,ios::beg);
while(sXCode!="IAG" && sXCode!="CBA" && sXCode!="NAB"){
cout<<"Wrong input .. Please enter again \n";
cin>>sXCode;
}
// Get code file name.
if(sXCode=="IAG")
{
if(IAGsales.is_open()==true){
IAGsales.close();
}
IAGsales.open("Datafolder/IAG/sales_index.txt");
if(!IAGsales)
{
cout << IAGsales<<" :File not found!!" << endl;
system("PAUSE");
exit(1);
}
// Read IAG file names.
while(!IAGsales.eof())
{
getline(IAGsales, sFileName);
if(sFileName.size() > 0)
{ //cout<<"before: "<< sFilePath <<endl;
string sFilePath = "Datafolder/IAG/";
sFilePath = sFilePath.append(sFileName);
cout<<"after append: "<< sFilePath <<endl;
// Read the csv file
infile.open(sFilePath);
if(! infile)
{
cout << sFileName<<": File not found!!" << endl;
exit(1);
}
getline(infile, record);//first line
getline(infile, record);//second line
while(! infile.eof())
{
getline(infile, record);
if(record.size() > 0)
{
S1.readfile(record, S1);
data.insert(S1);
counter ++;
}
}//while(! infile.eof())
infile.close();
// Insert to Map
mapIAG.insert(pair<string,Vector<Stock>>(sFileName,data));
}
}
IAGsales.clear();
IAGsales.seekg(0,ios::beg);
Tempsales = &IAGsales;
//cout<<"test1";
//IAGsales.close();
}
else if(sXCode=="CBA")
{
if(CBAsales.is_open()==true){
CBAsales.close();
}
CBAsales.open("Datafolder/CBA/sales_index.txt");
if(!CBAsales)
{
cout << CBAsales<<" : File not found!!" << endl;
system("PAUSE");
exit(1);
}
// Read IAG file names.
while(!CBAsales.eof())
{
getline(CBAsales, sFileName);
if(sFileName.size() > 0)
{
string sFilePath = "Datafolder/CBA/";
sFilePath = sFilePath.append(sFileName);
// Read the csv file
infile.open(sFilePath);
if(! infile)
{
cout << sFileName<<": File not foud!!!" << endl;
exit(1);
}
getline(infile, record);//first line
getline(infile, record);//second line
while(! infile.eof())
{
getline(infile, record);
if(record.size() > 0)
{
S1.readfile(record, S1);
data.insert(S1);
counter ++;
}
}//while(! infile.eof())
infile.close();
// Insert to Map
mapIAG.insert(pair<string,Vector<Stock>>(sFileName,data));
}
}
CBAsales.clear();
CBAsales.seekg(0,ios::beg);
Tempsales = &CBAsales;
//cout<<"test2";
}
else
{
if(NABsales.is_open()==true){
NABsales.close();
}
NABsales.open("Datafolder/NAB/sales_index.txt");
if(!NABsales)
{
cout << NABsales<<" : File not found!!!!" << endl;
system("PAUSE");
exit(1);
}
// Read IAG file names.
while(!NABsales.eof())
{
getline(NABsales, sFileName);
if(sFileName.size() > 0)
{
string sFilePath = "Datafolder/NAB/";
sFilePath = sFilePath.append(sFileName);
// Read the csv file
infile.open(sFilePath);
if(! infile)
{
cout << sFileName<<": File not foud!!" << endl;
exit(1);
}
getline(infile, record);//first line
getline(infile, record);//second line
while(! infile.eof())
{
getline(infile, record);
if(record.size() > 0)
{
S1.readfile(record, S1);
data.insert(S1);
counter ++;
}
}//while(! infile.eof())
infile.close();
// Insert to Map
mapIAG.insert(pair<string,Vector<Stock>>(sFileName,data));
}
}
NABsales.clear();
NABsales.seekg(0,ios::beg);
Tempsales = &NABsales;
//cout<<"test3";
}
highestPrice = (data.getvalue(0)).getprice();//Initialise highest price
lowestPrice = (data.getvalue(0)).getprice();//Initialise lowest price
(data.getvalue(0)).gettime(time1, data.getvalue(0));//Initialise time1
cout<<"Enter the date of transaction:" <<endl;
while(!Tempsales->eof()){
getline(*Tempsales,record);
cout<<record<<endl;
}
cin>>sInputDate;
cout<<"Choose from options 1 to 4: "<<endl;
cout << "Enter 1 to get the highest stock price & time:" << endl;
cout << "Enter 2 to get the lowest stock price & time:" << endl;
cout << "Enter 3 to output the csv file: " << endl;
cout << "Enter 4 to exit from the program:" << endl;
cin >> option;
// Get the vector from Map based on Date.
if(sXCode=="IAG")
{
it = mapIAG.find(sInputDate);
data = it->second;
}
else if(sXCode=="CBA")
{
it = mapIAG.find(sInputDate);
data = it->second;
}
else
{
it = mapIAG.find(sInputDate);
data = it->second;
}
}
Stock is a Vector.

std::out_of_range at memory location 0x0043f7c4.. error when using vectors and an input file

What i am trying to do is get user to enter a key code and if it matches to display the information on the data input file. I am getting this error which i have no idea what for.
std::out_of_range at memory location 0x0043f7c4..
Below is my input file and my code
HEA,EMA,British Airways,030,025
HEA,EMA,Thomas Cook Airlines,020,040
HEA,DUB,British Airways,420,450
HEA,DUB,Thomas Cook Airlines,400,550
EMA,BAR,British Airways,120,140
EMA,BAR,Thomas Cook Airlines,100,150
ROM,EMA,British Airways, 120,125
ROM,EMA,Thomas Cook Airlines,150,090
ROM,BAR,British Airways,106,050
ROM,BAR,Thomas Cook Airlines,100,080
BAR,HEA,British Airways,125,090
BAR,HEA,Thomas Cook Airlines,100,120
DUB,EMA,Thomas Cook Airlines,450,380
DUB,EMA,Thomas Cook Airlines,420,450
below is my C++ code
#include <vector>
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
//#include "TravelFunctions.h"
using namespace std;
vector<string>flightDetails;
vector<string>flightSearch;
string airportDepart;
string airportArrive;
bool errorArrive = false;
bool errorDepart = false;
string timeTaken;
int tax;
int cost;
bool needtoentercodes = false;
string entry;
int main()
{
// first i will read in the airport.txt data and store the information into a vector.
ifstream flightdata("flightinfo.txt");
string flightnextline;
if (!flightdata)
{
cout << "Cannot Open the file 'flightdata.txt'";
}
else
{
while (flightdata.good())
{
getline (flightdata, flightnextline);
flightDetails.push_back(flightnextline);
}
flightdata.close();
}
cout << " ___________________ " << endl;
cout << "| Airport Key Code |" << endl;
cout << "|EMA = East Midlands|" << endl;
cout << "|HEA = Heathrow |" << endl;
cout << "|BAR = Barcelona |" << endl;
cout << "|ROM = ROME |" << endl;
cout << "|DUB = DUBAI |" << endl;
cout << "| |" << endl;
cout << "|___________________|" << endl;
cout << endl;
cout << endl;
cout << endl;
entry = "Please enter the ID code of the starting destination.\n";
while (needtoentercodes == false)
{
cout<< entry;
cout << "Use the key above to see which airports are available. \n";
string userdepartid;
cin>> userdepartid;
bool k = false;
//VALIDATING USER INPUT FOR DEPARTURE AIRPORT CODE - As mentioned above, this little section validates the starting departure id code.
while (k==false){
if ((userdepartid != "HEA") && (userdepartid != "EMA") && (userdepartid != "DUB") && (userdepartid != "BAR") && (userdepartid != "ROM"))
{
cout << "You have entered an incorrect departure code.\nPlease Try Again...\n";
cin >> userdepartid;
}
else
{
k=true;
}
}
cout << "\n";
cout << "Please enter the code of the arrival destination.\n";
string userarrivalid;
cin >> userarrivalid;
//VALIDATING USER INPUT FOR ARRIVAL AIRPORT CODE - This little section of code validates the arrival id airport code inputted in by the user.
bool a = false;
while (a==false){
if ((userarrivalid != "HEA") && (userarrivalid != "EMA") && (userarrivalid != "ROM") && (userarrivalid != "DUB") && (userarrivalid != "BAR"))
{
cout << "You have entered an incorrect departure code.\nPlease Try Again...\n";
cin >> userarrivalid;
}
else
{
a=true;
}
}
int j = 1;
bool resultsfound = false;
cout << "\n";
//RETURN THE RESULTS AND PUT THE RESULTS IN AN ARRAY - This little section places the searched results in a unique vector which then can be used later on in the program.
for (int i=0; i < flightDetails.size(); i++)
{
string tempflightdata = flightDetails[i];
string departid = tempflightdata.substr(0,3);
string arrivalid = tempflightdata.substr(4,3);
if ((departid == userdepartid) && (arrivalid == userarrivalid))
{
cout << j << ":" << flightDetails[i] << "\n";
flightSearch.push_back(flightDetails[i]);
j++;
needtoentercodes = false;
}
else
{
entry = "| Incorrect Entry. No direct connections! |\nPlease enter the ID code of the starting destination.\n";
}
}
}
}
It's the old, old problem
while (flightdata.good())
{
getline (flightdata, flightnextline);
flightDetails.push_back(flightnextline);
}
flightdata.close();
should be
while (getline (flightdata, flightnextline))
{
flightDetails.push_back(flightnextline);
}
flightdata.close();
Your while loop goes round one too many times because flightdata is still good() even after you've read the last line, and so you end up adding a blank line to your flightDetails vector. Later when you do tempflightdata.substr(4,3); on a blank line this causes the out_of_range error you see.
Caveat, I've only looked at the code, not debugged it.