prgDevelop
prgDevelop

Reputation: 1587

Why does binary saving of array in a file works? [C++]

C++ newbie here.

I'm trying to figure out the following line that writes a buffer into a file:

fOut.write((char *)&_data, sizeof(_data));

_data = array of integers...

I have a couple of questions:

  1. Is &_data the address to the first element of the array?
  2. Whatever address it is, does that mean that we only save the address of the array? then how come I still can access the array after I free it?
  3. Shouldn't I pass sizeof(_data)*arrLength? what is the meaning of passing the size of int (in this case) and not the size of the entire array?
  4. What does casting into char* mean when dealing with addresses?

I would really appreciate some clarifications.

Upvotes: 1

Views: 625

Answers (6)

sleske
sleske

Reputation: 83609

is &_data the address to the first element of the array?

Yes, it is. This is the usual way to pass a "reference" to an array in C and C++. If you passed the array itself as a parameter, the whole array contents would be copied, which is usually wasteful and unnecessary. Correction: You can pass either &_data, or just _data. Either way, the array does not need to be copied to the stack.

whatever address it is, does that mean that we only save the address of the array? then how come I still can access the array after I delete him from the memory?

No, the method uses the address it gets to read the array contents; just saving the memory address would be pointless, as you point out.

Shouldn't I pass sizeof(_data)*arrLength? I mean... what is the logic of passing the size of int (in this case) and not the size of the entire array?

No, sizeof(_data) is the size of the array, not of one member. No need to multiply by length.

What does casting into char* means when dealing with addresses?

Casting to char* means that the array is accessed as a list of bytes; that's necessary for accessing and writing the raw values.

Upvotes: 0

Ben Voigt
Ben Voigt

Reputation: 283634

Contrary to your comment, the array must be automatic or static storage duration in order for sizeof to work.

  1. It should be just (char*)_data. The name of an array implicitly converts to a pointer to the first element.

  2. No, write expects a pointer, and stores the content found at that location, not the location's address.

  3. No. Since _data is an array, sizeof (_data) is the cumulative size of all elements in the array. If _data were a pointer (such as when an array is dynamically allocated on the heap), you would want numElems * sizeof(_data[0]). Multiplying the size of a pointer by the number of elements isn't helpful.

  4. It means that the content at that address will be treated as a series of individual bytes, losing whatever numeric meaning it might have had. This is often done to perform efficient bulk copy of data, either to and from a file, or with memcpy/memmove. The data type should be POD (plain old data) or you'll get unexpected results.

If _data is a pointer to an array allocated from the heap, as your comment suggests, then the code is badly broken. In that case, you are saving just the address, and it may appear to work if you load the file back into the same instance of your program, but that's just because it's finding the data still in memory at the same address. The data wouldn't actually be in the file, and if you re-started the program before loading the file, you'd find that the data was gone. Make the changes I mentioned in both (1) and (3) in order to save the complete array regardless of whether it's allocated automatic, static, or dynamically.

Upvotes: 6

user418748
user418748

Reputation:

What does casting into char* means when dealing with addresses?

Imagine this simple example

int x = 12;
char * z = (char *)&x;

And assume an architecture where int is 4 bytes long. From the C++ Standard sizeof(char)==1.

On the expression char * z the char * part, you could say that is being used for pointer arithmetic

on the Second line of the example I gave, what happens is that z now points to the first (out of 4 bytes) that x has. Doing a ++z; will make z point to the Second Byte of the (in my example) 4byte int

You could say that the left part of a declaration is used for pointer arithmetic, to simplify things. a ++(char *) would move you by one byte, while a ++(int *) would move you by the corresponding number of bytes int occupies on the memory.

Upvotes: 1

AK_
AK_

Reputation: 8099

read this : http://www.cplusplus.com/reference/iostream/ostream/write/

  1. should be.
  2. if you call "fstream.write(a,b)" then it writes b bytes starting from location a into the file (i.e. what the address is pointing at);
  3. it should be the size in bytes or chars .
  4. not much, similar to casting stuff to byte[] in more civilized languages.

By the way, it will only work on simple arrays with simple values inside them...

i suggest you look into the >> << operators .

Upvotes: 0

BlackBear
BlackBear

Reputation: 22979

1) Yes, &_data is the address of the first element of your array.
2) No, write() writes the number bytes you have specified via sizeof(_data) starting at address &_data
3) You would pass sizeof(int)*arrLength if _data is a pointer to an array, but since it is an array sizeof() returns the correct size.
4) don't know. ;)

Upvotes: 0

Sogger
Sogger

Reputation: 16132

  1. Yes
  2. No, write uses this address as the first location, and reads through sizeof(_data) writing the whole array
  3. sizeof(_data) will return the size of the entire array not the same as sizeof(int)
  4. Means the data will be read byte by byte, this is the pointer required by write as it writes in binary format(byte by byte)

Upvotes: 0

Related Questions