C语言 常用标准库函数代码实现

news2025/1/14 3:35:45

一、内存

1. memcpy函数

memcpy 函数用于 把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域);拷贝多少个?有一个size变量控制拷贝的字节数;

函数原型:void *memcpy( void *dest, const void *src, size_t n );
dest表示拷贝到哪个目标,src表示拷贝源,加const修饰,防止被修改,n表示拷贝多少个字节
返回void* 类型的原因,是为了使用链式表达,即strlen((char*)(memcpy(dest,src,n)),这样可以直接计算dest的长度,使程序代码更简洁

#include <stdio.h>
#include <assert.h>
#include <string.h>
void* my_memcpy(void* dest, const void* src, size_t n)
{
	assert((dest != NULL) && (src != NULL));
	char* dest_t = (char*)dest;                  //转换成字符型一个个复制拷贝,由于函数拷贝的过程是一个字节一个字节的拷贝的,
												 //所以实际操作的时候要把void*强制转化为char*,
	char* src_f = (char*)src;                    //这样在指针加的时候才会保证每次加一个字节
	while (n-- > 0)
	{
		*(dest_t++) = *(src_f++);
	}
	return dest;//void* 一定要返回一个值(指针),这个和void不太一样!函数返回指向dest的指针
}

int main()
{
	char arr1[10] = { 0 };
	char arr2[10] = { 2,3,4,5,6,7,8,9,10,11 };
	int i = 0;
	my_memcpy(arr1, arr2, 10);
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

2. memmove函数

void *my_memmove(void *dest, const void *src, size_t count)
{
    assert(dest != NULL || src != NULL);

    if (dest < src)
    {
        char *p = (char *)dest;
        char *q = (char *)src;
        while (count--)
        {
            *(p++) = *(q++);
        }
    }
    else
    {
        char *p = (char *)dest + count;
        char *q = (char *)src + count;
        while (count--)
        {
            *(--p) = *(--q);
        }
    }

    return dest;
}

memmove用于拷贝字节,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源内容会被更改。当目标区域与源区域没有重叠则和memcpy函数功能相同。
当出现了src的尾部和dest的头部内存有重合的时机时,memmove的处理规则是从后往前进行copy。

用上面编写的my_memcpy和my_memmove两个函数举例体会一下:

int main()
{
	char s[] = "1234567890";
	char* p1 = s;
	char* p2 = s + 2;
	my_memcpy(p2, p1, 5);
	printf("my_memcpy: s = %s\n", s);

    memcpy(s,"1234567890",10);
    my_memmove(p2, p1, 5);
    printf("my_memmove: s = %s\n", s);

	return(0);
}

在这里插入图片描述
如对 memmove 和 memcpy的区别还有不理解可以参考:https://blog.csdn.net/qq_40843865/article/details/101775762

3. memset函数

void *my_memset(void *s, int c, size_t n)
{
    unsigned char* p=s;
   	while(n--)
   	{
        *p++ = (unsigned char) c;
    }
    return s;
}

二、字符串

1. strstr函数

函数原型:char *strstr(char *str1, const char *str2);
str1: 被查找目标
str2: 要查找对象
返回值:若str2是str1的子串,则返回str2在str1的首次出现的地址;如果str2不是str1的子串,则返回NULL。

char* my_strstr(const char *str1, const char *str2)
{
    if (str1== NULL || str2 == NULL)
        return NULL;
    const char *temp = str1;
    const char *res = str2;
    while (*str1 != '\0')
    {
        temp = str1;
        res = str2;
        while (*temp== *res){
            temp++;
            res++;
        }
        if (*res == '\0')return str1;
        str1++;
    }
    return NULL;
}

2. strcpy函数

函数原型:char *strcpy(char *dest, const char *src);
返回char* 类型的原因,是为了使用链式表达,即strlen(strcpy(dest,src)),这样可以直接计算dest的长度,使程序代码更简洁

char* my_strcpy(char* dest, const char* src)
{
	assert(dest!=NULL && src!=NULL);
	
	char* ret = dest;//dest的起始位置赋给ret

	while ((*dest++ = *src++) != '\0');//源赋值给目标,源目标指针向后移动 可以直接写成while (*dest++ = *src++);
	
	return ret;
}

3. strncpy函数

char* my_strncpy(char* dest, const char* src, size_t count)
{
	assert(dest!=NULL && src!=NULL);
	
	char* ret = dest;//dest的起始位置赋给ret

	int i = 0;
	for (i = 0; i < (int)count; i++)//源赋值给目标,源目标指针向后移动
		*dest++ = *src++;

	return ret;
}

4. strlen函数

函数原型:size_t strlen(const char *s);

size_t my_strlen(const char *s) 
{
	assert(s!=NULL);
	size_t len = 0;
	while(*s++ != '\0')
	{
		len++;
	}
	return len;
}

size_t my_strlen(const char *s) 
{
	assert(s!=NULL);
	for(size_t i=0; s[i] != '\0'; i++);
	return i;
}

5. strcmp函数

strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。
函数原型:int strcmp(const char *s1,const char *s2);
ANSI标准规定,返回值为正数,负数,0 。而确切数值是依赖不同的C实现的。
1.当两个字符串不相等时,C标准没有规定返回值会是1 或 -1,只规定了正数和负数。
2.有些会把两个字符的ASCII码之差作为比较结果由函数值返回。但无论如何不能以此条依据作为程序中的流程逻辑。

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1!=NULL && str2!=NULL);//判断str1和str2是否为NULL
	while (*str1 == *str2)//如果*str1和*str2相等,进入循环
	{
		if (*str1 == '\0')//如果str1的值为'\0',str2的值也为'\0',表示两个字符串相等
			return 0;
		str1++;//指针向后移动
		str2++;
	}
	return *(const unsigned char*)str1 - *(const unsigned char*)str2;//如果两个字符串不相等,则返回它们的差值
}

