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.

5
  • 2
    There's a limit to how much you can allocate on the stack (see for example, this SO question). 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? Commented Sep 8, 2015 at 1: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. Commented Sep 8, 2015 at 2: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. Commented Sep 8, 2015 at 2:07
  • You could have written sizeof temp instead of sizeof(float) * n * n. Commented Sep 8, 2015 at 2:51
  • you should probably take a look at this command ulimit -a Commented Sep 8, 2015 at 4:48

3 Answers 3

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().

Sign up to request clarification or add additional context in comments.

4 Comments

This 2nd approach is ineffcient, to just perform a swap.
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.
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, you may even save one level of indirection float (*ptemp)[n] would do and then could be accessed as ptemp[42][42].
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;

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.