C/C++库函数的string内存拷贝

来源:互联网 发布:泰国和中国的关系 知乎 编辑:程序博客网 时间:2024/06/05 16:28

面试过程中,面试官一般会让写一些基础的库函数,比如strcpy,memcpy,memmove等。下面做个解释函数。
1、标准库函数strcpy,把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间。
char *strcpy(char *dst,const char *src)
{
assert(dst != NULL);
assert(src != NULL);
char *ret = dst;
while((* dst++ = * src++) != ‘\0’) ;
return ret;
}
特性:
(1)、检查指针的有效性:src为源地址,定义const类型表示只输入,不可修改。
(2)、定义临时变量,用作返回值,使该函数支持链式储存。
(3)、字符串的“\0”需要copy。
缺点:
此种copy不安全,无法避免源地址与目的地址重复的错误。

2、标准库函数memcpy,把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域);拷贝多少个?有一个size变量控制
拷贝的字节数;
函数原型:void *memcpy(void *dest, void *src, unsigned int count);
用法:(1)可以拷贝任何类型的对象,因为函数的参数类型是void*(未定义类型指针),也就是说传进去的实参可以是int*,short*,char*等等,
但是由于函数拷贝的过程是一个字节一个字节的拷贝的,所以实际操作的时候要把void*强制转化为char*,这样在指针加的时候才会保证每次加一个字节。
void memcpy1(void *desc,const void src,size_t size)
{
assert((desc != NULL) && (src != NULL));

unsigned char desc1 = (unsigned char)desc;
unsigned char src1 = (unsigned char)src;
while(size– >0)
{
*desc1 = *src1;
desc1++;
src1++;
}
return desc;
}
特性:
(1)、void* 一定要返回一个值(指针),这个和void不太一样!
(2)、首先要判断指针的值不能为空,desc为空的话肯定不能拷贝内存空间,src为空相当于没有拷贝;
(3)、”“空串是指内容为0,NULL是0,不是串;两个不等价;
(4)、int dest[2] = {0};这是对int 类型的数组初始化的方法;如果是char类型,就用char a[5] = “1234”; 注意数组下标要多于实际看到的字符数,因为还有’/0’
(5)、memcpy(dest,src,sizeof(src));注意里面的sizeof(src),这个是包括字符串的结束符’/0’的;但是如果用memcpy(dest,src,4);没有’/0’就要*(dest+5) = ‘/0’;这样保证是一个完整的字符串;
(6)、如果初始化的时候:
char dest[1024] = “12345666”;//{0};
const char src[5] = “3333”;
那么拷贝的时候,如果用memcpy1(dest,src,sizeof(src));则printf(dest);出来是3333
如果memcpy1(dest,src,4);则printf(dest);出来是33335666;因为上面的sizeof(src),包含’/0’,所以拷贝过去的字符串以’/0’
结束,就只有3333,而如果传4个字符,’/0’是第五个字符,那就遇到dest[1024] 的’/0’结束,所以是33335666
字符串的’/0’问题一定要注意啊!!!

3、memmove标准库函数,用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。
void * memmove (void * dst,const void * src,size_t count)
{
void * ret = dst;
if (dst <= src || (char )dst >= ((char )src + count))
{
// 若dst和src区域没有重叠,则从起始处开始逐一拷贝
while (count–)
{
(char )dst = (char )src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}
else
{ // 若dst和src 区域交叉,则从尾部开始向起始位置拷贝,这样可以避免数据冲突
dst = (char *)dst + count - 1;
src = (char *)src + count - 1;
while (count–)
{
(char )dst = (char )src;
dst = (char *)dst - 1;
src = (char *)src - 1;
}
}
return(ret);
}

原创粉丝点击