理之当然网

【C进阶】——详解C语言中常见的字符串操作函数及其模拟实现

【C进阶】——详解C语言中常见的字符串操作函数及其模拟实现

这篇文章给大家介绍一些C语言中处理字符串的进阶详解 库函数以及它们的使用和注意事项,一起来学习吧!中常字符作函!串操!数及
本篇文章介绍的其模函数需要包含的头文件都是#include

文章目录

    • 前言
    • 1.求字符串长度——strlen
      • 1.1 使用及注意事项
      • 1.2 strlen的模拟实现
    • 2.字符串拷贝——strcpy
      • 2.1 使用及注意事项
      • 2.2 strcpy的模拟实现
    • 3.字符串追加函数——strcat
      • 3.1使用及注意事项
      • 3.2 strcat的模拟实现
      • 3.3思考
    • 4.字符串比较函数——strcmp
      • 4.1使用及注意事项
      • 4.2strcmp 的模拟实现
    • 5.小结
    • 6. strncpy
      • 6.1 与strcpy对比
      • 6.2 使用及注意事项
    • 7. strncat
      • 7.1与strcat对比
      • 7.2使用及注意事项
      • 7.3上述3.3思考解答
    • 8. strncmp
      • 8.1演示练习
    • 9.字符串查找函数——strstr
      • 9.1使用及注意事项
      • 9.2strstr的模拟实现
    • 10. strtok
      • 10.1功能解释及使用说明
      • 10.2 代码演示及优化
    • 11. strerror
      • 11.1功能解释及使用说明
      • 11.2 应用场景

前言

C语言中对字符和字符串的处理很是频繁,但是拟实C语言本身是没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。进阶详解
字符串常量 适用于那些对它不做修改的中常字符作函字符串函数.

1.求字符串长度——strlen

strlen是库函数,我们要知道库函数的串操参数和它的功能是C语言标准规定好的,那我们怎么看它的数及参数是什么呢?

之前的文章里给大家提到过一个查询库函数的网站(cplusplus.com):
链接: link

那我们来看一下C语言标准规定strlen的参数和功能是怎么样的的:
在这里插入图片描述

1.1 使用及注意事项

相信这个函数大家以及比较熟悉了,但这里还是其模带大家一起来复习一下,并强调一些注意事项:

  1. 字符串以 ‘\0’ 作为结束标志,拟实strlen函数返回的进阶详解是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。

举个例子:

#include #include int main(){ 	char arr[] = "abcdef";	char arr2[] = {  'a',中常字符作函'b','c','d','e','f','\0' };	printf("%d\n", strlen(arr));	printf("%d\n", strlen(arr2));	return 0;}

看下结果:
在这里插入图片描述
字符’\0’之前有6个字符,所以结果是串操6,相信大家都能明白。

  1. 参数指向的字符串必须要以 ‘\0’ 结束。

我们知道字符串的结束标志是’\0’,那如果一个字符串中没有’\0’,还能用strlen计算它的长度吗?

int main(){ 	char arr[] = {  'a','b','c','d','e','f' };	char arr2[] = {  'a','b','f'};	printf("%d\n", strlen(arr));	printf("%d\n", strlen(arr2));	return 0;}

大家思考一下结果会是什么?
在这里插入图片描述
19和31,为什么会是这个结果,是巧合吗?我们再运行一次:
在这里插入图片描述
又一个不同的结果,为啥呢?

因为如果我们不加’\0’,去求一个没有结束标志的字符串,它的结果将会是一个随机值,为什么呢?
因为函数strlen 求的是字符串中’\0’之前的字符个数,但是上面的两个字符串(C语言没有字符串类型,我们放到了字符数组中)中没有’\0’,所以strlen函数就会一直向后寻找,直至遇到’\0’,但数组后面的内存空间放的是什么我们是不知道的,所以我们不知道什么时候会遇到’\0’,因此结果是一个随机值。

  1. 注意函数的返回值为size_t,是无符号的( 易错 )

大家可能不是太明白,我们来先看一段代码:

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

大家思考一下结果是啥?

str1的长度为6,str2的长度为3,所以strlen(str2)-strlen(str1)的结果是-3,小于0,if判断为假,所以打印"srt1>str2"
如果你是这样想的那就错了!!!

