Here's a function for making multiple copies of a block of memory in another block of memory. It handles the case when the size of the target is smaller than or not a perfect multiple of the source pattern.
It proceeds by copying the pattern once, twice, four times, eight times, etc. until it can make a last 'massive' copy and fill the target buffer.
The protocol on this site is (apparently) to answer your own question with the improved code rather than edit original question. That makes sense otherwise other answers and feedback may be difficult to understand!
#include <string.h> //This is where memcpy() hangs out. I know! I know!
///Fills a block of memory with a specified pattern.
///The target block starts at pToFill and extends for pToFillSize bytes.
///The source pattern starts at pFillWith and extends for pFillWithSize bytes.
///Will fill the whole buffer including a trailing partial pattern at the end (if necesssary).
///pFillWithSize must not be 0. pFillWith must not be NULL.
///If Either pToFill is NULL or pToFillSize is 0, does nothing and returns without error.
///The area to fill and pattern must not overlap or behaviour is undefined.
void memcopyfill(void*const pToFill,const size_t pToFillSize,void*const pFillWith,const size_t pFillWithSize){
if(pToFill==NULL||pToFillSize==0){
return;//Nothing to do.
}
if(pFillWith==NULL||pFillWithSize==0){
return;//Can do nothing...
}
if(pToFillSize<pFillWithSize){
memcpy(pToFill,pFillWith,pToFillSize);
return;//Short buffer.
}
//The to buffer is bigger so we start with a full copy of pattern.
//Now we keep doubling the copies by copying and copying from the target onto itself.
char*lFillFrom=((char*)pToFill)+pFillWithSize;
size_t lFilledSoFar=pFillWithSize;
char*lFillEnd=((char*)pToFill)+pToFillSize;
while(lFilledSoFar<(lFillEnd-lFillFrom)){//Overflow safe.
memcpy(lFillFrom,pToFill,lFilledSoFar);
lFillFrom+=lFilledSoFar;
lFilledSoFar=lFilledSoFar<<1;//Doubling....
}
//No we can fill the end of the buffer in one final step. Could be half the job.
memcpy(lFillFrom,pToFill,pToFillSize-lFilledSoFar);
}
Can it be bettered?
One use is to fill an array with a default structure. If that is the purpose you don't need the initial fannying about with the short buffer special case.
There is no guarantee that NULL
has a bit-pattern of all zeros so if you wanted to be ultra-ultra portable you ought to be doing something like this to get an array full of NULL
.
I think most people use calloc(.)
and don't even think about it.
If you use it for strings don't forget your null terminator!
Bonus question
Does anyone know of an extant platform where NULL
doesn't have a zero filled bit-pattern?
I half remember one where it was 0xFFF...FF and that was clever because the hardware could detect overflow easily and handle all sorts of wrap-around errors gracefully. I'm damned if I can remember what it was. It may have been a hypothetical example to show why standards should give implementers freedom.