字符串和字符串函数(2)

前言:

        在字符串和字符串函数(1)-CSDN博客中,已将将字符串和字符函数的使用了解,并且实现模拟了一些字符串的库函数。        

        接下来将继续深入学习字符串和字符串函数。并且模拟实现一些较为复杂的函数。

可控制字符长的的函数

介绍并使用strncpy函数

       相同点 strncpy函数和strcpy函数的形同点是都可以实现字符串的拷贝,可以将一个字符串中的内容拷贝到另一个字符串中。

       不同点strnpy和strcpy函数的区别在于,strcpy只能将一个字符串中的所有内容全部拷贝到另一个字符串中,但是strnpy可以将一个字符串中的内容,有选择的拷贝到另一个字符串当中,参数也从2个变成了3个。   

例如:我要将arr1[]中的前3个字符拷贝到arr2[]中:

        可不可以这样实现,其实问题就在于传完3个字符之后,有没有将\0也传进去?

int main()
{
	char arr1[] = { "ab cd ef" };
	char arr2[20];
	strncpy(arr2, arr1, 3);
	printf("%s\n", arr2);
	return 0;
}

通过调试可以看到:

        在arr1中:

拷贝之后,arr2中是这样:

发现:并没有将'\0'考进去!

所以,分两种情况:

    1、如果我想把一个字符串中几个字符给拿出来,这时候需要注意我们要手动将拿出来的字符串中的最后一个字符后面的一个字符加上'\0'

     2、如果我只是想将一个字符串中的前几个元素做一个替换,此时就不需要手动加上'\0'。

例1:拿出arr1中的3个字符。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = { "ab cd ef" };
	char arr2[20];
	strncpy(arr2, arr1, 3);
	arr2[3] = '\0';
	printf("%s\n", arr2);
	return 0;
}

打印结果:

        

例2:替换arr2中的前三个字符
        

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = { "ab cd ef" };
	char arr2[20] = {"hjklo"};
	strncpy(arr2, arr1, 3);
	printf("%s\n", arr2);
	return 0;
}

模拟实现strncpy函数:

        我们可以在strcpy的基础上再进行一些修改:

#include<stdio.h>
#include<assert.h>
char* my_strnpy( char* arr2, const char* arr1, size_t num)
{
	assert(arr1 != NULL);
	assert(arr2 != NULL);
	char* start = arr2;
	while (num)
	{
		*arr2++ = *arr1++;
		num--;
	}
	return start;
}

int main()
{
	char arr1[] = {"love you"};
	char arr2[] = { "like me" };
	my_strnpy(arr2, arr1,4);
	printf("%s\n", arr2);
	return 0;
}

介绍并使用strncat函数:

与strcat相比较:

相同点都可以实现对字符串的追加。

不同点strncat按自我需求调整所追加的字符串的长度。

                strcat只能将一个字符串全部内容追加到另一个字符串当中。

追加的时候是从目的地字符数组的'\0'处开始追加。

看一组代码:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = {"abcd"};
	char arr2[20] = { "asdf " };
	strncat(arr2, arr1, 4);
	printf("%s\n", arr2);
	return 0;
}

通过调试来观测一下:

        初始化之后:

进入函数之后:

        

注意:这是后也没有主动追加'\0',可以最后手动追加

模拟实现strncat函数:

        

char* my_strncat(char* arr1, const char* arr2, size_t num)
{
	assert(arr1 != NULL);
	assert(arr2 != NULL);
	char* start = arr1;
	while (*arr1)
	{
		arr1++;
	}
	while (num)
	{
		*arr1++ = *arr2++;
		num--;
	}
	return start;
}
int main()
{
	char arr1[20] = {"love me "};
	char arr2[] = { "like you" };
	my_strncat(arr1, arr2, 4);
	printf("%s\n", arr1);
	return 0;
}

介绍并使用strncmp函数:

        

相关介绍和返回值,发现和strcmp函数的返回值是一样的。

区别:除了多了一个参数num,也就是你要比较几个字符之外,其他的都是一样的。

int main()
{
	char arr1[] = {"abcdef"};
	char arr2[] = { "abcds" };
	int a =  strncmp(arr1, arr2,5);
	if (a == 0)
	{
		printf("=");
	}
	else if (a < 0)
	{
		printf("<");
	}
	else
	{
		printf(">");
	}

	return 0;
}

