字符串函数精讲1

news2024/11/26 9:44:32

又是好几天没有更新了,最近有些忙,但这并不是理由,还是怪我自己玩的时间多了!但还是有在每天敲代码的!话不多说,开始这一期的学习:

strlen的使用和模拟实现

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

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

• 注意函数的返回值为size_t,是⽆符号的( 易错 )

• strlen的使用需要包含头文件 

strlen的使用:

 字符串中一共有13个字符,末尾是以\0结尾的,我们strlen函数再计算字符个数时,\0不计入其中,遇到\0才会停下来!如果末尾没有\0的话,strlen就会一直寻找它的\0,直到遇到\0才会停下来,可能会存在越界访问!所以在使用时,一定要注意!而且要加上相应的头文件哦!

strlen的模拟实现:

方法一:

既然它遇到\0就会停止,那么我们就可以创建一个变量(count)来计数,如果arr[i]不为0,那么我们就count++;

#include <stdio.h>
size_t my_strlen(char* str)
{
	int count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "i want to try";
	size_t len = my_strlen(arr);
	printf("%zu", len);
	return 0;
}

方法二:

我们可以利用指针-指针的绝对值等于之间的元素个数来模拟,我们首先保存数组的首元素地址,接着我们找到\0的位置,然后两指针相减就可以知道了。

#include <stdio.h>
size_t my_strlen(char* str)
{
	char* start = str;
	while (*str)
	{
		str++;
	}
	return str-start;
}
int main()
{
	char arr[] = "i want to try";
	size_t len = my_strlen(arr);
	printf("%zu", len);
	return 0;
}

方法三:

第三种方法我们可以利用函数递归的方法进行计算,举个例子:我们要计算的是“hello”这个字符串,那么就是hello-> 1+ello ->1+1+llo ->1+1+1+lo -> +……+1+1+1+1+1+'\0' = 5;

#include <stdio.h>

size_t my_strlen(char* str)
{
	if (*str == '\0')
	{
		return 0;
	}
	else
	{
		return 1 + my_strlen(str + 1);
	}
}

int main()
{
	char arr[] = "i want to try";
	size_t len = my_strlen(arr);
	printf("%zu", len);
	return 0;
}

strcpy 的使用和模拟实现:

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

会将源字符串中的 '\0' 拷⻉到⽬标空间。

⽬标空间必须⾜够⼤,以确保能存放源字符串。

⽬标空间必须可修改。

strcpy 的使用:

 我们这时可以打开监视,看一看arr里面的情况,是只拷贝了abcd,还是把'\0'也拷贝了过去!

 可以看见是把我们的\0也拷贝过去的,所以这些小细节我们一定要拿捏好,哈哈。

strcpy 的模拟实现:

怎样实现我们strcpy的模拟实现呢?那么就是当我们源字符串不为\0时,我们就改变目的字符串的字符,直到源字符串的字符为0时,我们就跳出循环,接着把\0也copy过去!

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

char* my_strcpy( char* str1, const char* str2)
{
	char* ret = str1;//保存str1的首地址,下面需返回首地址打印,ret在下面代码中的位置会被改变
    assert(str1 && str2);//断言是否为空指针
	while (*str2 != '\0')
	{
		*str1 = *str2;
		str1++;
		str2++;
	}
	*str1 = *str2;//把\0也拷贝过去
	return ret;
}

int main()
{
	char arr1[] = "happy new year!";
	char arr2[] = "hello baby";
	
	printf("%s", my_strcpy(arr1, arr2));
	return 0;
}

其实上述的代码中while部分的代码还可以这样写:

while((*dest++ = *src++))
 {
     ;
 }

加加的优先级高于简引用,后置加加所以是先使用再进行加加运算,当*src为\0时,赋值给*dest后,循环条件终止跳出循环!


strcat 的使用和模拟实现:

 

源字符串必须以 '\0' 结束。
⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
⽬标空间必须有足够的⼤,能容纳下源字符串的内容。
⽬标空间必须可修改。

strcat 的使用:

 就是再arr1后面追加arr2的内容,我们去看一看是否把\0也追加了过去!

那么我们可以看见也是把\0追加了过去!那么我们的这个strcat函数,可以自己给自己追加吗?

 我们可以看出,\0的位置被改成了b,那么我们的arr2就不会指向我们的\0的位置,就会成为死循环状态,那么对于自己给自己追加的话,我们后面会讲到一种函数(strncat),它就能自己给自己追加!

strcat 的模拟实现:

我们有了上面模拟strcpy的知识,那么对于这个函数,我们就只需要再前面找到arr1\0的位置,然后进行copy就可以了!

