【C语言】常见字符函数和字符串函数

news2024/11/17 0:01:42

1.1strlen

size_t strlen(const char* str);

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

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

注意函数的返回值为size_t,是无符号整形(易错点)

下面看一段代码:

int main()
{
	const char* str1 = "abcdef";
	const char* str2 = "bbb";
	if (strlen(str2) - strlen(str1) > 0)
	{
		printf("str2>str1\n");
	}
	else
	{
		printf("srt1>str2\n");
	}
	return 0;
}

我们知道无符号整形的运算操作的是补码,代码中的3-6可以看做是3+(-6),补码相加的结果是11111111111111111111111111111101对于一个有符号的数字,最高位是1为负数,但是返回值是无符号的数,当这个补码被当做一个无符号的数字处理的时候是一个非常大的正数,所以程序运行结果为str2>str1。

1.2strlen的模拟实现

strlen的模拟实现有三种方法:计数器、递归、指针

方法一(计数器)

size_t my_strlen1(const char* str)
{
	assert(str);
	unsigned int count = 0;
	while (*str != '\0')
	{
		str++;
		count++;
	}
	return count;
}

方法二(递归)

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

方法三(指针)

size_t my_strlen3(const char* str)
{
	assert(str);
	const char* dest = str;//没有修改,只移查找
	while ('\0' != *dest)
	{
		dest++;
	}
	return dest - str;
}

2.1strcpy

char* strcpy(char* dest, const char* src);
Copies the C string pointed by source into 
the array pointed by destination,including
the terminating null character.

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

将源字符串中的'\0'拷贝到目标空间

目标空间必须足够大,以确定能存放源字符串。

目标空间必须可变

2.2strcpy的模拟实现

char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* start = dest;//记录进入的原始的dest
	while (*dest++ = *src++)//后置++
	{
		;
	}
	return start;
}

3.1strcat

char* strcat(char* dest, const char* src);

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

目标空间必须足够大,能容纳下源字符串的内容。

目标空间可修改。

3.2strcat的模拟实现

strcat的模拟实现和strcpy的模拟实现有着异曲同工之妙,只是在strcpy模拟实现的基础上加了一个找目标字符串中的'\0'。

char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* start = dest;
	//找目标字符串中的'\0'
	while ('\0' != *dest)
	{
		dest++;
	}
	//追加
	while (*dest++ = *src++)
	{
		;
	}
	return start;
}

4.1strcmp

int strcmp(const char* str1, const char* str2);

标准规定:

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

第一个字符串等于第二个字符串,则返回0。

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

4.2strcmp的模拟实现

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;
}

5.长度受限制的字符串函数

strncpy、strncat、strncmp

char * strncpy ( char * destination, const char * source, size_t num );
char * strncat ( char * destination, const char * source, size_t num );
int strncmp ( const char * str1, const char * str2, size_t num );

这是三个函数和长度受限制的字符串函数是相似的,只不过使用传参时多一个参数num,需要指明操作字符串的字节数目,在模拟实现的时候,只要多传递一个参数,然后限制参数的大小即可实现。

6.1strstr

char* strstr(const char* str1, const char* str2);

Returns a pointer to the first occurrence of str2 in str1,or a null pointer if str2 is not part of str1.

使用举例:

int main()
{
	char str[] = "This is a simple string";
	char* pch;
	pch = strstr(str, "simple");
	strncpy(pch, "sample", 6);
	puts(str);
	return 0;
}

6.2strstr的模拟实现

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = str1;//记录str1的位置
	const char* s2 = str2;//记录str2的位置
	const char* cur = str1;//记录移动的位置
	while (*cur)
	{
		s1 = cur;
		s2 = str2;
		while (*s1 && *s2 && (*s1 == *s2))//判断条件
		{
			s1++;
			s2++;
		}
		if ('\0' == *s2)
			return (char*)cur;
		cur++;
	}
	return NULL;
}

7.1strtok

char* strtok(char* str, const char* sep);

sep参数是个字符串,定义了用作分隔符的字符集和。

第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或多个分隔符分割的标记。

strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可以修改。)

strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

如果字符串中不存在更多的标记,则返回NULL指针。

下面看一个程序:

int main()
{
	char str[] = "- This, a sample string.";
	char* pch;
	printf("Splitting string \"%s\" into tokens:\n", str);
	pch = strtok(str, " ,.-");
	while (pch != NULL)
	{
		printf("%s\n", pch);
		pch = strtok(NULL, " ,.-");
	}
	return 0;
}

这种代码看起来并不是很好,所以可以对以上代码进行改进:

int main()
{
	char* p = "zhangpengwei@bitedu.tech";
	const char* sep = ".@";
	char arr[30];
	char* str = NULL;
	strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容
	for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
	{
		printf("%s\n", str);
	}
}

