I'm developing a small database application that can add records to a file, but also modify them in a few ways. It keeps the records in a temporary object of my class PersonInfo.
The problem now is that it doesn't want to display things correctly, it seems to only be able to save the last record, then it replaces the previous records with weird characters.

OK, this is my code:

The PersonInfo class header file


#ifndef _PERSONINFO_H_
#define _PERSONINFO_H_

class PersonInfo {
private:
string name, city, country;
int age;
public:
PersonInfo();
~PersonInfo();
void DisplayDatabase(int ct);
void DisplayChangedDatabase(int ct, int whoHasStar);
void ChangePersonData(string Name, int Age, string City, string Country);

};

#endif

The PersonInfo class declaration file


#include <iostream>

using namespace std;

#include <iomanip>
#include <string>
#include "personInfo.h"


PersonInfo::PersonInfo() {
}

PersonInfo::~PersonInfo() {
}

void PersonInfo:: DisplayDatabase(int ct) {
int checkCtValue;

if (ct > 8)
checkCtValue = 19;
else
checkCtValue = 20;

cout << (ct + 1) << ": " << setw(checkCtValue) << name
<< setw(6) << age << setw(18) << city
<< setw(18) << country << "\n";
}

void PersonInfo:: DisplayChangedDatabase(int ct, int whoHasStar) {
int checkCtValue, starOff;

if (ct > 8)
checkCtValue = 19;
else
checkCtValue = 20;

cout << (ct + 1) << ": " << setw(checkCtValue) << name;

if ((ct + 1) == whoHasStar) {
cout << "*";
starOff = 5;
}
else {
cout << "";
starOff = 6;
}

cout << setw(starOff) << age << setw(18)
<< city << setw(18) << country << "\n";
}

void PersonInfo::ChangePersonData(string Name, int Age, string City, string Country) {
name = Name;
age = Age;
city = City;
country = Country;
}


If you wonder what whoHasStar is, it's a star printed after the name of the person, if that record has been edited.

So far so good, but the problem lies in my addRecord() function, the ability to add records to the end of the file.
Here's this code:

My addRecord() function


#include <iostream>
using namespace std;


#include <windows.h>
#include <string>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include "personInfo.h"


inline void eatline() { // I've never really understood what this does,
// and where in the code I need it, someone who knows?
while (cin.get() != '\n')
continue;
}


PersonInfo pInfo; // Temporary record keeper, the thing between reading and writing
const char *pFile = "personDB.dat"; // Main database file

fstream pfInOut; // File I/O-stream

int whoHasStar = 0; // Record number that has the star


////////////
// code
////////////


void addRecord() { // Adds one or more posts to the end of file

string Name, City, Country;
int Age;
char _Name[20], _City[20], _Country[20]; // This is because cin.get() won't work with strings! Any other workaround?


int ct = 0; // Record counter


pfInOut.open(pFile, ios_base::in | ios_base::ate | ios_base:: out | ios_base::app | ios_base::binary); // Is this the correct way of opening the file? Is ios_base::ate necessary?


if (pfInOut.is_open()) {

pfInOut.seekg(0);

cout << "\nThis is the current contents of the file \"" << pFile << "\":\n\n";
cout << "Rec #" << setw(18) << "Name" << setw(6) << "Age"
<< setw(18) << "City" << setw(18) << "Country" << "\n\n";

while (pfInOut.read((char *) &pInfo, sizeof pInfo)) { // Loops through the file, reads a record, and displays it, then continues to the next one
pInfo.DisplayDatabase(ct); // Should I use sizeof pInfo or sizeof PersonInfo?
ct++;
}
if (pfInOut.eof())
pfInOut.clear();
else {
cerr << "Error while reading file \"" << pFile << "\".\n";
exit(1);
}
}

else {
cerr << "Couldn't open \"" << pFile << "\".\n";
exit(2);
}

if (pfInOut.eof())
pfInOut.clear();


cout << "\nEnter the name of the person: ";
eatline(); // Is this where I should put eatline()?
cin.get(_Name, 20);
//eatline(); // ... or should I put it here...
//while (_Name[0] != '\0') { // This is a problematic area, my app seems to be skipping this loop, so I've removed this while loop, why is it skipping it?
//eatline(); // ... or here?
cout << "Enter the age of the person: ";
cin >> Age;
eatline(); // Needed?
cout << "Enter the name of the new city: ";
cin.get(_City, 20);
eatline(); // Needed?
cout << "Enter the country: ";
cin.get(_Country, 20);
eatline(); // Needed?


Name = _Name; // Okidoki, defining char[] info to a string...
City = _City; // And here...
Country = _Country; // ... and here


pInfo.ChangePersonData(_Name, Age, _City, _Country);


pfInOut.write((char *) &pInfo, sizeof pInfo) << flush; // Writing the record to the end of file
if (pfInOut.fail()) {
cerr << "Error while attempt to write - bye.\n";
exit(5);
}

whoHasStar = ct + 1;

pfInOut.close();


viewChangedDatabase();

//}
}

It will display the records incorrectly, only showing the last one in a proper way.
Here is a screen of how it looks like:

[img]http://gabid001.thg.se/wrong.bmp[/img]


So there u have it, anyone who might know the solutions to the various problems here?

Help really appreciated, it means a lot to me to be able to finish this application.

Thanx in advance, guys!

/silkfire

Recommended Answers

All 2 Replies

Your biggest problem is trying to use stream.read() and stream.write() with a non-POD type. Because the string class is not a trivial class, and your PersonInfo struct has at least one of them, read and write are only guaranteed to cause undefined behavior. You would be better off defining a function that extracts and inserts fields from/to the database manually. Using unformatted binary I/O is tricky to get right and has a lot of restrictions in C++.

Okay... so how should I do it with chars? I have problems with how I should create my function that takes char arrars (char[X]) as parameters...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.