1

I initialise 2 arrays like so:

x = (double*) malloc(sizeof(double)*n);
xPlus1 = (double*) malloc(sizeof(double)*n);

Firstly, I'm not certain of exactly what x or xPlus1 now are, a pointer to an array full of doubles, or an array full of pointers to doubles? :/

The answer to that question probably effects this but if I do these various operations, I can't get it to do what I want, which is just to copy the values from xPlus1 into x. xPlus1 and x do hold different values for each index, because printing after a simple for loop achieves the desired effect:

for (int i = 0; i < n; i++) {
    x[i] = xPlus1[i];
}

But using...

memcpy(x, xPlus1, sizeof(x));
memcpy(x, &xPlus1, sizeof(x)); 

If I access x after either of these in the same function, x is unchanged, kept it's old values.

memcpy(&x, &xPlus1, sizeof(x)); 

I believe this makes x and xPlus1 point to the same memory location by the outputs I get. This is because if I modify x or xPlus1 after this copy, then both values change if I print both arrays.

memcpy(&x, xPlus1, sizeof(x)); 

Dies, exception: Unhandled exception at 0x011D5626 in MPITemplate.exe: 0xC0000005: Access violation writing location 0x00000000.

The ampersand in functions usually indicate a pass by reference, how does this play out when given to memcpy, and what difference does it make if it's going to write to the same blocks in the end?

I'd appreciate if someone could tell me in detail what's going on with these operations, because I can fiddle around making it work but I'd rather understand what's actually happening when these calls are made.

Thanks,

Mike

