4

従業員データベースをランダムアクセスファイルに保持するこのプログラムを作成しようとしています。このプログラムには、従業員を追加および削除する機能が必要です(レコード内のすべてのスペースを書き込むことによって)。これは私がこれまでに持っているものですが、それは完全には正しく機能しません。従業員を読​​み取るときは、正しいレコードの給与を読み取りますが、次のレコードの名前を読み取ります。また、最後のレコードを削除してそのレコードに従業員を追加すると、従業員情報を表示できず、例外エラーが発生します。

私はここで解決策を探しているのではなく、正しい方向に微調整するだけです。ありがとう。

#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include "ccc_empl.h"

using namespace std;

const int NEWLINE_LENGTH = 2; 
const int RECORD_SIZE = 30 + 10 + NEWLINE_LENGTH;

/** 
   converts a string to a floating-point value   
   @param s a string representing a floating-point value
   @return the equivalent floating-point value
*/   
double string_to_double(string s)
{  
   istringstream instr(s);
   double x;
   instr >> x;
   return x;
}


/*
   reads an employee record from the input file
   @param e  the employee
   @param in the file to read from
*/
Employee read_employee(istream& in)
{   
string line;
getline(in, line);  
string input_name = line.substr(0, 30);
double input_salary = string_to_double(line.substr(30, 10));
Employee e(input_name, input_salary);
return e;
}

/*
gets input for an Employee object
@param input_name the name of the employee
@param input_salary the salary of the employee
@param e the Employee object
@return returns the Employee object
*/
Employee input_employee()
{
string input_name;
cout << "Name: ";
cin.ignore();
getline(cin, input_name);
cout << "Salary: ";
double input_salary;
cin >> input_salary;
Employee e(input_name, input_salary);
return e;
}

/**
   adds an employee record to a file
   @param e the employee record to write
   @param out the file to write to
*/
void add_employee(Employee e, ostream& out)
{
out << e.get_name()
  << setw(30)
  << fixed << setprecision(2)
  << e.get_salary();
}

/**
   removes an employee record from a file
   @param e the employee record to remove
   @param out the file to remove from
*/
void remove_employee(ostream& out)
{
out << " " << setw(42) << fixed << setprecision(2) << " \n";
}

int main()
{  
   cout << "Please enter the data file name: ";
   string filename;
   cin >> filename;
   fstream fs;
   fs.open(filename);

   fs.seekg(0, ios::end); // Go to end of file
   int nrecord = fs.tellg() / RECORD_SIZE; // determine number of records in the file
   int menu_input = 0;
   string input_name;
   double input_salary = 0;

   while (menu_input != 4)
   {
   cout << "Please enter the record to update: (0 - " << nrecord - 1 << ") exit to quit ";
   int pos = 0;
   cin >> pos;
   if(cin.fail())
   {
       cout << "Exiting..." << endl;
       system("pause");
       return 0;
   }

   // menu for user input
   cout << "\nWhat action would you like to perform?" << endl;
   cout << "Add employee.....1" << endl;
   cout << "Remove employee..2" << endl;
   cout << "View employee....3" << endl;       
   cin >> menu_input;

   switch(menu_input)
   {
   case 1:  fs.seekg(pos * RECORD_SIZE, ios::beg);
       add_employee(input_employee(), fs);
       break;           
   case 2:  fs.seekg(pos * RECORD_SIZE, ios::beg);
       remove_employee(fs);
       break;
   case 3:  fs.seekg(pos * RECORD_SIZE, ios::beg);
       cout << "\nName: " << read_employee(fs).get_name() << "Salary: " << read_employee(fs).get_salary() << endl << endl;
       break;
   default: cout << "Invalid entry" << endl;
       break;
   }
   }

   fs.close();
   system("pause");
   return 0;
}

わかりました。これが新しく改良された(まあ、そう思います)コードです。私が抱えている唯一の問題は、従業員を追加するときに、最初の開いているレコードに追加するプログラムを取得できますが、開いているレコードがない場合は、最後に追加することができないようです。最初の空のレコードへの追加を台無しにすることなくファイル。つまり、空のレコードがある場合はレコードに従業員が追加されますが、空のレコードがない場合はファイルの最後に従業員が追加されません。ファイルの最後に追加するコードを追加すると、2つのいずれかが発生します。空のレコードに追加してから、別の従業員を要求して最後に追加するか、空のレコードをスキップしてに追加します。ファイルの終わり。

ここで何が間違っているのかわかりませんが、ヒントをいただければ幸いです。

#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include "ccc_empl.h"

using namespace std;

const int NEWLINE_LENGTH = 2; 
const int RECORD_SIZE = 30 + 10 + NEWLINE_LENGTH;