#include <stdio.h>
#include <assert.h>
char* my_strcat(char* str1, const char* str2)
{
	char* ret = str1;
	assert(str1 && str2);
	while (*str1)
	{
		str1++;
	}//找到str1的\0的位置
	while (*str1++ = *str2++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello\0xxxxxxx";
	char arr2[] = "baby";
	printf("%s", my_strcat(arr1, arr2));
	return 0;
}

strcmp 的使⽤和模拟实现:

 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字

第⼀个字符串等于第⼆个字符串,则返回0

第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
那么如何判断两个字符串? ⽐较两个字符串中对应位置上字符ASCII码值的⼤⼩。

strcmp 的使用:

 strcmp 的模拟实现:

当我们arr1和arr2指向的位置的字符相等时,我们就指向下一个字符进行比较,当所指向的字符不相等时,我们就比较此时所指向的字符的ASCII值的大小来进行返回值!但是还有一种情况,当我们的arr1所指向的元素为/0时,说明此时已经比较完了,说明两字符串是相等的,那么此时我们就可以返回0!

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

int my_strcmp(const char* str1, const char* str2)
{
    assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
		{
			return 0;
		}
		str1++;
		str2++;
	}

	return *str1 - *str2;

	/*if (*str1 > *str2)//也可以写成这种
	{
		return 1;
	}
	else
	{
		return -1;
	}*/
}
int main()
{
	char arr1[] = "abcd";
	char arr2[] = "abcd";
	int ret = my_strcmp(arr1, arr2);
	if (ret > 0)
	{
		printf("大于\n");
	}
	else if (ret == 0)
	{
		printf("等于\n");
	}
	else
	{
		printf("小于\n");
	}
	return 0;
}

strncpy 函数的使用和模拟实现:

 

拷⻉num个字符从源字符串到⽬标空间。
如果源字符串的长度小于num,则拷宝完源字符串之后,在⽬标的后边追加0,直到为num。

 

strncpy 函数的使用 :

我们可以根据打印出来的结果知道,此时并没有把arr2中的copy过去,因为如果copy过去的话,那么我们就只会看见hello!那么我们的num如果大于我们字符串的长度,会是什么结果呢?我们一起来看一看:

我们可以看见当我们的num大于我们的arr2的字符串长度时,我们的\0时拷贝过去了的,那么是拷贝了几个呢?我们一起看看咯:

是两个\0,那么我们就可以知道了:如果源字符串的长度小于num,则拷宝完源字符串之后,在⽬标的后边追加0,直到为num!

​​​​​​​strncpy 函数的模拟实现: 

我们有了上面模拟strcpy的经验,那么对于此函数我们想要模拟也不难咯!那么当我们的num小于等于我们的字符串的长度时,我们此时就以num为循环条件,当我们的num变为0时,我们就跳出循环,返回arr1的首元素地址:

if (num <= len)
{
	while (num--)
	{
		*dest = *src;
		dest++;
		src++;

	}
	return ret;
}

当大于的时候,我们除了copy完我们arr2的字符外,还要copy我们的\0,那么多出来的此数就copy我们的\0!

else
{
	while (len--)
	{
		*dest = *src;
		dest++;
		src++;
	}
	for (size_t i = a; i < num; i++)
	{
		*dest = '\0';
		dest++;
	}
	return ret;
}

我们来看看整体的代码:

char* my_strncpy(char* dest, const char* src, size_t num)
{
	char* ret = dest;
	assert(dest && src);
	size_t len = strlen(src);
	size_t a = len;//保存len的值,下面要用,因为len的值被改变了
	if (num <= len)
	{
		while (num--)
		{
			*dest = *src;
			dest++;
			src++;

		}
		return ret;
	}
	else
	{
		while (len--)
		{
			*dest = *src;
			dest++;
			src++;
		}
		for (size_t i = a; i < num; i++)
		{
			*dest = '\0';
			dest++;
		}
		return ret;
	}
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strncpy(arr1, arr2, 7);
	printf("%s", arr1);
	return 0;
}

我们还可以用其他的方法,用两个for循环就可以解决问题了:

char* my_strncpy(char* dest, const char* src, size_t n) 
{
	size_t i;
	for (i = 0; i < n && src[i] != '\0'; i++)
	{
		dest[i] = src[i];
	}
	for (; i < n; i++) 
	{
		dest[i] = '\0';
	}
	return dest;
}

 i < n && src[i] != '\0'这样就很好的解决了我们的问题!


strncat 函数的使用和模拟实现:

Appends the first num characters of source to destination, plus a terminating null-character. (将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追⼀个 \0 符)。
If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.(如果source 指向的字符串的⻓度⼩于num的时候,只会将字符串中到 \0 的内容追加到destination指向的字符串末尾)。

