一篇文章教你自己动手实现C语言库函数

目录
  • memmove
    • 函数声明
    • 函数作用
    • 实现memmove
  • memcpy
    • 函数声明
    • 函数作用
    • 实现memcpy
  • strstr
    • 函数声明
    • 函数作用
    • 实现strstr
  • strcat
    • 函数声明
    • 函数作用
    • 实现strcat
  • strcmp
    • 函数声明
    • 函数作用
    • 实现strcmp
  • strcpy
    • 函数声明
    • 函数作用
    • 实现strcpy
  • strlen
    • 函数声明
    • 函数作用
    • 实现strlen
  • 总结

memmove

函数声明

void * memmove ( void * destination, const void * source, size_t num );

函数作用

将num字节的值从source指向的位置复制到destination指向的内存块。复制就像使用了中间缓冲区一样进行,从而允许目标和源重叠。

该函数不检查source中是否有任何终止的空字符——它总是精确地复制num字节。

为了避免溢出,目标和源参数所指向的数组的大小必须至少为num字节。
返回destination。

实现memmove

#include <stdio.h>
#include <string.h>
#include <assert.h>
//实现memmove
void* my_memmove(void* dst, const void* src, size_t n)
{
    assert(dst && src);
	char* dst_temp = (char*)dst;
	char* src_temp = (char*)src;
	if (src_temp<dst_temp && src_temp + n>dst_temp)//src在dst前,两者交错,需从后往前复制
	{
		while (n)
		{
			*(dst_temp + n - 1 )= *(src_temp + n - 1);
			n--;
		}
	}
	else
	{
		while (n--)
		{
			*dst_temp++ = *src_temp++;
		}
	}
	return dst;
}
int main()
{
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
	my_memmove(a+2, a, 4*sizeof(int));
	for (int i = 0; i < 10; ++i)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

memcpy

函数声明

void * memcpy ( void * destination, const void * source, size_t num );

函数作用

将num个字节的值从source所指向的位置开始直接复制到destination所指向的内存块。

该函数不检查source中是否有任何终止的空字符——它总是精确地复制num字节。

为了避免溢出,目标和源参数所指向的数组的大小必须至少为num字节,并且不能重叠(对于重叠的内存块,memmove是一种更安全的方法)。
返回destination。

实现memcpy

//实现memcpy
void* my_memcpy(void* dst, const void* src, size_t n)
{
	assert(dst && src);
	char* dst_temp = (char*)dst;
	char* src_temp = (char*)src;
	while (n--)
	{
		*dst_temp++ = *src_temp++;
	}
	return dst;
}

int main()
{
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
	my_memcpy(a+2, a, 4*sizeof(int));
	for (int i = 0; i < 10; ++i)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

重叠的区间将会被提前破坏。

strstr

函数声明

char * strstr (char * str1, const char * str2 );

函数作用

查找子字符串

返回一个指向str1中第一次出现的str2的指针,如果str2不是str1的一部分,则返回一个空指针。

匹配过程不包括结束空字符,但它在此停止。

实现strstr

/实现strstr
char* my_strstr(const char* mom,const char* son)
{
	char* cp=mom;
	char* i, *j;
	if (*son == '\0')
	{
		return mom;
	}
	while (*cp != '\0')
	{
		i = cp;
		j = son;
		while (i && *i == *j)
		{
			i++;
			j++;
			if (*j == '\0')
				return cp;
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char mom[] = "abcdefghijk";
	char son[] = "ghi";
	printf("%s\n",my_strstr(mom, son));
	return 0;
}

strcat

函数声明

char * strstr (char * str1, const char * str2 );

函数作用

连接字符串

将source字符串的副本粘贴追加到目标字符串。destination中的结束空字符被source中的第一个字符覆盖,并且在由destination中的两个字符串联形成的新字符串的末尾包含一个空字符。

目标和源不应重叠。
返回destionation。

实现strcat

/实现strstr
char* my_strstr(const char* mom,const char* son)
{
	char* cp=mom;
	char* i, *j;
	if (*son == '\0')
	{
		return mom;
	}
	while (*cp != '\0')
	{
		i = cp;
		j = son;
		while (i && *i == *j)
		{
			i++;
			j++;
			if (*j == '\0')
				return cp;
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char mom[] = "abcdefghijk";
	char son[] = "ghi";
	printf("%s\n",my_strstr(mom, son));
	return 0;
}

strcmp

函数声明

char * strcat ( char * destination, const char * source );

函数作用

比较字符串str1和字符串str2。

这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续执行下面的对,直到字符不同或到达一个终止的空字符为止。

返回值

1)<0 第一个不匹配的字符在ptr1中的值比在ptr2中的值低

2)=0 两个字符串的内容相等

3)>0 第一个不匹配的字符在ptr1中的值大于ptr2中的值

实现strcmp

char* my_strcat(char* dst,const char* src)
{
	assert(dst && src);
	int len1 = strlen(dst);
	char* start = dst + len1;
	while (*start++ = *src++)
	{
		;
	}
	return dst;
}
int main()
{
	char mom[26] ="abcdefg";
	char son[] = "hijk";

	printf("%s\n",my_strcat(mom, son));
	return 0;
}

strcpy

函数声明

int strcmp ( const char * str1, const char * str2 );

函数作用

复制字符串

将source指向的字符串复制到destination指向的数组中,包括终止空字符(并在此点停止)。

为了避免溢出,destination指向的数组的大小应该足够长,以包含与source相同的字符串(包括结束的null字符),并且不应该在内存中与source重叠。
返回destination。

实现strcpy

//实现strcpy
char* my_strcpy(char* dst, const char* src)
{
	char* start = dst;
	assert(dst && src);
	while (*dst++ = *src++);
	return start;
}

int main()
{
	char mom[26] ="abcdefg";
	char son[] = "abq";
	my_strcpy(mom, son);
	printf("%s\n",mom);
	return 0;
}

strlen

函数声明

size_t strlen ( const char * str );

函数作用

获取字符串长度

返回C字符串str的长度。

C字符串的长度由结束空字符决定:C字符串的长度等于字符串开头和结束空字符之间的字符数(不包括结束空字符本身)。

char mystr[100]="test string";

定义了一个长度为100个字符的字符数组,但是用于初始化mystr的C字符串长度只有11个字符。因此,当sizeof(mystr)计算为100时,strlen(mystr)返回11。

实现strlen

//实现strlen
size_t my_strlen(const char* str)
{
	size_t len = 0;
	while (*str++)
	{
		len++;
	}
	return len;
}

int main()
{
	char mom[26] ="abcdefg";
	printf("%d\n",my_strlen(mom));
	return 0;
}

output:7

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C语言中关于库函数 qsort 快排的用法

    目录 前言 一.库函数(qsort)的含义 二.(qsort)函数的实现方式,话不多说,请看. 1. 第一个参数 2. 第二个参数 3. 第三个参数 4. 第四个参数 1). 函数的参数 2). 这第四个参数的重点 三.函数实现 四.总结 前言 我也只是一个奋斗的程序猿,仅以此篇文章,作为我学习的见证,可能我的文采不好,有时候讲的词不达意,但我尽力去做好我想做的这些事情,如果此篇文章能够给各位读者带来一定的认识,那自然是最好的.若文章中有鄙人讲错了的,欢迎评论区指点.谢谢!!! 一.库函数(qs

  • C语言中常用的几个头文件及库函数

    不完全统计,C语言标准库中的头文件有15个之多,所以我主要介绍常用的这四个头文件stdio.h,string.h,math.h,stdlib.h,以后用到其他的再做补充.下面上干货: 1.<stdio.h>:定义了输入输出函数.类型以及宏,函数几乎占了标准库的1/3. (1)文件访问. FILE *fopen("filename","mode"): 以mode模式打开地址为'filename'的文件,并返回文件指针. 访问模式主要是"r&quo

  • 一篇文章带你实现C语言中常用库函数的模拟

    目录 前言 函数介绍 strlen(求字符串长度) strcpy(字符串拷贝) strcat(字符串追加) strcmp(字符串比较) strstr(找子字符串) memcpy(内存拷贝) memmove(内存移动) 总结 前言 C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中. 字符串常量适用于那些对它不做修改的字符串函数. 函数介绍 strlen(求字符串长度) size_t strlen ( const char * str

  • C语言中关于库函数 qsort 的模拟实现过程

    目录 前言 一.qsort函数 二.qsort函数实现思路 1. 底层原理 2. 函数传参 1). 第一个参数 2). 第二个参数 3). 第三个参数 4). 第四个参数 三.局部函数实现 四.全部代码汇集 五.总结 前言 我们在上一篇博客讲解了库函数qsort的使用,今天我为大家带来qsort的模拟实现.上一篇博客这个库函数的阅读链接:C语言中关于库函数 qsort 快排的用法 其实有人会问,我明明已经掌握了库函数qsort的使用方法,为何还要去写模拟实现,其实啊,学好一个东西,不仅仅只是会用

  • 关于C语言多线程pthread库的相关函数说明

    线程相关操作说明 一 pthread_t pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义: typedef unsigned long int pthread_t; 它是一个线程的标识符. 二 pthread_create 函数pthread_create用来创建一个线程,它的原型为: extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__at

  • C++中的常用库

    1. cmath: 数学计算 #include <iostream> #include <cmath> using namespace std; int main () { // 数字定义 short s = 10; int i = -1000; long l = 100000; float f = 230.47; double d = 200.374; // 数学运算 cout << "sin(d) :" << sin(d) <&

  • 老生常谈C语言动态函数库的制作和使用(推荐)

    >>>>>>老生常谈C语言接静态函数库的制作和使用>>点击进入 2 动态函数库的制作和使用 动态函数库的制作步骤可以用下图来描述,具体包括 (1) 编写函数的.c文件(例如add.c.sub.c.mul.c和div.c) (2) 编写Makefile,然后make,实现函数的编译和归档入库 函数的编译:使用gcc –c add.c -fPIC只编译不链接函数.c文件,分别生成函数的目标文件(例如add.o.sub.o.mul.o和div.o). 函数的归档入

  • 一篇文章教你自己动手实现C语言库函数

    目录 memmove 函数声明 函数作用 实现memmove memcpy 函数声明 函数作用 实现memcpy strstr 函数声明 函数作用 实现strstr strcat 函数声明 函数作用 实现strcat strcmp 函数声明 函数作用 实现strcmp strcpy 函数声明 函数作用 实现strcpy strlen 函数声明 函数作用 实现strlen 总结 memmove 函数声明 void * memmove ( void * destination, const void

  • 一篇文章教你使用SpringBoot如何实现定时任务

    前言 在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具备这两个 Spring 中的定时任务实现策略,当然也支持 Quartz,本文我们就来看下 Spring Boot 中两种定时任务的实现方式. 一.第一种方式:@Scheduled 使用 @Scheduled

  • 一篇文章教你学会js实现弹幕效果

    目录 新建一个html文件: 建好html文件,搞出初始模版 HTML添加 CSS填充 js逻辑代码 动画效果 下面是弹幕效果 : 相信小伙伴们都看过了,那么它实现的原理是什么呢,那么我们前端怎么用我们web技术去实现呢?? 新建一个html文件: 哈哈哈,大家别像我一样用中文命名. 中文命名是不合规范的,行走江湖,大佬们看见你的中文命名会笑话你的. 上图中,我们引入了jquery插件,没错我们用jq写,回归原始(找不到cdn链接的小伙伴可以百度bootcdn,在里面搜索jquery).并且取了

  • 一篇文章教你学会使用Python绘制甘特图

    目录 优点 局限 一日一书 用来制作甘特图的专业工具也不少,常见的有:Microsoft Office Project.GanttProject.WARCHART XGantt.jQuery.Gantt.Excel等,网络上也有一些优质工具支持在线绘制甘特图. 可是这种现成的工具,往往也存在一些弊端,让编程人员不知所措.比如说,花里胡哨的UI,让人目不暇接,不知点哪个才好: 比如说,有些基于浏览器的图表需要掌握HTML.JS等编程语言,只会点Python的我直接被劝退: 再比如,进来就是注册.登

  • 一篇文章教你3分钟如何发布Qt程序

    导读:Qt程序编写好以后该如何发布.本文教你使用Qt自带工具windeployqt来进行操作. 本文字数:500,阅读时长大约:3分钟 (1)编写一个简单的程序 我们先做一个简单的窗口,添加一个图片资源文件,放置到窗口当中. 选择添加Qt Resource File文件类型 选择资源文件的路径,并为它命名 点击完成 设置资源前缀,如果资源层次不是很复杂的话,可以只设置一层,用"/"表示 点击Add Files添加一个图片文件 在主窗口中添加一个 Tool Button,设置刚才的图片为

  • 一篇文章教你用python画动态爱心表白

    初级画心 学Python,感觉你们的都好复杂,那我来个简单的,我是直接把心形看作是一个正方形+两个半圆: 于是这就很简单了,十行代码解决: import turtle as t t.pensize(2) # 笔大小2像素 t.pencolor("red") # 颜色为红色 t.left(45) # 45度 t.fd(200) # 向前200直线 t.circle(100, 180) # 画一圆半径100 弧度180 t.right(90) # 向右90度 t.circle(100, 1

  • 一篇文章教你如何排查.NET内存泄漏

    目录 前言 检查托管内存使用 生成dump文件 分析 core dump 总结 前言 内存泄漏通常表示:一个应用程序的某些对象在完成它的的生命周期后,由于它被其他对象意外引用,导致后续gc无法对它进行回收,长此以往就会导致程序性能的下降以及潜在的 OutOfMemoryException. 这篇我们通过一个内存泄漏工具对 .NET Core 程序进行内存泄漏分析,如果程序是跑在windows上,那直接可以使用 Visual Studio 进行诊断. 检查托管内存使用 在开始分析内存泄漏之前,你一

  • 一篇文章教你用JavaScript使用流程控制打印九九乘法表

    目录 一.选择结构 if单分支语句 if…else双分支语句 if…elseif…else多分支语句 switch多分支语句 二.循环结构 while循环语句 do…while循环语句 for循环语句 三.跳转语句 四.动手实践九九乘法表 总结 一.选择结构 概念:选择结构语句需要根据给出的条件进行判断来决定执行对应的代码. if单分支语句 概念:if条件判断语句也被称为单分支语句,当满足某种条件时,就进行某种处理. 举例:只有年龄大于等于18周岁,才输出已成年,否则无输出. if…else双分

  • 一篇文章教你使用枚举来实现java单例模式

    目录 传统的单例写法解决了什么问题 仍然存在的问题 为什么枚举就没有问题 总结 传统的单例写法解决了什么问题 首先,在大多数情况下(不包含面试),传统的单例写法已经完全够用了.通过 synchronized 关键字解决了多线程并发使用. public synchronized static SingleClassV1 getInstance(){ if(instance == null){ instance = new SingleClassV1(); } return instance; }

  • 一篇文章教你如何用多种迭代写法实现二叉树遍历

    目录 思想 实现 总结 思想 利用栈和队列都可以实现树的迭代遍历.递归的写法将这个遍历的过程交给系统的堆栈去实现了,所以思想都是一样的.无非就是插入值的时机不一样.利用栈的先进先出的特点,对于前序遍历.我们可以先将当前的值放进结果集中,表示的是根节点的值.然后将当前的节点加入到栈中.当前的节点等于自己的left.再次循环的时候.也会将left作为新的节点.直到节点为空.也就是走到了树的最左边.然后回退.也就是弹栈..也可以认为回退的过程是从低向上的.具体就是让当前的节点等于栈弹出的right.继

随机推荐