Hey folks. I am working on a program (really its 2, but they go hand in hand). The first one takes a text file which contains the following:

last name
first name
SSN
Salary
Years employed

There are 7 entries in the text file to be read in...
The program will then read one persons information at a time - storing the information into structures (at least thats what im assuming so far...it works, mostly).

The 2nd part of program is to then take the structure and write it out to a file called employees - sorted through one employee at a time from the text file until a new datafile is created full of these structs.

The 2nd program is to read this new data file called employees and then make an array of a struct and then print out the information for each employee.

For example:
Last: James First: Henry ID: 123456789
Salary: 12000 Years employed: 7
(this will be in a function outside of main)

Then another function that will sort through all the employees in the data file until none are left and print just like above...but for all employees.

My problem is that for whatever reason - the first name is not read into file in the 2nd program (i looked at the employees data file and i see the first persons name - so it SHOULD be read into the 2nd program) all i get is employee 2 to 7. So 6 prints and then an empty 7th like:

Last: First: ID:
Salary: Years Emp:

So obviously the first one isnt being read in correctly.

Here is my first program (which reads from a text file then writes out to another file called employees using the structures it created)

#include <iostream>
#include <fstream>
#include <ostream>
#include <string>

using namespace std;

//Structure 
struct Employee
  {
  char last_name[39];
  char first_name[39];
  char ss_num[10];
  double salary;
  int years_employed;
  };
  
//Function Prototypes

//Main function
int main()
{
  Employee personInfo;
  string end_of_file = "eof";
   
  ifstream inFile;
  ofstream outFile;
  
  inFile.open("empinfo.txt");
  outFile.open("employees", ios::binary);
  
  if (inFile.fail())
    {
    cout << "Unable to open empinfo.txt file\n";
    exit(1);
    }
   
   //Start read of data from file 
   inFile >> personInfo.last_name;
   while (personInfo.last_name != end_of_file)
     {
     inFile >> personInfo.first_name;
     inFile >> personInfo.ss_num;
     inFile >> personInfo.salary;
     inFile >> personInfo.years_employed;
     
     // Writes out to employees file
     outFile.write((char *)&personInfo, sizeof(Employee));  
     
     //Restart over from next user in file
     inFile >> personInfo.last_name;     
     }
     
inFile.close(); 
outFile.close();
system("PAUSE"); 
return 0;
}

NOTE : the end_of_file line in the above if is used because there is a line at the end of the text file that says 'eof'. So i am testing for this string, not to see if there nothing left at the end of the text file like you would with eof(). This is why i used this vs the alternative regular way.

My 2nd program looks like:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <ostream>
#include <string>

using namespace std;

//Structure 
struct Employee
  {
  char last_name[39];
  char first_name[39];
  char ss_num[10];
  double salary;
  int years_employed;
  };
  
//Function Prototypes
void displayEmployee(Employee);
void displayAllEmployees(Employee [], int);
void sortByName(Employee [], int);

//Main function
int main()
{
  Employee personInfo[100];
  string end_of_file = "eof";
   
  ifstream inFile;
  inFile.open("employees", ios::in | ios::binary);
  if (inFile.fail())
    {
    cout << "Unable to open employees file\n";
    exit(1);
    }
    
   int i = 0;
   inFile.read((char *)&personInfo[i], sizeof(Employee));
   while (inFile)
         {
         inFile.read((char *)&personInfo[i], sizeof(Employee));
         i++;
         } 
inFile.close();     

cout << "personInfo[0].lastname should be: " << endl;
cout << personInfo[0].salary << endl;

/*
cout << "Displays ONE persons information!" << endl;
displayEmployee(*personInfo);  
cout << "\nDisplays ALL persons information!" << endl;
displayAllEmployees(personInfo, i);   
*/
system("PAUSE"); 
return 0;
}
  
/****************************************************************************
Function:  displayEmployee()
Use: displays one employee from the struct
Arguments: employee struct 
Returns: nothing
*****************************************************************************/ 
void displayEmployee(Employee emp)
{
cout << left;
cout << "Last:   " << setw(12) << emp.last_name << "First: " << setw(12) 
     << setw(12) << emp.first_name << "ID: " << setw(12) << emp.ss_num 
     << "\nSalary: " << setw(12) << emp.salary << "Years Employed: "
     << setw(12) << emp.years_employed << endl;
    
}