7.2strerror

char* strerror(int errnum);

返回错误码所对应的错误信息。

#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件
int main()
{
	FILE* pFile;
	pFile = fopen("unexist.ent", "r");
	if (pFile == NULL)
		printf("Error opening file unexist.ent: %s\n", strerror(errno));
	//errno: Last error number
	return 0;
}

7.3memcmp

int memcmp(const void* ptr1,
           const void* ptr2,
           size_t num);

比价从ptr1和ptr2指针开始的num个字节

返回值如下:

8.1memcpy 

void * memcpy ( void * destination, const void * source, size_t num );

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。


8.2memcpy的模拟实现

void* my_memcpy(void* dest, const void* src, size_t count)
{
	assert(dest && src);
	void* ret = dest;
	while (count--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}

	return ret;
}

9.1memmove

void * memmove ( void * destination, const void * source, size_t num );

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

9.2memmove的模拟实现

void* my_memmove(void* dest, const void* src, size_t count)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)
	{
		//从前往后
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//从后往前
		while (count--)
		{
			*((char*)dest+count) = *((char*)src+count);
		}
	}
	return ret;
}

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

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

相关文章

五、Vector底层源码详解

文章目录特点底层源码分析有参构造器public Vector(int initialCapacity, int capacityIncrement)有参构造器public Vector(int initialCapacity)有参构造器public Vector(Collection<? extends E> c)无参构造器public Vector()扩容机制特点 底层是elementDate数组线程…

自学Python真的可以吗?

自学当然可以学成功python了&#xff0c;但是前提是你需要认真去学&#xff0c;而不是三天打渔两天晒网的&#xff0c;因为python初学很容易&#xff0c;稍微过几天忘记也很容易&#xff0c;所以一定要坚持学习&#xff0c;并且通过平时多加练习来熟练掌握各个知识点。 一、学…

非零基础自学Golang 第15章 Go命令行工具 15.4 注释文档(doc)

非零基础自学Golang 文章目录非零基础自学Golang第15章 Go命令行工具15.4 注释文档(doc)第15章 Go命令行工具 15.4 注释文档(doc) Go语言文档工具go doc和go fmt一样&#xff0c;也是对godoc的简单封装。 我们通常使用go doc查看指定包的文档。 例如我们查看函数fmt.Println…

焕然一新的 Vue 3 中文文档要来了

前言 大家好&#xff0c;我是LBJ&#xff0c;最近参与了 Vue 3新文档的翻译和校验工作 (vuejs/docs contributor 和 docs-zh-cn contributor) 我们知道 Vue 3 新文档 ( vuejs.org ) 已经发布一个多月了&#xff0c;但那是英文版的&#xff0c;不知道你看了没&#xff1f; 没…

恒业微晶冲刺深交所:年营收4.3亿 戴联平控制73.8%表决权

雷递网 雷建平 12月20日上海恒业微晶材料科技股份有限公司&#xff08;简称&#xff1a;“恒业微晶”&#xff09;日前递交招股书&#xff0c;准备在深交所创业板上市。恒业微晶计划募资8亿元&#xff0c;用于恒业新型分子筛项目。年营收4.31亿恒业微晶创建于1992年&#xff0c…

Vue3 Proxy代理为什么要用 Reflect映射

瞅一眼Vue3源码 地址&#xff1a;https://github.com/vuejs/core/blob/main/packages/reactivity/src/baseHandlers.ts 可以看到Proxy响应式代理 依赖 createGetter与createSetter方法&#xff1a; &#x1f6a5; createGetter function createGetter(isReadonly false, s…

Go并发大坑:inconsistent mutex state 解决及心得体会

文章目录前言首次排查&#xff08;未重视&#xff09;问题逐渐严重加大排查力度增加锁日志race detector一次意外的复现写在最后解决问题所必需的品格前言 大概在这篇文章发布数个月之前&#xff0c;某天&#xff0c;线上稳定运行的Go服务突然毫无征兆的发生了一次重启&#x…

MyBatis的相应API与传统和代理开发的Dao层实现

MyBatis的相应API 1、SqlSession工厂构建器SqlSessionFactoryBuilder 常用API&#xff1a;SqlSessionFactory build(InputStream inputStream) 通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象 其中&#xff0c;mybatis-config.xml是类加载器的路径&…

为什么要学编程?为什么是Python?怎么学?

今天我们聊了为什么要去学编程&#xff0c;学编程为什么要选择Python。上大学的时候我学的信息管理&#xff0c;毕业后选择了和网络相关的网络安全公司做售后。 从上学的时候自己就想过去学学编程&#xff0c;感觉他们敲代码都敲的那么酷&#xff0c;看着满屏的代码还有命令行…

