Hello,
I'm writing a function that updates an array. That is, given an
array, change each element.
The trick is this: I can't change any elements until I've processed
the entire array. For example, the manner in which I update element 1
depends on several other (randomly numbered) elements in the array.
So, I can't change an element until I've figured out how every element
changes.
To do this, I am simply creating a duplicate array and writing the new
values in that array. When I'm done, I copy the new array over the
old one. My question is, what's the best way of doing this?
The (seemingly) naive way [to put the new values back into an
existing array] is to copy the elements from the new over
the old array one-by-one. ...
That will indeed work:
double h[SIZE];
void update()
{
double hnew[SIZE];
// do stuff to populate hnew
memcpy(h,hnew,SIZE*sizeof(double));
}
Or, simpler:
memcpy(h, hnew, sizeof h);
However, since arrays are pointers ...
But arrays are not pointers. You might as well start with "since
cows are hamburger". Cows are not hamburger, and a pile of ground
beef cannot do everything a cow can do.
It *is* true that the "good stuff" you get with arrays is basically
as useful as the "good stuff" you get with pointers. If you just
want the protein, the bones and other bits in a cow just get in
the way. But while you only may *want* the one part or the other,
never mistake the one *for* the other.
it seems like it'd be much more
efficient to just change where the pointer is pointing.
You can do that, provided you have a pointer (not an array) *and*
sufficient memory to which the pointer can point.
For example:
double h[SIZE];
void update(double* hnew)
{
// do stuff to populate hnew
delete(h);
h = hnew;
}
This requires relying on the caller to allocate memory for hnew.
This also does not work, because h is still an array. C forbids
the assignment (h is not a "modifiable lvalue", in standard-ese).
Note that if you use a pointer, it takes *more* space than if
you just use an array, because the pointer itself requires space,
and you still need just as much space as you used to have in the
array. Consider the two versions diagrammatically:
(A) array version:
+---------------------------------+
| big chunk of memory |
+---------------------------------+
(B) pointer version:
+---------------------------------+
| big chunk of memory |
+---------------------------------+
^
| +---+
+-------------------|-* | tiny little pointer
+---+
Is the pointer method better?
"Better" is subjective; but if your application currently spends
a lot of time copying memory from hnew to h, and you can remove
all the "copy" time, your application may run noticeably faster.
Does anyone have any better ideas?
"Better" is subjective...
Note that regardless of which version (array or pointer) you have
above, you *also* need, at least temporarily, a second "big chunk
of memory" (hnew -- whether this is another array, or a pointer
plus a chunk of memory it points to) to hold all the new values.
If there is no reason not to leave that big chunk of memory around
all the time, you can simply make *two* arrays:
(C) two-array version:
+---------------------------------+
| big chunk of memory |
+---------------------------------+
+---------------------------------+
| big chunk of memory |
+---------------------------------+
Now you just need a way to select which of the two arrays to use.
You can do this with a pointer, and point it to either array, or
with a simple two-valued variable:
double array0[SIZE], array1[SIZE];
int which_array = 0;
...
which_array = 1 - which_array; /* from 0 to 1, or 1 to 0 */
Of course, writing:
if (which_array == 0)
... array0
...
else
... array1 ...
is a pain -- but it is also unnecessary. Just make your two arrays
into a single variable, by using an array of two arrays:
(D) array of two arrays version:
+---------------------------------+
| big chunk of memory |
+---------------------------------+
| big chunk of memory |
+---------------------------------+
double array[2][SIZE];
int which_array = 0;
...
which_array = 1 - which_array; /* from 0 to 1, or 1 to 0 */
... array[which_array] ...
Alternatively, use that "tiny little pointer", along with the arrays.
This works with both arrangements (C) and (D):
(C):
which_array = 1 - which_array;
ptr = (which_array == 0 ? &array0[0] : &array1[0]);
(D):
which_array = 1 - which_array;
ptr = &array[which_array][0];
Instead of actual arrays, of course, if you have pointers, you can
use malloc():
#include <stdlib.h>
double *mem_blob_0, *mem_blob_1;
...
mem_blob_0 = malloc(SIZE * sizeof *mem_blob_0);
mem_blob_1 = malloc(SIZE * sizeof *mem_blob_1);
or an array of two pointers:
double *mem_blob[2];
...
mem_blob[0] = malloc(SIZE * sizeof *mem_blob[0]);
mem_blob[1] = malloc(SIZE * sizeof *mem_blob[1]);
and/or you can get twice as much memory with a single malloc():
double *mem_blob_of_twice_the_size;
...
mem_blob_times_two = malloc(2 * SIZE * sizeof *mem_blob_times_two);
after which something like:
double *p = &mem_blob_times_two[SIZE];
/* or: = mem_blob_times_two + SIZE; */
gets you the "second half".
Of all these methods, which one is the best? "Best" is subjective....