Count in string - c++

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 . . .

Related

Getting the input from the file as string and also integer C++

I have a text file. I have a text file consisting of member data. I am developing a program where we can get the member data from the file. After searching in the internet, I have searched a way to read all the data from the file as char array. But I want to change it where upon reading from file I want the data to be string and also integer.
name, icno, email, phone_number, acc_num, password ( read from file AS STRING )
month, year ( read from file AS INTEGER )
Content of Membership.txt
Mathavan|021127100897|MathavanKrishnan27#gmail.com|0167750575|1410065449|Mathavan1234|3|2022
Mathavan|021127100897|MathavanKrishnan27#gmail.com|0167750575|1410065448|Mathavan1234|3|2024
Mathavan|021127100897|MathavanKrishnan27#gmail.com|0167750575|1410065447|Mathavan1234|3|2022
string member_login(){
title();
fstream member;
member.open("Membership.txt",ios::in);
string pass_input, line, acc_num1, password1;
int login_attempt = 0, count = 0 , account = 0;
char dummy, resp, accno_input[25], name[25], icno[25],email [40], phone_number[25],acc_num[25],password[25],month[25], year[25];
account_num:
cout << " Enter your account number : ";
cin >> accno_input;
ifstream file("Membership.txt");
while (!file.eof()){
getline(file, line);
count++;
}
cout << accno_input;
int i = 0;
while(i <= count)
{
member.getline(name,25,'|');
member.getline(icno,25,'|');
member.getline(email,40,'|');
member.getline(phone_number,25, '|');
member.getline(acc_num,25, '|');
member.getline(password,25,'|' );
member.getline(month,25,'|' );
member.getline(year, 25);
cout << name << " ";
cout << icno << " ";
cout << acc_num << " ";
cout << accno_input;
if (acc_num == accno_input){
account = 1;
break;
}
i ++;
}
cout << account;
member.close();
if ( account != 1 ){
cout << endl;
cout << " Your account not found !!!"<< endl;
cout << " Please try again !!" << endl << endl;
cout << " PLEASE ENTER ANY KEY TO CONTINUE >>> ";
cin >> dummy;
goto account_num;
}
password1 = password;
cout << endl;
cout << " Enter your account password : ";
cin >> pass_input;
for (login_attempt = 1 ; login_attempt <= 2 ; login_attempt ++){
if (pass_input == password1){
cout << "Login Successful !!!";
break;
}
cout << endl;
cout << "Login Failed. Attempt " << login_attempt << " of 3" << endl;
cout << "Please re-enter Password: " ;
cin >> pass_input;
if (pass_input == password1){
cout << "Login Successful !!!";
break;
}
}
if ( login_attempt == 3){
cout << endl;
cout << "Login Failed. Attempt 3 of 3";
}
return accno_input;
}
There are so many things completely wrong in your program that I do recomend to you:
Delete and start from scratch.
There is no meaningful fix possible. There is even a goto. And you MUST stop using C-Style arrays with some agic dimension in C++. And C++ has many things to make your live easier. Simply use them.
Please find below a C++ solution.
You can copy and paste it and stay as you are, or, you take 3 hours and google all constructs and try to understand and learn and become a better programmer. Your choise.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
#include <regex>
#include <iterator>
#include <algorithm>
const std::regex re{ R"(\|)" };
struct Member {
// Memeber data
std::string name{};
std::string icno{};
std::string email{};
std::string phoneNumber{};
std::string accountNumber{};
std::string password{};
int month{};
int year{};
// Extractor operator
friend std::istream& operator >> (std::istream& is, Member& m) {
// Readone complete line
if (std::string line{}; std::getline(is, line)) {
// Split it into parts
std::vector parts(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {});
// assign parts to member data
if (parts.size() == 8) {
m.name = parts[0]; m.icno = parts[1]; m.email = parts[2]; m.phoneNumber = parts[3]; m.accountNumber = parts[4]; m.password = parts[5];
m.month = std::stoi(parts[6]); m.year = std::stoi(parts[7]);
}
}
return is;
}
};
// Filename for member data
const std::string fileName{ "r:\\Membership.txt" };
int main() {
// Open the data file and check, if it could be opened
if (std::ifstream fileStream{ fileName }; fileStream) {
// Read complete source file, parse it and get all data
std::vector memberData(std::istream_iterator<Member>(fileStream), {});
// We want the user to give 3 trials to enter valid data
constexpr unsigned int MaxTrials = 3u;
unsigned int numberOfTrials{};
// A valid input will stop the loop immediately
bool validInputgiven{};
// Now, try to get the correct input
while (not validInputgiven and numberOfTrials < MaxTrials) {
// Get an acoount number
std::cout << "\nEnter a account number: ";
std::string account{};
std::cin >> account;
// Check, if the account number is in the member data
if (std::count_if(memberData.begin(), memberData.end(), [&](const Member& m) { return m.accountNumber == account; }) > 0) {
// Account info wasOK. Get the password
std::cout << "\nEnter your password: ";
std::string password{};
std::cin >> password;
if (std::count_if(memberData.begin(), memberData.end(), [&](const Member& m) { return m.accountNumber == account and m.password == password; }) > 0) {
// Valid data found
validInputgiven = true;
std::cout << "\n\nEverything OK. Data validated.\n\n";
}
}
// Next try
++numberOfTrials;
if (not validInputgiven and numberOfTrials < MaxTrials) std::cout << "\nInvalid input. Please try again\n\n\n";
}
if (not validInputgiven ) std::cout << "\nToo many wrong tries. Aborting . . .\n\n\n";
}
else std::cerr << "\n\nError. Could not open source file '" << fileName << "'\n\n";
}

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

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!
}

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 "".

