字符串与内存库函数的模拟实现(新手)(C语言)

**运行通过编译器(VS2022) **

注意1:只有部分对除整形以外的类型乃至结构体做过测试

注意2:如果还有其他的字符串与内存操作函数,欢迎补充

注意3:因为本人不清楚专业命名,所以所有函数都以自己的理解代称

所用到的库函数以及宏:

#define _CRT_SECURE_NO_WARNING
#define cahr char

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

此处因为本人因输入习惯常将char打成cahr,所以专门定义了一个宏

*一、字节替换函数memset() *

void _cdecl my_memset(void* arr, cahr ch, size_t num)
{
	assert(arr);
	for (int i = 0; i < num; i++)
		*((char*)arr + i) = ch;
}

1、assert(arr)相当于assert(arr != NULL) (下面有类似用法)

2、选择使用for循环而非while循环的原因为vs2022如果使用++(char*)arr会报出“表达式必须是可修改的左值”错误,因此没有直接对地址进行操作(下面有类似问题)

其他版本的编译器可能没有类似问题。

*二、字节比较函数memcmp() *

int _cdecl my_memcmp(const void* dest, const void* src, size_t num)
{
	assert(dest && src);
	for (int i = 0; i < num; i++)
		if (*((char*)dest + i) > *((char*)src + i))
			return 1;
		else if (*((char*)dest + i) < *((char*)src + i))
			return -1;
		else;
	return 0;
}

循环提前结束代表不等,否则相等

*三、内存重叠拷贝函数memmove() *

void* _cdecl my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)
	//从前向后拷贝
		for (int i = 0; i < num; i++)
			*((char*)dest + i) = *((char*)src + i);
	else
	//从后向前拷贝
		for (int i = num - 1; i >= 0; i--)
			*((char*)dest + i) = *((char*)src + i);
	return ret;
}

其实就是更具不同情况使用memcpy()函数,本质大差不离,多了一层if

*四、内存拷贝函数memcpy() *

void* _cdecl my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	for (int i = 0; i < num; i++)
		*((char*)dest + i) = *((char*)src + i);
	return ret;
}

*五、是否被包含判断函数strstr() *

char* _cdecl my_strstr(const char* dest, const char* src)
//只是比较而不改变内容,所以用const增加常属性
{
	assert(dest && src);
	char* ret = (char*)dest;
  //如果src只有一个\0,则直接跳出函数减少运算
	if (!*src)
		return ret;
	else
		while (*dest++ != *src && *(dest - 1))
			;
  /*此处因为当*dest == *src && *dest == '\0'时,传出的dest多进行一次++,
  所以判断对应*dest时要-1,但为了后续判断又不能改变dest的值*/
	if (!(*--dest))//同上因为dest跳出循环时多进行一次++
		return ret;
	ret = (cahr*)dest;//已定义宏
	while (*dest++ == *src++ && *dest)
			;//*dest == '\0'时跳出循环,避免死循环
	if (!(*src)) return ret;
  //防止出现dest与src是交集的情况
	else return NULL;
}

if(*src)表示判断其是否为'\0',如果是\0则返回0

*六、字符串比较函数strcmp() *

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1++ == *str2++)
		if (!(*(str1 - 1) || *(str2 - 1)))
          //等价于!(*(str1 - 1)) && !(*(str2 - 1))
			return 0;
	if (*--str1 > *--str2) 
      //此处因为str1与str2跳出循环时多进行一次++,所以要--
      return 1;
	else 
      return -1;
}

此处用到的逻辑运算: (!A && !B) == !!(!A && !B) == !(!!A || !!B) == !(A || B)

*七、字符串复制函数strcpy() *

char* my_strcpy(char* dest, const char* src)
{
	assert(dest);
	assert(src);
	char* ret = dest;
	while (*dest++ = *src++);
	return ret;
}

*八、字符串追加函数strcat() *

char* my_strcat(char* dest, const char* src)
{
	assert(dest != NULL);
	assert(src);
	//二者语法等价
	char* ret = dest;
	while (*dest++);
	dest--;
	while (*dest++ = *src++);
	return ret;
}