strncat 函数的使用:

 我们的num值为3,那么·追加过去的除了wor三个字符,还有我们的\0。那么如果我们追加的Num值大于字符串长度呢?又会是什么样的结果呢?一起来看一看:

那么可以看见不管多了多少,也只是在后面追加了一个\0!

strncat 函数的模拟实现:

这里就直接展示代码嘛:有了上面的经验,相信大家都是会的吧!

#include <stdio.h>
#include <assert.h>
//方法一:
char* my_strncat(char* dest, const char* src, size_t num)
{
	char* ret = dest;
	assert(dest && src);
	int j = 0;
	while (dest[j])
	{
		j++;
	}
	size_t i = 0;
	for (i = 0; i < num && src[i] != '\0'; i++)
	{
		dest[j] = src[i];
		j++;
	}
		dest[j] = '\0';
	return ret;
}

//方法二:
//char* my_strncat(char* destination, const char* source, size_t num)
//{
//    char* ptr = destination;
//    while (*ptr) 
//    {
//        ptr++;
//    }
//
//    while (*source && num) 
//    {
//        *ptr++ = *source++;
//        num--;
//    }
//
//    *ptr = '\0';
//
//    return destination;
//}
//
//int main() 
// {
//    char str1[30] = "Hello \0xxxxxxxx";
//    char str2[] = "World!";
//
//    printf("%s\n", my_strncat(str1, str2, 9));
//
//    return 0;
//}

strncmp函数的使用:

⽐较str1和str2的前num个字符,如果相等就继续往后⽐较,最多⽐较num个字⺟,如果提前发现不⼀ 样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0.

这里就讲一下怎么使用的,感兴趣的伙伴可以去模拟实现一下看看哦!

相信你们一定可以的!本期的内容就到此了,我们下期再见!

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

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

相关文章

Python实现学生信息管理系统(详解版)

Python实现学生信息管理系统-详解版 个人简介实验名称&#xff1a;学生信息管理系统系统功能实验步骤详讲添加入住学生信息删除学生的住宿信息修改学生的住宿信息查询学生的住宿信息显示所有学生住宿信息显示所有请假学生的信息 运行截图展示1.主界面2.添加新的入住学生信息3.显…

Java LeetCode篇-深入了解关于单链表的经典解法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 移除链表元素 1.1 使用双指针方法 2.0 反转链表 2.1 递归法 2.2 头插法 3.0 链表中倒数第 k 个节点 3.1 递归法 3.2 快慢指针 4.0 合并两个有序链表 4.1 递归法 …

java科学计数法表示数值

Background 大多数计算器及计算机程序用科学记数法显示非常大和非常小的结果&#xff1b;但很多时候&#xff0c;我们需要做一个统一&#xff0c;要么全部以科学计数法输出&#xff0c;要么就全部显示为普通计数。注意&#xff1a;这里对大于等于1的数据做了特殊处理&#xff0…

RocketMQ源码剖析之createUniqID方法

目录 版本信息&#xff1a; 写在前面&#xff1a; 源码剖析&#xff1a; 总计&#xff1a; 版本信息&#xff1a; RocketMQ-5.1.3 源码地址&#xff1a;https://github.com/apache/rocketmq 写在前面&#xff1a; 首先&#xff0c;笔者先吐槽一下RocketMQ的官方&#xff0…

用代码评论代替代码注释

在一个软件项目中&#xff0c;某些逻辑部分可能非常复杂&#xff0c;容易让人困惑。为了确保其他开发人员能够理解这些代码&#xff0c;同时也为了自己回顾时能够快速上手&#xff0c;我们通常会编写相关文档或添加大量注释来对这些复杂的逻辑进行解释。这样做的好处是能够提高…

1.自动化运维工具Ansible的安装

1.物料准备 四台服务器&#xff0c;其中一个是主控机&#xff0c;三个为host 2.安装 在主控机上安装ansible 2.1 设置EPEL仓库 Ansible仓库默认不在yum仓库中&#xff0c;因此我们需要使用下面的命令启用epel仓库。 yum install epel-release -y2.2 执行安装命令 yum i…

香港人均gdp世界排名,和内地相比怎么样?

香港人均gdp世界排名&#xff0c;和内地相比怎么样&#xff1f; 香港作为世界贸易港口&#xff0c;也是中国最发达的城市之一。其经济相比于北上广深而言&#xff0c;都要发达。香港人均收入世界排名第18&#xff0c;人均收入为4.2万美元&#xff0c;在世界各国人均收入排名中处…

八个优秀开源内网穿透工具

