Please help solving this problem: Reading & Writing Records in a Structure

In summary: Again? (y/n) "; cin >> again; if (again == 'y') { //Here, we try to modify the record. //If the record already exists, it will be modified. //Otherwise, it will be created. //If the record doesn't exist, it will be created with the given value. //This function returns -1 if an error occurs. //Otherwise, it returns the
  • #1
yungman
5,718
241
Hi
I have a funky problem I have been working on for over a day, it is supposed to be quite simple, but I have funny result. What the program does is to pick out one of the five records(of structure) stored in the file, modify it and store back into the file in the same position. It supposed to only change the chosen one and leave the others alone. But instead it erase the others. I went through it so many times and I cannot figure this out. This is modification of an exercise from the book. I finally keyed in the exact program from the book, it did the same thing.

There is one program ( 12.20) that create the file with 5 of the records. This program pick one to edit. Because this program destroy the data inside the file, I put exercise 12.20 in line1 to line35. I made it into comment to get it out of the way after creating the Inventory.dat.

C++:
/*//12.20 create file of blank struct inventory records
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
const int d_size = 31;
const int numRec = 5;
struct invItem
{
    char desc[d_size];
    int qty;
    double price;
};
int main()
{
    fstream inventory;
    int index = 0;
    invItem record;
    cout << " Size of inventory = " << sizeof(invItem) << "\n\n";
    inventory.open("Inventory.dat", ios::out | ios::binary);
    for (index = 0; index < numRec; index++)
    {
        cout << " Record  " << index << endl;
        cout << setw(25) << left << " Description: ";
        cin >> record.desc; cout << endl;
        cout << setw(25) << left << " Quantity: ";
        cin >> record.qty; cout << endl;
        cout << setw(25) << left << " Price: " << "$";
        cin >> record.price; cout << "\n\n";
        inventory.seekp(index * sizeof(invItem), ios::beg);
        inventory.write(reinterpret_cast<char*>(&record), sizeof(record));
    }
    inventory.close();
    return 0;
}*/
//12.22 edit record created by 12.20
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
const int d_size = 31, numRec = 5;
struct invItem
{
    char desc[d_size];
    int qty;
    double price;
};
void displayRec();
void modify(long);

int main()
{
    char again, choose;    int sel;
//Display all the records in the file
    cout << " Do you want to see all records? "; cin >> choose;
    if(tolower(choose) == 'y')  displayRec();
//Read and edit particular file.
    do
    {
        cout << " What record you want to read and edit? ";    cin >> sel; cout << "\n\n";
        modify(sel);
        cout << " Do you want to edit another record? "; cin >> again;
    } while (tolower(again) == 'y');
    return 0;
}
void displayRec()
{
    fstream inven;    invItem rec; long select = 0;
    inven.open("Inventory.dat", ios::in | ios::binary);
    inven.read(reinterpret_cast<char*>(&rec), sizeof(invItem));
    do
    {    cout << " Record   " << select << endl;
        cout << setw(25) << left << " Description: " << rec.desc << endl;
        cout << setw(25) << left << " Quantity: " << rec.qty << endl;
        cout << setw(25) << left << " Price: " << "$" << rec.price << "\n\n";
        inven.read(reinterpret_cast<char*>(&rec), sizeof(invItem));
        select++;
    } while (!inven.eof());
    inven.close();
}
void modify(long index)
{
    char choose, again = 'n';fstream inventory;
    invItem record; //It's object of struct invItem.
    inventory.open("Inventory.dat", ios::in | ios::binary);
    inventory.seekg(index * sizeof(invItem), ios::beg);
    inventory.read(reinterpret_cast<char*>(&record), sizeof(invItem));
    cout << " Record  " << index << endl;
    cout << setw(25) << left << " Description: " << record.desc << endl;
    cout << setw(25) << left << " Quantity: " << record.qty << endl;
    cout << setw(25) << left << " Price: " << "$" << record.price << "\n\n";
    inventory.close();
    cout << " Do you want to change change record " << index << "? ";
    cin >> choose; cout << "\n\n";
    if (tolower(choose == 'y'))
    {
        cout << " Record  " << index << endl;
        cout << setw(25) << left << " Description: "; cin >> record.desc; cout << endl;
        cout << setw(25) << left << " Quantity: "; cin >> record.qty; cout << endl;
        cout << setw(25) << left << " Price: " << "$"; cin >> record.price; cout << "\n\n";
//Display what you entered
        cout << " You entered new data in record " << index << endl;
        cout << setw(25) << left << " Description: " << record.desc << endl;
        cout << setw(25) << left << " Quantity: " << record.qty << endl;
        cout << setw(25) << left << " Price: " << "$" << record.price << "\n\n";
//Write to file
        inventory.open("Inventory.dat", ios::out | ios::binary);
        inventory.seekp(index * sizeof(record), ios::beg);
        inventory.write(reinterpret_cast<char*>(&record), sizeof(record));
        inventory.close();
    }
}
I first run the program to read the invItems as shown here before editing. You can see the 5 records.
Compile error Listing 7.2.jpg


