memcpy/memmove/strcpy/strncpy区别
1.函数原型
各函数原型如下:
void *memcpy(void *str1, const void *str2, size_t n);
void *memmove(void *str1, const void *str2, size_t n);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
2.函数功能
- memcpy: 从存储区 str2 复制 n 个字节到存储区 str1;
- memmove: 从存储区 str2 复制 n 个字节到存储区 str1;
- strcpy: 把 src 所指向的字符串复制到 dest;
- strncpy: 把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
3.memcpy和memmove区别
memcpy和memmove都是 从存储区 str2 复制 n 个字节到存储区 str1,两者的主要区别在于: 源存储空间和目标存储空间重叠时,memcpy可能会出错,而memmove不会出错。
源存储空间和目标存储空间重叠,有两种情况,分别如图1和图2所示:
举例说明,假设str1[6] ,str2[6] = {11,12,13,14,15,16}。按照正常逻辑,在拷贝时,str1[i] =str2[i],i=0,1,…,n。拷贝完成后,目标存储区域str1应该为{11,12,13,14,15,16}。
图1所示是目标存储空间在前,源存储空间在后,两者有重叠部分。这种情况下使用memcpy和memmove是一样的,结果都正确。
图2所示是源存储空间在前,目标存储空间在后,两者有重叠部分。这种情况下使用memcpy就会产生如图2所示的结果,目标存储区域str1变成为{11,12,13,14,11,12},出错。而使用memmove就能正确拷贝数据,因为memmove会判断这种重叠情况,如果出现这种重叠情况,则从后往前拷贝数据。如图3所示。详情看第6章memmove源码。
4.memcpy和strcpy区别
memcpy和strcpy区别在于:
- memcpy是从源存储空间拷贝到目标存储空间;而strcpy是从源字符串拷贝到目标字符串。
- memcpy拷贝时是按照参数n作为结束标志的,即拷贝n个字节就结束;而strcpy是判断字符串作为结束标志,即判断源字符串结束后,拷贝结束。
代码举例说明:
int main()
{
char str1[10] = {0};
char str2[10] = "abcde fghi";
int i;
/* 以ASCII码(十进制)打印源存储空间 */
str2[5] = 0;//手动设置成0,截断str2字符串
printf("str2:");
for(i = 0;i<sizeof(str2);i++)
printf("%d ",str2[i]);
printf("\r\n");
/* 以ASCII码(十进制)打印目标存储空间str1 */
strcpy(str1,str2);
printf("str1:");
for(i = 0;i<sizeof(str1);i++)
printf("%d ",str1[i]);
printf("\r\n");
/* 以ASCII码(十进制)打印目标存储空间str1 */
memcpy(str1,str2,10);
printf("str1:");
for(i = 0;i<sizeof(str1);i++)
printf("%d ",str1[i]);
printf("\r\n");
system("pause");
return 0;
}
运行结果如下:
结果显示使用strcpy时,当源字符串结束时(手动设置str2[5]=0,截断了str2),拷贝停止。而使用memcpy拷贝n个字节的存储空间。
5.memcpy和strncpy区别
strncpy与strcpy类似,这不过strncpy的判断条件处了字符串结束,还受参数n的限制。
代码举例:
int main()
{
char str1[10] = {0};
char str2[10] = "abcde";
printf("str2:%s\r\n",str2);
strncpy(str1,str2,3);//拷贝3字节
printf("str1:%s\r\n",str1);
strncpy(str1,str2,10);//拷贝长度大于字符串长度
printf("str1:%s\r\n",str1);
system("pause");
return 0;
}
运行结果如下图
- 当参数n小于等于源字符串长度,则strcpy只拷贝n个字节到源字符串;
- 当参数n大于源字符串长度,则strcpy拷贝到源字符串结束,剩余部分用0填充。
6.源码
/************************************************************************
*功能:从存储区 str2 复制 n 个字节到存储区 str1
*输入:str1:目标数组
* str2:原数组
* n:字节数
*输出:无
*返回:指向目标区str1的指针
************************************************************************/
void *Mymemcpy(void *str1, const void *str2, size_t n)
{
char *temp1,*temp2;
if(str1 == NULL || str2 == NULL)
{
printf("字符串不能为空!\r\n");
exit(-1);
}
temp1 = (char *)str1;
temp2 = (char *)str2;
while(n --)
{
*temp1++ = *temp2++;
}
return str1;
}
/************************************************************************
*功能:从存储区 str2 复制 n 个字节到存储区 str1
* 与Mymemcpy不同的是,该函数在目标区域和源区域重叠时依然有效。
* 如果出现覆区域重叠的情况,函数执行后会改变源目标的值
*输入:str1:目标数组
* str2:原数组
* n:字节数
*输出:无
*返回:指向目标区str1的指针
************************************************************************/
void *Mymemmove(void *str1, const void *str2, size_t n)
{
char *dst = (char *)str1;
char *src = (char *)str2;
if(dst > src && src + n > dst)//目标区域在源区域之后,且有覆盖,此时需要从后向前赋值
{
dst += n - 1;
src += n - 1;
while(n --)
*dst-- = *src--;
}
else
{
while(n --)
*dst++ = *src++;
}
return dst;
}
/************************************************************************
*功能:把 src 所指向的字符串复制到 dest
*输入:dest:指向用于存储复制内容的目标数组。
* src:要复制的字符串。
*输出:无
*返回:返回一个指向最终的目标字符串 dest 的指针。
************************************************************************/
char *Mystrcpy(char *dest, const char *src)
{
char *temp = dest;
while((*dest++ = *src++)!='\0');
return temp;
}
/************************************************************************
*功能:把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
*输入:dest:指向用于存储复制内容的目标数组。
* src:要复制的字符串。
* n:要从源中复制的字符数。
*输出:无
*返回:返回最终复制的字符串
************************************************************************/
char *Mystrncpy(char *dest, const char *src, size_t n)
{
char *temp = dest;
while((*dest++ = *src++)!='\0' && n)
n--;
while(n)//src长度<n
{
*dest++ = 0;
n--;
}
return temp;
}
原创不易,转载请注明出处。