Writing to file, char * corrupted data

I am trying to write data to a file so that it can be loaded in the next time around...when I save to file...it works. But when I read from the same file and then try to save...the char * data is corrupted. I though my program was closing before it could save all the date but that is not the case; tried a sleep( 10 ) before exiting the program.

Here is the code for loading from the file...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Screen *Pro::LoadScreenFromFile( ifstream &aStream )
{
	ReportMessage( "Pro: Loading screen from file..." );
	
	string Command      = "";
	string NameID       = "";
	string FileID       = "";
	float PosX          = 0.0f;
	float PosY          = 0.0f;
	int NumberOfButtons = 0;

	Screen *aTempScreen = new Screen( );
	
	//Read IDs Into Strings
	aStream >> NameID;
	aStream >> FileID;
	
	printf( "Pro: Screen -> Name ID: %s\n", NameID.c_str( ) );
	printf( "Pro: Screen -> File ID: %s\n", FileID.c_str( ) );
	
	//Setup Screen IDs
	aTempScreen->SetNameID( NameID );
	aTempScreen->SetFileID( FileID );
}
Button *Pro::LoadButtonFromFile( ifstream &aStream )
{
	ReportMessage( "Pro: Loading button from file..." );
	
	string NameID  = "";
	string FileID  = "";
	string Command = "";
	int Width      = 0;
	int Height     = 0;
	int OffsetX    = 0;
	int OffsetY    = 0;

	Button *aTempButton = new Button( );
	
	aStream >> NameID;
	aStream >> FileID;
	
	printf( "Pro: Button -> Name ID: %s\n", NameID.c_str( ) );
	printf( "Pro: Button -> File ID: %s\n", FileID.c_str( ) );
	
	aTempButton->SetNameID( NameID );
	aTempButton->SetFileID( FileID );
}



Here is the code for saving to the file...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void Screen::Save( ofstream &aStream )
{
	ReportMessage( "Pro: Saving screen to file..." );
	
	char *NameID = const_cast<char*>( GetNameID( ) );
	char *FileID = const_cast<char*>( GetFileID( ) );
	
	printf( "Pro: Screen -> Name ID: %s\n", NameID );
	printf( "Pro: Screen -> File ID: %s\n", FileID );
		
	aStream << ".screen ";
	aStream << NameID << " ";
	aStream << FileID << " ";
}
void Button::Save( ofstream &aStream )
{
	ReportMessage( "Pro: Saving button to file..." );

	char *NameID = const_cast<char*>( GetNameID( ) );
	char *FileID = const_cast<char*>( GetFileID( ) );
	
	printf( "Pro: Button -> Name ID: %s\n", NameID );
	printf( "Pro: Button -> File ID: %s\n", FileID );
	
	aStream << ".button ";
	aStream << NameID << " ";
	aStream << FileID << " ";
}


GetNameID( ) & GetFileID( ) return char *



Console Output -- Working Version

In this version, I am just setting values in the main.cpp and then saving them to the file.
------------------------------------------------------

Pro: Constructing Pro Engine...
Pro: Constructing null screens to fill array...
Pro: Done.
Pro: Constructing texture...
Pro: Constructing screen...
Pro: Done.
Pro: Setting properties of Pro Engine...
Pro: Loading fonts to engine...
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Texture -> File ID: Font.bmp
Pro: Texture -> File ID: Particle.bmp
Pro: Loading texture with alpha channel...
Pro: Texture -> File ID: AmbientDust.bmp
Pro: Done.
Pro: Setting blend state.
Pro: Done.
Pro: Loading texture with alpha channel...
Pro: Texture -> File ID: Clouds2.bmp
Pro: Done.
Pro: Setting blend state.
Pro: Done.
Pro: Setting blend state.
Pro: Done.
Pro: Loading texture...
Pro: Texture -> File ID: Background.bmp
Pro: Done.
Pro: Setting blend state.
Pro: Done.
Pro: Attaching screen to engine...
Pro: Loading texture...
Pro: Texture -> File ID: 9Patch.bmp
Pro: Done.
Pro: Done.
Pro: Finding font...
Pro: Font was found.
Pro: Beginning to attach button to screen...
Pro: Loading texture...
Pro: Texture -> File ID: Button.bmp
Pro: Done.
Pro: Attaching button to screen...
Pro: Done.
Pro: Done.
~ Project closed by user...
Pro: Saving game to file...
Pro: Saving screen to file...
Pro: Screen -> Name ID: TestScreen
Pro: Screen -> File ID: 9Patch.bmp
Pro: Saving buttons inside screen...
Pro: Saving button to file...
Pro: Screen -> Name ID: Test
Pro: Screen -> File ID: Button.bmp
Pro: Done saving button to file.
Pro: Done saving screen to file.
Pro: Done saving game to file.

