I have an array that is already in heap (dynamic) memory. That's not very difficult to understand, but writing it to a file by means of the fwrite()
function can be a bit tricky to understand if it's also a double pointer by a way I see online, which I don't understand logic-wise, which is what I'm trying to clear up here.
int ** A;
A = new int* [randomSize];
A[0] = new int [randomSize];
For example, a single pointer by fwrite()
would look like:
fwrite(&A[0], sizeof(teststruct), 54, dogfile);
So logic-wise, to what I understand, A[0]
is holding a pointer pointing to a de-referenced address. But with fwrite()
, what you want is the address itself, so you put the &
in front of the A[0]
. The contents at that address is then written to the file (correct me if I'm wrong).
So, if that's how a single pointer array looks in the fwrite()
function, I think the logic of a double pointer array should look something like:
fwrite(&A[0][0], sizeof(teststruct), 54, dogfile);
With the 1st [0]
at A[0][0]
as a pointer pointing to another address containing a pointer (the 2nd [0]
in &A[0][0]
), which holds the address for an actual value.
fwrite()
uses that 2nd [0]
which is being de-referenced to print the actual values located at that address out to a file 54 times. So, basically, the &
in front of A[0][0]
should give the address of whatever is being de-referenced so stuff can be printed to the file.
This is how I understand it, based on the logic of how I think the fwrite()
function works.
However, I saw on the Internet a double pointer being used with fwrite()
to print to a file with a single box array (A[0]
) not a double box array (A[0][0]
). It looked like:
fwrite(A[0], sizeof(teststruct), 54, dogfile);
It was explained that this way is how to print all the values to a file from the double pointer array row by row, which makes no sense to me at all because it's a single box (A[0]
). Also, where's the &
symbol that's suppose to be in front of the array?
Could someone who understand this stuff explain the logics of this to me, please?
fwrite()
wants a pointer to (the address of) the data to be written.
In this code:
int A[size];
A
is an array of int
values:
[0] [1] [2] [...]
+---+---+---+-----+
A = | x | x | x | ... |
+---+---+---+-----+
Where A[0]
is the 1st int
in that array, and &A[0]
is a pointer to that 1st int
.
So, this code would work:
fwrite(&A[0], sizeof(int), size, dogfile);
As would this code:
fwrite(A, sizeof(int), size, dogfile);
Because referring to a fixed array by its name alone will yield (ie it decays into) a pointer to its 1st element in various contexts, such as in a function parameter, or a variable assignment.
[0] [1] [2] [...]
+---+---+---+-----+
A = | x | x | x | ... |
+---+---+---+-----+
^
|
fwrite(buffer, ...)
Now, in your code:
int ** A;
A = new int* [randomSize];
A[0] = new int [randomSize];
This is creating an array of int*
pointers, where each int*
points at its own array of int
values:
[0] [1] [2] [...]
+---+---+---+-----+
A = | x | x | x | ... |
+---+---+---+-----+
| | | [0] [1] [2] [...]
| | | +---+---+---+-----+
+---|---|--------> | x | x | x | ... |
| | +---+---+---+-----+
| |
| | [0] [1] [2] [...]
| | +---+---+---+-----+
+---|--------> | x | x | x | ... |
| +---+---+---+-----+
|
| [0] [1] [2] [...]
| +---+---+---+-----+
+--------> | x | x | x | ... |
+---+---+---+-----+
Where:
A[0]
is the 1st int*
in that array, and &A[0]
is a pointer to that int*
A[0][0]
is the 1st int
pointed at by the 1st int*
in A
, and &A[0][0]
is a pointer to that int
So, if you try to write &A[0]
using this code:
fwrite(&A[0], sizeof(int), randomSize, dogfile);
You will write garbage to the file, because A
is an array of int*
pointers, and you are writing the values of those pointers themselves, not the values of the int
s that they point to.
[0] [1] [2] [...]
+---+---+---+-----+
A = | x | x | x | ... |
+---+---+---+-----+
^ | [0] [1] [2] [...]
| | +---+---+---+-----+
| +---------------> | x | x | x | ... |
| +---+---+---+-----+
+---+
|
fwrite(buffer, ...)
This code works, though:
fwrite(A[0], sizeof(int), randomSize, dogfile);
Because A[0]
is a pointer to the 1st int
in another array.
[0] [1] [2] [...]
+---+---+---+-----+
A = | x | x | x | ... |
+---+---+---+-----+
| [0] [1] [2] [...]
| +---+---+---+-----+
+---------------> | x | x | x | ... |
+---+---+---+-----+
^
|
+-----------------+
|
fwrite(buffer, ...)
Using &A[0][0]
will also work, because it is also a pointer to that same int
.
In general, when accessing array elements, brace syntax is just syntax-sugar for pointer arithmetic. Array[Index]
is the same as *(Array+Index)
1, and so &Array[Index]
is the same as &*(Array+Index)
2, which simplifies to just Array+Index
.
1: meaning, take the starting address of Array
, increment it by Index
number of elements (ie by Index
multiplied by sizeof(element type)
number of bytes), and then dereference it to access the element at that address.
2: meaning take the starting address of Array
, increment it by Index
number of elements , dereference it to access the element, and then take the address of that element.