字符串和内存函数

news2025/1/21 9:39:29

目录

strlen

模拟实现

长度不受限字符串函数 

strcpy

模拟实现

​编辑 strcat

模拟实现

 strcmp

 模拟实现

长度受限字符串函数

strncpy

模拟实现

strncat

strncmp

strstr 

模拟实现

 strtok

strerror

perror

字符分类函数

字符转换

示例:

​编辑内存函数

memcpy

模拟实现 

memmove

 模拟实现

memcmp

 memset


strlen

功能:统计字符串中\0之前的字符个数。

注意:如果没有\0则返回一个随机值

易错: 

 

strlen的返回值为size_t,也就是无符号整形,使用时要注意这点。 

模拟实现

#include <assert.h>
size_t my_strlen(const char* str)
{
	assert(str);
	const char* start = str;
	const char* end = str;
	while (*end != '\0')
	{
		end++;
	}
	return end - start;
}

长度不受限字符串函数 

strcpy

功能:将一个源头字符串拷贝到一个目标字符串中

注意:如果源头字符串没有\0则会报错。目标空间要足够大,且可变

 易错:

	char* p = "hello";//常量字符串
	char arr[] = "world";
	strcpy(p, arr);

模拟实现

char* my_strcpy(char* dest, const char* src)
{
	assert(dest);
	assert(src);
	char* str = dest;
	while (*dest++ = *src++)\\取巧写法,注意后置++不会对程序产生影响
	{
		;
	}
	return str;//能够被接收
}

测试结果: 

 strcat

功能:在一个字符串后面追加另一个字符串。

注意:目标空间要足够大,且可变。都需要包含\0

易错:

 追加位置在\0处:

模拟实现

char* my_strcat(char* dest, const char* src)
{
	assert(dest);
	assert(src);
	char* str = dest;
	while (*dest)//\0处追加,循环体内++
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return str;
}

注意不要利用strcat去追加自身,否则会造成死循环!

 strcmp

功能:比较字符串对应位置的ascii码大小

注意:都要包含\0。

 模拟实现

//写法1
int my_strcmp(const char* s1, const char* s2)
{
	assert(s1 && s2);
	while (*s1 == *s2)
	{
		if (*s1 == '\0')//全等
		{
			return 0;
		}
		s1++;
		s2++;
	}
	if (*s1 > *s2)
		return 1;
	else 
		return -1;
}
//写法2
int my_strcmp(const char* s1, const char* s2)
{
	assert(s1 && s2);
	while (*s1 == *s2)
	{
		if (*s1 == '\0')
		{
			return 0;
		}
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

长度受限字符串函数

strncpy

模拟实现

模拟实现一次,后续不再模拟实现。

具体逻辑是用一个无符号整数加入循环条件,如果需要拷贝的源头字符串超过了自身长度可以考虑给多余的地方拷贝\0。 

char* my_strncpy(char* dest, const char* src,size_t size)
{
	assert(dest);
	assert(src);
	char* str = dest;
	while (size && (*dest++ = *src++))//=优先级最低,所以加()
	{
		size--;
	}
	if(size)	//超出源头字符串长度
		while (--size)
		{
			*dest++ = '\0';
			size--;
		}
	return str;
}

strncat

将n个子串拷贝到目标字符串后,自动补\0,可以自己增添自己。

strncmp

比较n个子串的大小,大于返回正数,小于返回负数,等于返回0。

 

strstr 

查找一个字符串里的子串,返回首次匹配所有子串的目标字符串中相应字符串的首地址。

模拟实现

法一:我的逻辑是能不能用strncmp负责比较字符串,用一个指针去遍历目标数组,注意结束条件为\0。但这样做有个漏洞,一次性比较多个字符串势必有越界的情况,我们以\0为突破口,能不能用它们的地址进行比较?于是思路就出现了。

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1);
	assert(str2);
	const char* ptr = str1;
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	while (strncmp(str1, str2, len2)!=0 && str1)
	{
		if (str1 + len2 > ptr + len1)
		{
			return NULL;
		}
		str1++;
	}
	return (char*)str1;
}

法二:四指针遍历法。两指针负责移动,两指针负责记录。

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1);
	assert(str2);
	const char* p = str1;
	const char* src = str2;

	while (*p)
	{
		str1 = p;
		str2 = src;
		while (*str1 != '\0' && *str2 != '\0' && * str1 == *str2)//注意\0
		{
			str1++;
			str2++;
		}
		if (*str2 == '\0')
		{
			return (char*)p;
		}
		p++;
	}
	return NULL;
}

 strtok

功能:分隔字符串,strtok函数找到str的下一个标记,并将其用\0替换,返回一个指向这个标记的指针。

注意:strtok会改变原数据的内容!一般修改临时拷贝的内容。

 

使用方法:

  • 第一个参数传字符串,第二个参数传字符串里分隔符
  • 第一个参数首次传递不为空,通过strtok函数找到指定分隔符位置后,将其替换成\0并记录下它的地址再返回回去,后面第一个参数一律为NULL(否则重置),从被保存的位置开始查找下一个分隔符所在位置。
  • 如果本次找不到分隔符,就返回NULL。

 测试:

 发现确实实现了分割并返回,但并不完全,我们可以写个循环:

strerror

功能:当函数调用失败时,将错误码(errno)转换成对应的错误信息或指向对应的地址。

perror

等价于printf + strerror函数,如需打印可以使用这个函数。

字符分类函数

int isalnum(int c):检查字符是否为数字或字母;(0~9,a~z,A~Z) 
int isalpha(int c):检查字符是否为字母;(a~z, A~Z) 
int iscntrl(int c):检查字符是否为控制字符;(八进制000~037以及177的字符) 
int isdigit(int c):检查字符是否为十进制数字;(0~9) 
int isgraph(int c):检查字符是否为图形表示,依赖于使用语言的环境;0~9,a~z,A~Z,以及标点符号) 
int islower(int c):检查字符是否为小写的字母;(a~z) 
int isprint(int c):检查字符是否为可打印的;(数字、字母、标点符号、空白字符) 
int ispunct(int c):检查字符是否为标点符号;(! ” # $ % & ’ ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~等) 
int isspace(int c):检查字符是否为空白字符;(TAB、换行、垂直TAB、换页、回车、空格) 
int isupper(int c):检查字符是否为大写字母;(A~Z) 
int isxdigit(int c):检查字符是否为十六进制数字;(0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f) 

字符转换

int tolower(int c):转化字符为小写字母; 
int toupper(int c):转化字符为大写字母;

示例:


内存函数

memcpy

功能: 将一个内存空间的数据按字节复制到另一块空间。

模拟实现 

void* my_memcpy(void* dest, void* src, size_t num)
{
	void* ret = dest;
	assert(dest);
	assert(src);

	while(num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}

	return ret;
}

memmove

使用memcpy拷贝空间出现重叠时分两种情况:

memcpy显然只能从一方进行拷贝,如果出现另一种情况,则会存在内存覆盖现象。而memmove的作用就是对重叠空间进行拷贝。(有些编译器memcpy可以实现重叠拷贝)

字符串重叠空间拷贝用memmove代替strncpy。

 模拟实现

void* my_memmove(void* dest, void* src, size_t num)
{
	assert(dest);
	assert(src);
	//(char*)dest++;不能这样写,强制暂时改变了类型,void*无法自增
	void* ret = dest;
	//从前往后
	if (src > dest)
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
		//从后往前
	else
	{
		while (num--)
		{
			*((char*)dest+num) = *((char*)src+num);
		}
	}
	return ret;
}

 测试:

memcmp

内存比较函数,不多赘述。 

 memset

字节初始化内存空间。

测试: 

 

由于小端的存储方式,我们修改前9个字节实则将前3个整形变量修改成了0。 

 

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

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

相关文章

10.4 认识Capstone反汇编引擎

Capstone 是一款开源的反汇编框架&#xff0c;目前该引擎支持的CPU架构包括x86、x64、ARM、MIPS、POWERPC、SPARC等&#xff0c;Capstone 的特点是快速、轻量级、易于使用&#xff0c;它可以良好地处理各种类型的指令&#xff0c;支持将指令转换成AT&T汇编语法或Intel汇编语…

C++:模板进阶与继承

模板进阶与继承 模板进阶1.非类型的模板参数2.模板的特化2.1特化的概念2.2函数模板特化2.3类模板特化2.4全特化和偏特化2.4.1全特化2.4.2偏特化 3.模板的分离编译3.1同文件分离3.2不同文件下分离 继承1.继承的概念和定义1.1继承的概念1.2继承的定义1.2.1定义格式1.2.2继承关系和…

哈希应用之位图

文章目录 1.位图概念2.面试题引入3.代码解决[配注释]4.位图应用4.1找到100亿个整数里只出现一次的整数4.2找两个分别有100亿个整数的文件的交集[只有1G内存]1.法一[使用于数据量<42亿]2.法二[适用于数据量大>42亿]3.在一个有100亿个int的文件中找到出现次数不超过2次的所…

自动驾驶技术的基础知识

自动驾驶技术是现代汽车工业中的一项革命性发展&#xff0c;它正在改变着我们对交通和出行的理解。本文将介绍自动驾驶技术的基础知识&#xff0c;包括其概念、历史发展、分类以及关键技术要素。 1. 自动驾驶概念 自动驾驶是一种先进的交通技术&#xff0c;它允许汽车在没有人…

字符集、编码格式的理解

计算机中只能存储二进制01&#xff0c; 要想存储字符&#xff0c;就要有一个字符与编码的映射关系&#xff0c;这个关系就是字符集。 字符集就是字符与编码的映射关系* 字符集的发展历程&#xff1a; 因为计算机是欧美先发明的&#xff0c;他们的语言就26个字母&#xff0c;所…

MyBatis-plus使用

1 基础介绍 MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 它已经封装好了一些crud方法&#xff0c;我们不需要再写…

速学数据结构 | 手把手教你会单链表的构建方式

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《初阶数据结构》《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 &#x1f4cb; 前言1. 什么是链表1.1 链表的物理结构1.2 链表的种类 2. 链表的实现一. SList.h 单链表的声明3.…

10. 激光雷达到车身坐标系外参的标定方法(lidar2car)

目录 0. 论文及代码1. 标定原理2. 拟合平面3. 标定roll/pitch/height4. 标定yaw4.1 理解从B_spline拟合的轨迹中得到vehicle航向 5. 精度 0. 论文及代码 参考论文&#xff1a;SensorX2car: Sensors-to-car calibration for autonomous driving in road scenarios 参考代码&…

kafka初体验基础认知部署

kafka 基础介绍 Apache Kafka是一个分布式流处理平台&#xff0c;最初由LinkedIn开发并于2011年开源。它主要用于解决大规模数据的实时流式处理和数据管道问题。 Kafka是一个分布式的发布-订阅消息系统&#xff0c;可以快速地处理高吞吐量的数据流&#xff0c;并将数据实时地分…

医院PACS系统源码 PACS系统源码

医用软件中的影像归档与传输系统软件&#xff08;Picture Archiving and Communication System&#xff0c;简称PACS&#xff09;是一种用于存储、管理和传输医学影像数据的系统。其主要功能包括&#xff1a; 影像存储&#xff1a;PACS可以将医学影像数据以数字化的形式存储在服…

YoloV8训练自己的模型 Pycharm Remote Development

参考视频&#xff1a;https://www.youtube.com/watch?vm9fH9OWn8YM YOLO官方网站&#xff1a;GitHub - ultralytics/ultralytics: NEW - YOLOv8 &#x1f680; in PyTorch > ONNX > OpenVINO > CoreML > TFLite 在本地的pycharm上面建立一个项目 使用scp把代码传…

星球作业(第十一期)Android中Binder简述

Binder 什么是binder&#xff1f;简述下它的工作过程和使用场景。 什么是Binder&#xff1f; Binder是Android中的一个类&#xff0c;实现了IBinder接口&#xff1b; 从IPC的角度来说&#xff0c;Binder是Android中的一种通讯方式&#xff1b; 从Android Framework角度来说&a…

一文搞清楚Java中常见的IO模型

什么是IO 首先&#xff0c;我们要清楚什么是IO&#xff0c;根据冯诺依曼结构&#xff0c;计算机结构分为5部分&#xff1a;运算器、控制器、存储器、输入设备和输出设备。 输入设备和输出设备都属于外设&#xff0c;网卡、硬盘这种既可以属于输入设备也可以属于输出设备。 输入…

深度学习-卷积神经网络-ResNET

文章目录 前言1.resnet2.作者3.精度&#xff08;TOP-5&#xff09;4.论文一览5.竞赛排名6.网络退化7.残差8.残差 1.作者 前言 本文来自B站&#xff1a; ResNet深度残差网络 1.resnet 2.作者 3.精度&#xff08;TOP-5&#xff09; 4.论文一览 5.竞赛排名 6.网络退化 ResNet解…

拆解常见的6类爆款标题写作技巧!

究竟是先写好文章再拟标题还是先确定标题再写文章呢&#xff1f;很多写稿小白都会有这样的疑惑。 在“人人皆可新媒体”的时代&#xff0c;公众号推文类型琳琅满目&#xff0c;每个人都可以建立自己的公众号&#xff0c;写出自己想写的文章。 但怎样起标题、起什么样的标题&a…

MyCat安装文档

JDK安装 JDK具体安装步骤如下&#xff1a; 1. 上传安装包 使用FinalShell自带的上传工具将jdk的二进制发布包上传到Linux 由于上述在进行文件上传时&#xff0c;选择的上传目录为根目录 /&#xff0c;上传完毕后&#xff0c;我们执行指令 cd / 切换到根目录下&#xff0c;查…

STM32 10个工程篇:1.IAP远程升级(六)

在IAP远程升级的最后一篇博客里&#xff0c;笔者想概括性地梳理总结IAP程序设计中值得注意的问题&#xff0c;诚然市面上或者工作后存在不同版本的IAP下位机和上位机软件&#xff0c;也存在不同定义的报文格式&#xff0c;甚至对于相似的知识点不同教程又有着完全不同的解读&am…

You Know What is C++嵌套类

C嵌套类 一、嵌套类1.嵌套类和访问权限2.作用域3.访问控制 一、嵌套类 在一个类的内部定义另一个类&#xff0c;我们称之为嵌套类&#xff0c;或者嵌套类型。引入嵌套类&#xff0c;因为外围类需要使用嵌套类对象作为底层实现&#xff0c;并且该嵌套类只用于外围类的实现&…

黑马JVM总结(二十七)

&#xff08;1&#xff09;synchronized代码块 synchronized代码块的底层原理&#xff0c;它是给一个对象进行一个加锁操作&#xff0c;它是如何保证如果你出现了synchronized代码块中出现了问题&#xff0c;它需要给这个对象有一个正确的解锁操作呢&#xff0c;加锁解锁是成对…