tags:

views:

1146

answers:

9

I wish to copy content of specific length from one buffer to another from a specific starting point. I checked memcpy() but it takes only the length of content to be copied while I want to specify the starting index too. Is there any function which can do this? Or is there any good approach to do it with existing memcpy function.

+2  A: 

Just add the offset to the addresses. For example, if you wanted to copy the buffer starting with the Nth byte:

memcpy( destination, source + N, sourceLen - N );

This will copy to the destination. If you also want to offset the destination - add the offset to both:

memcpy( destination + N, source + N, sourceLen - N );
sharptooth
This will only work for cases where source points to a type which is 1 byte in length. For all other cases you will get an incorrect offset (void simply won't compile)
JaredPar
@JaredPar: True, then some more arithmetic will be required.
sharptooth
+7  A: 

Just add the offset you want to the address of the buffer.

char abuff[100], bbuff[100];
....
memcpy( bbuff, abuff + 5, 10 );

This copies 10 bytes starting at abuff[5] to bbuff.

anon
This is a slightly deceiving example. It only works because char is guaranteed to be 1 byte in length. For all other types where size <> 1, this code will compile but run incorrectly (except void of coures).
JaredPar
@JaredPar: IMHO Neil's answer is entirely correct. The question states "...I want to specify the starting index". Adding a constant to a pointer will take the size of the type being pointed to into account. I.e. an 'int *p = ...; p += 5;' will make 'p' point sizeof(int)*5 bytes further.
Frerich Raabe
char is not mentioned at all in the question, however the term buffer slightly implies it
CsTamas
The code does what I said it does, no matter what the type of abuff.
anon
+1, does what was asked for. It does what you say, which I think is what the OP said. But it's maybe slightly debateable whether that's what the OP wants. A "starting index" is mentioned, but it's conceivable the OP intends that index to be quantified in bytes, as it is mentioned in the same breath as the length. If it's not actually an index into the source array, something with more casts is called for. Could this be what JaredPar is assuming which leads to a conclusion that the array type affects the correctness of the answer?
Steve Jessop
@Frerich, I didn't say Neil's answer was wrong at all merely that I felt it was a bit misleading. The way I read the question was with startIndex being a byte offset and not an index. Most other people read it the other way though
JaredPar
+1  A: 

An index is not required because you can simply update the source pointer by the specified number of bytes. The following wrapper should do the trick

void* memcpy_index(void *s1, const void *s2, size_t index, size_t n) {
  s2 = ((char*)s2)+index;
  return memcpy(s1, s2,n);
}
JaredPar
you are assuming that index is a byte index and n is a byte count. In that case s1 and s2 might as well be typed char *
Indeera
@Indeera, the only assumption I am making is that index, like the size field n, is specified in bytes.
JaredPar
+1  A: 

Simply increase your pointer to your start index.

Example

const unsigned char * src = reinterpret_cast<const unsigned char*>(your source);
unsigned char * dest = reinterpret_cast<unsigned char *>(your dest);
memcpy(dest, src + offset, len);

What about using STL collections to avoid memory access errors?

Edouard A.
A: 

Simply add the index to the address of the buffer, and pass it to memcpy() as the source parameter, e.g. copy from 3rd item of buffer b

char a[10], b[20];
::memcpy(a,b+2,10);

Also take into account the type of items in the buffer, length (3rd) parameter of memcpy() is in bytes, so to copy 4 ints you shall put 4*sizeof(int) - which will probably be 16 (on a 32 bit system. But the type does not matter for the start address, because of pointer arithmetics:

int a[10], b[10];
::memcpy( a+2, b, 2*sizeof(int) );
// a+2 will be address of 3rd item in buffer a
// not address of 1st item + 2 bytes
CsTamas
+5  A: 

I always prefer the syntax

memcpy( &dst[dstIdx], &src[srcIdx], numElementsToCopy * sizeof( Element ) );
Goz
Ditto. You cannot be too verbose when copying memory around at such a low level. Naming your indicies well increases the chance that you will recall exactly what's going on 5 months down the line.
Matt Green
A: 

You could have a function like below.

template<typename T>
T* memcopy_index(T* dst,T* src,unsigned int index, unsigned int element_count)
{
    return (T*)memcpy(dst,src + index, element_count * sizeof(T));
}

It can be used as below:

int src[]={0,1,2,3,4,5,6};
int dst[15];

memcopy_index(dst,src,2,5);    //copy 5 elements from index 2

You have to make sure that destination buffer has enough room to copy the elements.

Indeera
A: 

If you're using c++, it is probably better to use std::copy() instead of memcpy(). std::copy can take pointers just as easily as iterators.

e.g.

int src[20];
int dst[15];

// Copy last 10 elements of src[] to first 10 elements of dst[]
std::copy( src+10, src+20, dst );

As with memcpy(), it's your responsibility to make sure the pointers are valid.

NOTE. If your usage is performance critical you may find a memcpy() as detailed in the other answers quicker, but probably not by much.

Andy J Buchanan
Your implementation is free to implement std::copy using memcpy for plain old objects.
Matt Green
That's nice to know. Thanks. +1
Andy J Buchanan
A: 

This site needs a way to allow anonymous followups in addition to anonymous answers.

Why, more than once, do I see this insane assertion that an "index" must be in units of 1 byte? It's the complete opposite of convention. An "index" is usually symbolic, a measure whose physical byte offset is determined by the size of the element in the array (or vector, which may not even have the physical layout of an array, but then memcpy() is irrelevant too of course).

So, the 5th element in an array has "index" 5, but:

  • If the array is type char, then the byte offset of that "index" is 5.
  • If the array is type short (on x86), then the byte offset of that "index" is 10.
  • If the array is type int (on x86), then the byte offset of that "index" is 20.
  • If the array is type of some large 48-byte object, then the byte offset of that "index" is 240.

Which way is the correct way to access that specific element is a side point. The important part is that you understand the difference, choose one, and make the code correct.


On the meaning of words, I would much rather read:

 void* memcpy_offset(void *s1, const void *s2, size_t offset, size_t n);

than:

 void* memcpy_index(void *s1, const void *s2, size_t index, size_t n);

I find the idea that a completely generic void * could have an "index" to be misleading. (While we're here, "dest" and "source" or "in" and "out" would be much less ambiguous than "s1" and "s2". Code doesn't need as many comments when you pick self-explanatory variable names.)

Matthew