剖析C语言字符串函数

news2024/11/15 11:15:42

目录

前言:

一、strlen函数

功能:

参数和返回值:

注意事项:

返回值是无符号的易错点:

strlen函数的模拟实现

1、计数器算法

2、递归算法

3、指针减去指针

二、strcpy函数

功能:

参数和返回值

注意事项:

strncpy函数

strcpy函数的模拟实现

三、strcat函数

 功能:

参数和返回值

注意事项:

底层原理:

strncat函数

模拟实现:

四、strcmp函数

​编辑功能:

标准规定:

参数和返回值

注意事项:

strncpy函数

模拟实现

五、strstr函数

功能: 

参数和返回值

模拟实现

六、strtok函数

功能:

参数和返回值:

注意事项:

使用方法:


前言:

这是一篇关于C语言字符串函数详解的文章,里面不仅包含我们常见的strlen、strcpy、strcat等,也包含不太常见的strstr、strtok、strerror等,这篇文章不仅仅讲解他们的使用方法,还剖析了这些函数的底层原理,大部分我们都可以自己模拟实现。希望对大家有帮助~

一、strlen函数

功能:

统计字符串中\0前面出现的字符个数

参数和返回值:

返回类型是无符号整型,参数是字符指针

注意事项:

  • 字符串以\0作为结束标志,strlen函数返回的字符串中\0前面出现的字符个数(不包含\0
  • 参数指向的字符串必须要以\0结束
  • 注意函数的返回值为size_t,是无符号的(易错)
  • 学会strlen函数的模拟实现

返回值是无符号的易错点:

int main()
{
	if (strlen("abc") - strlen("abcd") > 0)
		printf(">\n");
	else
		printf("<\n");
	return 0;
}

 这段代码的输出结果是>,这是为何?

就是因为strlen函数返回无符号数,前者是无符号数3,后者是无符号数4,3-4=-1。

在数值上是-1,但是-1的补码是全1,又因为无符号数原码反码补码相同,所以最后表达式的结果就是全1,一个非常大的正数。

strlen函数的模拟实现

既然要实现,我们就要知道底层原理。

计算的就是\0之前出现的字符个数,那么就有计数器的算法。

1、计数器算法
//方法一、计数器法
size_t my_strlen(const char* str)
{
	size_t cnt = 0;
	while (*str++)
	{
		cnt++;
	}
	return cnt;
}

int main()
{
	size_t sz= my_strlen("bcd");
	printf("%u\n", sz);
	return 0;
}
2、递归算法
//法三、递归
size_t my_strlen(const char* str)
{

	if (*str)
	{
		return 1 + my_strlen(str + 1);
	}
	else
	{
		return 0;
	}
}

int main()
{
	int sz = my_strlen("abcd");
	printf("%d\n", sz);
	return 0;
}
3、指针减去指针
//法二、指针相减
size_t my_strlen(const char* str)
{
	char* start = str;
	char* end = str+2;
	while (*end++)
	{
		;
	}
	end--;
	return    (size_t)(end - start);
}

指针减去指针得到的是两个指针之间相差的元素个数

二、strcpy函数

功能:

拷贝字符串,将一个数组的字符串拷贝到另一个数组中,并且必须将\0拷贝过去,到\0停止。

参数和返回值

第一个参数是目标字符串的地址,第二个参数是源字符串的地址。

返回值是目标字符串地址

注意事项:

  • 源字符串必须以\0结束
  • 会将源字符串中的\0拷贝到目标空间
  • 目标空间必须足够大,以确保能存放元字符串
  • 目标空间必须可变

比如char *arr = " abcdef "

这里的arr就是不可改变的,因为👉是常量字符串

  • 学会模拟实现

strncpy函数

 与strcpy函数的区别在于strncpy限定了拷贝字符的个数。

若要求数字大于源字符串,补上\0

若不大于,正常拷贝,就是 xxxdef

strcpy函数的模拟实现

//模拟实现my_strcpy
#include<assert.h>

char* my_strcpy(char* dest,const char* sou)
{
	assert(dest != NULL && sou != NULL);
	char* ret = dest;
	while (*dest++=*sou++)
	{
		;
	}
	printf("%s\n", ret);
	return ret;
}

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

三、strcat函数

 功能:

将一个字符串追加到另一个字符串的末尾。

参数和返回值

与strcpy相同

注意事项:

  • 源字符串必须以\0结束
  • 目标空间必须有足够大的空间,能容纳下源字符串的内容
  • 目标空间必须可以修改
  • 字符串不能自己给自己追加

底层原理:

先找到目标字符串的\0位置,然后将\0替换为源字符串的首元素,接着开始追加。

strncat函数

不管长度大小,限定追加的个数,然后再补上一个\0

模拟实现:

//模拟实现strcat函数

char* my_strcat(char* dest,const char* sou)
{
	char* ret = dest;//记住dest首元素的地址,后面指针会向后加
	/*while (*dest)
	{
		dest++;
	}
	printf("%c\n", *dest);*/
	while (*++dest)
	{
		;
	}
	printf("%c\n", *dest);
	while (*dest++ = *sou++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] =  "hello " ;
	char arr2[] = "world" ;
	char *str = my_strcat(arr1, arr2);
	printf("%s\n", str);
	return 0;
}

四、strcmp函数

功能:

两个字符串比较,比较方式是一对一对比较,从每个字符串的首元素相比较,若相同,继续向第二个元素比较。

标准规定:

  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字

参数和返回值

参数就是需要比较的两个字符串,返回值是int类型,看正负,得知两个字符串的大小

注意事项:

在不同编译器,strcmp函数返回值不一定相等

strncpy函数

在给定的数字内,在前几个字符中就比较出大小。

模拟实现

#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 && *str2)
	{
		if (*str1 > *str2)
			return 1;
		else if (*str1 < *str2)
			return -1;
		else
			;
		str1++;
		str2++;
	}
	if (*str1 == *str2)
		return 0;
	else if (*str1 > *str2)
		return 1;
	else
		return -1;
}