*九、字符串分段函数strtok() *

尚在钻研

**其他问题: **

1、#define _CRT_SECURE_NO_WARNINGS

这是因为在vs2022中一些原本C语言的函数例如scanf()会被任务存在风险,在最开始加人该语句使得程序得以运行,当然,如果不加这句话也可以运行,可以使用自带的函数,例如scanf_s(),这种写法可以保证在该编译器中得以无风险运行,但是相同代码无法保证在其他编译器中运行。

另外,不止vs2022,其他的编译器可能也存在相关问题。

2、assert()

因为无法完全保证代码的正确性,所以加入断言函数防止传入空指针

3、_cdecl

因本人最近在研究该调用,所以部分函数用到该关键词,实际上该关键词即使不输入也默认是该类型,就像是auto一样,省略时默认该类型

4、size_t 库函数中将unsighed int类型重命名为size_t

5、对void类型的强制类型转换 因为void类型算是无类型指针,所以要先转换为字节大小为1的char*类型以方便操作

缺陷

1、部分代码尤其是strstr()函数过于繁杂,远远没有达到库函数应有的标准

2、注释多处可能存在不合理,例如strstr()函数就十分影响阅读,而且,很多函数可能也缺乏注释

3、调试不充分,只有小部分函数对包括结构体变量进行过测试

#C语言##库函数##初学者#
全部评论

相关推荐

03-12 15:35
嘉应学院 Python
快说谢谢牛牛精灵:说不定就是下一个寒武纪!
点赞 评论 收藏
分享
上周组里招人,我面了六个候选人,回来跟同事吃饭的时候聊起一个让我挺感慨的现象。前三个候选人,算法题写得都不错。第一道二分查找,五分钟之内给出解法,边界条件也处理得干净。第二道动态规划,状态转移方程写对了,空间复杂度也优化了一版。我翻他们的简历,力扣刷题量都在300以上。后三个呢,就有点参差不齐了。有的边界条件没处理好,有的直接说这道题没刷过能不能换个思路讲讲。其中有一个女生,我印象特别深——她拿到题之后没有马上写,而是先问我:“面试官,我能先跟你确认一下我对题目的理解吗?”然后她把自己的思路讲了一遍,虽然最后代码写得不是最优解,但整个沟通过程非常顺畅。这个女生的代码不是最优的,但当我问她“如果这里是线上环境,你会怎么设计’的时候,她给我讲了一套完整的方案——异常怎么处理、日志怎么打、怎么平滑发布。她对这是之前在实习的时候踩过的坑。”我在想LeetCode到底在筛选什么?我自己的经历可能有点代表性。我当年校招的时候,也是刷了三百多道题才敢去面试。那时候大家都刷,你不刷就过不了笔试关。后来工作了,前三年基本没再打开过力扣。真正干活的时候,没人让你写反转链表,也没人让你手撕红黑树。更多的是:这个接口为什么慢了、那个服务为什么OOM了、线上数据对不上了得排查一下。所以后来我当面试官,慢慢调整了自己的评判标准。算法题我还会出,但目的变了。我出算法题,不是想看你能不能背出最优解。而是想看你拿到一个陌生问题的时候,是怎么思考的。你会先理清题意吗?你会主动问边界条件吗?你想不出来的时候会怎么办?你写出来的代码,变量命名乱不乱、结构清不清楚?这些才是工作中真正用得到的能力。LeetCode是一个工具,不是目的。它帮你熟悉数据结构和常见算法思路,这没问题。但如果你刷了三百道题,却说不清楚自己的项目解决了什么问题、遇到了什么困难、你是怎么解决的,那这三百道题可能真的白刷了。所以还要不要刷LeetCode?要刷,但别只刷题。刷题的时候,多问自己几个为什么:为什么用这个数据结构?为什么这个解法比那个好?如果换个条件,解法还成立吗?把刷题当成锻炼思维的方式,而不是背答案的任务。毕竟面试官想看到的,从来不是一台背题机器,而是一个能解决问题的人。
牛客51274894...:意思是光刷力扣还不够卷
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务