字符串函数精讲1

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

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.mfbz.cn/a/200684.html

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

相关文章

java学习part24异常throws

127-异常处理-异常处理方式二&#xff1a;throws_哔哩哔哩_bilibili 1.方法throws 2.如何抉择try和throws 3.手动throw语句 抛出一些java语法上没错但是不符合实际情况的异常。 用throw手动抛&#xff0c;方法上必须加throws。除非是运行时异常。 4.自定义异常

Java常见CodeReview及编码规范

鉴于自己的开发经验,以及常见容易产生bug及性能问题的点做个记录. 1.数据库 如果开发人员的经验不足,Java通过ORM(Mybatis)对数据库的操作的性能问题比较隐蔽.因为不压测或者异常case没发生的时候一般发现不了问题.特别是异常case发生的时候. 除配置表以外的sql都要经过expl…

软件设计师——程序设计语言基础(一)

&#x1f4d1;前言 本文主要是【程序设计语言基础】——程序设计语言基础的相关题目&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#…

荣耀冲击高端,一边推新「修路」,一边降价「拆桥」

作者 | 辰纹 来源 | 洞见新研社 从2020年11月17日与华为分家&#xff0c;开启独立创业之路&#xff0c;到成功逆袭&#xff0c;今年第三季度以18%的份额重回中国智能手机市场榜首&#xff0c;荣耀用了3年时间。 图源&#xff1a;Canalys 在这三年时间内&#xff0c;荣耀经历…

【算法萌新闯力扣】:环形链表及环形链表II

力扣题目&#xff1a;环形链表及环形链表II 开篇 今天是备战蓝桥杯的第26天和算法村开营第4天。挑选了链表的黄金关卡与大家分享。 题目一&#xff1a;环形链表 题目链接: 141.环形链表 题目描述 方法一、哈希表 判断是否有环&#xff0c;可以利用哈希表&#xff0c;遍历…

‘tsc‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

最近在用nodejs typescript 某游戏服务器在做一些研究 nodejs-tcs 问题描述&#xff1a; 1.使用命令npm install -g typescript安装typescript后&#xff0c;输入 tsc命令&#xff0c;一直报错 tsc 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 2.目…

算法面试题--树与对象数组的转化

1. Array -> Tree var arr [{ id: 12, parentId: 1, name: "朝阳区" },{ id: 241, parentId: 24, name: "田林街道" },{ id: 31, parentId: 3, name: "广州市" },{ id: 13, parentId: 1, name: "昌平区" },{ id: 2421, parentId:…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之存储管理(1)》(14)

[TOC](《Linux操作系统原理分析之存储管理》&#xff08;14&#xff09; 5 存储管理5.1 存储管理的目的和功能5.1.1 存储管理目的&#xff1a;5.1.2 存储管理的主要功能5.1.3 存储管理主要是对用户区进行管理 5.2 地址重定位5.2.1 作业的地址空间5.2.2&#xff0e;地址映射&…

Linux基本指令汇总

本专栏内容为&#xff1a;Linux学习专栏&#xff0c;分为系统和网络两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握Linux。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;Linux从入门到精通 &#x1f69a;代码仓库&#xff1a;小…

UI自动化测试工具工作原理是怎样的?

随着软件开发的不断演进&#xff0c;保障软件质量成为了至关重要的一环。在这个过程中&#xff0c;UI自动化测试工具崭露头角&#xff0c;为开发团队提供了一种强有力的方式来确保应用程序的稳定性、功能性和兼容性。本文将深入探讨UI自动化测试工具的定义、工作原理以及其在提…

名字大却不中用的AI大模型,名不副实

这两天 OpenAI 团队&#xff08; ChatGPT 公司&#xff09;的戏比较多&#xff0c;两三天的功夫&#xff0c;剧情发展都超出了 OpenAI 首席科学家的预期&#xff0c;目前来看&#xff0c;微软还是最大的赢家。这是个引子&#xff0c;这个话题&#xff0c;网络上早已传烂了&…

InnoDB存储引擎中的锁

文章目录 概要一、需要解决的问题二、共享锁和独占锁1.1 锁定读1.2 表级别的共享锁、独占锁 三、行锁3.1 数据准备3.2 几种常见的行级锁3.3 行锁升级为表锁 概要 关于MySQL涉及到的锁&#xff0c;大致可以总结如下&#xff1a; MyISAM存储引擎在开发过程中几乎很少使用了&…

【重磅合作】九章云极DataCanvas公司与生态伙伴强强联手,构建人工智能强生态!

11月21日&#xff0c;在「筑基赋能 智向未来」九章云极DataCanvas大模型系列成果发布会上&#xff0c;九章云极DataCanvas公司与人工智能产业链上下游合作伙伴广东民营投资股份有限公司&#xff08;以下简称“粤民投”&#xff09;、西藏赛富合银投资有限公司&#xff08;以下简…

通过流量监控分析某个部门或客户端网络性能

在当今数字化时代&#xff0c;网络已经成为组织和企业不可或缺的基础设施之一。作为信息传输和数据交互的关键载体&#xff0c;网络的性能对于保障业务的稳定运行和提升工作效率至关重要。因此&#xff0c;对某个部门或客户端网络的性能进行分析和评估&#xff0c;有助于了解当…

vue2 el-table 封装

vue2 el-table 封装 在 custom 文件夹下面创建 tableList.vue直接上代码&#xff08;代码比较多&#xff0c;复制可直接用&#xff09; <template><div class"mp-list"><el-tableref"multipleTable"class"mp-custom-table":dat…

解决d3dcompiler_43.dll文件丢失的方法,最详细的d3dcompiler_43.dll修复指南

如果你的电脑出现了d3dcompiler_43.dll文件丢失的问题&#xff0c;你知道要怎么去解决么&#xff1f;其实要解决这个问题还是比较简单的&#xff0c;只要你了解清楚d3dcompiler_43.dll文件&#xff0c;那么就知道有多种不同的方法可以去解决它&#xff0c;下面我们一起来看看吧…

bodymovin:AE动画导出为JSONforMac/win中文版下载

对于动画制作爱好者和专业设计师来说&#xff0c;Adobe After Effects&#xff08;AE&#xff09;是一个强大的工具&#xff0c;可以创造出惊人的动画效果。然而&#xff0c;将这些动画导出为可交互的格式一直是一个挑战。现在&#xff0c;有了bodymovin&#xff0c;你可以轻松…

【C++初阶】:简单的图书管理系统(可保存,完整源代码)

图书管理系统 library.h #include<iostream> #include<string> #include<vector> using namespace std;/****************************************************************公共类**********************************************************************…

element-plus 使用密码输入框的自定义图标

<el-inputv-model"ruleFormPassword.newPassword"placeholder"请输入新密码":type"showPassword ? text : password":style"{ width: 360px }"><template #suffix><span class"input_icon" click"swit…

视频智能分析国标GB28181云平台EasyCVR加密机授权异常是什么原因?

国标GB28181视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等。 近期有用户选择使用加密机进行EasyCVR授…