Strange character in C++ program output - c++

I am creating an ATM program in C++ for school and I'm using this project as an opportunity to begin learning the language. I am trying to output bank accounts to a text file in this format:
First Last
CardNumber
PinNumber
Balance
Originally it was outputting fine and then I developed a bunch of new methods etc. I didn't change any of the original code that has to do with outputting the bank account but now it's outputting strangely.
My output ends up being:
First Last
random letter or symbol
PinNumber
blank
Here is my code for creating a new bank account:
AccountHandler.h
#include <iostream>
#include <string>
using namespace std;
struct bankAccount //Create a new bank account type
{
string name;
string cardNum;
string balance;
string pin;
};
class AccountHandler
{
public:
AccountHandler();
~AccountHandler();
void withdraw(struct bankAccount acc, string amount);
void deposit(struct bankAccount acc);
int checkBalance(struct bankAccount acc);
void createAccount();
};
AccountHandler.cpp
void AccountHandler::createAccount() //creates a new bank account and stores in accounts.txt
{
ofstream accounts;
struct bankAccount newAcc;
string first, last;
string tempPin1, tempPin2;
if (!accounts.is_open())
{
accounts.open("accounts.txt", ofstream::app);
}
std::cout << "Thank you for choosing to bank with ATM406!\n\n";
std::cout << "Please enter the name for the account: ";
std::cin >> first >> last;
newAcc.name = first + " " + last;
while (true)
{
std::cout << "\nPlease enter a 4-digit pin for security: ";
std::cin >> tempPin1;
std::cout << "\nPlease re-enter your 4-digit pin for validation: ";
std::cin >> tempPin2;
if (tempPin1 == tempPin2) //PINS MATCH
{
newAcc.pin = tempPin1;
break;
}
else //PINS DO NOT MATCH
{
std::cout << "The pins did not match!" << std::endl;
}
}
//GENERATE A RANDOM 4-DIGIT NUMBER FOR CARDNUM
srand(time(NULL));
newAcc.cardNum = rand() % 9000 + 1000;
//STORE ACCOUNT IN FORMAT: NAME\nCARDNUM\nPIN\nBALANCE
accounts << newAcc.name << "\n" << newAcc.cardNum << "\n"
<< newAcc.pin << "\n" << newAcc.balance << "\n";
accounts.close();
std::cout << "\nAccount created with name: " << newAcc.name << " pin: " << newAcc.pin
<< ". Card number: " << newAcc.cardNum << "\n\n\n";
}
Thank you!

cardNum is a string, but you assign an integer to it. That converts the integer to a char (truncating it to a much smaller value) and stores it in the string.
balance is blank because it's an empty string, you never give the string a value.
N.B. the call to is_open() in createAccount is pointless, the fstream can't be open, because you just default-constructed it.

Related

When I try to use cin in my C++ program, it throws a strange exception

So in the program I'm currently writing, the user is supposed to add people to a vector by inputting their names and partisan identities. However, I have been unable to make the code that actually stores the input work. The program first prompts the user for a name; then, once the user gives a name, it prompts the user again for a partisan identity. Whenever I enter more than one word for the name (e.g. "John Smith"), instead of accepting the input, the program throws this exception.
It also gives this error when I enter "D" or "R" in response to the second prompt, no matter how I respond to the first prompt. Does anyone have an idea what I'm doing wrong here? Here's the code I've written so far:
#include "DelibDem.h"
#include <stdio.h>
#include <vector>
//initializing variables
using namespace std;
bool continue_ = true;
string name = "";
string partyID = "";
int numD = 0;
int numR = 0;
int difference = 0;
int vectorSize = 0;
int newVectorSize = 0;
struct person{
string Name;
string PartyID;
string equivalentName;
string equivalenceClass;
};
vector<person> Sample;
int main()
{
//user adds people to the vector. I have not yet implemented the code that actually adds the people specified by the user yet, because I am still trying
//to figure out why my cin code is not working.
while (continue_ == true) {
string personName;
string personPartyID;
cout << "Enter a person's name: ";
cin >> personName;
cout << "Enter the person's party ID (D or R): ";
cin >> personPartyID;
if (personPartyID == "D") struct person inputtedPerson = { personName, personPartyID, NULL, "Republicans" };
else struct person inputtedPerson = { personName, personPartyID, NULL, "Democrats" };
cout << "Do you wish to add more people? (Y/N) ";
string answer;
cin >> answer;
if (answer == "N") continue_ = false;
}
//The number of Democrats in the sample is stored in numD. The number of Republicans is stored in numR.
for (auto& element : Sample)
{
if (element.PartyID == "D") numD++;
else numR++;
}
//print the number of Democrats and Republicans
cout << numD;
cout << numR;
//print the properties of each element in the sample
for (auto& element : Sample)
{
cout << element.Name << endl;
cout << element.PartyID << endl;
cout << element.equivalentName << endl;
cout << element.equivalenceClass << endl;
cout << "\n";
}
return 0;
}

