Thread: A book exercise: Reading and writing to binary records through random access...

  1. #1
    Registered User
    Join Date
    Jun 2011
    Posts
    46

    A book exercise: Reading and writing to binary records through random access...

    (The book is C++ without Fear)

    I was able to get it to work one way, but was not able to get the authors solution. Actually he uses different commands then in the book examples, but I like his approach so I decided to try and solve his way. He uses functions in the control statements which I didn't in the first go around.


    Here is my first try which works.

    Code:
    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    
    int get_int(int default_value);
    
    
    int main() {
        char filename[MAX_PATH + 1];
        int n = 0;
        int choice = 0;
        char model[21];
        char make[21];
        char year[6];
        int mileage = 0;
        int recsize = sizeof(model) + sizeof(make) + sizeof(year) + sizeof(int);
    
    
        cout << "Enter file name: ";
        cin.getline(filename, MAX_PATH);
    
        // Open file for binary read and write.
    
        fstream  fbin(filename, ios::binary | ios::out | ios::in);
        if (!fbin) {
            cout << "Could not open file " << filename << endl;
            system("PAUSE");
            return -1;
        }
    
    //  Get record number to write to.
    
        while(1){
    
                cout << "What would you like to do?" << endl;
                cout << "Enter 1 to write a record." << endl;
                cout << "Enter 2 to read a record." << endl;
                cout << "Enter 3 to quit" << endl;
                cout << "Enter here: ";
                choice = get_int(0);
    
                if (choice == 3)
                    break;
    
                if(choice == 1){
                        cout << "Enter file record number: ";
                        n = get_int(0);
    
                        // Get data from end user.
    
                        cout << "Enter model: ";
                        cin.getline(model, sizeof(model));
    
                        cout << "Enter make: ";
                        cin.getline(make, sizeof(make));
    
                        cout << "Enter year: ";
                        cin.getline(year, sizeof(year));
    
                        cout << "Enter mileage: ";
                        mileage = get_int(0);
    
                        // Write data to the file.
    
                        fbin.seekp(n * recsize);
                        fbin.write(model, sizeof(model) - 1);
                        fbin.write(make, sizeof(make) - 1);
                        fbin.write(year, sizeof(year) - 1);
                        fbin.write((char*)(&mileage), sizeof(int));
                }
    
                if (choice == 2){
                    cout << "Enter file record number: ";
                    n = get_int(0);
                    fbin.seekp(n * recsize);
    
                    // Read data from the file.
    
    
                    fbin.read(model, sizeof(model) - 1);
                    fbin.read(make, sizeof(make) - 1);
                    fbin.read(year, sizeof(year) - 1);
                    fbin.read((char*)(&mileage), sizeof(int));
    
                    // Display the data
    
                    cout << "The model is: " << model << endl;
                    cout << "The make is: " << make << endl;
                    cout << "The year is: " << year << endl;
                    cout << "The mileage is: " << mileage << endl;
                 }
                 if (choice != (1 || 2 || 3))
                    continue;
        }
        fbin.close();
        system("PAUSE");
        return 0;
    }
    
    #define COL_WIDTH 80 // 80 is typical column width.
    
    // Get integer function
    // Get an integer from keyboard; return default
    //  value if user enters 0-length string.
    //
    int get_int(int default_value) {
        char s[COL_WIDTH + 1];
    
        cin.getline(s, COL_WIDTH);
        if (strlen(s) == 0)
             return default_value;
        return atoi(s);
    }
    and my second try which compiles, run, but it doesn't seem to write anything to the file and I get garbage back.

    Code:
    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    
    int get_int(int default_value);
    void write_record();
    void read_record();
    
    int main() {
        char filename[MAX_PATH + 1];
        int n = 0;
        int choice = 0;
    
        cout << "Enter file name: ";
        cin.getline(filename, MAX_PATH);
    
        // Open file for binary read and write.
    
        fstream fbin(filename, ios::binary | ios::out | ios::in);
        if (!fbin) {
            cout << "Could not open file " << filename << endl;
            system("PAUSE");
            return -1;
        }
    
    //  Get record number to write to.
    
        while(1){
    
                cout << "What would you like to do?" << endl;
                cout << "Enter 1 to write a record." << endl;
                cout << "Enter 2 to read a record." << endl;
                cout << "Enter 3 to quit" << endl;
                cout << "Enter here: ";
                choice = get_int(0);
    
                if (choice == 1)
                    write_record();
                else if(choice == 2)
                    read_record();
                else if(choice == 3){
                    fbin.close();
                    system("PAUSE");
                    return 0;}
                else
                    cout << "Bad Entry!!! Re-enter choice: " << endl << endl;
            } //end while
    } // end main
    
    void write_record(){
    
        int n = 0;
        int choice = 0;
        char model[21];
        char make[21];
        char year[6];
        int mileage = 0;
        int recsize = sizeof(model) + sizeof(make) + sizeof(year) + sizeof(int);
        fstream fbin;
    
                        cout << "Enter file record number: ";
                            n = get_int(0);
    
                        cout << "Enter model: ";
                        cin.getline(model, sizeof(model));
    
                        cout << "Enter make: ";
                        cin.getline(make, sizeof(make));
    
                        cout << "Enter year: ";
                        cin.getline(year, sizeof(year));
    
                        cout << "Enter mileage: ";
                        mileage = get_int(0);
    
                        // Write data to the file.
    
                        fbin.seekp(n * recsize);
                        fbin.write(model, sizeof(model) - 1);
                        fbin.write(make, sizeof(make) - 1);
                        fbin.write(year, sizeof(year) - 1);
                        fbin.write((char*)(&mileage), sizeof(int));
    
    }
    
    void read_record(){
    
        int n = 0;
        int choice = 0;
        char model[21];
        char make[21];
        char year[6];
        int mileage = 0;
        int recsize = sizeof(model) + sizeof(make) + sizeof(year) + sizeof(int);
        fstream fbin;
    
                    cout << "Enter file record number: ";
                    n = get_int(0);
                    fbin.seekp(n * recsize);
    
                    // Read data from the file.
    
    
                    fbin.read(model, sizeof(model) - 1);
                    fbin.read(make, sizeof(make) - 1);
                    fbin.read(year, sizeof(year) - 1);
                    fbin.read((char*)(&mileage), sizeof(int));
    
                    // Display the data
    
                    cout << "The model is: " << model << endl;
                    cout << "The make is: " << make << endl;
                    cout << "The year is: " << year << endl;
                    cout << "The mileage is: " << mileage << endl;
    }
    
    
    #define COL_WIDTH 80 // 80 is typical column width.
    
    // Get integer function
    // Get an integer from keyboard; return default
    //  value if user enters 0-length string.
    //
    int get_int(int default_value) {
        char s[COL_WIDTH + 1];
    
        cin.getline(s, COL_WIDTH);
        if (strlen(s) == 0)
             return default_value;
        return atoi(s);
    }
    any ideas? keep in mind I'm a beginner to C++, if you see any other errors I may be making please let me have it. Braces for impact.

    Thanks all!

  2. #2
    -bleh-
    Join Date
    Aug 2010
    Location
    somewhere in this universe
    Posts
    463
    How did that compile? You have never declared MAX_PATH.
    "All that we see or seem
    Is but a dream within a dream." - Poe

  3. #3
    Registered User
    Join Date
    Jun 2011
    Posts
    46
    MAX_PATH is a predefined constant. It contains the maximum length for file names(path included) supported on the system.

    It also shows in the examples that they do not declare it.

    I'm assuming you don't have to.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    You do have to define it. This may be a error in the print. The related member constant that the C standard library has is FILENAME_MAX, according to wikipedia, but it is important not to confuse max filename sizes with max paths.

    For example, this is a path

    C:\Documents and Settings\Owner\My Documents\My Pictures\People

    Now imagine something with a really long file name overflowing a char array. The max path length is OS specific.

  5. #5
    Registered User
    Join Date
    Jun 2011
    Posts
    46
    whiteflags: doesn't #include<cstdlib> take care of this?

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by tabl3six
    doesn't #include<cstdlib> take care of this?
    As far as I can tell, there is no standard constant named MAX_PATH.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    It's not standard. Windows defines it (or at least my Windows MinGW accepts it). gcc on Ubuntu complains bitterly.

  8. #8
    Registered User
    Join Date
    Jun 2011
    Posts
    46
    I'm using Code::Blocks with MinGW. My code runs and in the first case works, second case I'm not sure what could be wrong.

    I think it may have something to do with the statement fstream fbin(filename, ios::binary | ios:: out | ios::in); and they way I set up the functions. Author uses a different command fbin.open(filename, ios::binary | ios::in | ios:: out), he also declares fstream fbin at the top.

    so confused

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by tabl3six
    I'm using Code::Blocks with MinGW. My code runs and in the first case works, second case I'm not sure what could be wrong.
    Since MAX_PATH is not standard, you have no guarantees that it will be available, hence your observation. A simple solution is to conditionally define MAX_PATH yourself.

    Quote Originally Posted by tabl3six
    I think it may have something to do with the statement fstream fbin(filename, ios::binary | ios::out | ios::in); and they way I set up the functions. Author uses a different command fbin.open(filename, ios::binary | ios::in | ios::out), he also declares fstream fbin at the top.
    Your version is equivalent to the author's version because the order of parameters for bitwise or does not change its result.

    However, what is important is the part about declaring fbin at the top: global variables are usually a bad sign, but here you used a local variable but failed to pass it to the functions that needed it. As such, your fbin in say write_record() is different from the one in main(), and consequently that is a problem. You can fix it by providing write_record() with a reference parameter for fstream.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Jun 2011
    Posts
    46
    "You can fix it by providing write_record() with a reference parameter for fstream. "

    can you give me an example, not sure how to do this. I tried pasting in fstream fbin(filename, ios::binary | ios:: out | ios::in); in both functions. I just get an error message.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by tabl3six
    can you give me an example, not sure how to do this.
    Something like:
    Code:
    int main() {
        // ...
        fstream fbin(filename, ios::binary | ios::out | ios::in);
        // ...
        write_record(fbin);
        // ...
    }
    
    void write_record(fstream& fbin) {
        // ...
    }
    Note that you will remove this line from the definition of write_record:
    Code:
    fstream fbin;
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Jun 2011
    Posts
    46
    Wow it's like you've done this before. It worked like a charm. Thanks.

    I would have never figured that out. I'm still not sure why it works. What does the fstream& represent? I'm still not getting pointers.

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    That's okay, because there aren't any pointers involved. A reference to fstream means the fstream itself is passed to the function, rather than having a copy made and the function getting a copy.

  14. #14
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    References are like pointers, but you don't need to dereference them, and you assign what they point to when you declare them.

    When you pass an object to a function that expects a reference to that type of object, the compiler knows to make a reference. Then you just use the variable.

    That's all you really need to know right now.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. reading then displaying some data from a random access file
    By kool_hamster in forum C Programming
    Replies: 5
    Last Post: 01-21-2010, 10:56 AM
  2. Replies: 3
    Last Post: 09-30-2008, 12:10 AM
  3. binary tree random access
    By dlcp in forum C Programming
    Replies: 1
    Last Post: 03-29-2008, 05:38 PM
  4. Reading/Writing Binary
    By Queatrix in forum C++ Programming
    Replies: 4
    Last Post: 02-01-2006, 11:15 PM
  5. Reading/Writing in Binary
    By kuphryn in forum C++ Programming
    Replies: 4
    Last Post: 12-11-2001, 10:32 PM