【C语言进阶】-- 重点字符串函数内存函数及其模拟实现(strlen,strcmp,strcat...memcpy,memmove)

news2024/11/26 7:48:46

目录

1、strlen

1.1 strlen的模拟实现

2、strcpy

2.1 strcpy的模拟实现

3、strcat

3.1 strcat的模拟实现

4、strcmp

4.1 strcmp的模拟实现

5、strstr

5.1 strstr的模拟实现

6、memcpy

6.1 memcpy的模拟实现

7、memmove

7.1 memmove的模拟实现


前言

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串 中或者 字符数组中。字符串常量适用于那些对它不做修改的字符串函数。

1、strlen

头文件:#include <string.h>

作用:字符串以 '\0' 作为结束标志,strlen 函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0')。

注意:

1、参数指向的字符串必须要以 '\0' 结束。

2、函数的返回值是size_t,是无符号的(易错)。

测试:

#include <stdio.h>
#include <string.h>
int main()
{
	int len = strlen("abc");
	printf("%d\n", len);
	return 0;
}

运行结果:3

1.1 strlen的模拟实现

#include <stdio.h>
#include <assert.h>
//计数器实现
//int my_strlen(const char* str)//我们只是用这个字符串,不修改,因此使用const修饰
//{
//	assert(str);
//
//	int count = 0;
//
//	while (*str != '\0')
//	{
//		count++;
//		str++;
//	}
//	return count;
//}
//递归实现
int my_strlen(const char* str)//我们只是用这个字符串,不修改,因此使用const修饰
{
	if (*str != '\0')
		return 1 + my_strlen(str + 1);
	else
		return 0;
}
int main()
{
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

运行结果:3

strlen 的模拟可以有多种方法:

1.计数器(此方式可以做到不创建临时变量计算字符串长度)

2.递归

3.指针 - 指针

我们这里是用的计数器与递归两种方法写的。

2、strcpy

头文件:#include <string.h>

作用:将源字符串中的 '\0' 之前的字符拷贝到目标空间,包含 '\0'。

注意:

1、源字符串必须要以 '\0' 结束。

2、会将源字符串中的 '\0' 拷贝到目标空间。

3、目标空间必须足够大,以确保能存放源字符串。

4、目标空间必须可变(注意:目标字符串必须是有足够空间的,不能是一个常量字符串的指针)。

测试:

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

int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	strcpy(arr2, arr1)
	printf("%s\n", arr2);
	return 0;
}

结果:abcdef

2.1 strcpy的模拟实现

#include <string.h>
#include <assert.h>
#include <stdio.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);//只要有一个是空指针就报错
	char* head = dest;
    
	while (*dest++ = *src++)//这里做到了既拷贝,又能在遇到'\0'停止
	{
		;
	}
	return head;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };

    //my_strcpy(arr2, arr1);
    //printf("%s\n", arr2);
	printf("%s\n", my_strcpy(arr2, arr1));
	return 0;
}

结果:abcdef

3、strcat

头文件:#include <string.h>

作用:将源字符串追加到目标字符串后。

自己不能追加自己,这样会陷入死循环。

注意:

1、源字符串与目标字符串必须以 '\0' 结束。
2、目标空间必须有足够的大,能容纳下源字符串的内容。
3、目标空间必须可修改(注意:目标字符串必须是有足够空间的,不能是一个常量字符串的指针)。

测试:

#include <string.h>
#include <stdio.h>
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";

	strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

运行结果:hello world

3.1 strcat的模拟实现

#include <assert.h>
#include <string.h>
#include <stdio.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* head = dest;

	while (*dest != '\0')
	{
		dest++;//调整必须在这写,不能在判断条件里写。因为会走到'\0'后一位
	}
	while (*dest++ = *src++)
	{
		;
	}
	return head;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";

	my_strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

运行结果:hello world

4、strcmp

头文件:#include <string.h>

作用:比较两个字符串的大小(注意:这里比的不是字符串的长度,比的是对应位置字符的ASCII码值的大小)。

标准规定:

第一个字符串大于第二个字符串,返回大于 0 的数字

第一个字符串等于第二个字符串,返回 0

第一个字符串小于第二个字符串,返回小于 0 的数字

测试:

#include <string.h>
#include <stdio.h>
int main()
{
	char arr1[] = "abcd";
	char arr2[] = "abcc";

	printf("%d\n", strcmp(arr1, arr2));//最后一个字符分别是 d与c ,d的ASCII值大于c的ASCII值
	return 0;
}

运行结果:大于 0 的数字。

4.1 strcmp的模拟实现

#include <assert.h>
#include <string.h>
#include <stdio.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1 == *str2)
	{
        if ('\0' == *str1)
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
	char arr1[] = "abcd";
	char arr2[] = "abcc";

	int ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}

运行结果:大于 0 的数字。

5、strstr

头文件:#include <string.h>

作用:在目标字符串中查找源字符串,如果找到,则返回目标字符串中第一次包含源字符串之后的所有字符串,若未找到,则返回NULL。