So I'm having trouble understanding files in C++

I just started learning files and I understand how to set it up and get it to work. I have to write this program where I have to allow the user to enter some information and have the user also update and adjust any data, using binary.
So I can write up until the point where the user can write to and read from the file. But I don't know how to let the user adjust data or add data.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class client {
public:
string name;
int balance;
string id;
};
int main()
{
int ans;
int x;
string nameIn;
string adjName;
client client1;
ofstream out("client1.dat", ios::binary);
cout << "\nDo you want to add information or update info" << endl;
cin >> ans;
if (ans == 1)
{
cout << "\nPlease enter the name of your client" << endl;
cin >> nameIn;
x = nameIn.length();
if (x <= 10)
{
for (int i; i < 10; i++)
{
adjName[i] = nameIn[i];
}
}
else
{
for (int i = x; i < 10; i++)
{
adjName[i] = ' ';
}
}
client1.name = adjName;
cout << "\nPlease enter the balance of your client" << endl;
cin >> client1.balance;
cout << "\nPlease enter the id of your client" << endl;
cin >> client1.id;
cout << "\nThe name of your client is " << endl << client1.name
<< endl << "\nThe balance of your client is " << endl
<< client1.balance << endl << "\nThe id of your client is "
<< endl << client1.id;
out.write(reinterpret_cast<const char*> (&client1), sizeof(client));
}
/*
else if (ans == 2)
{
string answer, newName,line;
cout << "\nWhat name do you want to update? " << endl;
cin >> answer;
cout << "\nWhat is the new name?" << endl;
cin >> newName;
if (out)
}
*/
system("pause");
return 0;
}
so the name needs to be only 10 characters long, so that we can adjust/update it. It compiles and runs, but every time the compiler gets to the part where it checks the name length, it freaks out and says "debug assertion failed"
string subscript out of range.
Also a thing about this code-- if i run it without the bits where you adjust the name to a certain array length, the program runs, and stores everything nicely. But when I try to read back the .dat, it reads it back but exits with an access violation, forcing me to manually stop the debugging. What am I doing wrong?
this is the code for reading the file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class client {
public:
string name;
int balance;
string id;
};
int main()
{
client client1;
char ans;
cout << "\nDo you want to view the information about your client?"
<< endl;
cin >> ans;
ifstream in("client1.dat", ios::binary);
if (ans == 'y' || ans == 'Y')
{
in.read(reinterpret_cast<char*> (&client1), sizeof(client));
cout << "The name is " << endl << client1.name << endl
<< "The balance is " << endl << client1.balance << endl
<< "The id is " << endl << client1.id << endl;
}
system("pause");
return 0;
}
As for the 1st part:
for (int i; i < 10; i++)
// ^
misses to initialize i to zero. Also what if the input was smaller than 10 characters? You're going to access the std::string out of bounds. You should replace the if/else and loops with simply
adjName = nameIn;
while(adjName.length() <= 10) {
adjName += ' ';
}
to get rid of the debug assertion.
For the 2nd part of the question, as already mentioned in the comments you cannot do this with a structure containing classes like std::string.
The reinterpret_cast<char*> (&client1) just obfuscates that std::string uses a pointer to the dynamically allocated character data internally, and that cannot be restored meaningfully when reading the stored data back later (hence the access violation you get).
A viable way might be to use something like
struct client {
char name[11];
int balance;
char id[5];
};
As I guess you need to do this for a homework exercise, and for this purpose that would probably be sufficient.
But you quickly can see the drawbacks, that the character data needs to be fixed in size and you cannot have arbitrary length strings. I never would use such for production ready code.
Another pitfall (as also mentioned) is, that int isn't represented in the same way (order of bytes used, i.e. endianess) in the same way for different CPU architectures. So the binary file can't be used portably with different computers.
The simplest solution is not to use a binary file, but a text formatted file and overload the std::ostream& operator<<(std::ostream&, const client&) and std::istream& operator>>(std::istream&, client&) output/input operators.
Or use some 3rd party library like boost::serialization or google protocol buffers, that supports de-/serialization to binary files.

