拷贝函数
strcpy
实现:
char* My_Strcpy(char* des, const char* src)
{
assert(des);
assert(src);
char * ret = des;
/*do{
*ret = *src;
ret++;
} while (*src++);*/
//while (*src){
// *ret = *src;
// ret++;
// src++;
//}
//*ret = '\0';
while (*ret++ = *src++); // 为'\0'时退出循环
/* 因为后缀++优先级高于解引用。先进行后置++
(后置++,先使用值再自增,效率低于前置++,因为要开辟临时空间,++i可以做左值,i++不行)
然后解引用,对指针+1(加其所指向类型的大小)。*/
return ret;
}
memcpy
void* My_Memcpy(char* des, const char* src, size_t num)
{
assert(des);
assert(src);
void* ret = des;
while (num--)
{
// 逐字节拷贝
*(char*)des++ = *(char*)src++;
}
return;
}
memcpy
与strcpy
的区别
- 复制的内容不同。
strcpy
只能复制字符串,而memcpy
以字节为单位复制,可以复制任意内容,例如字符数组、整型、结构体、类等。memcpy通常与memset函数配合使用。 - 复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符
\0
才结束,所以容易溢出。memcpy则是根据其第3个参数num决定复制的长度。
memmove
memcpy
与memmove
的区别
它们唯一的区别是当内存发生局部重叠时,memmove可以保证拷贝正确,memcpy拷贝的结果是未定义的(取决于编译平台内部对memcpy的优化处理)。
实现:
void* My_memmove(void* dst, const void* src, size_t num)
{
assert(dst);
assert(src);
char * _dst = (char *)dst;
char * _src = (char *)src;
if (_dst > _src && _dst < _src + num){ //内存重叠情况
// 从高地址——>低地址拷贝
_dst = _dst + num - 1;
_src = _src + num - 1;
while (num--){
*_dst-- = *_src--;
}
}
else{ //memcpy
while (num--){
*_dst++ = *_src++;
}
}
return;
}
strncpy
char* My_Strncpy(char* dest, const char* src, size_t num)
{
assert(dst);
assert(src);
char *tmp = dest;
while (num) {
if ((*tmp = *src) != 0)
++src;
++tmp;
--count;
}
return dest;
}
strcpy
和strncpy
的缺陷
- 存在潜在越界问题
当dest的长度 < src的长度的时候,由于无法根据指针判定其所指指针的长度,故数组内存边界不可知的。因此会导致内存越界,尤其是当数组是分配在栈空间的,其越界会进入你的程序代码区,将使你的程序出现非常隐晦的异常。 - 字符串结束标志服’\0’丢失
当dest所指对象的数组长度==count的时候,调用strncpy使得dest字符结束符’\0’丢失。 - 效率较低
当count > src所指对象的长度的时候,会继续填充’\0’知道count的长度为止。 - 不能处理内存覆盖问题
不能处理dest和src内存重叠的情况。
拼接函数
strcat
char* My_Strcat(char * dst, const char * src)
{
assert(dst!= NULL && src != NULL); //保证dest、src非空
while (*dst){
dst++;
}
while (*src){
*dst++ = *source++;
}
return dst;
}
strncat
char* My_strncat(char* dst, const char* src, size_t num)
{
assert(dst!= NULL && src != NULL); //保证dest、src非空
char* ret = dst;
while (*dst!= '\0') //用指针往后一个个找,找到dest结尾的‘\0’
dst++;
while (num && *dst){
*dst++ = *src++;
--num;
}
*dst= '\0';
return ret; //返回dst字符串起始地址
}
其他
memset
strlen
// 1.计数器方式
size_t My_Strlen(const char *str )
{
size_t res = 0;
while (str[res]){
res ++;
}
return res ;
}
//2. 递归模拟(不创建临时变量)
size_t My_Strlen(const char* str )
{
if (*str == '\0'){
return 0;
}
return 1 + My_Strlen(str + 1);
}
// 3.指针减指针(中间越过元素个数)
size_t My_Strlen(const char *str)
{
char *p = str;
while (*p != '\0'){
p++;
}
return p - str;
}
memset
void* My_Memset(void* des, int val, size_t num)
{
assert(des);
char *p = (char *)des;
while (num){
--num;
*p++ = value;
}
return des;
}