字符串函数(二):strlen(求长度),strstr(查找子串),strtok(分割),strerror(打印错误信息)

本文主要是介绍字符串函数(二):strlen(求长度),strstr(查找子串),strtok(分割),strerror(打印错误信息),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

字符串函数

  • 一.strlen(求字符串长度)
    • 1.函数使用
    • 2.模拟实现(三种方法)
  • 二.strstr(字符串查找子串)
    • 1.函数使用
    • 2.模拟实现
  • 三.strtok(字符串分割)
  • 四.strerror,perror(打印错误信息)

一.strlen(求字符串长度)

1.函数使用

size_t strlen(const char* str);
  • strlen函数用于求字符串的长度,参数是字符串的首地址,返回值是无符号的整形,初始化字符串有两种,它们各自存在一些小的细节,如下:
#include<stdio.h>
#include<string.h>
int main()
{char str1[] = "abcdef";//本质:{ 'a','b','c','d','e','f','\0' };隐藏了\0在末尾char str2[] = { 'a','b','c','d','e','f' };//函数strlen(): 求字符串长度printf("%zu\n", strlen(str1));//6printf("%zu\n", strlen(str2));//由于尾部没有'\0'随机数,所以打印随机数printf("%s\n", str2);//直到找到'\0'为止,停止打印//关键字sizeof():求字节的大小返回值同样是size_t(unsigned int)printf("%zu\n", sizeof(str1));//7printf("%zu\n", sizeof(str2));//6return 0;
}

在这里插入图片描述

  • 可以看到str2的长度居然是33,其实这是因为strlen函数会从首地址指向的字符一直向后查找,直到遇到’\0’,才会停下(不包含 ‘\0’ ),统计’\0’之前出现的字符的个数,而str2末尾没有’\0’,所以会一直向后查找,在某个位置恰好遇到了’\0’,所以打印随机数33。
  • printf函数打印字符串也是同样的道理,看似传入"abcdef",其实真正传入的是首地址(a的地址),遇到了’\0’,停止打印。那为什么会出现烫烫烫呢?这就牵扯到了函数栈帧了,日后会将函数栈帧更新上来。

总结:

  • 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前⾯出现的字符个数(不包
    含 ‘\0’ )。

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

  • 注意函数的返回值为size_t,是无符号整形(size_t 等价于 unsigned int)。

易错点:

#include<stdio.h>
int main()
{if (strlen("abc") - strlen("abcdef"))printf(">\n");elseprintf("<\n");return 0;
}

在这里插入图片描述

  • 我们会发现输出的居然大于号,这是因为strlen函数的返回值是无符号的整形,而无符号的整形相减仍然得到无符号的整形,而-3按照无符号整形来说是一个很大的数,自然打印大于号。

如图:
在这里插入图片描述
在这里插入图片描述

  • 也可以这么写:
#include<stdio.h>
int main()
{//if ((int)strlen("abc") - (int)strlen("abcdef") >0)if (strlen("abc") > strlen("abcdef"))printf(">\n");elseprintf("<\n");return 0;
}

2.模拟实现(三种方法)

  • 方法一:计数器方法
  • 我们定义一个变量为count,如果传入的指针指向的内容不是’\0’,那么count++,同时指针后移一位,循环往复,直到找到’\0’时返回count即可。
#include<assert.h>
size_t my_strlen(const char* str)
{assert(str != NULL);//断言,若str为NULL,报错,头文件assert.hsize_t count = 0;while (*str != '\0'){str++;count++;}return count;
}
  • 方法二:指针减指针
  • 我们先定义两个指针变量start与end将传入的指针保存下来,然后将指针end向后移,直到遇到’\0’时,我们返回指针end与指针start的差值即可。(指针与指针的差的绝对值是两个指针之间的元素个数)。
#include<assert.h>
size_t my_strlen(const char* str)
{assert(str != NULL);//断言,若str为NULL,报错,头文件assert.hconst char* start = str;const char* end = str;while (*end != '\0'){end++;}return end - start;
}
  • 方法三:递归
  • 判断传入指针指向的内容是否为’\0’,如果是就返回0,不是就返回my_strlen2(str+1)+1,如此进行下去,直到递归到内层时找到’\0’,这时再一步步将值返回回来即可。
#include<assert.h>
size_t my_strlen(const char* str)
{assert(str != NULL);//断言,若str为NULL,报错,头文件assert.hif (*str == '\0')return 0;elsereturn my_strlen(str + 1) + 1;
}

二.strstr(字符串查找子串)

1.函数使用

char* strstr(const char* str1, const char* str2)
  • strstr函数用于在字符串 str1 中查找另一个字符串 str2,如果字符串 str1 存在字符串 str2,那么就返回字符串 str2 在字符串 str1 中第一次出现的起始位置,如果找不到那么就返回空指针(NULL)。它的第一个参数是字符串 str1 的首地址,第二个参数是字符串 str2 的首地址。
  • 若字符串 str2 为空字符串,则返回字符串 str1 的首地址。
#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "ABCDEFG";char arr2[] = "CDE";char* ret = strstr(arr1, arr2);//返回arr1中字符C的地址if (ret != NULL)printf("%s\n", ret);//打印CDEFGelseprintf("子串不存在\n");return 0;
}

2.模拟实现

例如,在字符串"abbbcdef"中查找字符串"bbc":

  • p指针: 记录每次开始匹配时的起始位置,当从该位置开始匹配时就找到了目标字符串,便于返回指针p;当从该位置开始没有匹配成功时,则指针p后移一位进行下一次的匹配。
  • s1和s2指针: 通过判断s1和s2指针解引用后是否相等来判断单个字符是否匹配成功。若成功,则指针s1与s2后移一位比较下一对字符;若失败,指针p后移一位,指针s1返回指针p处,指针s2返回待查找字符串的起始位置。