模拟实现strncmp函数

        

int my_strncmp(const char* arr1, const char* arr2, size_t num)
{
    assert(arr1 != NULL);
    assert(arr2 != NULL);
	while ( *arr1 - *arr2 == 0)
	{
		arr1++;
		arr2++;
		num--;
		if (num-1 == 0)
		{
			break;
		}
	}
	return *arr1-*arr2;
}
int main()
{
	char arr1[] = {"abcd"};
	char arr2[] = {"abfde"};
	int a = my_strncmp(arr1,arr2,4);
	 if (a == 0)
			{
				printf("=");
			}
			else if (a < 0)
			{
				printf("<");
			}
			else
			{
				printf(">");
			}
	return 0;
}

其他类型库函数

介绍并使用strstr函数:

        

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

        

int main()
{
	char arr1[] = {"love you best"};
	char *arr =  strstr(arr1, "you");
	printf("%s\n", arr);
	return 0;
}

   在arr1中找you,找到第一次出现的地方返回第一次出现的首字符的地址。

打印结果:

如果找不到,就返回NULL;

例如:

int main()
{
	char arr1[] = {"love you best"};
	char *arr =  strstr(arr1, "yoo");
	printf("%s\n", arr);
	return 0;
}

打印结果:

注:这里找相同的字符串必须完全相同,差一个字符都不行!!

模拟实现strstr函数:

        首先通过画图来讲解:

        

char* my_strstr(const char* arr1, const char* arr2)
{
	char* cp = (char*)arr1;//表示arr1的红色指针
	char* a;//表示arr1的绿色指针
	char* b;//表示arr2的绿色指针
	while (*cp)
	{
		if (*cp == *arr2)
		{
			a = cp;
			b = (char*)arr2;
			while (*cp == *b)
			{
				cp++;
				b++;
				if (*b == '\0')
					return a;
			}
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char arr1[] = { " welcom next new world" };
	char arr2[] = {"new"};
	 char *str = my_strstr(arr1, arr2);
	 printf("%s\n", str);
	return 0;
}

介绍并使用memcpy(内存拷贝函数)函数:

        

之前探讨了strcpy和strncpy,这两个库函数是用来拷贝字符串的,其它类型的不能拷贝,那么其他类型的数据该如何拷贝呢?

        就需要用到memcpy函数,可以拷贝任意类型的数据!

例如:

int main()
{
	int arr1[] = {1,2,3,4,5};
	int arr2[20];
	memcpy(arr2,arr1, 20);
	return 0;
}

需要三个参数,目的地地址,源头地址,需要拷贝的字节数,

        通过调试发现:

拷贝成功!

模拟实现memcpy函数

void* my_memcpy(void* str1, const void *str2, size_t sz)
{
	void* start = str1;
	assert(str1 && str2);
	while (sz)
	{
		*(char*)str1 = *(char*)str2;
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
		sz--;
	}
	return start;
}
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[10];
	my_memcpy(arr2,arr1,20);
	return 0;
}

拷贝完成!

但是,这回突发奇想,想将arr1中的前4个拷贝到从第二个整形开始。可不可以呢?

void* my_memcpy(void* str1, const void *str2, size_t sz)
{
	void* start = str1;
	assert(str1 && str2);
	while (sz)
	{
		*(char*)str1 = *(char*)str2;
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
		sz--;
	}
	return start;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9 };
	my_memcpy(arr1+2,arr1,16);
	return 0;
}

发现是不可以的,那么如果我要实现重叠部分的拷贝,应该怎么办,可以使用库函数中的memmove函数!

        接下来就来探究一下memmove函数!

介绍并使用memmove函数

和memcopy相比,memmove可以完成重叠部分的拷贝工作!

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9 };
	memmove(arr1+2,arr1,16);
	return 0;
}

发现可以进行重叠部分的拷贝!

模拟实现memmove函数:

        那么应该怎样拷贝,才不会出现在memcpy中的情况呢,这里分为三种情况:

1、源头地址在目的地的左侧,源头低地址,目的地高地址。

此时不会再出现被覆盖的情况。

2、源头地址在目的地的左右侧,源头高地址,目的地低地址。

3、源头和目的地没有重叠部分

这种情况怎么拷贝都行,只要空间够用即可。