Calling for function, only returning 0

Alrighty, the goal of what I am trying to do right now is call the function getSingleStudentInfo, which contains the student's number, last name, and age. In the end this program is designed to do two things, the first being the single student info, the second, printing out an array of 20 students. Disregard the second part, as I have not really gotten into that part yet, so ignore anything involving vectors.
The problem that I am having is that in main the first thing that the program will do is ask you to press 1 for the single info or 2 for the full 20 peoples info. The program compiles fine, but what happens is, no matter what number you enter, the program will say "process returned 0 (0x0)" and be done, I'm having a hard time figuring out why it is doing that instead of printing out the single students info, being "student's ID number is 400" "student's last name is: Simmons" "student's age is: 20"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct Student {
int studentNumber = 400;
string lastName = "Simmons";
int age = 20;
};
Student s;
int selection;
vector<int> studentNumber (20);
vector<string> lastName;
vector<int> age (20);
void getSingleStudentInfo (int studentNumber, string lastName, int age) {
cout << "Student's ID number is: ";
cout << s.studentNumber << endl;
cout << "Student's last name is: ";
cout << s.lastName << endl;
cout << "Student's age is: ";
cout << s.age << endl;
return;
};
int main()
{
cout << "Press '1' to see a single student data entry" << endl;
cout << "Press '2' to see all 20 student records" << endl;
cin >> selection;
if (selection == 1) {
getSingleStudentInfo;
};
/*for (vector<int>::size_type i = 0; i <= 20; i++)
{
cout << "Student's ID number is: " << 400 + i << endl;
}
return 0;*/
}
You need to call the function, e.g.
if (selection == 1)
{
getSingleStudentInfo(7, "Johnson", 20);
}
However, it seems like by the implementation, this should be a method off of the student itself
struct Student {
int studentNumber = 400;
string lastName = "Simmons";
int age = 20;
void getSingleStudentInfo() const;
};
Then you'd call it off a Student instance
Student s{400, "Simmons", 20};
s.getSingleStudentInfo();
Then if you had a vector of Student you could do
std::vector<Student> students; // assume this has been populated
std::for_each(begin(students),
end(students),
[](const Student& s){s.getSingleStudentInfo();});
To print in columns, you could change your function to something like
void Student::getSingleStudentInfo()
{
cout << s.studentNumber << '\t'
<< s.lastName << '\t'
<< s.age << endl;
};

Sorting names between a Student class

edit. I want to thank the two people who helped me in my code. I fixed my coding as of 7:22 PM PST 9/25/2014. Still having trouble with the sorting though.
So I'm trying to teach myself how to use C++ in order to get ahead of my programming class in school. I've already taken Java so I'm relatively familiar with the structure of the coding but not exactly sure what to be typing. This practice problem is:
1)Ask the user how many people he wants to enter into the list.
2)Read 3 strings, then turn that info into a student class and put the student inside a vector.
3)Sort the list by name. (Extra credit would be to sort the list by Student ID)
4)Print the info of each student in the list.
5)Ask user while answer is 'Y', search the list for a name and print the info correlating to the name
While in Java, this seems pretty easy, I'm having an extremely hard time understanding what is going on in C++.
I currently only have 1, 2, 4 and 5 done. This is what I have so far.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include <fstream>
#include <iomanip>
using namespace std;
class Student
{
string myName, myStudentID, myClassID;
public:
Student(string name, string studentID, string classID)
{
myName = name;
myStudentID = studentID;
myClassID = classID;
}
string getName() { return myName; }
string getStudentID() { return myStudentID; }
void printInfo() { cout << myName << setw(15) << myStudentID << setw(10) << myClassID << endl; }
};
int main()
{
int num;
std::vector<Student> studentList;
cout << "How many students do you wish to add to the student list ? " << endl;
cin >> num;
cin.ignore();
for (int a = 0; a < num; a++)
{
string inputName, inputStudentID, inputClassID;
//get name
cout << "Please enter the Student name : ";
getline(cin, inputName);
//get student ID
cout << "Please enter the Student ID number : ";
getline(cin, inputStudentID);
//get class ID
cout << "Please enter the Student class ID : ";
getline(cin, inputClassID);
Student thisStudent(inputName, inputStudentID, inputClassID);
studentList.push_back(thisStudent);
cout << endl;
}
//sort(studentList.begin(), studentList.end());
/*
I never figured out how to sort the list by name.
I do not know how to compare the name of studentList[0] and studentList[1]
to put them in alphabetical order.
*/
cout << endl;; // FORMATTING
cout << "The student list has a size of " << studentList.size() << endl;
cout << endl;; // FORMATTING
cout << "Student Name" << setw(15) << "Student ID" << setw(10) << "Class ID" << endl;
for (int a = 0; a < studentList.size(); a++)
{
studentList[a].printInfo();
}
cout << endl;; // FORMATTING
string searchedName;
char answer;
do
{
cout << endl;; // FORMATTING
cout << "Please type the name of the person you want to search for: ";
getline(cin, searchedName);
for (int a = 0; a < studentList.size(); a++)
{
if (searchedName.compare(studentList[a].getName()) == 0)
{
studentList[a].printInfo();
break;
}
else
if (a == (studentList.size() - 1)) //If went to end of the list, tell them name not found.
cout << "There is no " << searchedName << " in the list. \n";
}
cout << "Would you like to search for another person? \n";
cout << "Y for Yes, N for No. \n";
cin >> answer;
cin.ignore();
} while (answer == 'Y' || answer == 'y');
return 0;
}
You could create a static compare function in class Student to use with std::sort
class Student
{
string myName, myStudentID, myClassID;
// ...
static bool compare_name(const Student & lStudent, const Student & rStudent)
{return (lStudent.myName < rStudent.myName);}
};
// ...
std::sort(studentList.begin(), studentList.end(), Student::compare_name);
or if your compiler supports lambda functions:
std::sort(studentList.begin(), studentList.end(),
[studentList](const Student & lStudent, const Student & rStudent)
{return (lStudent.myName < rStudent.myName);});