starlight54
  • 1,051
  • 1
  • 14
  • 20
  • 1
    `xPlus1` is ALREADY a pointer to the malloc'd memory. when you do `&xPlus1` you're getting the address of the pointer itself, NOT the malloc'd memory. e.g. you're not copying into your malloc block, you're copying into wherever the pointer exists and trashing whatever else comes after it. – Marc B Nov 04 '14 at 15:09
  • 3
    have you tried `memcpy(x, xPlus1, n * sizeof(double));`? – mch Nov 04 '14 at 15:10
  • x is a `double` pointer pointing to a memory block allocated for `n` double elements. `xplus1` is also doing the same, but they are in different memory locations. if you print the addresses for all `x`s and `xplus1`s you will see that they are all different. If you use &x as an argument, you are using pointer of pointer, which is not correct. The exception you got is basically telling you that because you were copying and writing to and reading from the same location concurrently, you have access problems. – ha9u63a7 Nov 04 '14 at 15:14
  • I get the pointers of pointers failing then, I guess it's just luck that it doesn't kill the program when I use memcpy(x, &xPlus1, sizeof(x)); I think then that it is using the size of the pointer 'x' when I place sizeof(x) in not the size of the array it points to? I'll try using n * sizeof(double) – starlight54 Nov 04 '14 at 15:18
  • @starlight54 luck is merely a consolation. if you look at the documentation for memcpy, it says `void * memcpy ( void * destination, const void * source, size_t num );` you can clearly see that doing `memcpy(x, xPlus1, sizeof(x))` is good for you. Also, the `const source` bit means that your source data isn't modified, which you ended up doing and having the access violation error when you tried pointer of pointer. – ha9u63a7 Nov 04 '14 at 15:20
  • To all intents and purposes, `memcpy` behaves in exactly the same way, whether you pass it a pointer (which is what `x` and `xPlus1` are), or an array. Simply because arrays _decay into pointers_ when passed to functions. Your pointers point to a block of memory you allocated using `malloc`, that block _can_ be treated as an array, so to copy the contents of the memory `x` points to to `xPlus1`, you simply have to do `memcpy(xPlus1, x, n*sizeof *x);` – Elias Van Ootegem Nov 04 '14 at 15:30
  • BTW: [Don't cast the result of `malloc()`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Elazar Nov 04 '14 at 15:43
  • @Elazar Should have mentioned that I'm writing in C++, I had a read of that question, I don't think I can get around it in C++ as in the header file x is declared as a pointer to a double (double*) – starlight54 Nov 04 '14 at 18:46
  • Fair enough. But then why `malloc()` in the first place? – Elazar Nov 04 '14 at 19:14
  • @Elazar Good point, I see there are other ways to initialise arrays in C++, even with dynamic inputs (although it seems if I want variable sizes not known at run time for both array dimensions, I'd need to loop), is there any advantage over using malloc really though? I've done almost all of my programming in C#, so haven't come across this lower level kind of coding before really. – starlight54 Nov 04 '14 at 20:35
  • There are. Unless you are 100% sure you know exactly what you are doing and why, don't use `malloc()`. Use [`new`](http://www.cplusplus.com/reference/new/operator%20new[]/) - similar to C#, except you have to manage the memory. Better still, use [`std::make_unique`](http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) and [`std::make_shared`](http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared) as appropriate. Even better (whenever reasonable): use default stack allocation and copy the values. Don't use arrays, use `std::vector` and `std::array`. – Elazar Nov 04 '14 at 22:10
  • `new` initialises the object. It's also more type-safe, and helps the allocator to do its job more efficiently. See here: http://www.parashift.com/c++-faq/new-vs-malloc.html – Elazar Nov 04 '14 at 22:11

3 Answers3

4

Both x and xPlus1 should be of type double*. They are pointers to an array of n doubles.

So when you do this:

memcpy(x, xPlus1, sizeof(x));

Since x is just a double*, that only copies sizeof(double*) bytes... which is to say, 8. What you want to do is:

memcpy(x, xPlus1, n * sizeof(*x));

because the type of *x is double, so n * sizeof(*x) will be the total bytes of memory that xPlus1 owns: n doubles.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • I'm just debugging that now, it does make sense, when I check the sizeof(x) it actually shows unsigned int for size 4, but if it then copies 4 bytes to the start of array x from xPlus1, how comes x[0] still coems out the same on printing, shouldn't it destroy it in some way? Unless they just happen to be the same? – starlight54 Nov 04 '14 at 15:26
  • @starlight54 32-bit machine I guess? It depends on what `x[0]` happens to be... regardless, those 8 bytes will be some valid `double` value - perhaps your assignment just happened to not change the lower 4 bytes. – Barry Nov 04 '14 at 15:35
  • Indeed that makes sense, aye it's compiling for 32-bit anyway – starlight54 Nov 04 '14 at 15:42
3

You left out the declarations.
Adding the type,

double* x = (double*) malloc(sizeof(double)*n);

makes it clearer that x is a pointer to a double.
In this particular case, the double x points to is the first element in an array of n doubles.

Something like this:

       (------- n doubles  -----)        
      ___________________________
x ===>| | | | | | | | | | | | | |
      ---------------------------

&x would give you the address of the variable x itself. This is very different from the address that the variable x contains.
(If you have int x = 1;, &x will most likely not be 1.)

memcpy takes two pointers, one for the destination and one for the source, and the size of the memory to copy.
But sizeof(x) doesn't give you the size of the array you allocated; it gives you the size of x, which is a pointer.
(Size is measured in multiples of sizeof(char), which by definition is 1, and sizeof(double*) will be 4 (32 bits) or 8 (64 bits) on most modern machines. So you're copying 32 or 64 bits.)

The size parameter should be the same size that you passed to malloc, if you want to copy the whole thing.
The pointers should be the ones returned from malloc, since these are the memory blocks you want to copy.

So,

memcpy(x, xPlus1, sizeof(double) * n);

should work as expected.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
2

I initialise 2 arrays like so:

No you are not. You did not show x and xPlus1 definition, but if they are arrays like:

double x[10];

your code wouldn't compile. So assuming your code compiles x and xPlus1 are pointers to double. They are close, but not the same thing.

Firstly, I'm not certain of exactly what x or xPlus1 now are, a pointer to an array full of doubles, or an array full of pointers to doubles? :/

Again you should publish their definition and then your question would not make any sense. They are pointers and whatever you assign to them does not change that fact. So they are pointers holding address of memory block size sizeof(double) * n. What will be in that memory depends on you, you can treat it as array of doubles, or something else that has size less or equal to sizeof(double) * n.

But using...

memcpy(x, xPlus1, sizeof(x));
memcpy(x, &xPlus1, sizeof(x)); 

So first line of code copies sizeof( double * ) probably 8 bytes ie one double (which is just coincedence that on 64 bit platform sizeof( double * ) == sizeof( double ) ) from memory pointed by xPlus1 to memory pointed by x. So you basically copied one element and that the same as (if you are on 32 bit platform you would just copy half of double):

x[0] = xPlus1[0]; 

Second line copied memory where pointer xPlus1 located to memory block pointed by x. So you copied double * to double x[0] which does not make much sense:

x[0] = (double) xPlus1;

This code:

memcpy(&x, &xPlus1, sizeof(x)); 

basically did this (just convoluted way):

x = xPlus1;

Following code:

memcpy(&x, xPlus1, sizeof(x)); 

is equivalent to this:

x = (double *)xPlus1[0]; 

which makes x pointer to have garbage address which leads to exception.

So your actual code should be:

memcpy( x, xPlus1, sizeof( double ) * n );
Slava
  • 43,454
  • 1
  • 47
  • 90
  • Thanks for the detailed response, I believe it was co-incidence that since this is compiled for 32-bit, it copied 4 bytes which were in fact the same on xPlus1 and x so appeared to have no effect. I understand malloc more now, you're just pre-allocating some memory, I'm assuming it's by design that it can then use the x[3] notation (for example) to locate what is basically the location of the 4th double in the memory pointed to by x. – starlight54 Nov 04 '14 at 15:53