0

Still new to the world of C++, and the following question is because of a homework assignment! I have not found much in the way of help searching through previously answered questions or Google, does not mean I have not missed it.

The Homework's Goals: 1.) Take user input information and store it in a binary file. 2.) Read that data back in later.

I have an array of up to 10 structures, the struct takes on char array of a user name, char array of user phone number, and a float salary. When I enter a few test cases, the file writes, I am assuming correctly. When I go to read the values in, the first name prints out nicely as does the first phone number. The float gives me -4013602080 not matter what value I had entered into the test case. From there it goes downhill. I am trying this using . My question boils down to two parts, am I "properly" writing the structure members to the file, and how do I read in floats from binary? (or should would it be advantageous to use fopen and fclose?) Hints or references would be wonderful.

header

//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_

Here is the necessary parts from the source file I believe:

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";
    }


}

and here is the main file

#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;
}

I imagine there are many things I could improve, but for now I would like to figure binary part out. Any hints are much appreciated. Thanks!

nope
  • 151
  • 1
  • 14
  • Recursively, write the struct members out one by one, in a format that you specify and document (e.g. "integers as-is, strings as length-prefixed byte sequences representing ASCII"). – Kerrek SB Oct 25 '12 at 22:44
  • ...and specify whether your numerics larger than 1 native byte are written in big-endian or little-endian format, and **be precise** about their byte-size representation: "integers written as big-endian 32-bit (4byte) values, etc..." Properly specced anyone should be able to take your bin file, load it in a hex editor and see *exactly* how the layout reflects your description. if they cannot, chances are you need finer details. – WhozCraig Oct 25 '12 at 22:50

1 Answers1

3

This looks wrong:

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));

In the first line, you're storing a name field, but you're using sizeof(pt) as the size, where the size is actually the size of a pointer value. You're also taking the address of the name array (a char**) and casting it as a char*

To fix:

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));

Actually, you might not need to do these fields individually (unless you're trying to conform to an ordering that is different to the structure) because the structure does not have any dynamic data. You can store the entire record in one hit:

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

Even better, you can store the entire array in one hit and avoid looping:

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

Similarly for reading... Note that you might want to store the value of gl in the file too, so you know how many records it contains. Or if you want to be slightly more arcane, you could check the file size and divide sizeof(struct emp) into it to infer the number of records.

paddy
  • 60,864
  • 6
  • 61
  • 103
  • Thanks for the help, I will see what I can do. – nope Oct 25 '12 at 23:20
  • 1
    To be compatible between 32 bits and 64 bits platfroms, you should use "#pragma pack()" around the struct definition if you want to write it with a single write(). See http://stackoverflow.com/a/3318475/443992 – PRouleau Oct 25 '14 at 02:39