#include<fstream>
#include<iostream>
using namespace std;
class employee
{
char *name;
int age;
string designation; // string data type is used
float salary;
public:
void getdata();
void display();
};
void employee::getdata() // for taking the input
{
cout<<"\nENTER THE NAME OF THE EMPLOYEE: ";
gets(name); /*name is a char pointer */
cout<<"\nENTER THE AGE OF THE EMPLOYEE: ";
cin>>age;
cout<<"\nENTER THE DESIGNATION OF THE EMPLOYEE: ";
getline(cin,designation); /*designation is string data type*/
cout<<"\nENTER THE SALARY OF THE EMPLOYEE: ";
cin>>salary;
}
void employee::display()//for displaying the inputed data
{
cout<<"\nTHE NAME OF THE EMPLOYEE: ";
puts(name);
cout<<"\nENTER THE AGE OF THE EMPLOYEE: ";
cout<<age;
cout<<"\nENTER THE DESIGNATION OF THE EMPLOYEE: ";
cout<<designation;
cout<<"ENTER THE SALARY OF THE EMPLOYEE: ";
cout<<salary;
}
int main()
{
ofstream fout;
char ch;
fout.open("employee.txt",ios::out|ios::binary);/*use of open function in file handing*/
employee e;
for(int i=0;i<3;i++)
{
e.getdata();
fout.write((char*)&e,sizeof(e));//write() is used
}
fout.close();
ifstream fin;
fin.open("employee.txt",ios::in|ios::binary);
int j;
cout<<"\n Enter the employee no. to be read ";
cin>>j;
fin.seekg((j-1)*sizeof(e));
fin.read((char*)&e,sizeof(e));
cout<<"\n Details of employee no. of object is = ";
e.display();
return 0;
}
I am not able to identify the error in my code...I had cross checked the code...there is no syntax error and no compiler error but the output is not correct...it is not taking the proper input from the user.
As Bo Persson said, your program does not provide any memory for name and designation. You declare pointers like name in your class alright, but they do not point to anything. You could just declare e.g. name as char name[100]; and hope that 100 is enough (and, in production code, add checks to ensure it isn't exceeded).
But in C++ there is the string class which frees you of many worries. In particular, it makes input of arbitrarily long strings easy. If the string can't have whitespace in it, a simple string s; cin >> s; reads a "word" from the input into the string. If it can have whitespace, you need some way to tell where it starts and ends. Databases, Excel etc. often use quotes to surround a string. If it cannot contain newlines, ensuring that it is on a line of its own is sufficient and obviates the need for parsing. That's what we'll do here.
The second issue you faced is what's technically called "serialization". You want to store ("persist") your class on disk and later (much later, perhaps) re-read it into a new instance. Nathan Oliver pointed you to a resource which discusses serialization. For a simple class like employee with a limited number of simple data members we can simply roll our own ad-hoc serialization: We write everything to disk with operator<<(), and read everything back with operator>>().
The main thing to consider is that strings may have whitespace, so that we'll put them on a line of their own.
An addition is that in order to be more robust when reading from a file we start each employee with a start marker (header in the code below). This way reading an employee will work from any position in the file. Also, if later employees should have more fields we can still read our basic employee data and just skip the additional fields before we read the next employee in a sequence of employees on disk.
streams are closed automatically when they are destroyed at the end of their scope; we use block scope for that (check the additional {} in the code).
A plain float is not precise enough for higher salaries (it only has about 7 decimal digits, so that for salaries > 167772.16 (if I can believe Wikipedia) in whatever currency the pennies start to fall off the cliff). I use long double and make sure to not lose precision when converting it to text.
You didn't compare reals but I did in order to check whether I read the employee back correctly. Care must be taken there. I wiggle out of the gory details by comparing half pennies which should be appropriate for money.
Here is the whole program. (Compared with my previous version I have simplified the (de)serialization, in particular I have eliminated the useless tags.)
It would be wise to perform error checking after each read/write in order to make sure it succeeded; remember, a stream coverts to bool, so a simple if(!os) { cerr << "oops" << endl; /* exit? */} is enough; but I didn't want to distract from the actual program too much.
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <cfloat> // for LDBL_DIG in ostream precision.
#include <cstdlib> // for exit()
using namespace std;
/** A simple class holding employee information */
class employee
{
public:
/** This header starts each
"serialization" of an employee on a line
of its own. */
static constexpr const char *header = "--- Employee ---";
// use C++ std::string
string name;
int age;
// use C++ std::string
string designation;
// Be as precise as possible,
// for later uses like salary increases
// by 4.5% or so :-)
// The salary is in units like USD or EUR.
// The fraction part is pennies, and fractions of them.
long double salary;
public:
void readdata(istream &is);
void writedata(ostream &os);
void display();
bool operator==(employee &rhs)
{ return
name == rhs.name
&& age == rhs.age
&& designation == rhs.designation
// Do not compare floats directly.
// We compare pannies, leaving slack for rounding.
// If two salaries round to the same penny value,
// i.e. 0.01, they are equal for us.
// (This may not be correct, for an accounting app,
// but will do here.)
&& salary - rhs.salary < 0.005
&& rhs.salary - salary < 0.005;
}
};
/** Write a header and then
each data member in declaration order, converted to text,
to the given stream. The header is used to find the start
of the next employee; that way we can have comments or other
information in the file between employees.
The conversion is left to operator<<.
Each member is written to a line of its own, so that we
can store whitespace in them if applicable.
The result is intended to be readable by #readdata().
*/
void employee::writedata(ostream &os)
{
os.precision(LDBL_DIG); // do not round the long double when printing
// make sure to start on a new line....
os << endl
// ... write the header on a single line ...
<< header << endl
// ... and then the data members.
<< name << endl
<< age << endl
<< designation << endl
<< salary << endl;
}
/**
Read an amployee back which was written with #writedata().
We first skip lines until we hit a header line,
because that's how an employee record starts.
Then we read normal data mambers with operator>>.
(Strictly spoken, they do not have to be on lines
of thier own.)
Strings are always on a line of their own,
so we remove a newline first.
*/
void employee::readdata(istream &is)
{
string buf;
while(getline(is, buf)) // stream converts to bool; true is "ok"
{
if( buf == header) break; // wait for start of employee
}
if( buf != header )
{
cerr << "Error: Didn't find employee" << endl;
return;
}
getline(is, name); // eats newline, too
is >> age; // does not eat newline:
// therefore skip all up to and including the next newline
is.ignore(1000, '\n');
// line on its own, skips newline
getline(is, designation);
is >> salary;
}
int main()
{
const char *const fname = "emp.txt";
employee empa;
empa.name = "Peter A. Schneider";
empa.age = 42;
empa.designation = "Bicycle Repair Man";
empa.salary = 12345.67;
employee empb;
empb.name = "Peter B. Schneider";
empb.age = 43;
empb.designation = "Bicycle Repair Woman";
empb.salary = 123456.78;
{
ofstream os(fname);
if(!os)
{
cerr << "Couldn't open "
<< fname << " for writing, aborting" << endl;
exit(1);
}
empa.writedata(os);
cout << "Employee dump:" << endl;
empa.writedata(cout);
// insert a few funny non-employee lines
os << endl << "djasdlköjsdj" << endl << endl;
empb.writedata(os);
cout << "Employee dump:" << endl;
empb.writedata(cout);
}
// show the file contents
{
ifstream is(fname);
if(!is)
{
cerr << "Couldn't open "
<< fname << " for reading, aborting" << endl;
exit(1);
}
string line;
cout << "-------------- File: -------------" << endl;
while(getline(is, line)) cout << line << endl;
cout << "---------------End file ----------" << endl;
}
/////////////////////////////////////////////////////////
{
ifstream is(fname); // read from the file "emp.txt" just written
if(!is)
{
cerr << "Couldn't open "
<< fname << " for reading, aborting" << endl;
exit(1);
}
{
employee emp2; // new employee, sure to be empty
cout << endl << "Re-reading an employee..." << endl;
emp2.readdata(is);
cout << endl << "Re-read employee dump:" << endl;
emp2.writedata(cout);
cout << "Original and written/read employee are "
<< (empa == emp2 ? "" : "NOT ") << "equal" << endl;
}
{
employee emp2; // new employee, sure to be empty
// now read next employee from same stream.
// readdata() should skip garbage until the header is found.
cout << endl << "Re-reading an employee..." << endl;
emp2.readdata(is);
cout << endl << "Re-read employee dump:" << endl;
emp2.writedata(cout);
cout << "Original and written/read employee are "
<< (empb == emp2 ? "" : "NOT ") << "equal" << endl;
}
}
}
Sample session:
Employee dump:
--- Employee ---
Peter A. Schneider
42
Bicycle Repair Man
12345.6700000000001
Employee dump:
--- Employee ---
Peter B. Schneider
43
Bicycle Repair Woman
123456.779999999999
-------------- File: -------------
--- Employee ---
Peter A. Schneider
42
Bicycle Repair Man
12345.6700000000001
djasdlköjsdj
--- Employee ---
Peter B. Schneider
43
Bicycle Repair Woman
123456.779999999999
---------------End file ----------
Re-reading an employee...
Re-read employee dump:
--- Employee ---
Peter A. Schneider
42
Bicycle Repair Man
12345.6700000000001
Original and written/read employee are equal
Re-reading an employee...
Re-read employee dump:
--- Employee ---
Peter B. Schneider
43
Bicycle Repair Woman
123456.779999999999
Original and written/read employee are equal
In addition to what the comments say about gets being dangerous, you immediately run into that buffer overflow by not allocating any space for name. Just having a pointer is not enough.
In addition to that, mixing cin >> and getline(cin,...) is known to skip input, because the two functions handle end-of-line differently.
Then we have the problem of doing binary I/O for the employee type. In general, you cannot do that for class types that are non-trivial. Specifically, the std::string designation member internally holds a pointer to some data. That pointer will not survive the transfer to disk and back.
Related
While creating a simple stock management system, I encountered some problem after adding a new item in the list. My code will explain better.
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std; // For sake of speed
class INVENTORY
{
char name[10];
int code;
float cost;
public:
void setData();
void getData();
};
void INVENTORY ::setData()
{
std::cout << "Enter Name: ";
std::cin.getline(name, 10);
std::cout << "Enter Code: ";
std::cin >> code;
std::cout << "Enter Cost: ";
std::cin >> cost;
}
void INVENTORY::getData()
{
cout << setiosflags(ios::left) << setw(10) << name << setw(10) << code << setw(5) << cost << '\n';
}
int main()
{
INVENTORY item;
fstream inoutfile;
inoutfile.open("STOCK.DAT", ios::ate | ios::in | ios::out | ios::binary);
inoutfile.seekg(0, ios::beg); // go to beginning.
cout << "CURRENT CONTENTS OF STOCK" << '\n';
while (inoutfile.read((char *)&item, sizeof(item)))
{
item.getData();
}
inoutfile.clear(); // clears the eof state flag.
cout<<'\n'<<inoutfile.good()<<'\n';
/* ADD more items */
cout << "\nAdd an item: \n";
item.setData();
char ch;
cin.get(ch);
inoutfile.write((char *)&item, sizeof(item));
cout<<'\n'<<inoutfile.good()<<'\n';
// Display the appended file
inoutfile.seekg(0);
cout << "CONTENTS OF APPENDED FILE\n";
while (inoutfile.read((char *)&item, sizeof(item)))
{
item.getData();
}
cout<<'\n'<<inoutfile.good()<<'\n';
// Find the number of objects in the file.
int last = inoutfile.tellg();
int n = last / sizeof(item);
cout << "Number of Objects: " << n << endl;
cout << "Total bytes in file: " << last << endl;
/* Modify the details of an item */
cout << "Enter object number to be updated: ";
int object;
cin >> object;
cin.get(ch);
int location = (object - 1) * sizeof(item);
if (inoutfile.eof())
{
inoutfile.clear();
}
inoutfile.seekp(location);
cout << "Enter the new values of objects \n";
item.setData();
cin.get(ch);
inoutfile.write((char *)&item, sizeof item) << flush;
/* SHOW UPDATED FILE */
cout << "Contents of updated file: \n";
while (inoutfile.read((char *)&item, sizeof item))
{
item.getData();
}
inoutfile.close();
return 0;
}
I reused the class from some file, please don't sue me for using namespace std I don't use it usually, but used today for sake of speed.
The 3rd cout<<'\n'<<inoutfile.good()<<'\n'; returns false and I am not able to figure out why this happens. I already have the file STOCK.DAT and there is data already present in it (of the same type). The relevant output:
CURRENT CONTENTS OF STOCK
Apple 5 50
Banana 6 80
1
Add an item:
Enter Name: Pineapple
Enter Code: 8
Enter Cost: 150
1
CONTENTS OF APPENDED FILE
Apple 5 50
Banana 6 80
Pineapple 8 150
0 // something is not good here but what?
Number of Objects: -858993460
Total bytes in file: -1
There are more elements in output but I showed you the relevant output, tellg returns false, so there is definitely something wrong and I can't figure it out.
I will explain what is happening over here:
I made a class named INVENTORY and made a few members and member functions in it.
Then in the main function, I made a fstream object and opened a file named STOCK.DAT, with a few additional flags.
Then I point the get pointer to the beginning (both pointers move together for a fstream object).
The file is in binary so I print out what's already present in the file.
Then I use clear() to remove eof flag and check whether everything is right, which will result true here.
Then I add another item to the end of file and check whether everything is good, true over here also.
Then I set the get pointer to beginning to print all the data in the file again and now everything is not good and I am not able to figure it out.
I found a solution. After reaching eof if you try to do inoutfile.tellg() it will return -1. Instead use inoutfile.clear() to clear the eof tag and then use inoutfile.tellg().
I have to do the following tasks:
Read information about individual persons in file person.txt (see below) and store to array p. Set the spouse pointer for each person to NULL value first.
Perform marry operation for Mary and Tom. You can marry two people by setting their spouse pointer to point to each other (store address of one another).
Print out the content in array p where you need to print every person variable pointed by array p. If a person spouse pointer is a NULL value, then print Not Married, else print the spouse name. The output of the program is shown below. Make sure your output is the same.
I can do (1), read the text file person.txt, which has the following content:
Mary 012-35678905 20000
John 010-87630221 16000
Alice 012-90028765 9000
Tom 019-76239028 30000
Pam 017-32237609 32000
But I don't know how to do (2) and (3).
This is what I have done so far, based on the template provided with the question and that I'm not supposed to change:
#include <iostream> //>>>>>>> This part is the template given >>>>>>>
#include <cstdlib> //
#include <fstream> //
//
using namespace std; //
//
struct person //
{ //
char name[30]; //
char phone[15]; //
double money; //
person *spouse; //
}; //
//
int main() //
{ //
person *p[10]; //<<<<<<<< This is the end of the template part <<<
ifstream inFile;
inFile.open("person.txt");
if (inFile.fail())
{
cout << "Error in opening the file!" << endl;
exit(1);
}
char name[30], phone[15];
int money;
int number = 5;
for (int i = 0; i < number; i++)
{
inFile >> name >> phone >> money;
cout << "Name:" << name << endl;
cout << "Phone:" << phone << endl;
cout << "Money:" << money << endl;
cout << "Spouse Name:" << endl;
cout << endl;
}
cin.get();
system("pause");
return 0;
}
The expected output should be like this:
Name: Mary
Phone Number:012-35678905
Money: 20000
Spouse Name:Tom
Name: John
Phone Number:010-87630221
Money: 16000
Spouse Name: Not Married
...
Be aware that this exercise shows outdated use of C++
First to your array p that you somewhat forgot to use. p[10] is an array of 10. But of 10 what ? of person*, so of pointers to persons.
This is very old-fashioned C++. If you follow a course on internet, change immediately, because nowadays, we'd use vector<person>, string and nullptr. If it's a class course, you have no choice, so let's go on...
Some hints, based on what you have already done
First simplify the reading loop and don't forget to set the pointer to NULL as requested in the question:
for (int i = 0; i < number; i++)
{
person *r = new person; // allocate a new person
inFile >> r->name >> r->phone >> r->money; // read data into the new person
r->spouse = NULL; // initialize the poitner
p[i] = r; // store the pointer in the array
}
You already almost have the printing part(3). You just have to move it from your reading loop to a new loop, print from the array, and tackle the special case of married people:
for (int i = 0; i < number; i++)
{
cout << "Name:" << p[i]->name << endl;
cout << "Phone:" << p[i]->phone << endl;
cout << "Money:" << p[i]->money << endl;
cout << "Spouse:" ;
if (p[i]->spouse==NULL) {
cout << "Not married" <<endl;
}
else {
cout << p[i]->spouse->name <<endl;
}
cout << endl;
}
Now something to do on your own
Now about marrying Marry and Tom in (2). This is more delicate. I will not do it for you, because now you have all you need to finish homework. But the general principle is:
Create two pointers spouse1 and spouse2 and initialize them to NULL.
Loop through the array to find which person is Tom and which one is Marry, and update the relevant pointer (e.g. spouse1 = p[i]; )
At the end of the loop, check that we have found both spouses (both pointers are not NULL anymore, and both pointers are different, because you cannot marry someone with hi/her-self)
If it's ok, then just marry them: spouse1->spouse=spouse2; spouse2->spouse=spouse1;
Finally, before you end the programme, you need to deallocate all the pointers in the array (with vectors, you wouldn't have to care about this).
Further improvements needed
You still need to improve your reading loop, to make it more dynamic. Because in reality, you don't know how many lines are in the text file. So start with number=0 and read data as long as possible, incrementing number each time, but stoping if not possible to read anymore, or if the maximum size of the array is reached.
Disclaimer: I am a beginner to programming, so what I say might sound really stupid
I have to make a "Telephone Directory" for school. The program isn't complete, but there are some things that I need to fix before moving on. The array TelephoneNumbers either isn't storing the numbers from the file correctly, or isn't displaying them. For the SeaerchRecords function, the first number in the file is displayed correctly, the second is displayed as "2147483647," and the rest of the numbers display as "0." The modify function also doesn't change the number, and I confirmed this with the while in the function. The string array works perfectly fine, however. May someone explain what I'm doing incorrectly?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string TelephoneNames[100];
int TelephoneNumbers[100];
void ModifyRecords(); //Function to Modify Records
void SearchRecords(); //Function to Search Records
void DeleteRecords(); //Function to Delete Records
int main()
{
fstream inputFile;
fstream outputFile;
char choice;
inputFile.open("Telephone Names.txt"); //To store
for (int count=0;count<100;count++) //file names
{ //into a
inputFile >> TelephoneNames[count]; //string
}
inputFile.close();
inputFile.open("Telephone Numbers.txt");//To store
for (int count=0;count<100;count++) //file #'s
{ //into a
inputFile >> TelephoneNumbers[count];//string
}
inputFile.close();
//Display options available
cout << " Hello, do you want to:\n";
cout << " ======================\n";
cout << "-Modify Records|Enter M\n";
cout << "-Search Records|Enter S\n";
cout << "-Delete Records|Enter D\n";
//Store choice
cin >> choice;
//Send to different function
if (choice=='M'||choice=='m')
{
ModifyRecords();
}
if (choice=='S'||choice=='s')
{
SearchRecords();
}
return 0;
}
void ModifyRecords()
{
string name;
string newname;
int newnumber;
int count=0;
cout << "Enter the name of the person: ";
cin >> name;
for (count=0;TelephoneNames[count]!=name;count++)//To determine where in the strings the new numbers need to be
{
}
cout << "Enter the new name of the person: ";
cin >> newname;
cout << "Enter the new number of the person: ";
cin >> newnumber;
TelephoneNames[count]={newname};
TelephoneNumbers[count]={newnumber};
count=0;
while (count<6)
{
cout << TelephoneNames[count] << endl;
cout << TelephoneNumbers[count] << endl;
cout << endl;
count++;
}
}
void SearchRecords()
{
string name;
int count=0;
cout << "Enter the name of the person you would like to find: ";
cin >> name;
for (count=0;TelephoneNames[count]!=name;count++)//To determine where in the strings the new numbers need to be
{
}
cout << "Name: " << TelephoneNames[count] << endl;
cout << "Number: " << TelephoneNumbers[count] << endl;
}
Since there is no any answer still and I don't see exactly the problem at this point I'll provide some suggestions how you can find a problem in your code.
In any programming situation when you can't find a bug, first task is to locate it as much precisely as you can and check all input data and assumptions. Usually, debugger is used for such purposes, but you can just output text in console before creating final version of your program.
To start with, you must check that you really received names and telephones from your file:
inputFile.open("Telephone Names.txt"); //To store
for (int count=0;count<100;count++) //file names
{ //into a
inputFile >> TelephoneNames[count]; //string
cout << TelephoneNames[count] << endl; //WE MUST SEE WHAT IS REALLY STORED IN TelephoneNames
}
inputFile.close();
inputFile.open("Telephone Numbers.txt");//To store
for (int count=0;count<100;count++) //file #'s
{ //into a
inputFile >> TelephoneNumbers[count];//string
cout << TelephoneNumbers[count] << endl; //WE MUST SEE WHAT IS REALLY STORED IN TelephoneNumbers
}
inputFile.close();
Ok, when it is checked and you are defenitely sure there is no problem in your data we can move to SeaerchRecords function doing the same procedure. We must check what is happening while you are searching:
for (count=0;TelephoneNames[count]!=name;count++)//To determine where in the strings the new numbers need to be
{
cout << "Search step: " << count << " name " << name << " found name " << TelephoneNames[count] << " number " << TelephoneNumbers[count] << endl;
}
Doing so you will locate your bug rather quickly. The problem can be in input files format, in difference of "name" and stored names format etc.
I'll provide several additional suggestion how you can improve your code.
1) Try to use const declarations for such commonly used things as number of records (const int NUMBER_OF_RECORDS = 100; insted of just putting '100' everywhere), it will reduce the amout of work and possible bugs. 2) Try to check all possible problems that you program can encounter if someting is wrong with data. What will happen if you have less than 100 records in your files now? Program crush or silent reading of unappropriate data which is even worse. Check that you haven't reach file end on any step of reading along with current check that you've reached you number of records and do something in case of unappropriate data.
3) Check the possible problems with conditions in your cycles not to run them infinite number of times. Now your condition for(count=0;TelephoneNames[count]!=name;count++)
will execute forever if there is no such name or just crush the program on count 100 or more. You should check that count doesn't exceed that value. Good luck!
How do I set up a loop to read in file data until eof is reached?
Basically, I have a data file with student data, and for each student there is quiz grades, test grades, lab grades, etc.
I have a function that gives the values as letter grades.
My issue is to set up the loop to compute each function 4 times for each student. My loop code so far uses a counter loop, but I'm supposed to turn it into an eof loop instead.
My code below ends when there is no more data to read.
int main()
{
int counters = 1;
char lab;
char assgniment_score;
char quiz_score;
char test_score;
float final_total_average;
myfile.open("infile.txt");
while (counters <= 20) {
lab = Compute_lab_grade();
assgniment_score = Compute_Assignment_grade();
quiz_score = Compute_Quiz_grade();
test_score = Compute_test_grade();
final_total_average = (10 * (total(quiz_score))
+ (25 * (total(assgniment_score)))
+ (30 * (total(lab))) + (35 * total(test_score))) / 100;
cout << "Student " << counters << endl;
cout << "Student Lab grade is : " << lab << endl;
cout << "Student Assignment grade is : " << assgniment_score << endl;
cout << "Student Quiz grade is : " << quiz_score << endl;
cout << "Student Exam grade is : " << test_score << endl;
cout << "Student Final grade is : " << final_average_score(final_total_average) << endl << endl;
counters++;
}
}
The structure of the given data looks like this:
Rational for answer: OP is headed in many wrong directions all at once and I think a few of them can be headed off with one good example.
Problem 1: EOF loop is a myth. Read more here: Why is iostream::eof inside a loop condition considered wrong?
Problem 2: using char to represent numbers. Technically char is an integer type, but it is most commonly associated with a single character and its input/output routines are overloaded accordingly. Eg. if given input "1234" std::cin >> a_char; will result in char a_char containing the character '1', but std::cin >> an_int; will result in int an_int containing the the number 1234. In addition using a character to represent a number can often lead to confusion for thew reader who may misinterpret what your code is supposed to do. You can do it and sometimes it is the appropriate choice, but this time it doesn't make much sense.
Problem 3 Scattershot and unchecked IO. It's generally best to read in everything you want and then, if the input is good, make a decision on all of it all at once. If a student's record is not complete without 27 integers, read all 27 integers and check that each and every one read correctly. If you can't read them all, that's an error. If some are not integers, that's an error. If you have an error, the student is not a valid input and should either be discarded or investigated more closely.
Problem 4: Not using a data structure to contain associated data. A student is represented by a bunch of information. It is convenient to package that information with the methods by which the information can be accessed and manipulated. Read up on encapsulation.
Minor nag: Why is "using namespace std" considered bad practice?
So here we go:
#include <iostream>
#include <fstream>
#include <sstream>
// using namespace std; avoid using this. Can be very dangerous to the unwary.
// container class to aggregate student stats and provide manipulators to read
// and display a student
class Student
{
static int count; // only the students use the counter. No need for it to be global.
int student_number;
// int telegraphs your intent much better than char
// These variables are numbers, not characters and should be treated like them
int lab;
int assgniment_score;
int quiz_score;
int test_score;
float final_total_average;
public:
// simple input function. This is a bit too simple for OP, but should be
// enough for OP to get the idea.
friend std::istream & operator>>(std::istream & in, Student & student)
{
std::string line;
student.student_number = count ++;
if (std::getline(in, line))
{
std::stringstream stream(line);
if (stream >> student.lab
>> student.assgniment_score
>> student.quiz_score
>> student.test_score)
{ // if we read all the variables we needed
// divided by 4.0 because division of int by int will
// give an int, not a float.
student.final_total_average = (student.lab +
student.assgniment_score +
student.quiz_score +
student.test_score) / 4.0;
}
else
{ // failed to read. Mark stream bad.
in.setstate(std::istream::failbit);
}
}
return in;
}
// simple output function OP shouldn't have to change much here.
friend std::ostream & operator<<(std::ostream & out, Student & student)
{
//endl is line feed and IO flush very expensive, so use only
// when you absolutely need to flush the stream. This turns out to be
// almost enver.
out << "Student " << student.student_number << '\n'
<< "Student Lab grade is : " << student.lab << '\n'
<< "Student Assignment grade is : " << student.assgniment_score << '\n'
<< "Student Quiz grade is : " << student.quiz_score << '\n'
<< "Student Exam grade is : " << student.test_score << '\n'
<< "Student Final grade is : " << student.final_total_average << '\n';
return out;
}
};
// allocate storage for student counter
int Student::count = 1;
int main()
{
// create and open file. As with the counter, no need for it to be global
// because it can easily be passed by reference into functions that need it.
std::ifstream myfile("infile.txt");
Student student; // allocate a dummy student to read into and print
// because we have smart rules for reading in a student, this is easy.
while (myfile >> student) // read students until error or end of file
{
std::cout << student; // write the current student
}
}
I'm writing a file matching program for a project for school. The idea is that one program allows you to enter info as follows: 1000 (acct number) Jane Doe 54.50 (balance). Then allow you to enter the account number and a transaction amount for the second program to combine and update a new master file.
The programs are working together just fine (the second one takes information from the first, including any transactions and updates the new balance - searching by account number) but the problem I am running into is with the name.
---Wasn't clear here. When I ask for a name and I put in a single string of characters, the program works fine, if I try to put in a full name, like Jane Doe I go into the loop mentioned below.
I've tried char name[20] which puts me into an infinite loop and I have to 'x' out of the program and I've tried assigning first and lastName to string. That worked for the writing but the program that takes the input file oldMaster and the transaction file inTransaction then outputs a new file newMaster, doesn't recognize the name.
I've tried getline also which isn't working for me, probably programmer error.
Should this be done as an array, if that's possible for this? I think I'm getting hung up on the fact that I am editing files. Answers are fine - but I like to figure it out on my own, just looking for a little guidance on where to go from here.
Hopefully this was fairly clear - if not I'll be happy to explain again in a different way. Just frustrated that I'm this close and can't solve it.
Thanks in advance!
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
using namespace std;
void createOldMaster()
{
ofstream oldMaster;
int accountNum;
double balance;
char name[15];
oldMaster.open("oldmast.dat", ios::out);
if(!oldMaster)
{
cout << "Unable to open the file." << endl;
exit(1);
} // end if
cout << "Enter the account number (0 to exit)." << endl;
while(true)
{
cout << "Account Number: ";
cin >> accountNum;
if(accountNum == 0)
break;
else
{
\\ This is where it hangs up if I use a first and last name
cout << "\nName: ";
cin >> name;
cout << "\nBalance : " << endl;
cin >> balance;
oldMaster << accountNum << " " << name << " " << balance << endl;
}
}
} //end createOldMaster
void createTransaction()
{
ofstream inTransaction;
int accountNum;
double balance;
inTransaction.open("trans.dat");
if(!inTransaction)
{
cout << "Unable to open the transaction file." << endl;
exit(1);
}
cout << "Enter the account number and balance (0 to exit): " << endl;
while(true)
{
cout << "Account Number: " << endl;
cin >> accountNum;
if(accountNum == 0)
break;
else
{
cout << "Balance: " << endl;
cin >> balance;
inTransaction << accountNum << " " << balance << endl;
}
}
} //end createTransaction
int main()
{
createOldMaster();
createTransaction();
return 0;
}
Your best bet is to use as much of the standard C++ library as you can. Have a reference handy, maybe even a copy of the C++ standard if you're so inclined, and look for shortcuts to make your work easier and your code shorter.
Avoid primitive arrays and primitive strings wherever possible. Instead of primitive arrays try to use std::vector. Instead of primitive strings try to use std::string. Instead of C's FILE* try to use std::ofstream and std::ifstream. If you need to prohibit two accounts with the same account number then choose a C++ container that guarantees unique elements. If you need to find an element in a container try to use a member function of the container for the search, and if that doesn't exist then a standard search function from the standard C++ algorithms.
Reuse and steal mercilessly.