<string.h>字符操作函数的实现(strcpy、strcat、mem)

在这里插入图片描述

拷贝函数

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;
}

memcpystrcpy的区别

  1. 复制的内容不同。
    strcpy只能复制字符串,而memcpy以字节为单位复制,可以复制任意内容,例如字符数组、整型、结构体、类等。memcpy通常与memset函数配合使用。
  2. 复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符\0才结束,所以容易溢出。memcpy则是根据其第3个参数num决定复制的长度。

memmove

在这里插入图片描述

memcpymemmove的区别
它们唯一的区别是当内存发生局部重叠时,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;
}

strcpystrncpy的缺陷

  1. 存在潜在越界问题
    当dest的长度 < src的长度的时候,由于无法根据指针判定其所指指针的长度,故数组内存边界不可知的。因此会导致内存越界,尤其是当数组是分配在栈空间的,其越界会进入你的程序代码区,将使你的程序出现非常隐晦的异常。
  2. 字符串结束标志服’\0’丢失
    当dest所指对象的数组长度==count的时候,调用strncpy使得dest字符结束符’\0’丢失。
  3. 效率较低
    当count > src所指对象的长度的时候,会继续填充’\0’知道count的长度为止。
  4. 不能处理内存覆盖问题
    不能处理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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值