测试:

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

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "cd";

	char* p = strstr(arr1, arr2);
	if (NULL == p)
		printf("找不到!\n");
	else
		printf("%s\n", p);
	return 0;
}

运行结果:cdef。

5.1 strstr的模拟实现

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

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	char* s1 = NULL;
	char* s2 = NULL;
	char* cp = (char*)str1;//const修饰的str1直接给会报警告
	
	while (*cp)
	{
		s1 = cp;
		s2 = (char*)str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return cp;
		cp++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "cd";

	char* p = my_strstr(arr1, arr2);
	if (NULL == p)
		printf("找不到!\n");
	else
		printf("%s\n", p);
	return 0;
}

运行结果:cdef。

注意:我们这里用到的 cp 指针在不断记录每次开始比较的 str1 更新后的位置。

6、memcpy

头文件:#include <string.h>

作用:函数memcpy从开始的位置开始向后复制num个字节的数据到目标的内存位置。

注意:

1、这个函数在遇到 '\0' 的时候并不会停下来。
2、如果source和destination有任何的重叠,复制的结果都是未定义的。

测试:

#include <string.h>
#include <stdio.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	memcpy(arr2, arr1, 20);//拷贝20字节的数据

	for (int i = 0; i < 8; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

运行结果:1 2 3 4 5 0 0 0

6.1 memcpy的模拟实现

#include <assert.h>
#include <string.h>
#include <stdio.h>
//memcpy函数返回的是目标空间的其实地址
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;

	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest+1;//dest不能直接+-操作,得强转。强转是临时的,所以先强转再赋值回去
		src = (char*)src+1;
	}

	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	my_memcpy(arr2, arr1, 20);

	for (int i = 0; i < 8; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

运行结果:1 2 3 4 5 0 0 0

7、memmove

头文件:#include <string.h>

作用:与memcpy相似。和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。

测试:

#include <string.h>
#include <stdio.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1+2, arr1, 20);

	for (int i = 0; i < sizeof(arr1)/sizeof(arr1[0]); i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果:1 2 1 2 3 4 5 6 7 8 9 10

7.1 memmove的模拟实现

#include <assert.h>
#include <string.h>
#include <stdio.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;

	//目标在前源头在后,前->后
	if (dest < src)
	{
		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;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1+2, arr1, 20);

	for (int i = 0; i < sizeof(arr1)/sizeof(arr1[0]); i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果:1 2 1 2 3 4 5 6 7 8 9 10

结论:

memmove可以操作可重叠空间,如果不重叠拷贝内存,就是用memcpy,存在重叠就使用memmove。

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

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

相关文章

Ant Design Vue,a-table组件加序号

<a-table:columns"columns":pagination"pagination":data-source"dataSource":defaultExpandAllRows"true"change"tableChange":rowKey"(record, index) > index 1"> columns是表格列的配置&#xff0c…

【2023五一杯数学建模】 B题 快递需求分析问题 建模方案及MATLAB实现代码

【2023五一杯数学建模】 B题 快递需求分析问题 1 题目 请依据以下提供的附件数据和背景内容&#xff0c;建立数学模型&#xff0c;完成接下来的问题&#xff1a;问题背景是&#xff0c;网络购物作为一种重要的消费方式&#xff0c;带动着快递服务需求飞速增长&#xff0c;为我…

25特别放送:我的Gopher成长之路

很早就开始准备这篇文章了,但总是想了又想不知怎样才能更好的写下自己最真实的想法,后来在经过了好几个晚上睡前的思考后才得以完成。 首先,写这篇文章的目的并不是为了吹嘘Go语言有多厉害,也不是鼓励大家都来学习Go语言,仅是为了记录和分享。当然如果是兴趣使然,那么欢…

实时更新天气微信小程序开发

1.新建一个天气weather项目 2.在app.json中创建一个路由页面 当我们点击保存的时候&#xff0c;微信小程序会自动的帮我们创建好页面 3.在weather页面上书写我们的骨架 4.此时我们的页面很怪&#xff0c;因为没有给它添加样式和值。此时我们给它一个样式。&#xff08;样式写在…

蓝桥杯——二分专题

二分分为&#xff1a;实数二分&#xff0c;二分理论题 二分套路题&#xff1a;最小值最大化&#xff0c;最大值最小化 运用二分满足条件&#xff1a;有界&#xff0c;单调。 1.两个二分模板 找>x的第一个&#xff0c;mid&#xff08;lowhigh&#xff09;//2 &#xff0c;没…

java基础知识——23.正则表达式

这篇文章我们简略的讲一下java的正则表达式 目录 1.正则表达式概述 2.正则表达式的简单匹配规则 3.正则表达式的复杂匹配规则 4.正则表达式的分组匹配规则 5.正则表达式的非贪婪匹配 6.使用正则表达式进行搜索和替换 1.正则表达式概述 首先&#xff0c;我们需要明确一个…

leetcode 面试题 02.04. 分割链表

原题为&#xff1a; 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在大于或等于x 的节点之前。 你不需要 保留 每个分区中各节点的初始相对位置。 测试示例如下&#xff1a; 输入&#xff1a;head [1,4…

Flink第一章:环境搭建

系列文章目录 Flink第一章:环境搭建 文章目录 系列文章目录前言一、Idea项目1.创建项目2.pom.依赖3.DataSet4.DataStreaming 二、环境搭建1.Standalone2.Flink on Yarn 总结 前言 Flink也是现在现在大数据技术中火爆的一门,反正大数据的热门技术学的也差不多了,啃完Flink基本…

Packet Tracer - 研究直连路由

Packet Tracer - 研究直连路由 目标 第 1 部分&#xff1a;研究 IPv4 直连路由 第 2 部分&#xff1a;研究 IPv6 直连路由 拓扑图 背景信息 本活动中的网络已配置。 您将登录路由器并使用 show 命令发现并回答以下有关直连路由的问题。 注&#xff1a;用户 EXEC 密码是 c…

A2B汽车音响系统开发设计与改装

hezkz17进数字音频系统研究开发答疑群 1 前装与后装

安装了Volar插件vue文件没有显示Volar的图标

vue3官网 推荐使用Volar来替换Vetur 一、安装Volar 安装Volar前&#xff1a; 安装Volar后&#xff1a; 二、安装Volar插件后&#xff0c;无法显示高亮 之前我安装Volar插件后&#xff0c;vue文件的<script>、<template>、<style>标签仍然是白色的&#xff0c…

Doris(17):动态分区

动态分区是在 Doris 0.12 版本中引入的新功能。旨在对表级别的分区实现生命周期管理(TTL)&#xff0c;减少用户的使用负担。 目前实现了动态添加分区及动态删除分区的功能。 1 原理 在某些使用场景下&#xff0c;用户会将表按照天进行分区划分&#xff0c;每天定时执行例行任…

【网课平台】Day14.集成RabbitMQ:消息队列实现异步通知

文章目录 一、需求&#xff1a;支付通知1、需求分析2、技术方案3、集成RabbitMQ4、生产端发送消息5、消费方发送消息 二、需求&#xff1a;在线学习1、需求分析2、表设计与实体类3、接口定义--查询课程4、接口定义获取视频5、Service层开发6、FeignClient定义7、代码完善 三、需…

数字设计小思 - D触发器与死缠烂打的亚稳态

前言 本系列整理数字系统设计的相关知识体系架构&#xff0c;为了方便后续自己查阅与求职准备。在FPGA和ASIC设计中&#xff0c;D触发器是最常用的器件&#xff0c;也可以说是时序逻辑的核心&#xff0c;本文根据个人的思考历程结合相关书籍内容和网上文章&#xff0c;聊一聊D…

Hudi数据湖技术之数据中心案例实战

目录 1 案例架构2 业务数据2.1 客户信息表2.2 客户意向表2.3 客户线索表2.4 线索申诉表2.5 客户访问咨询记录表 3 Flink CDC 实时数据采集3.1 开启MySQL binlog3.2 环境准备3.3 实时采集数据3.3.1 客户信息表3.3.2 客户意向表3.3.3 客户线索表3.3.4 客户申诉表3.3.5 客户访问咨…

微信小程序 WebSocket 通信 —— 在线聊天

在Node栏目就讲到了Socket通信的内容&#xff0c;使用Node实现Socke通信&#xff0c;还使用两个流行的WebSocket 库&#xff0c;ws 和 socket.io&#xff0c;在小程序中的WebSocket接口和HTML5的WebSocket基本相同&#xff0c;可以实现浏览器与服务器之间的全双工通信。那么本篇…

SSH 服务器、NFS 服务器、TFTP 服务器详解及测试

文章目录 前言一、SSH 服务器1、SSH 能做什么&#xff1f;2、安装 SSH 服务器3、测试 SSH 服务4、用 SecureCRT 测试 二、NFS 服务器1、NFS 能做什么&#xff1f;2、安装 NFS 软件包3、添加 NFS 共享目录4、启动 NFS 服务5、测试 NFS 服务器 三、TFTP 服务器1、TFTP 能做什么&a…

轻松掌握mysql事务的四大特性ACID及实现原理

1、介绍 要实现这四大特性&#xff0c;我们先了解下mysql中的缓冲池和数据页 2、保证原子性和一致性 1、通过undo log保证数据的原子性和一致性 undo log保证了事务的原子性和一致性。 3、保证隔离性 1、并发事务产生时容易产生的隔离性问题 脏读 不可重复读 幻读…

【数据库复习】第四章数据库保护 1

数据库安全性&#xff1a; 数据库的一大特点是数据可以共享 数据共享必然带来数据库的安全性问题 数据库系统中的数据共享不能是无条件的共享 用户标识与鉴别 用户名和口令易被窃取&#xff0c;每个用户预先约定好一个计算过程或者函数 存取控制 常用存取控制方法 自主存…

电子电气架构——车辆E/E架构常识

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 人只有在举棋不定,无从把握的时候才感到疲惫。只有去行动就能获得解放,哪怕做的不好也比无所作为强! 本文主要介绍车辆E/E架构常识,主要涉及E/E架构面临…