Console Output -- Non-Working Version

In this version, I am loading the values from the file and then saving them when the program is closed.
------------------------------------------------------

Pro: Constructing Pro Engine...
Pro: Constructing null screens to fill array...
Pro: Done.
Pro: Constructing texture...
Pro: Constructing screen...
Pro: Done.
Pro: Setting properties of Pro Engine...
Pro: Loading fonts to engine...
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Loading font with offset...
Pro: Texture -> File ID: PixelFont.bmp
Pro: Done.
Pro: Texture -> File ID: Font.bmp
Pro: Texture -> File ID: Particle.bmp
Pro: Loading texture with alpha channel...
Pro: Texture -> File ID: AmbientDust.bmp
Pro: Done.
Pro: Setting blend state.
Pro: Done.
Pro: Loading texture with alpha channel...
Pro: Texture -> File ID: Clouds2.bmp
Pro: Done.
Pro: Setting blend state.
Pro: Done.
Pro: Setting blend state.
Pro: Done.
Pro: Loading texture...
Pro: Texture -> File ID: Background.bmp
Pro: Done.
Pro: Setting blend state.
Pro: Done.
Pro: Loading game from file...
Pro: Loading screen from file...
Pro: Constructing screen...
Pro: Done.
Pro: NameID - TestScreen, FileID - 9Patch.bmp
Pro: Loading texture...
Pro: Texture -> File ID: 9Patch.bmp
Pro: Done.
Pro: Loading buttons inside screen...
Pro: Loading button from file...
Pro: Loading texture...
Pro: Texture -> File ID: Button.bmp
Pro: Done.
Pro: Done loading button from file.
Pro: Attaching button to screen...
Pro: Done.
Pro: Done loading screen from file.
Pro: Attaching screen to engine...
Pro: Done.
Pro: Loading blank command...
Pro: Done loading game from file.
~ Project closed by user...
Pro: Saving game to file...
Pro: Saving screen to file...
Pro: Screen -> Name ID:
Pro: Screen -> File ID: 9Pat ?
Pro: Saving buttons inside screen...
Pro: Saving button to file...
Pro: Screen -> Name ID:
Pro: Screen -> File ID: U??V?
Pro: Done saving button to file.
Pro: Done saving screen to file.
Pro: Done saving game to file.


Now the problem has to occur after I load the screen and button from the file...cause from the console output, the filenames are read in correct and the textures are loaded properly. Why does it save the file incorrectly here?
Last edited on
No one has any idea what's wrong here? Any help would be greatly appreciated...can't move forward till I figure out what is going on here....
Can I see what GetName/FileID() do?
Does GetNameID( ) return the characters in some kind of unicode encoding perhaps?
Sure you can...here you go. I just added the overloaded functions with the string...just trying everything at this point.


Setters...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void Screen::SetFileID( const char *aFileID )
{
	FileID = aFileID;
}
void Screen::SetFileID( string aFileID )
{
	FileID = aFileID.c_str( );
}
void Screen::SetNameID( const char *aNameID )
{
	NameID = aNameID;
}
void Screen::SetNameID( string aNameID )
{
	NameID = aNameID.c_str( );
}

