4

So at the end of each iteration that I'm doing, I want to make my array be equal to my new array (which I have called array_new). I want every element of array to take the same value as is in array_new but I'm interested in getting my code as quick as possible and so copying everything across element-by-element as this current code does isn't an option:

for(i=0;i<N_a;i++) {
  for(j=0;j<N_b;j++) {
    array[i][j] = array_new[i][j];
  }
}

This takes quite a long time because my values of N_a and N_b are very large. Is there a way to simply change what each of them point to so that I can start my next iteration more quickly? I've tried doing stuff like

 double *temp = *array;
 *array = *array_new;
 *array_new = temp;

in order to try and avoid a slow element-by-element copying procedure but it doesn't seem to work for me. Effectively what I'm trying to make happen is for every element of array point to the corresponding element in array_new but I can't work out how to make the pointers do that.

Any help would be much appreciated!

13
  • 2
    Please edit your post to indicate (via tags) what language you're using. A short but complete example of what you're trying to do would help, too... Commented Nov 11, 2015 at 21:23
  • Edited now, is that more clear? Commented Nov 11, 2015 at 21:28
  • 2
    memcpy if the copy is really needed. If it is just to swap two arrays each time, work with a pointer which will be updated with the currently used array address (double-buffering). Commented Nov 11, 2015 at 21:32
  • 1
    Note that your title indicates "swapping" arrays, but your actual question only implies "copying" one array to another. I think you need to explain what it is you're actually trying to do, and see if anyone can make a better suggestion. Commented Nov 11, 2015 at 21:34
  • 1
    Because in order to calculate the element array_new[i][j], I use the values array[i][j], array[i-1][j], array[i+1][j], array[i][j-1] and array [i][j+1]. So if I overwrite the element in array[i][j] straight away, I would end up using the wrong values when I came to calculate array_new[i][j+1]. Commented Nov 11, 2015 at 21:42

4 Answers 4

9

Since the memory size of your array is fixed, you can simply copy the memory block from one pointer to the other. It doesn't get any faster than that.

In c/c++ you could use memcpy if that is the language you are using. Every language has something equivalent.

Edit: since you confirmed use of c I can get more detailed:

memcpy(array_new,array,sizeof(VARIABLE_TYPE_of_ARRAY_ELEMENT)*N_a*N_b);
Sign up to request clarification or add additional context in comments.

5 Comments

what do you mean with "Since the memory size of your array is fixed"?
'known' was probably a better word. As opposed to passing the array pointer to a function that does not 'know' the actual size of the array.
I bet the optimizer will recognize the loops as a block copy, and use memcpyif that is faster.
Well hopefullly the size of the array is known, otherwise you could not copy the array at all! I guess you mean "known at compile time", and also "declared as an array with a fixed size".
@Martin James That's what I'm trying to do but I can't get it to work. Can you be more specific?
1

Your pointer-swap code is just a little bit off: you are dereferencing your pointers where you shouldn't. After all, the point of that code is to avoid copying data by just swapping two pointers. Here are the correct versions (depending on whether you use a true 2D array or an array of pointers to arrays):

//array is declared as
double (*array)[N_b];

double (*temp)[N_b] = array;
array = array_new;
array_new = temp;

or

//array is declared as
double** array;

double** temp = array;
array = array_new;
array_new = temp;

This is all you need, and it's definitely the fastest possible way to exchange contents of two buffers. Much faster than memcpy()...

6 Comments

Both of these give me a segmentation fault?
@thay2302 Then there's something wrong with your arrays. How did you declare your arrays, how are you allocating them, and how are you destroying them?
Arrays were declared as "double **array, **array_new", they were allocated using "allocate2d(&array,N_a,N_b)" and "allocate2d(&array_new,N_a,N_b)" and are being destroyed using "free2d(&array,N_a)" and "free2d(&array_new,N_a)".
Can you add the full failing code in your question? As I said, the pointer swap is generally sound the way I posted it, so there must be something else wrong with your code if you get a segfault with that pointer swap. Unfortunately, I'll be away from keyboard for the next 20 hours, but I'll certainly take a look tomorrow.
I can't really share the full code as it is for an assignment that I am doing. I've tried to be reasonably unspecific with my questions but I can't realistically post the entire code on here.
|
0

If you just want to swap the pointers, not physically copying the data, and to still be able to access the arrays using indexes, here is an example of how it can be done:

#define N_a 2
#define N_b 3

typedef struct arr 
{ 
    int val[N_a][N_b]; 
} arr;

arr array     = {{{11,12,13},{14,15,16}}};
arr array_new = {{{21,22,23},{24,25,26}}};

int main()
{
    arr *p_array;
    arr *p_array_new;

    p_array     = &array;
    p_array_new = &array_new;
    printf("%d %d\n", p_array->val[1][2], p_array_new->val[1][2]);
    // output: 16 26

    p_array     = &array_new;
    p_array_new = &array;
    printf("%d %d\n", p_array->val[1][2], p_array_new->val[1][2]);
    // output: 26 16
}

6 Comments

Sorry, I'm struggling to follow this. So what is the typedef struct bit doing? What about if I've already got all the elements of my two arrays "array" and "array_new"?
It's just encapsulating the array type definition / dimensions, to help with indexing. If you already have the array data, just initialize the pointers to it: arr *p_array = your_array_address;
So if I have the values already then I should just use "*p_array = &array", "*p_array_new = &array_new", "p_array = &array_new" and "p_array_new = &array"?
It's giving me errors saying "initialization from incompatible pointer type" and "assignment from incompatible pointer type"
I edited my answer to separate the pointer declaration and initialization. To avoid the warning / error, use a cast. For your array, you may not need to use &array, but just array (especially if dynamically allocated). Use p_array = (arr*)array;
|
0

Two answer this, you first need to understand how the array is represented in memory. E.g. see this question: How are multi-dimensional arrays formatted in memory?

So first we need to know if you have a static array or not. If it is a static array then the task is particularly simple, because the data is laid out contiguously in memory. This means that if you have a 2x2 static array, with the content {{9, 8}, {7, 6}} your memory could look like this:

Address  0  1  2  3  4  5  6  7  8
Content  ?  ?  9  8  7  6  ?  ?  ?

In this case your variable which is declared like this:

int[2][2] myArray;

is actually a pointer to address "2" and you can easily copy the whole thing. with memcpy:

int [2][2] newArray;
memcpy(&newArray, &myArray, sizeof(int)*2*2);

Notice that this copies starting from wherever "myArray" points (in my example that is 2) as many bytes as 2*2*sizeof(int). So 4 times the size of int. (For simplicity my example assume a size of one byte for an int, but of course on most systems it is 4 byte).

If you have a dynamic array, then it is a different story. In this case your memory for your array declared like this:

int** myArray;

may well look like this:

Address  0  1  2  3  4  5  6  7  8
Content  9  8  0  6  ?  ?  7  6  ?

Note that the pointer myArray still points to the Address "2". However at the address "2" you don't find the first value, but instead another pointer which points to "0". And here you find the values of the first "row" which are 9 and 8. Next to the address "2" in number "3" you find the pointer to your second "row" which starts at position 6. As you can see, you can still find all your data, but you cannot copy them in a single go. To copy the whole array you will at least need the outer row:

int SIZE_X = 2;
int SIZE_Y = 2;
int** newArray = malloc(sizeof(int*)*SIZE_X);
for(i = 0; i < SIZE_X; ++i) {
  newArray[i] = malloc(sizeof(int)*SIZE_Y);
  memcpy(newArray[i], myArray, SIZE_Y*sizeof(int));
}

This should be faster then using two loops, as memcpy can use more efficient ways to copy than a copy loop.

4 Comments

Shouldn't line #3 be like: int** newArray = (int**)malloc(sizeof(int*) * SIZE_X);? If not, what does this version mean? And when should I use it?
@Rad: You added a cast which has no effect (at least I believe it works without, it is too long ago that I checked) and you used sizeof(int*) instead of sizeof(int). All systems I am aware of implement int* as a plain int, so that would be the same. However I agree that it is better practice to write int* so I changed my answer.
Thanks for the info. My point was sizeof(int*), not the casting. Just to make sure I understand it correctly, what about this one: sizeof(char*). The way I understand sizeof(type*) returns the size of address on the machine (might be 4 or 8), but sizeof(type) returns the size of that specific type (e.g if it's char it returns 1). Is it correct?
@Rad: Yes, that is correct. However an address is usually an int and thus size of address (for any type) is usually the same as an int. That means of course that sizeof(int) == sizeof(int*) but it also means sizeof(char) != sizeof(char*) (depending on the system)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.