Creating a menu using vectors, strings and arrays while reading from 2 text files

Alright, I been trying to do this for a couple of hours but I'm not getting anywhere. First of
all, I have 2 text files that I need to read from a different function which is simple enough. Then for one of the text files, mainly the college.txt, I have to add it to a vector of strings; for the other text file(states.txt), I have to add the states to parallel arrays of strings.
The problem(This is related to the college.txt file) I have is how do I compare the strings the user inputs to the strings inside the vector since I have to validate whether or not the colleges/universities that the user inputs are on the list(and of course repeat it until the user decides to quit but that's also simple enough to do with a while loop).
Note1: Before you ask, The else/if with empty statements are empty because I want to focus on this problem first and then I will continue on with the program.
Note2: The IDE that I'm using is CodeBlocks
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;
bool DoesStringEqualVector(vector<string> total, string name)
{
for (unsigned int i=0; i < total.size(); ++i)
{
if (name == total[i])
return true;
}
return false;
}
void collegesUniversities(string)
{
ifstream campuses;
campuses.open("colleges.txt");
string schools;
vector<string> schoolVector;
if(!campuses)
cerr << "Error opening file. ";
else
{
while(campuses.good())
{
getline(campuses,schools, '\n');
schoolVector.push_back(schools);
cout << schools << endl;
}
}
DoesStringEqualVector(schoolVector, schools);
campuses.close();
}
int main()
{
char response;
string comparison;
int choice;
string userInput;
cout << "\nWelcome to my college and university search program.\n";
cout << "\nPress any button to continue.\n ";
system("pause>nul");
do
{
cout << "\nPress 1 to enter possible colleges and universities.";
cout << "\nPress 2 to find out how many colleges and universities";
cout << " appear in your state.\n";
cout << "Press 3 to find the total amount of colleges and";
cout << " universities in our list. ";
cout << "\nPress 4 to quit. ";
cin >> choice;
if(choice == 1)
{
do
{
cout << "\nEnter the name of your college/university. ";
cin >> userInput;
collegesUniversities(comparison);
if(userInput != comparison)
cout << "\nThis institution isn't on out list.\n ";
else
cout << "\nThis institution is on the list.\n";
cout << "\nWould you like to return to the menu?[Y/N] ";
cin >> response;
while(response != 'Y' && response != 'y' && response != 'N' &&
response != 'n')
{
cerr << "\nError, Invalid Input.";
cin >> response;
}
}
while(response != 'N' && response != 'n');
}
else if(choice == 2)
{
}
else if(choice == 3)
{
}
else if(choice == 4)
{
cout << "\nThank you for using my program. ";
cout << "Have a great day.\n ";
}
else
{
cerr << "\nError, Invalid input. ";
cout << "Only integers from 1 through 4 are allowed.\n";
}
}
while(choice != 4);
}
Wrap it all up in a method that checks through the vector:
bool IsStringInVector(vector <string> collection, string item)
{
for (int i=0; i < collection.size(); ++i)
{
if (item == collection[i])
return true;
}
return false;
}
You have to scan through the collection to see if it's in there.

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.