/****************************************************************************
Function:  displayAllEmployees()
Use: displays all employees from the struct
Arguments: employee struct , count
Returns: nothing
*****************************************************************************/
void displayAllEmployees(Employee emp[], int count)
{
cout << "\nCOUNT FROM DISPLAY ALL IS: " << count << endl;
for (int i = 0; i < count ; i++)
    {
    *emp = emp[i];     
    displayEmployee(*emp);
    }
}

If possible - i would like to just figure out why i get this output instead of the correct one...here is the text file i use in program 1.

Kent Robert
123456789
58576.45
7
Jones Mary
111223333
65983.23
12
Adams Joe
111445678
34864.82
5
Zelazneck Jill
333456789
46239.45
7
Anders Lucy
222341234
28564.39
1
Maxwell Lawrence
999887654
100324.65
14
Liu Lee
999887654
54023.44
4
eof

And this is the output of the run of my 2nd program (after i run the 1st one to create the employees data file).

http://www.strifex.net/prog2-run.GIF

I hope someone can help me out for this problem. Thanks once again folks.

Recommended Answers

All 10 Replies

Member Avatar for iamthwee

Why don't you learn to read files properly?

int i = 0;
   inFile.read((char *)&personInfo[i], sizeof(Employee));
   while (inFile)
         {
         inFile.read((char *)&personInfo[i], sizeof(Employee));
         i++;
         }

note that you read into position 0 of your array, then read into it again, overwriting the first record.
Put the i++ as the first action in the loop body.

Val

Thats helpful! I looked up ways to read from files like this on the forums and in my book. Originally the way i wanted to do it didn't work so i looked online for an answer and used it. It obviously works somewhat - but i guess im a complete moron for trying.

int i = 0;
   inFile.read((char *)&personInfo[i], sizeof(Employee));
   while (inFile)
         {
         inFile.read((char *)&personInfo[i], sizeof(Employee));
         i++;
         }

note that you read into position 0 of your array, then read into it again, overwriting the first record.
Put the i++ as the first action in the loop body.

Val

Wow. Useful infomation. Thank you ever so much Val. Thanks for your time and effort to HELP someone out! Worked like a charm!!!

Glad to help.

As to the comment about reading files, I don't think you're dong that poorly. With a defined sentinel value ("eof"), your code

inFile >> personInfo.last_name;
   while (personInfo.last_name != end_of_file)
   {
       //do stuff
       inFile >> personInfo.last_name;
   }

is correct.

In general, we don't find sentinel values in files, the file just ends. So it becomes a matter of correctly determining that ending.

You could simply change your while condition to: while( infile ) or, as many do, combine the input and condition as while( inFile >> personInfo.last_name ) and eliminate the read statement at the end of the loop.

Val

Final question. I have to sort the names by last name in ascending order. To do this i would selection sort using strcmp() correct? So something along these lines (using my above 2nd program - adding this function):

