2

I'm trying to copy one 2D array to another using memcpy. My code:

#include <stdio.h>
#include <string.h>

int print(int arr[][3], int n) {
    for (int r = 0; r < 3; ++r) {
        for (int c = 0; c < n; ++c)
            printf("%d ", arr[r][c]);
        printf("\n");
    }
}

int main() {
    int arr[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    int arr_copy[3][3];

    print(arr, 3);
    memcpy(arr_copy, arr, 3);
    print(arr_copy, 3);

    return 0;
}

Result:

1 2 3 
4 5 6 
7 8 9 
-1426063359 32726 -1902787872 
22012 0 0 
-1902788416 22012 48074240

I also tried:

for (int i = 0; i < 3; ++i)
    memcpy(arr_copy[i], arr[i], 3);

Why above codes don't work and how I should correct?

Elgin Cahangirov
  • 1,932
  • 4
  • 24
  • 45
  • 1
    The third argument to `memcpy()` is the number of bytes to copy. Why are you passing only 3? – Barmar Sep 25 '21 at 19:21
  • 3
    `memcpy(arr_copy, arr, sizeof(arr_copy))` – Barmar Sep 25 '21 at 19:22
  • 3
    `memcpy(arr_copy, arr, sizeof arr);` should do it - or `for (int i = 0; i < 3; ++i) memcpy(arr_copy[i], arr[i], sizeof arr[i]);` for the second version – Ted Lyngmo Sep 25 '21 at 19:23
  • @TedLyngmo does second version have any benefit over the first one? – Elgin Cahangirov Sep 25 '21 at 19:32
  • @ElginCahangirov My C knowledge is a bit dated, but I suspect that the first version technically has UB (_undefined behavior_) while the second version does not. – Ted Lyngmo Sep 25 '21 at 19:32
  • 3
    @TedLyngmo Can't see any UB in the first (simpler) version. Each array will occupy contiguous memory. – Adrian Mole Sep 25 '21 at 19:42
  • @AdrianMole I know they occupy contiguous memory and I can't swear that it's UB in C. It is in C++ though. – Ted Lyngmo Sep 25 '21 at 19:43
  • 1
    @Ted Nope. Still don't understand. *Why* is it UB (in C++)? – Adrian Mole Sep 25 '21 at 19:44
  • @AdrianMole In C++ you aren't allowed to access an array out of bounds. Any attempt to do so has undefined behavior - even in this case where the first inner array is known to be followed by the 2 other arrays. – Ted Lyngmo Sep 25 '21 at 19:45
  • 1
    @TedLyngmo I don't think there's any out-of-bounds here. Just like `memcpy` works for an array of `int`s, it works for an array of `int [3]`s, and both should be contiguous (but I'm not 100% sure). – mediocrevegetable1 Sep 25 '21 at 19:46
  • @mediocrevegetable1 The out of bounds access happens when you copy the first byte from `arr[0][3]`. I've never seen it actually fail, but, in C++, it has UB. – Ted Lyngmo Sep 25 '21 at 19:48
  • Hmm - interesting. Maybe worth a C++/Language-Lawyer question. – Adrian Mole Sep 25 '21 at 19:50
  • @AdrianMole [This](https://stackoverflow.com/questions/25139579/2d-array-indexing-undefined-behavior) seems to touch on the subject. – Ted Lyngmo Sep 25 '21 at 19:52
  • 1
    @TedLyngmo I don't think the `arr[0][3]` thing applies. By that logic, I think copying the second `int` of an `int` array through `memcpy` would be UB as well. `int [3]` is simply the type of `arr`'s elements, and the bounds of `arr` as a whole in bytes should be `sizeof (int [3]) * 3`. I'm probably missing something though :/ – mediocrevegetable1 Sep 25 '21 at 19:55
  • @mediocrevegetable1 The second `int` in an `int` array (of at least 2 `int`s) is within the array bounds and copying it has defined behavior. Accessing `int[0][4]` in a `int[3][3]` is out of bounds of the first inner array though. – Ted Lyngmo Sep 25 '21 at 19:59
  • 1
    @AdrianMole yes, but also arrays declared this way are contiguous and one object. I see no way to get UB from `memcpy(arr_copy, arr, sizeof arr)` as long as `arr_copy` is sufficient size. – Neil Sep 25 '21 at 20:00
  • @Ted Maybe. But the `memcpy` function/call doesn't do any array indexing - it's just given two `void*` pointers and copies memory from one to the other. – Adrian Mole Sep 25 '21 at 20:00
  • @TedLyngmo I guess you're right. I still don't entirely agree since we're talking about `arr` as a whole, no subarrays or anything, and since we're `memcpy`ing only `sizeof arr` bytes it should all be in the bounds of `arr`, but I guess we are just going in circles now. – mediocrevegetable1 Sep 25 '21 at 20:01
  • @AdrianMole I can't say for sure if that matters in C. In C++ it doesn't. You get a pointer to the first `int[3]` and any access out of its range has UB. I haven't found any exception to that in the C++ standard. – Ted Lyngmo Sep 25 '21 at 20:03
  • 1
    @mediocrevegetable1 `struct obj { int arr[3][3]; } a_2d_arr, a_copy;` and `memcpy(&a_copy, &a_2d_arr, sizeof a_2d_arr);` should be a safe workaround. – Ted Lyngmo Sep 25 '21 at 20:05
  • 2
    @Ted - I raised the issue in a [new question](https://stackoverflow.com/q/69329884/10871073). Hope you don't mind that I quoted you. (Also, what ***is*** UB is the `int print` function not returning anything!) – Adrian Mole Sep 25 '21 at 20:45
  • @AdrianMole No, I don't mind at all. I read a description of _why_ it's UB a long time ago but I haven't found it since then so I hope that whomever wrote that description shows up to answer :-) – Ted Lyngmo Sep 26 '21 at 02:19
  • @AdrianMole That certainly became a popular question :-) I'm glad to have gotten my misconceptions straightened out. – Ted Lyngmo Sep 27 '21 at 12:28
  • @TedLyngmo Yeah - I'm surprised how much debate it triggered. There's some good stuff in the answers ... I'll need to have a thorough read (or two) before deciding which one to award the "Green Tick" to ... – Adrian Mole Sep 27 '21 at 12:29
  • @AdrianMole Yes, there are a lot of angles and standards quoting going on - and I noticed a few more answers have come in. Exciting stuff. – Ted Lyngmo Sep 27 '21 at 12:33

1 Answers1

10

The size is in bytes, so you copy only 3 bytes - not even one integer.

memcpy(arr_copy, arr, 3);

You can see how big your array is by printing its size in bytes:

printf("sizeof(arr) = %zu\n", sizeof(arr));

So the correct memcpy code should be:

memcpy(arr_copy, arr, sizeof(arr));

Same error here:

memcpy(arr_copy[i], arr[i], 3);

It has to be:

memcpy(arr_copy[i], arr[i], sizeof(arr[i]));
Yun
  • 3,056
  • 6
  • 9
  • 28
0___________
  • 60,014
  • 4
  • 34
  • 74