Lets see:
memset: sets a memory segment to a constant value, so, there is no "overlapping" possible here, because there is just a unique, contiguous, memory segment to "set".
memcpy: you are reading from one memory segment and, well, copying it to another memory segment. If the memory segments coincide at some point, a "overlapping" would occur. Imagine a memory segment starts at address 0x51, and the other starts at address 0x70, and you try to copy 50 bytes from 0x51 to 0x70... at some point, the process will start reading from address at 0x70, and copying to address 0x8F. This is most likely not what you wanted to do.
At a lower level, in assembly, you should be able to find several ways of doing this, including MMX, SSE2 and other SIMD instructions. If you download glibc source code (https://www.gnu.org/software/libc/download.html), you will see some implementations done in assembly.
C is a "high-level" language, but is quite close to assembly, you can get memory address for variables and even for functions, so, it is quite powerful, allowing you to do all kind of things, like reading/writing an array after its "official" end (the OS will stop you once you try to access memory outside your process' memory), so, yes, memory overlapping is totally possible in C. Something like this would create two potentially overlapping memory "segments" (actually, the same segment, that I am manually dividing and assigning to two pointers).
This is a funny-behaving program, it is definitely, and intentionally buggy, just to show what kind of odd things can happen if memory do overlap with memcpy:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *a,*b;
a=malloc(100*sizeof(char));
b=(a+25);
strcpy(a,"This is just a test");
strcpy(b,"And this is another test, longer test string.");
printf("a: %s\nb: %s\n",a,b);
printf("Now, I am copying b in a, and lets see what happen...\n");
memcpy(a,b,75);
printf("a: %s\nb: %s\n",a,b);
}
Save it to a .c file, like test.c, and compile it using gcc, like this:
gcc -O0 -o test test.c
Run it and then try again compiling like that:
gcc -O2 -o test test.c
It will (most likely) behave differently.
Try replacing memcpy with strncpy and see what happen.
I hope the example is useful.
memset
notmemmove
?