/** 
converts a string to a floating-point value   
@param s a string representing a floating-point value
@return the equivalent floating-point value
*/   
double string_to_double(string s)
{  
   istringstream instr(s);
   double x;
   instr >> x;
   return x;
}


/*
reads an employee record from the input file
@param e  the employee
@param in the file to read from
*/
Employee read_employee(istream& in)
{   
string line;
getline(in, line);  
string input_name = line.substr(0, 30);
double input_salary = string_to_double(line.substr(30, 10));
Employee e(input_name, input_salary);
return e;
}

/*
gets input for an Employee object
@param input_name the name of the employee
@param input_salary the salary of the employee
@param e the Employee object
@return returns the Employee object
*/
Employee input_employee()
{
string input_name;
cout << "Name: ";
cin.ignore();
getline(cin, input_name);
cout << "Salary: ";
double input_salary;
cin >> input_salary;
Employee e(input_name, input_salary);
return e;
}

/**
adds an employee record to a file
@param e the employee record to write
@param out the file to write to
*/

void add_employee(Employee e, ostream& out)
{
out << e.get_name()
  << setw(10 + 30 - e.get_name().length())
  << fixed << setprecision(2)
  << e.get_salary() << "\n";
}

/**
removes an employee record from a file
@param e the employee record to remove
@param out the file to remove from
*/

void remove_employee(ostream& out)
{
out << " " << setw(40) << fixed << setprecision(2) << " \n";
}


int main()
{  
   cout << "Please enter the data file name: ";
   string filename;
   cin >> filename;
   fstream fs;
   fs.open(filename);

   fs.seekg(0, ios::end); // Go to end of file
   int nrecord = fs.tellg() / RECORD_SIZE; // determine number of records in the file
   int menu_input = 1;
   string input_name;
   double input_salary = 0;

   while (menu_input)
   {       
   // menu for user input
   cout << "\nWhat action would you like to perform?" << endl;
   cout << "Add employee.....1" << endl;
   cout << "Remove employee..2" << endl;
   cout << "View employee....3" << endl;
   cout << "Exit.............4" << endl;
   cin >> menu_input;
   if (menu_input == 4)
   {
       cout << "\nExiting..." << endl << endl;
       system("pause");
       return 0;
   }
   // switch statment to perform selected menu_input task
   switch(menu_input)
   {
   case 1:  // adds an employee in the first empty record
            // or at the end of the file if no records are empty          
            {
                int count = 0;
                string s;
                for (int i = 0; i < nrecord; i++)
                {
                    fs.seekp(count, ios::beg);
                    getline(fs, s);
                    if (isspace(s[0]))
                    {
                        fs.seekp(count, ios::beg);
                        add_employee(input_employee(), fs);
                        nrecord++;
                        break;
                    }else
                        count += 42;
                }
            }           
       break;           
   case 2:  {
            cout << "Please enter the record to remove: (0 - " << nrecord -1 << ") ";
            int pos = 0;
            cin >> pos;
            fs.seekp(pos * RECORD_SIZE, ios::beg);
            remove_employee(fs);
            }
       break;
   case 3: {
            cout << "Please enter the record to view: (0 - " << nrecord -1 << ") ";
            int pos = 0;
            cin >> pos;
            fs.seekg(pos * RECORD_SIZE, ios::beg);
            Employee e(read_employee(fs));        
            cout << "\nName: " << e.get_name() << "Salary: " << e.get_salary() << endl << endl;
           }
       break;     
   default: cout << "Invalid entry" << endl;
       break;
   }
}

fs.close();
system("pause");
return 0;
}
4

2 に答える 2

1

read_employee(fs)あなたは2回電話します。最初に必要なレコードを読み取り、2 番目に次のレコードを読み取ります (標準では、どちらが「最初」であるかは指定されていません)。

于 2012-09-09T17:38:26.953 に答える
0

add_employee に行末記号を追加していないようで、read_employee が 2 回呼び出されます。関数の結果をキャッシュするだけです。

これは単なる宿題であることは承知していますが、このプログラムを改善できると思います。

  1. 実行時にデータベースをファイルのままにしておく必要がありますか? ファイル全体を Employee の配列に読み込み、最後に書き直すことができます。従業員名の長さを制限しません。

  2. このプログラムはクロスプラットフォームではありません。行末記号は OS ごとに異なるため、データベース内のエントリ数を決定するためにファイル サイズに依存しないでください。代わりに、すべてを読み、エントリを数えます。

  3. 「一時停止」プログラムがあるのは Windows だけです。同じ効果を得るには、プログラムの最後で stdin を読み取り、入力を無視します。

于 2012-09-09T17:40:48.073 に答える