void sortByName(Employee emp[], int count)
{
Employee temp;
int min = 1;
for (int i = 0; i < count; i++)
{
     if (strcmp(emp[i].last_name, emp[min].last_name) == 0)
        {
        temp = emp[i];
        emp[i] = emp[min];    
}

This is just the starting point. But i get really confused while trying to use just basic selection sort... and adding this strcmp() into the mix -- . Any useful ideas or suggestions would be very much welcome. Comments such as "you have no idea what you are doing", "you shouldnt code this or that its horrible" are NOT welcome.

Im learning - you all learnt at some point too. So let me work at it. I'll get there. Just have some patience!

Look up the bubble sort. It's much easier than the selection sort.

Comments such as "you have no idea what you are doing", "you shouldnt code this or that its horrible" are NOT welcome.

Im learning - you all learnt at some point too. So let me work at it. I'll get there. Just have some patience!

Touchy, aren't we? Has this happened a lot to you in 14 posts?

You're on the right track. Your sort needs another loop, when doing the comparison you look for the strcmp( ) return to be less than 0, and the swap is a three way exchange.

Val

You're on the right track. Your sort needs another loop, when doing the comparison you look for the strcmp( ) return to be less than 0, and the swap is a three way exchange.

Val

Thanks once again for your input. I have looked up selection sort and have this now working - but my only problem occurs now is that one entry is repeated twice in the output, while the first persons information is not used (Robert kent - maybe similar problem to me original problem Val?).

Here is my function (i have to use selection sort - its required per the assignment!)

void sortByName(Employee emp[], int count)
{
Employee temp;
 
     for (int nStartIndex = 0; nStartIndex < count; nStartIndex++)  
 {  
     // nSmallestIndex is the index of the smallest element  
     // we've encountered so far.  
     int nSmallestIndex = nStartIndex;  
   
     // Search through every element starting at nStartIndex+1  
     for (int nCurrentIndex = nStartIndex + 1; nCurrentIndex < count; nCurrentIndex++)  
     {  
         // If the current element is smaller than our previously found smallest  
         if (strcmp(emp[nCurrentIndex].last_name, emp[nSmallestIndex].last_name) == 1)
             // Store the index in nSmallestIndex  
             nSmallestIndex = nCurrentIndex;  
     }  
   
     // Swap our start element with our smallest element  
     //swap(emp[nStartIndex].last_name, emp[nSmallestIndex].last_name);  
     temp = emp[nStartIndex];
     emp[nStartIndex] = emp[nSmallestIndex];
     emp[nSmallestIndex] = temp;
}
 displayAllEmployees(emp, count);  [B]// This will call this function added in comments below[/B]
}

Called function below:

void displayAllEmployees(Employee emp[], int count)
{
for (int i = 0; i < count ; i++)
    {
    *emp = emp[i];     
    displayEmployee(*emp);
    }
}

Which then calls this:

void displayEmployee(Employee emp)
{
cout << left;
cout << "Last:   " << setw(12) << emp.last_name << "First: " << setw(12) 
     << setw(12) << emp.first_name << "ID: " << setw(12) << emp.ss_num 
     << "\nSalary: " << setw(12) << emp.salary << "Years Employed: "
     << setw(12) << emp.years_employed << endl;
    
}

This is my output for a run of my program:

http://strifex.net/2nd-run.GIF

Notice the repeat of Liu lee - in there should be the name Kent Robert as seen from the 2nd section.

Also - how would i change the sorting to be asceding..so A-Z? Would that be as simple as switching these 2 statements?

emp[nStartIndex] = emp[nSmallestIndex]; ??
to this
emp[nSmallestIndex] = emp[nStartIndex];????

Thanks once again for your help in advance..

**And yes i have had enough issues with people telling me im horrible on here and now use other forums (even though i really like 99% of the people on the information on here!!!)

Thanks to the 99% im sticking around tho!

To sort in ascending fashion, change the comparison in your if( strcmp( ) ) line to be < 0.

With the strcmp( ) functions, it's better to compare <0, >0 or == 0, depending on what you're trying to determine. Testing for the return to be exactly -1 or +1 may not work on all compilers. The values can be thought of as a meter needle pointing to the string that comes first in sorting order - negative values point to the first argument, positive values to the second argument, 0 (straight up) indicates the strings are equivalent.

The outer loop of the sort should have its limit as nStartIndex < count-1; , since the last possible comparison is the next to last item and the last (which will be nStartIndex+1 as set in the inner loop.)

As to the extra Liu replacing Kent - I cannot figure out what's happening!!*$*#*@
It might be helpful to put the displayAllEmployees( ) call inside the main loop, so you can see the state of the array after each exchange. Then you can identify when Kent goes AWOL, which will help to determine how.

I'm curious here:

void displayAllEmployees(Employee emp[], int count)
{
for (int i = 0; i < count ; i++)
    {
    *emp = emp[i];     
    displayEmployee(*emp);
    }
}

What's this *emp all about? Why not simply pass the array element to the display function, as in :

void displayAllEmployees(Employee emp[], int count)
{
   for (int i = 0; i < count ; i++)
    {
          displayEmployee( emp[i] );
    }
}

Val

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.