void Button::SetNameID( const char *aNameID )
{
	NameID = aNameID;
}
void Button::SetNameID( string aNameID )
{
	NameID = aNameID.c_str( );
}
void Button::SetFileID( const char *aFileID )
{
	FileID = aFileID;
}
void Button::SetFileID( string aFileID )
{
	FileID = aFileID.c_str( );
}


Getters...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const char *Button::GetNameID( )
{
	return NameID;
}
const char *Button::GetFileID( )
{
	return FileID;
}

const char *Screen::GetFileID( )
{
	return FileID;
}
const char *Screen::GetNameID( )
{
	return NameID;
}
Last edited on
Ok, I believe the problem is in your setters. When you set the pointers, you need to create a copy of the string and store it in the pointer, you can't just use = like that. Couldn't you just use std::strings in your Screen class and save yourself the trouble?
Here is the information that is in the file when I load the program up...

.screen TestScreen 9Patch.bmp 0 256 512 256 0 512 512 512 1
.button Test Button.bmp 128 64 64 16

When I load it and save it...it comes out like this...

.screen 9Pat ? 0 256 512 256 0 512 512 512 1
.button U??V? 128 64 64 16
firedraco> I am using char * for a variety of reasons and I like to keep doing so. Is your respond referring to the setters with the string parameter? Your basically saying I need a temp variable when I'm setting the char *?

If so, then why will my program continue to function normally when I am not loading from a file. If I just use the setters in "main.cpp" and then try saving, everything works fine.

Can you elaborate on your solution? Thanks for your input.
I think firedraco is right. You are holding pointers to temporary storage that will not survive the scope of the std::string that it is attached to.

Better to just use std::string throughout. Only use c_str() at the point you need to use it and dont hold a reference (pointer) to it when the std::string goes out of scope.
Last edited on
http://cplusplus.com/reference/string/string/c_str/

c_str() returns a pointer to the data inside the std::string object, not a copy of it. As soon as the std::string object is modified / deleted then so is that string. Because your initial std::string is a local variable, it is deleted as soon as scope is lost to it, which means that the memory is given back to the heap for use by something else.

In your code, you put the data read from the file into a local variable within the Pro::LoadScreenFromFile() function. You then store a pointer to your data in NameID and FileID, but this data is in the local variable. As soon as the function ends, the local variable is deleted and the memory storing it can be used by something else, corrupting the data pointed to by NameID and FileID.

You need to copy the string/array, instead of the pointer to the string.

http://cplusplus.com/doc/tutorial/pointers/
Last edited on
I am in the process of converting all my char * over to std::string. But I have another problem that has been troubling me all day...

When I am using std::string, I cant get it to print in the printf function like it should be able to according to the documentation on printf.

1
2
	printf( "Pro: Button -> Name ID: %s\n", GetNameID( ) );
	printf( "Pro: Button -> File ID: %s\n", GetFileID( ) );


Why can't I do that?
arathalion> I am very familiar with the concept of pointers...I picked up the whole c_str( ) from another forum as I thought I had the same problem...should of taken the time to look through the documentation. Thanks for the links.
If GetNameID( ) returns a std::string then you can write GetNameID( ).c_str() when you need it.

But you can also do this:

 
std::cout << "Pro: Button -> Name ID: "<< GetNameID() << '\n';
Galik> I was just about to ask. What is the proper way to typecast from std::string to char *...For instance when I need to open a file, it takes a char * input...so I just want to do something like...

1
2
3
4
ifstream &in;
string FileID = "File.txt";

in.open( FileID.c_str( ) );
@Leegit: your printf line is fine (assuming that GetNameID() is defined as above). The problem is that your data is corrupt.
@Everyone: Kudos all! I just reworked my program using std::string and it's working like a charm. I should of never doubted the Standard Template Library. Thanks! :D
You can cast like so. but remember it's const for a reason.
never play aorund with a std::string's c_str()

1
2
3
    std::string s("Hello");
    char *p = (char *) s.c_str();
    puts(p);
Topic archived. No new replies allowed.