2022广航蓝桥杯选拔赛压轴题:取数博弈游戏

原题链接 对于这种「判断先手后手的必胜必败」的题目&#xff0c;博弈论方向是一个优先考虑的方向。 博弈论的重要思想就是决策者都要做出全局最优的决策而非局部最优&#xff0c;就好比专业的棋手走一步看五步&#xff0c;而博弈论则要求棋手走一步看无限步。 解题思路 凡…

[洛谷]P3613 【深基15.例2】寄包柜

[洛谷]P3613 【深基15.例2】寄包柜一、问题描述题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示二、思路分析1、算法标签2、算法思路三、代码实现一、问题描述 [洛谷]P3613 【深基15.例2】寄包柜 题目描述 超市里有 n(1≤n≤105)n(1\le n\le10^5)n(1≤n≤105) 个…

《Quarkus实战》总结

《Quarkus实战》总结 目录 一、优势二、搭建脚手架三、Rest 1)启用跨源资源共享2)拦截HTTP请求3)使用SSL进行安全连接 四、配置 1)以程序化的方式访问配置属性2)在外部覆盖配置值3)修改日志配置 五、编程模型 1)校验输入值和输出值2)全局异常处理3)创建自定义校验4)以程序化的方…

荣耀加冕 大道可期 | WotoKOL卧兔荣获星球奖BrandStar Awards 2022服务创新奖

2022年11月&#xff0c;星球奖BrandStar Awards 2022获奖名单揭晓&#xff0c;WotoKOL卧兔荣获服务创新奖 &#xff01; 据了解&#xff0c;星球奖BrandStar Awards 是品牌星球于 2021 年发起的&#xff0c;以「品牌创新」为核心指标的奖项。星球奖系统囊括品牌建设的核心板块&…

【C语言】你知道程序是如何调用函数的吗?

目录 1.函数栈帧的含义 概念 要用到的汇编语言的知识 示例 2.理解栈帧 2.1 main函数栈帧的创建 2.2 局部变量的创建 2.3 函数传参 2.4 调用函数 2.5 函数返回 一个.c文件在调用函数的时候&#xff08;包括main 函数&#xff09;&#xff0c;其内存中的栈区有什么变…

祝贺誉天多位学员通过HCIE-Datacom,喜提誉天助跑奖学金

华为HCIE-Datacom自发布以来&#xff0c;就一直牵动着数通学员们的心。不论是版本之间的取舍&#xff0c;还是新增模块的学习&#xff0c;都一度引发热议。为了帮助各位小伙伴完成过渡顺利通过考试&#xff0c;誉天除了在师资、设备、教研等方面下足功夫之外&#xff0c;还专门…

12. 【gRPC系列学习】失败重试Retry原理

本节分析gRPC的失败重试机制,从原理、源码上进行深入分析,下节编写测试代码,验证Retry机制。 官方文档在失败重试方面的讲解比较透彻,下面内容是对官方文档的整理、归类、总结。 1. 两种重试策略简介 1)retry策略 retry策略:发送RPC,服务端应用层返回指定的异常码后,…

ES6--》了解并使用模块化规范

目录 ES6模块化规范 模块化的分类 ES6模块化的语法 ES6模块化规范 ES6模块化规范是浏览器端与服务器端通用的模块化开发规范。它的出现极大的降低了前端开发者的模块化学习成本&#xff0c;开发者不需要再额外的学习AMD、CMD或CommonJS等模块化规范。 ES6模块化规范定义&am…

激活海量数据价值,实现生产过程优化

背景 在全球掀起的新一轮工业转型浪潮中&#xff0c;智能制造面临巨大发展机遇。得益于云计算、大数据和人工智能技术的加持&#xff0c;工业转型升级进入新阶段&#xff0c;人们逐渐意识到由数据驱动催生的新商业模式所带来的巨大价值&#xff0c;数据和算法模型的结合与碰撞…

KMP算法,686. 重复叠加字符串匹配,

首先&#xff0c;要明白&#xff0c;如果b串的第一个字母b[0]在a串中没有找到&#xff0c;那么不管a串复制多少次&#xff0c;b串都不会是a的子串。 如果b串的第一个字母b[0]在a串中能找到&#xff0c;那么我们看一下a串需要复制几次呢&#xff1f; 总结,可以发现这四种情况是…

数据库系统概论第六章(关系数据理论)知识点总结(3)—— 范式知识点总结

本专栏收录了数据库的知识点&#xff0c;而从本文起&#xff0c;将讲述有关于关系数据理论中的第一范式、第二范式、第三范式以及BC范式有关知识点&#xff0c;提供给有需要的小伙伴进行学习&#xff0c;本专栏地址可以戳下面链接查看 &#x1f388; 数据库知识点总结&#xff…