手写 str*、mem* 字符串相关函数

strcat

/*
 * 追加 src 指向字符串到 dest 指向的字符串末尾
 */
char *my_strcat(char *dest, const char *src)
{
	char *result = NULL;

	// 入参有效性检查
	assert(src != NULL);
	assert(dest != NULL);

	// 保存 dest 字符串地址
	result = dest;
	// 首先,让 dest 指向原本字符串末尾
	while (*dest != '\0')
	{
		dest++;
	}

	// 以单个字符形式追加 src 字符串所有内容到 dest 原字符串末尾
	while (*src != '\0')
	{
		*(dest++) = *(src++);
	}

	// 末尾补上字符串结束符
	*dest = '\0';

	// 返回最终结果
	return result;
}

strcpy

/*
 * 拷贝 src 所指向的字符串到 dest 指向的地址中
 */
char *my_strcpy(char *dest, const char *src)
{
	char *result = NULL;

	// 入参有效性检查
	assert(src != NULL);
	assert(dest != NULL);
	
	// 保存 dest 字符串地址
	result = dest;
	// 拷贝 src 字符串到 dest 中
	while (*src != '\0')
	{
		*(dest++) = *(src++);
	}
	
	// 末尾补上字符串结束符
	*dest = '\0';

	// 返回最终结果
	return result;
}

strncpy

/*
 * 拷贝 src 所指向的字符串的前 n 字节到 dest 指向的地址中
 */
char *my_strncpy(char *dest, const char *src, size_t n)
{
	char	*result = NULL;
	size_t	i = 0;

	// 入参有效性检查
	assert(src != NULL);
	assert(dest != NULL);
	
	// 保存 dest 字符串地址
	result = dest;
	/* 
	 * 拷贝 src 字符串到 dest 中
	 * 结束拷贝条件为:n 字节或者 src 遇到 '\0' 
	 */
	for (i = 0; i < n && *src != '\0'; i++)
	{
		*(dest++) = *(src++);
	}

	// 若 src 本身长度不足 n 字节,填充 dest 后续内容为 '\0'
	for (; i < n; i++)
	{
		*(dest++) = '\0';
	}	

	// 末尾补上字符串结束符
	*dest = '\0';

	// 返回最终结果
	return result;
}

strstr

/*
 * 在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'
 */

char *my_strstr(const char *haystack, const char *needle)
{
	const char *tmp_str = haystack;
	
	// 入参有效性检查
	assert(haystack != NULL);
	assert(needle != NULL);

	// 如果 needle 为空,直接返回 haystack
	if (*needle == '\0')
	{
		return (char *)haystack;
	}
	
	while (*tmp_str != '\0')
	{
		const char *s1 = tmp_str;
		const char *s2 = needle;
		
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		
		// s2 结束说明找到了 needle ,返回此时的 tmp_str 
		if (*s2 == '\0') 
		{
			return (char *)tmp_str;
		}

		tmp_str++;
	}

	// 未找到返回NULL
	return NULL;
}

strcmp

/*
 * 比较两个字符串 s1 和 s2。
 * 如果 s1 分别小于、匹配或大于 s2,则返回一个小于、等于或大于 0 的整数。
 */
int my_strcmp(const char *s1, const char *s2)
{
	// 入参有效性检查
	assert(s1 != NULL);
	assert(s2 != NULL);

	while (*s1 != '\0' && s2 != '\0')
	{
		// 不相等就返回差值
		if (*s1 != *s2)
		{
			return *s1 - *s2;
		}
		s1++;
		s2++;
	}

	// 如果字符串长度不同,提前结束了 while 循环,此时返回差值
	if (*s1 != *s2)
	{
		return *s1 - *s2;
	}

	return 0;
}

strncmp

/*
 * 与 strcmp 函数相似,只是它比较的是 s1 和 s2 的前 n 个字节(最多)
 */
int my_strncmp(const char *s1, const char *s2, size_t n)
{
	size_t i = 0;
	// 入参有效性检查
	assert(s1 != NULL);
	assert(s2 != NULL);

	for (i = 0; i < n; i++)
	{
		// 如果字符串不足 n 字节,返回差值
		if (*s1 != '\0' && s2 != '\0')
		{
			return *s1 - *s2;
		}
		
		// 不相等就返回差值
		if (*s1 != *s2)
		{
			return *s1 - *s2;
		}
		
		s1++;
		s2++;
	}

	return 0;
}

memcpy

/*
 * 从内存区域 src 复制 n 个字节到内存区域 dest。
 * 内存区域不能重叠。如果内存区域重叠,使用 memmove。
 */
void *my_memcpy(void *dest, const void *src, size_t n)
{
	size_t i = 0;
	unsigned char *res = (unsigned char*)dest;
	const unsigned char *tmp_src = (const unsigned char*)src;
	
	// 入参有效性检查
	assert(dest != NULL);
	assert(src != NULL);

	for (i = 0; i < n; i++)
	{
		res[i] = tmp_src[i];
	}

	return res;
}

memcmp

/*
 * 比较内存区域 s1 和 s2 的前 n 个字节(每个被解释为unsigned char)
 */
int my_memcmp(const void *s1, const void *s2, size_t n)
{
	size_t i = 0;
	const unsigned char *tmp_s1 = (const unsigned char*)s1;
	const unsigned char *tmp_s2 = (const unsigned char*)s2;

	// 入参有效性检查
	assert(s1 != NULL);
	assert(s2 != NULL);

	for (i = 0; i < n; i++)
	{
		// 不相等就返回差值
		if (*tmp_s1 != *tmp_s2)
		{
			return *tmp_s1 - *tmp_s2;
		}
		
		tmp_s1++;
		tmp_s2++;
	}

	// 如果 n 个字节相等,就返回 0
	return 0;
}

memmove

/*
 * 将n个字节从内存区域 src 复制到内存区域 dest。
 * 内存区域可能重叠: 复制的过程就好像 src 中的字节首先被复制到一个不与 src 或 dest 重叠的临时数组中,
 * 然后这些字节从临时数组复制到 dest。
 */
void *my_memmove(void *dest, const void *src, size_t n)
{
	size_t i = 0;
	unsigned char *d = (unsigned char*)dest;
	const unsigned char *s = (const unsigned char*)src;
	
	// 入参有效性检查
	assert(dest != NULL);
	assert(src != NULL);
	
	// 检查地址是否存在重叠
	if (d > s)
	{
		// 目标地址在源地址之后,正常从前往后复制
		for (i = 0; i < n; i++)
		{
			d[i] = s[i];
		}
		
	}
	else if (d < s)
	{
		// 目标地址在源地址之前,从后往前复制防止地址重叠损坏数据
		for (i = n; i > 0; i--)
		{
			d[i - 1] = s[i - 1];
		}
	}

	// 若地址相同,则什么也不做
	return dest;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aSimpleSheep

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值