int main()
{
	char arr1[] = "abcdg";
	char arr2[] = "abcdef";
	int ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}

五、strstr函数

功能: 

在str1这个字符串中找到str2字符串第一次出现的起始位置

参数和返回值

两个参数就是字符指针,表示两个字符串

返回值,如果找到了,就返回在第一个字符串中出现str2的起始地址;没有找到,返回空指针。

模拟实现

char* my_strstr(const char* str1, const char* str2)
{
	
	while (*str1)
	{
		char* tmp1 = str1;
		char* tmp2 = str2;
		while (*tmp2)
		{
			if (*tmp1 == *tmp2)
			{
				tmp1++;
				tmp2++;
			}
			else
				break;
		}
		if (*tmp2 == '\0')
			return str1;
		else
			str1++;
	}
	return NULL;
}


int main()
{
	char arr1[] = { "abcdefgcdefg" };
	char arr2[] = { "gc" };
	char* ret = my_strstr(arr1, arr2);
	printf("%s\n", ret);
	return 0;
}

六、strtok函数

功能:

根据特定的字符,去分割字符串。

参数和返回值:

参数:第一个参数是一个字符串,第二个参数是一些特定的字符,字符串就是由这些字符去分割

返回值:

 被分割的字符串首元素地址

注意事项:

  • 第二个参数是个字符串,定义了用作分隔符的字符集合
  • 第一个参数指定一个字符串,它包含了0个或者多个由第二个参数的字符串中一个或者多个分隔符分割的标记
  • strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:
    strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记如果字符串中不存在更多的标记,则返回NULL指针。

使用方法:

int main()
{
	char arr1[] = { "3099472927@qq.com" };
	char arr2[] = { "@." };
	char* ret = NULL;//定义指针需要初始化,不然是野指针
	for (ret=strtok(arr1,arr2);ret!=NULL;ret=strtok(NULL,arr2))
	{
		printf("%s\n", ret);
	}
	return 0;
}



 

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

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