或 简洁写法:

int my_strcmp(const char* s1, const char* s2)
{
	assert((s1 != NULL) && (s2 != NULL));
	while(*s1 && (*s1==*s2))
	   	s1++,s2++;
	return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}

上面是返回差值的写法,下面给出返回1,-1,0的写法参考:

int my_strcmp(const char *str1, const char *str2)
{
    assert((str1 != NULL) && (str2 != NULL));
    
    while ((*str1 != '\0') && (*str2 != '\0'))
    {
        if (*str1 == *str2)
        {
            str1++;
            str2++;
        }
        else
        {
            if (*str1 > *str2)
                return 1;
            else
                return -1;
        }
    }if (*str1 == '\0' && *str2 == '\0')
        return 0;
    else if (*str1 == '\0' && *str2 != '\0')
        return -1;
    else if (*str1 != '\0' && *str2 == '\0')
        return 1;
} 

6. strncmp函数

strncmp()首先将str1第一个字符值减去str2第一个字符值。若差值为0继续比较,直到字符结束标志’\0’;若差值不为0,则将差值返回。

前面的my_strcmp稍微改动下即可:

int my_strncmp(const char* str1, const char* str2, size_t n)
{
	assert((str1 != NULL) && (str2 != NULL));//判断str1和str2是否为NULL
	while ((n-->0)&&(*str1 == *str2))//如果*str1和*str2相等,进入循环
	{
		if (*str1 == '\0')//如果str1的值为'\0',str2的值也为'\0',表示两个字符串相等
			return 0;
		str1++;//指针向后移动
		str2++;
	}
	return *(const unsigned char*)str1 - *(const unsigned char*)str2;//如果两个字符串不相等,则返回它们的差值
}

或 返回1,-1,0的写法参考

int my_strncmp(const char *s1 , const char *s2 , size_t n)
{
	assert((str1 != NULL) && (str2 != NULL));
    for( ; n > 0 ; ++s1, ++s2, --n)//for后面做多件事情,分别指向下一个元素,以及n减一
        if(*s1 != *s2)//条件运算符优先级最低.解址符优先与关系运算符
            return   ( *(unsigned char *)s1 < *(unsigned char *)s2 ? -1 : 1 );//条件运算符进行比较
        else if(*s1 == '\0')//碰到终止字符结束.
            return (0);
    return (0);//字典比较每一个字符相等或者碰到终止,则返回0
}

7. strcat函数

char* my_strcat(char* dest, const char* src)
{
	//判断dest和src是否为NULL
	assert(dest && src);
	//把dest的起始位置赋值给ret,以便返回
	char* ret = dest;
	while (*dest != '\0')//dest指针移动到字符串末尾
	{
		dest++;//dest指针向后移动 注意这里必须单独++ 不能放到判断里去
	}
	//此时dest的指针已指向最后一个位置
	while ((*dest++ = *src++) != '\0');//循环追加字符

	return ret;
}

char* my_strcat(char *dest , const char *src)
{
	assert(dest && src);
    char *s;//暂存进行拷贝作用
    for(s = dest;*s != '\0';++s)
        ;//s指向s1的结尾
    for( ; (*s = *src) != '\0'; ++s, ++src)
        ;//将s2拷贝到s1末尾,直到遇到s2的结束符
    return(dest);//可以不测试返回值
}

注:赋值表达式的返回值为等号左边的值

8. strncat函数

C 库函数 char *strncat(char *dest, const char *src, size_t n) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。