我们来看一下结果是啥?
在这里插入图片描述

结果是str2>str1,与我们想的不一样,原因就在于函数strlen的返回值为size_t。

解释:
在这里插入图片描述
不知道大家有没有注意到,库函数strlen的返回类型是size_t。

那什么是size_t呢?我们来看一下:在这里插入图片描述
怎么看,在vs2022中输入一个size_t,鼠标右键转到定义或直接按F12即可查看:
在这里插入图片描述
我们看到,size_t其实就是unsigend int (无符号整型),因为typedef unsigned int size_t的意思其实就是把类型unsigned int 重命名为 size_t。
由于strlen的返回类型是size_t,所以strlen(str2)-strlen(str1)的结果就也是size_t了。
那么3-6=-3,我们知道内存中存的是补码:
在这里插入图片描述
那如果11111111111111111111111111111101被当作一个无符号整型,转化为10进制将是一个非常大的正数,肯定大于0,所以结果才是str2>str1

1.2 strlen的模拟实现

那我们现在已经知道了函数strlen的参数以及它的功能,我们是不是可以尝试去模拟实现一下strlen呢?
在这里插入图片描述

这里我们介绍三种方法去模拟实现strlen:

  1. 计数器方式

怎么实现呢?
把字符串的首字符地址传给函数,用指针接收,用该指针遍历字符串,如果指针指向的内容不是’\0’,计数器++,指针继续向后移动,直至遇到’\0’停止,返回计数器的值。

size_t my_strlen(const char* str) { 	int count = 0;	while (*str)	{ 		count++;		str++;	}	return count;}

看一下能不能达到效果:
在这里插入图片描述

  1. 递归实现

怎么递归呢?
我们对传过来的首字符地址直接解引用,如果是’\0’,那就返回0。
如果不是’\0’,那说明至少有一个有效字符,让指针+1,返回1+my_strlen(str+1),直至遇到’\0’,开始回归得出结果。

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

也能得到正确结果:
在这里插入图片描述

  1. 指针-指针

在指针的学习中我们已经知道,指针-指针得到的是两个指针之间的元素个数,那我们让一个指针指向首字符,另一个指针指向’\0’,后者减前者,得到的元素个数不就是字符串长度吗?

size_t my_strlen(char* s) { 	char* p = s;	while (*p != '\0')		p++;	return p - s;}

这样依然可行:
在这里插入图片描述

2.字符串拷贝——strcpy

先来认识一下它吧:
在这里插入图片描述
网站上都是英文的,不过我们可以翻译一下(当然有些地方可能翻译的不太准确):
在这里插入图片描述

2.1 使用及注意事项

  1. 源字符串必须以 ‘\0’ 结束

我们知道字符串的结束标志是’\0’,也就是说,strcpy在拷贝源字符串时,遇到’\0’才会停止拷贝,而跟字符串的长度无关,只要不遇到’\0’,就一直往后继续拷贝,那如果我们的源字符串中没有’\0’,会出现什么后果呢?

int main(){ 	char arr1[20] = {  0 };	char arr2[] = { 'a','b','c'};	strcpy(arr1, arr2);	return 0;}

将arr2中的字符串拷贝到arr1中,但是arr2中的字符串并没有’\0’,会出现什么样的结果呢?
在这里插入图片描述

我们调试可以发现,这样是会发生错误的,因为在字符’a’、‘b’、‘c’的后面并没有放’\0’,所以strcpy会一直向后拷贝,我们不知道什么时候才会遇到’\0’停止下来,而且arr1我们申请的空间也是有限的,也不能无限的向里面放东西,所以这样就有可能造成越界,而且在’a’、‘b’、'c’后面会拷贝什么内容我们也不知道,这是不可行的。
因此,源字符串必须以 ‘\0’ 结束。

  1. 会将源字符串中的 ‘\0’ 拷贝到目标空间

strcpy在拷贝的时候会将源字符串的’\0’也拷贝到目标空间

我们来验证一下:

int main(){ 	char arr1[20] = "

未经允许不得转载:理之当然网 » 【C进阶】——详解C语言中常见的字符串操作函数及其模拟实现