I used all the tools I know how with debugger. It ALL works UNTIL line 108 to line 110. I verify I wrote in the new data in line 103 to 106 that I got the right data written into record. I edited record #2. But after writing, I closed the program and restart the program so I can read back the 5 records, all the other ones got erased as shown.
Compile error Listing 7.3.jpg

Like I said, I finally key in the exercise from the book, it did exactly the same thing. In the exercise, they won't know because it only read back the one they changed. As you see, the #2 record I changed is there. Just the rest got erased.

Now I am at a lost, will line 108 to line 110 erase the other record when editing the chosen one? I thought seekp() and write() only write over the one that is pointing and leave the others alone.

Another thing is, I cannot upload the Inventory.dat here, I even change to .txt and still won't work. Another funny thing is If I create the Inventory.dat with another program and just copy into the folder of this program, It WON'T work. Got to create by this program. Don't ask me why. That's why I finally copy 12.20 onto this program from line 1 to line 35. Use it to create the Inventory.dat for the program to use.

I know this is a long program, I exhausted everything I know how to do and I can't fix it. The problem is really in line 108 to 110.

Please help.

Thanks
 
Technology news on Phys.org
  • #2
If you were using fopen, I would say you needed to open it with the "r+" flag.
Since you are using fstream:: open, I would try ios::in | ios:: out | ios::binary.
 
  • Like
Likes yungman
  • #3
.Scott said:
If you were using fopen, I would say you needed to open it with the "r+" flag.
Since you are using fstream:: open, I would try ios::in | ios:: out | ios::binary.
Why using ios::in | ios:: out | ios::binary works?

I did it in ios::in, then I make sure I close the file, then open in ios:: out. Isn't it the same?

I wasted over a day, never think that will make a difference!

Thanks
 
Last edited:
  • #4
yungman said:
I did it in ios::in, then I make sure I close the file, then open in ios::eek:ut. Isn't it the same?
No. If you open a file for output (i.e., with ios:: out), if it already exists, it will be overwritten.
https://docs.microsoft.com/en-us/cpp/standard-library/output-file-stream-member-functions?view=vs-2019 said:
Creating a file. If the file already exists, the old version is deleted.
C++:
ofstream ofile("FILENAME", ios::out);
 
  • Like
Likes yungman
  • #5
Mark44 said:
No. If you open a file for output (i.e., with ios:: out), if it already exists, it will be overwritten.
Yes, it's my fault, I was so sure it doesn't matter and I skipped reading deeper that ios::in | ios::eek:ut is the only way that won't delete the existing content other than the one needs to be changed.

Can you delete this thread, this is the end. Now I am ready to move on to Chapter 13 Classes.

Thanks
 
  • #6
yungman said:
Can you delete this thread, this is the end. Now I am ready to move on to Chapter 13 Classes.
We will keep this thread - who knows how many others will need this tip.
 
  • #7
Mark44 said:
No. If you open a file for output (i.e., with ios:: out), if it already exists, it will be overwritten.
Hi Mark
I want to use this threat to thank you for kept mentioning streaming operators <<, >> vs member function getline() and get(). I was busy experimenting with file object streaming vs file.write()/file.read() member functions, by the time I finish, you closed that thread already. I thought I thank you here while this thread is still open.

