Archived

This topic is now archived and is closed to further replies.

terrence321

Strange file i/o with an array of strings

Recommended Posts

I have the weirdest problem with sending an array of string via fstream... The code below illustrates a simple test program that isn''t working for me. If I run both Part 1 and Part 2 the two strings are sent from SendString, and recieved in RecieveString. But if I comment out all of part 1 (after I wrote Test.Bin by using it once) and run the program, RecieveString[0] and 1 are complete gibberish! Why would it matter whether I ran the first part or not, assuming I''ve already written the file? I''m spent hours on this, its really holding back my project. Any help would be appreciated, thanks. std::string SendString[2]; std::string RecieveString[2]; //======== PART 1: SEND =============== SendString[0]="THIS IS A MESSAGE FOOL0"; SendString[1]="THIS IS A MESSAGE FOOL1"; ofstream astream("TEST.bin", ios::out|ios::binary); int SendSize=SendString[0].size(); astream.write((char *) &SendSize, sizeof(SendSize)); astream.write((char *) &SendString[0], SendSize); astream.write((char *) &SendString[1], SendSize); astream.close(); //======== PART 2: RECIEVE=============== fstream bstream("TEST.bin", ios::in|ios::binary); int RecieveSize; bstream.read((char *)&RecieveSize, sizeof(RecieveSize)); bstream.read((char *)&RecieveString[0], RecieveSize); bstream.read((char *)&RecieveString[1], RecieveSize); bstream.close();

Share this post


Link to post
Share on other sites
std::string is an object. You can't just write raw data from it's address. It could contain members you don't know about. You must use the interface.


astream.write((char*)&SendSize,sizeof(SendSize));
astream.write((char*)SendString[0].c_str(),SendSize);
astream.write((char*)SendString[1].c_str(),SendSize);

And even then it only works if both strings are the same size. You might want to consider just writing the strings in plain ASCII, unless you really need the binary.

And unfortunately, you'll need to use the extraction operator if you want to read right into the string object. I don't know if that works in binary mode, since it's for formatted input. The other way is to read into temporary char arrays.

[edited by - Zipster on July 7, 2003 10:20:46 PM]

Share this post


Link to post
Share on other sites
Well I do need to use the binary format (the strings are just part of a large file.. I just used this small example program to try to isolate the problem), however I could easily change my objects to use char*''s instead of strings, but that hasn''t been working either! I''ve tried both methods, and I always seem to end up with gibberish on the other end.

Share this post


Link to post
Share on other sites
int SendSize=SendString[0].size()+1;

// add the +1 to the end and see if it works. I think the result string object will miss the null terminator in your above code.

[edited by - Nypyren on July 7, 2003 10:34:10 PM]

Share this post


Link to post
Share on other sites
you have to read into a temporary buffer, null terminate it, and then assign it to the std::string. you can just read into the recieve string like that.

Share this post


Link to post
Share on other sites
Great, thanks a lot for the suggestions. I''m in the process of trying each and every one now.. however in switching over to char*''s I compiled virtually the same code as before, and had the same problem! Let me be very explicit in what happens. The code DOES work and DOES send if I include both the send and recieve sections in my program... but if I send, stop the program, and restart the program only with the recieve code, i no longer get the message in my RecieveString char*''s! It''s bizzarre. Anyway, sorry I don''t know how to get one of those fancy code windows:

char *SendString[2];
char *RecieveString[2];

//======================= SEND ==============
SendString[0]="THIS IS A MESSAGE FOOL0";
SendString[1]="THIS IS A MESSAGE FOOL1";
ofstream astream("TEST.bin", ios::out|ios::binary);
int SendSize=strlen(SendString[0]);
astream.write((char *) &SendSize, sizeof(SendSize));
astream.write((char *) &SendString[0], SendSize);
astream.write((char *) &SendString[1], SendSize);
astream.close();

