1.函数声明
char* strcpy(char *d_s, const char *s_s);
char* strcpy(char *d_s, const char *s_s, size_t n);
void* memcpy(void *d_s, const void *s_s, size_t n);
void* memmove(void *d_s, const void *s_s, size_t n);
2.函数理解和区别
strcpy:拷贝s_s指向的内容到d_s,直到遇到字符串结束符'\0',并返回d_s
strncpy:拷贝s_s指向的内容到d_s,拷贝n个字节,并返回d_s
memcpy:拷贝s_s指向的内容到d_s,拷贝n个字节,并返回d_s
memmove:拷贝s_s指向的内容到d_s,拷贝n个字节,并返回d_s
这几个函数,strcpy没有考虑到d_s溢出的情况,程序员只能自己避免这种情况,其余的函数都有参数n做了一个限制
strcpy是遇到结束符之后就不拷贝了,strncpy是拷贝n字节,受结束符影响,但是不会在结束符停止,而是继续剩余个结束符
memcpy传入的是void*,strcpy和strncpy是char*,所以对于其他类型的数据(数组、结构体等),要用memcpy拷贝,strcpy和strncpy是不行
不考虑性能问题,memmove应该是最好的,它即考虑到了安全(溢出),通用性(数据类型),还考虑到了地址重叠,其余3个函数,对于地址重叠的情况是不考虑的
对于前面2种情况,4个函数拷贝没有问题,但是对于第3种情况,只有memmove才能正确拷贝
所有函数对于传入的源都用了const限制,这个是很好编程习惯,防止源被修改
3.函数个人实现
下面这些函数的实现和某些系统标准库的实现还是有差别的,在Ubuntu里面,strcpy好像是先计算长度,再把要拷贝的内容复制到一个局部buffer里面,memcpy应该和我的实现应该一样,一个字节一个字节的拷贝,但是应该还有更细节的东西(拷贝效率按字节还是按字拷贝和字节对齐),具体还要看源码
char* my_strcpy(char *d_s, const char *s_s)
{
if ((NULL == d_s) || (NULL == s_s))
{
assert(0);
}
char *temp = d_s;
while((*d_s++ = *s_s++) != '\0');
return temp;
}
char* my_strncpy(char *d_s, const char *s_s, size_t n)
{
if ((NULL == d_s) || (NULL == s_s))
{
assert(0);
}
char *temp = d_s;
while(n--)
{
if ((*d_s = *s_s) != '\0')
{
s_s++;
}
d_s++;
}
return temp;
}
void* my_memcpy(void *d_s, const void *s_s, size_t n)
{
if ((NULL == d_s) || (NULL == s_s))
{
assert(0);
}
char *temp = (char*)d_s;
const char *ss_s = (char*)s_s;
while(n--)
{
*temp++ = *ss_s++;
}
return d_s;
}
void* my_memmove(void *d_s, const void *s_s, size_t n)
{
if ((NULL == d_s) || (NULL == s_s))
{
assert(0);
}
char *temp = (char*)d_s;
const char *ss_s = (char*)s_s;
if ((s_s >= d_s) || d_s - n >= s_s)//1, 2
{
printf("not\n");
while(n--)
{
*temp = *ss_s;
temp++;
ss_s++;
}
}
else //3
{
printf("yes\n");
temp = temp + n - 1;
ss_s = ss_s + n - 1;
while(n--)
{
*temp = *ss_s;;
temp--;
ss_s--;
}
}
return d_s;
}