相关文章

【小沐学NLP】龙猫-InsCode Stable Diffusion 美图活动一期

文章目录 1、应用简介1.1 Stable Diffusion模型1.2 Stable Diffusion WebUI1.3 InsCode平台 2、界面简介2.1 打开Stable Diffusion WebUI2.2 选择模型2.3 选择功能模块2.4 文本输入2.5 参数设置 3、测试3.1 龙猫3.2 恐龙3.3 蓝天白云3.4 美少女战士 4、其他4.1 DALLE 24.2 Drea…

Linux调试工具GDB(2)

文章目录 前言一、数据断点二、x查看内存命令三、深入info命令四、调试中的技巧总结 前言 本篇文章我们继续讲解GDB调试。 一、数据断点 在 GDB (GNU Debugger) 中&#xff0c;数据断点是一种断点类型&#xff0c;它允许你在程序访问指定内存地址的数据时暂停程序的执行。通…

浅聊 【ThreadLocal】(超级详细)

写在开始 : 本文主要讲述 : ThreadLocal简介; 常用API; demo案例; 特点引用场景;以及部分底层原理源码内容。 引言 &#xff1a; 从常见面试题看 ThreadLocal: **①解释 **&#xff1a; ThreadLocal是多线程中对于解决线程安全的一个操作类&#xff0c;它会为每个线程都分 配一…

121、仿真-基于51单片机8路温度 ds18b20多路温度传感器检测仿真设计(Proteus仿真+程序+原理图+参考论文+任务书+流程图等)

摘 要 随着社会经济的高速发展和科技水平的不断进步&#xff0c;温度监控器的运用范围越来越广泛&#xff0c;也渐渐地发展到了核变站的温度监控。温度与人们的生活生产密切相关&#xff0c;比如在核变站的环境下&#xff0c;对温度的监控更是必不可少的&#xff0c;不但能保…

【代码随想录 | Leetcode | 第四天】数组 | 螺旋矩阵 | 59-54

前言 欢迎来到小K的Leetcode|代码随想录|专题化专栏&#xff0c;今天将为大家带来螺旋矩阵的分享✨ 目录 前言59. 螺旋矩阵 II54. 螺旋矩阵总结 59. 螺旋矩阵 II 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n…

ASIDE-Simulink接口预研报告

ASIDE-Simulink接口预研报告 2018年4月 1 引言 本报告描述ASIDE-Simulink接口的预先研究情况和结果。 2 目的 ASIDE-Simulink接口是ASIDE中的一个模块。它的主要功能是通过解析Simulink模型文件&#xff0c;把Simulink模型中的相关信息导入到ASIDE中&#xff0c;从而把Simu…

Vue-封装组件的案例

1.案例效果 封装要求&#xff1a; ①允许用户自定义title标题 ②允许用户自定义bgcolor背景色 ③允许用户自定义color文本颜色 ④MyHeader组件需要在页面顶部进行fixed固定定位&#xff0c;且z-index等于999 使用示例如下&#xff1a; <template><div class"…

独立、相关和正交的关系以及白噪声

注意如下边缘密度的计算&#xff1a; 第一个题&#xff1a;不独立&#xff0c;不相关&#xff0c;正交 第一个题&#xff1a;独立&#xff0c;不相关&#xff0c;正交 第一个题&#xff1a;独立&#xff0c;不相关&#xff0c;不正交

【第九天】面向程序设计_类

类 是一种数据结构&#xff0c;它可以包含数据&#xff0c;成员&#xff0c;常量和变量函数&#xff0c;成员方法&#xff0c;属性&#xff0c;构造函数和析构函数等和嵌套类型。 类的声明 在程序中类适用class关键字来声明的语法如下: class 类名 { }类的成员 类的定义包…

Coursier安装Scala报错Error downloading的解决方法