以上这几种情况就是memmove函数的思路!

以下是代码:

void* my_memmove(void* str1, void* str2, size_t num)
{
	void* start = str1;
	int sz = num;
	if (str1 > str2)
	{
		while (sz)
		{
			str2 = (char*)str2+1;
			str1 = (char*)str1 + 1;
			sz--;
		}
		while (sz != num)
		{
			*(char*)str1 = *(char*)str2;
			str1 = (char*)str1-1;
			str2 = (char*)str2 - 1;
			sz++;
		}
	}
	else 
	{
		while (sz--)
		{
			*(char*)str1 = *(char*)str2;
				str1 = (char*)str1 + 1;
				str2 = (char*)str2 + 1;
		}
	}
	return start;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9 };
	my_memmove(arr1,arr1+2,12);
	return 0;
}

        

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

gpt-4o api申请开发部署应用:一篇全面的指南

利用 GPT-4o API 开发创新应用&#xff1a;一篇全面的指南 OpenAI 的 GPT-4o 是一款集成了音频、视觉和文本处理能力的多模态人工智能模型&#xff0c;它的出现代表了人工智能领域的重大进步。在本篇文章中&#xff0c;我们将详细介绍如何通过 OpenAI API 使用 GPT-4o&#xf…

xcode开发swift允许发送http请求设置

Xcode 现在新建项目默认只支持HTTPS请求&#xff0c;认为HTTP请求不安全&#xff0c;所以不支持。但是开发环境一般都是http模式&#xff0c;所以需要单独配置才可以访问。 需要到项目的设置里面&#xff0c;点击info&#xff0c;如果没有App Transport Security Setting这一项…

【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(二)

Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查询、部分字段查询 3、Spring Data JPA数据批量插入、批量更新真的用对了吗 4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作 5、Spring Data JPA自定…

生信分析进阶3 - pysam操作bam文件统计unique reads和mapped reads高级技巧合辑

pysam操作bam文件统计unique reads和mapped reads高级技巧 1. Linux服务器读取bam文件 服务器查看bam常用方法。 # bam_path&#xff1a; bam文件路径 samtools view -h bam_path|grep -v ^|less -S2. samtools python os库读取bam文件 缺点速度较慢。 import os# 读取ba…

springboot从2.7.2 升级到 3.3.0

文章目录 概要准备报错调整小结后记 概要 时代在进步&#xff0c;springboot已经来到了3.3.0 , 于是我们也打算升级下sbvadmin到3.3&#xff0c; jdk使用21的版本&#xff0c;下面是升级过程中碰到的一些问题&#xff0c;问题不大。 2.7.2 -> 3.3.0 准备 下载jdk21&#…

AdroitFisherman模块安装日志(2024/5/31)

安装指令 pip install AdroitFisherman-0.0.29.tar.gz -v 安装条件 1:Microsoft Visual Studio Build Tools 2:python 3.10.x 显示输出 Using pip 24.0 from C:\Users\12952\AppData\Local\Programs\Python\Python310\lib\site-packages\pip (python 3.10) Processing c:\u…

UML静态图-类图

概述 静态图包含类图、对象图和包图的主要目的是在系统详细设计阶段&#xff0c;帮助系统设计人员以一种可视化的方式来理解系统的内部结构和代码结构&#xff0c;包括类的细节、类的属性和操作、类的依赖关系和调用关系、类的包和包的依赖关系。 一、类图的表示法 类图(Cla…

【linux】自定义快捷命令/脚本

linux自定义快捷命令 场景自定义命令自定义脚本 场景 深度学习经常要切换到自己环境&#xff0c;conda activate mmagic&#xff0c;但是又不想每次重复打这么多字&#xff0c;想使用快捷命令直接切换。 自定义命令 使用别名&#xff08;alias&#xff09;或自定义脚本来创建…

【期末速成】——计算机组成原理(1)

目录 一、什么是计算机的组成 二、冯诺依曼体系结构计算机的特点 三、计算机系统的层次结构 四、机器语言、汇编语言、高级语言, 五、 编译程序、解释程序、汇编程序 六、已知主频、CPI计算程序运行时间 一、什么是计算机的组成 计算机的组成可以分为五个部件和两个信息…

10.Halcon3D点云和MESH的相互转换