char* my_strncat(char* dest, const char* src, size_t count)
{
	assert(dest && src);

	char* ret = dest;
	while (*dest != '\0')//dest指针移动到字符串末尾
		dest++;
	int i;
	for (i = 0; i < (int)count; i++)
		dest[i] = src[i];

	return ret;
}

9. atoi函数

int isspace(int x)  
{  
    if (x == ' ' || x == '\t' || x == '\n' || x =='\f' || x =='\b' || x == '\r')  
        return 1;  
    else   
        return 0;  
}

int isdigit(int x)  
{
    if (x <= '9' && x >= '0')           
        return 1;   
    else   
        return 0;  
}

int my_atoi(const char *nptr)  
{  
    int c;              /*当前字符*/  
    int total;          /*总计字节数*/  
    int sign;           /*正数or负数*/     
  
    /*跳过开头的空格*/  
    while (isspace((unsigned char)*nptr))  
        ++nptr;  
  
    c = (unsigned char)*nptr++;  
    sign = c;           /*保存符号*/  
    if (c == '-' || c == '+')  
        c = (unsigned char)*nptr++;    /* skip sign */  
   
    total = 0;  
    while (isdigit(c)) 
    {  
        total = 10 * total + (c - '0');     /*求和*/  
        c = (unsigned char)*nptr++;    /*获取下一个字符*/  
    }if (sign == '-')  
        return -total;  
    else  
        return total;  
}

注:atol只要把函数返回值类型改为long,变量total的类型改为long就行了。

10. itoa函数

