[RESOLVED] null terminating character removed
Hi,
I am reading a binary file to string to update it and write it back again. When I add (append) user profiles in the binary file and read it again, every thing is oki because a null terminating character is generated after every user profile.
My problem is when I have for example 3 users and update the first one. When I update the first or second user profile, the null terminating character is removed and the rest of the contents are shifted backward ruining my data when read in binary mode again.
To update a user profile I am using this to modify my string:
Code:
buff.replace((rec*sizeof(sPlayer))-sizeof(sPlayer.szLastword), sizeof(sPlayer.szLastword), word.data());
Re: null terminating character removed
Quote:
Originally Posted by
trojsi
To update a user profile I am using this to modify my string:
Code:
buff.replace((rec*sizeof(sPlayer))-sizeof(sPlayer.szLastword), sizeof(sPlayer.szLastword), word.data());
And what are all these operands, objects, etc (well, we know what sizeof is)
Re: null terminating character removed
Quote:
Originally Posted by
VictorN
And what are all these operands, objects, etc (well, we know what sizeof is)
Okay, this is a hangman game and at the end of each game I want to update the last word guessed not to be chosen next time the user plays in his profile selected.
I am declaring a global struct:
Code:
struct PlayerInfo
{
char szName[20];
short nAge;
int nScore;
char szLastword[20];
};
sPlayer.szLastword is updated everytime after each game.
When user profiles (new users) are added one after each other, the data is updated properly and (null termination applied correctly) and therefore it is written correctly in the binary file so that when it is read again by putting each entry in the correct struct member, the data is displayed perfectly. However when I select a user profile at the beginning of the game, and after I go to modify only the szLastword, in the string (by string replace) - for some reason, the null terminated character is ommited and my data shifts backward causing the fread to view mixed data. I used a function to add white space to the guessedword in order to resize it to sizeof(sPlayer.szLastword). I could observe that the rest of the user profiles all of them shifted by 1 character which I assume is the null terminator because I saw it from the debugging.
Most probably, the string replace is not leaving the null terminator.
Re: null terminating character removed
Quote:
Originally Posted by
trojsi
I am declaring a global struct:
Code:
struct PlayerInfo
{
char szName[20];
short nAge;
int nScore;
char szLastword[20];
};
And what is buff, replace, sPlayer, word, data? :confused:
Quote:
Originally Posted by
trojsi
... when I select a user profile at the beginning of the game, and after I go to modify only the szLastword, in the string (by string replace) - for some reason, the null terminated character is ommited and my data shifts backward causing the fread to view mixed data. I used a function to add white space to the guessedword in order to resize it to sizeof(sPlayer.szLastword). I could observe that the rest of the user profiles all of them shifted by 1 character which I assume is the null terminator because I saw it from the debugging.
If you saw it from the debugging then you should find a way to fix your code!
Note that we cannot do it for you because we have no idea about your file structure.
Re: null terminating character removed
This is update part in the main:
Code:
int main() {
fstream fread; // read and write streams
fread.open(pszFileName, ios_base::in | ios_base::out | ios_base::binary);
string buff;
char tempChar;
while ( !fread.eof() )
{
fread.get(tempChar);
buff += tempChar;
}
fread.clear(); // clear eof flag
fread.close();
test = sizeof(sPlayer.szLastword) - iLength;
for(int i = 0; i < (test-1) ; i++)
{
word.append(" ");
}
buff.replace((rec*sizeof(sPlayer))-sizeof(sPlayer.szLastword), sizeof(sPlayer.szLastword), word.data());
fstream fupdate;
fupdate.open(pszFileName, ios_base::out | ios_base::binary);
if (fupdate.is_open() == true)
{
fupdate.write(buff.data(), buff.length()) << flush;
}
else
{
cout << "Failed to open file " << pszFileName << endl;
}
if (fupdate.fail())
{
cerr << "Error on attempted write" << endl;
exit(EXIT_FAILURE);
}
word.erase(0);
return 0;
}
this is the select user function :
Code:
void SelectUser()
{
// show initial contents
fstream finout; // read and write streams
finout.open(pszFileName, ios_base::in | ios_base::out | ios_base::binary);
int ct = 1;
if (finout.is_open())
{
finout.seekg(0); // go to beginning
cout << "Here are the current contents of " << pszFileName << endl << endl ;
while (finout.read((char *) &sPlayer, sizeof(sPlayer)))
{
cout << ct++ << ": " << sPlayer.szName << " "
<< sPlayer.nAge << " " << sPlayer.nScore << " "
<< sPlayer.szLastword << " "<< endl;
}
if (finout.eof())
finout.clear(); // clear eof flag
else
{
cerr << "Error in reading “ << file << “.\n";
exit(EXIT_FAILURE);
}
}
else
{
cerr << pszFileName << "could not be opened -- bye.\n";
exit(EXIT_FAILURE);
}
cout << "Please Select a User Profile." << endl << endl;
// change a record
cin >> rec;
eatline(); // get rid of newline
if (rec < 0 || rec >= ct)
{
cerr <<"Invalid record number -- bye\n";
exit(EXIT_FAILURE);
}
streampos place = rec * sizeof(sPlayer); // convert to streampos type
finout.seekg(place); // random access
if (finout.fail())
{
cerr << "Error on attempted seek\n";
exit(EXIT_FAILURE);
}
finout.read((char *) &sPlayer, sizeof(sPlayer));
cout << "Your selection:\n";
cout << rec << ": " << sPlayer.szName << " "
<< sPlayer.nAge << " " << sPlayer.nScore << " "
<< sPlayer.szLastword << " "<< endl;
if (finout.eof())
finout.clear(); // clear eof flag
finout.close();
}
and this is the adduser function :
Code:
void Adduser()
{
//USER INPUT //
cout << "Enter your Name: ";
cin >> sPlayer.szName;
cout << endl;
cout << "Enter your Age: ";
cin >> sPlayer.nAge;
cout << endl;
//cout << "Enter your Score: ";
//cin >> newPlayer.nScore;
//cout << endl;
//cout << "Enter your Lastword: ";
//cin >> newPlayer.szLastword;
cout << "The size of Infowrite is " << sizeof(sPlayer) << endl;
ofstream addFile;
addFile.open(pszFileName, ios::out | ios::app | ios_base::binary);
if (addFile.is_open() == true)
{
//addFile.seekg(0, ios::end);
addFile.write((char*) &sPlayer, sizeof(sPlayer));
}
else
{
cout << "Failed to open file " << pszFileName << endl;
}
addFile.close();
ifstream inf(pszFileName);
if (!inf)
{
// Print an error and exit
cerr << "Sry, Test.dat could not be opened for reading!" << endl;
exit(1);
}
inf.seekg(0, ios::end); // move to end of file
rec = ((inf.tellg())/sizeof(sPlayer));
cout << rec << endl;
system("pause");
}
Re: null terminating character removed
1) string::data() does not necessarily append a null character
2) the version of string::replace() you are using does not copy the NULL character.
You need to explicitly do that.
3) One solution (assuming I did the arithmetic correctly) ...
Code:
const int n1 = rec*sizeof(sPlayer)-sizeof(sPlayer.szLastword);
const int n2 = sizeof(sPlayer.szLastword);
buff.replace( n1 , n2 , word.c_str() );
if (word.size() < n2)
buff[n1+word.size()] = 0;
else
buff[n1+n2-1] = 0;
Re: null terminating character removed
Quote:
Originally Posted by
VictorN
And what is buff, replace, sPlayer, word, data? :confused:
If you saw it from the debugging then you should find a way to fix your code!
Note that we cannot do it for you because we have no idea about your file structure.
Do you think my method is correct and suitable for what I want to do, or do you suggest another technique to update profiles in a binary file please?
Re: null terminating character removed
Quote:
Originally Posted by
trojsi
Do you think my method is correct and suitable for what I want to do, or do you suggest another technique to update profiles in a binary file please?
I have no idea how you are going to use these user profiles, but you could consider using registry rather than a binary file.
Or, perhaps, some simple database like MS Access...
Re: null terminating character removed
Quote:
Originally Posted by VictorN
Or, perhaps, some simple database like MS Access...
Or SQLite! :D
Re: null terminating character removed
I don't understand why you're replacing the last word instead of just overwriting it. Use strcpy to write to szLastWord and the NULL will be put there for you.
Re: null terminating character removed
Quote:
Originally Posted by
GCDEF
I don't understand why you're replacing the last word instead of just overwriting it. Use strcpy to write to szLastWord and the NULL will be put there for you.
Cheers, that did the trick :)
Thanks everyone who gave other suggestions. I would have looked into the database thing if I had more time :) ..