views:

362

answers:

11

Hi,

I want to copy an int array to another int array. They use the same define for length so they'll always be of the same length.

What are the pros/cons of the following two alternatives of the size parameter to memcpy()?

memcpy(dst, src, ARRAY_LENGTH*sizeof(int));

or

memcpy(dst, src, sizeof(dst));

Will the second option always work? Regardless of the content?

One thing that favors the last one is that if the array were to change, it'll be some house-keeping to update the memcpy()'s.

Thanks

+3  A: 

sizeof(dst) is correct only if dst is an array which size is known at compile time: like int arr[ARRAY_LENGTH] or a C99 variable length array; otherwise it returns the size of a pointer, not the length of the destination array.

To avoid future bug, be consistent and prefer the first form: size of type * length.

Gregory Pakosz
Really? I did int arr[10]; cout << sizeof(arr) << endl; to get 40 which I suspect is not the pointer value.
Tomas
Not if `dst` is an array.
dreamlax
It depends whether dst is pointer or "real" array.
el.pescado
ah yeah it's because it's statically allocated
Gregory Pakosz
The answer is still not correct because in C99 `sizeof` will return the size of a variable length array, which is only known at runtime (usually).
dreamlax
dreamlax > i added it to the answer
Gregory Pakosz
if its declared as int dst[10] , sizeof(dst) returns the size of array
mkamthan
@Gregory Pakosz: Great! +1
dreamlax
+1  A: 

Assuming dst is of type int*, sizeof(dst) will return the size of the pointer itself (i.e. 4 on a 32 bit system, 8 on a 64 bit system), so your second example will only every copy this many bytes, while the first one will correctly use the actual size of the content.

Mark_Carrington
+1  A: 

If you have allocated using malloc you must state the size of the array

int * src = malloc(ARRAY_LENGTH*sizeof(*src));
int * dst1 = malloc(ARRAY_LENGTH*sizeof(*dst));
memcpy(dst1,src,ARRAY_LENGTH*sizeof(*dst));

If you have allocated with a static array you can just use sizeof

int dst2[ARRAY_LENGTH];
memcpy(dst2,src,sizeof(dst2));
Scott Wales
+3  A: 

Will the second option always work? Regardless of the content?

The 2nd option works only if you added back the missing ) and dst is a static array (i.e. of type int[123]).

If dst has unknown size (i.e. int[]), then sizeof dst only returns the pointer size, since dst has been decayed to a pointer. In this case, you need to use sizeof(*dst)*ARRAY_LENGTH.

KennyTM
+1, but I don't think "static" is the correct term for a variable of array type. It could be an automatic, and "static" already has plenty of meanings in C and especially C++. Your "ie" is more like it.
Steve Jessop
+11  A: 

As long as dst is declared as an array with a size, sizeof will return the size of that array in bytes:

int dst[ARRAY_LENGTH];

memcpy( dst, src, sizeof(dst) ); // Good, sizeof(dst) returns sizeof(int) * ARRAY_LENGTH

If dst just happens to be a pointer to the first element of such an array (which is the same type as the array itself), it wont work:

int buffer[ARRAY_LENGTH];
int* dst = &buffer[0];

memcpy( dst, src, sizeof(dst) ); // Bad, sizeof(dst) returns sizeof(int*)
Timbo
+1  A: 

Will the second option always work? Regardless of the content?

It will work only if both conditions are satisfied:

  • dst is regular array, not pointer
  • src and dst are the same size
el.pescado
Or `src` is bigger than `dst`.
dreamlax
A: 

The second version will only copy the first element of the array. EDIT: Sorry, I read sizeof(int) instead of sizeof(dst) in your second method. As suggested by the others, sizeof(dst) works for statically allocated arrays.

Novox
A: 

It depends. Both arr and pointer are arrays, but sizeof() returns only the correct size for arr, which is declared at compile time.

int main() {
        int arr[10];
        int * pointer;
        pointer = (int *) malloc(10 * sizeof(int));
        printf("%d\n", sizeof(arr)); // 40
        printf("%d\n", sizeof(pointer)); // 4 or 8
        free(pointer);
}
Sjoerd
Don't forget about C99 variable length arrays. Their length is determined at runtime but `sizeof` will still work.
dreamlax
A: 

If dst was allocated from the heap (using malloc for example) the second solution will not work. sizeof(dst) will only work when it is know to the compiler. For example, the following example will fail as sizeof(dst) will be equal to the sizeof a pointer (4-8 bytes.)

#define ARRAY_LENGTH 10
int *dst;

dst = malloc(ARRAY_LENGTH*sizeof(int));
memcpy(dst, src, sizeof(dst)); // sizeof dst in this case would be 4 bytes on 32 bit system

This code segment will work every time:

#define ARRAY_LENGTH 10
int *dst;

dst = malloc(ARRAY_LENGTH*sizeof(int));
memcpy(dst, src, ARRAY_LENGTH*sizeof(int)); // sizeof would be 40 bytes
Misk
+3  A: 

If and when you have an array (real one) you can use the sizeof(array) trick, but note that if you refactor the code and push it somewhere where the array has decayed into a pointer (or if the memory was initially allocated in a pointer (malloc/new) you will need to pass a known size.

Ignoring the relative sizes of source and destination, that is, assuming that they are the same for the rest of the discussion, if you are using C++ I would recommend a metaprogramming trick that will give you a typesafe size count for arrays and will fail to compile if you try to use it with pointers:

template <typename T, int N>
inline int array_memory_size( T (&a)[N] ) { return N*sizeof(T); }

That way:

int main() {
   int array[10];
   int *ptr = array;
   int orig[10] = { 0 };
   memcpy( array, orig, array_memory_size(array) ); // ok
   //memcpy( ptr, orig, array_memory_size(ptr) ); // compilation error
}

If at any time you refactor and the code moves to a place where the array has decayed (or you replace an static array for a dynamically allocated one) the compiler will tell you that you need to correct the size calculation.

David Rodríguez - dribeas
I didn't even notice the question was tagged `c++`, +1!
dreamlax
A: 

How about?

memcpy(dst, src, &src[ARRAY_LENGTH] - &src[0]);

This should work even if the size of individual elements was smaller than the size taken by each item in the actual array.

squelart
I'm not clear on which circumstances you think this will work but the original form would not.
Dennis Zickefoose
squelart