内网穿透&#xff08;NAT穿透&#xff09;是一种将本地网络服务暴露给互联网的一种技术。这种技术可以很好地解决许多局域网内的资源共享。采用路由的方式将一台计算机变成一个“路由器”&#xff0c;将公共的网络地址转为内部网络地址&#xff0c;从而实现通过英特网可以访问局…

dbeaver连接amabri-hbase

目录 尝试过程 解决之道 总结 尝试过程 注意此章节为记录试错过程&#xff0c;无需跟随操作&#xff0c;仅作试错记录。真正操作方法请看“解决之道”章节 环境ambari安装的hbase2.1.6 使用apche phoenix默认驱动配置 备注&#xff1a;Apache Phoenix 是一个开源的、基于…

软件设计师——法律法规(一)

&#x1f4d1;前言 本文主要是【法律法规】——软件设计师法律法规的题目&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日…

7 种 JVM 垃圾收集器详解

一、概述 如果说收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回收的具体实现。Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定&#xff0c;因此不同的厂商、版本的虚拟机所提供的垃圾收集器都可能会有很大差别&#xff0c;并且一般都会提供参数供用…

国内外四款SAST工具约登指数

开放Web应用程序安全项目&#xff08;OWASP&#xff09;&#xff0c;是一个非营利性基金会&#xff0c;致力于提高软件的安全性。OWASP Benchmark是一个免费和开放的测试套件。主要是通过Java语言基准测试案例对SAST工具进行评价。通过Yonden Index(约登指数)进行计算。约登指数…

量子力学应用:探索科技前沿的奇幻之旅

量子力学应用:探索科技前沿的奇幻之旅 引言 量子力学,这门探讨微观世界规律的学科,自其诞生以来就充满了神秘与奇幻。随着科学技术的不断进步,量子力学已经从纯理论研究走向了实际应用领域,为我们打开了一个全新的科技世界。在本文中,我们将深入探讨量子力学的应用方面,…

从 Elasticsearch 到 SelectDB,观测云实现日志存储与分析的 10 倍性价比提升

作者&#xff1a;观测云 CEO 蒋烁淼 & 飞轮科技技术团队 在云计算逐渐成熟的当下&#xff0c;越来越多的企业开始将业务迁移到云端&#xff0c;传统的监控和故障排查方法已经无法满足企业的需求。在可观测理念逐渐深入人心的当下&#xff0c;人们越来越意识到通过多层次、…

深入了解HMAC加密技术:原理、应用与实践

一、引言 在网络安全领域&#xff0c;消息认证码&#xff08;MAC&#xff09;是一种重要的技术手段。Hash-based Message Authentication Code&#xff08;HMAC&#xff09;作为其中的一种&#xff0c;凭借其简单、高效、安全的特性&#xff0c;广泛应用于各种网络通信场景。本…

数据结构与算法--特殊的完全二叉树--堆,堆排序,利用堆解决topk的问题

目录 前言 1.树概念及结构 1.1树的概念 1.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2.二叉树概念及结构 2.1概念 2.2现实中的二叉树&#xff1a; 2.3 特殊的二叉树&#xff1a; 2.4 二叉树的性质 …

网络篇---第五篇

系列文章目录 文章目录 系列文章目录前言一、如何实现跨域?二、TCP 为什么要三次握手,两次不行吗?为什么?三、说一下 TCP 粘包是怎么产生的?怎么解决粘包问题的?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站…

解码 SQL:深入探索 Antlr4 语法解析器背后的奥秘

探寻SQL的背后机制 前言 在数据领域&#xff0c;SQL&#xff08;Structured Query Language&#xff09;是一门广泛使用的语言&#xff0c;用于查询和处理数据。你可能已经使用过诸如MySQL、Hive、ClickHouse、Doris、Spark和Flink等工具来编写SQL查询。 每一种框架都提供了…

ASEM工控机维修工业电脑控制器维修PB3400

ASEM工控机维修asem工业电脑维修常见型号&#xff1a;PB3400;PB2000;PB3200;PB3600&#xff1b;BM2200等。 ASEM工控机维修常见故障有&#xff1a;开不了机、黑屏、不能启动、电路板故障、主板、开机没反应、显示器没反应、主板故障、蓝屏、卡机、显示器信号灯一直闪、系统不能…

PlantUML语法(全)及使用教程-用例图

目录 1. 用例图1.1、什么是用例图1.2、用例图的构成1.3、参与者1.4、用例1.4.1、用例基本概念1.4.2、用例的识别1.4.3、用例的要点1.4.3、用例的命名1.4.4、用例的粒度 1.5、应用示例1.5.1、用例1.5.2、角色1.5.3、改变角色的样式1.5.4、用例描述1.5.5、改变箭头方向1.5.6、使用…