I studied through like 15 pages of Classes, that really open my eyes on the names that you guys use all the time.

Like int x =5, y=10; If I am correct, int is the datatype, it's a Class. x and y are Objects of datatype int. x and y are both INSTANCE of datatype int. 5 and 10 are Object data. Did I get this right?

Like fstream is a datatype ( Class), fstream outFile declares outFile an Object of fstream. With that, I can use member function read(), write(), seekp() etc. to work on the data. These are the hardest part for me and it was like Russian to me before when people using these terms.

It is very interesting. I don't have any question, it's still quite simple at this point ( only 15 pages in!). I budgeted one month for this chapter, one month for chapter 14 and another month for chapter 15 on Inheritance and Polymorphism. That's should be a generous time frame so I can go back and re-visit stuffs in the pass chapters with the new knowledge.

thanks
 
Last edited:
  • #8
yungman said:
Like int x =5, y=10; If I am correct, int is the datatype, it's a Class.
int is the datatype, but it's not a class. Same is true for char, short, long, float, etc.
yungman said:
x and y are Objects of datatype int.
No, they are not objects. They are just variables of type int.
yungman said:
x and y are both INSTANCE of datatype int. 5 and 10 are Object data. Did I get this right?
An object is an instance of some class, but x and y are just variables of type int.
yungman said:
Like fstream is a datatype ( Class), fstream outFile declares outFile an Object of fstream. With that, I can use member function read(), write(), seekp() etc. to work on the data. These are the hardest part for me and it was like Russian to me before when people using these terms.
Right. fstream is a class, and outFile is an instance of that class (an object). The fstream class has member functions, and maybe some member data -- I'll have to check.
 
  • Like
Likes yungman
  • #9
Ha ha, I guess I reached a little too far. I was wondering where are the member functions of int, char etc. I know +, -, *, / etc. are not member function like append(), length() in String Class, nor read(), seekp() of fstream.

I'll get there...slowly.

Thanks
 
  • #10
yungman said:
I was wondering where are the member functions of int, char etc. I know +, -, *, / etc. are not member function like append(), length() in String Class, nor read(), seekp() of fstream.
int, char, short, long, float, double, and a few others are built-in types.
+, -, *, /, %, >, >>, <, !, *, &, and others are operators, some of which can be overloaded in C++.
 
  • Like
Likes yungman
  • #11
yungman said:
I'll get there...slowly.

Right. Have you heard the expression "If we work any faster, we'll never finish!"?

I might think about starting from the beginning, now that you have the background to understand what the book was saying then.
 

1. What is a structure in coding?

A structure in coding is a user-defined data type that allows you to store a group of related variables under one name. It is similar to a record in a database, where each variable represents a field in the record.

2. How do I read and write records in a structure?

To read and write records in a structure, you need to first declare the structure and its variables. Then, you can use the dot operator to access and modify the values of the variables within the structure. You can also use loops and arrays to read and write multiple records in a structure.

3. What is the purpose of using structures in coding?

The purpose of using structures is to organize and group related data in a more efficient way. It also allows for easier manipulation and processing of the data, as well as making the code more readable and maintainable.

4. What are some common mistakes when working with structures?

Some common mistakes when working with structures include forgetting to declare the structure, accessing the variables without using the dot operator, and not properly initializing the structure or its variables.

5. Can structures only contain primitive data types?

No, structures can also contain other data types such as arrays, pointers, and even other structures. This allows for more complex and versatile data structures to be created.

Similar threads

  • Programming and Computer Science
2
Replies
66
Views
4K
  • Programming and Computer Science
3
Replies
75
Views
4K
  • Programming and Computer Science
Replies
32
Views
2K
  • Programming and Computer Science
Replies
30
Views
2K
  • Programming and Computer Science
Replies
12
Views
2K
  • Programming and Computer Science
Replies
5
Views
884
  • Programming and Computer Science
Replies
12
Views
1K
  • Programming and Computer Science
3
Replies
89
Views
4K
  • Programming and Computer Science
Replies
6
Views
1K
  • Programming and Computer Science
Replies
5
Views
1K
Back
Top