char* myitoa(int value, char* str, int radix) {
    static char dig[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int n = 0, neg = 0;
    unsigned int v;
    char* p, * q;
    char c;
    /* 负数:十进制直接在前面加负号,其它进制用补码 */
    if (radix == 10 && value < 0) {
        v = -value;
        neg = 1;
    }
    else
    {
        v = value;
    }
    /* 其它进制的负数转为unsigned int类型,即取了补码 */
    do {
        str[n++] = dig[v % radix];
        v /= radix;
    } while (v);
    if (neg)
        str[n++] = '-';
    str[n] = '\0';
    /* 字符串反转 */
    for (p = str, q = p + (n - 1); p < q; ++p, --q)
        c = *p, * p = *q, * q = c;
    return str;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络工程毕业设计 SSM汽车租赁系统(源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新完成的毕业设计项目作品&#xff0c;【基于SSM的汽车租赁…

mitmproxy 抓包神器-2.抓取Android 和 iOS 手机 https 请求

前言 抓取手机请求的前提条件是确保手机和电脑在同一网段上&#xff0c;也就是说使用同一WiFi。 启动服务 mitmweb 命令启动服务&#xff0c;默认监听8080端口 (venv) D:\demo\mitmproxy_xuexi>mitmweb [11:59:49.361] HTTP(S) proxy listening at *:8080. [11:59:49.36…

linux redhat8.0 权限管理

在linux里面&#xff0c;一切皆文件&#xff0c;不同的用户对文件有不同的管理权限&#xff0c;而只有root用户能为其他用户分配权限。 读&#xff08;r&#xff09;写&#xff08;w&#xff09;执行&#xff08;x&#xff09;数字表示421文件&#xff08;默认644&#xff09;…

SpringBoot-OneDay

优势 创建独立的spring程序自动配置spring简化的maven配置内嵌tomcat提供生产就绪型功能&#xff0c;如指标&#xff0c;健康检查和外部配置特性 为基于Spring 的开发提供更快的入门体验 开箱即用&#xff0c;没有代码生成&#xff0c;也无需XML 配置。同时也可以修改默认值来…

【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】

目录1. NiN块介绍2. 构建NiN模型3.NIN模型每层输出形状4. 获取Fashion-MNIST数据和训练NiN模型5. 总结前几篇文章介绍的LeNet、AlexNet和VGG在设计上的共同之处是&#xff1a;先以由卷积层构成的模块充分抽取空间特征&#xff0c;再以由全连接层构成的模块来输出分类结果。其中…

RocketMQ基本概念及功能

文章目录背景架构模型NameServer 名字服务器Broker 代理服务器生产者主题队列消息消息标签消息位点消费者消费位点消费者分组订阅关系参考文章背景 RocketMQ是阿里巴巴在2012年开发的分布式消息中间件&#xff0c;专为万亿级超大规模的消息处理而设计&#xff0c;具有高吞吐量…

【VScode插件开发】<二>插件实践开发+发布

开发环境配置完&#xff0c;就得好好琢磨开发内容了&#xff0c;不能老停留在hello world上呀&#xff01; 一、开发文档结构分析 1.Package.json {"name": "kidtest","displayName": "KidTest","description": "for…

Gnoppix Linux系统发布

导读基于 Kali Linux 的 Linux 滚动发行版 Gnoppix 22.12 带来了 GNOME 43、Linux 内核 6.0 和新的升级。作为传统的现场 CD 发行版 Knoppix 项目的继承者&#xff0c;​​Gnoppix Linux​​ 是专门为渗透测试和反向工程而设计的。它为网页应用安全和数字权利保护进行了优化。除…

Java也可以轻松编写并发程序

如今&#xff0c;多核处理器在服务器&#xff0c;台式机及笔记本电脑上已经很普遍了&#xff0c;同时也被应用在更小的设备上&#xff0c;比如智能手机和平板电脑。这就开启了并发编程新的潜力&#xff0c;因为多个线程可以在多个内核上并发执行。在应用中要实现最大性能的一个…

SpringBoot+Vue实现前后端分离的小而学在线考试系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

访问者模式(Visitor)

参考&#xff1a; 模板方法设计模式 (refactoringguru.cn) design-patterns-cpp/TemplateMethod.cpp at master JakubVojvoda/design-patterns-cpp GitHubhttps://github.com/JakubVojvoda/design-patterns-cpp/blob/master/state/State.cpp) 文章目录一、什么是访问者模式…

【Python机器学习】Sklearn库中Kmeans类、超参数K值确定、特征归一化的讲解(图文解释)

一、局部最优解 采用随机产生初始簇中心 的方法&#xff0c;可能会出现运行 结果不一致的情况。这是 因为不同的初始簇中心使 得算法可能收敛到不同的 局部极小值。 不能收敛到全局最小值&#xff0c;是最优化计算中常常遇到的问题。有一类称为凸优化的优化计算&#xff0c;不…

数字货币市场风暴肆虐,币圈人应该把握哪些新的赛道机遇

11月11日&#xff08;周五&#xff09;美股盘前&#xff0c;曾经为全球第二大加密货币交易所FTX在推特发布了申请破产保护的声明&#xff0c;创始人SBF已经辞去CEO职务。据声明&#xff0c;FTX已经任命John J. Ray III 担任CEO&#xff0c;SBF还将协助相关破产事宜。据FTX在推特…

[附源码]Python计算机毕业设计Django面向高校活动聚App

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

记录--三分钟打造自己专属的uni-app工具箱

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 介绍 可曾想过我们每次创建新项目&#xff0c;或者换地方写程序&#xff0c;都要把之前写过的工具类找出来又要复制粘贴一遍有些麻烦&#xff0c;尤其是写uni-app自定义模板主要还是开发工具完成的。这…

反序列化漏洞之CVE-2016-7124

目录 魔术函数 发生条件 靶场练习 魔术函数 __constuct: 构建对象的时被调用 __destruct: 明确销毁对象或脚本结束时被调用 __invoke: 当以函数方式调用对象时被调用 __toString: 当一个类被转换成字符串时被调用 __wakeup: 当使用unserialize时被调用&#xff0c;可用于做些…

【python】pandas 之 DataFrame、Series使用详解

目录 一&#xff1a;Pandas简介 二&#xff1a;Pandas数据结构 三&#xff1a;Series 四&#xff1a;字典生成Series 五&#xff1a;标量值生成Series 六&#xff1a;Series类似多维数组 七&#xff1a;Series类似字典 八&#xff1a;矢量操作与对齐 Series 标签 九…

对话交通银行:中国金融业数据仓库有哪些重要趋势?

数字经济时代&#xff0c;什么才是金融机构的核心竞争力&#xff1f;笔者访谈了交通银行软件开发中心总经理刘雷。刘雷指出&#xff1a;“数据和数据能力是金融机构发展的核心竞争力”。 当下&#xff0c;金融机构的数字化转型正迈入纵深阶段&#xff0c;使得两大核心诉求更加…

SpringMVC学习:四、SpringMVC的高级开发(异常处理器、文件上传、 拦截器)

5. SpringMVC的高级开发 5.1 异常处理器 ​ springmvc在处理请求过程中出现异常信息交由异常处理器进行处理&#xff0c;自定义异常处理器可以实现一个系统的异常处理逻辑。 思路: ​ 系统中异常包括两类&#xff1a;预期异常和运行时异常RuntimeException&#xff0c;前者…

如何利用代理IP做SEO监控优化?

从事互联网营销相关的用户多多少少都会接触到SEO&#xff0c;一般来说企业为了实现传播效果&#xff0c;每天都需要大量重复地做各种渠道的投放&#xff0c;这是一项逐渐累积的长期性工作。而这其中关键的优化分析与监控&#xff0c;势必需要大量的数据支持。接下来就一起来了解…