如图:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
代码实现:

#include<assert.h>
#include<stdio.h>
char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);const char* s1 = str1;const char* s2 = str2;const char* p = str1;if (*str2 == '\0')//要查找的字符串为空字符串{return str1;}while(*p != '\0')//若要减少循环数则可以修改为//while ((p - str1) <= (int)strlen(str1) - (int)strlen(str2)){while (*s1 == *s2 && *s1 != '\0' && *s2 != '\0'){s1++;s2++;}if(*s2=='\0')//字符串查找子串成功{return p;}p++;s1 = p;s2 = str2;}return NULL;//找不到目标字符串,返回NULL
}
int main()
{char arr1[] = "abbbcdef";char arr2[] = "bbc";char* ret = my_strstr(arr1, arr2);if (ret != NULL)printf("%s\n", ret);elseprintf("子串不存在\n");return 0;
}

对于以上代码,对于循环次数还可以优化下,比如待比较的字符串str2长度大于字符串str1还能比较的字符的个数时,是不可能查找到的,所以:

while(*p != '\0')//若要减少循环数则可以修改为
while ((p - str1) <= (int)strlen(str1) - (int)strlen(str2))

三.strtok(字符串分割)

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

strtok函数能通过给定的一系列字符将一个字符串分割成许多子字符串的函数。它的第一个参数是需要被分割的字符串的首地址;第二个参数是一个字符串的首地址,该字符串是用作分隔符的字符集合。返回值是查找到的标记的首地址。

注意:

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

例如:

#include<stdio.h>
#include<string.h>
int main()
{char email[] = "3315898248@qq.com";//待分割字符串char* sep = "@.";//分隔符的字符集合char cp[20] = { 0 };strcpy(cp, email);//将数据拷贝一份使用,防止原数据被修改//char* ret = strtok(email, sep);//第一次传参需传入待分割字符串首地址//while (ret != NULL)//说明还未分割完//{//	printf("%s\n", ret);//	ret = strtok(NULL, sep);//对同一个字符串进行分割,第二次及以后的第一个参数为NULL//}//或者char* ret = NULL;//利用for循环的特点,先ret = strtok(email, sep);判断ret != NULL;//打印ret,再ret = strtok(NULL, sep);判断ret != NULL;循环到ret == NULL结束for (ret = strtok(email, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}return 0;
}

四.strerror,perror(打印错误信息)

char* strerror (int errnum);

strerror函数可以把参数部分错误码转换为对应的错误信息,将错误信息字符串的首地址返回来。

注意:

  1. 在不同的系统和C语言标准库的实现中都规定了一些errno(错误码),一般是放在 errno.h 这个头文件中说明的。
  2. C语言程序启动的时候就会使用一个全局变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在errno中。
  3. 而一个错误码的数字是整数很难理解是什么意思,所以每一个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
#include<errno.h>
#include<string.h>
#include<stdio.h>
//我们打印一下0~10这些错误码对应的信息 
int main()
{int i = 0;for (i = 0; i <= 10; i++){printf("%s\n", strerror(i));}return 0;
}

在这里插入图片描述
例如:打开一个文件(fopen函数表示:打开文件(读或写),当其执行成功时会返回文件的首地址,执行失败时会返回一个空指针(NULL)。)

int main()
{FILE* pf = fopen("test.txt", "r");//打开文件 ———— 读文件if (pf == NULL)//若为NULL,文件打开失败,下一步查看错误信息{printf("%s\n", strerror(errno));//将错误码转换成对应的错误信息perror("fopen");//直接打印错误信息return 1;}return 0;
}

在这里插入图片描述

  1. printf(“%s\n”, strerror(errno)) 等价于 perror(“”)
  2. perror(“fopen”):可以代替strerror(errno)且效果更好,加上(fopen)来明确错误来源于哪里。
  3. 程序执行会加上一个冒号。

创作不易,如果能帮到你的话能赏个三连吗?感谢啦!!!
在这里插入图片描述

这篇关于字符串函数(二):strlen(求长度),strstr(查找子串),strtok(分割),strerror(打印错误信息)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/989789

相关文章

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

Springboot3+将ID转为JSON字符串的详细配置方案

《Springboot3+将ID转为JSON字符串的详细配置方案》:本文主要介绍纯后端实现Long/BigIntegerID转为JSON字符串的详细配置方案,s基于SpringBoot3+和Spr... 目录1. 添加依赖2. 全局 Jackson 配置3. 精准控制(可选)4. OpenAPI (Spri

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

使用Python实现base64字符串与图片互转的详细步骤

《使用Python实现base64字符串与图片互转的详细步骤》要将一个Base64编码的字符串转换为图片文件并保存下来,可以使用Python的base64模块来实现,这一过程包括解码Base64字符串... 目录1. 图片编码为 Base64 字符串2. Base64 字符串解码为图片文件3. 示例使用注意

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

java中BigDecimal里面的subtract函数介绍及实现方法

《java中BigDecimal里面的subtract函数介绍及实现方法》在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigD... 目录Java中BigDecimal里面的subtract函数的意思?一、数值型减法(高精度计算)1.

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

Python函数返回多个值的多种方法小结

《Python函数返回多个值的多种方法小结》在Python中,函数通常用于封装一段代码,使其可以重复调用,有时,我们希望一个函数能够返回多个值,Python提供了几种不同的方法来实现这一点,需要的朋友... 目录一、使用元组(Tuple):二、使用列表(list)三、使用字典(Dictionary)四、 使