//====================== RECIEVE =============
fstream bstream("TEST.bin", ios::in|ios::binary);
int ReceiveSize;
bstream.read((char *)&ReceiveSize, sizeof(ReceiveSize));
bstream.read((char *)&RecieveString[0], ReceiveSize);
bstream.read((char *)&RecieveString[1], ReceiveSize);
bstream.close();

Share this post


Link to post
Share on other sites
you have to allocate a buffer, you are reading into a random location in ram. i'm suprised you aren't getting an access violation.

std::string aString;

// open file

astream.write((char *)aString.c_str(), aString.size() + 1);

// close file

// you have two options here, you can read the file, and find the exact length of your string, which would be more code than i am willing to write, or you can use a stack buffer temporarily

char Buffer[64];

// open file for reading

int BufPos = 0;
while(BufPos < 64)
{
bstream.read((char *)&Buffer[BufPos], 1);
if(Buffer[BufPos] == 0)
break;
++BufPos;
}
Buffer[63] = '\0';
std::string ReadString = Buffer;


edit: you'll want to null terminate it to be sure

[edited by - billybob on July 7, 2003 12:14:02 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
there are several problems with your code. i''m assuming you are using char*, not std::string, but the same problems will manifest themselves in different ways with std::string

1) your send segment doesn''t do the right thing.

it should read:

astream.write((char *) SendString[0], SendSize);
astream.write((char *) SendString[1], SendSize);

instead of

astream.write((char*) &SendString[0], SendSize);

i expect that this is a holdover from when you had a std::string there, but regardless, that''s one problem with your char* routine

2) you don''t allocate memory for your input

after the line:
bstream.read((char *)&ReceiveSize, sizeof(ReceiveSize));

you must do something like the following:
RecieveString[0] = (char*) malloc(ReceiveSize + 1);
RecieveString[1] = (char*) malloc(ReceiveSize + 1);

the "+ 1" is there because strings must be null terminated.
this part of the code may look a bit different if you are using std::string...
or you may want to read into a temporary buffer and then assign to a std::string, in which case you need to do what i''ve mentioned anyways.

3) you don''t read properly, either

again, this is probably a holdover from when you had std::string, but you have to many pointer indirections in your read line. it should be:

bstream.read(RecieveString[0], ReceiveSize);
bstream.read(RecieveString[1], ReceiveSize);

not:

bstream.read((char*) &RecieveString[0], ReceiveSize);

4) so what if you did use std::string?

it looks like the relevant changes (some have already been mentioned in this thread are)

astream.write((char*)&SendSize,sizeof(SendSize));
astream.write((char*)SendString[0].c_str(),SendSize);
astream.write((char*)SendString[1].c_str(),SendSize);

and for the read routine, you should just read into a temp buffer, as mentioned above, and then assign "std::string read0 = RecieveString[0]"

you might also want to look at what routines are supplied by std::string -- std::vector has "reserve(int size)" and "operator[]" so that you can access it just like a pointer. i don''t belive std::string has both of those, so you may just work with the assignment trick, above.

5) null terminate your strings on input and output

you need to be sure that your string are null terminated. strlen does not count the null character, so if you use it as a length to write out, you''ll miss that. you can still allocate "+1" on your input, and then null terminate it yourself, but it is probably easier to set SendSize = strlen(...) + 1; and let the code take care of it on input, rather then special case the null char ...

6) why did it work when you had both routines going, but not work when you had only the read?

i expect this has to do with memory from your std::strings being on top of one another. the main problem with your initial code was not allocating memory for the strings, and not using "std::string::c_str()" to get the string out.. so strange things happen when you do that.

hope this gets your project rolling again.

Share this post


Link to post
Share on other sites
Great, thanks so much. I''m a bit tired at the moment but I''ll look carefuly at this in the morning. Anonymous poster, yes some of that code was a holdover from using string, but I do think I had some misunderstandins about reading with char arrays that you cleared up (i''ve steered pretty clear of char *''s until now, quite intentionally). It looks like the suggestions I''m given will solve things, but I might still post some feedback in the morning when I implement things. Thanks again.

Share this post


Link to post
Share on other sites