1.实现效果 这个案例主要是想告诉我们,如何在点云数据(全是点)和MESH(网格数据)中转换,理论上说可以点云数据可以看作的离散的,而MESH网格数据可以看作是连续的。 上图展示了三个(其实是四个)空间中的3d对象,左边第一个是一个立方体,经过降采样之后的点云,中间的是…

systemctl 添加自定义系统服务

以 “启动、停止、重启” boa web server为例&#xff1a; 1. 编写系统服务脚本 编写一个符合系统服务规范的脚本。这个脚本通常描述了服务的启动、停止、重启等行为。你可以使用shell、C、C、Java等语言来编写这个脚本。 # boa_server_run.sh&#xff1a;#!/bin/bashset -e …

浅谈申请小程序地理位置权限的正确打开方式

小程序地理位置接口有什么功能&#xff1f; 这篇内容会教大家如何快速申请“获取当前的地理位置&#xff08;onLocationChange&#xff09;”接口&#xff0c;以便帮助大家顺利开通接口。以下内容是本人经历了多次的申请经历得出来的经验&#xff0c;来之不易&#xff0c;望大家…

基础—SQL—DQL(数据查询语言)分页查询

一、引言 上一篇博客学习了排序查询&#xff0c;这次来讲查询的最后一个部分&#xff1a;分页查询。 涉及到的关键字是&#xff1a;LIMIT 。 二、DQL—分页查询 对于分页&#xff0c;不管以后做的是传统的管理系统还是做互联网的项目&#xff0c;基本上都会遇到分页查询的操…

【C语言】常见的动态内存的错误

前言 在动态内存函数的使用过程中我们可能会遇到一些错误&#xff0c;这里将常见的错误进行总结。 对NULL解引用 请看以下代码&#xff1a; 可以看到&#xff0c;这时我们的malloc开辟是失败的&#xff0c;所以返回的是空指针NULL&#xff0c;而我们却没有进行检查&#xff0…

东莞酷得智能 组装机械狗电子玩具方案

这款机械狗玩具电子方案结合了现代电子技术和人工智能元素&#xff0c;旨在为用户提供一个高科技、互动性强的娱乐体验。通过不断的软件更新和硬件迭代&#xff0c;机械狗的功能将持续扩展。 一、功能特点&#xff1a; 1、自动巡游&#xff1a;机械狗能够自主在房间内巡游&am…

计算机组成原理-----实验1

实 验 报 告 实验一 基本运算器实验 1、实验目的 &#xff08;一&#xff09;了解运算器的组成结构&#xff1b; &#xff08;二&#xff09; 掌握运算器的工作原理&#xff1b; &#xff08;三&#xff09;熟悉运算器的数据传送通路&#xff1b; &#xff08;四&#xff09;按…

Amis源码构建 sdk版本

建议在linux环境下构建&#xff08;mac环境下也可以&#xff09;&#xff0c;需要用到sh脚本&#xff08;amis/build.sh&#xff09;。 Js sdk打包是基于fis进行编译打包的&#xff0c;具体可见fis-conf.js&#xff1a; amis-master源码下载:https://github.com/baidu/amis g…

推荐几款优秀的文档加密软件 | 企业文件加密解决方案

在数字化时代&#xff0c;信息安全问题日益突出&#xff0c;文档加密软件成为了保护数据安全的重要手段。但是&#xff0c;市面上的文档加密软件种类繁多&#xff0c;功能各异&#xff0c;如何选择一款好用的文档加密软件成为了许多用户关注的焦点。本文将为大家提供一份实用的…

@Value 读取环境变量配置

在项目开发过程中&#xff0c;有必要使用一些灰色规则&#xff08;即仅用于开发使用过程中的逻辑控制变量&#xff09;。 比如&#xff0c;本地开发中&#xff0c;一些业务逻辑需要调用第三方代码&#xff0c;但又在本地调不通&#xff0c;怎么办。只能通过 if(本地开发) {mock…

手拉手springboot整合kafka发送消息

环境介绍技术栈springbootmybatis-plusmysqlrocketmq软件版本mysql8IDEAIntelliJ IDEA 2022.2.1JDK17Spring Boot3.1.7kafka2.13-3.7.0 创建topic时&#xff0c;若不指定topic的分区(Partition主题分区数)数量使&#xff0c;则默认为1个分区(partition) springboot加入依赖kafk…