赶紧来修炼内功~字符串函数详解大全(一)

2023-11-17

目录

1.strlen

重点:

模拟实现:

法一:

法二:

法三:

2.strcpy

重点:

模拟实现:

3.strcat

重点:

模拟实现:

4.strcmp

重点:

模拟实现


1.strlen

strlen函数是用来计算字符串长度的

重点:

  1. 字符串以  '\0' 作为结束标志 strlen 函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )
  2. 注意函数的返回值为 size_t ,是无符号的( 易错
  3. 参数指向的字符串必须要 '\0' 结束

1. 

 

这里答案为6,确实是有6个字符,但是没有看到'\0'啊!

其实,'\0'是在最后一个字符后面自动添加的

 我们进一步验证该字符函数是以'\0'来计算字符串长度的我们可以在字符串的中间部分手动添加一个'\0'。

这时,字符串就提前终止,计算到的数值为3。

 2.

前面字符串的长度为3,后面字符串的长度为4,按理说应该是打印小于号,但是这里却是大于号!

其实,无论你怎么减,这里都只能是大于号,因为strlen函数的定义类型就是size_t类型,即无符号整形,所以无论如何他都是大于0的。

3.

 

如上图代码,字符串中只有4个字符,但是却输出有74个字符,那是因为,这种定义的字符串后面不会自动添加'\0',strlen函数要一直向后读取,直到找到'\0'为止,这个数值是随机的。 

 因此,strlen函数的参数指向的字符串必须要'\0' 结束

模拟实现:

创建一个my_strlen函数,模拟实现strlen函数的功能:

法一:

计数器的方式,只要遇到'\0'就停止

size_t my_strlen(const char* str)//返回值类型和参数与原函数保持一致
{
	int num = 0;
	while (*str != '\0')//当不等于'\0'时进入循环
	{
		num++;//计数器加一
		str++;//向后移动一位
	}
	return num;//最后循环结束,返回计数器的值,即为字符串的长度
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d\n", ret);
	return 0;
}

 法二:

不能创建临时变量计数器,使用递归算法:

size_t my_strlen(const char* str)//返回值类型和参数与原函数保持一致
{
	if (*str == '\0')//若该字符为'\0'就返回0.
		return 0;
	else
		return 1 + my_strlen(str + 1);//不是'\0'就返回1+my_strlen(str+1),实现递归
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d\n", ret);
	return 0;
}

法三:

 指针-指针的方式:(我们之前讲过指针-指针得到的时两个指针间的元素个数)

size_t my_strlen(const char* str)//返回值类型和参数与原函数保持一致
{
	char* p = str;//创建一个char* 类型保存字符串的起始位置
	while (*str != '\0')//当*str不为'\0'时,str++一下指向下一个字符,否则结束循环,
		str++;          //否则结束循环,得到字符串的结束位置
	return str - p;//最终两个指针相减,得到中间的元素个数
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d\n", ret);
	return 0;
}

2.strcpy

 strcpy函数是将source指向的字符串拷贝到destination指向的空间中,同时覆盖该空间中原有的字符串

重点:

  1. 源字符串必须 '\0' 结束
  2. 会将源字符串中的 '\0' 拷贝到目标空间
  3. 目标空间必须足够大,以确保能存放源字符串。
  4. 目标空间必须可变

 1.

与上一个strlen函数相似,这里需要'\0'来判断拷贝是否完成,当source指向的字符串读取到'\0'时拷贝就结束了。

2.

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

 通过监视,我们发现arr1字符串中有两个'\0',其中红色的'\0'是由arr2字符串拷贝过来的黑色的'\0'是arr1字符串中自带的

3.

这条就不用过多解释了吧,目标空间不够大的话根本拷贝不过去的,编译器也会报错。

4.

目标空间的内容必须可变,不能是常量字符串。

发生访问冲突,就是p指向的这个常量字符串不可以被修改,就不能使用strcpy函数。

模拟实现:

创建一个my_strcpy函数,模拟实现strcpy函数的功能: 

#include <assert.h>//assert函数所需的头文件
char* my_strcpy(char* dest, const char* src)//返回值类型和参数类型与原函数保持一致,
{//dest所指向的字符串需要被修改,不用const保护,src所指向的字符串不需要被修改用const修饰保护
	assert(dest && src);//断言一下,保证两个指针均不为空指针,若为空指针则中止程序并报错
	char* ret = dest;//创建一个char*变量保存起始地址,后面需要返回起始地址
	while (*dest++ = *src++)//将src所指向的内容赋值给dest所指向的内容,
		;                   //也可以赋值'\0'然后就被判定为假,退出循环
	return ret;//返回起始地址,容易形成链式访问
}
int main()
{
	char arr1[] = "xxxxxxxxxxx";
	char arr2[] = "abcdef";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

3.strcat

 在destination指向的字符串后面追加一个source指向的字符串

int main()
{
	char arr1[15] = "hello ";
	char arr2[] = "world!";
	strcat(arr1, arr2);

	return 0;
}

重点:

  1. 源字符串必须 '\0' 结束
  2. 目标空间必须有足够的大,能容纳下源字符串的内容。
  3. 目标空间必须可修改
  4. 会将源字符串中的 '\0' 拷贝到目标空间

1、2、3.

 与上面所诉的strcpy函数相似,这里就不多赘述了。

4.

int main()
{
	char arr1[15] = "hello \0xxxxxxx";
	char arr2[] = "world!";
	strcat(arr1, arr2);

	return 0;
}

  通过监视,我们发现arr1字符串中有两个'\0',其中红色的'\0'是由arr2字符串追加过来的黑色的'\0'是arr1字符串中自带的

模拟实现:

 创建一个my_strcat函数,模拟实现strcat函数的功能:

#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;         //上面的代码与前几个模拟实现的函数原因相同,这里就不多赘述了
	while (*dest != '\0')  //找到dest指针指向的字符串的末尾的'\0'
		dest++;
	while (*dest++ = *src++)//将src所指向的内容赋值给dest所指向的内容, 
		;                   //也可以赋值'\0'然后就被判定为假,退出循环
	return ret;//最后返回字符串的起始地址
}
int main()
{
	char arr1[15] = "abcdef";
	char arr2[] = "1234";
	printf("%s\n", my_strcat(arr1, arr2));
	return 0;
}

4.strcmp

strcmp是用来比较两个字符串大小的 

重点:

strcmp比较的是对应位置上字符的大小,而非字符串的长度

模拟实现:

创建一个my_strcmp函数,模拟实现strcmp函数的功能:

#include <assert.h>
int my_strcmp(const char* str1, const char* str2)//返回值类型和参数类型与原函数保持一致
{                 //该函数只是比较两个字符串的大小,不对字符串进行修改,所以用const保护起来
	assert(str1 && str2);    //断言,防止参数为NULL
	while (*str1 == *str2)   //比较字符,当两字符不同时就跳出来
	{
		if (*str1 == '\0')
			return 0;       //判断是否已经比较到了末尾,若为'\0'则表示两字符串相等
		str1++;
		str2++;
	}
	return *str1 - *str2;   //返回直接就用两字符相减
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcefg";
	printf("%d\n", my_strcmp(arr1, arr2));
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

赶紧来修炼内功~字符串函数详解大全(一) 的相关文章

  • 运行JDK代码时Java JIT会作弊吗?

    我正在对一些代码进行基准测试 但我无法让它运行得像java math BigInteger https docs oracle com javase 7 docs api java math BigInteger html 即使使用完全相同
  • JVM CPU 峰值故障排除

    我们在其中一台应用程序服务器上发现了一个有趣的 尽管相当严重 问题 在某个时间点 运行 Web 应用程序的 JVM 的 CPU 使用率开始上升 并持续上升 直到应用程序最终减慢到爬行 修复此问题的唯一方法是重新启动应用程序服务器软件 应用服
  • IntelliJ 调试:暂停整个虚拟机,然后进入单线程

    我正在调试一个具有大量线程的应用程序 我的断点设置为暂停整个虚拟机 当线程遇到其中一个断点时 我想使用 Step Over 但这似乎会恢复整个虚拟机 直到该步骤完成 如果我可以只单步执行到达断点的单个线程 那确实会有帮助 在 Intelli
  • 增加堆大小后无法启动 Glassfish

    我想增加 Glassfish 的堆大小 为此 我知道我可以达到 4GB java Xmx4000M version java version 1 6 0 26 Java TM SE Runtime Environment build 1 6
  • 从 Intellij 在远程主机上部署/运行 jvm 应用程序

    是否可以在 intellij 的远程服务器上部署 运行 出于测试目的 独立的 Java 应用程序 我并不是要连接到已经运行的 JVM 而是要从 intellij 在远程主机上启动一个新的 JVM 就像它在我的本地计算机上运行一样 目前没有内
  • 显示JVM中当前运行的所有线程组和线程

    所以我的任务是显示所有线程组以及当前在 JVM 中运行的属于这些组的所有线程 输出时应首先显示线程组 然后在下面显示该组中的所有线程 这是针对所有线程组完成的 目前 我的代码将仅显示每个线程组 然后显示每个线程 但我不确定如何达到我所描述的
  • Jprofile可以连接到docker中运行的JVM

    我是 JProfiler 的新手 我最近遇到了一个问题 我的Java应用程序在docker中运行 这意味着JVM在docker中运行 但我的jprofile安装在主机上 我知道 jprofiler 必须连接到 JVM 那么 jprofile
  • JVM HotSpot 上的 Java 异常计数器

    我想知道是否可以在不更改应用程序代码的情况下记录 JVM 级别上发生的每个异常 我所说的每个异常是指捕获和未捕获的异常 我想稍后分析这些日志并按异常类型 类 对它们进行分组 并简单地按类型对异常进行计数 我正在使用热点 也许有更明智的理由这
  • 哪种语言(在 JVM 上运行)最适合创建 DSL?

    我们需要创建复杂的固定长度和可变长度字符串 这些字符串可能代表客户资料 订单等 你们建议使用哪种基于 JVM 的编程语言 想法是让最终用户使用此 DSL 创建字符串 所以我正在寻找验证 代码完成等 Groovy http docs code
  • 如何在JVM不退出的情况下多次运行Java程序?

    假设我有一个Java程序Test class 如果我使用下面的脚本 for i in 1 10 do java Test done JVM每次都会退出java Test被调用 我想要的是跑步java Test在不退出JVM的情况下多次执行
  • 当 Java 中的集合超出容量时会发生什么?

    我有一个服务 它将所有对其进行的调用暂存在内存中 因为我们不想丢失数据 同时我们需要该服务因任何外部依赖项 例如数据库 而失败 然后 这些分阶段的调用会在后台例行接收和处理 如果出于任何原因 如果调用太多并且内存不足 我们就需要警惕 所以
  • 我的代码中出现内存不足异常

    作为 Oracle 数据库压力测试的一部分 我正在长时间运行代码并使用 java 版本 1 4 2 简而言之 我正在做的是 while true Allocating some memory as a blob byte data new
  • 为什么 JVM 同时具有“invokespecial”和“invokestatic”操作码?

    两条指令都使用静态而不是动态调度 似乎唯一的实质性区别是invokespecial始终将一个对象作为其第一个参数 该对象是分派方法所属类的实例 然而 invokespecial实际上并没有把物体放在那里 编译器负责通过在发出之前发出适当的堆
  • 如何查看JVM中JIT编译的代码?

    有什么方法可以查看 JVM 中 JIT 生成的本机代码吗 一般用法 正如其他答案所解释的 您可以使用以下 JVM 选项运行 XX UnlockDiagnosticVMOptions XX PrintAssembly 根据特定方法进行过滤 您
  • 如何减少Scala中创建的对象数量?

    我正在 Scala 中编写一个计算机图形应用程序 它使用 RGB 类返回图像中某个点的颜色 正如你可以想象的 返回颜色 RGB 对象的函数被调用了很多次 class RGB val red Int val green Int val blu
  • 在intellij中为java启用ssl调试

    从我的问题开始 上一期尝试通过 tls ssl 发送 java 邮件 https stackoverflow com questions 39259578 javamail gmail issue ready to start tls th
  • Scala 对大数的阶乘有时会崩溃,有时不会

    以下程序经过编译和测试 有时返回结果 有时充满屏幕 java lang StackOverflowError at scala BigInt apply BigInt scala 47 at scala BigInt equals BigI
  • jvm 如何以及何时何地更改 Linux 的最大打开文件值?

    在linux中 每个登录用户的每个进程的最大打开文件数有限制 如下所示 ulimit n 1024 当我学习java nio时 我想检查这个值 因为channel在Linux中也是一个文件 所以我编写了一个客户端代码来不断创建socketC
  • Bipush 在 JVM 中如何工作?

    我知道 iload 接受整数 1 到 5 但是如何使用 bipush 指令扩展到更高的数字 特定整数如何与字节码一起存储 有几种不同的指令可用于推送整数常量 最小的是iconst 指令 这些只是一个字节 因为该值是在操作码本身中编码的 ic
  • Kotlin 未解决的参考:CLI 上 gradle 的 println

    放一个printlnkotlin 函数返回之前的语句会崩溃 堆栈跟踪 thufir dur NetBeansProjects kotlin thufir dur NetBeansProjects kotlin gradle clean bu

随机推荐

  • 网管员牢记10种较为常见服务器管理错误

    网络管理阶层的工作就是保证网络的正常工作 从而使得职工们的工作不被打断 可问题在于事物并非总是按照理想状况发展 事实上经常会出现平地起风波的状况 其间有许多原因 这里我们只讨论10种较为常见的网管错误 1 UPS 不间断电源 的使用问题 某
  • Python+Requests-2-接口自动化脚本实现(虫师-Django接口测试实例)

    编写脚本前分析项目架构 需求 python脚本实现 添加发布会信息 的接口测试 以邮件形式发送测试报告 1 新建一个case目录 存放测试用例 2 新建一个config目录 存放配置信息和读取配置信息 3 新建一个db fixture目录
  • vue项目打包部署到服务器

    目录 一 打包项目 二 修改Nginx的配置 三 部署 四 开放端口号 一 打包项目 1 在 vue config js 文件中找到并修改 主要是publicPath 与outputDir 两项配置 若项目中有baseUrl 替换为publ
  • 【嵌入式学习-C语言篇】 char & short & int 的使用

    嵌入式学习 C语言篇 char short int 的使用 三种数据类型常用场景 智能家居 网关协议中mac地址上报 网关 网关 Gateway 又称网间连接器 协议转换器 网关在传输层以上实现网络互连 是最复杂的网络互连设备 仅用于两个高
  • STM32 进阶教程 7 -  C与C++混合编程

    前言 在嵌入式开发过程中经常会用到第三个芯片 设备 这些第三方的芯片提供的DEMO程序或驱动程序有时候是C 如果先前的系统用C语言写的就会出现点问题 往往需先将C 的驱动程序自已手动改成C语言再用 本节给大家介给一下如何在KEL MDK环境
  • html cgi改变字体颜色,在CGI文件中导致错误的HTML变量

    我在从我的cgi文件中打印特定变量时出现问题 我收到这个变量 从我的网页中调用totalCost 然后尝试打印它 但没有任何反应 所有其他变量可以从网页成功接收 并通过我的cgi文件打印到另一个网页上 除了这一个 我检查过大小写敏感但是没有
  • jQuery 入门教程(14): 添加HTML元素

    使用jQuery可以方便的添加新的HTML元素 下面的方法用于添加HTML元素 append 在指定的元素的尾部添加一个新内容 prepend 在指定的元素里前部添加新内容 after 在指定元素后添加新内容 before 在指定元素的前面
  • Vue3 -- teleport传送门

    目录 teleport传送门 例 蒙层特效 目标效果 代码演示 页面效果 未使用teleport存在的问题 使用teleport实现目标效果 完整代码 总结 teleport传送门 Teleport 是一种能够移动 DOM到Vue根节点之外
  • 自学区块链:原理、技术及应用——什么是区块链(笔记)

    Bitcoin和区块链有很深的渊源 但Bitcoin与区块链两者不能等同 区块链是Bitcoin的底层技术 除了Bitcoin 还有很多其他的区块链技术应用 什么是 区块链 时间戳服务器对以区块 Block 形式存在的一组数据实施随机散列
  • 华为云计算HCIE之oceanstor仿真器的使用操作

    华为云计算HCIE之oceanstor仿真器的使用操作 一 登录检查oceanstor的状态 二 配置存储资源 1 创建硬盘域 2 创建存储池 3 创建LUN 4 创建LUN组 5 创建主机 6 创建主机组 7 创建映射关系 三 配置存储H
  • idea 连接云mysql_IntelliJ IDEA 连接数据库 详细过程

    连接到MySQL数据库 调出Database面板 IDEA配置Database数据源需要我们在IDEA的主界面中找到View gt ToolWindows gt Database 如下图所示 1 选择数据源 在IDEA中新建一个Java工程
  • T系接口源数据格式

    item apiStack name esi value endpoint mode android osVersion 9 26 0 protocolVersion 3 0 ultronage true data dinamic TB d
  • Unity + Jenkins自动打包 (二)构建Jenkins项目以及编写Python、Unity脚本

    1 新建Jenkens项目 在上一篇中 完成了Jenkins的安装和初始化 以及权限设置 查看上一篇 Jenkins安装 点此 现在打开浏览器 输入http localhost 8081 当然 需要改成你自己设置的Jenkins端口号 然后
  • lua c++中的一种回调解决方法

    见很多人发问cocos2dx 3 版本 lua 函数回调问题 我在项目中是这样解决的 因为我是使用了cocos 带有的 lua 绑定脚本 python写的 cocos2d x tools tolua genbindings py 在生成绑定
  • mac .ssh文件位置

    1 Finder gt 前往文件夹 gt 输入 ssh 2 打开终端 输入cd ssh cd ssh
  • vue组件库的开发流程

    欢迎点击领取 前端面试题进阶指南 前端登顶之巅 最全面的前端知识点梳理总结 开发流程 1 创建项目 vue cli 公司现有架构 2 调整项目静态目录结构 3 使用webpack相关库模式打包编译 4 使用npm或者公司源地址发布到你需要的
  • 向List Control中添加ACCESS数据内容

    转 给List Control 添加变量tt 加入引入ADO使用智能指针 import c program files common files system ado msado15 dll no namespace rename EOF
  • MySQL - 索引的隐藏和删除

    隐藏索引 MySQL 8开始支持隐藏索引 隐藏索引提供了更人性化的数据库操作 隐藏索引 顾名思义 让索引暂时不可见 不会被优化器使用 默认情况下索引是可见的 隐藏索引可以用来测试索引的性能 验证索引的必要性时不需要删除索引 可以先将索引隐藏
  • 【qt应用软件Focus Note++】

    本专栏介绍了使用Qt开发的一些小型桌面软件 其中包括软件功能介绍 软件截图 主要代码等内容 此外 本专栏还提供完整的软件源码和安装包供有需要的同学下载 我的目标是开发一些简洁美观且实用的客户端小软件 如果能够为大家提供有用的软件或对学习有益
  • 赶紧来修炼内功~字符串函数详解大全(一)

    目录 1 strlen 重点 模拟实现 法一 法二 法三 2 strcpy 重点 模拟实现 3 strcat 重点 模拟实现 4 strcmp 重点 模拟实现 1 strlen strlen函数是用来计算字符串长度的 重点 字符串以 0 作