4

I have a function that swaps 2d arrays in C by using memcpy. I know you can swap pointers but I'd like to do a comparison between copying the arrays and swapping pointers.

Here is my code for it, the 2d arrays are n x n.

void swap_arrays(int n, float old[][n], float new_arr[][n]) {
    float temp[n][n];
    int arr_size = sizeof(float) * n * n;
    memcpy(temp, old, arr_size);
    memcpy(old, new_arr, arr_size);
    memcpy(new_arr, temp, arr_size);
}

It works fine for a 5 x 5 array, but it segfaults when the array is larger (the actual size I need is 4000+, it starts seg faulting at 2000+), at the first memcpy. Any help is appreciated.

user5004049
  • 691
  • 1
  • 8
  • 17
  • 2
    There's a limit to how much you can allocate on the stack (see for example, [this SO question](http://stackoverflow.com/questions/1825964/c-c-maximum-stack-size-of-program)). I'm sure `sizeof(float) * n * n` for values of `n` much smaller than you're wanting to use. Why do you need to swap arrays? Normally, you'd just swap their pointers. And if you do need to swap all their contents, why not use the heap instead of the stack? – lurker Sep 08 '15 at 01:52
  • @lurker In any case if the volume of the data is that large, the OP would have to use the heap to make the program work. It's not as simple as using the stack because arrays are simpler than pointer and `malloc()` in many aspects. But in this case it seems impossible to avoid it. – Iharob Al Asimi Sep 08 '15 at 02:05
  • @iharob that is exactly the point I'm making. The stack is inadequate for data that large and the heap should be used, if even such a swap is necessary in the context. – lurker Sep 08 '15 at 02:07
  • You could have written `sizeof temp` instead of `sizeof(float) * n * n`. – M.M Sep 08 '15 at 02:51
  • you should probably take a look at this command ulimit -a – asio_guy Sep 08 '15 at 04:48

3 Answers3

6

It segfaults with 4000 but it's not memcpy()'s fault. It's because the size exceeds the stack size of your program.

Try to allocate the array dynamically and it should work fine, something like this

float *temp;
temp = malloc(sizeof(float) * n * n);
if (temp != NULL)
{
    /* memcpys here */
}

note that unlike the array, this cannot be accessed with two index notation, to achieve that you need something like

float **temp;
temp = malloc(sizeof(float *) * n);
for (size_t i = 0 ; i < n ; ++i)
    temp[i] = malloc(sizeof(float) * n); /* please check for `NULL' */

You will need free() in both cases, and in the second case your memcpy() will not work as it is. Because each element in temp is a pointer and not a float, so you need first to access the pointer and then copy the data with memcpy().

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • This 2nd approach *is* ineffcient, to just perform a swap. – alk Sep 08 '15 at 05:47
  • I know, I did not propose a swap anywhere. It's just that to make the `tem[i][j]` notation work, this is the way to allocate it dynamically. But perhaps I should say something about the swap part of the OP's code. – Iharob Al Asimi Sep 08 '15 at 12:03
  • 2
    What about allocating the array in the following way: `float (*ptemp)[n][n] = malloc(sizeof *ptemp);` which should perfectly allow indexing like `(*ptemp)[42][42] = 42.42;`. – alk Sep 08 '15 at 12:06
  • @alk, you may even save one level of indirection `float (*ptemp)[n]` would do and then could be accessed as `ptemp[42][42]`. – Jens Gustedt Sep 20 '15 at 12:29
3

Assuming that your problem is stack overflow caused by temp being too large, you can dynamically allocate the space. Since you are just memcpying you don't need to use a typed pointer:

void swap_arrays(int n, float old[n][n], float new[n][n])
{
    size_t sz = sizeof(float[n][n]);
    void *buf = malloc(sz);
    if ( !buf ) exit(EXIT_FAILURE);

    memcpy(buf, old, sz);
    memcpy(old, new, sz);
    memcpy(new, buf, sz);

    free(buf);
}

Of course, you may also have a stack overflow issue if you are writing float a[n][n]; in your calling code. You can get around that by using malloc too, e.g.:

float (*a)[n] = malloc(n * sizeof *a);
float (*b)[n] = malloc(n * sizeof *b);

If you use this latter approach then you can "swap" by swapping the pointers over, without having to copy all the data: void *tmp = a; a = b; b = tmp;

M.M
  • 138,810
  • 21
  • 208
  • 365
0

The answers above are all good. As @iharod point out that your program exceeds the stack size. If you like you can increase the stack size by setting user limits.

If you're running on a Linux host:

alan@~$ulimit -all
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 62978
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 62978
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

As you can see the stack size is 8192k by default.

You can use ulimit command to set stack size like:

alan@~$ulimit -s <stack_size_you_want>.

This is only for illustrate purpose, not a recommended solution.

Alan
  • 469
  • 10
  • 26