根据 Scala 官方目前的安装教程 https://docs.scala-lang.org/getting-started/index.html&#xff0c;我们下载 cs-x86_64-pc-win32.zip 并解压为 cs-x86_64-pc-win32.exe。在 PowerShell 中通过java --version确认 JVM 是否已安装&#xff0c;如果已安装&#xff0c;则切换到…

从代码到内容创作:程序员如何通过自媒体项目实现赚钱?

从代码到内容创作&#xff1a;程序员如何通过自媒体项目实现赚钱&#xff1f; 自媒体项目已成为程序员们实现赚钱的一种创新方式。通过将代码技术与内容创作结合&#xff0c;程序员可以在互联网上建立自己的品牌&#xff0c;并通过以下方式实现收入增长&#xff1a; 技术教程&a…

java学习路程之篇八、知识点、方法介绍、方法的定义和调用格式、方法常见问题、方法重载

文章目录 1、方法介绍2、方法的定义和调用格式3、方法常见问题4、方法重载 1、方法介绍 2、方法的定义和调用格式 3、方法常见问题 4、方法重载

微信小程序三脚猫功夫拿下组件注册与使用

1.局部注册组件 1.1创建components文件夹 1.2创建文件夹MyHeader 1.3选中MyHeader右键 说明&#xff1a;执行此步&#xff0c;将会自己创建四个文件 1.4MyHeader.wxml文件 说明&#xff1a;随便写点h5结构 <view class"sentence">励志语句</view> <…

实验四(双向重发布)7 14

一、配置网络地址&#xff0c;启用OSPF以及环回类型更改&#xff0c;启用RiP&#xff1a; R1&#xff1a; R2&#xff1a; R3&#xff1a; R4&#xff1a;环回接口放置OSPF区域 R5&#xff1a; R6&#xff1a;环回接口放置RIp区域 二、重发布&#xff1a; 未重发布之前&#…

Gitee生成ssh公钥

进入 C:/Users/Administrator/.ssh &#xff0c;没有就手动创建该文件夹 打开cmd输入指令 ssh-keygen -t rsa -C "Gitee SSH Key" -f "C:\Users\.ssh\github_id_rsa"中间通过三次回车键确定查看ssh公钥 type C:\Users\Zzzy\.ssh\github_id_rsa.pub 复制放到…

[LeetCode] #118 杨辉三角

给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c; 每个数是它左上方和右上方的数的和。 杨辉三角&#xff1a; class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<…

Linux 动态主机配置协议 DHCP

文章首发地址 如果管理的计算机有几十台&#xff0c;那么初始化服务器配置IP地址、网关和子网掩码等参数是一个繁琐耗时的过程。如果网络结构要更改&#xff0c;需要重新初始化网络参数&#xff0c;使用动态主机配置协议DHCP&#xff08;Dynamic Host Configuration Protocol&a…

Ubuntu U盘只能读取不能写入

Ubuntu U盘只能读取不能写入 1. 问题2. 解决办法 1. 问题 Ubuntu系统下&#xff0c;U盘突然只能读取无法写入 原因是U盘的文件系统损坏&#xff0c;操作系统为了防止进一步毁坏文件系统&#xff0c;而将其设置成了只读 2. 解决办法 查看U盘分区和挂载 $ df -h 解除挂载 $ u…

微服务系列文章 之 SpringCloud中遇到的一些bug

1、There was a problem with the instance info replicator 错误原因&#xff1a; 该服务尝试将自己作为客服端注册解决办法&#xff1a; 在application.yml配置文件中&#xff0c;设置 # 注册Eureka服务 eureka:client:# Eureka服务注册中心会将自己作为客户端来尝试注册它自…

半导体热阻问题解析(Tc,Ta,Tj,Pc)

自记&#xff1a; 晶体管(或半导体)的热阻与温度、功耗之间的关系为&#xff1a; TaTj-*P(RjcRcsRsa)Tj-P*Rja 公式中&#xff0c;Ta(Ambient temperature)表示环境温度 Tj(Junction temperature)表示晶体管的结温&#xff0c;也就是封装内部半导体裸片的温度。硅片的…