0

C++ の世界ではまだ新しいので、次の質問は宿題のせいです! 以前に回答した質問や Google を検索してもあまり役に立たなかったからといって、それを見逃していないわけではありません。

宿題の目標: 1.) ユーザー入力情報を取得し、バイナリ ファイルに保存します。2.) そのデータを後で読み戻します。

最大 10 個の構造体の配列があり、構造体はユーザー名の char 配列、ユーザーの電話番号の char 配列、浮動小数点給与を受け取ります。いくつかのテストケースを入力すると、ファイルに書き込みがあり、正しく想定しています。値を読み込むと、最初の名前と最初の電話番号がうまく出力されます。float は、テスト ケースに入力した値に関係なく、-4013602080 を返します。そこから下り坂になります。を使用してこれを試しています。私の質問は2つの部分に要約されます.構造体のメンバーをファイルに「適切に」書き込んでいますか?バイナリからフロートを読み込むにはどうすればよいですか? (または、fopen と fclose を使用する方が有利でしょうか?)ヒントや参考文献はすばらしいでしょう。

ヘッダ

//my header
#ifndef USERS_H
#define USERS_H


#include <iostream>
#include <cstring>
#include <cstdlib>
#include <limits>
#include <iomanip>

const int arsize=20;
using namespace std;
struct emp
{
    char name[arsize];
    char phone[arsize];
    float salary;
};
class Users
{
private:
    //const int arsize=20;
    int choice, num_of_names;
public:
    Users();
    void menu();
    void enter(emp*pt, int n);
    void print_all(emp*pt);
    void print_condition(emp*pt);
    void end_phone_array(emp*pt);
    void bubble_sort(emp*pt);
    void selection_sort(emp*pt);
    void raise(emp*pt);
            void file_store(emp*pt);
    void file_read(emp*pt);

};
#endif USERS_H_

私が信じているソースファイルからの必要な部分は次のとおりです。

void Users::enter(emp*pt, int n)
{
    extern int gl,count,f;
    if(gl+n>10)
    {
        cout<<"Memory Full!\n";
    }
    else
    {
        for (int i=count;i<f+n;i++)
        {
            gl++;
            cout<<"Enter user #"<<i+1<< " name(no more than 20 characters)\n";
            cin.get();
            cin.getline(pt[i].name, arsize);//.get();
            cout<<"Enter user #"<<i+1<< " phone #\n";
            cin.getline(pt[i].phone, arsize);//.get();
            cout<<"Enter user #"<<i+1<< " salary\n";
            (cin>>pt[i].salary);//.get();
        }
        count=gl;
        f=gl;
    }
}
void Users::file_store(emp* pt)
{
    //ifstream::pos_type size;
    extern int gl;
    //float test;
    //ofstream Testfile ("C:\\Users\\Ian\\Desktop\\Programming\\C++\\data.bin", ios::out| ios::binary);  //for personal computer use
    ofstream Testfile ("data.bin", ios::out | ios::binary);
    for (int i=0; i<gl;i++)
    {
        Testfile.write((char*)&pt[i].name, sizeof(pt));
        Testfile.write(pt[i].phone, sizeof(pt[i].phone));
        Testfile.write((char *)&pt[i].salary, sizeof(pt[i].salary));
    }
}
void Users::file_read(emp*pt)
{
    //extern int gl;
    struct TEST
    {
        char n_array[20];
        char p_array[13];
        float salary;
    };
    TEST test[20];
    for (int i=0;i<20;i++)
    {
        test[i].n_array[0]='\0';
        test[i].p_array[0]='\0';
        test[i].salary=0.0;
    }
    /*ifstream::pos_type size;
     * char *memblocktest;*/
    ifstream test_in ("data.bin", ios::in | ios::binary);
    for(int i=0;i<10;i++)
    {
        if(test_in.is_open())for(int i=0;i<10;i++)
        {
            test_in.read((char*)&test, sizeof(test));
            cout<<test[i].n_array<<"\n";
            cout<<test[i].p_array<<endl;
            cout<<"$"<<test[i].salary<<endl;
        }
        else
            cout<<"Don't know what I am doing!\n";
    }


}

ここにメインファイルがあります

#include "stdafx.h"
#include "users.h"
#include <iostream>
#include <cctype>
#include <limits>
#include <iomanip>
#include <cstring>
using namespace std;


extern int gl=0, count =0, f=0;
int main()
{
    Users Test;
    std::cout.setf(std::ios::fixed);
    std::cout.precision(2);
    emp*test=new emp[10];
    Test.menu();
    int choice, num_of_names;
    while(1)
    {
        if(!(cin>>choice))
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(),'\n');
            cout<<"ERROR!\n";
        }
        else
            break;
    }
    while(choice!=9)
    {
        switch(choice)
        {
            case 1:{cout<<"How many users will you enter?\n";
                    cin>>num_of_names;
                    Test.enter(test, num_of_names);
                    Test.end_phone_array(test);
                    break;}
            case 2:{Test.print_all(test);
                    break;}
            case 3:{Test.print_condition(test);
                    break;}
            case 4:{Test.bubble_sort(test);
                    break;}
            case 5:{Test.selection_sort(test);
                    break;}
            case 6:{Test.raise(test);
                break;}
            case 7:{Test.file_store(test);
                    break;}
            case 8:{Test.file_read(test);
                break;}
            default:{"Bad Choice..........\n";
                     break;}
        }
        Test.menu();
        while(1)
        {
            if(!(cin>>choice))
            {
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(),'\n');
                cout<<"ERROR!\n";
            }
            else
                break;
        }
    }
    delete [] test;
    //system("Pause");
    return 0;
}

改善できることはたくさんあると思いますが、今のところ、バイナリ部分を把握したいと思います。どんなヒントでも大歓迎です。ありがとう!

4

1 に答える 1

3

これは間違っているように見えます:

void Users::file_store(emp* pt)
{
    // etc...

        Testfile.write((char*)&pt[i].name, sizeof(pt));
        Testfile.write(pt[i].phone, sizeof(pt[i].phone));
        Testfile.write((char *)&pt[i].salary, sizeof(pt[i].salary));

最初の行では、名前フィールドを格納していますがsizeof(pt)、サイズとして使用しています。ここで、サイズは実際にはポインター値のサイズです。また、名前配列 (a char**) のアドレスを取得し、それを a としてキャストしています。char*

修正するには:

Testfile.write(pt[i].name, sizeof(pt[i].name));
Testfile.write(pt[i].phone, sizeof(pt[i].phone));
Testfile.write((char *)&pt[i].salary, sizeof(pt[i].salary));

実際には、構造体には動的データがないため、これらのフィールドを個別に行う必要はありません (構造体とは異なる順序に準拠しようとしている場合を除く)。1 回のヒットでレコード全体を保存できます。

Testfile.write((char*)&pt[i], sizeof(struct emp));

さらに良いことに、配列全体を 1 回のヒットで格納し、ループを回避できます。

Testfile.write((char*)pt, gl * sizeof(struct emp));

読み取りについても同様です... の値もファイルに保存したい場合があることに注意してください。glこれにより、ファイルに含まれるレコードの数がわかります。または、もう少し難解にしたい場合は、ファイルサイズを確認して分割sizeof(struct emp)し、レコード数を推測できます。

于 2012-10-25T22:54:48.553 に答える