how to read from a binary file and search for a record

I am trying to read from a file and search a particular record based on the employee number entered. I have written the code but every time i search for a record which is already present i am getting the message record not found. Can anyone please point out the error.
My code is:
#include <iostream>
#include <fstream>
using namespace std;
class emp
{
int empno;
char name[20];
char dept[10];
float salary;
public:
void getdata()
{
cout << "Enter the employee number " << endl;
cin >> empno;
cout << "Enter the name : " << endl;
cin >> name;
cout << "Enter the department of the employee : " << endl;
cin >> dept;
cout << "Enter the salary of the employee : " <<endl;
cin >> salary;
}
void display()
{
cout << "Emp No : " <<empno;
cout << endl << "Name : " << name << endl << "Department : " <<dept <<endl
<<"Salary : " << salary <<endl;
}
int getempno()
{
return empno;
}
};
int main()
{
emp obj1;
int eno;
char ch = 'n';
ifstream file1("emp.txt", ios:: in); // this file should already exist
cout << "Enter the employee number to be searched for : " <<endl;
cin >> eno;
while(!file1.eof())
{
file1.read((char *)&obj1, sizeof(obj1));
if(obj1.getempno()==eno)
{
obj1.display();
ch = 'y';
break;
}
}
if(ch =='n')
cout << "Record Not Found !!" << endl;
file1.close();
}
I am using a variable eno in my main function and comparing the eno to the empno returned from the function getempno. If it is equal i am calling the member function display but the display function is not working. I am only getting the message record not found.
Open the stream as binary as said in the title:
ifstream file1("emp.txt", ios:: in | ios::binary); // binary
and also change your loop in order to not test on eof() without having read first:
while (file1.read((char *)&obj1, sizeof(obj1)))
I could test successfully this updated code, by producing a quick and dirty binary file, written with ios::binary set (I don't put the constructor code here):
void produceTest(string file) {
ofstream os(file, ios::out | ios::binary);
emp a(1, "Durand", "IT", 1234.30);
emp b(2, "Dupond", "Finance", 1530.20);
emp c(25, "Chris", "MD", 15.30);
os.write(reinterpret_cast<char*>(&a), sizeof(emp));
os.write(reinterpret_cast<char*>(&b), sizeof(emp));
os.write(reinterpret_cast<char*>(&c), sizeof(emp));
}
If it doesn't work, the problem is with your file. Potential issues could for example be:
the file was written without ios::binary, producting alteration of the structure (ignoring 0, on windows tranforming binary bytes 0x0A into binary 0x0D + binary 0x0A)
the file was written on a system with a different int encoding (big endian vs.little endian
the file was written with a leading unicode BOM
the encoding of the file is not as you thought.